diff --git a/services/core/.dockerignore b/services/core/.dockerignore
index 64a76cf84a..c6a7d2580d 100644
--- a/services/core/.dockerignore
+++ b/services/core/.dockerignore
@@ -64,3 +64,6 @@ db_data
 
 # Benchmark directory
 benchmark
+
+# Data download directory
+data
diff --git a/services/core/.gitignore b/services/core/.gitignore
index d554aca42d..f3afa87985 100644
--- a/services/core/.gitignore
+++ b/services/core/.gitignore
@@ -61,5 +61,5 @@ xunit-report.xml
 # Embedded DB directory
 db_data
 
-# Genesis block download
-shared/core/compat/sdk_v5/static
+# Data download directory
+data
diff --git a/services/core/config.js b/services/core/config.js
index 756587cee2..9a1256933a 100644
--- a/services/core/config.js
+++ b/services/core/config.js
@@ -34,7 +34,21 @@ config.endpoints.redis = process.env.SERVICE_CORE_REDIS || 'redis://localhost:63
 config.endpoints.liskStatic = process.env.LISK_STATIC || 'https://static-data.lisk.io';
 config.endpoints.geoip = process.env.GEOIP_JSON || 'https://geoip.lisk.io/json';
 config.endpoints.mysql = process.env.SERVICE_CORE_MYSQL || 'mysql://lisk:password@localhost:3306/lisk';
-config.endpoints.genesisBlock = process.env.GENESIS_BLOCK_URL || 'https://downloads.lisk.io/lisk/mainnet/genesis_block.json.tar.gz';
+
+config.network = [
+	{
+		name: 'mainnet',
+		identifier: '022097430f51c10da3146920f4c82005900ce5da83bd5d92c04dec2645e54325',
+		genesisHeight: Number(process.env.GENESIS_HEIGHT || 0),
+		genesisBlockUrl: process.env.GENESIS_BLOCK_URL || 'https://downloads.lisk.io/lisk/mainnet/genesis_block.json.tar.gz',
+	},
+	{
+		name: 'testnet',
+		identifier: '15f0dacc1060e91818224a94286b13aa04279c640bd5d6f193182031d133df7c',
+		genesisHeight: Number(process.env.GENESIS_HEIGHT || 14075260),
+		genesisBlockUrl: process.env.GENESIS_BLOCK_URL || 'https://downloads.lisk.io/lisk/testnet/genesis_block.json.tar.gz',
+	},
+];
 
 /**
  * Indexing
@@ -48,7 +62,6 @@ config.endpoints.genesisBlock = process.env.GENESIS_BLOCK_URL || 'https://downlo
  * such as transactions, accounts, votes etc.
  */
 config.indexNumOfBlocks = Number(process.env.INDEX_N_BLOCKS || 202);
-config.genesisHeight = Number(process.env.GENESIS_HEIGHT || 0);
 
 config.transactionStatistics = {
 	enabled: Boolean(String(process.env.ENABLE_TRANSACTION_STATS).toLowerCase() === 'true'),
diff --git a/services/core/package-lock.json b/services/core/package-lock.json
index e73529aa6e..47a519f96a 100644
--- a/services/core/package-lock.json
+++ b/services/core/package-lock.json
@@ -2830,6 +2830,15 @@
       "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==",
       "dev": true
     },
+    "JSONStream": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+      "requires": {
+        "jsonparse": "^1.2.0",
+        "through": ">=2.2.7 <3"
+      }
+    },
     "abab": {
       "version": "2.0.5",
       "resolved": "https://npm.lisk.io/abab/-/abab-2.0.5.tgz",
@@ -3329,6 +3338,19 @@
         }
       }
     },
+    "big-json": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/big-json/-/big-json-3.1.0.tgz",
+      "integrity": "sha512-Xfzbp/LWMgOg41eO72u+TJnUflNsZf1U/Yhw9kNHP4J418xKzAxdVT5aHbZBQcAtjBj6KZasPefeAWclHyKrpQ==",
+      "requires": {
+        "JSONStream": "^1.3.1",
+        "assert-plus": "^1.0.0",
+        "into-stream": "^5.1.0",
+        "json-stream-stringify": "^2.0.1",
+        "once": "^1.4.0",
+        "through2": "^3.0.1"
+      }
+    },
     "big-number": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/big-number/-/big-number-2.0.0.tgz",
@@ -3341,7 +3363,7 @@
     },
     "block-stream": {
       "version": "0.0.9",
-      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+      "resolved": "https://npm.lisk.io/block-stream/-/block-stream-0.0.9.tgz",
       "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
       "optional": true,
       "requires": {
@@ -4793,6 +4815,15 @@
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
       "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
     },
+    "from2": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+      "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+      "requires": {
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0"
+      }
+    },
     "fs-extra": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -5236,6 +5267,15 @@
       "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
       "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw=="
     },
