diff --git a/lib/modules/gva/resources/schema.gql b/lib/modules/gva/resources/schema.gql
index d9147a4f7801e2a3ae3555524586154580f2bfdd..f3808c35e9be23189c30f66fac0d7952322a4f7c 100644
--- a/lib/modules/gva/resources/schema.gql
+++ b/lib/modules/gva/resources/schema.gql
@@ -8,12 +8,25 @@ type Query {
   node: Node! @juniper(ownership: "owned")
   current: Block @juniper(ownership: "owned")
   block(number: Int!): Block @juniper(ownership: "owned")
+  blocks(paging: Paging): [Block!]! @juniper(ownership: "owned")
 }
 
 type Mutation {
   noop: Boolean!
 }
 
+#################################
+# Inputs
+#################################
+
+input Paging {
+  pageNumber: Int # default value: 0
+	pageSize: Int # default value: 50
+  fromBlock: Int # default value: 0
+  # If toBlock is null, current block number is used
+  toBlock: Int
+}
+
 #################################
 # NODE types
 #################################
diff --git a/lib/modules/gva/src/schema.rs b/lib/modules/gva/src/schema.rs
index 842a3873a3cb93ad5f130c78a26984d726f139f5..b41ccf9eaa6cdc61e777523cfdcdcaac4dc4a991 100644
--- a/lib/modules/gva/src/schema.rs
+++ b/lib/modules/gva/src/schema.rs
@@ -16,6 +16,7 @@
 // ! model and resolvers implementation
 
 mod block;
+mod paging;
 
 use self::block::Block;
 use crate::context::Context;
@@ -89,7 +90,26 @@ impl QueryFields for Query {
         };
 
         db.read(|r| block::get_block(db, r, block_number))
-            .map_err(|e| juniper::FieldError::from(format!("Db error: {:?}", e)))
+            .map_err(db_err_to_juniper_err)
+    }
+    fn field_blocks(
+        &self,
+        executor: &Executor<'_, Context>,
+        _trail: &QueryTrail<'_, Block, Walked>,
+        paging_opt: Option<Paging>,
+    ) -> FieldResult<Vec<Block>> {
+        let db: &BcDbRo = &executor.context().get_db();
+        db.read(|r| {
+            paging::FilledPaging::new(db, r, paging_opt)?
+                .get_range()
+                .filter_map(|n| match block::get_block(db, r, BlockNumber(n)) {
+                    Ok(Some(db_block)) => Some(Ok(db_block)),
+                    Ok(None) => None,
+                    Err(e) => Some(Err(e)),
+                })
+                .collect::<Result<Vec<Block>, DbError>>()
+        })
+        .map_err(db_err_to_juniper_err)
     }
 }
 
diff --git a/lib/modules/gva/src/schema/paging.rs b/lib/modules/gva/src/schema/paging.rs
new file mode 100644
index 0000000000000000000000000000000000000000..af47c177c1a088d2cb129d24c9f63a6b625829ba
--- /dev/null
+++ b/lib/modules/gva/src/schema/paging.rs
@@ -0,0 +1,108 @@
+//  Copyright (C) 2017-2019  The AXIOM TEAM Association.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+// ! Schema paging input
+
+use super::Paging;
+use durs_bc_db_reader::{BcDbRo, DbError, DbReader};
+use std::ops::Range;
+
+const DEFAULT_PAGE_NUMBER: i32 = 0;
+const DEFAULT_PAGE_SIZE: i32 = 50;
+const DEFAULT_FROM_BLOCK: i32 = 0;
+
+const MAX_PAGE_NUMBER: i32 = std::i32::MAX;
+const MAX_PAGE_SIZE: i32 = 500;
+const MAX_FROM_BLOCK: i32 = std::i32::MAX;
+
+/// Paging with all values filled in
+pub struct FilledPaging {
+    page_number: usize,
+    page_size: usize,
+    from_block: u32,
+    to_block: u32,
+}
+
+#[inline]
+fn i32_opt_to_positive_i32(int_opt: Option<i32>, default: i32) -> i32 {
+    if let Some(int) = int_opt {
+        if int < 0 {
+            0
+        } else {
+            int
+        }
+    } else {
+        default
+    }
+}
+
+impl FilledPaging {
+    pub fn new<R: DbReader>(
+        db: &BcDbRo,
+        r: &R,
+        paging_opt: Option<Paging>,
+    ) -> Result<Self, DbError> {
+        if let Some(paging) = paging_opt {
+            Ok(FilledPaging {
+                page_number: std::cmp::min(
+                    MAX_PAGE_NUMBER,
+                    i32_opt_to_positive_i32(paging.page_number, DEFAULT_PAGE_NUMBER),
+                ) as usize,
+                page_size: std::cmp::min(
+                    MAX_PAGE_SIZE,
+                    i32_opt_to_positive_i32(paging.page_size, DEFAULT_PAGE_SIZE),
+                ) as usize,
+                from_block: std::cmp::min(
+                    MAX_FROM_BLOCK,
+                    i32_opt_to_positive_i32(paging.from_block, DEFAULT_FROM_BLOCK),
+                ) as u32,
+                to_block: if let Some(to_block) = paging.to_block {
+                    if to_block < 0 {
+                        0
+                    } else {
+                        to_block as u32
+                    }
+                } else {
+                    Self::get_default_to_block(db, r)?
+                },
+            })
+        } else {
+            Ok(FilledPaging {
+                page_number: DEFAULT_PAGE_NUMBER as usize,
+                page_size: DEFAULT_PAGE_SIZE as usize,
+                from_block: DEFAULT_FROM_BLOCK as u32,
+                to_block: Self::get_default_to_block(db, r)?,
+            })
+        }
+    }
+    fn get_default_to_block<R: DbReader>(db: &BcDbRo, r: &R) -> Result<u32, DbError> {
+        if let Some(current_blockstamp) =
+            durs_bc_db_reader::current_meta_datas::get_current_blockstamp_(db, r)?
+        {
+            Ok(current_blockstamp.id.0)
+        } else {
+            Ok(0)
+        }
+    }
+    pub fn get_range(&self) -> Range<u32> {
+        Range {
+            start: self.from_block + (self.page_number * self.page_size) as u32,
+            end: std::cmp::min(
+                self.to_block + 1,
+                self.from_block + ((self.page_number + 1) * self.page_size) as u32,
+            ),
+        }
+    }
+}