Skip to content

Commit

Permalink
feat(common): storage, code and nonce handled in genesis state & cust…
Browse files Browse the repository at this point in the history
…om hash and state root can be passed
  • Loading branch information
cbrzn committed Feb 28, 2022
1 parent c842a97 commit 1cecab7
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 29 deletions.
2 changes: 2 additions & 0 deletions packages/client/bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ async function run() {
const chainName = path.parse(args.gethGenesis).base.split('.')[0]
const genesisParams = await parseCustomParams(genesisFile, chainName)
const genesisState = genesisFile.alloc ? await parseGenesisState(genesisFile) : {}
console.log('Genesis block hash: ', genesisParams.genesis.hash)
console.log('Genesis state root: ', genesisParams.genesis.stateRoot)
common = new Common({
chain: genesisParams.name,
customChains: [[genesisParams, genesisState]],
Expand Down
1 change: 1 addition & 0 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"lint:fix": "../../config/cli/lint-fix.sh",
"tape": "tape -r ts-node/register",
"test": "npm run test:node && npm run test:browser",
"test:temp": "npm run tape -- ./tests/customChains.spec.ts",
"test:node": "npm run tape -- ./tests/*.spec.ts",
"test:browser": "karma start karma.conf.js",
"docs:build": "typedoc --options typedoc.js"
Expand Down
56 changes: 32 additions & 24 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Chain as IChain,
GenesisBlock,
GenesisState,
GethGenesisState,
Hardfork as HardforkParams,
} from './types'

Expand Down Expand Up @@ -132,7 +133,7 @@ export interface CommonOpts extends BaseOpts {
* Initialize (in addition to the supported chains) with the selected
* custom chains
*
* Usage (directly with the respective chain intialization via the {@link CommonOpts.chain} option):
* Usage (directly with the respective chain initialization via the {@link CommonOpts.chain} option):
*
* Pattern 1 (without genesis state):
*
Expand All @@ -149,7 +150,7 @@ export interface CommonOpts extends BaseOpts {
* const common = new Common({ chain: 'myCustomChain1', customChains: [ [ myCustomChain1, chain1GenesisState ] ]})
* ```
*/
customChains?: IChain[] | [IChain, GenesisState][]
customChains?: IChain[] | [IChain, GenesisState | GethGenesisState][]
}

/**
Expand Down Expand Up @@ -185,7 +186,7 @@ export default class Common extends EventEmitter {
private _hardfork: string | Hardfork
private _supportedHardforks: Array<string | Hardfork> = []
private _eips: number[] = []
private _customChains: IChain[] | [IChain, GenesisState][]
private _customChains: IChain[] | [IChain, GenesisState | GethGenesisState][]

/**
* Creates a {@link Common} object for a custom chain, based on a standard one.
Expand Down Expand Up @@ -379,22 +380,33 @@ export default class Common extends EventEmitter {
* representation. Or, a Dictionary of chain parameters for a private network.
* @returns The dictionary with parameters set as chain
*/
setChain(chain: string | number | Chain | BN | object): any {
setChain(chain: string | number | Chain | BN | object): IChain {
if (typeof chain === 'number' || typeof chain === 'string' || BN.isBN(chain)) {
// Filter out genesis states if passed in to customChains
let plainCustomChains: IChain[]
if (
this._customChains &&
this._customChains.length > 0 &&
Array.isArray(this._customChains[0])
) {
plainCustomChains = (this._customChains as [IChain, GenesisState][]).map((e) => e[0])
if (this._customChains?.length && Array.isArray(this._customChains[0])) {
plainCustomChains = (this._customChains as [IChain, GenesisState | GethGenesisState][]).map(
([chain, state]) => {
if ('hash' && 'stateRoot' in state) {
return {
...chain,
genesis: {
...chain.genesis,
hash: state.hash,
stateRoot: state.stateRoot,
},
} as IChain
}

return chain
}
)
} else {
plainCustomChains = this._customChains as IChain[]
}
this._chainParams = Common._getChainParams(chain, plainCustomChains)
} else if (typeof chain === 'object') {
if (this._customChains.length > 0) {
if (this._customChains.length) {
throw new Error(
'Chain must be a string, number, or BN when initialized with customChains passed in'
)
Expand Down Expand Up @@ -1001,6 +1013,15 @@ export default class Common extends EventEmitter {
* all values are provided as hex-prefixed strings.
*/
genesisState(): GenesisState {
// Custom chains with genesis state provided
if (this._customChains?.length && Array.isArray(this._customChains[0])) {
for (const chainArrayWithGenesis of this._customChains as [IChain, GenesisState][]) {
if (chainArrayWithGenesis[0].name === this.chainName()) {
return chainArrayWithGenesis[1]
}
}
}

// Use require statements here in favor of import statements
// to load json files on demand
// (high memory usage by large mainnet.json genesis state file)
Expand All @@ -1019,19 +1040,6 @@ export default class Common extends EventEmitter {
return require('./genesisStates/sepolia.json')
}

// Custom chains with genesis state provided
if (
this._customChains &&
this._customChains.length > 0 &&
Array.isArray(this._customChains[0])
) {
for (const chainArrayWithGenesis of this._customChains as [IChain, GenesisState][]) {
if (chainArrayWithGenesis[0].name === this.chainName()) {
return chainArrayWithGenesis[1]
}
}
}

return {}
}

Expand Down
15 changes: 13 additions & 2 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,21 @@ export interface Chain {
}
}

export interface GenesisState {
[key: string]: string | [string, [[string, string]]] // balance | [balance, code, [[storageKey, storageValue]]]
export interface GethGenesisState {
json?: any
hash: string
stateRoot: string
}

export interface AccountState {
balance: string
nonce: string
code?: string
storage?: Record<string, string>
}

export type GenesisState = Record<string, string | AccountState>

export interface eipsType {
[key: number]: any
}
Expand Down
45 changes: 42 additions & 3 deletions packages/common/tests/customChains.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import Common, { Chain, ConsensusType, CustomChain, Hardfork } from '../src/'
import testnet from './data/testnet.json'
import testnet2 from './data/testnet2.json'
import testnet3 from './data/testnet3.json'
import { AccountState, Chain as IChain, GenesisState, GethGenesisState } from '../src/types'

import { Chain as IChain, GenesisState } from '../src/types'

tape('[Common]: Custom chains', function (t: tape.Test) {
tape.only('[Common]: Custom chains', function (t: tape.Test) {
t.test(
'chain -> object: should provide correct access to private network chain parameters',
function (st: tape.Test) {
Expand Down Expand Up @@ -210,4 +209,44 @@ tape('[Common]: Custom chains', function (t: tape.Test) {

st.end()
})

t.test('custom genesis state', function (st: tape.Test) {
const mockedCode = '0xcde'
const firstAddress = '0x0000000000000000000000000000000000000001'
const genesisState = {
'0x0000000000000000000000000000000000000000': '0x1',
[firstAddress]: {
balance: '0x1',
nonce: '0x',
storage: {},
code: mockedCode,
},
}
const customChainsWithGenesis: [IChain, GenesisState][] = [[testnet, genesisState]]
const c = new Common({
chain: 'testnet',
customChains: customChainsWithGenesis,
})

const expectedGenesisState = c.genesisState()[firstAddress] as AccountState

st.equal(c.genesisState(), genesisState)
st.equal(expectedGenesisState.code, genesisState[firstAddress].code)
st.end()
})

t.test('custom hash and state root sent in genesis state', function (st: tape.Test) {
const genesisState = {
stateRoot: 'cool-state-root',
hash: 'cool-hash',
}
const customChainsWithGenesis: [IChain, GethGenesisState][] = [[testnet, genesisState]]
const c = new Common({
chain: 'testnet',
customChains: customChainsWithGenesis,
})
st.equal(c.genesis().hash, genesisState.hash)
st.equal(c.genesis().stateRoot, genesisState.stateRoot)
st.end()
})
})

0 comments on commit 1cecab7

Please sign in to comment.