Skip to content

Commit 417b466

Browse files
authored
More example rewrites (#3228)
* Add common examples * Partial blockchain examples * Add simple blockchain example * Add remaining blockchain example * revert test changes
1 parent 7bcb197 commit 417b466

File tree

14 files changed

+446
-39
lines changed

14 files changed

+446
-39
lines changed

packages/blockchain/README.md

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,58 @@ The library also supports reorg scenarios e.g. by allowing to add a new block wi
3636
The following is an example to instantiate a simple Blockchain object, put blocks into the blockchain and then iterate through the blocks added:
3737

3838
```ts
39+
// ./examples/simple.ts
40+
41+
import { Block } from '@ethereumjs/block'
3942
import { Blockchain } from '@ethereumjs/blockchain'
43+
import { Common, Hardfork } from '@ethereumjs/common'
4044
import { bytesToHex } from '@ethereumjs/util'
4145

42-
// Use the safe static constructor which awaits the init method
43-
const blockchain = Blockchain.create({ common, db })
44-
45-
// See @ethereumjs/block on how to create a block
46-
await blockchain.putBlock(block1)
47-
await blockchain.putBlock(block2)
48-
49-
blockchain.iterator('i', (block) => {
50-
const blockNumber = block.header.number.toString()
51-
const blockHash = bytesToHex(block.hash())
52-
console.log(`Block ${blockNumber}: ${blockHash}`)
53-
})
46+
const main = async () => {
47+
const common = new Common({ chain: 'mainnet', hardfork: Hardfork.London })
48+
// Use the safe static constructor which awaits the init method
49+
const blockchain = await Blockchain.create({
50+
validateBlocks: false, // Skipping validation so we can make a simple chain without having to provide complete blocks
51+
validateConsensus: false,
52+
common,
53+
})
54+
55+
// We use minimal data to provide a sequence of blocks (increasing number, difficulty, and then setting parent hash to previous block)
56+
const block = Block.fromBlockData(
57+
{
58+
header: {
59+
number: 1n,
60+
parentHash: blockchain.genesisBlock.hash(),
61+
difficulty: blockchain.genesisBlock.header.difficulty + 1n,
62+
},
63+
},
64+
{ common, setHardfork: true }
65+
)
66+
const block2 = Block.fromBlockData(
67+
{
68+
header: {
69+
number: 2n,
70+
parentHash: block.header.hash(),
71+
difficulty: block.header.difficulty + 1n,
72+
},
73+
},
74+
{ common, setHardfork: true }
75+
)
76+
// See @ethereumjs/block for more details on how to create a block
77+
await blockchain.putBlock(block)
78+
await blockchain.putBlock(block2)
79+
80+
// We iterate over the blocks in the chain to the current head (block 2)
81+
await blockchain.iterator('i', (block) => {
82+
const blockNumber = block.header.number.toString()
83+
const blockHash = bytesToHex(block.hash())
84+
console.log(`Block ${blockNumber}: ${blockHash}`)
85+
})
86+
87+
// Block 1: 0xa1a061528d74ba81f560e1ebc4f29d6b58171fc13b72b876cdffe6e43b01bdc5
88+
// Block 2: 0x5583be91cf9fb14f5dbeb03ad56e8cef19d1728f267c35a25ba5a355a528f602
89+
}
90+
main()
5491
```
5592

5693
### Database Abstraction / Removed LevelDB Dependency
@@ -102,18 +139,29 @@ A genesis state can be set along `Blockchain` creation by passing in a custom `g
102139
For many custom chains we might come across a genesis configuration, which can be used to build both chain config as well the genesis state (and hence the genesis block as well to start off with)
103140

104141
```ts
105-
import { Blockchain, parseGethGenesisState } from '@ethereumjs/blockchain'
106-
import { Common, parseGethGenesis } from '@ethereumjs/common'
142+
// ./examples/gethGenesis.ts
107143

108-
// Load geth genesis json file into lets say `gethGenesisJson`
109-
const common = Common.fromGethGenesis(gethGenesisJson, { chain: 'customChain' })
110-
const genesisState = parseGethGenesisState(gethGenesisJson)
111-
const blockchain = await Blockchain.create({
112-
genesisState,
113-
common,
114-
})
115-
const genesisBlockHash = blockchain.genesisBlock.hash()
116-
common.setForkHashes(genesisBlockHash)
144+
import { Blockchain } from '@ethereumjs/blockchain'
145+
import { Common, parseGethGenesis } from '@ethereumjs/common'
146+
import { bytesToHex, parseGethGenesisState } from '@ethereumjs/util'
147+
import gethGenesisJson from './genesisData/post-merge.json'
148+
149+
const main = async () => {
150+
// Load geth genesis json file into lets say `gethGenesisJson`
151+
const common = Common.fromGethGenesis(gethGenesisJson, { chain: 'customChain' })
152+
const genesisState = parseGethGenesisState(gethGenesisJson)
153+
const blockchain = await Blockchain.create({
154+
genesisState,
155+
common,
156+
})
157+
const genesisBlockHash = blockchain.genesisBlock.hash()
158+
common.setForkHashes(genesisBlockHash)
159+
console.log(
160+
`Genesis hash from geth genesis parameters - ${bytesToHex(blockchain.genesisBlock.hash())}`
161+
)
162+
}
163+
164+
main()
117165
```
118166

119167
The genesis block from the initialized `Blockchain` can be retrieved via the `Blockchain.genesisBlock` getter. For creating a genesis block from the params in `@ethereumjs/common`, the `createGenesisBlock(stateRoot: Buffer): Block` method can be used.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"config": {
3+
"chainId": 1,
4+
"homesteadBlock": 0,
5+
"eip150Block": 0,
6+
"eip155Block": 0,
7+
"eip158Block": 0,
8+
"byzantiumBlock": 0,
9+
"constantinopleBlock": 0,
10+
"petersburgBlock": 0,
11+
"istanbulBlock": 0,
12+
"muirGlacierBlock": 0,
13+
"berlinBlock": 0,
14+
"londonBlock": 0,
15+
"clique": {
16+
"period": 5,
17+
"epoch": 30000
18+
},
19+
"terminalTotalDifficulty": 0
20+
},
21+
"nonce": "0x42",
22+
"timestamp": "0x0",
23+
"extraData": "0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
24+
"gasLimit": "0x1C9C380",
25+
"difficulty": "0x400000000",
26+
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
27+
"coinbase": "0x0000000000000000000000000000000000000000",
28+
"alloc": {
29+
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { "balance": "0x6d6172697573766477000000" }
30+
},
31+
"number": "0x0",
32+
"gasUsed": "0x0",
33+
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
34+
"baseFeePerGas": "0x7"
35+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Blockchain } from '@ethereumjs/blockchain'
2+
import { Common, parseGethGenesis } from '@ethereumjs/common'
3+
import { bytesToHex, parseGethGenesisState } from '@ethereumjs/util'
4+
import gethGenesisJson from './genesisData/post-merge.json'
5+
6+
const main = async () => {
7+
// Load geth genesis json file into lets say `gethGenesisJson`
8+
const common = Common.fromGethGenesis(gethGenesisJson, { chain: 'customChain' })
9+
const genesisState = parseGethGenesisState(gethGenesisJson)
10+
const blockchain = await Blockchain.create({
11+
genesisState,
12+
common,
13+
})
14+
const genesisBlockHash = blockchain.genesisBlock.hash()
15+
common.setForkHashes(genesisBlockHash)
16+
console.log(
17+
`Genesis hash from geth genesis parameters - ${bytesToHex(blockchain.genesisBlock.hash())}`
18+
)
19+
}
20+
21+
main()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Block } from '@ethereumjs/block'
2+
import { Blockchain } from '@ethereumjs/blockchain'
3+
import { Common, Hardfork } from '@ethereumjs/common'
4+
import { bytesToHex } from '@ethereumjs/util'
5+
6+
const main = async () => {
7+
const common = new Common({ chain: 'mainnet', hardfork: Hardfork.London })
8+
// Use the safe static constructor which awaits the init method
9+
const blockchain = await Blockchain.create({
10+
validateBlocks: false, // Skipping validation so we can make a simple chain without having to provide complete blocks
11+
validateConsensus: false,
12+
common,
13+
})
14+
15+
// We use minimal data to provide a sequence of blocks (increasing number, difficulty, and then setting parent hash to previous block)
16+
const block = Block.fromBlockData(
17+
{
18+
header: {
19+
number: 1n,
20+
parentHash: blockchain.genesisBlock.hash(),
21+
difficulty: blockchain.genesisBlock.header.difficulty + 1n,
22+
},
23+
},
24+
{ common, setHardfork: true }
25+
)
26+
const block2 = Block.fromBlockData(
27+
{
28+
header: {
29+
number: 2n,
30+
parentHash: block.header.hash(),
31+
difficulty: block.header.difficulty + 1n,
32+
},
33+
},
34+
{ common, setHardfork: true }
35+
)
36+
// See @ethereumjs/block for more details on how to create a block
37+
await blockchain.putBlock(block)
38+
await blockchain.putBlock(block2)
39+
40+
// We iterate over the blocks in the chain to the current head (block 2)
41+
await blockchain.iterator('i', (block) => {
42+
const blockNumber = block.header.number.toString()
43+
const blockHash = bytesToHex(block.hash())
44+
console.log(`Block ${blockNumber}: ${blockHash}`)
45+
})
46+
47+
// Block 1: 0xa1a061528d74ba81f560e1ebc4f29d6b58171fc13b72b876cdffe6e43b01bdc5
48+
// Block 2: 0x5583be91cf9fb14f5dbeb03ad56e8cef19d1728f267c35a25ba5a355a528f602
49+
}
50+
main()

packages/blockchain/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"coverage": "DEBUG=ethjs npx vitest run --coverage.enabled --coverage.reporter=lcov",
3636
"docs:build": "typedoc --options typedoc.cjs",
3737
"examples": "tsx ../../scripts/examples-runner.ts -- blockchain",
38+
"examples:build": "npx embedme README.md",
3839
"lint": "../../config/cli/lint.sh",
3940
"lint:diff": "../../config/cli/lint-diff.sh",
4041
"lint:fix": "../../config/cli/lint-fix.sh",

packages/common/README.md

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ const { Common, Chain, Hardfork } = require('@ethereumjs/common')
4040
All parameters can be accessed through the `Common` class, instantiated with an object containing either the `chain` (e.g. 'Chain.Mainnet') or the `chain` together with a specific `hardfork` provided:
4141

4242
```ts
43+
// ./examples/common.ts#L1-L7
44+
45+
import { Chain, Common, Hardfork } from '@ethereumjs/common'
46+
4347
// With enums:
44-
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
48+
const commonWithEnums = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
4549

4650
// (also possible with directly passing in strings:)
47-
const common = new Common({ chain: 'mainnet', hardfork: 'london' })
51+
const commonWithStrings = new Common({ chain: 'mainnet', hardfork: 'london' })
4852
```
4953

5054
If no hardfork is provided, the common is initialized with the default hardfork.
@@ -54,19 +58,23 @@ Current `DEFAULT_HARDFORK`: `Hardfork.Shanghai`
5458
Here are some simple usage examples:
5559

5660
```ts
61+
// ./examples/common.ts#L9-L23
62+
5763
// Instantiate with the chain (and the default hardfork)
5864
let c = new Common({ chain: Chain.Mainnet })
59-
c.param('gasPrices', 'ecAddGas') // 500
65+
console.log(`The gas price for ecAdd is ${c.param('gasPrices', 'ecAddGas')}`) // 500
6066

6167
// Chain and hardfork provided
6268
c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium })
63-
c.param('pow', 'minerReward') // 3000000000000000000
69+
console.log(`The miner reward under PoW on Byzantium us ${c.param('pow', 'minerReward')}`) // 3000000000000000000
6470