+    "into-stream": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz",
+      "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==",
+      "requires": {
+        "from2": "^2.3.0",
+        "p-is-promise": "^3.0.0"
+      }
+    },
     "ioredis": {
       "version": "4.27.1",
       "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.1.tgz",
@@ -8329,6 +8369,11 @@
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
       "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
     },
+    "json-stream-stringify": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-2.0.3.tgz",
+      "integrity": "sha512-Ry+1rZE1YVKlCMG1emCiReP/OfZrFrEGZn6TC7NPpIGO9NXf0KEqqBL0flgt2J59EiRPv+CKi7S7v31RAHrdXw=="
+    },
     "json-stringify-safe": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -8351,6 +8396,11 @@
         "graceful-fs": "^4.1.6"
       }
     },
+    "jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+    },
     "jsprim": {
       "version": "1.4.1",
       "resolved": "https://npm.lisk.io/jsprim/-/jsprim-1.4.1.tgz",
@@ -9502,6 +9552,11 @@
       "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
       "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
     },
+    "p-is-promise": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz",
+      "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ=="
+    },
     "p-limit": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@@ -11260,6 +11315,22 @@
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
     },
+    "through2": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+      "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+      "requires": {
+        "inherits": "^2.0.4",
+        "readable-stream": "2 || 3"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+        }
+      }
+    },
     "tildify": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
diff --git a/services/core/package.json b/services/core/package.json
index 6f514df5e1..1f1da70748 100644
--- a/services/core/package.json
+++ b/services/core/package.json
@@ -34,6 +34,7 @@
     "@liskhq/lisk-transactions-v4": "npm:@liskhq/lisk-transactions@^4.0.0",
     "@liskhq/lisk-transactions-v5": "npm:@liskhq/lisk-transactions@^5.0.3",
     "async": "^3.2.0",
+    "big-json": "^3.1.0",
     "big-number": "=2.0.0",
     "bluebird": "^3.7.2",
     "body-parser": "^1.19.0",
diff --git a/services/core/shared/arrayUtils.js b/services/core/shared/arrayUtils.js
new file mode 100644
index 0000000000..d9c17835fd
--- /dev/null
+++ b/services/core/shared/arrayUtils.js
@@ -0,0 +1,20 @@
+/*
+ * LiskHQ/lisk-service
+ * Copyright © 2021 Lisk Foundation
+ *
+ * See the LICENSE file at the top-level directory of this distribution
+ * for licensing information.
+ *
+ * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
+ * no part of this software, including this file, may be copied, modified,
+ * propagated, or distributed except according to the terms contained in the
+ * LICENSE file.
+ *
+ * Removal or modification of this copyright notice is prohibited.
+ *
+ */
+const dropDuplicates = arr => arr.filter((v, i, a) => a.findIndex(t => (t === v)) === i);
+
+module.exports = {
+	dropDuplicates,
+};
diff --git a/services/core/shared/core/compat/common/constants.js b/services/core/shared/core/compat/common/constants.js
index 539b4b6306..49b1eae4dc 100644
--- a/services/core/shared/core/compat/common/constants.js
+++ b/services/core/shared/core/compat/common/constants.js
@@ -13,7 +13,7 @@
  * Removal or modification of this copyright notice is prohibited.
  *
  */
-const { Utils } = require('lisk-service-framework');
+const { CacheRedis, Utils } = require('lisk-service-framework');
 
 const http = require('./httpRequest');
 const { getApiClient } = require('./wsRequest');
@@ -21,6 +21,10 @@ const { getApiClient } = require('./wsRequest');
 const ObjectUtilService = Utils.Data;
 const { isProperObject } = ObjectUtilService;
 
+const config = require('../../../../config');
+
+const constantsCache = CacheRedis('networkConstants', config.endpoints.redis);
+
 let coreVersion = '1.0.0-alpha.0';
 let constants;
 let readyStatus;
@@ -82,6 +86,7 @@ const getNetworkConstants = async () => {
 			}
 			if (!isProperObject(result)) return {};
 			constants = result;
