@nomicfoundation/ethereumjs-common
Advanced tools
Comparing version 4.0.3 to 4.0.4
{ | ||
"name": "@nomicfoundation/ethereumjs-common", | ||
"version": "4.0.3", | ||
"version": "4.0.4", | ||
"description": "Resources common to all Ethereum implementations", | ||
@@ -29,4 +29,5 @@ "keywords": [ | ||
], | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"type": "commonjs", | ||
"main": "dist/cjs/index.js", | ||
"module": "dist/esm/index.js", | ||
"files": [ | ||
@@ -39,17 +40,17 @@ "dist", | ||
"clean": "../../config/cli/clean-package.sh", | ||
"coverage": "../../config/cli/coverage.sh", | ||
"docs:build": "typedoc --options typedoc.js", | ||
"coverage": "DEBUG=ethjs npx vitest run --coverage.enabled --coverage.reporter=lcov", | ||
"docs:build": "typedoc --options typedoc.cjs", | ||
"examples": "tsx ../../scripts/examples-runner.ts -- common", | ||
"examples:build": "npx embedme README.md", | ||
"lint": "../../config/cli/lint.sh", | ||
"lint:diff": "../../config/cli/lint-diff.sh", | ||
"lint:fix": "../../config/cli/lint-fix.sh", | ||
"tape": "tape -r ts-node/register", | ||
"test": "npm run test:node && npm run test:browser", | ||
"test:browser": "karma start karma.conf.js", | ||
"test:node": "npm run tape -- ./test/*.spec.ts", | ||
"test:browser": "npx vitest run --browser.name=chrome --browser.headless", | ||
"test:node": "npx vitest run", | ||
"tsc": "../../config/cli/ts-compile.sh" | ||
}, | ||
"dependencies": { | ||
"@nomicfoundation/ethereumjs-util": "9.0.3", | ||
"crc-32": "^1.2.0" | ||
"@nomicfoundation/ethereumjs-util": "9.0.4" | ||
} | ||
} |
206
README.md
@@ -28,4 +28,4 @@ # @ethereumjs/common | ||
```typescript | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common | ||
```ts | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
``` | ||
@@ -35,16 +35,20 @@ | ||
```typescript | ||
```ts | ||
const { Common, Chain, Hardfork } = require('@ethereumjs/common') | ||
``` | ||
## Parameters | ||
### Parameters | ||
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: | ||
```typescript | ||
```ts | ||
// ./examples/common.ts#L1-L7 | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
// With enums: | ||
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) | ||
const commonWithEnums = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) | ||
// (also possible with directly passing in strings:) | ||
const common = new Common({ chain: 'mainnet', hardfork: 'london' }) | ||
const commonWithStrings = new Common({ chain: 'mainnet', hardfork: 'london' }) | ||
``` | ||
@@ -54,24 +58,34 @@ | ||
Current `DEFAULT_HARDFORK`: `Hardfork.Merge` | ||
Current `DEFAULT_HARDFORK`: `Hardfork.Shanghai` | ||
Here are some simple usage examples: | ||
```typescript | ||
```ts | ||
// ./examples/common.ts#L9-L23 | ||
// Instantiate with the chain (and the default hardfork) | ||
let c = new Common({ chain: Chain.Ropsten }) | ||
c.param('gasPrices', 'ecAddGas') // 500 | ||
let c = new Common({ chain: Chain.Mainnet }) | ||
console.log(`The gas price for ecAdd is ${c.param('gasPrices', 'ecAddGas')}`) // 500 | ||
// Chain and hardfork provided | ||
c = new Common({ chain: Chain.Ropsten, hardfork: Hardfork.Byzantium }) | ||
c.param('pow', 'minerReward') // 3000000000000000000 | ||
c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }) | ||
console.log(`The miner reward under PoW on Byzantium us ${c.param('pow', 'minerReward')}`) // 3000000000000000000 | ||
// Get bootstrap nodes for chain/network | ||
c.bootstrapNodes() // Array with current nodes | ||
console.log('Below are the known bootstrap nodes') | ||
console.log(c.bootstrapNodes()) // Array with current nodes | ||
// Instantiate with an EIP activated | ||
c = new Common({ chain: Chain.Mainnet, eips: [2537] }) | ||
c = new Common({ chain: Chain.Mainnet, eips: [4844] }) | ||
console.log(`EIP 4844 is active -- ${c.isActivatedEIP(4844)}`) | ||
``` | ||
# API | ||
## Browser | ||
With the breaking release round in Summer 2023 we have added hybrid ESM/CJS builds for all our libraries (see section below) and have eliminated many of the caveats which had previously prevented a frictionless browser usage. | ||
It is now easily possible to run a browser build of one of the EthereumJS libraries within a modern browser using the provided ESM build. For a setup example see [./examples/browser.html](./examples/browser.html). | ||
## API | ||
### Docs | ||
@@ -86,2 +100,26 @@ | ||
### Hybrid CJS/ESM Builds | ||
With the breaking releases from Summer 2023 we have started to ship our libraries with both CommonJS (`cjs` folder) and ESM builds (`esm` folder), see `package.json` for the detailed setup. | ||
If you use an ES6-style `import` in your code files from the ESM build will be used: | ||
```ts | ||
import { EthereumJSClass } from '@ethereumjs/[PACKAGE_NAME]' | ||
``` | ||
If you use Node.js specific `require`, the CJS build will be used: | ||
```ts | ||
const { EthereumJSClass } = require('@ethereumjs/[PACKAGE_NAME]') | ||
``` | ||
Using ESM will give you additional advantages over CJS beyond browser usage like static code analysis / Tree Shaking which CJS can not provide. | ||
### Buffer -> Uint8Array | ||
With the breaking releases from Summer 2023 we have removed all Node.js specific `Buffer` usages from our libraries and replace these with [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) representations, which are available both in Node.js and the browser (`Buffer` is a subclass of `Uint8Array`). | ||
We have converted existing Buffer conversion methods to Uint8Array conversion methods in the [@ethereumjs/util](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/util) `bytes` module, see the respective README section for guidance. | ||
### BigInt Support | ||
@@ -95,4 +133,3 @@ | ||
The `Common` class is implemented as an `EventEmitter` and is emitting the following events | ||
on which you can react within your code: | ||
The `Common` class has a public property `events` which contains an `EventEmitter`. Following events are emitted on which you can react within your code: | ||
@@ -109,4 +146,4 @@ | Event | Description | | ||
```typescript | ||
const c = new Common({ chain: Chain.Ropsten }) | ||
```ts | ||
const c = new Common({ chain: Chain.Mainnet }) | ||
``` | ||
@@ -117,6 +154,5 @@ | ||
- `mainnet` (`Chain.Mainnet`) | ||
- `ropsten` (`Chain.Ropsten`) | ||
- `rinkeby` (`Chain.Rinkeby`) | ||
- `goerli` (`Chain.Goerli`) | ||
- `sepolia` (`Chain.Sepolia`) (`v2.6.1`+) | ||
- `holesky` (`Chain.Holesky`) (`v4.1.0`+) | ||
- Private/custom chain parameters | ||
@@ -137,4 +173,4 @@ | ||
To get an overview of the different parameters have a look at one of the chain-specific | ||
files like `mainnet.json` in the `chains` directory, or to the `Chain` type in [./src/types.ts](./src/types.ts). | ||
To get an overview of the different parameters have a look at one of the chain configurations in the `chains.ts` configuration | ||
file, or to the `Chain` type in [./src/types.ts](./src/types.ts). | ||
@@ -149,4 +185,8 @@ ### Working with private/custom chains | ||
```typescript | ||
const common = Common.custom({ chainId: 1234 }) | ||
```ts | ||
// ./examples/common.ts#L25-L27 | ||
// Instantiate common with custom chainID | ||
const commonWithCustomChainId = Common.custom({ chainId: 1234 }) | ||
console.log(`The current chain ID is ${commonWithCustomChainId.chainId}`) | ||
``` | ||
@@ -156,3 +196,3 @@ | ||
```typescript | ||
```ts | ||
const common = Common.custom(CustomChain.ArbitrumRinkebyTestnet) | ||
@@ -178,5 +218,11 @@ ``` | ||
```typescript | ||
import myCustomChain from './[PATH]/myCustomChain.json' | ||
const common = new Common({ chain: myCustomChain }) | ||
```ts | ||
// ./examples/customChain.ts | ||
import { Common } from '@ethereumjs/common' | ||
import myCustomChain1 from './genesisData/testnet.json' | ||
// Add custom chain config | ||
const common1 = new Common({ chain: myCustomChain1 }) | ||
console.log(`Common is instantiated with custom chain parameters - ${common1.chainName()}`) | ||
``` | ||
@@ -193,14 +239,20 @@ | ||
```typescript | ||
import myCustomChain1 from './[PATH]/myCustomChain1.json' | ||
import myCustomChain2 from './[PATH]/myCustomChain2.json' | ||
```ts | ||
// ./examples/customChains.ts | ||
import { Common } from '@ethereumjs/common' | ||
import myCustomChain1 from './genesisData/testnet.json' | ||
import myCustomChain2 from './genesisData/testnet2.json' | ||
// Add two custom chains, initial mainnet activation | ||
const common1 = new Common({ chain: 'mainnet', customChains: [myCustomChain1, myCustomChain2] }) | ||
// Somewhat later down the road... | ||
common1.setChain('customChain1') | ||
console.log(`Common is instantiated with mainnet parameters - ${common1.chainName()}`) | ||
common1.setChain('testnet1') | ||
console.log(`Common is set to use testnet parameters - ${common1.chainName()}`) | ||
// Add two custom chains, activate customChain1 | ||
const common1 = new Common({ | ||
chain: 'customChain1', | ||
const common2 = new Common({ | ||
chain: 'testnet2', | ||
customChains: [myCustomChain1, myCustomChain2], | ||
}) | ||
console.log(`Common is instantiated with testnet2 parameters - ${common1.chainName()}`) | ||
``` | ||
@@ -216,10 +268,18 @@ | ||
```typescript | ||
```ts | ||
// ./examples/fromGeth.ts | ||
import { Common } from '@ethereumjs/common' | ||
import { hexToBytes } from '@ethereumjs/util' | ||
import genesisJson from './genesisData/post-merge.json' | ||
const genesisHash = hexToBytes('0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a') | ||
// Load geth genesis json file into lets say `genesisJson` and optional `chain` and `genesisHash` | ||
const common = Common.fromGethGenesis(genesisJson, { chain: 'customChain', genesisHash }) | ||
// If you don't have `genesisHash` while initiating common, you can later configure common (for e.g. | ||
// post calculating it via `blockchain`) | ||
// after calculating it via `blockchain`) | ||
common.setForkHashes(genesisHash) | ||
console.log(`The London forkhash for this custom chain is ${common.forkHash('london')}`) | ||
``` | ||
@@ -231,6 +291,9 @@ | ||
```typescript | ||
```ts | ||
// ./examples/common.ts#L1-L4 | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
const c = new Common({ chain: Chain.Ropsten, hardfork: Hardfork.Byzantium }) | ||
// With enums: | ||
const commonWithEnums = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) | ||
``` | ||
@@ -257,6 +320,7 @@ | ||
- `shanghai` (`Hardfork.Shanghai`) (since `v3.1.0`) | ||
- `cancun` (`Hardfork.Cancun`) (since `v4.0.0`) | ||
### Future Hardforks | ||
The next upcoming HF `Hardfork.Cancun` is currently not yet supported by this library. | ||
The next upcoming HF `Hardfork.Prague` is currently not yet supported by this library. | ||
@@ -274,7 +338,7 @@ ### Parameter Access | ||
See one of the hardfork files like `byzantium.json` in the `hardforks` directory | ||
See one of the hardfork configurations in the `hardforks.ts` file | ||
for an overview. For consistency, the chain start (`chainstart`) is considered an own | ||
hardfork. | ||
The hardfork-specific json files only contain the deltas from `chainstart` and | ||
The hardfork configurations above `chainstart` only contain the deltas from `chainstart` and | ||
shouldn't be accessed directly until you have a specific reason for it. | ||
@@ -287,4 +351,4 @@ | ||
```typescript | ||
const c = new Common({ chain: Chain.Mainnet, eips: [2537] }) | ||
```ts | ||
const c = new Common({ chain: Chain.Mainnet, eips: [4844] }) | ||
``` | ||
@@ -294,23 +358,31 @@ | ||
- [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559): Fee market change for ETH 1.0 chain | ||
- [EIP-2315](https://eips.ethereum.org/EIPS/eip-2315): Simple subroutines for the EVM (`experimental`) | ||
- [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537): BLS precompiles | ||
- [EIP-2565](https://eips.ethereum.org/EIPS/eip-2565): ModExp gas cost | ||
- [EIP-2718](https://eips.ethereum.org/EIPS/eip-2565): Transaction Types | ||
- [EIP-2929](https://eips.ethereum.org/EIPS/eip-2929): gas cost increases for state access opcodes | ||
- [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930): Optional access list tx type | ||
- [EIP-3198](https://eips.ethereum.org/EIPS/eip-3198): Base fee Opcode | ||
- [EIP-3529](https://eips.ethereum.org/EIPS/eip-3529): Reduction in refunds | ||
- [EIP-3540](https://eips.ethereum.org/EIPS/eip-3541) - EVM Object Format (EOF) v1 (`experimental`) | ||
- [EIP-3541](https://eips.ethereum.org/EIPS/eip-3541): Reject new contracts starting with the 0xEF byte | ||
- [EIP-3554](https://eips.ethereum.org/EIPS/eip-3554): Difficulty Bomb Delay to December 2021 (only PoW networks) | ||
- [EIP-3607](https://eips.ethereum.org/EIPS/eip-3607): Reject transactions from senders with deployed code | ||
- [EIP-3651](https://eips.ethereum.org/EIPS/eip-3651): Warm COINBASE (Shanghai) | ||
- [EIP-3670](https://eips.ethereum.org/EIPS/eip-3670): EOF - Code Validation (`experimental`) | ||
- [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675): Upgrade consensus to Proof-of-Stake | ||
- [EIP-3855](https://eips.ethereum.org/EIPS/eip-3855): Push0 opcode (Shanghai) | ||
- [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860): Limit and meter initcode (Shanghai) | ||
- [EIP-4345](https://eips.ethereum.org/EIPS/eip-4345): Difficulty Bomb Delay to June 2022 | ||
- [EIP-4399](https://eips.ethereum.org/EIPS/eip-4399): Supplant DIFFICULTY opcode with PREVRANDAO (Merge) (`experimental`) | ||
- [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895): Beacon chain push withdrawals as operations (Shanghai) | ||
- [EIP-1153](https://eips.ethereum.org/EIPS/eip-1153) - Transient storage opcodes (Cancun) | ||
- [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) - Fee market change for ETH 1.0 chain | ||
- [EIP-2315](https://eips.ethereum.org/EIPS/eip-2315) - Simple subroutines for the EVM (`outdated`) | ||
- [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) - BLS precompiles (removed in v4.0.0, see latest v3 release) | ||
- [EIP-2565](https://eips.ethereum.org/EIPS/eip-2565) - ModExp gas cost | ||
- [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) - Transaction Types | ||
- [EIP-2929](https://eips.ethereum.org/EIPS/eip-2929) - gas cost increases for state access opcodes | ||
- [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) - Optional access list tx type | ||
- [EIP-3074](https://eips.ethereum.org/EIPS/eip-3074) - AUTH and AUTHCALL opcodes | ||
- [EIP-3198](https://eips.ethereum.org/EIPS/eip-3198) - Base fee Opcode | ||
- [EIP-3529](https://eips.ethereum.org/EIPS/eip-3529) - Reduction in refunds | ||
- [EIP-3540](https://eips.ethereum.org/EIPS/eip-3540) - EVM Object Format (EOF) v1 (`outdated`) | ||
- [EIP-3541](https://eips.ethereum.org/EIPS/eip-3541) - Reject new contracts starting with the 0xEF byte | ||
- [EIP-3554](https://eips.ethereum.org/EIPS/eip-3554) - Difficulty Bomb Delay to December 2021 (only PoW networks) | ||
- [EIP-3607](https://eips.ethereum.org/EIPS/eip-3607) - Reject transactions from senders with deployed code | ||
- [EIP-3651](https://eips.ethereum.org/EIPS/eip-3651) - Warm COINBASE (Shanghai) | ||
- [EIP-3670](https://eips.ethereum.org/EIPS/eip-3670) - EOF - Code Validation (`outdated`) | ||
- [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675) - Upgrade consensus to Proof-of-Stake | ||
- [EIP-3855](https://eips.ethereum.org/EIPS/eip-3855) - Push0 opcode (Shanghai) | ||
- [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) - Limit and meter initcode (Shanghai) | ||
- [EIP-4345](https://eips.ethereum.org/EIPS/eip-4345) - Difficulty Bomb Delay to June 2022 | ||
- [EIP-4399](https://eips.ethereum.org/EIPS/eip-4399) - Supplant DIFFICULTY opcode with PREVRANDAO (Merge) | ||
- [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) - Beacon block root in the EVM (Cancun) | ||
- [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) - Shard Blob Transactions (Cancun) (`experimental`) | ||
- [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895) - Beacon chain push withdrawals as operations (Shanghai) | ||
- [EIP-5133](https://eips.ethereum.org/EIPS/eip-5133) - Delaying Difficulty Bomb to mid-September 2022 (Gray Glacier) | ||
- [EIP-5656](https://eips.ethereum.org/EIPS/eip-5656) - MCOPY - Memory copying instruction (Cancun) | ||
- [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780) - SELFDESTRUCT only in same transaction (Cancun) | ||
- [EIP-7516](https://eips.ethereum.org/EIPS/eip-7516) - BLOBBASEFEE opcode (Cancun) | ||
@@ -317,0 +389,0 @@ ### Bootstrap Nodes |
@@ -1,16 +0,20 @@ | ||
import { TypeOutput, intToBuffer, toType } from '@nomicfoundation/ethereumjs-util' | ||
import { buf as crc32Buffer } from 'crc-32' | ||
import { | ||
BIGINT_0, | ||
TypeOutput, | ||
bytesToHex, | ||
concatBytes, | ||
hexToBytes, | ||
intToBytes, | ||
toType, | ||
} from '@nomicfoundation/ethereumjs-util' | ||
import { EventEmitter } from 'events' | ||
import * as goerli from './chains/goerli.json' | ||
import * as mainnet from './chains/mainnet.json' | ||
import * as rinkeby from './chains/rinkeby.json' | ||
import * as ropsten from './chains/ropsten.json' | ||
import * as sepolia from './chains/sepolia.json' | ||
import { EIPs } from './eips' | ||
import { Chain, CustomChain, Hardfork } from './enums' | ||
import { hardforks as HARDFORK_SPECS } from './hardforks' | ||
import { parseGethGenesis } from './utils' | ||
import { chains as CHAIN_SPECS } from './chains.js' | ||
import { crc32 } from './crc.js' | ||
import { EIPs } from './eips.js' | ||
import { Chain, CustomChain, Hardfork } from './enums.js' | ||
import { hardforks as HARDFORK_SPECS } from './hardforks.js' | ||
import { parseGethGenesis } from './utils.js' | ||
import type { ConsensusAlgorithm, ConsensusType } from './enums' | ||
import type { ConsensusAlgorithm, ConsensusType } from './enums.js' | ||
import type { | ||
@@ -25,11 +29,19 @@ BootstrapNodeConfig, | ||
CustomCommonOpts, | ||
CustomCrypto, | ||
EIPConfig, | ||
EIPOrHFConfig, | ||
EthashConfig, | ||
GenesisBlockConfig, | ||
GethConfigOpts, | ||
HardforkByOpts, | ||
HardforkConfig, | ||
} from './types' | ||
import type { BigIntLike } from '@nomicfoundation/ethereumjs-util' | ||
HardforkTransitionConfig, | ||
} from './types.js' | ||
import type { BigIntLike, PrefixedHexString } from '@nomicfoundation/ethereumjs-util' | ||
type HardforkSpecKeys = keyof typeof HARDFORK_SPECS | ||
type HardforkSpecKeys = string // keyof typeof HARDFORK_SPECS | ||
type HardforkSpecValues = typeof HARDFORK_SPECS[HardforkSpecKeys] | ||
type ParamsCacheConfig = Omit<EIPOrHFConfig, 'comment' | 'url' | 'status'> | ||
/** | ||
@@ -43,12 +55,19 @@ * Common class to access chain and hardfork parameters and to provide | ||
*/ | ||
export class Common extends EventEmitter { | ||
export class Common { | ||
readonly DEFAULT_HARDFORK: string | Hardfork | ||
private _chainParams: ChainConfig | ||
private _hardfork: string | Hardfork | ||
private _eips: number[] = [] | ||
private _customChains: ChainConfig[] | ||
protected _chainParams: ChainConfig | ||
protected _hardfork: string | Hardfork | ||
protected _eips: number[] = [] | ||
protected _customChains: ChainConfig[] | ||
private HARDFORK_CHANGES: [HardforkSpecKeys, HardforkSpecValues][] | ||
public readonly customCrypto: CustomCrypto | ||
protected _paramsCache: ParamsCacheConfig = {} | ||
protected _activatedEIPsCache: number[] = [] | ||
protected HARDFORK_CHANGES: [HardforkSpecKeys, HardforkSpecValues][] | ||
public events: EventEmitter | ||
/** | ||
@@ -73,3 +92,3 @@ * Creates a {@link Common} object for a custom chain, based on a standard one. | ||
* network ID and a name) and can only be used for selected use cases (e.g. sending a tx with | ||
* the `@nomicfoundation/ethereumjs-tx` library to a Layer-2 chain). | ||
* the `@ethereumjs/tx` library to a Layer-2 chain). | ||
* | ||
@@ -116,12 +135,2 @@ * @param chainParamsOrName Custom parameter dict (`name` will default to `custom-chain`) or string with name of a supported custom chain | ||
} | ||
if (chainParamsOrName === CustomChain.ArbitrumRinkebyTestnet) { | ||
return Common.custom( | ||
{ | ||
name: CustomChain.ArbitrumRinkebyTestnet, | ||
chainId: 421611, | ||
networkId: 421611, | ||
}, | ||
opts | ||
) | ||
} | ||
if (chainParamsOrName === CustomChain.ArbitrumOne) { | ||
@@ -204,11 +213,11 @@ return Common.custom( | ||
static isSupportedChainId(chainId: bigint): boolean { | ||
const initializedChains = this._getInitializedChains() | ||
const initializedChains = this.getInitializedChains() | ||
return Boolean((initializedChains['names'] as ChainName)[chainId.toString()]) | ||
} | ||
private static _getChainParams( | ||
protected static _getChainParams( | ||
chain: string | number | Chain | bigint, | ||
customChains?: ChainConfig[] | ||
): ChainConfig { | ||
const initializedChains = this._getInitializedChains(customChains) | ||
const initializedChains = this.getInitializedChains(customChains) | ||
if (typeof chain === 'number' || typeof chain === 'bigint') { | ||
@@ -233,6 +242,7 @@ chain = chain.toString() | ||
constructor(opts: CommonOpts) { | ||
super() | ||
this.events = new EventEmitter() | ||
this._customChains = opts.customChains ?? [] | ||
this._chainParams = this.setChain(opts.chain) | ||
this.DEFAULT_HARDFORK = this._chainParams.defaultHardfork ?? Hardfork.Merge | ||
this.DEFAULT_HARDFORK = this._chainParams.defaultHardfork ?? Hardfork.Shanghai | ||
// Assign hardfork changes in the sequence of the applied hardforks | ||
@@ -250,2 +260,8 @@ this.HARDFORK_CHANGES = this.hardforks().map((hf) => [ | ||
} | ||
this.customCrypto = opts.customCrypto ?? {} | ||
if (Object.keys(this._paramsCache).length === 0) { | ||
this._buildParamsCache() | ||
this._buildActivatedEIPsCache() | ||
} | ||
} | ||
@@ -296,3 +312,5 @@ | ||
this._hardfork = hardfork | ||
this.emit('hardforkChanged', hardfork) | ||
this._buildParamsCache() | ||
this._buildActivatedEIPsCache() | ||
this.events.emit('hardforkChanged', hardfork) | ||
} | ||
@@ -308,4 +326,4 @@ existing = true | ||
/** | ||
* Returns the hardfork based on the block number or an optional | ||
* total difficulty (Merge HF) provided. | ||
* Returns the hardfork either based on block numer (older HFs) or | ||
* timestamp (Shanghai upwards). | ||
* | ||
@@ -316,15 +334,11 @@ * An optional TD takes precedence in case the corresponding HF block | ||
* | ||
* @param blockNumber | ||
* @param td : total difficulty of the parent block (for block hf) OR of the chain latest (for chain hf) | ||
* @param timestamp: timestamp in seconds at which block was/is to be minted | ||
* @param Opts Block number, timestamp or TD (all optional) | ||
* @returns The name of the HF | ||
*/ | ||
getHardforkByBlockNumber( | ||
blockNumber: BigIntLike, | ||
td?: BigIntLike, | ||
timestamp?: BigIntLike | ||
): string { | ||
getHardforkBy(opts: HardforkByOpts): string { | ||
let { blockNumber, timestamp, td } = opts | ||
blockNumber = toType(blockNumber, TypeOutput.BigInt) | ||
td = toType(td, TypeOutput.BigInt) | ||
timestamp = toType(timestamp, TypeOutput.Number) | ||
timestamp = toType(timestamp, TypeOutput.BigInt) | ||
@@ -350,4 +364,6 @@ // Filter out hardforks with no block number, no ttd or no timestamp (i.e. unapplied hardforks) | ||
(hf) => | ||
(hf.block !== null && hf.block > blockNumber) || | ||
(timestamp !== undefined && Number(hf.timestamp) > timestamp) | ||
(blockNumber !== undefined && | ||
hf.block !== null && | ||
BigInt(hf.block) > (blockNumber as bigint)) || | ||
(timestamp !== undefined && hf.timestamp !== undefined && hf.timestamp > timestamp) | ||
) | ||
@@ -387,3 +403,3 @@ | ||
throw Error('Maximum HF determined by total difficulty is lower than the block number HF') | ||
} else if (hfIndex < mergeIndex && BigInt(hfs[mergeIndex].ttd!) <= td) { | ||
} else if (hfIndex < mergeIndex && BigInt(hfs[mergeIndex].ttd!) < td) { | ||
throw Error('HF determined by block number is lower than the minimum total difficulty HF') | ||
@@ -407,6 +423,9 @@ } | ||
if (timestamp) { | ||
if (timestamp !== undefined) { | ||
const minTimeStamp = hfs | ||
.slice(0, hfStartIndex) | ||
.reduce((acc: number, hf: HardforkConfig) => Math.max(Number(hf.timestamp ?? '0'), acc), 0) | ||
.reduce( | ||
(acc: number, hf: HardforkTransitionConfig) => Math.max(Number(hf.timestamp ?? '0'), acc), | ||
0 | ||
) | ||
if (minTimeStamp > timestamp) { | ||
@@ -419,4 +438,5 @@ throw Error(`Maximum HF determined by timestamp is lower than the block number/ttd HF`) | ||
.reduce( | ||
(acc: number, hf: HardforkConfig) => Math.min(Number(hf.timestamp ?? timestamp), acc), | ||
timestamp | ||
(acc: number, hf: HardforkTransitionConfig) => | ||
Math.min(Number(hf.timestamp ?? timestamp), acc), | ||
Number(timestamp) | ||
) | ||
@@ -432,4 +452,4 @@ if (maxTimeStamp < timestamp) { | ||
/** | ||
* Sets a new hardfork based on the block number or an optional | ||
* total difficulty (Merge HF) provided. | ||
* Sets a new hardfork either based on block numer (older HFs) or | ||
* timestamp (Shanghai upwards). | ||
* | ||
@@ -440,13 +460,7 @@ * An optional TD takes precedence in case the corresponding HF block | ||
* | ||
* @param blockNumber | ||
* @param td | ||
* @param timestamp | ||
* @param Opts Block number, timestamp or TD (all optional) | ||
* @returns The name of the HF set | ||
*/ | ||
setHardforkByBlockNumber( | ||
blockNumber: BigIntLike, | ||
td?: BigIntLike, | ||
timestamp?: BigIntLike | ||
): string { | ||
const hardfork = this.getHardforkByBlockNumber(blockNumber, td, timestamp) | ||
setHardforkBy(opts: HardforkByOpts): string { | ||
const hardfork = this.getHardforkBy(opts) | ||
this.setHardfork(hardfork) | ||
@@ -461,3 +475,3 @@ return hardfork | ||
*/ | ||
_getHardfork(hardfork: string | Hardfork): HardforkConfig | null { | ||
protected _getHardfork(hardfork: string | Hardfork): HardforkTransitionConfig | null { | ||
const hfs = this.hardforks() | ||
@@ -479,3 +493,3 @@ for (const hf of hfs) { | ||
} | ||
const minHF = this.gteHardfork(EIPs[eip]['minimumHardfork']) | ||
const minHF = this.gteHardfork((EIPs as any)[eip]['minimumHardfork']) | ||
if (!minHF) { | ||
@@ -486,4 +500,10 @@ throw new Error( | ||
} | ||
if (EIPs[eip].requiredEIPs !== undefined) { | ||
for (const elem of EIPs[eip].requiredEIPs) { | ||
} | ||
this._eips = eips | ||
this._buildParamsCache() | ||
this._buildActivatedEIPsCache() | ||
for (const eip of eips) { | ||
if ((EIPs as any)[eip].requiredEIPs !== undefined) { | ||
for (const elem of (EIPs as any)[eip].requiredEIPs) { | ||
if (!(eips.includes(elem) || this.isActivatedEIP(elem))) { | ||
@@ -495,10 +515,81 @@ throw new Error(`${eip} requires EIP ${elem}, but is not included in the EIP list`) | ||
} | ||
this._eips = eips | ||
} | ||
/** | ||
* Internal helper for _buildParamsCache() | ||
*/ | ||
protected _mergeWithParamsCache(params: HardforkConfig | EIPConfig) { | ||
this._paramsCache['gasConfig'] = { | ||
...this._paramsCache['gasConfig'], | ||
...params['gasConfig'], | ||
} | ||
this._paramsCache['gasPrices'] = { | ||
...this._paramsCache['gasPrices'], | ||
...params['gasPrices'], | ||
} | ||
this._paramsCache['pow'] = { | ||
...this._paramsCache['pow'], | ||
...params['pow'], | ||
} | ||
this._paramsCache['sharding'] = { | ||
...this._paramsCache['sharding'], | ||
...params['sharding'], | ||
} | ||
this._paramsCache['vm'] = { | ||
...this._paramsCache['vm'], | ||
...params['vm'], | ||
} | ||
} | ||
/** | ||
* Build up a cache for all parameter values for the current HF and all activated EIPs | ||
*/ | ||
protected _buildParamsCache() { | ||
this._paramsCache = {} | ||
// Iterate through all hardforks up to hardfork set | ||
const hardfork = this.hardfork() | ||
for (const hfChanges of this.HARDFORK_CHANGES) { | ||
// EIP-referencing HF config (e.g. for berlin) | ||
if ('eips' in hfChanges[1]) { | ||
const hfEIPs = hfChanges[1]['eips'] | ||
for (const eip of hfEIPs!) { | ||
if (!(eip in EIPs)) { | ||
throw new Error(`${eip} not supported`) | ||
} | ||
this._mergeWithParamsCache(EIPs[eip]) | ||
} | ||
// Parameter-inlining HF config (e.g. for istanbul) | ||
} else { | ||
this._mergeWithParamsCache(hfChanges[1]) | ||
} | ||
if (hfChanges[0] === hardfork) break | ||
} | ||
// Iterate through all additionally activated EIPs | ||
for (const eip of this._eips) { | ||
if (!(eip in EIPs)) { | ||
throw new Error(`${eip} not supported`) | ||
} | ||
this._mergeWithParamsCache(EIPs[eip]) | ||
} | ||
} | ||
protected _buildActivatedEIPsCache() { | ||
this._activatedEIPsCache = [] | ||
for (const hfChanges of this.HARDFORK_CHANGES) { | ||
const hf = hfChanges[1] | ||
if (this.gteHardfork(hf['name']) && 'eips' in hf) { | ||
this._activatedEIPsCache = this._activatedEIPsCache.concat(hf['eips'] as number[]) | ||
} | ||
} | ||
this._activatedEIPsCache = this._activatedEIPsCache.concat(this._eips) | ||
} | ||
/** | ||
* Returns a parameter for the current chain setup | ||
* | ||
* If the parameter is present in an EIP, the EIP always takes precedence. | ||
* Otherwise the parameter if taken from the latest applied HF with | ||
* Otherwise the parameter is taken from the latest applied HF with | ||
* a change on the respective parameter. | ||
@@ -513,8 +604,10 @@ * | ||
// can change the same parameter | ||
let value | ||
for (const eip of this._eips) { | ||
value = this.paramByEIP(topic, name, eip) | ||
if (value !== undefined) return value | ||
let value = null | ||
if ( | ||
(this._paramsCache as any)[topic] !== undefined && | ||
(this._paramsCache as any)[topic][name] !== undefined | ||
) { | ||
value = (this._paramsCache as any)[topic][name].v | ||
} | ||
return this.paramByHardfork(topic, name, this._hardfork) | ||
return BigInt(value ?? 0) | ||
} | ||
@@ -532,17 +625,17 @@ | ||
for (const hfChanges of this.HARDFORK_CHANGES) { | ||
// EIP-referencing HF file (e.g. berlin.json) | ||
// EIP-referencing HF config (e.g. for berlin) | ||
if ('eips' in hfChanges[1]) { | ||
const hfEIPs = hfChanges[1]['eips'] | ||
for (const eip of hfEIPs) { | ||
for (const eip of hfEIPs!) { | ||
const valueEIP = this.paramByEIP(topic, name, eip) | ||
value = typeof valueEIP === 'bigint' ? valueEIP : value | ||
} | ||
// Parameter-inlining HF file (e.g. istanbul.json) | ||
// Parameter-inlining HF config (e.g. for istanbul) | ||
} else { | ||
if (hfChanges[1][topic] === undefined) { | ||
throw new Error(`Topic ${topic} not defined`) | ||
if ( | ||
(hfChanges[1] as any)[topic] !== undefined && | ||
(hfChanges[1] as any)[topic][name] !== undefined | ||
) { | ||
value = (hfChanges[1] as any)[topic][name].v | ||
} | ||
if (hfChanges[1][topic][name] !== undefined) { | ||
value = hfChanges[1][topic][name].v | ||
} | ||
} | ||
@@ -566,5 +659,5 @@ if (hfChanges[0] === hardfork) break | ||
const eipParams = EIPs[eip] | ||
const eipParams = (EIPs as any)[eip] | ||
if (!(topic in eipParams)) { | ||
throw new Error(`Topic ${topic} not defined`) | ||
return undefined | ||
} | ||
@@ -594,3 +687,3 @@ if (eipParams[topic][name] === undefined) { | ||
): bigint { | ||
const hardfork = this.getHardforkByBlockNumber(blockNumber, td, timestamp) | ||
const hardfork = this.getHardforkBy({ blockNumber, td, timestamp }) | ||
return this.paramByHardfork(topic, name, hardfork) | ||
@@ -609,13 +702,5 @@ } | ||
isActivatedEIP(eip: number): boolean { | ||
if (this.eips().includes(eip)) { | ||
if (this._activatedEIPsCache.includes(eip)) { | ||
return true | ||
} | ||
for (const hfChanges of this.HARDFORK_CHANGES) { | ||
const hf = hfChanges[1] | ||
if (this.gteHardfork(hf['name']) && 'eips' in hf) { | ||
if ((hf['eips'] as number[]).includes(eip)) { | ||
return true | ||
} | ||
} | ||
} | ||
return false | ||
@@ -634,3 +719,3 @@ } | ||
const hfBlock = this.hardforkBlock(hardfork) | ||
if (typeof hfBlock === 'bigint' && hfBlock !== BigInt(0) && blockNumber >= hfBlock) { | ||
if (typeof hfBlock === 'bigint' && hfBlock !== BIGINT_0 && blockNumber >= hfBlock) { | ||
return true | ||
@@ -714,3 +799,3 @@ } | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
if (hf['eips'].includes(eip)) { | ||
if ((hf['eips'] as any).includes(eip)) { | ||
return this.hardforkBlock(hfChanges[0]) | ||
@@ -738,16 +823,2 @@ } | ||
/** | ||
* True if block number provided is the hardfork (given or set) change block | ||
* @param blockNumber Number of the block to check | ||
* @param hardfork Hardfork name, optional if HF set | ||
* @returns True if blockNumber is HF block | ||
* @deprecated | ||
*/ | ||
isHardforkBlock(blockNumber: BigIntLike, hardfork?: string | Hardfork): boolean { | ||
blockNumber = toType(blockNumber, TypeOutput.BigInt) | ||
hardfork = hardfork ?? this._hardfork | ||
const block = this.hardforkBlock(hardfork) | ||
return typeof block === 'bigint' && block !== BigInt(0) ? block === blockNumber : false | ||
} | ||
/** | ||
* Returns the change block for the next hardfork after the hardfork provided or set | ||
@@ -763,3 +834,3 @@ * @param hardfork Hardfork name, optional if HF set | ||
// calcs even if the merge hf block is set | ||
if (hardfork === Hardfork.Merge) { | ||
if (hardfork === Hardfork.Paris) { | ||
hfIndex -= 1 | ||
@@ -783,3 +854,3 @@ } | ||
return ( | ||
hf.name !== Hardfork.Merge && | ||
hf.name !== Hardfork.Paris && | ||
hfTimeOrBlock !== null && | ||
@@ -804,54 +875,2 @@ hfTimeOrBlock !== undefined && | ||
/** | ||
* Returns the change block for the next hardfork after the hardfork provided or set | ||
* @param hardfork Hardfork name, optional if HF set | ||
* @returns Block number or null if not available | ||
* @deprecated | ||
*/ | ||
nextHardforkBlock(hardfork?: string | Hardfork): bigint | null { | ||
hardfork = hardfork ?? this._hardfork | ||
let hfBlock = this.hardforkBlock(hardfork) | ||
// If this is a merge hardfork with block not set, then we fallback to previous hardfork | ||
// to find the nextHardforkBlock | ||
if (hfBlock === null && hardfork === Hardfork.Merge) { | ||
const hfs = this.hardforks() | ||
const mergeIndex = hfs.findIndex((hf) => hf.ttd !== null && hf.ttd !== undefined) | ||
if (mergeIndex < 0) { | ||
throw Error(`Merge hardfork should have been found`) | ||
} | ||
hfBlock = this.hardforkBlock(hfs[mergeIndex - 1].name) | ||
} | ||
if (hfBlock === null) { | ||
return null | ||
} | ||
// Next fork block number or null if none available | ||
// Logic: if accumulator is still null and on the first occurrence of | ||
// a block greater than the current hfBlock set the accumulator, | ||
// pass on the accumulator as the final result from this time on | ||
const nextHfBlock = this.hardforks().reduce((acc: bigint | null, hf: HardforkConfig) => { | ||
// We need to ignore the merge block in our next hardfork calc | ||
const block = BigInt( | ||
hf.block === null || (hf.ttd !== undefined && hf.ttd !== null) ? 0 : hf.block | ||
) | ||
// Typescript can't seem to follow that the hfBlock is not null at this point | ||
return block > hfBlock! && acc === null ? block : acc | ||
}, null) | ||
return nextHfBlock | ||
} | ||
/** | ||
* True if block number provided is the hardfork change block following the hardfork given or set | ||
* @param blockNumber Number of the block to check | ||
* @param hardfork Hardfork name, optional if HF set | ||
* @returns True if blockNumber is HF block | ||
* @deprecated | ||
*/ | ||
isNextHardforkBlock(blockNumber: BigIntLike, hardfork?: string | Hardfork): boolean { | ||
blockNumber = toType(blockNumber, TypeOutput.BigInt) | ||
hardfork = hardfork ?? this._hardfork | ||
const nextHardforkBlock = this.nextHardforkBlock(hardfork) | ||
return nextHardforkBlock === null ? false : nextHardforkBlock === blockNumber | ||
} | ||
/** | ||
* Internal helper function to calculate a fork hash | ||
@@ -862,4 +881,4 @@ * @param hardfork Hardfork name | ||
*/ | ||
_calcForkHash(hardfork: string | Hardfork, genesisHash: Buffer) { | ||
let hfBuffer = Buffer.alloc(0) | ||
protected _calcForkHash(hardfork: string | Hardfork, genesisHash: Uint8Array): PrefixedHexString { | ||
let hfBytes = new Uint8Array(0) | ||
let prevBlockOrTime = 0 | ||
@@ -880,6 +899,6 @@ for (const hf of this.hardforks()) { | ||
blockOrTime !== prevBlockOrTime && | ||
name !== Hardfork.Merge | ||
name !== Hardfork.Paris | ||
) { | ||
const hfBlockBuffer = Buffer.from(blockOrTime.toString(16).padStart(16, '0'), 'hex') | ||
hfBuffer = Buffer.concat([hfBuffer, hfBlockBuffer]) | ||
const hfBlockBytes = hexToBytes('0x' + blockOrTime.toString(16).padStart(16, '0')) | ||
hfBytes = concatBytes(hfBytes, hfBlockBytes) | ||
prevBlockOrTime = blockOrTime | ||
@@ -890,8 +909,8 @@ } | ||
} | ||
const inputBuffer = Buffer.concat([genesisHash, hfBuffer]) | ||
const inputBytes = concatBytes(genesisHash, hfBytes) | ||
// CRC32 delivers result as signed (negative) 32-bit integer, | ||
// convert to hex string | ||
const forkhash = intToBuffer(crc32Buffer(inputBuffer) >>> 0).toString('hex') | ||
return `0x${forkhash}` | ||
const forkhash = bytesToHex(intToBytes(crc32(inputBytes) >>> 0)) | ||
return forkhash | ||
} | ||
@@ -904,3 +923,3 @@ | ||
*/ | ||
forkHash(hardfork?: string | Hardfork, genesisHash?: Buffer): string { | ||
forkHash(hardfork?: string | Hardfork, genesisHash?: Uint8Array): PrefixedHexString { | ||
hardfork = hardfork ?? this._hardfork | ||
@@ -927,4 +946,4 @@ const data = this._getHardfork(hardfork) | ||
*/ | ||
hardforkForForkHash(forkHash: string): HardforkConfig | null { | ||
const resArray = this.hardforks().filter((hf: HardforkConfig) => { | ||
hardforkForForkHash(forkHash: string): HardforkTransitionConfig | null { | ||
const resArray = this.hardforks().filter((hf: HardforkTransitionConfig) => { | ||
return hf.forkHash === forkHash | ||
@@ -940,3 +959,3 @@ }) | ||
*/ | ||
setForkHashes(genesisHash: Buffer) { | ||
setForkHashes(genesisHash: Uint8Array) { | ||
for (const hf of this.hardforks()) { | ||
@@ -965,3 +984,3 @@ const blockOrTime = hf.timestamp ?? hf.block | ||
*/ | ||
hardforks(): HardforkConfig[] { | ||
hardforks(): HardforkTransitionConfig[] { | ||
return this._chainParams.hardforks | ||
@@ -1019,3 +1038,4 @@ } | ||
/** | ||
* Returns the active EIPs | ||
* Returns the additionally activated EIPs | ||
* (by using the `eips` constructor option) | ||
* @returns List of EIPs | ||
@@ -1039,3 +1059,3 @@ */ | ||
if ('consensus' in hfChanges[1]) { | ||
value = hfChanges[1]['consensus']['type'] | ||
value = (hfChanges[1] as any)['consensus']['type'] | ||
} | ||
@@ -1062,3 +1082,3 @@ if (hfChanges[0] === hardfork) break | ||
if ('consensus' in hfChanges[1]) { | ||
value = hfChanges[1]['consensus']['algorithm'] | ||
value = hfChanges[1]['consensus']!['algorithm'] | ||
} | ||
@@ -1090,3 +1110,5 @@ if (hfChanges[0] === hardfork) break | ||
// The config parameter is named after the respective consensus algorithm | ||
value = hfChanges[1]['consensus'][hfChanges[1]['consensus']['algorithm']] | ||
const config = hfChanges[1] | ||
const algorithm = config['consensus']!['algorithm'] | ||
value = (config['consensus'] as any)[algorithm] | ||
} | ||
@@ -1105,7 +1127,7 @@ if (hfChanges[0] === hardfork) break | ||
const copy = Object.assign(Object.create(Object.getPrototypeOf(this)), this) | ||
copy.removeAllListeners() | ||
copy.events = new EventEmitter() | ||
return copy | ||
} | ||
static _getInitializedChains(customChains?: ChainConfig[]): ChainsConfig { | ||
static getInitializedChains(customChains?: ChainConfig[]): ChainsConfig { | ||
const names: ChainName = {} | ||
@@ -1115,3 +1137,3 @@ for (const [name, id] of Object.entries(Chain)) { | ||
} | ||
const chains = { mainnet, ropsten, rinkeby, goerli, sepolia } as ChainsConfig | ||
const chains = { ...CHAIN_SPECS } as ChainsConfig | ||
if (customChains) { | ||
@@ -1118,0 +1140,0 @@ for (const chain of customChains) { |
@@ -0,9 +1,54 @@ | ||
import { BIGINT_0, hexToBytes } from '@nomicfoundation/ethereumjs-util' | ||
export enum Chain { | ||
Mainnet = 1, | ||
Ropsten = 3, | ||
Rinkeby = 4, | ||
Goerli = 5, | ||
Sepolia = 11155111, | ||
Holesky = 17000, | ||
Kaustinen = 69420, | ||
} | ||
/** | ||
* Genesis state meta info which is decoupled from common's genesis params | ||
*/ | ||
type GenesisState = { | ||
name: string | ||
/* blockNumber that can be used to update and track the regenesis marker */ | ||
blockNumber: bigint | ||
/* stateRoot of the chain at the blockNumber */ | ||
stateRoot: Uint8Array | ||
} | ||
// Having this info as record will force typescript to make sure no chain is missed | ||
/** | ||
* GenesisState info about well known ethereum chains | ||
*/ | ||
export const ChainGenesis: Record<Chain, GenesisState> = { | ||
[Chain.Mainnet]: { | ||
name: 'mainnet', | ||
blockNumber: BIGINT_0, | ||
stateRoot: hexToBytes('0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544'), | ||
}, | ||
[Chain.Goerli]: { | ||
name: 'goerli', | ||
blockNumber: BIGINT_0, | ||
stateRoot: hexToBytes('0x5d6cded585e73c4e322c30c2f782a336316f17dd85a4863b9d838d2d4b8b3008'), | ||
}, | ||
[Chain.Sepolia]: { | ||
name: 'sepolia', | ||
blockNumber: BIGINT_0, | ||
stateRoot: hexToBytes('0x5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494'), | ||
}, | ||
[Chain.Holesky]: { | ||
name: 'holesky', | ||
blockNumber: BIGINT_0, | ||
stateRoot: hexToBytes('0x69d8c9d72f6fa4ad42d4702b433707212f90db395eb54dc20bc85de253788783'), | ||
}, | ||
[Chain.Kaustinen]: { | ||
name: 'kaustinen', | ||
blockNumber: BIGINT_0, | ||
stateRoot: hexToBytes('0x5e8519756841faf0b2c28951c451b61a4b407b70a5ce5b57992f4bec973173ff'), | ||
}, | ||
} | ||
export enum Hardfork { | ||
@@ -25,5 +70,6 @@ Chainstart = 'chainstart', | ||
MergeForkIdTransition = 'mergeForkIdTransition', | ||
Merge = 'merge', | ||
Paris = 'paris', | ||
Shanghai = 'shanghai', | ||
ShardingForkDev = 'shardingFork', | ||
Cancun = 'cancun', | ||
Prague = 'prague', | ||
} | ||
@@ -59,9 +105,2 @@ | ||
/** | ||
* Arbitrum Rinkeby Testnet | ||
* | ||
* - [Documentation](https://developer.offchainlabs.com/docs/public_testnet) | ||
*/ | ||
ArbitrumRinkebyTestnet = 'arbitrum-rinkeby-testnet', | ||
/** | ||
* Arbitrum One - mainnet for Arbitrum roll-up | ||
@@ -68,0 +107,0 @@ * |
@@ -1,4 +0,5 @@ | ||
export * from './common' | ||
export * from './enums' | ||
export * from './types' | ||
export * from './utils' | ||
export * from './common.js' | ||
export * from './enums.js' | ||
export * from './interfaces.js' | ||
export * from './types.js' | ||
export * from './utils.js' |
107
src/types.ts
@@ -1,2 +0,3 @@ | ||
import type { Chain, ConsensusAlgorithm, ConsensusType, Hardfork } from './enums' | ||
import type { Chain, ConsensusAlgorithm, ConsensusType, Hardfork } from './enums.js' | ||
import type { BigIntLike, ECDSASignature } from '@nomicfoundation/ethereumjs-util' | ||
@@ -18,2 +19,11 @@ export interface ChainName { | ||
export type CasperConfig = {} | ||
type ConsensusConfig = { | ||
type: ConsensusType | string | ||
algorithm: ConsensusAlgorithm | string | ||
clique?: CliqueConfig | ||
ethash?: EthashConfig | ||
casper?: CasperConfig | ||
} | ||
export interface ChainConfig { | ||
@@ -27,12 +37,6 @@ name: string | ||
genesis: GenesisBlockConfig | ||
hardforks: HardforkConfig[] | ||
hardforks: HardforkTransitionConfig[] | ||
bootstrapNodes: BootstrapNodeConfig[] | ||
dnsNetworks?: string[] | ||
consensus: { | ||
type: ConsensusType | string | ||
algorithm: ConsensusAlgorithm | string | ||
clique?: CliqueConfig | ||
ethash?: EthashConfig | ||
casper?: CasperConfig | ||
} | ||
consensus: ConsensusConfig | ||
} | ||
@@ -42,10 +46,11 @@ | ||
timestamp?: string | ||
gasLimit: number | ||
difficulty: number | ||
gasLimit: number | string | ||
difficulty: number | string | ||
nonce: string | ||
extraData: string | ||
baseFeePerGas?: string | ||
excessBlobGas?: string | ||
} | ||
export interface HardforkConfig { | ||
export interface HardforkTransitionConfig { | ||
name: Hardfork | string | ||
@@ -68,2 +73,18 @@ block: number | null // null is used for hardforks that should not be applied -- since `undefined` isn't a valid value in JSON | ||
export interface CustomCrypto { | ||
/** | ||
* Interface for providing custom cryptographic primitives in place of `ethereum-cryptography` variants | ||
*/ | ||
keccak256?: (msg: Uint8Array) => Uint8Array | ||
ecrecover?: ( | ||
msgHash: Uint8Array, | ||
v: bigint, | ||
r: Uint8Array, | ||
s: Uint8Array, | ||
chainId?: bigint | ||
) => Uint8Array | ||
sha256?: (msg: Uint8Array) => Uint8Array | ||
ecsign?: (msg: Uint8Array, pk: Uint8Array, chainId?: bigint) => ECDSASignature | ||
} | ||
interface BaseOpts { | ||
@@ -78,9 +99,16 @@ /** | ||
* Selected EIPs which can be activated, please use an array for instantiation | ||
* (e.g. `eips: [ 2537, ]`) | ||
* (e.g. `eips: [ 1559, 3860 ]`) | ||
*/ | ||
eips?: number[] | ||
/** | ||
* This option can be used to replace the most common crypto primitives | ||
* (keccak256 hashing e.g.) within the EthereumJS ecosystem libraries | ||
* with alternative implementations (e.g. more performant WASM libraries). | ||
* | ||
* Currently supported: | ||
* | ||
* - [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) - BLS12-381 precompiles | ||
* Note: please be aware that this is adding new dependencies for your | ||
* system setup to be used for sensitive/core parts of the functionality | ||
* and a choice on the libraries to add should be handled with care | ||
* and be made with eventual security implications considered. | ||
*/ | ||
eips?: number[] | ||
customCrypto?: CustomCrypto | ||
} | ||
@@ -125,4 +153,47 @@ | ||
chain?: string | ||
genesisHash?: Buffer | ||
genesisHash?: Uint8Array | ||
mergeForkIdPostMerge?: boolean | ||
} | ||
export interface HardforkByOpts { | ||
blockNumber?: BigIntLike | ||
timestamp?: BigIntLike | ||
td?: BigIntLike | ||
} | ||
type ParamDict = { | ||
v: number | bigint | null | ||
d: string | ||
} | ||
export type EIPOrHFConfig = { | ||
comment: string | ||
url: string | ||
status: string | ||
gasConfig?: { | ||
[key: string]: ParamDict | ||
} | ||
gasPrices?: { | ||
[key: string]: ParamDict | ||
} | ||
pow?: { | ||
[key: string]: ParamDict | ||
} | ||
sharding?: { | ||
[key: string]: ParamDict | ||
} | ||
vm?: { | ||
[key: string]: ParamDict | ||
} | ||
} | ||
export type EIPConfig = { | ||
minimumHardfork: Hardfork | ||
requiredEIPs: number[] | ||
} & EIPOrHFConfig | ||
export type HardforkConfig = { | ||
name: string | ||
eips?: number[] | ||
consensus?: ConsensusConfig | ||
} & EIPOrHFConfig |
import { intToHex, isHexPrefixed, stripHexPrefix } from '@nomicfoundation/ethereumjs-util' | ||
import { Hardfork } from './enums' | ||
import { Hardfork } from './enums.js' | ||
@@ -40,2 +40,3 @@ type ConfigHardfork = | ||
baseFeePerGas, | ||
excessBlobGas, | ||
}: { | ||
@@ -49,2 +50,3 @@ name: string | ||
baseFeePerGas: string | ||
excessBlobGas: string | ||
} = json | ||
@@ -83,4 +85,4 @@ let { extraData, timestamp, nonce }: { extraData: string; timestamp: string; nonce: string } = | ||
timestamp, | ||
gasLimit: parseInt(gasLimit), // geth gasLimit and difficulty are hex strings while ours are `number`s | ||
difficulty: parseInt(difficulty), | ||
gasLimit, | ||
difficulty, | ||
nonce, | ||
@@ -91,2 +93,3 @@ extraData, | ||
baseFeePerGas, | ||
excessBlobGas, | ||
}, | ||
@@ -130,3 +133,4 @@ hardfork: undefined as string | undefined, | ||
[Hardfork.Shanghai]: { name: 'shanghaiTime', postMerge: true, isTimestamp: true }, | ||
[Hardfork.ShardingForkDev]: { name: 'shardingForkTime', postMerge: true, isTimestamp: true }, | ||
[Hardfork.Cancun]: { name: 'cancunTime', postMerge: true, isTimestamp: true }, | ||
[Hardfork.Prague]: { name: 'pragueTime', postMerge: true, isTimestamp: true }, | ||
} | ||
@@ -162,5 +166,14 @@ | ||
params.hardforks.sort(function (a: ConfigHardfork, b: ConfigHardfork) { | ||
return (a.timestamp ?? genesisTimestamp) - (b.timestamp ?? genesisTimestamp) | ||
// non timestamp forks come before any timestamp forks | ||
return (a.timestamp ?? 0) - (b.timestamp ?? 0) | ||
}) | ||
// only set the genesis timestamp forks to zero post the above sort has happended | ||
// to get the correct sorting | ||
for (const hf of params.hardforks) { | ||
if (hf.timestamp === genesisTimestamp) { | ||
hf.timestamp = 0 | ||
} | ||
} | ||
if (config.terminalTotalDifficulty !== undefined) { | ||
@@ -173,3 +186,3 @@ // Following points need to be considered for placement of merge hf | ||
const mergeConfig = { | ||
name: Hardfork.Merge, | ||
name: Hardfork.Paris, | ||
ttd: config.terminalTotalDifficulty, | ||
@@ -205,4 +218,6 @@ block: null, | ||
try { | ||
if (['config', 'difficulty', 'gasLimit', 'alloc'].some((field) => !(field in json))) { | ||
throw new Error('Invalid format, expected geth genesis fields missing') | ||
const required = ['config', 'difficulty', 'gasLimit', 'nonce', 'alloc'] | ||
if (required.some((field) => !(field in json))) { | ||
const missingField = required.filter((field) => !(field in json)) | ||
throw new Error(`Invalid format, expected geth genesis field "${missingField}" missing`) | ||
} | ||
@@ -209,0 +224,0 @@ if (name !== undefined) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
648720
1
11721
393
97
1
+ Added@nomicfoundation/ethereumjs-rlp@5.0.4(transitive)
+ Added@nomicfoundation/ethereumjs-util@9.0.4(transitive)
- Removedcrc-32@^1.2.0
- Removed@chainsafe/as-sha256@0.3.1(transitive)
- Removed@chainsafe/persistent-merkle-tree@0.5.0(transitive)
- Removed@chainsafe/ssz@0.10.2(transitive)
- Removed@nomicfoundation/ethereumjs-rlp@5.0.3(transitive)
- Removed@nomicfoundation/ethereumjs-util@9.0.3(transitive)
- Removedcrc-32@1.2.2(transitive)