6571
// Get bootstrap nodes for chain/network
66-
c.bootstrapNodes() // Array with current nodes
72+
console.log('Below are the known bootstrap nodes')
73+
console.log(c.bootstrapNodes()) // Array with current nodes
6774

6875
// Instantiate with an EIP activated
6976
c = new Common({ chain: Chain.Mainnet, eips: [4844] })
77+
console.log(`EIP 4844 is active -- ${c.isActivatedEIP(4844)}`)
7078
```
7179

7280
## Browser
@@ -167,7 +175,11 @@ There are two distinct APIs available for setting up custom(ized) chains.
167175
There is a dedicated `Common.custom()` static constructor which allows for an easy instantiation of a Common instance with somewhat adopted chain parameters, with the main use case to adopt on instantiating with a deviating chain ID (you can use this to adopt other chain parameters as well though). Instantiating a custom common instance with its own chain ID and inheriting all other parameters from `mainnet` can now be as easily done as:
168176

169177
```ts
170-
const common = Common.custom({ chainId: 1234 })
178+
// ./examples/common.ts#L25-L27
179+
180+
// Instantiate common with custom chainID
181+
const commonWithCustomChainId = Common.custom({ chainId: 1234 })
182+
console.log(`The current chain ID is ${commonWithCustomChainId.chainId}`)
171183
```
172184

173185
The `custom()` method also takes a string as a first input (instead of a dictionary). This can be used in combination with the `CustomChain` enum dict which allows for the selection of predefined supported custom chains for an easier `Common` setup of these supported chains:
@@ -194,8 +206,14 @@ you can pass a dictionary - conforming to the parameter format described above -
194206
values to the constructor using the `chain` parameter or the `setChain()` method, here is some example:
195207

196208
```ts
197-
import myCustomChain from './[PATH]/myCustomChain.js'
198-
const common = new Common({ chain: myCustomChain })
209+
// ./examples/customChain.ts
210+
211+
import { Common } from '@ethereumjs/common'
212+
import myCustomChain1 from './genesisData/testnet.json'
213+
214+
// Add custom chain config
215+
const common1 = new Common({ chain: myCustomChain1 })
216+
console.log(`Common is instantiated with custom chain parameters - ${common1.chainName()}`)
199217
```
200218

201219
#### Initialize using customChains Array
@@ -208,17 +226,23 @@ use the `chain` option to activate one of the custom chains passed or activate a
208226
(e.g. `mainnet`) and switch to other chains - including the custom ones - by using `Common.setChain()`.
209227

210228
```ts
211-
import myCustomChain1 from './[PATH]/myCustomChain1.js'
212-
import myCustomChain2 from './[PATH]/myCustomChain2.js'
229+
// ./examples/customChains.ts
230+
231+
import { Common } from '@ethereumjs/common'
232+
import myCustomChain1 from './genesisData/testnet.json'
233+
import myCustomChain2 from './genesisData/testnet2.json'
213234
// Add two custom chains, initial mainnet activation
214235
const common1 = new Common({ chain: 'mainnet', customChains: [myCustomChain1, myCustomChain2] })
215-
// Somewhat later down the road...
216-
common1.setChain('customChain1')
236+
console.log(`Common is instantiated with mainnet parameters - ${common1.chainName()}`)
237+
common1.setChain('testnet1')
238+
console.log(`Common is set to use testnet parameters - ${common1.chainName()}`)
217239
// Add two custom chains, activate customChain1
218-
const common1 = new Common({
219-
chain: 'customChain1',
240+
const common2 = new Common({
241+
chain: 'testnet2',
220242
customChains: [myCustomChain1, myCustomChain2],
221243
})
244+
245+
console.log(`Common is instantiated with testnet2 parameters - ${common1.chainName()}`)
222246
```
223247

224248
Starting with v3 custom genesis states should be passed to the [Blockchain](../blockchain/) library directly.
@@ -230,23 +254,34 @@ has both config specification for the chain as well as the genesis state specifi
230254
common from such configuration in the following manner:
231255

232256
```ts
257+
// ./examples/fromGeth.ts
258+
233259
import { Common } from '@ethereumjs/common'
260+
import { hexToBytes } from '@ethereumjs/util'
234261

262+
import genesisJson from './genesisData/post-merge.json'
263+
264+
const genesisHash = hexToBytes('0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a')
235265
// Load geth genesis json file into lets say `genesisJson` and optional `chain` and `genesisHash`
236266
const common = Common.fromGethGenesis(genesisJson, { chain: 'customChain', genesisHash })
237267
// If you don't have `genesisHash` while initiating common, you can later configure common (for e.g.
238-
// post calculating it via `blockchain`)
268+
// after calculating it via `blockchain`)
239269
common.setForkHashes(genesisHash)
270+
271+
console.log(`The London forkhash for this custom chain is ${common.forkHash('london')}`)
240272
```
241273

242274
### Hardforks
243275

244276
The `hardfork` can be set in constructor like this:
245277

246278
```ts
279+
// ./examples/common.ts#L1-L4
280+
247281
import { Chain, Common, Hardfork } from '@ethereumjs/common'
248282

249-
const c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium })
283+
// With enums:
284+
const commonWithEnums = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
250285
```
251286

252287
### Active Hardforks

packages/common/examples/common.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Chain, Common, Hardfork } from '@ethereumjs/common'
2+
3+
// With enums:
4+
const commonWithEnums = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
5+
6+
// (also possible with directly passing in strings:)
7+
const commonWithStrings = new Common({ chain: 'mainnet', hardfork: 'london' })
8+
9+
// Instantiate with the chain (and the default hardfork)
10+
let c = new Common({ chain: Chain.Mainnet })
11+
console.log(`The gas price for ecAdd is ${c.param('gasPrices', 'ecAddGas')}`) // 500
12+
13+
// Chain and hardfork provided
14+
c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium })
15+
console.log(`The miner reward under PoW on Byzantium us ${c.param('pow', 'minerReward')}`) // 3000000000000000000
16+
17+
// Get bootstrap nodes for chain/network
18+
console.log('Below are the known bootstrap nodes')
19+
console.log(c.bootstrapNodes()) // Array with current nodes
20+
21+
// Instantiate with an EIP activated
22+
c = new Common({ chain: Chain.Mainnet, eips: [4844] })
23+
console.log(`EIP 4844 is active -- ${c.isActivatedEIP(4844)}`)
24+
25+
// Instantiate common with custom chainID
26+
const commonWithCustomChainId = Common.custom({ chainId: 1234 })
27+
console.log(`The current chain ID is ${commonWithCustomChainId.chainId}`)

0 commit comments

Comments
 (0)