Skip to content

Commit

Permalink
block -> enforce BNs on fields which are interpreted as numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
jochem-brouwer committed Sep 28, 2020
1 parent 17a33a8 commit 72b5b78
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 68 deletions.
104 changes: 48 additions & 56 deletions packages/block/src/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import {
rlp,
toBuffer,
unpadBuffer,
bufferToInt,
rlphash,
} from 'ethereumjs-util'
import { Blockchain, HeaderData, BlockOptions } from './types'
import { Buffer } from 'buffer'
import { Block } from './block'
import { checkBufferLength } from './util'
import { checkBufferLength, toBN } from './util'

/**
* An object that represents the block header
Expand All @@ -26,11 +25,11 @@ export class BlockHeader {
public readonly transactionsTrie: Buffer
public readonly receiptTrie: Buffer
public readonly bloom: Buffer
public readonly difficulty: Buffer
public readonly number: Buffer
public readonly gasLimit: Buffer
public readonly gasUsed: Buffer
public readonly timestamp: Buffer
public readonly difficulty: BN
public readonly number: BN
public readonly gasLimit: BN
public readonly gasUsed: BN
public readonly timestamp: BN
public readonly extraData: Buffer
public readonly mixHash: Buffer
public readonly nonce: Buffer
Expand Down Expand Up @@ -64,11 +63,11 @@ export class BlockHeader {
transactionsTrie ? checkBufferLength(toBuffer(transactionsTrie), 32) : KECCAK256_RLP,
receiptTrie ? checkBufferLength(toBuffer(receiptTrie), 32) : KECCAK256_RLP,
bloom ? toBuffer(bloom) : zeros(256),
difficulty ? toBuffer(difficulty) : Buffer.from([]),
number ? toBuffer(number) : Buffer.from([]),
gasLimit ? toBuffer(gasLimit) : Buffer.from('ffffffffffffff', 'hex'),
gasUsed ? toBuffer(gasUsed) : Buffer.from([]),
timestamp ? toBuffer(timestamp) : Buffer.from([]),
difficulty ? toBN(difficulty) : new BN(0),
number ? toBN(number) : new BN(0),
gasLimit ? toBN(gasLimit) : new BN(Buffer.from('ffffffffffffff', 'hex')),
gasUsed ? toBN(gasUsed) : new BN(0),
timestamp ? toBN(timestamp) : new BN(0),
extraData ? toBuffer(extraData) : Buffer.from([]),
mixHash ? toBuffer(mixHash) : zeros(32),
nonce ? toBuffer(nonce) : zeros(8),
Expand Down Expand Up @@ -109,21 +108,21 @@ export class BlockHeader {
nonce,
] = values
return new BlockHeader(
parentHash,
uncleHash,
coinbase,
stateRoot,
transactionsTrie,
receiptTrie,
bloom,
difficulty,
number,
gasLimit,
gasUsed,
timestamp,
extraData,
mixHash,
nonce,
toBuffer(parentHash),
toBuffer(uncleHash),
toBuffer(coinbase),
toBuffer(stateRoot),
toBuffer(transactionsTrie),
toBuffer(receiptTrie),
toBuffer(bloom),
toBN(difficulty),
toBN(number),
toBN(gasLimit),
toBN(gasUsed),
toBN(timestamp),
toBuffer(extraData),
toBuffer(mixHash),
toBuffer(nonce),
opts,
)
}
Expand All @@ -141,11 +140,11 @@ export class BlockHeader {
transactionsTrie: Buffer,
receiptTrie: Buffer,
bloom: Buffer,
difficulty: Buffer,
number: Buffer,
gasLimit: Buffer,
gasUsed: Buffer,
timestamp: Buffer,
difficulty: BN,
number: BN,
gasLimit: BN,
gasUsed: BN,
timestamp: BN,
extraData: Buffer,
mixHash: Buffer,
nonce: Buffer,
Expand Down Expand Up @@ -181,30 +180,23 @@ export class BlockHeader {
this.nonce = nonce

if (options.hardforkByBlockNumber) {
this._common.setHardforkByBlockNumber(bufferToInt(this.number))
this._common.setHardforkByBlockNumber(this.number.toNumber())
}
if (options.initWithGenesisHeader) {
if (this._common.hardfork() !== 'chainstart') {
throw new Error(
'Genesis parameters can only be set with a Common instance set to chainstart',
)
}
this.timestamp = toBuffer(this._common.genesis().timestamp || this.timestamp)
this.gasLimit = toBuffer(this._common.genesis().gasLimit || this.gasLimit)
this.difficulty = toBuffer(this._common.genesis().difficulty || this.difficulty)
this.timestamp = toBN(this._common.genesis().timestamp || this.timestamp)
this.gasLimit = toBN(this._common.genesis().gasLimit || this.gasLimit)
this.difficulty = toBN(this._common.genesis().difficulty || this.difficulty)
this.extraData = toBuffer(this._common.genesis().extraData || this.extraData)
this.nonce = toBuffer(this._common.genesis().nonce || this.nonce)
this.stateRoot = toBuffer(this._common.genesis().stateRoot || this.stateRoot)
this.number = toBuffer(0)
this.number = new BN(0)
}

// Unpad all fields which should be interpreted as numbers
this.timestamp = unpadBuffer(this.timestamp)
this.difficulty = unpadBuffer(this.difficulty)
this.gasLimit = unpadBuffer(this.gasLimit)
this.number = unpadBuffer(this.number)
this.timestamp = unpadBuffer(this.timestamp)

this._checkDAOExtraData()

Object.freeze(this)
Expand All @@ -217,9 +209,9 @@ export class BlockHeader {
*/
canonicalDifficulty(parentBlock: Block): BN {
const hardfork = this._getHardfork()
const blockTs = new BN(this.timestamp)
const parentTs = new BN(parentBlock.header.timestamp)
const parentDif = new BN(parentBlock.header.difficulty)
const blockTs = toBN(this.timestamp)
const parentTs = toBN(parentBlock.header.timestamp)
const parentDif = toBN(parentBlock.header.difficulty)
const minimumDifficulty = new BN(
this._common.paramByHardfork('pow', 'minimumDifficulty', hardfork),
)
Expand Down Expand Up @@ -365,11 +357,11 @@ export class BlockHeader {
throw new Error('invalid gas limit')
}

if (bufferToInt(this.number) - bufferToInt(parentBlock.header.number) !== 1) {
if (!this.number.sub(parentBlock.header.number).eqn(1)) {
throw new Error('invalid height')
}

if (bufferToInt(this.timestamp) <= bufferToInt(parentBlock.header.timestamp)) {
if (this.timestamp.cmp(parentBlock.header.timestamp) <= 0) {
throw new Error('invalid timestamp')
}

Expand Down Expand Up @@ -399,11 +391,11 @@ export class BlockHeader {
this.transactionsTrie,
this.receiptTrie,
this.bloom,
this.difficulty,
this.number,
this.gasLimit,
this.gasUsed,
this.timestamp,
unpadBuffer(toBuffer(this.difficulty)), // we unpadBuffer, because toBuffer(new BN(0)) == <Buffer 00>
unpadBuffer(toBuffer(this.number)),
unpadBuffer(toBuffer(this.gasLimit)),
unpadBuffer(toBuffer(this.gasUsed)),
unpadBuffer(toBuffer(this.timestamp)),
this.extraData,
this.mixHash,
this.nonce,
Expand All @@ -414,7 +406,7 @@ export class BlockHeader {
* Checks if the block header is a genesis header.
*/
isGenesis(): boolean {
return this.number.equals(zeros(0))
return this.number.isZero()
}

/**
Expand Down Expand Up @@ -455,7 +447,7 @@ export class BlockHeader {

return commonHardFork !== null
? commonHardFork
: this._common.activeHardfork(bufferToInt(this.number))
: this._common.activeHardfork(this.number.toNumber())
}

private async _getBlockByHash(blockchain: Blockchain, hash: Buffer): Promise<Block | undefined> {
Expand Down
13 changes: 8 additions & 5 deletions packages/block/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Common from '@ethereumjs/common'
import { TxData } from '@ethereumjs/tx'
import { Block } from './block'
import { BN } from 'ethereumjs-util'

/**
* An object to set to which blockchain the blocks and their headers belong. This could be specified
Expand Down Expand Up @@ -51,6 +52,8 @@ export type PrefixedHexString = string
*/
export type BufferLike = Buffer | TransformableToBuffer | PrefixedHexString | number

export type BNLike = BN | string | number

/**
* A block header's data.
*/
Expand All @@ -62,11 +65,11 @@ export interface HeaderData {
transactionsTrie?: BufferLike
receiptTrie?: BufferLike
bloom?: BufferLike
difficulty?: BufferLike
number?: BufferLike
gasLimit?: BufferLike
gasUsed?: BufferLike
timestamp?: BufferLike
difficulty?: BNLike
number?: BNLike
gasLimit?: BNLike
gasUsed?: BNLike
timestamp?: BNLike
extraData?: BufferLike
mixHash?: BufferLike
nonce?: BufferLike
Expand Down
12 changes: 12 additions & 0 deletions packages/block/src/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { BNLike } from './types'
import { BN } from 'ethereumjs-util'

export function checkBufferLength(value: Buffer, expected: number): Buffer {
const provided = value.length
if (provided != expected) {
Expand All @@ -7,3 +10,12 @@ export function checkBufferLength(value: Buffer, expected: number): Buffer {
}
return value
}

export function toBN(value: BNLike | Buffer) {
if (typeof value == 'string') {
if (value.substr(0, 2) == '0x') {
return new BN(Buffer.from(value.substr(2), 'hex'))
}
}
return new BN(value)
}
10 changes: 5 additions & 5 deletions packages/block/test/block.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as tape from 'tape'
import Common from '@ethereumjs/common'
import { rlp } from 'ethereumjs-util'
import { rlp, BN } from 'ethereumjs-util'
import { Block } from '../src/block'

tape('[Block]: block functions', function (t) {
Expand Down Expand Up @@ -58,18 +58,18 @@ tape('[Block]: block functions', function (t) {
})

t.test('should test isGenesis (mainnet default)', function (st) {
const block = Block.fromBlockData({ header: { number: Buffer.from('01', 'hex') } })
const block = Block.fromBlockData({ header: { number: 1 } })
st.notEqual(block.isGenesis(), true)
const genesisBlock = Block.fromBlockData({ header: { number: Buffer.from([]) } })
const genesisBlock = Block.fromBlockData({ header: { number: 0 } })
st.equal(genesisBlock.isGenesis(), true)
st.end()
})

t.test('should test isGenesis (ropsten)', function (st) {
const common = new Common({ chain: 'ropsten' })
const block = Block.fromBlockData({ header: { number: Buffer.from('01', 'hex') } }, { common })
const block = Block.fromBlockData({ header: { number: 1 } }, { common })
st.notEqual(block.isGenesis(), true)
const genesisBlock = Block.fromBlockData({ header: { number: Buffer.from([]) } }, { common })
const genesisBlock = Block.fromBlockData({ header: { number: 0 } }, { common })
st.equal(genesisBlock.isGenesis(), true)
st.end()
})
Expand Down
2 changes: 1 addition & 1 deletion packages/block/test/difficulty.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ tape('[Header]: difficulty tests', (t) => {
header: {
timestamp: test.parentTimestamp,
difficulty: test.parentDifficulty,
number: intToBuffer(bufferToInt(test.currentBlockNumber) - 1),
number: bufferToInt(test.currentBlockNumber) - 1,
uncleHash: test.parentUncles,
},
}
Expand Down
1 change: 1 addition & 0 deletions packages/block/test/from-rpc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ tape('[fromRPC]: block #2924874', function (t) {
t.test('should create a block header with the correct hash', function (st) {
const block = blockHeaderFromRpc(blockData)
const hash = Buffer.from(blockData.hash.slice(2), 'hex')
console.log(hash, block.hash())
st.ok(block.hash().equals(hash))
st.end()
})
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 @@ -56,7 +56,7 @@ tape('[Block]: Header functions', function (t) {
})*/

t.test('should test isGenesis', function (st) {
let header = BlockHeader.fromHeaderData({ number: Buffer.from('01', 'hex') })
let header = BlockHeader.fromHeaderData({ number: 1 })
st.equal(header.isGenesis(), false)
header = BlockHeader.fromHeaderData({}, { initWithGenesisHeader: true })
st.equal(header.isGenesis(), true)
Expand Down

0 comments on commit 72b5b78

Please sign in to comment.