Skip to content

Commit

Permalink
block, common: new block/header option hardforkByBlockNumber, removed…
Browse files Browse the repository at this point in the history
… chain/hardfork options, added Common method setHardforkByBlockNumber()
  • Loading branch information
holgerd77 committed Sep 7, 2020
1 parent 2ba5701 commit 116ea78
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 105 deletions.
34 changes: 13 additions & 21 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { BaseTrie as Trie } from 'merkle-patricia-tree'
import Common from '@ethereumjs/common'
import { BN, rlp, keccak256, KECCAK256_RLP, baToJSON } from 'ethereumjs-util'
import { BN, rlp, keccak256, KECCAK256_RLP, baToJSON, bufferToInt } from 'ethereumjs-util'
import { Transaction, TransactionOptions } from '@ethereumjs/tx'
import { BlockHeader } from './header'
import { Blockchain, BlockData, ChainOptions } from './types'
import { Blockchain, BlockData, BlockOptions } from './types'

/**
* An object that represents the block
Expand All @@ -20,31 +20,22 @@ export class Block {
* Creates a new block object
*
* @param data - The block's data.
* @param chainOptions - The network options for this block, and its header, uncle headers and txs.
* @param options - The options for this block (like the chain setup)
*/
constructor(
data: Buffer | [Buffer[], Buffer[], Buffer[]] | BlockData = {},
chainOptions: ChainOptions = {},
options: BlockOptions = {},
) {
// Checking at runtime, to prevent errors down the path for JavaScript consumers.
if (data === null) {
data = {}
}

if (chainOptions.common) {
if (chainOptions.chain !== undefined || chainOptions.hardfork !== undefined) {
throw new Error(
'Instantiation with both chainOptions.common and chainOptions.chain / chainOptions.hardfork parameter not allowed!',
)
}

this._common = chainOptions.common
if (options.common) {
this._common = options.common
} else {
const chain = chainOptions.chain ? chainOptions.chain : 'mainnet'
// TODO: Compute the hardfork based on this block's number. It can be implemented right now
// because the block number is not immutable, so the Common can get out of sync.
const hardfork = chainOptions.hardfork ? chainOptions.hardfork : null
this._common = new Common({ chain, hardfork })
const DEFAULT_CHAIN = 'mainnet'
this._common = new Common({ chain: DEFAULT_CHAIN })
}

let rawTransactions
Expand All @@ -66,17 +57,18 @@ export class Block {
rawTransactions = data.transactions || []
rawUncleHeaders = data.uncleHeaders || []
}
if (options.hardforkByBlockNumer) {
this._common.setHardforkByBlockNumber(bufferToInt(this.header.number))
}

// parse uncle headers
for (let i = 0; i < rawUncleHeaders.length; i++) {
this.uncleHeaders.push(new BlockHeader(rawUncleHeaders[i], chainOptions))
this.uncleHeaders.push(new BlockHeader(rawUncleHeaders[i], options))
}

// parse transactions
for (let i = 0; i < rawTransactions.length; i++) {
// TODO: Pass the common object instead of the options. It can't be implemented right now
// because the hardfork may be `null`. Read the above TODO for more info.
const tx = new Transaction(rawTransactions[i], chainOptions as TransactionOptions)
const tx = new Transaction(rawTransactions[i], { common: this._common })
this.transactions.push(tx)
}
}
Expand Down
16 changes: 6 additions & 10 deletions packages/block/src/from-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FakeTransaction, TransactionOptions } from '@ethereumjs/tx'
import { toBuffer, setLengthLeft } from 'ethereumjs-util'
import { Block, ChainOptions } from './index'
import { Block, BlockOptions } from './index'

import blockHeaderFromRpc from './header-from-rpc'

