Skip to content

Commit

Permalink
block -> refactoring: added new static factory helpers to block class
Browse files Browse the repository at this point in the history
  • Loading branch information
holgerd77 committed Sep 21, 2020
1 parent ec71e48 commit 96318fa
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 48 deletions.
121 changes: 78 additions & 43 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,85 @@ import { BaseTrie as Trie } from 'merkle-patricia-tree'
import Common from '@ethereumjs/common'
import { BN, rlp, keccak256, KECCAK256_RLP, baToJSON, bufferToInt } from 'ethereumjs-util'
import { Transaction, TransactionOptions } from '@ethereumjs/tx'
import { BlockHeader } from './header'
import { Blockchain, BlockData, BlockOptions } from './types'
import { Header } from './header'
import { Blockchain, BlockData, BlockOptions, HeaderData } from './types'

/**
* An object that represents the block
*/
export class Block {
public readonly header: BlockHeader
public readonly header: Header
public readonly transactions: Transaction[] = []
public readonly uncleHeaders: BlockHeader[] = []
public readonly uncleHeaders: Header[] = []
public readonly txTrie = new Trie()

private readonly _common: Common

public static fromBlockData(blockData: BlockData, opts: BlockOptions = {}) {
// Checking at runtime, to prevent errors down the path for JavaScript consumers.
if (blockData === null) {
blockData = {}
}

const headerData = blockData.header || {}
const txsData = blockData.transactions || []
const uncleHeadersData = blockData.uncleHeaders || []

const header = Header.fromHeaderData(headerData, opts)

// parse transactions
let transactions = []
for (const txData of txsData) {
transactions.push(new Transaction(txData, opts))
}

// parse uncle headers
let uncleHeaders = []
for (const uncleHeaderData of uncleHeadersData) {
uncleHeaders.push(Header.fromHeaderData(uncleHeaderData, opts))
}

return new Block(header, transactions, uncleHeaders, opts)
}

public static fromRLPSerializedBlock(serialized: Buffer, opts: BlockOptions = {}) {
// We do this to silence a TS error. We know that after this statement, data is
// a [Buffer[], Buffer[], Buffer[]]
let values = (rlp.decode(serialized) as any) as [Buffer[], Buffer[], Buffer[]]

if (!Array.isArray(values)) {
throw new Error('Invalid serialized block input. Must be array')
}

return Block.fromValuesArray(values, opts)
}

public static fromValuesArray(values: [Buffer[], Buffer[], Buffer[]], opts: BlockOptions = {}) {
if (values.length > 3) {
throw new Error('invalid block. More values than expected were received')
}

const headerArray = values[0] || []
const txsData = values[1] || []
const uncleHeadersData = values[2] || []

const header = Header.fromValuesArray(headerArray, opts)

// parse transactions
let transactions = []
for (const txData of txsData) {
transactions.push(new Transaction(txData, opts))
}

// parse uncle headers
let uncleHeaders = []
for (const uncleHeaderData of uncleHeadersData) {
uncleHeaders.push(Header.fromRLPSerializedHeader(uncleHeaderData, opts))
}

return new Block(header, transactions, uncleHeaders, opts)
}

/**
* Creates a new block object
*
Expand All @@ -27,46 +92,16 @@ export class Block {
* @param options - The options for this block (like the chain setup)
*/
constructor(
data: Buffer | [Buffer[], Buffer[], Buffer[]] | BlockData = {},
options: BlockOptions = {},
header: Header,
transactions: Transaction[],
uncleHeaders: Header[],
//data: Buffer | [Buffer[], Buffer[], Buffer[]] | BlockData = {},
opts: BlockOptions = {},
) {
// Checking at runtime, to prevent errors down the path for JavaScript consumers.
if (data === null) {
data = {}
}

let rawTransactions
let rawUncleHeaders

if (Buffer.isBuffer(data)) {
// We do this to silence a TS error. We know that after this statement, data is
// a [Buffer[], Buffer[], Buffer[]]
const dataAsAny = rlp.decode(data) as any
data = dataAsAny as [Buffer[], Buffer[], Buffer[]]
}

// Initialize the block header
if (Array.isArray(data)) {
this.header = new BlockHeader(data[0], options)
rawTransactions = data[1]
rawUncleHeaders = data[2]
} else {
this.header = new BlockHeader(data.header, options)
rawTransactions = data.transactions || []
rawUncleHeaders = data.uncleHeaders || []
}
this.header = header
this.transactions = transactions
this.uncleHeaders = uncleHeaders
this._common = this.header._common

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

// parse transactions
for (let i = 0; i < rawTransactions.length; i++) {
const tx = new Transaction(rawTransactions[i], { common: this._common })
this.transactions.push(tx)
}
}

get raw(): [Buffer[], Buffer[], Buffer[]] {
Expand Down Expand Up @@ -235,7 +270,7 @@ export class Block {
await this.txTrie.put(rlp.encode(txIndex), tx.serialize())
}

private _validateUncleHeader(uncleHeader: BlockHeader, blockchain: Blockchain) {
private _validateUncleHeader(uncleHeader: Header, blockchain: Blockchain) {
// TODO: Validate that the uncle header hasn't been included in the blockchain yet.
// This is not possible in ethereumjs-blockchain since this PR was merged:
// https://github.com/ethereumjs/ethereumjs-blockchain/pull/47
Expand Down
5 changes: 3 additions & 2 deletions packages/block/src/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { statSync } from 'fs'
* An object that represents the block header
*/
export class Header {
public readonly _common: Common
public readonly parentHash: Buffer
public readonly uncleHash: Buffer
public readonly coinbase: Buffer
Expand All @@ -39,6 +38,8 @@ export class Header {
public readonly mixHash: Buffer
public readonly nonce: Buffer

public readonly _common: Common

public static fromHeaderData(headerData: HeaderData, opts: BlockOptions = {}) {
const {
parentHash,
Expand Down Expand Up @@ -85,7 +86,7 @@ export class Header {
throw new Error('Invalid serialized header input. Must be array')
}

return this.fromValuesArray(values, opts)
return Header.fromValuesArray(values, opts)
}

public static fromValuesArray(values: Buffer[], opts: BlockOptions) {
Expand Down
9 changes: 6 additions & 3 deletions packages/block/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,12 @@ export interface HeaderData {
* A block's data.
*/
export interface BlockData {
header?: Buffer | PrefixedHexString | BufferLike[] | HeaderData
transactions?: Array<Buffer | PrefixedHexString | BufferLike[] | TxData>
uncleHeaders?: Array<Buffer | PrefixedHexString | BufferLike[] | HeaderData>
/**
* Header data for the block
*/
header?: HeaderData
transactions?: Array<TxData>
uncleHeaders?: Array<HeaderData>
}

export interface Blockchain {
Expand Down

0 comments on commit 96318fa

Please sign in to comment.