Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client: refactor execution #1068

Merged
merged 12 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 78 additions & 18 deletions packages/blockchain/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Semaphore from 'semaphore-async-await'
import { Address, BN, rlp } from 'ethereumjs-util'
import { Block, BlockHeader } from '@ethereumjs/block'
import { Block, BlockData, BlockHeader } from '@ethereumjs/block'
import Ethash from '@ethereumjs/ethash'
import Common from '@ethereumjs/common'
import { DBManager } from './db/manager'
Expand Down Expand Up @@ -177,6 +177,41 @@ export default class Blockchain implements BlockchainInterface {
*/
private _cliqueLatestBlockSigners: CliqueLatestBlockSigners = []

/**
* Safe creation of a new Blockchain object awaiting the initialization function,
* encouraged method to use when creating a blockchain object.
*
* @param opts Constructor options, see [[BlockchainOptions]]
*/

public static async create(opts: BlockchainOptions = {}) {
const blockchain = new Blockchain(opts)
await blockchain.initPromise!.catch((e) => {
throw e
})
return blockchain
}

/**
* Creates a blockchain from a list of block objects,
* objects must be readable by the `Block.fromBlockData()` method
*
* @param blockData List of block objects
* @param opts Constructor options, see [[BlockchainOptions]]
*/
public static async fromBlocksData(blocksData: BlockData[], opts: BlockchainOptions = {}) {
const blockchain = await Blockchain.create(opts)
for (const blockData of blocksData) {
const common = Object.assign(
Object.create(Object.getPrototypeOf(blockchain._common)),
blockchain._common
)
const block = Block.fromBlockData(blockData, { common, hardforkByBlockNumber: true })
await blockchain.putBlock(block)
}
return blockchain
}

/**
* Creates new Blockchain object
*
Expand Down Expand Up @@ -236,22 +271,6 @@ export default class Blockchain implements BlockchainInterface {
this.initPromise = this._init(opts.genesisBlock)
}

/**
* This static constructor safely creates a new Blockchain object, which also
* awaits the initialization function. If this initialization function throws,
* then this constructor will throw as well, and is therefore the encouraged
* method to use when creating a blockchain object.
* @param opts Constructor options, see [[BlockchainOptions]]
*/

public static async create(opts: BlockchainOptions = {}) {
const blockchain = new Blockchain(opts)
await blockchain.initPromise!.catch((e) => {
throw e
})
return blockchain
}

/**
* Returns an object with metadata about the Blockchain. It's defined for
* backwards compatibility.
Expand Down Expand Up @@ -622,7 +641,36 @@ export default class Blockchain implements BlockchainInterface {
/**
* Returns the specified iterator head.
*
* @param name - Optional name of the state root head (default: 'vm')
* This function replaces the old `getHead()` method. Note that
* the function deviates from the old behavior and returns the
* genesis hash instead of the current head block if an iterator
* has not been run. This matches the behavior of the `iterator()`
* method.
*
* @param name - Optional name of the iterator head (default: 'vm')
*/
async getIteratorHead(name = 'vm'): Promise<Block> {
return await this.initAndLock<Block>(async () => {
// if the head is not found return the genesis hash
const hash = this._heads[name] || this._genesis
if (!hash) {
throw new Error('No head found.')
}

const block = await this._getBlock(hash)
return block
})
}

/**
* Returns the specified iterator head.
*
* @param name - Optional name of the iterator head (default: 'vm')
*
* @deprecated use `getIteratorHead()` instead. Note that `getIteratorHead()`
* doesn't return the `headHeader` but the genesis hash as an initial
* iterator head value (now matching the behavior of the `iterator()`
* method on a first run)
*/
async getHead(name = 'vm'): Promise<Block> {
return await this.initAndLock<Block>(async () => {
Expand Down Expand Up @@ -1141,6 +1189,18 @@ export default class Blockchain implements BlockchainInterface {
* @param tag - The tag to save the headHash to
* @param headHash - The head hash to save
*/
async setIteratorHead(tag: string, headHash: Buffer) {
return await this.setHead(tag, headHash)
}

/**
* Set header hash of a certain `tag`.
* When calling the iterator, the iterator will start running the first child block after the header hash currenntly stored.
* @param tag - The tag to save the headHash to
* @param headHash - The head hash to save
*
* @deprecated use `setIteratorHead()` instead
*/
async setHead(tag: string, headHash: Buffer) {
await this.initAndLock<void>(async () => {
this._heads[tag] = headHash
Expand Down
33 changes: 29 additions & 4 deletions packages/blockchain/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Block, BlockHeader, BlockOptions } from '@ethereumjs/block'
import tape from 'tape'
import Blockchain from '../src'
import { generateBlockchain, generateBlocks, isConsecutive, createTestDB } from './util'
import * as testData from './testdata.json'
import * as testData from './testdata/testdata.json'
import blocksData from './testdata/blocks_mainnet.json'

const level = require('level-mem')

Expand All @@ -23,8 +24,32 @@ tape('blockchain test', (t) => {
const blockchain = new Blockchain({ common })

const head = await blockchain.getHead()
const iteratorHead = await blockchain.getIteratorHead()

st.equals(head.hash().toString('hex'), common.genesis().hash.slice(2), 'correct genesis hash')
st.equals(
head.hash().toString('hex'),
common.genesis().hash.slice(2),
'correct genesis hash (getHead())'
)
st.equals(
iteratorHead.hash().toString('hex'),
common.genesis().hash.slice(2),
'correct genesis hash (getIteratorHead())'
)
st.end()
})

t.test('should initialize correctly with Blockchain.fromBlocksData()', async (st) => {
const common = new Common({ chain: 'mainnet' })
const blockchain = await Blockchain.fromBlocksData(blocksData, {
validateBlocks: true,
validateConsensus: false,
common,
})

const head = await blockchain.getHead()

st.equals(head.header.number.toNumber(), 5, 'correct block number')
st.end()
})

Expand Down Expand Up @@ -415,14 +440,14 @@ tape('blockchain test', (t) => {
// Note: if st.end() is not called (Promise did not throw), then this test fails, as it does not end.
})

t.test('should test setHead method', async (st) => {
t.test('should test setHead (@deprecated)/setIteratorHead method', async (st) => {
const { blockchain, blocks, error } = await generateBlockchain(25)
st.error(error, 'no error')

const headBlockIndex = 5

const headHash = blocks[headBlockIndex].hash()
await blockchain.setHead('myHead', headHash)
await blockchain.setIteratorHead('myHead', headHash)
const currentHeadBlock = await blockchain.getHead('myHead')

st.ok(headHash.equals(currentHeadBlock.hash()), 'head hash equals the provided head hash')
Expand Down
143 changes: 143 additions & 0 deletions packages/blockchain/test/testdata/blocks_mainnet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
[
{
"header": {
"parentHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"coinbase": "0x05a56e2d52c817161883f50c441c3228cfe54d9f",
"stateRoot": "0xd67e4d450343046425ae4271474353857ab860dbc0a1dde64b41b5cd3a532bf3",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3ff800000",
"number": "0x1",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba4224",
"extraData": "0x476574682f76312e302e302f6c696e75782f676f312e342e32",
"mixHash": "0x969b900de27b6ac6a67742365dd65f55a0526c41fd18e1b16f1a1215c2e66f59",
"nonce": "0x539bd4979fef1ec4"
},
"transactions": [],
"uncleHeaders": []
},
{
"header": {
"parentHash": "0x88e96d4537bea4d9c05d12549907b32561d3bf31f45aae734cdc119f13406cb6",
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"coinbase": "0xdd2f1e6e498202e86d8f5442af596580a4f03c2c",
"stateRoot": "0x4943d941637411107494da9ec8bc04359d731bfd08b72b4d0edcbd4cd2ecb341",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3ff001000",
"number": "0x2",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba4241",
"extraData": "0x476574682f76312e302e302d30636463373634372f6c696e75782f676f312e34",
"mixHash": "0x2f0790c5aa31ab94195e1f6443d645af5b75c46c04fbf9911711198a0ce8fdda",
"nonce": "0xb853fa261a86aa9e"
},
"transactions": [],
"uncleHeaders": []
},
{
"header": {
"parentHash": "0xb495a1d7e6663152ae92708da4843337b958146015a2802f4193a410044698c9",
"uncleHash": "0x6b17b938c6e4ef18b26ad81b9ca3515f27fd9c4e82aac56a1fd8eab288785e41",
"coinbase": "0x5088d623ba0fcf0131e0897a91734a4d83596aa0",
"stateRoot": "0x76ab0b899e8387436ff2658e2988f83cbf1af1590b9fe9feca3714f8d1824940",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3fe802ffe",
"number": "0x3",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba4260",
"extraData": "0x476574682f76312e302e302d66633739643332642f6c696e75782f676f312e34",
"mixHash": "0x65e12eec23fe6555e6bcdb47aa25269ae106e5f16b54e1e92dcee25e1c8ad037",
"nonce": "0x2e9344e0cbde83ce"
},
"transactions": [],
"uncleHeaders": [
{
"parentHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"coinbase": "0xc8ebccc5f5689fa8659d83713341e5ad19349448",
"stateRoot": "0x1e6e030581fd1873b4784280859cd3b3c04aa85520f08c304cf5ee63d3935add",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3ff800000",
"number": "0x1",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba4242",
"extraData": "0x59617465732052616e64616c6c202d2045746865724e696e6a61",
"mixHash": "0xf8c94dfe61cf26dcdf8cffeda337cf6a903d65c449d7691a022837f6e2d99459",
"nonce": "0x68b769c5451a7aea"
}
]
},
{
"header": {
"parentHash": "0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741",
"uncleHash": "0x83a8da8965660cb6bdf0c37f1b111778e49753c4213bf7c3e280fccfde89f2b5",
"coinbase": "0xc8ebccc5f5689fa8659d83713341e5ad19349448",
"stateRoot": "0xe6d9f6e95a05ee69719c718c6157d0759049ef3dffdba2d48f015d7c8b9933d8",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3fe005ff9",
"number": "0x4",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba427d",
"extraData": "0x59617465732052616e64616c6c202d2045746865724e696e6a61",
"mixHash": "0x06ba40902198357cbeac24a86b2ef11e9fdff48d28a421a0055e26476e3ac59f",
"nonce": "0xc2535b5efca9bee0"
},
"transactions": [],
"uncleHeaders": [
{
"parentHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"coinbase": "0x5088d623ba0fcf0131e0897a91734a4d83596aa0",
"stateRoot": "0x9a6597b26adc0e5915cfcca537ba493a647cad1c3c923d406cdec6ca49a0a06d",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3ff800000",
"number": "0x1",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba4237",
"extraData": "0x476574682f76312e302e302d66633739643332642f6c696e75782f676f312e34",
"mixHash": "0xd045b852770160da169ec793ec0c6e6ff562e473b2bf3f8192dc59842e36f754",
"nonce": "0xdb821a775bf9dace"
}
]
},
{
"header": {
"parentHash": "0x23adf5a3be0f5235b36941bcb29b62504278ec5b9cdfa277b992ba4a7a3cd3a2",
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"coinbase": "0x05a56e2d52c817161883f50c441c3228cfe54d9f",
"stateRoot": "0x4470f3dc1cc8097394a4ae85302eac3368462b3c1cfa523ffca942c1dd478220",
"transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x3fe802004",
"number": "0x5",
"gasLimit": "0x1388",
"gasUsed": "0x0",
"timestamp": "0x55ba4283",
"extraData": "0x476574682f76312e302e302f6c696e75782f676f312e342e32",
"mixHash": "0x17b85b5ec310c4868249fa2f378c83b4f330e2d897e5373a8195946c71d1d19e",
"nonce": "0xfba9d0cff9dc5cf3"
},
"transactions": [],
"uncleHeaders": []
}
]
2 changes: 1 addition & 1 deletion packages/client/bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async function runNode(config: Config) {
client.on('synchronized', () => {
config.logger.info('Synchronized')
})
config.logger.info(`Connecting to network: ${config.common.chainName()}`)
config.logger.info(`Connecting to network: ${config.chainCommon.chainName()}`)
await client.open()
config.logger.info('Synchronizing blockchain...')
await client.start()
Expand Down
10 changes: 5 additions & 5 deletions packages/client/lib/blockchain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class Chain extends EventEmitter {
options.blockchain ??
new Blockchain({
db: options.chainDB,
common: this.config.common,
common: this.config.chainCommon,
validateBlocks: false,
validateConsensus: false,
})
Expand Down Expand Up @@ -138,14 +138,14 @@ export class Chain extends EventEmitter {
* @return {number}
*/
get networkId(): number {
return this.config.common.networkId()
return this.config.chainCommon.networkId()
}

/**
* Genesis block parameters
*/
get genesis(): GenesisBlockParams {
const genesis = this.config.common.genesis()
const genesis = this.config.chainCommon.genesis()
Object.entries(genesis).forEach(([k, v]) => {
genesis[k] = toBuffer(v as string)
})
Expand Down Expand Up @@ -267,7 +267,7 @@ export class Chain extends EventEmitter {
}
await this.open()
blocks = blocks.map((b: Block) =>
Block.fromValuesArray(b.raw(), { common: this.config.common })
Block.fromValuesArray(b.raw(), { common: this.config.chainCommon })
)
await this.blockchain.putBlocks(blocks)
await this.update()
Expand Down Expand Up @@ -302,7 +302,7 @@ export class Chain extends EventEmitter {
}
await this.open()
headers = headers.map((h) =>
BlockHeader.fromValuesArray(h.raw(), { common: this.config.common })
BlockHeader.fromValuesArray(h.raw(), { common: this.config.chainCommon })
)
await this.blockchain.putHeaders(headers)
await this.update()
Expand Down
Loading