Expand All @@ -11,22 +11,18 @@ import blockHeaderFromRpc from './header-from-rpc'
* @param uncles - Optional list of Ethereum JSON RPC of uncles (eth_getUncleByBlockHashAndIndex)
* @param chainOptions - An object describing the blockchain
*/
export default function blockFromRpc(
blockParams: any,
uncles?: any[],
chainOptions?: ChainOptions,
) {
export default function blockFromRpc(blockParams: any, uncles?: any[], options?: BlockOptions) {
uncles = uncles || []

const header = blockHeaderFromRpc(blockParams, chainOptions)
const header = blockHeaderFromRpc(blockParams, options)

const block = new Block(
{
header: header.toJSON(true),
transactions: [],
uncleHeaders: uncles.map((uh) => blockHeaderFromRpc(uh, chainOptions).toJSON(true)),
uncleHeaders: uncles.map((uh) => blockHeaderFromRpc(uh, options).toJSON(true)),
},
chainOptions,
options,
)

if (blockParams.transactions) {
Expand All @@ -36,7 +32,7 @@ export default function blockFromRpc(
const fromAddress = toBuffer(txParams.from)
delete txParams.from

const tx = new FakeTransaction(txParams, chainOptions as TransactionOptions)
const tx = new FakeTransaction(txParams, options as TransactionOptions)
tx.from = fromAddress
tx.getSenderAddress = function () {
return fromAddress
Expand Down
6 changes: 3 additions & 3 deletions packages/block/src/header-from-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { BlockHeader } from './header'
import { KECCAK256_NULL, toBuffer } from 'ethereumjs-util'
import { ChainOptions } from './types'
import { BlockOptions } from './types'

/**
* Creates a new block header object from Ethereum JSON RPC.
*
* @param blockParams - Ethereum JSON RPC of block (eth_getBlockByNumber)
* @param chainOptions - An object describing the blockchain
*/
export default function blockHeaderFromRpc(blockParams: any, chainOptions?: ChainOptions) {
export default function blockHeaderFromRpc(blockParams: any, options?: BlockOptions) {
const blockHeader = new BlockHeader(
{
parentHash: blockParams.parentHash,
Expand All @@ -27,7 +27,7 @@ export default function blockHeaderFromRpc(blockParams: any, chainOptions?: Chai
mixHash: blockParams.mixHash,
nonce: blockParams.nonce,
},
chainOptions,
options,
)

// override hash in case something was missing
Expand Down
23 changes: 9 additions & 14 deletions packages/block/src/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
bufferToInt,
rlphash,
} from 'ethereumjs-util'
import { Blockchain, BlockHeaderData, BufferLike, ChainOptions, PrefixedHexString } from './types'
import { Blockchain, BlockHeaderData, BufferLike, BlockOptions, PrefixedHexString } from './types'
import { Buffer } from 'buffer'
import { Block } from './block'

Expand Down Expand Up @@ -43,22 +43,14 @@ export class BlockHeader {
*/
constructor(
data: Buffer | PrefixedHexString | BufferLike[] | BlockHeaderData = {},
opts: ChainOptions = {},
options: BlockOptions = {},
) {
if (opts.common !== undefined) {
if (opts.chain !== undefined || opts.hardfork !== undefined) {
throw new Error(
'Instantiation with both opts.common and opts.chain / opts.hardfork parameter not allowed!',
)
}

this._common = opts.common
if (options.common) {
this._common = options.common
} else {
const chain = opts.chain ? opts.chain : 'mainnet'
const hardfork = opts.hardfork ? opts.hardfork : null
this._common = new Common({ chain, hardfork })
const DEFAULT_CHAIN = 'mainnet'
this._common = new Common({ chain: DEFAULT_CHAIN })
}

const fields = [
{
name: 'parentHash',
Expand Down Expand Up @@ -132,6 +124,9 @@ export class BlockHeader {
},
]
defineProperties(this, fields, data)
if (options.hardforkByBlockNumer) {
this._common.setHardforkByBlockNumber(bufferToInt(this.number))
}

this._checkDAOExtraData()
}
Expand Down
14 changes: 5 additions & 9 deletions packages/block/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ import { Block } from './block'
* using a Common object, or `chain` and `hardfork`. Defaults to mainnet without specifying a
* hardfork.
*/
export interface ChainOptions {
export interface BlockOptions {
/**
* A Common object defining the chain and the hardfork a block/block header belongs to.
*/
common?: Common

/**
* The chain of the block/block header, default: 'mainnet'
*/
chain?: number | string

/**
* The hardfork of the block/block header, default: 'petersburg'
* Determine the HF by the block number
*
* Default: `false` (HF is set to whatever default HF is set by the Common instance)
*/
hardfork?: string
hardforkByBlockNumer?: boolean
}

/**
Expand Down
27 changes: 8 additions & 19 deletions packages/block/test/block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,10 @@ import { Block } from '../src/block'

tape('[Block]: block functions', function (t) {
t.test('should test block initialization', function (st) {
const block1 = new Block(undefined, { chain: 'ropsten' })
const common = new Common({ chain: 'ropsten' })
const block2 = new Block(undefined, { common: common })
const block1 = new Block(undefined, { common: common })
block1.setGenesisParams()
block2.setGenesisParams()
st.strictEqual(
block1.hash().toString('hex'),
block2.hash().toString('hex'),
'block hashes match',
)

st.throws(
function () {
new Block(undefined, { chain: 'ropsten', common: common })
},
/not allowed!$/,
'should throw on initialization with chain and common parameter',
) // eslint-disable-line
st.ok(block1.hash().toString('hex'), 'block should initialize')
st.end()
})

Expand All @@ -36,7 +22,8 @@ tape('[Block]: block functions', function (t) {

t.test('should initialize with null parameters without throwing', function (st) {
st.doesNotThrow(function () {
const opts = { chain: 'mainnet' }
const common = new Common({ chain: 'ropsten' })
const opts = { common }
new Block(undefined, opts)
st.end()
})
Expand Down Expand Up @@ -81,7 +68,8 @@ tape('[Block]: block functions', function (t) {
})

t.test('should test isGenesis (ropsten)', function (st) {
const block = new Block(undefined, { chain: 'ropsten' })
const common = new Common({ chain: 'ropsten' })
const block = new Block(undefined, { common })
st.notEqual(block.isGenesis(), true)
block.header.number = Buffer.from([])
st.equal(block.isGenesis(), true)
Expand Down Expand Up @@ -127,7 +115,8 @@ tape('[Block]: block functions', function (t) {
})

t.test('should test genesis parameters (ropsten)', function (st) {
const genesisBlock = new Block(undefined, { chain: 'ropsten' })
const common = new Common({ chain: 'ropsten' })
const genesisBlock = new Block(undefined, { common })
genesisBlock.setGenesisParams()
const ropstenStateRoot = '217b0bbcfb72e2d57e28f33cb361b9983513177755dc3f33ce3e7022ed62b77b'
st.strictEqual(
Expand Down
34 changes: 23 additions & 11 deletions packages/block/test/difficulty.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toBuffer } from 'ethereumjs-util'
import { toBuffer, bufferToInt, intToBuffer } from 'ethereumjs-util'
import { Block } from '../src/block'
import tape = require('tape')
import Common from '@ethereumjs/common'

const { BN } = require('ethereumjs-util')

Expand Down Expand Up @@ -40,12 +41,13 @@ tape('[Header]: difficulty tests', (t) => {
const testData = hardforkTestData[hardfork]
for (const testName in testData) {
const test = testData[testName]
const parentBlock = new Block(undefined, { chain: 'mainnet', hardfork: hardfork })
const common = new Common({ chain: 'mainnet', hardfork: hardfork })
const parentBlock = new Block(undefined, { common })
parentBlock.header.timestamp = test.parentTimestamp
parentBlock.header.difficulty = test.parentDifficulty
parentBlock.header.uncleHash = test.parentUncles

const block = new Block(undefined, { chain: 'mainnet', hardfork: hardfork })
const block = new Block(undefined, { common })
block.header.timestamp = test.currentTimestamp
block.header.difficulty = test.currentDifficulty
block.header.number = test.currentBlockNumber
Expand All @@ -67,15 +69,25 @@ tape('[Header]: difficulty tests', (t) => {
const testData = chainTestData[chain]
for (const testName in testData) {
const test = testData[testName]
const parentBlock = new Block(undefined, { chain: chain })
parentBlock.header.timestamp = test.parentTimestamp
parentBlock.header.difficulty = test.parentDifficulty
parentBlock.header.uncleHash = test.parentUncles
const common = new Common({ chain })
const parentData = {
header: {
timestamp: test.parentTimestamp,
difficulty: test.parentDifficulty,
number: intToBuffer(bufferToInt(test.currentBlockNumber) - 1),
uncleHash: test.parentUncles,
},
}
const parentBlock = new Block(parentData, { common, hardforkByBlockNumer: true })

const block = new Block(undefined, { chain: chain })
block.header.timestamp = test.currentTimestamp
block.header.difficulty = test.currentDifficulty
block.header.number = test.currentBlockNumber
const blockData = {
header: {
timestamp: test.currentTimestamp,
difficulty: test.currentDifficulty,
number: test.currentBlockNumber,
},
}
const block = new Block(blockData, { common, hardforkByBlockNumer: true })

runDifficultyTests(
test,
Expand Down
23 changes: 5 additions & 18 deletions packages/block/test/header.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,10 @@ tape('[Block]: Header functions', function (t) {
})

t.test('should test header initialization', function (st) {
const header1 = new BlockHeader(undefined, { chain: 'ropsten' })
const common = new Common({ chain: 'ropsten' })
const header2 = new BlockHeader(undefined, { common: common })
header1.setGenesisParams()
header2.setGenesisParams()
st.strictEqual(
header1.hash().toString('hex'),
header2.hash().toString('hex'),
'header hashes match',
)

st.throws(
function () {
new BlockHeader(undefined, { chain: 'ropsten', common: common })
},
/not allowed!$/,
'should throw on initialization with chain and common parameter',
) // eslint-disable-line
const block1 = new Block(undefined, { common: common })
block1.setGenesisParams()
st.ok(block1.hash().toString('hex'), 'block should initialize')
st.end()
})

Expand Down Expand Up @@ -90,7 +76,8 @@ tape('[Block]: Header functions', function (t) {
})

t.test('should test genesis parameters (ropsten)', function (st) {
const genesisHeader = new BlockHeader(undefined, { chain: 'ropsten' })
const common = new Common({ chain: 'ropsten' })
const genesisHeader = new BlockHeader(undefined, { common })
genesisHeader.setGenesisParams()
const ropstenStateRoot = '217b0bbcfb72e2d57e28f33cb361b9983513177755dc3f33ce3e7022ed62b77b'
st.strictEqual(
Expand Down
Loading

0 comments on commit 116ea78

Please sign in to comment.