Skip to content
This repository was archived by the owner on Apr 6, 2020. It is now read-only.

Commit 30c4186

Browse files
authored
Merge pull request #55 from ethereumjs/forCustomChain
Add a forCustomChain static factory method
2 parents edd94fc + 7721d44 commit 30c4186

File tree

5 files changed

+121
-19
lines changed

5 files changed

+121
-19
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,5 @@ node_modules
6868
package-lock.json
6969

7070
dist
71+
72+
.idea

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,16 @@ The following chain-specific parameters are provided:
130130
- `bootstrapNodes` list
131131

132132
To get an overview of the different parameters have a look at one of the chain-specifc
133-
files like `mainnet.json` in the `chains` directory.
133+
files like `mainnet.json` in the `chains` directory, or to the `Chain` type in [./src/types.ts](./src/types.ts).
134134

135-
If you want to set up a common instance with parameters for a **private/custom chain** you can pass a
136-
dictionary - conforming to the parameter format described above - with your custom values in
137-
the constructor or the `setChain()` method for the `chain` parameter.
135+
## Working with private/custom chains
136+
137+
There are two ways to set up a common instance with parameters for a private/custom chain:
138+
139+
1. You can pass a dictionary - conforming to the parameter format described above - with your custom values in
140+
the constructor or the `setChain()` method for the `chain` parameter.
141+
142+
2. You can base your custom chain's config in a standard one, using the `Common.forCustomChain` method.
138143

139144
# Bootstrap Nodes
140145

src/index.ts

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { chains as chainParams } from './chains'
22
import { hardforks as hardforkChanges } from './hardforks'
3+
import { Chain } from './types'
34

45
interface hardforkOptions {
56
/** optional, only allow supported HFs (default: false) */
@@ -14,7 +15,51 @@ interface hardforkOptions {
1415
export default class Common {
1516
private _hardfork: string | null
1617
private _supportedHardforks: Array<string>
17-
private _chainParams: object
18+
private _chainParams: Chain
19+
20+
/**
21+
* Creates a Common object for a custom chain, based on a standard one. It uses all the [[Chain]]
22+
* params from [[baseChain]] except the ones overridden in [[customChainParams]].
23+
*
24+
* @param baseChain The name (`mainnet`) or id (`1`) of a standard chain used to base the custom
25+
* chain params on.
26+
* @param customChainParams The custom parameters of the chain.
27+
* @param hardfork String identifier ('byzantium') for hardfork (optional)
28+
* @param supportedHardforks Limit parameter returns to the given hardforks (optional)
29+
*/
30+
static forCustomChain(
31+
baseChain: string | number,
32+
customChainParams: Partial<Chain>,
33+
hardfork?: string | null,
34+
supportedHardforks?: Array<string>,
35+
): Common {
36+
const standardChainParams = Common._getChainParams(baseChain)
37+
38+
return new Common(
39+
{
40+
...standardChainParams,
41+
...customChainParams,
42+
},
43+
hardfork,
44+
supportedHardforks,
45+
)
46+
}
47+
48+
private static _getChainParams(chain: string | number): Chain {
49+
if (typeof chain === 'number') {
50+
if (chainParams['names'][chain]) {
51+
return chainParams[chainParams['names'][chain]]
52+
}
53+
54+
throw new Error(`Chain with ID ${chain} not supported`)
55+
}
56+
57+
if (chainParams[chain]) {
58+
return chainParams[chain]
59+
}
60+
61+
throw new Error(`Chain with name ${chain} not supported`)
62+
}
1863

1964
/**
2065
* @constructor
@@ -42,26 +87,16 @@ export default class Common {
4287
* @returns The dictionary with parameters set as chain
4388
*/
4489
setChain(chain: string | number | object): any {
45-
if (typeof chain === 'number') {
46-
if (chainParams['names'][chain]) {
47-
this._chainParams = chainParams[chainParams['names'][chain]]
48-
} else {
49-
throw new Error(`Chain with ID ${chain} not supported`)
50-
}
51-
} else if (typeof chain === 'string') {
52-
if (chainParams[chain]) {
53-
this._chainParams = chainParams[chain]
54-
} else {
55-
throw new Error(`Chain with name ${chain} not supported`)
56-
}
90+
if (typeof chain === 'number' || typeof chain === 'string') {
91+
this._chainParams = Common._getChainParams(chain)
5792
} else if (typeof chain === 'object') {
5893
const required = ['networkId', 'genesis', 'hardforks', 'bootstrapNodes']
5994
for (const param of required) {
6095
if ((<any>chain)[param] === undefined) {
6196
throw new Error(`Missing required chain parameter: ${param}`)
6297
}
6398
}
64-
this._chainParams = chain
99+
this._chainParams = chain as Chain
65100
} else {
66101
throw new Error('Wrong input format')
67102
}

src/types.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,43 @@ export interface chainsType {
99
names: {
1010
[key: string]: string
1111
}
12-
[key: string]: {}
12+
[key: string]: any
13+
}
14+
15+
export interface Chain {
16+
name: string
17+
chainId: number
18+
networkId: number
19+
comment: string
20+
url: string
21+
genesis: GenesisBlock
22+
hardforks: Hardfork[]
23+
bootstrapNodes: BootstrapNode[]
24+
}
25+
26+
export interface GenesisBlock {
27+
hash: string
28+
timestamp: string | null
29+
gasLimit: number
30+
difficulty: number
31+
nonce: string
32+
extraData: string
33+
stateRoot: string
34+
}
35+
36+
export interface Hardfork {
37+
name: string
38+
block: number | null
39+
consensus: string
40+
finality: any
41+
}
42+
43+
export interface BootstrapNode {
44+
ip: string
45+
port: number | string
46+
network?: string
47+
chainId?: number
48+
id: string
49+
location: string
50+
comment: string
1351
}

tests/params.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,26 @@ tape('[Common]: Parameter access', function(t: tape.Test) {
8787
st.comment('-----------------------------------------------------------------')
8888
st.end()
8989
})
90+
91+
t.test('Custom chain usage', function(st: tape.Test) {
92+
const mainnetCommon = new Common('mainnet')
93+
94+
const customChainParams = { name: 'custom', chainId: 123, networkId: 678 }
95+
const customChainCommon = Common.forCustomChain('mainnet', customChainParams, 'byzantium')
96+
97+
// From custom chain params
98+
st.equal(customChainCommon.chainName(), customChainParams.name)
99+
st.equal(customChainCommon.chainId(), customChainParams.chainId)
100+
st.equal(customChainCommon.networkId(), customChainParams.networkId)
101+
102+
// Fallback params from mainnet
103+
st.equal(customChainCommon.genesis(), mainnetCommon.genesis())
104+
st.equal(customChainCommon.bootstrapNodes(), mainnetCommon.bootstrapNodes())
105+
st.equal(customChainCommon.hardforks(), mainnetCommon.hardforks())
106+
107+
// Set only to this Common
108+
st.equal(customChainCommon.hardfork(), 'byzantium')
109+
110+
st.end()
111+
})
90112
})

0 commit comments

Comments
 (0)