Lisk-sdk: Split block processing steps into separate functions and expose them from module/blocks

Created on 26 Jun 2019  路  5Comments  路  Source: LiskHQ/lisk-sdk

Expected behavior

Block processing includes block and transactions validation, verification and applying into the blockchain. Each step is an expensive operation and should be called only once for each block. As part of BFT, we execute these steps at different stages, and block processing should allow calling these functions independently.

Actual behavior

process.js file only exports applyBlock and processBlock functions which encapsulate all the work related to validating, verifying and applying a block. It does not allow executing these steps separately.

Which version(s) does this affect? (Environment, OS, etc...)

feature/introduce_bft_consensus

framewornode

Most helpful comment

While at this I would also encapsulate this methods in different objects so we can switch between different processing models on the fly.

All 5 comments

This could be a way of implementing this based on the steps defined in the section Processing Blocks of LIP-0014:

    async _validateAndVerifyInMemory(block, lastBlock, broadcast) {
        const enhancedBlock = !broadcast
            ? blocksUtils.addBlockProperties(block)
            : block;
        const normalizedBlock = blocksLogic.objectNormalize(
            enhancedBlock,
            this.exceptions
        );
        const { verified, errors } = this.blocksVerify.verifyBlock(
            normalizedBlock,
            lastBlock
        );
        await this.blocksVerify.validateBlockSlot(normalizedBlock);
    }

    async _verifyBlockAgainsState() {
        await this.blocksVerify.checkExists(normalizedBlock); // Step 4
        await this.blocksVerify.checkTransactions(normalizedBlock); // Step 4
    }

    async processValidatedBlock(block, lastBlock, broadcast) {
        this.BFTConsensusManager.validateBlockHeader(block); //Step 2

        if (typeof broadcast === 'function') {
            broadcast(normalizedBlock); // Step3
        }

        await this.verifyBlockAgainsState(); // Step4
        await this.blocksChain.applyBlock(normalizedBlock, true); // Step 5

        this.BFTConsensusManager.addBlockHeader(
            normalizedBlock
        ); // Step 6: Compute prevotes and precommits

        this.channel.publish('chain:blocks:processing:succeeded', {
            block: {
                id: block.id,
                height: block.height,
                heightPrevoted: block.heightPrevoted
            }
        });

        return normalizedBlock;
    }

    async processBlock(block, lastBlock, broadcast) {
        const validatedVerifiedBlock = this._validateAndVerifyInMemory(block, lastBlock); // Step 1
        this.processValidatedBlock(validatedVerifiedBlock, lastBlock, broadcast);
    }

While at this I would also encapsulate this methods in different objects so we can switch between different processing models on the fly.

Absolutely, something like blocks processing v2 having processV2.js or similar to achieve what Pablo said.

Absolutely, something like blocks processing v2 having processV2.js or similar to achieve what Pablo said.

Check this out https://github.com/pablitovicente/random_experiments/tree/master/strategy_test (gist does not support folders so I just created a repo but we can move somewhere else :) )

https://github.com/LiskHQ/lisk-sdk/blob/4797f8d7c4a4d245e69c8531139b00018da4fc20/framework/src/modules/chain/blocks/process.js#L46-L89

processBlocks funciton does everything that applyBlock function does. So, can we get rid of applyBlock @SargeKhan ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ScrewchMcMuffin picture ScrewchMcMuffin  路  3Comments

hendrikhofstadt picture hendrikhofstadt  路  4Comments

Isabello picture Isabello  路  4Comments

ManuGowda picture ManuGowda  路  3Comments

Nazgolze picture Nazgolze  路  3Comments