Skip to content

Commit

Permalink
client: merge related work (#1493)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanio committed Sep 30, 2021
1 parent 6e41fb3 commit e897985
Show file tree
Hide file tree
Showing 21 changed files with 420 additions and 173 deletions.
4 changes: 4 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions packages/client/README.md
Expand Up @@ -16,7 +16,7 @@ The EthereumJS Client is an Ethereum Execution Client (similar to [go-ethereum](
Here are some use cases:

- Sync the main Ethereum networks (`mainnet`, `goerli`, `rinkeby`,...)
- Set up your own local development networks (PoA Clique)
- Set up your own local development networks (PoA Clique or PoW with CPU miner)
- Run a network with your own custom [EthereumJS VM](../vm)
- Analyze what's in the Ethereum `mainnet` [transaction pool](./lib/sync/txpool.ts)
- Run experiments with Ethereum browser sync (see [example](./examples/light-browser-sync.md))
Expand Down Expand Up @@ -114,18 +114,17 @@ ethereumjs --gethGenesis=[GETH_GENESIS_JSON_FILE]

### Custom Network Mining (Beta)

The client supports private custom network mining on PoA clique chains by using the `--mine` option together with passing in a comma separated list of accounts with the `--unlock` option:
The client supports private custom network mining by using the `--mine` option together with passing in a comma separated list of accounts with the `--unlock` option:

```shell
ethereumjs --mine --unlock=[ADDRESS1],[ADDRESS2],...
```

Note that this feature is in `beta` and shouldn't be used with accounts holding a substantial amount of `Ether` on mainnet (or other valuable assets) for security reasons.

### Custom network for development
#### Custom Network for Development

The client provides a quick way to get a local instance of a blockchain up and running using the `--dev` command. This will start up a private PoA clique
network with a prefunded account that mines block on 10 second intervals. The prefunded account and its private key are printed to the screen when the client starts. When paired with the `--rpc` command, you have a ready-made environment for local development.
The client provides a quick way to get a local instance of a blockchain up and running using the `--dev` command. This will start up a private PoA clique network with a prefunded account that mines block on 10 second intervals. The prefunded account and its private key are printed to the screen when the client starts. When paired with the `--rpc` command, you have a ready-made environment for local development.

```shell
ethereumjs --dev --rpc
Expand All @@ -148,6 +147,10 @@ ethereumjs --dev --rpc --unlock=0xd8066d5822138e7c76d1565deb249f5f7ae370fa

Note: If the `--dev` command is used in conjunction with `--unlock` to use a predefined account, the blockchain's state will be preserved between consecutive runs. If you try to use a different predefined account, you may see errors related to incompatible genesis blocks. Simply run the client with the `--dev` flag by itself and use the new prefunded account provided by the client in further rounds of execution.

To explicitly set the miner coinbase (etherbase) specify `--minerCoinbase=[ADDRESS]` - otherwise this will default to the primary account.

The `--dev` command defaults to `--dev=poa`. If you would like to use PoW ethash with CPU miner (warning: slow) then pass `--dev=pow`.

## API

[API Reference](./docs/README.md)
Expand Down
58 changes: 30 additions & 28 deletions packages/client/bin/cli.ts
Expand Up @@ -6,7 +6,7 @@ import readline from 'readline'
import { randomBytes } from 'crypto'
import { ensureDirSync, readFileSync, removeSync } from 'fs-extra'
import { Server as RPCServer } from 'jayson/promise'
import Common, { Chain, Hardfork, ConsensusType } from '@ethereumjs/common'
import Common, { Chain, Hardfork } from '@ethereumjs/common'
import { _getInitializedChains } from '@ethereumjs/common/dist/chains'
import { Address, toBuffer } from 'ethereumjs-util'
import { parseMultiaddrs, parseGenesisState, parseCustomParams } from '../lib/util'
Expand Down Expand Up @@ -132,19 +132,23 @@ const args = require('yargs')
boolean: true,
},
mine: {
describe: 'Enable private custom network mining (beta, PoA only)',
describe: 'Enable private custom network mining (beta)',
boolean: true,
default: false,
},
unlock: {
describe:
'Comma separated list of accounts to unlock - currently only the first account is used for sealing mined blocks. Beta, you will be promped for a 0x-prefixed private key until keystore functionality is added - FOR YOUR SAFETY PLEASE DO NOT USE ANY ACCOUNTS HOLDING SUBSTANTIAL AMOUNTS OF ETH',
'Comma separated list of accounts to unlock - currently only the first account is used (for sealing PoA blocks and as the default coinbase). Beta, you will be promped for a 0x-prefixed private key until keystore functionality is added - FOR YOUR SAFETY PLEASE DO NOT USE ANY ACCOUNTS HOLDING SUBSTANTIAL AMOUNTS OF ETH',
array: true,
},
dev: {
describe: 'Start an ephemeral PoA blockchain with a single miner and prefunded accounts',
boolean: true,
default: false,
choices: [undefined, false, true, 'poa', 'pow'],
},
minerCoinbase: {
describe:
'Address for mining rewards (etherbase). If not provided, defaults to the primary account',
string: true,
},
})
.locale('en_EN').argv
Expand Down Expand Up @@ -204,7 +208,7 @@ function runRpcServer(client: EthereumClient, config: Config) {
*/
async function run() {
// give network id precedence over network name
const chain = args.networkId ?? args.network ?? 'mainnet'
const chain = args.networkId ?? args.network ?? Chain.Mainnet

// configure accounts for mining and prefunding in a local devnet
const accounts: [address: Address, privateKey: Buffer][] = []
Expand Down Expand Up @@ -260,16 +264,14 @@ async function run() {
rl.close()
}

let common = new Common({ chain: Chain.Mainnet })
let common = new Common({ chain, hardfork: Hardfork.Chainstart })

if (args.dev) {
args.discDns = false
if (accounts.length === 0) {
// Delete old chain data for devnet if generating ephemeral keys for mining to prevent genesis block mismatch
// If generating new keys delete old chain data to prevent genesis block mismatch
removeSync(`${args.datadir}/devnet`)
}

if (accounts.length === 0) {
// Create new account for devnet if not provided
// Create new account
const privKey = randomBytes(32)
const account = Address.fromPrivateKey(privKey)
accounts.push([account, privKey])
Expand All @@ -278,6 +280,15 @@ async function run() {
}

const prefundAddress = accounts[0][0].toString().slice(2)
const consensusConfig =
args.dev === 'pow'
? { ethash: true }
: {
clique: {
period: 10,
epoch: 30000,
},
}
const defaultChainData = {
config: {
chainId: 123456,
Expand All @@ -292,10 +303,7 @@ async function run() {
istanbulBlock: 0,
berlinBlock: 0,
londonBlock: 0,
clique: {
period: 10,
epoch: 30000,
},
...consensusConfig,
},
nonce: '0x0',
timestamp: '0x614b3731',
Expand Down Expand Up @@ -361,20 +369,13 @@ async function run() {
chain: genesisParams.name,
customChains: [[genesisParams, genesisState]],
})
} else if (!args.dev) {
// Use default common configuration for specified `chain` if no custom parameters specified
common = new Common({ chain: chain, hardfork: Hardfork.Chainstart })
}

if (args.mine) {
if (common.consensusType() !== ConsensusType.ProofOfAuthority) {
console.error('Currently mining is only supported for PoA consensus')
process.exit()
}
if (!args.unlock) {
console.error('Please provide an account to sign sealed blocks with `--unlock [address]` ')
process.exit()
}
if (args.mine && accounts.length === 0) {
console.error(
'Please provide an account to mine blocks with `--unlock [address]` or use `--dev` to generate'
)
process.exit()
}

const datadir = args.datadir ?? Config.DATADIR_DEFAULT
Expand Down Expand Up @@ -405,6 +406,7 @@ async function run() {
discV4: args.discV4,
mine: args.mine || args.dev,
accounts,
minerCoinbase: args.minerCoinbase,
})
logger = config.logger
config.events.setMaxListeners(50)
Expand Down
8 changes: 8 additions & 0 deletions packages/client/lib/config.ts
Expand Up @@ -192,6 +192,12 @@ export interface ConfigOptions {
* Default: []
*/
accounts?: [address: Address, privKey: Buffer][]

/**
* Address for mining rewards (etherbase)
* If not provided, defaults to the primary account.
*/
minerCoinbase?: Address
}

export class Config {
Expand Down Expand Up @@ -240,6 +246,7 @@ export class Config {
public readonly discV4: boolean
public readonly mine: boolean
public readonly accounts: [address: Address, privKey: Buffer][]
public readonly minerCoinbase?: Address

public synchronized: boolean
public lastSyncDate: number
Expand Down Expand Up @@ -272,6 +279,7 @@ export class Config {
this.debugCode = options.debugCode ?? Config.DEBUGCODE_DEFAULT
this.mine = options.mine ?? false
this.accounts = options.accounts ?? []
this.minerCoinbase = options.minerCoinbase

this.synchronized = false
this.lastSyncDate = 0
Expand Down

0 comments on commit e897985

Please sign in to comment.