+			await constantsCache.set('networkConstants', JSON.stringify(constants));
 		}
 		return constants;
 	} catch (_) {
diff --git a/services/core/shared/core/compat/sdk_v5/accounts.js b/services/core/shared/core/compat/sdk_v5/accounts.js
index 5bedc1dd1e..2e9eca6f77 100644
--- a/services/core/shared/core/compat/sdk_v5/accounts.js
+++ b/services/core/shared/core/compat/sdk_v5/accounts.js
@@ -40,6 +40,10 @@ const {
 	initializeQueue,
 } = require('../../queue');
 
+const {
+	dropDuplicates,
+} = require('../../../arrayUtils');
+
 const {
 	parseToJSONCompatObj,
 } = require('../../../jsonTools');
@@ -108,7 +112,9 @@ const getAccountsFromCore = async (params) => {
 };
 
 const indexAccountsbyAddress = async (addressesToIndex, isGenesisBlockAccount = false) => {
-	const { data: accountsToIndex } = await getAccountsFromCore({ addresses: addressesToIndex });
+	const { data: accountsToIndex } = await getAccountsFromCore({
+		addresses: dropDuplicates(addressesToIndex),
+	});
 	const finalAccountsToIndex = await BluebirdPromise.map(
 		accountsToIndex,
 		async account => {
@@ -223,8 +229,8 @@ const indexAccountsbyPublicKey = async (accountInfoArray) => {
 	const accountsDB = await getAccountsIndex();
 
 	const { data: accountsToIndex } = await getAccountsFromCore({
-		addresses: accountInfoArray
-			.map(accountInfo => getHexAddressFromPublicKey(accountInfo.publicKey)),
+		addresses: dropDuplicates(accountInfoArray
+			.map(accountInfo => getHexAddressFromPublicKey(accountInfo.publicKey))),
 	});
 
 	const finalAccountsToIndex = await BluebirdPromise.map(
diff --git a/services/core/shared/core/compat/sdk_v5/blocks.js b/services/core/shared/core/compat/sdk_v5/blocks.js
index f90a391d21..ecd6024c03 100644
--- a/services/core/shared/core/compat/sdk_v5/blocks.js
+++ b/services/core/shared/core/compat/sdk_v5/blocks.js
@@ -56,10 +56,12 @@ const getBlocksIndex = () => mysqlIndex('blocks', blocksIndexSchema);
 
 const logger = Logger();
 
-const { genesisHeight } = config;
+let genesisHeight;
 let finalizedHeight;
 let indexStartHeight;
 
+const setGenesisHeight = (height) => genesisHeight = height;
+
 const getGenesisHeight = () => genesisHeight;
 
 const setFinalizedHeight = (height) => finalizedHeight = height;
@@ -124,10 +126,10 @@ const indexBlocksQueue = initializeQueue('indexBlocksQueue', indexBlocks);
 const updateBlockIndexQueue = initializeQueue('updateBlockIndexQueue', updateBlockIndex);
 const deleteIndexedBlocksQueue = initializeQueue('deleteIndexedBlocksQueue', deleteIndexedBlocks);
 
-const normalizeBlocks = async blocks => {
+const normalizeBlocks = async (blocks, isIgnoreGenesisAccounts = true) => {
 	const apiClient = await getApiClient();
 
-	const normalizedBlocks = BluebirdPromise.map(
+	const normalizedBlocks = await BluebirdPromise.map(
 		blocks.map(block => ({ ...block.header, payload: block.payload })),
 		async block => {
 			const account = await getIndexedAccountInfo({ publicKey: block.generatorPublicKey.toString('hex') });
@@ -153,6 +155,17 @@ const normalizeBlocks = async blocks => {
 				block.totalFee += Number(txn.fee) - txnMinFee;
 			});
 
+			if (isIgnoreGenesisAccounts) {
+				const {
+					accounts,
+					initRounds,
+					initDelegates,
+					...otherAssets
+				} = block.asset;
+
+				block.asset = { ...otherAssets };
+			}
+
 			return parseToJSONCompatObj(block);
 		},
 		{ concurrency: blocks.length },
@@ -171,9 +184,9 @@ const getBlocksByIDs = async ids => {
 	return normalizeBlocks(response.data);
 };
 
-const getBlockByHeight = async height => {
+const getBlockByHeight = async (height, isIgnoreGenesisAccounts = true) => {
 	const response = await coreApi.getBlockByHeight(height);
-	return normalizeBlocks(response.data);
+	return normalizeBlocks(response.data, isIgnoreGenesisAccounts);
 };
 
 const getBlocksByHeightBetween = async (from, to) => {
@@ -353,30 +366,40 @@ const deleteBlock = async (block) => {
 };
 
 const indexGenesisBlock = async () => {
-	logger.info(`Ìndexing genesis block at height ${genesisHeight}`);
-	const [genesisBlock] = await getBlockByHeight(genesisHeight);
-
-	// Index the genesis block transactions first
-	await indexTransactions([genesisBlock]);
-
-	// Index the genesis block accounts next
-	const accountAddressesToIndex = genesisBlock.asset.accounts
-		.filter(account => account.address.length > 16) // Filter out reclaim accounts
-		.map(account => account.address);
-
-	const PAGE_SIZE = 20;
-	const NUM_PAGES = Math.ceil(accountAddressesToIndex.length / PAGE_SIZE);
-	for (let i = 0; i < NUM_PAGES; i++) {
-		// eslint-disable-next-line no-await-in-loop
-		await indexAccountsbyAddress(
-			accountAddressesToIndex.slice(i * PAGE_SIZE, (i + 1) * PAGE_SIZE),
-			true,
-		);
-	}
+	const blocksDB = await getBlocksIndex();
+	const [indexedGenesisBlock] = await blocksDB.find({ height: genesisHeight });
+
+	if (indexedGenesisBlock) {
+		logger.info(`Genesis block already indexed at height ${genesisHeight}`);
+	} else {
+		logger.info(`Ìndexing genesis block at height ${genesisHeight}`);
+		const [genesisBlock] = await getBlockByHeight(genesisHeight, false);
+
+		// Index the genesis block transactions first
+		await indexTransactions([genesisBlock]);
+
+		// Index the genesis block accounts next
+		const initDelegateAddresses = genesisBlock.asset.initDelegates;
+		const nonDelegateAddressesToIndex = genesisBlock.asset.accounts
+			.filter(account => account.address.length > 16) // Filter out reclaim accounts
+			.map(account => account.address);
+
+		const accountAddressesToIndex = initDelegateAddresses.concat(nonDelegateAddressesToIndex);
+
+		const PAGE_SIZE = 20;
+		const NUM_PAGES = Math.ceil(accountAddressesToIndex.length / PAGE_SIZE);
+		for (let i = 0; i < NUM_PAGES; i++) {
+			// eslint-disable-next-line no-await-in-loop
+			await indexAccountsbyAddress(
+				accountAddressesToIndex.slice(i * PAGE_SIZE, (i + 1) * PAGE_SIZE),
+				true,
+			);
+		}
 
-	// Finally index the genesis block itself
-	await indexBlocksQueue.add('indexBlocksQueue', { blocks: [genesisBlock] });
-	logger.info('Finished indexing the genesis block');
+		// Finally index the genesis block itself
+		await indexBlocksQueue.add('indexBlocksQueue', { blocks: [genesisBlock] });
+		logger.info('Finished indexing the genesis block');
+	}
 };
 
 const buildIndex = async (from, to) => {
@@ -463,7 +486,7 @@ const indexMissingBlocks = async (startHeight, endHeight) => {
 };
 
 const indexPastBlocks = async () => {
-	logger.info('Building index of blocks');
+	logger.info('Building the blocks index');
 	const blocksDB = await getBlocksIndex();
 
 	if (config.indexNumOfBlocks === 0) setIsSyncFullBlockchain(true);
@@ -485,29 +508,34 @@ const indexPastBlocks = async () => {
 	// Start building the block index
 	await buildIndex(highestIndexedHeight, blockIndexHigherRange);
 	await indexMissingBlocks(blockIndexLowerRange, blockIndexHigherRange);
+	logger.info('Finished building the blocks index');
 };
 
 const checkIndexReadiness = async () => {
 	logger.debug('============== Checking blocks index ready status ==============');
 	if (!getIndexReadyStatus()) {
-		const blocksDB = await getBlocksIndex();
-		const currentChainHeight = (await coreApi.getNetworkStatus()).data.height;
-		const numBlocksIndexed = await blocksDB.count();
-		const [lastIndexedBlock] = await blocksDB.find({ sort: 'height:desc', limit: 1 });
-
-		logger.debug(
-			`\nnumBlocksIndexed: ${numBlocksIndexed}`,
-			`\nlastIndexedBlock: ${lastIndexedBlock.height}`,
-			`\ncurrentChainHeight: ${currentChainHeight}`,
-		);
-		if (numBlocksIndexed >= currentChainHeight - genesisHeight
-			&& lastIndexedBlock.height >= currentChainHeight - 1) {
-			setIndexReadyStatus(true);
-			logger.info('Blocks index is now ready');
-			logger.debug(`============== 'blockIndexReady' signal: ${Signals.get('blockIndexReady')} ==============`);
-			Signals.get('blockIndexReady').dispatch(true);
-		} else {
-			logger.debug('Blocks index is not yet ready');
+		try {
+			const blocksDB = await getBlocksIndex();
+			const currentChainHeight = (await coreApi.getNetworkStatus()).data.height;
+			const numBlocksIndexed = await blocksDB.count();
+			const [lastIndexedBlock] = await blocksDB.find({ sort: 'height:desc', limit: 1 });
+
+			logger.debug(
+				`\nnumBlocksIndexed: ${numBlocksIndexed}`,
+				`\nlastIndexedBlock: ${lastIndexedBlock.height}`,
+				`\ncurrentChainHeight: ${currentChainHeight}`,
+			);
+			if (numBlocksIndexed >= currentChainHeight - genesisHeight
+				&& lastIndexedBlock.height >= currentChainHeight - 1) {
+				setIndexReadyStatus(true);
+				logger.info('Blocks index is now ready');
+				logger.debug(`============== 'blockIndexReady' signal: ${Signals.get('blockIndexReady')} ==============`);
+				Signals.get('blockIndexReady').dispatch(true);
+			} else {
+				logger.debug('Blocks index is not yet ready');
+			}
+		} catch (err) {
+			logger.warn(`Error while checking index readiness: ${err.message}`);
 		}
 	}
 	return getIndexReadyStatus();
@@ -519,6 +547,9 @@ const init = async () => {
 
 	// Check state of index and perform update
 	try {
+		// Set the genesis height
+		setGenesisHeight(await coreApi.getGenesisHeight());
+
 		await indexGenesisBlock().catch(err => {
 			logger.error(err.message);
 			logger.warn('Unable to index the Genesis block. Continuing with the remaining...');
diff --git a/services/core/shared/core/compat/sdk_v5/blocksUtils.js b/services/core/shared/core/compat/sdk_v5/blocksUtils.js
index 2a88fdb457..461404ec70 100644
--- a/services/core/shared/core/compat/sdk_v5/blocksUtils.js
+++ b/services/core/shared/core/compat/sdk_v5/blocksUtils.js
@@ -15,47 +15,75 @@
  */
 const fs = require('fs');
 const https = require('https');
+const json = require('big-json');
 const path = require('path');
 const tar = require('tar');
 
 const {
+	CacheRedis,
 	Logger,
 	HTTP: { request },
+	Exceptions: { NotFoundException },
 } = require('lisk-service-framework');
 
 const config = require('../../../../config');
 
 const logger = Logger();
 
-const genesisBlockURL = config.endpoints.genesisBlock;
+let readStream;
+let genesisBlockURL;
+let genesisBlockFilePath;
+let genesisBlock = { header: {} };
 
-const genesisBlockFilePath = './shared/core/compat/sdk_v5/static/genesis_block.json';
+const constantsCache = CacheRedis('networkConstants', config.endpoints.redis);
 
-let genesisBlockId;
+const parseStream = json.createParseStream();
 
-const setGenesisBlockId = (id) => genesisBlockId = id;
+const setGenesisBlock = (block) => genesisBlock = block;
 
-const getGenesisBlockId = () => genesisBlockId;
+const getGenesisBlock = () => genesisBlock;
+
+const getGenesisBlockId = () => genesisBlock.header.id;
+
+const loadConfig = async () => {
+	const { data: { networkIdentifier } } = JSON.parse(await constantsCache.get('networkConstants'));
+
+	const [networkConfig] = config.network.filter(c => c.identifier === networkIdentifier);
+	genesisBlockURL = networkConfig.genesisBlockUrl;
+	logger.debug(`genesisBlockURL set to ${genesisBlockURL}`);
+
+	genesisBlockFilePath = `./data/${networkConfig.name}/genesis_block.json`;
+	logger.debug(`genesisBlockFilePath set to ${genesisBlockFilePath}`);
+
+	// If file exists, already create a read stream
+	if (fs.existsSync(genesisBlockFilePath)) readStream = fs.createReadStream(genesisBlockFilePath);
+};
 
 const downloadGenesisBlock = async () => {
 	const directoryPath = path.dirname(genesisBlockFilePath);
-	if (!fs.existsSync(directoryPath)) fs.mkdirSync(directoryPath);
+	if (!fs.existsSync(directoryPath)) fs.mkdirSync(directoryPath, { recursive: true });
 
-	logger.info(`Persisting genesis block to the filesystem. Downloading from: ${genesisBlockURL}`);
+	logger.info(`Downloading genesis block to the filesystem from: ${genesisBlockURL}`);
 
 	return new Promise((resolve, reject) => {
 		if (genesisBlockURL.endsWith('.tar.gz')) {
 			https.get(genesisBlockURL, (response) => {
-				response.pipe(tar.extract({ cwd: directoryPath }));
-				response.on('error', async (err) => reject(err));
-				response.on('end', async () => setTimeout(resolve, 500));
+				if (response.statusCode === 200) {
+					response.pipe(tar.extract({ cwd: directoryPath }));
+					response.on('error', async (err) => reject(err));
+					response.on('end', async () => setTimeout(resolve, 500));
+				} else {
+					const errMessage = `Download failed with HTTP status code: ${response.statusCode} (${response.statusMessage})`;
+					logger.error(errMessage);
+					if (response.statusCode === 404) throw new NotFoundException(errMessage);
+					throw new Error(errMessage);
+				}
 			});
 		} else {
 			request(genesisBlockURL)
 				.then(async response => {
-					const genesisBlock = typeof response === 'string' ? JSON.parse(response).data : response.data;
-					fs.writeFileSync(genesisBlockFilePath, JSON.stringify(genesisBlock));
-					resolve();
+					const block = typeof response === 'string' ? JSON.parse(response).data : response.data;
+					fs.writeFile(genesisBlockFilePath, JSON.stringify(block), () => resolve());
 				})
 				.catch(err => reject(err));
 		}
@@ -63,21 +91,22 @@ const downloadGenesisBlock = async () => {
 };
 
 const getGenesisBlockFromFS = async () => {
-	if (!fs.existsSync(genesisBlockFilePath)) await downloadGenesisBlock();
-
-	const genesisBlock = await new Promise((resolve, reject) => {
-		fs.readFile(genesisBlockFilePath, (err, data) => {
-			if (err) {
-				logger.error(err);
-				return reject(err);
-			}
-			const parsedGenesisBlock = JSON.parse(data.toString());
-			return resolve(parsedGenesisBlock);
+	if (!genesisBlockURL || !genesisBlockFilePath) await loadConfig();
+	if (!getGenesisBlockId()) {
+		if (!fs.existsSync(genesisBlockFilePath)) {
+			await downloadGenesisBlock();
+			readStream = fs.createReadStream(genesisBlockFilePath);
+		}
+
+		const block = await new Promise((resolve, reject) => {
+			readStream.pipe(parseStream.on('data', (data) => resolve(data)));
+			parseStream.on('error', (err) => reject(err));
 		});
-	});
 
-	if (!getGenesisBlockId()) setGenesisBlockId(genesisBlock.header.id);
-	return genesisBlock;
+		if (!getGenesisBlockId()) setGenesisBlock(block);
+	}
+
+	return getGenesisBlock();
 };
 
 module.exports = {
diff --git a/services/core/shared/core/compat/sdk_v5/coreApi.js b/services/core/shared/core/compat/sdk_v5/coreApi.js
index 114b7c7230..24fdbea554 100644
--- a/services/core/shared/core/compat/sdk_v5/coreApi.js
+++ b/services/core/shared/core/compat/sdk_v5/coreApi.js
@@ -22,10 +22,14 @@ const {
 	getGenesisBlockId,
 	getGenesisBlockFromFS,
 } = require('./blocksUtils');
-const { getApiClient } = require('../common/wsRequest');
 
-const { genesisHeight } = require('../../../../config');
+const {
+	getApiClient,
+} = require('../common/wsRequest');
+
+const config = require('../../../../config');
 
+let genesisHeight;
 const logger = Logger();
 const timeoutMessage = 'Response not received in';
 
@@ -43,16 +47,27 @@ const getNetworkStatus = async () => {
 	}
 };
 
+const getGenesisHeight = async () => {
+	if (!genesisHeight) {
+		// Determine genesis height
+		const { data: { networkIdentifier } } = await getNetworkStatus();
+		const [networkConfig = {}] = config.network.filter(c => c.identifier === networkIdentifier);
+		genesisHeight = Number(networkConfig.genesisHeight || 0);
+	}
+	return genesisHeight;
+};
+
 const getBlockByID = async id => {
 	try {
+		// File based Genesis block handling
+		if (id === getGenesisBlockId()) return { data: [await getGenesisBlockFromFS()] };
+
 		const apiClient = await getApiClient();
 		const block = await apiClient.block.get(id);
 		return { data: [block] };
 	} catch (err) {
 		if (err.message.includes(timeoutMessage)) {
 			await getApiClient();
-			// File based Genesis block handling
-			if (id === getGenesisBlockId()) return { data: [await getGenesisBlockFromFS()] };
 			throw new TimeoutException(`Request timed out when calling 'getBlocksByID' for ID: ${id}`);
 		}
 		throw err;
@@ -61,6 +76,19 @@ const getBlockByID = async id => {
 
 const getBlocksByIDs = async ids => {
 	try {
+		// File based Genesis block handling
+		const genesisBlockId = getGenesisBlockId();
+		if (ids.includes(genesisBlockId)) {
+			const remainingIds = ids.filter(id => id !== genesisBlockId);
+			const genesisBlockResult = await getBlockByID(genesisBlockId);
+			if (remainingIds.length) {
+				const { data: [genesisBlock] } = genesisBlockResult;
+				const { data: [...remainingBlocks] } = await getBlocksByIDs(remainingIds);
+				return { data: [genesisBlock, ...remainingBlocks] };
+			}
+			return genesisBlockResult;
+		}
+
 		const apiClient = await getApiClient();
 		const encodedBlocks = await apiClient._channel.invoke('app:getBlocksByIDs', { ids });
 		const blocks = encodedBlocks.map(blk => apiClient.block.decode(Buffer.from(blk, 'hex')));
@@ -68,18 +96,6 @@ const getBlocksByIDs = async ids => {
 	} catch (err) {
 		if (err.message.includes(timeoutMessage)) {
 			await getApiClient();
-			const genesisBlockId = getGenesisBlockId();
-			// File based Genesis block handling
-			if (ids.includes(genesisBlockId)) {
-				const remainingIds = ids.filter(id => id !== genesisBlockId);
-				const genesisBlockResult = await getBlockByID(genesisBlockId);
-				if (remainingIds.length) {
-					const { data: [genesisBlock] } = genesisBlockResult;
-					const { data: [...remainingBlocks] } = await getBlocksByIDs(remainingIds);
-					return { data: [genesisBlock, ...remainingBlocks] };
-				}
-				return genesisBlockResult;
-			}
 			throw new TimeoutException(`Request timed out when calling 'getBlocksByIDs' for IDs: ${ids}`);
 		}
 		throw err;
@@ -88,15 +104,20 @@ const getBlocksByIDs = async ids => {
 
 const getBlockByHeight = async height => {
 	try {
+		// File based Genesis block handling
+		if (getGenesisBlockId() && Number(height) === await getGenesisHeight()) {
+			return { data: [await getGenesisBlockFromFS()] };
+		}
+
 		const apiClient = await getApiClient();
 		const block = await apiClient.block.getByHeight(height);
 		return { data: [block] };
 	} catch (err) {
 		if (err.message.includes(timeoutMessage)) {
 			await getApiClient();
-			// File based Genesis block handling
+			// Download to the FS & return the genesis block
 			// eslint-disable-next-line max-len
-			if (Number(height) === Number(genesisHeight)) return { data: [await getGenesisBlockFromFS()] };
+			if (Number(height) === await getGenesisHeight()) return { data: [await getGenesisBlockFromFS()] };
 			throw new TimeoutException(`Request timed out when calling 'getBlockByHeight' for height: ${height}`);
 		}
 		throw err;
@@ -105,6 +126,17 @@ const getBlockByHeight = async height => {
 
 const getBlocksByHeightBetween = async (from, to) => {
 	try {
+		// File based Genesis block handling
+		if (getGenesisBlockId() && Number(from) === await getGenesisHeight()) {
+			const genesisBlockResult = await getBlockByHeight(from);
+			if (from < to) {
+				const { data: [genesisBlock] } = genesisBlockResult;
+				const { data: [...remainingBlocks] } = await getBlocksByHeightBetween(from + 1, to);
+				return { data: [genesisBlock, ...remainingBlocks] };
+			}
+			return genesisBlockResult;
+		}
+
 		const apiClient = await getApiClient();
 		const encodedBlocks = await apiClient._channel.invoke('app:getBlocksByHeightBetween', { from, to });
 		const blocks = encodedBlocks.map(blk => apiClient.block.decode(Buffer.from(blk, 'hex')));
@@ -112,16 +144,6 @@ const getBlocksByHeightBetween = async (from, to) => {
 	} catch (err) {
 		if (err.message.includes(timeoutMessage)) {
 			await getApiClient();
-			// File based Genesis block handling
-			if (Number(from) === Number(genesisHeight)) {
-				const genesisBlockResult = await getBlockByHeight(from);
-				if (from < to) {
-					const { data: [genesisBlock] } = genesisBlockResult;
-					const { data: [...remainingBlocks] } = await getBlocksByHeightBetween(from + 1, to);
-					return { data: [genesisBlock, ...remainingBlocks] };
-				}
-				return genesisBlockResult;
-			}
 			throw new TimeoutException(`Request timed out when calling 'getBlocksByHeightBetween' for heights: ${from} - ${to}`);
 		}
 		throw err;
@@ -290,6 +312,7 @@ const getTransactionsSchemas = async () => {
 };
 
 module.exports = {
+	getGenesisHeight,
 	getBlockByID,
 	getBlocksByIDs,
 	getBlockByHeight,
diff --git a/services/core/shared/core/delegates.js b/services/core/shared/core/delegates.js
index c5171e12d2..cc897b433a 100644
--- a/services/core/shared/core/delegates.js
+++ b/services/core/shared/core/delegates.js
@@ -250,10 +250,11 @@ const reload = async () => {
 };
 
 // Keep the delegate cache up-to-date
-Signals.get('newBlock').add(async data => {
+const updateDelegateListEveryBlock = () => Signals.get('newBlock').add(async data => {
 	const dposModuleId = 5;
-	const voteDelegateAssetId = 1;
 	const registerDelegateAssetId = 0;
+	const voteDelegateAssetId = 1;
+
 	const updatedDelegateAddresses = [];
 	const [block] = data.data;
 	if (block && block.payload) {
@@ -268,20 +269,26 @@ Signals.get('newBlock').add(async data => {
 				}
 			}
 		});
+
 		const { data: updatedDelegateAccounts } = await coreApi
 			.getAccounts({ addresses: updatedDelegateAddresses });
+
 		updatedDelegateAccounts.forEach(delegate => {
 			const delegateIndex = delegateList.findIndex(acc => acc.address === delegate.address);
 			if (delegateIndex === -1) delegateList.push(delegate);
 			else delegateList[delegateIndex] = delegate;
 		});
+
 		// Rank is impacted only when a delegate gets (un-)voted
 		if (updatedDelegateAddresses.length) await computeDelegateRank();
 	}
 });
 
 // Reload the delegate cache when all the indexes are up-to-date
-Signals.get('blockIndexReady').add(() => reload());
+const refreshDelegateListOnIndexReady = () => Signals.get('blockIndexReady').add(() => reload());
+
+updateDelegateListEveryBlock();
+refreshDelegateListOnIndexReady();
 
 module.exports = {
 	reloadDelegateCache: reload,
diff --git a/services/core/shared/core/peerCache.js b/services/core/shared/core/peerCache.js
index 6c46dd707f..00f63b2d15 100644
--- a/services/core/shared/core/peerCache.js
+++ b/services/core/shared/core/peerCache.js
@@ -88,17 +88,21 @@ const getStatistics = () => peerStore.statistics;
 
 const reload = async () => {
 	logger.debug('Refreshing peer cache...');
-	if (sdkVersion <= 4) {
-		peerStore.peers = await requestAll(coreApi.getPeers, {});
-	} else {
-		peerStore.peers = (await coreApi.getPeers()).data;
+	try {
+		if (sdkVersion <= 4) {
+			peerStore.peers = await requestAll(coreApi.getPeers, {});
+		} else {
+			peerStore.peers = (await coreApi.getPeers()).data;
+		}
+		peerStore.connected = peerStore.peers.filter(o => o.state === peerStates.CONNECTED);
+		peerStore.disconnected = peerStore.peers.filter(o => o.state === peerStates.DISCONNECTED);
+		peerStore.statistics = await refreshStatistics();
+		logger.debug('Updated peer cache.');
+		logger.debug(`============== 'peerReload' signal: ${Signals.get('peerReload')} ==============`);
+		Signals.get('peerReload').dispatch(peerStore.peers);
+	} catch (err) {
+		logger.debug(`Unable to reload peer cache: ${err.message}`);
 	}
-	peerStore.connected = peerStore.peers.filter(o => o.state === peerStates.CONNECTED);
-	peerStore.disconnected = peerStore.peers.filter(o => o.state === peerStates.DISCONNECTED);
-	peerStore.statistics = await refreshStatistics();
-	logger.debug('Updated peer cache.');
-	logger.debug(`============== 'peerReload' signal: ${Signals.get('peerReload')} ==============`);
-	Signals.get('peerReload').dispatch(peerStore.peers);
 };
 
 module.exports = {
diff --git a/services/core/shared/knownAccounts.js b/services/core/shared/knownAccounts.js
index a95795474c..5cf659dbf6 100644
--- a/services/core/shared/knownAccounts.js
+++ b/services/core/shared/knownAccounts.js
@@ -36,11 +36,11 @@ const getAccountKnowledge = (address) => {
 const reloadKnowledge = async () => {
 	logger.debug('Reloading known accounts...');
 
-	await waitForLastBlock();
-	const netStatus = await getNetworkStatus();
-	const { nethash } = netStatus.data.constants;
-
 	try {
+		await waitForLastBlock();
+		const netStatus = await getNetworkStatus();
+		const { nethash } = netStatus.data.constants;
+
 		const knownNetworks = await HTTP.request(`${staticUrl}/networks.json`);
 		if (knownNetworks.data[nethash]) {
 			const knownAccounts = await HTTP.request(`${staticUrl}/known_${knownNetworks.data[nethash]}.json`);