Skip to content

Commit

Permalink
Merge pull request #918 from ethereumjs/update-header-validation-methods
Browse files Browse the repository at this point in the history
BlockHeader Validation Method Changes / Corresponding Block Methods
  • Loading branch information
holgerd77 committed Oct 21, 2020
2 parents d5560d8 + 7206ea2 commit 244db75
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 35 deletions.
12 changes: 12 additions & 0 deletions packages/block/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ try {
}
```

### Header Validation Methods > Signature Changes

**Breaking**: The signatures of the following header validation methods have been updated to take a `parentBlockHeader` instead of a
`parentBlock` input parameter for consistency and removing a circling dependency with `Block`:

- `BlockHeader.canonicalDifficulty(parentBlockHeader: BlockHeader): BN`
- `BlockHeader.validateDifficulty(parentBlockHeader: BlockHeader): boolean`
- `BlockHeader.validateGasLimit(parentBlockHeader: BlockHeader): boolean`

On the `Block` library new corresponding methods have been added which both operate on a block instance and expect a `parentBlock`
as an input parameter.

### New Default Hardfork

**Breaking:** The default HF on the library has been updated from `petersburg` to `instanbul`, see PR [#906](https://github.com/ethereumjs/ethereumjs-vm/pull/906).
Expand Down
29 changes: 28 additions & 1 deletion packages/block/src/block.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-dupe-class-members */

import { BaseTrie as Trie } from 'merkle-patricia-tree'
import { rlp, keccak256, KECCAK256_RLP } from 'ethereumjs-util'
import { BN, rlp, keccak256, KECCAK256_RLP } from 'ethereumjs-util'
import Common from '@ethereumjs/common'
import { Transaction, TxOptions } from '@ethereumjs/tx'
import { BlockHeader } from './header'
Expand Down Expand Up @@ -237,6 +237,33 @@ export class Block {
}
}

/**
* Returns the canonical difficulty for this block.
*
* @param parentBlock - the parent of this `Block`
*/
canonicalDifficulty(parentBlock: Block): BN {
return this.header.canonicalDifficulty(parentBlock.header)
}

/**
* Checks that the block's `difficulty` matches the canonical difficulty.
*
* @param parentBlock - the parent of this `Block`
*/
validateDifficulty(parentBlock: Block): boolean {
return this.header.validateDifficulty(parentBlock.header)
}

/**
* Validates the gasLimit.
*
* @param parentBlock - the parent of this `Block`
*/
validateGasLimit(parentBlock: Block): boolean {
return this.header.validateGasLimit(parentBlock.header)
}

/**
* Returns the block in JSON format.
*/
Expand Down
45 changes: 24 additions & 21 deletions packages/block/src/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
zeros,
} from 'ethereumjs-util'
import { HeaderData, JsonHeader, BlockHeaderBuffer, Blockchain, BlockOptions } from './types'
import { Block } from './block'

const DEFAULT_GAS_LIMIT = new BN(Buffer.from('ffffffffffffff', 'hex'))

Expand Down Expand Up @@ -257,12 +256,12 @@ export class BlockHeader {
/**
* Returns the canonical difficulty for this block.
*
* @param parentBlock - the parent `Block` of this header
* @param parentBlockHeader - the header from the parent `Block` of this header
*/
canonicalDifficulty(parentBlock: Block): BN {
canonicalDifficulty(parentBlockHeader: BlockHeader): BN {
const hardfork = this._getHardfork()
const blockTs = this.timestamp
const { timestamp: parentTs, difficulty: parentDif } = parentBlock.header
const { timestamp: parentTs, difficulty: parentDif } = parentBlockHeader
const minimumDifficulty = new BN(
this._common.paramByHardfork('pow', 'minimumDifficulty', hardfork)
)
Expand All @@ -276,7 +275,7 @@ export class BlockHeader {

if (this._common.hardforkGteHardfork(hardfork, 'byzantium')) {
// max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99) (EIP100)
const uncleAddend = parentBlock.header.uncleHash.equals(KECCAK256_RLP_ARRAY) ? 1 : 2
const uncleAddend = parentBlockHeader.uncleHash.equals(KECCAK256_RLP_ARRAY) ? 1 : 2
let a = blockTs.sub(parentTs).idivn(9).ineg().iaddn(uncleAddend)
const cutoff = new BN(-99)
// MAX(cutoff, a)
Expand Down Expand Up @@ -341,19 +340,19 @@ export class BlockHeader {
/**
* Checks that the block's `difficulty` matches the canonical difficulty.
*
* @param parentBlock - this block's parent
* @param parentBlockHeader - the header from the parent `Block` of this header
*/
validateDifficulty(parentBlock: Block): boolean {
return this.canonicalDifficulty(parentBlock).eq(this.difficulty)
validateDifficulty(parentBlockHeader: BlockHeader): boolean {
return this.canonicalDifficulty(parentBlockHeader).eq(this.difficulty)
}

/**
* Validates the gasLimit.
*
* @param parentBlock - this block's parent
* @param parentBlockHeader - the header from the parent `Block` of this header
*/
validateGasLimit(parentBlock: Block): boolean {
const parentGasLimit = parentBlock.header.gasLimit
validateGasLimit(parentBlockHeader: BlockHeader): boolean {
const parentGasLimit = parentBlockHeader.gasLimit
const gasLimit = this.gasLimit
const hardfork = this._getHardfork()

Expand Down Expand Up @@ -387,31 +386,31 @@ export class BlockHeader {
}

if (blockchain) {
const parentBlock = await this._getBlockByHash(blockchain, this.parentHash)
const header = await this._getHeaderByHash(blockchain, this.parentHash)

if (!parentBlock) {
throw new Error('could not find parent block')
if (!header) {
throw new Error('could not find parent header')
}

const { number } = this
if (!number.eq(parentBlock.header.number.addn(1))) {
if (!number.eq(header.number.addn(1))) {
throw new Error('invalid number')
}

if (this.timestamp.lte(parentBlock.header.timestamp)) {
if (this.timestamp.lte(header.timestamp)) {
throw new Error('invalid timestamp')
}

if (!this.validateDifficulty(parentBlock)) {
if (!this.validateDifficulty(header)) {
throw new Error('invalid difficulty')
}

if (!this.validateGasLimit(parentBlock)) {
if (!this.validateGasLimit(header)) {
throw new Error('invalid gas limit')
}

if (height) {
const dif = height.sub(parentBlock.header.number)
const dif = height.sub(header.number)
if (!(dif.cmpn(8) === -1 && dif.cmpn(1) === 1)) {
throw new Error('uncle block has a parent that is too old or too young')
}
Expand Down Expand Up @@ -490,9 +489,13 @@ export class BlockHeader {
return this._common.hardfork() || this._common.activeHardfork(this.number.toNumber())
}

private async _getBlockByHash(blockchain: Blockchain, hash: Buffer): Promise<Block | undefined> {
private async _getHeaderByHash(
blockchain: Blockchain,
hash: Buffer
): Promise<BlockHeader | undefined> {
try {
return blockchain.getBlock(hash)
const header = (await blockchain.getBlock(hash)).header
return header
} catch (error) {
if (error.type === 'NotFoundError') {
return undefined
Expand Down
4 changes: 2 additions & 2 deletions packages/block/test/difficulty.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ tape('[Header]: difficulty tests', (t) => {
function runDifficultyTests(test: any, parentBlock: Block, block: Block, msg: string) {
normalize(test)

const dif = block.header.canonicalDifficulty(parentBlock)
const dif = block.canonicalDifficulty(parentBlock)
t.equal(dif.toString(), test.currentDifficulty.toString(), `test canonicalDifficulty (${msg})`)
t.assert(block.header.validateDifficulty(parentBlock), `test validateDifficulty (${msg})`)
t.assert(block.validateDifficulty(parentBlock), `test validateDifficulty (${msg})`)
}

const hardforkTestData: any = {
Expand Down
2 changes: 1 addition & 1 deletion packages/block/test/header.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ tape('[Block]: Header functions', function (t) {
const parentBlock = Block.fromRLPSerializedBlock(genesisRlp)
const blockRlp = bcBlockGasLimitTestData[key].blocks[0].rlp
const block = Block.fromRLPSerializedBlock(blockRlp)
st.equal(block.header.validateGasLimit(parentBlock), true)
st.equal(block.validateGasLimit(parentBlock), true)
})

st.end()
Expand Down
18 changes: 9 additions & 9 deletions packages/blockchain/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ tape('blockchain test', (t) => {
header: {
number,
parentHash: lastBlock.hash(),
difficulty: lastBlock.header.canonicalDifficulty(lastBlock),
difficulty: lastBlock.canonicalDifficulty(lastBlock),
timestamp: lastBlock.header.timestamp.addn(1),
gasLimit,
},
Expand Down Expand Up @@ -118,7 +118,7 @@ tape('blockchain test', (t) => {
header: {
number: 1,
parentHash: genesis.hash(),
difficulty: genesis.header.canonicalDifficulty(genesis),
difficulty: genesis.canonicalDifficulty(genesis),
timestamp: genesis.header.timestamp.addn(1),
gasLimit,
},
Expand Down Expand Up @@ -377,7 +377,7 @@ tape('blockchain test', (t) => {
const headerData = {
number: 15,
parentHash: blocks[14].hash(),
difficulty: blocks[14].header.canonicalDifficulty(blocks[14]),
difficulty: blocks[14].canonicalDifficulty(blocks[14]),
gasLimit: 8000000,
timestamp: blocks[14].header.timestamp.addn(1),
}
Expand All @@ -400,7 +400,7 @@ tape('blockchain test', (t) => {
const headerData = {
number: 15,
parentHash: blocks[14].hash(),
difficulty: blocks[14].header.canonicalDifficulty(blocks[14]),
difficulty: blocks[14].canonicalDifficulty(blocks[14]),
gasLimit: 8000000,
timestamp: blocks[14].header.timestamp.addn(1),
}
Expand Down Expand Up @@ -558,7 +558,7 @@ tape('blockchain test', (t) => {
const headerData = {
number: 1,
parentHash: genesis.hash(),
difficulty: genesis.header.canonicalDifficulty(genesis),
difficulty: genesis.canonicalDifficulty(genesis),
gasLimit,
timestamp: genesis.header.timestamp.addn(1),
}
Expand Down Expand Up @@ -595,7 +595,7 @@ tape('blockchain test', (t) => {
header: {
number: 1,
parentHash: genesis.hash(),
difficulty: genesis.header.canonicalDifficulty(genesis),
difficulty: genesis.canonicalDifficulty(genesis),
timestamp: genesis.header.timestamp.addn(3),
gasLimit,
},
Expand All @@ -605,7 +605,7 @@ tape('blockchain test', (t) => {
const headerData1 = {
number: 1,
parentHash: genesis.hash(),
difficulty: genesis.header.canonicalDifficulty(genesis),
difficulty: genesis.canonicalDifficulty(genesis),
timestamp: genesis.header.timestamp.addn(1),
gasLimit,
}
Expand All @@ -615,7 +615,7 @@ tape('blockchain test', (t) => {
const headerData2 = {
number: 2,
parentHash: header1.hash(),
difficulty: header1.canonicalDifficulty(block),
difficulty: header1.canonicalDifficulty(block.header),
timestamp: header1.timestamp.addn(1),
gasLimit,
}
Expand Down Expand Up @@ -655,7 +655,7 @@ tape('blockchain test', (t) => {
header: {
number: 1,
parentHash: genesis.hash(),
difficulty: genesis.header.canonicalDifficulty(genesis),
difficulty: genesis.canonicalDifficulty(genesis),
timestamp: genesis.header.timestamp.addn(1),
gasLimit,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/blockchain/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const generateBlocks = (numberOfBlocks: number, existingBlocks?: Block[])
header: {
number: i,
parentHash: lastBlock.hash(),
difficulty: lastBlock.header.canonicalDifficulty(lastBlock),
difficulty: lastBlock.canonicalDifficulty(lastBlock),
gasLimit,
timestamp: lastBlock.header.timestamp.addn(1),
},
Expand Down

0 comments on commit 244db75

Please sign in to comment.