diff --git a/backend/src/interfaces/output/blocksResponse.interface.ts b/backend/src/interfaces/output/blocksResponse.interface.ts index 4f4a7f5..85a0b6f 100644 --- a/backend/src/interfaces/output/blocksResponse.interface.ts +++ b/backend/src/interfaces/output/blocksResponse.interface.ts @@ -18,6 +18,7 @@ export interface BlockResponse extends BaseBlockResponse { parentHash: string; committedInSubnet: boolean; committedInParentChain: boolean; + submittedInParentChain: boolean; } export interface BaseBlockResponse { diff --git a/backend/src/services/block.service.ts b/backend/src/services/block.service.ts index dd23c68..a44b15d 100644 --- a/backend/src/services/block.service.ts +++ b/backend/src/services/block.service.ts @@ -62,15 +62,15 @@ export class BlockService { public async getLastMinedBlocks(): Promise { const allBlocks = await this.blockStorage.getAllBlocks(); const latestMinedBlock = - allBlocks && allBlocks.length - ? { - hash: allBlocks[allBlocks.length - 1].hash, - number: allBlocks[allBlocks.length - 1].number, - } - : { - hash: "", - number: 0 - }; + allBlocks && allBlocks.length + ? { + hash: allBlocks[allBlocks.length - 1].hash, + number: allBlocks[allBlocks.length - 1].number, + } + : { + hash: '', + number: 0, + }; return latestMinedBlock; } @@ -79,9 +79,9 @@ export class BlockService { const allBlocks = await this.blockStorage.getAllBlocks(); const lastCommittedBlockInfo = await this.getLastSubnetCommittedBlock(); const lastCommittedBlock = await this.blockStorage.getMinedBlockByHash(lastCommittedBlockInfo.hash); - const endIndex = blockIndex != -1? allBlocks.findIndex((block) => block.number == blockIndex) : allBlocks.length-1; + const endIndex = blockIndex != -1 ? allBlocks.findIndex(block => block.number == blockIndex) : allBlocks.length - 1; const startIndex = endIndex - NUM_OF_BLOCKS_RETURN >= 0 ? endIndex - NUM_OF_BLOCKS_RETURN : 0; - const selectedBlocks = allBlocks.slice(startIndex, endIndex) + const selectedBlocks = allBlocks.slice(startIndex, endIndex); // Short-curcit if the committedBlock is not even recored in the system. The gap between mined and committed is too far if (!lastCommittedBlock) { @@ -89,21 +89,14 @@ export class BlockService { } const sameChainBlocks = this.filterOutForksBeforeStartingBlock(selectedBlocks, lastCommittedBlock); - const { committed } = await this.getLastParentchainSubnetBlock(); + const { committed, submitted } = await this.getLastParentchainSubnetBlock(); return sameChainBlocks.map(b => { - let committedInSubnet = false; - let committedInParentChain = false; - if (b.number <= lastCommittedBlockInfo.number) { - committedInSubnet = true; - } - if (b.number <= committed.height) { - committedInParentChain = true; - } return { ...b, - committedInSubnet, - committedInParentChain, + committedInSubnet: b.number <= lastCommittedBlockInfo.number, + committedInParentChain: b.number <= committed.height, + submittedInParentChain: b.number <= submitted.height, }; }); } @@ -127,7 +120,7 @@ export class BlockService { public async getLastParentchainSubnetBlock() { const { smartContractCommittedHash, smartContractCommittedHeight, smartContractHash, smartContractHeight } = - await this.parentChainClient.getLastAudittedBlock(); + await this.getAndSetLastSubmittedBlockInfo(); return { committed: { height: smartContractCommittedHeight, @@ -217,7 +210,7 @@ export class BlockService { } private async getSmartContractProcessingInfo(): Promise<{ processedUntil: number; isProcessing: boolean }> { - const { smartContractHeight, smartContractCommittedHash } = await this.parentChainClient.getLastAudittedBlock(); + const { smartContractHeight, smartContractCommittedHash } = await this.getAndSetLastSubmittedBlockInfo(); const { timestamp } = await this.parentChainClient.getParentChainBlockBySubnetHash(smartContractCommittedHash); let isProcessing = true; const timeDiff = new Date().getTime() / 1000 - parseInt(timestamp.toString()); @@ -229,6 +222,17 @@ export class BlockService { }; } + private async getAndSetLastSubmittedBlockInfo() { + const lastSubmittedBlockInfo = await this.blockStorage.getLastSubmittedBlockInfo(); + // Not exist, we need to call the parentchain node and set the value + if (!lastSubmittedBlockInfo) { + const result = await this.parentChainClient.getLastAudittedBlock(); + await this.blockStorage.setLastSubmittedToParentchainBlockInfo(result); + return result; + } + return lastSubmittedBlockInfo; + } + /** In order to insert into the queue. we need it satisfy any of the below condition @@ -260,7 +264,7 @@ export class BlockService { } const lastBLock = chainToFilter[chainToFilter.length - 1]; - const startingPointer = startingBlock && startingBlock.number <= lastBLock.number? startingBlock : lastBLock; + const startingPointer = startingBlock && startingBlock.number <= lastBLock.number ? startingBlock : lastBLock; const onChainHash = [startingPointer.hash]; let parentHashPointer = startingPointer.parentHash; // Track back through the parentChain hash, if found then mark them as on the same chain @@ -287,6 +291,7 @@ export class BlockService { ...b, committedInSubnet: false, committedInParentChain: false, + submittedInParentChain: false, }; }); } diff --git a/backend/src/storage/block.ts b/backend/src/storage/block.ts index fae3de9..bce5b3c 100644 --- a/backend/src/storage/block.ts +++ b/backend/src/storage/block.ts @@ -1,3 +1,4 @@ +import { SmartContractAuditedBlockInfo } from '../client/parentchain'; import { MAX_NUM_OF_BLOCKS_IN_HISTORY } from '../config'; import { Db } from './base'; @@ -5,8 +6,10 @@ const TYPE = 'BLOCK'; // In case of no new blocks in 60s, we declare the block componenet of the system is not operational const STATUS_KEY = 'BLOCK_STATUS'; const TTL = 60; +const CHECK_PARENTCHAIN_TTL = 2; const LATEST_COMMITTEDBLOCK_KEY = 'LATEST_COMMITTED_BLOCK'; +const LATEST_PARENTCHAIN_SUBMITTED_KEY = 'LATEST_PARENTCHAIN_SUBMITTED_BLOCKINFO'; /** This class is created so that we can easily swap with real DB without making changes to any other files. @@ -58,6 +61,14 @@ export class BlockStorage { async getStatus(): Promise { return this.db.get(STATUS_KEY) || false; } + + async getLastSubmittedBlockInfo(): Promise { + return this.db.get(LATEST_PARENTCHAIN_SUBMITTED_KEY); + } + + async setLastSubmittedToParentchainBlockInfo(blockInfo: SmartContractAuditedBlockInfo) { + this.db.set(LATEST_PARENTCHAIN_SUBMITTED_KEY, blockInfo, CHECK_PARENTCHAIN_TTL); + } } export interface StoredBlock { diff --git a/backend/swagger.yaml b/backend/swagger.yaml index 3bd933c..f4b2a5e 100644 --- a/backend/swagger.yaml +++ b/backend/swagger.yaml @@ -356,11 +356,15 @@ definitions: committedInParentChain: description: This boolean value is to indicate whether this block has been confirmed in the parent chain smart contract type: boolean + submittedInParentChain: + description: This boolean value is to indicate whether this block has been submitted in the parent chain smart contract and waiting for the confirmation + type: boolean required: - hash - number - committedInParentChain - committedInSubnet + - submittedInParentChain schemes: - https