Skip to content

Commit

Permalink
blockchain: handle nil blockbodies for backward compatibility (#3394)
Browse files Browse the repository at this point in the history
  • Loading branch information
g11tech committed May 3, 2024
1 parent 8735f48 commit d667cc8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 9 deletions.
45 changes: 39 additions & 6 deletions packages/blockchain/src/db/manager.ts
Expand Up @@ -3,8 +3,11 @@ import { RLP } from '@ethereumjs/rlp'
import {
BIGINT_0,
BIGINT_1,
KECCAK256_RLP,
KECCAK256_RLP_ARRAY,
bytesToBigInt,
bytesToHex,
equalsBytes,
unprefixedHexToBytes,
} from '@ethereumjs/util'

Expand Down Expand Up @@ -103,7 +106,40 @@ export class DBManager {

if (hash === undefined || number === undefined) return undefined
const header = await this.getHeader(hash, number)
const body = await this.getBody(hash, number)
let body = await this.getBody(hash, number)

// be backward compatible where we didn't use to store a body with no txs, uncles, withdrawals
// otherwise the body is never partially stored and if we have some body, its in entirity
if (body === undefined) {
body = [[], []] as BlockBodyBytes
// Do extra validations on the header since we are assuming empty transactions and uncles
if (!equalsBytes(header.transactionsTrie, KECCAK256_RLP)) {
throw new Error('transactionsTrie root should be equal to hash of null')
}

if (!equalsBytes(header.uncleHash, KECCAK256_RLP_ARRAY)) {
throw new Error('uncle hash should be equal to hash of empty array')
}

// If this block had empty withdrawals push an empty array in body
if (header.withdrawalsRoot !== undefined) {
// Do extra validations for withdrawal before assuming empty withdrawals
if (!equalsBytes(header.withdrawalsRoot, KECCAK256_RLP)) {
throw new Error('withdrawals root shoot be equal to hash of null when no withdrawals')
} else {
body.push([])
}
}

// If requests root exists, validate that requests array exists or insert it
if (header.requestsRoot !== undefined) {
if (!equalsBytes(header.requestsRoot, KECCAK256_RLP)) {
throw new Error('requestsRoot should be equal to hash of null when no requests')
} else {
body.push([])
}
}
}

const blockData = [header.raw(), ...body] as BlockBytes
const opts: BlockOptions = { common: this.common }
Expand All @@ -118,12 +154,9 @@ export class DBManager {
/**
* Fetches body of a block given its hash and number.
*/
async getBody(blockHash: Uint8Array, blockNumber: bigint): Promise<BlockBodyBytes> {
async getBody(blockHash: Uint8Array, blockNumber: bigint): Promise<BlockBodyBytes | undefined> {
const body = await this.get(DBTarget.Body, { blockHash, blockNumber })
if (body === undefined) {
throw Error('Body not found')
}
return RLP.decode(body) as BlockBodyBytes
return body !== undefined ? (RLP.decode(body) as BlockBodyBytes) : undefined
}

/**
Expand Down
1 change: 0 additions & 1 deletion packages/blockchain/test/blockValidation.spec.ts
Expand Up @@ -401,7 +401,6 @@ describe('EIP 7685: requests field validation tests', () => {
timestamp: blockchain.genesisBlock.header.timestamp + 1n,
gasLimit: 5000,
},
requests: [],
},
{ common }
)
Expand Down
11 changes: 9 additions & 2 deletions packages/blockchain/test/index.spec.ts
Expand Up @@ -512,14 +512,17 @@ describe('blockchain test', () => {
await blockchain.putBlock(blocks[3])
})

it('should not reconstruct nil bodies / throw', async () => {
it('should test nil bodies / throw', async () => {
const blocks = generateBlocks(3)
const blockchain = await Blockchain.create({
validateBlocks: false,
validateConsensus: false,
genesisBlock: blocks[0],
})
await blockchain.putHeader(blocks[1].header)
// Should be able to get the block
await blockchain.getBlock(BigInt(1))

const block2HeaderValuesArray = blocks[2].header.raw()

block2HeaderValuesArray[1] = new Uint8Array(32)
Expand All @@ -531,7 +534,11 @@ describe('blockchain test', () => {
await blockchain.getBlock(BigInt(2))
assert.fail('block should not be constucted')
} catch (e: any) {
assert.equal(e.message, 'Body not found', 'block not constructed from empty bodies')
assert.equal(
e.message,
'uncle hash should be equal to hash of empty array',
'block not constructed from empty bodies'
)
}
})

Expand Down

0 comments on commit d667cc8

Please sign in to comment.