From cfecb238014492ead4f4e3c639702501137fbcd1 Mon Sep 17 00:00:00 2001 From: supaiku Date: Fri, 22 Feb 2019 16:20:12 +0100 Subject: [PATCH 1/2] fix: stuck at not ready to accept block --- packages/core-blockchain/src/blockchain.ts | 6 +- .../processor/handlers/unchained-handler.ts | 55 ++++++++++++++++++- .../src/utils/validate-generator.ts | 2 + 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/core-blockchain/src/blockchain.ts b/packages/core-blockchain/src/blockchain.ts index 6650fcd992..ef959d8f9f 100644 --- a/packages/core-blockchain/src/blockchain.ts +++ b/packages/core-blockchain/src/blockchain.ts @@ -481,9 +481,13 @@ export class Blockchain implements blockchain.IBlockchain { /** * Fork the chain at the given block. */ - public forkBlock(block: models.Block): void { + public forkBlock(block: models.Block, numberOfBlockToRollback?: number): void { this.state.forkedBlock = block; + if (numberOfBlockToRollback) { + this.state.numberOfBlocksToRollback = numberOfBlockToRollback; + } + this.dispatch("FORK"); } diff --git a/packages/core-blockchain/src/processor/handlers/unchained-handler.ts b/packages/core-blockchain/src/processor/handlers/unchained-handler.ts index f706288a43..e41dddf48b 100644 --- a/packages/core-blockchain/src/processor/handlers/unchained-handler.ts +++ b/packages/core-blockchain/src/processor/handlers/unchained-handler.ts @@ -1,3 +1,5 @@ +// tslint:disable:max-classes-per-file + import { app } from "@arkecosystem/core-container"; import { models } from "@arkecosystem/crypto"; import { Blockchain } from "../../blockchain"; @@ -6,6 +8,7 @@ import { BlockHandler } from "./block-handler"; enum UnchainedBlockStatus { NotReadyToAcceptNewHeight, + ExceededNotReadyToAcceptNewHeightMaxAttempts, AlreadyInBlockchain, EqualToLastBlock, GeneratorMismatch, @@ -13,7 +16,40 @@ enum UnchainedBlockStatus { InvalidTimestamp, } +class BlockNotReadyCounter { + public static maxAttempts = 5; + + private id = ""; + private attempts = 0; + + public increment(block: models.Block): boolean { + const { id } = block.data; + let attemptsLeft = false; + + if (this.id !== id) { + this.reset(); + this.id = id; + } + + this.attempts += 1; + + attemptsLeft = this.attempts <= BlockNotReadyCounter.maxAttempts; + if (!attemptsLeft) { + this.reset(); + } + + return attemptsLeft; + } + + public reset() { + this.attempts = 0; + this.id = ""; + } +} + export class UnchainedHandler extends BlockHandler { + public static notReadyCounter = new BlockNotReadyCounter(); + public constructor( protected blockchain: Blockchain, protected block: models.Block, @@ -39,6 +75,11 @@ export class UnchainedHandler extends BlockHandler { return BlockProcessorResult.Rejected; } + case UnchainedBlockStatus.ExceededNotReadyToAcceptNewHeightMaxAttempts: { + this.blockchain.forkBlock(this.block, 5000); // TODO: find a better heuristic based on peer information + return BlockProcessorResult.DiscardedButCanBeBroadcasted; + } + case UnchainedBlockStatus.GeneratorMismatch: case UnchainedBlockStatus.InvalidTimestamp: { return BlockProcessorResult.Rejected; @@ -65,7 +106,19 @@ export class UnchainedHandler extends BlockHandler { this.logger.debug(`Discarded ${this.blockchain.processQueue.length()} downloaded blocks.`); } - return UnchainedBlockStatus.NotReadyToAcceptNewHeight; + // If we consecutively fail to accept the same block, our chain is likely forked. In this + // case `increment` returns false. + if (UnchainedHandler.notReadyCounter.increment(this.block)) { + return UnchainedBlockStatus.NotReadyToAcceptNewHeight; + } + + this.logger.debug( + `Blockchain is still not ready to accept block at height ${this.block.data.height.toLocaleString()} after ${ + BlockNotReadyCounter.maxAttempts + } tries. Going to rollback. :warning:`, + ); + + return UnchainedBlockStatus.ExceededNotReadyToAcceptNewHeightMaxAttempts; } else if (this.block.data.height < lastBlock.data.height) { this.logger.debug( `Block ${this.block.data.height.toLocaleString()} disregarded because already in blockchain :warning:`, diff --git a/packages/core-blockchain/src/utils/validate-generator.ts b/packages/core-blockchain/src/utils/validate-generator.ts index f517b58948..5c951a61ea 100644 --- a/packages/core-blockchain/src/utils/validate-generator.ts +++ b/packages/core-blockchain/src/utils/validate-generator.ts @@ -18,6 +18,8 @@ export const validateGenerator = async (block: models.Block): Promise = block.data.generatorPublicKey }) is allowed to forge block ${block.data.height.toLocaleString()} :grey_question:`, ); + + return false; } else if (forgingDelegate.publicKey !== block.data.generatorPublicKey) { const forgingUsername = database.walletManager.findByPublicKey(forgingDelegate.publicKey).username; From 42587a079b78f552851f9187f217cdea0ad40f5c Mon Sep 17 00:00:00 2001 From: supaiku Date: Fri, 22 Feb 2019 17:16:28 +0100 Subject: [PATCH 2/2] revert --- packages/core-blockchain/src/utils/validate-generator.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core-blockchain/src/utils/validate-generator.ts b/packages/core-blockchain/src/utils/validate-generator.ts index 5c951a61ea..f517b58948 100644 --- a/packages/core-blockchain/src/utils/validate-generator.ts +++ b/packages/core-blockchain/src/utils/validate-generator.ts @@ -18,8 +18,6 @@ export const validateGenerator = async (block: models.Block): Promise = block.data.generatorPublicKey }) is allowed to forge block ${block.data.height.toLocaleString()} :grey_question:`, ); - - return false; } else if (forgingDelegate.publicKey !== block.data.generatorPublicKey) { const forgingUsername = database.walletManager.findByPublicKey(forgingDelegate.publicKey).username;