Skip to content

Commit 60bc6da

Browse files
authored
Merge branch 'master' into tx-new-release-v301
2 parents 8ff7377 + 16abc7b commit 60bc6da

File tree

15 files changed

+344
-81
lines changed

15 files changed

+344
-81
lines changed

packages/common/README.md

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ c.bootstrapNodes() // Array with current nodes
5151
If the initializing library only supports a certain range of `hardforks` you can use the `supportedHardforks` option to restrict hardfork access on the `Common` instance:
5252

5353
```typescript
54-
let c = new Common({
54+
const c = new Common({
5555
chain: 'ropsten',
5656
supportedHardforks: ['byzantium', 'constantinople', 'petersburg'],
5757
})
@@ -104,12 +104,48 @@ files like `mainnet.json` in the `chains` directory, or to the `Chain` type in [
104104

105105
### Working with private/custom chains
106106

107-
There are two ways to set up a common instance with parameters for a private/custom chain:
107+
There are two distinct APIs available for setting up custom(ized) chains.
108108

109-
1. You can pass a dictionary - conforming to the parameter format described above - with your custom values in
110-
the constructor or the `setChain()` method for the `chain` parameter.
109+
### Activate with a single custom Chain setup
111110

112-
2. You can base your custom chain's config in a standard one, using the `Common.forCustomChain` method.
111+
If you want to initialize a `Common` instance with a single custom chain which is then directly activated
112+
you can pass a dictionary - conforming to the parameter format described above - with your custom chain
113+
values to the constructor using the `chain` parameter or the `setChain()` method, here is some example:
114+
115+
```typescript
116+
import myCustomChain from './[PATH]/myCustomChain.json'
117+
const common = new Common({ chain: myCustomChain })
118+
```
119+
120+
If you just want to change some certain parameters on a chain configuration it can also be conveniened to use
121+
the `Common.forCustomChain()` method. With this method you can base your custom chain configuration with
122+
a standard one (so using all the values from `baseChain` as the default values) and then just provide the
123+
parameters you want to override:
124+
125+
```typescript
126+
const customChainParams = { name: 'custom', chainId: 123, networkId: 678 }
127+
const customChainCommon = Common.forCustomChain('mainnet', customChainParams, 'byzantium')
128+
```
129+
130+
### Initialize using customChains Array
131+
132+
A second way for custom chain initialization is to use the `customChains` constructor option. This
133+
option comes with more flexibility and allows for an arbitrary number of custom chains to be initialized on
134+
a common instance in addition to the already supported ones. It also allows for an activation-independent
135+
initialization, so you can add your chains by adding to the `customChains` array and either directly
136+
use the `chain` option to activate one of the custom chains passed or activate a build in chain
137+
(e.g. `mainnet`) and switch to other chains - including the custom ones - by using `Common.setChain()`.
138+
139+
```typescript
140+
import myCustomChain1 from './[PATH]/myCustomChain1.json'
141+
import myCustomChain2 from './[PATH]/myCustomChain2.json'
142+
// Add two custom chains, initial mainnet activation
143+
const common1 = new Common({ chain: 'mainnet', customChains: [ myCustomChain1, myCustomChain2 ] })
144+
// Somewhat later down the road...
145+
common1.setChain('customChain1')
146+
// Add two custom chains, activate customChain1
147+
const common1 = new Common({ chain: 'customChain1', customChains: [ myCustomChain1, myCustomChain2 ] })
148+
```
113149

114150
## Hardforks
115151

packages/common/src/chains/goerli.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "goerli",
33
"chainId": 5,
44
"networkId": 5,
5+
"defaultHardfork": "istanbul",
56
"consensus": {
67
"type": "poa",
78
"algorithm": "clique"
Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,42 @@
1-
import { chainsType } from './../types'
1+
import { Chain, chainsType } from './../types'
2+
import mainnet from './mainnet.json'
3+
import ropsten from './ropsten.json'
4+
import rinkeby from './rinkeby.json'
5+
import kovan from './kovan.json'
6+
import goerli from './goerli.json'
27

3-
export const chains: chainsType = {
4-
names: {
8+
/**
9+
* @hidden
10+
*/
11+
export function _getInitializedChains(customChains?: Chain[]) {
12+
const names: any = {
513
'1': 'mainnet',
614
'3': 'ropsten',
715
'4': 'rinkeby',
816
'42': 'kovan',
917
'5': 'goerli',
10-
},
11-
mainnet: require('./mainnet.json'),
12-
ropsten: require('./ropsten.json'),
13-
rinkeby: require('./rinkeby.json'),
14-
kovan: require('./kovan.json'),
15-
goerli: require('./goerli.json'),
18+
}
19+
const chains: any = {
20+
mainnet,
21+
ropsten,
22+
rinkeby,
23+
kovan,
24+
goerli,
25+
}
26+
if (customChains) {
27+
for (const chain of customChains) {
28+
const name = chain.name
29+
names[chain.chainId.toString()] = name
30+
chains[name] = chain
31+
}
32+
}
33+
34+
chains['names'] = names
35+
return chains
1636
}
37+
38+
/**
39+
* @deprecated this constant will be internalized (removed)
40+
* on next major version update
41+
*/
42+
export const chains: chainsType = _getInitializedChains()

packages/common/src/chains/kovan.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "kovan",
33
"chainId": 42,
44
"networkId": 42,
5+
"defaultHardfork": "istanbul",
56
"consensus": {
67
"type": "poa",
78
"algorithm": "aura"

packages/common/src/chains/mainnet.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "mainnet",
33
"chainId": 1,
44
"networkId": 1,
5+
"defaultHardfork": "istanbul",
56
"consensus": {
67
"type": "pow",
78
"algorithm": "ethash"

packages/common/src/chains/rinkeby.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "rinkeby",
33
"chainId": 4,
44
"networkId": 4,
5+
"defaultHardfork": "istanbul",
56
"consensus": {
67
"type": "poa",
78
"algorithm": "clique"

packages/common/src/chains/ropsten.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "ropsten",
33
"chainId": 3,
44
"networkId": 3,
5+
"defaultHardfork": "istanbul",
56
"consensus": {
67
"type": "pow",
78
"algorithm": "ethash"

packages/common/src/index.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { buf as crc32Buffer } from 'crc-32'
2-
import { chains as chainParams } from './chains'
2+
import { _getInitializedChains } from './chains'
33
import { hardforks as HARDFORK_CHANGES } from './hardforks'
44
import { EIPs } from './eips'
55
import { Chain } from './types'
@@ -9,7 +9,8 @@ import { Chain } from './types'
99
*/
1010
export interface CommonOpts {
1111
/**
12-
* String ('mainnet') or Number (1) chain
12+
* Chain name ('mainnet') or id (1), either from a chain directly supported
13+
* or a custom chain passed in via `customChains`
1314
*/
1415
chain: string | number | object
1516
/**
@@ -31,6 +32,18 @@ export interface CommonOpts {
3132
* - [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) - BLS12-381 precompiles
3233
*/
3334
eips?: number[]
35+
/**
36+
* Initialize (in addition to the supported chains) with the selected
37+
* custom chains
38+
*
39+
* Usage (directly with the respective chain intialization via the `chain` option):
40+
*
41+
* ```javascript
42+
* import myCustomChain1 from '[PATH_TO_MY_CHAINS]/myCustomChain1.json'
43+
* const common = new Common({ chain: 'myCustomChain1', customChains: [ myCustomChain1 ]})
44+
* ```
45+
*/
46+
customChains?: Chain[]
3447
}
3548

3649
interface hardforkOptions {
@@ -44,12 +57,13 @@ interface hardforkOptions {
4457
* Common class to access chain and hardfork parameters
4558
*/
4659
export default class Common {
47-
readonly DEFAULT_HARDFORK: string = 'istanbul'
60+
readonly DEFAULT_HARDFORK: string
4861

4962
private _chainParams: Chain
5063
private _hardfork: string
5164
private _supportedHardforks: Array<string> = []
5265
private _eips: number[] = []
66+
private _customChains: Chain[]
5367

5468
/**
5569
* Creates a Common object for a custom chain, based on a standard one. It uses all the [[Chain]]
@@ -79,17 +93,19 @@ export default class Common {
7993
})
8094
}
8195

82-
private static _getChainParams(chain: string | number): Chain {
96+
private static _getChainParams(chain: string | number, customChains?: Chain[]): Chain {
97+
const initializedChains: any = _getInitializedChains(customChains)
8398
if (typeof chain === 'number') {
84-
if (chainParams['names'][chain]) {
85-
return chainParams[chainParams['names'][chain]]
99+
if (initializedChains['names'][chain]) {
100+
const name: string = initializedChains['names'][chain]
101+
return initializedChains[name]
86102
}
87103

88104
throw new Error(`Chain with ID ${chain} not supported`)
89105
}
90106

91-
if (chainParams[chain]) {
92-
return chainParams[chain]
107+
if (initializedChains[chain]) {
108+
return initializedChains[chain]
93109
}
94110

95111
throw new Error(`Chain with name ${chain} not supported`)
@@ -99,7 +115,9 @@ export default class Common {
99115
* @constructor
100116
*/
101117
constructor(opts: CommonOpts) {
118+
this._customChains = opts.customChains ?? []
102119
this._chainParams = this.setChain(opts.chain)
120+
this.DEFAULT_HARDFORK = this._chainParams.defaultHardfork ?? 'istanbul'
103121
this._hardfork = this.DEFAULT_HARDFORK
104122
if (opts.supportedHardforks) {
105123
this._supportedHardforks = opts.supportedHardforks
@@ -120,8 +138,13 @@ export default class Common {
120138
*/
121139
setChain(chain: string | number | object): any {
122140
if (typeof chain === 'number' || typeof chain === 'string') {
123-
this._chainParams = Common._getChainParams(chain)
141+
this._chainParams = Common._getChainParams(chain, this._customChains)
124142
} else if (typeof chain === 'object') {
143+
if (this._customChains.length > 0) {
144+
throw new Error(
145+
'Chain must be a string or number when initialized with customChains passed in'
146+
)
147+
}
125148
const required = ['networkId', 'genesis', 'hardforks', 'bootstrapNodes']
126149
for (const param of required) {
127150
if ((<any>chain)[param] === undefined) {
@@ -613,7 +636,7 @@ export default class Common {
613636
* @returns chain name (lower case)
614637
*/
615638
chainName(): string {
616-
return chainParams['names'][this.chainId()] || (<any>this._chainParams)['name']
639+
return (<any>this._chainParams)['name']
617640
}
618641

619642
/**

packages/common/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,18 @@ export interface Chain {
1616
name: string
1717
chainId: number
1818
networkId: number
19+
// TODO: make mandatory in next breaking release
20+
defaultHardfork?: string
1921
comment: string
2022
url: string
2123
genesis: GenesisBlock
2224
hardforks: Hardfork[]
2325
bootstrapNodes: BootstrapNode[]
26+
// TODO: make mandatory in next breaking release
27+
consensus?: {
28+
type: string
29+
algorithm: string
30+
}
2431
}
2532

2633
export interface eipsType {
@@ -40,6 +47,7 @@ export interface GenesisBlock {
4047
export interface Hardfork {
4148
name: string
4249
block: number | null
50+
forkHash?: string | null
4351
}
4452

4553
export interface BootstrapNode {

packages/common/tests/chains.ts

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -119,39 +119,4 @@ tape('[Common]: Initialization / Chain params', function (t: tape.Test) {
119119

120120
st.end()
121121
})
122-
123-
t.test(
124-
'Should provide correct access to private network chain parameters',
125-
function (st: tape.Test) {
126-
const chainParams = require('./testnet.json')
127-
const c = new Common({ chain: chainParams, hardfork: 'byzantium' })
128-
st.equal(c.chainName(), 'testnet', 'should initialize with chain name')
129-
st.equal(c.chainId(), 12345, 'should return correct chain Id')
130-
st.equal(c.networkId(), 12345, 'should return correct network Id')
131-
st.equal(
132-
c.genesis().hash,
133-
'0xaa00000000000000000000000000000000000000000000000000000000000000',
134-
'should return correct genesis hash'
135-
)
136-
st.equal(c.hardforks()[3]['block'], 3, 'should return correct hardfork data')
137-
st.equal(c.bootstrapNodes()[1].ip, '10.0.0.2', 'should return a bootstrap node array')
138-
139-
st.end()
140-
}
141-
)
142-
143-
t.test('Should handle custom chain parameters with missing field', function (st: tape.Test) {
144-
const chainParams = require('./testnet.json')
145-
delete chainParams['hardforks']
146-
st.throws(
147-
function () {
148-
new Common({ chain: chainParams })
149-
},
150-
/Missing required/,
151-
'should throw an exception on missing parameter'
152-
) // eslint-disable-line no-new
153-
154-
st.comment('-----------------------------------------------------------------')
155-
st.end()
156-
})
157122
})

0 commit comments

Comments
 (0)