core: refactor genesis handling

This commit solves several issues concerning the genesis block:

* Genesis/ChainConfig loading was handled by cmd/geth code. This left
  library users in the cold. They could specify a JSON-encoded
  string and overwrite the config, but didn't get any of the additional
  checks performed by geth.
* Decoding and writing of genesis JSON was conflated in
  WriteGenesisBlock. This made it a lot harder to embed the genesis
  block into the forthcoming config file loader. This commit changes
  things so there is a single Genesis type that represents genesis
  blocks. All uses of Write*Genesis* are changed to use the new type
  instead.
* If the chain config supplied by the user was incompatible with the
  current chain (i.e. the chain had already advanced beyond a scheduled
  fork), it got overwritten. This is not an issue in practice because
  previous forks have always had the highest total difficulty. It might
  matter in the future though. The new code reverts the local chain to
  the point of the fork when upgrading configuration.

The change to genesis block data removes compression library
dependencies from package core.
This commit is contained in:
Felix Lange 2017-03-02 14:03:33 +01:00
parent 67c47459f2
commit 37dd9086ec
45 changed files with 1379 additions and 1275 deletions

View File

@ -37,9 +37,6 @@ import (
"github.com/ethereum/go-ethereum/pow"
)
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
var chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
@ -60,11 +57,12 @@ type SimulatedBackend struct {
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
// for testing purposes.
func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend {
func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
database, _ := ethdb.NewMemDatabase()
core.WriteGenesisBlockForTesting(database, accounts...)
blockchain, _ := core.NewBlockChain(database, chainConfig, new(pow.FakePow), new(event.TypeMux), vm.Config{})
backend := &SimulatedBackend{database: database, blockchain: blockchain}
genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
genesis.MustCommit(database)
blockchain, _ := core.NewBlockChain(database, genesis.Config, new(pow.FakePow), new(event.TypeMux), vm.Config{})
backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
backend.rollback()
return backend
}
@ -90,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
}
func (b *SimulatedBackend) rollback() {
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
}
@ -253,7 +251,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{})
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
return ret, gasUsed, err
@ -274,7 +272,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
}
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx)
}

View File

@ -169,7 +169,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy an interaction tester contract and call a transaction on it
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
@ -210,7 +210,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a tuple tester contract and execute a structured call on it
_, _, getter, err := DeployGetter(auth, sim)
@ -242,7 +242,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a tuple tester contract and execute a structured call on it
_, _, tupler, err := DeployTupler(auth, sim)
@ -284,7 +284,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a slice tester contract and execute a n array call on it
_, _, slicer, err := DeploySlicer(auth, sim)
@ -318,7 +318,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a default method invoker contract and execute its default method
_, _, defaulter, err := DeployDefaulter(auth, sim)
@ -351,7 +351,7 @@ var bindTests = []struct {
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
`
// Create a simulator and wrap a non-deployed contract
sim := backends.NewSimulatedBackend()
sim := backends.NewSimulatedBackend(nil)
nonexistent, err := NewNonExistent(common.Address{}, sim)
if err != nil {
@ -387,7 +387,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a funky gas pattern contract
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
@ -423,7 +423,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a sender tester contract and execute a structured call on it
_, _, callfrom, err := DeployCallFrom(auth, sim)
@ -458,7 +458,7 @@ func TestBindings(t *testing.T) {
t.Skip("go sdk not found for testing")
}
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend())\n}")
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}")
linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
if err != nil {
t.Fatalf("failed check for goimports symlink bug: %v", err)

View File

@ -53,9 +53,8 @@ var waitDeployedTests = map[string]struct {
func TestWaitDeployed(t *testing.T) {
for name, test := range waitDeployedTests {
backend := backends.NewSimulatedBackend(core.GenesisAccount{
Address: crypto.PubkeyToAddress(testKey.PublicKey),
Balance: big.NewInt(10000000000),
backend := backends.NewSimulatedBackend(core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
})
// Create the transaction.

View File

@ -17,6 +17,7 @@
package main
import (
"encoding/json"
"fmt"
"os"
"runtime"
@ -110,17 +111,22 @@ func initGenesis(ctx *cli.Context) error {
stack := makeFullNode(ctx)
chaindb := utils.MakeChainDatabase(ctx, stack)
genesisFile, err := os.Open(genesisPath)
file, err := os.Open(genesisPath)
if err != nil {
utils.Fatalf("failed to read genesis file: %v", err)
}
defer genesisFile.Close()
defer file.Close()
block, err := core.WriteGenesisBlock(chaindb, genesisFile)
genesis := new(core.Genesis)
if err := json.NewDecoder(file).Decode(genesis); err != nil {
utils.Fatalf("invalid genesis file: %v", err)
}
_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
if err != nil {
utils.Fatalf("failed to write genesis block: %v", err)
}
log.Info("Successfully wrote genesis state", "hash", block.Hash())
log.Info("Successfully wrote genesis state", "hash", hash)
return nil
}

View File

@ -786,7 +786,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
ethConf := &eth.Config{
Etherbase: MakeEtherbase(ks, ctx),
ChainConfig: MakeChainConfig(ctx, stack),
FastSync: ctx.GlobalBool(FastSyncFlag.Name),
LightMode: ctx.GlobalBool(LightModeFlag.Name),
LightServ: ctx.GlobalInt(LightServFlag.Name),
@ -822,7 +821,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
ethConf.NetworkId = 3
}
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name):
ethConf.Genesis = core.DevGenesisBlock()
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
@ -884,67 +882,6 @@ func SetupNetwork(ctx *cli.Context) {
params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name))
}
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
db := MakeChainDatabase(ctx, stack)
defer db.Close()
return MakeChainConfigFromDb(ctx, db)
}
// MakeChainConfigFromDb reads the chain configuration from the given database.
func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
// If the chain is already initialized, use any existing chain configs
config := new(params.ChainConfig)
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
if genesis != nil {
storedConfig, err := core.GetChainConfig(db, genesis.Hash())
switch err {
case nil:
config = storedConfig
case core.ChainConfigNotFoundErr:
// No configs found, use empty, will populate below
default:
Fatalf("Could not make chain configuration: %v", err)
}
}
// set chain id in case it's zero.
if config.ChainId == nil {
config.ChainId = new(big.Int)
}
// Check whether we are allowed to set default config params or not:
// - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
// - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
defaults := genesis == nil ||
(genesis.Hash() == params.MainNetGenesisHash && !ctx.GlobalBool(TestNetFlag.Name)) ||
(genesis.Hash() == params.TestNetGenesisHash && ctx.GlobalBool(TestNetFlag.Name))
if defaults {
if ctx.GlobalBool(TestNetFlag.Name) {
config = params.TestnetChainConfig
} else if ctx.GlobalBool(DevModeFlag.Name) {
config = params.AllProtocolChanges
} else {
// Homestead fork
config.HomesteadBlock = params.MainNetHomesteadBlock
// DAO fork
config.DAOForkBlock = params.MainNetDAOForkBlock
config.DAOForkSupport = true
// DoS reprice fork
config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
// DoS state cleanup fork
config.EIP155Block = params.MainNetSpuriousDragon
config.EIP158Block = params.MainNetSpuriousDragon
config.ChainId = params.MainNetChainID
}
}
return config
}
func ChainDbName(ctx *cli.Context) string {
if ctx.GlobalBool(LightModeFlag.Name) {
return "lightchaindata"
@ -968,26 +905,34 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
return chainDb
}
func MakeGenesis(ctx *cli.Context) *core.Genesis {
var genesis *core.Genesis
switch {
case ctx.GlobalBool(TestNetFlag.Name):
genesis = core.DefaultTestnetGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name):
genesis = core.DevGenesisBlock()
}
return genesis
}
// MakeChain creates a chain manager from set command line flags.
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
var err error
chainDb = MakeChainDatabase(ctx, stack)
if ctx.GlobalBool(TestNetFlag.Name) {
_, err := core.WriteTestNetGenesisBlock(chainDb)
if err != nil {
Fatalf("Failed to write testnet genesis: %v", err)
}
}
chainConfig := MakeChainConfigFromDb(ctx, chainDb)
seal := pow.PoW(pow.FakePow{})
if !ctx.GlobalBool(FakePoWFlag.Name) {
seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
}
chain, err = core.NewBlockChain(chainDb, chainConfig, seal, new(event.TypeMux), vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)})
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
if err != nil {
Fatalf("Could not start chainmanager: %v", err)
Fatalf("%v", err)
}
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg)
if err != nil {
Fatalf("Can't create BlockChain: %v", err)
}
return chain, chainDb
}

View File

@ -21,17 +21,16 @@ import (
"errors"
"fmt"
"io/ioutil"
"math/big"
"os"
"strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/jsre"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
)
const (
@ -97,9 +96,9 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create node: %v", err)
}
ethConf := &eth.Config{
ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
Etherbase: common.HexToAddress(testAddress),
PowTest: true,
Genesis: core.DevGenesisBlock(),
Etherbase: common.HexToAddress(testAddress),
PowTest: true,
}
if confOverride != nil {
confOverride(ethConf)

View File

@ -42,11 +42,11 @@ var (
)
func newTestBackend() *backends.SimulatedBackend {
return backends.NewSimulatedBackend(
core.GenesisAccount{Address: addr0, Balance: big.NewInt(1000000000)},
core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000000)},
core.GenesisAccount{Address: addr2, Balance: big.NewInt(1000000000)},
)
return backends.NewSimulatedBackend(core.GenesisAlloc{
addr0: {Balance: big.NewInt(1000000000)},
addr1: {Balance: big.NewInt(1000000000)},
addr2: {Balance: big.NewInt(1000000000)},
})
}
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {

View File

@ -34,7 +34,7 @@ var (
)
func TestENS(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000000)})
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
transactOpts := bind.NewKeyedTransactor(key)
// Workaround for bug estimating gas in the call to Register
transactOpts.GasLimit = big.NewInt(1000000)

View File

@ -35,11 +35,11 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
accounts := []core.GenesisAccount{{Address: auth.From, Balance: big.NewInt(10000000000)}}
alloc := core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}
for _, key := range prefund {
accounts = append(accounts, core.GenesisAccount{Address: crypto.PubkeyToAddress(key.PublicKey), Balance: big.NewInt(10000000000)})
alloc[crypto.PubkeyToAddress(key.PublicKey)] = core.GenesisAccount{Balance: big.NewInt(10000000000)}
}
sim := backends.NewSimulatedBackend(accounts...)
sim := backends.NewSimulatedBackend(alloc)
// Deploy a version oracle contract, commit and return
_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})

View File

@ -166,13 +166,17 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Generate a chain of b.N blocks using the supplied block
// generator function.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
gspec := Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}},
}
genesis := gspec.MustCommit(db)
chain, _ := GenerateChain(gspec.Config, genesis, db, b.N, gen)
// Time the insertion of the new chain.
// State and blocks are stored in the same DB.
evmux := new(event.TypeMux)
chainman, _ := NewBlockChain(db, &params.ChainConfig{HomesteadBlock: new(big.Int)}, pow.FakePow{}, evmux, vm.Config{})
chainman, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
defer chainman.Stop()
b.ReportAllocs()
b.ResetTimer()
@ -282,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err)
}
chain, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
chain, err := NewBlockChain(db, params.TestChainConfig, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if err != nil {
b.Fatalf("error creating chain: %v", err)
}

View File

@ -17,51 +17,36 @@
package core
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
)
func testChainConfig() *params.ChainConfig {
return params.TestChainConfig
//return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
}
func proc() (Validator, *BlockChain) {
db, _ := ethdb.NewMemDatabase()
var mux event.TypeMux
WriteTestNetGenesisBlock(db)
blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &mux, vm.Config{})
if err != nil {
fmt.Println(err)
func testGenesis(account common.Address, balance *big.Int) *Genesis {
return &Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{account: {Balance: balance}},
}
return blockchain.validator, blockchain
}
func TestNumber(t *testing.T) {
_, chain := proc()
chain := newTestBlockChain()
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
cfg := testChainConfig()
header := makeHeader(cfg, chain.Genesis(), statedb)
header := makeHeader(chain.config, chain.Genesis(), statedb)
header.Number = big.NewInt(3)
err := ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
err := ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
if err != BlockNumberErr {
t.Errorf("expected block number error, got %q", err)
}
header = makeHeader(cfg, chain.Genesis(), statedb)
err = ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
header = makeHeader(chain.config, chain.Genesis(), statedb)
err = ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
if err == BlockNumberErr {
t.Errorf("didn't expect block number error")
}

View File

@ -20,10 +20,6 @@ import (
"fmt"
"math/big"
"math/rand"
"os"
"path/filepath"
"runtime"
"strconv"
"testing"
"time"
@ -36,24 +32,21 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
"github.com/hashicorp/golang-lru"
)
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain {
var eventMux event.TypeMux
WriteTestNetGenesisBlock(db)
blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &eventMux, vm.Config{})
if err != nil {
t.Error("failed creating blockchain:", err)
t.FailNow()
return nil
// newTestBlockChain creates a blockchain without validation.
func newTestBlockChain() *BlockChain {
db, _ := ethdb.NewMemDatabase()
gspec := &Genesis{
Config: params.TestChainConfig,
Difficulty: big.NewInt(1),
}
gspec.MustCommit(db)
blockchain, err := NewBlockChain(db, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if err != nil {
panic(err)
}
blockchain.SetValidator(bproc{})
return blockchain
}
@ -171,21 +164,6 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
return nil
}
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
if err != nil {
return nil, err
}
defer fh.Close()
var chain types.Blocks
if err := rlp.Decode(fh, &chain); err != nil {
return nil, err
}
return chain, nil
}
func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {
_, err := blockchain.InsertChain(chain)
if err != nil {
@ -196,12 +174,10 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
}
func TestLastBlock(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
bchain := theBlockChain(db, t)
block := makeBlockChain(bchain.CurrentBlock(), 1, db, 0)[0]
bchain := newTestBlockChain()
block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
bchain.insert(block)
if block.Hash() != GetHeadBlockHash(db) {
if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
t.Errorf("Write/Get HeadBlockHash failed")
}
}
@ -340,88 +316,6 @@ func testBrokenChain(t *testing.T, full bool) {
}
}
func TestChainInsertions(t *testing.T) {
t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase()
chain1, err := loadChain("valid1", t)
if err != nil {
fmt.Println(err)
t.FailNow()
}
chain2, err := loadChain("valid2", t)
if err != nil {
fmt.Println(err)
t.FailNow()
}
blockchain := theBlockChain(db, t)
const max = 2
done := make(chan bool, max)
go insertChain(done, blockchain, chain1, t)
go insertChain(done, blockchain, chain2, t)
for i := 0; i < max; i++ {
<-done
}
if chain2[len(chain2)-1].Hash() != blockchain.CurrentBlock().Hash() {
t.Error("chain2 is canonical and shouldn't be")
}
if chain1[len(chain1)-1].Hash() != blockchain.CurrentBlock().Hash() {
t.Error("chain1 isn't canonical and should be")
}
}
func TestChainMultipleInsertions(t *testing.T) {
t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase()
const max = 4
chains := make([]types.Blocks, max)
var longest int
for i := 0; i < max; i++ {
var err error
name := "valid" + strconv.Itoa(i+1)
chains[i], err = loadChain(name, t)
if len(chains[i]) >= len(chains[longest]) {
longest = i
}
fmt.Println("loaded", name, "with a length of", len(chains[i]))
if err != nil {
fmt.Println(err)
t.FailNow()
}
}
blockchain := theBlockChain(db, t)
done := make(chan bool, max)
for i, chain := range chains {
// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
i := i
chain := chain
go func() {
insertChain(done, blockchain, chain, t)
fmt.Println(i, "done")
}()
}
for i := 0; i < max; i++ {
<-done
}
if chains[longest][len(chains[longest])-1].Hash() != blockchain.CurrentBlock().Hash() {
t.Error("Invalid canonical chain")
}
}
type bproc struct{}
func (bproc) ValidateBlock(*types.Block) error { return nil }
@ -452,6 +346,7 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash,
Time: big.NewInt(int64(i) + 1),
}
if i == 0 {
header.ParentHash = genesis.Hash()
@ -464,29 +359,6 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
return chain
}
func chm(genesis *types.Block, db ethdb.Database) *BlockChain {
var eventMux event.TypeMux
bc := &BlockChain{
chainDb: db,
genesisBlock: genesis,
eventMux: &eventMux,
pow: pow.FakePow{},
config: testChainConfig(),
}
valFn := func() HeaderValidator { return bc.Validator() }
bc.hc, _ = NewHeaderChain(db, testChainConfig(), valFn, bc.getProcInterrupt)
bc.bodyCache, _ = lru.New(100)
bc.bodyRLPCache, _ = lru.New(100)
bc.blockCache, _ = lru.New(100)
bc.futureBlocks, _ = lru.New(100)
bc.badBlocks, _ = lru.New(10)
bc.SetValidator(bproc{})
bc.SetProcessor(bproc{})
bc.ResetWithGenesisBlock(genesis)
return bc
}
// Tests that reorganising a long difficult chain after a short easy one
// overwrites the canonical numbers and links in the database.
func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
@ -506,18 +378,15 @@ func testReorgShort(t *testing.T, full bool) {
}
func testReorg(t *testing.T, first, second []int, td int64, full bool) {
// Create a pristine block chain
db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
bc := newTestBlockChain()
// Insert an easy and a difficult chain afterwards
if full {
bc.InsertChain(makeBlockChainWithDiff(genesis, first, 11))
bc.InsertChain(makeBlockChainWithDiff(genesis, second, 22))
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11))
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22))
} else {
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
}
// Check that the chain is valid number and link wise
if full {
@ -536,7 +405,7 @@ func testReorg(t *testing.T, first, second []int, td int64, full bool) {
}
}
// Make sure the chain total difficulty is the correct one
want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td))
want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
if full {
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
@ -553,19 +422,16 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }
func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
func testBadHashes(t *testing.T, full bool) {
// Create a pristine block chain
db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
bc := newTestBlockChain()
// Create a chain, ban a hash and try to import
var err error
if full {
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 4}, 10)
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
BadHashes[blocks[2].Header().Hash()] = true
_, err = bc.InsertChain(blocks)
} else {
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
BadHashes[headers[2].Hash()] = true
_, err = bc.InsertHeaderChain(headers, 1)
}
@ -580,14 +446,11 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }
func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
func testReorgBadHashes(t *testing.T, full bool) {
// Create a pristine block chain
db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
bc := newTestBlockChain()
// Create a chain, import and ban afterwards
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
if full {
if _, err := bc.InsertChain(blocks); err != nil {
@ -608,8 +471,9 @@ func testReorgBadHashes(t *testing.T, full bool) {
BadHashes[headers[3].Hash()] = true
defer func() { delete(BadHashes, headers[3].Hash()) }()
}
// Create a new chain manager and check it rolled back the state
ncm, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
// Create a new BlockChain and check that it rolled back the state.
ncm, err := NewBlockChain(bc.chainDb, bc.config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if err != nil {
t.Fatalf("failed to create new chain manager: %v", err)
}
@ -663,7 +527,7 @@ func testInsertNonceError(t *testing.T, full bool) {
failHash = headers[failAt].Hash()
blockchain.pow = failPow{failNum}
blockchain.validator = NewBlockValidator(testChainConfig(), blockchain, failPow{failNum})
blockchain.validator = NewBlockValidator(params.TestChainConfig, blockchain, failPow{failNum})
failRes, err = blockchain.InsertHeaderChain(headers, 1)
}
@ -705,10 +569,11 @@ func TestFastVsFullChains(t *testing.T) {
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
genesis = GenesisBlockForTesting(gendb, address, funds)
signer = types.NewEIP155Signer(big.NewInt(1))
gspec = testGenesis(address, funds)
genesis = gspec.MustCommit(gendb)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
)
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {
block.SetCoinbase(common.Address{0x00})
// If the block number is multiple of 3, send a few bonus transactions to the miner
@ -728,17 +593,17 @@ func TestFastVsFullChains(t *testing.T) {
})
// Import the chain as an archive node for the comparison baseline
archiveDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if n, err := archive.InsertChain(blocks); err != nil {
t.Fatalf("failed to process block %d: %v", n, err)
}
// Fast import the chain as a non-archive node to test
fastDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
headers := make([]*types.Header, len(blocks))
for i, block := range blocks {
@ -788,10 +653,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
genesis = GenesisBlockForTesting(gendb, address, funds)
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
genesis = gspec.MustCommit(gendb)
)
height := uint64(1024)
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil)
blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil)
// Configure a subchain to roll back
remove := []common.Hash{}
@ -812,9 +678,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
}
// Import the chain as an archive node and ensure all pointers are updated
archiveDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if n, err := archive.InsertChain(blocks); err != nil {
t.Fatalf("failed to process block %d: %v", n, err)
@ -825,8 +691,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Import the chain as a non-archive node and ensure all pointers are updated
fastDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
headers := make([]*types.Header, len(blocks))
for i, block := range blocks {
@ -844,8 +710,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Import the chain as a light node and ensure all pointers are updated
lightDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds})
light, _ := NewBlockChain(lightDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
gspec.MustCommit(lightDb)
light, _ := NewBlockChain(lightDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
t.Fatalf("failed to insert header %d: %v", n, err)
@ -857,9 +723,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Tests that chain reorganisations handle transaction removals and reinsertions.
func TestChainTxReorgs(t *testing.T) {
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
@ -868,13 +731,19 @@ func TestChainTxReorgs(t *testing.T) {
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase()
signer = types.NewEIP155Signer(big.NewInt(1))
)
genesis := WriteGenesisBlockForTesting(db,
GenesisAccount{addr1, big.NewInt(1000000)},
GenesisAccount{addr2, big.NewInt(1000000)},
GenesisAccount{addr3, big.NewInt(1000000)},
gspec = &Genesis{
Config: params.TestChainConfig,
GasLimit: 3141592,
Alloc: GenesisAlloc{
addr1: {Balance: big.NewInt(1000000)},
addr2: {Balance: big.NewInt(1000000)},
addr3: {Balance: big.NewInt(1000000)},
},
}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
)
// Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain
@ -892,7 +761,7 @@ func TestChainTxReorgs(t *testing.T) {
// - futureAdd: transaction added after the reorg has already finished
var pastAdd, freshAdd, futureAdd *types.Transaction
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {
switch i {
case 0:
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
@ -911,13 +780,13 @@ func TestChainTxReorgs(t *testing.T) {
})
// Import the chain. This runs all block validation rules.
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
if i, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
}
// overwrite the old chain
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
switch i {
case 0:
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
@ -969,23 +838,20 @@ func TestChainTxReorgs(t *testing.T) {
}
func TestLogReorgs(t *testing.T) {
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
db, _ = ethdb.NewMemDatabase()
// this code generates a log
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
signer = types.NewEIP155Signer(big.NewInt(1))
)
genesis := WriteGenesisBlockForTesting(db,
GenesisAccount{addr1, big.NewInt(10000000000000)},
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
)
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
var evmux event.TypeMux
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &evmux, vm.Config{})
subs := evmux.Subscribe(RemovedLogsEvent{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
@ -1017,19 +883,20 @@ func TestReorgSideEvent(t *testing.T) {
db, _ = ethdb.NewMemDatabase()
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
signer = types.NewEIP155Signer(big.NewInt(1))
gspec = testGenesis(addr1, big.NewInt(10000000000000))
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
)
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
replacementBlocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
if i == 2 {
gen.OffsetTime(-1)
@ -1092,28 +959,21 @@ done:
// Tests if the canonical block can be fetched from the database during chain insertion.
func TestCanonicalBlockRetrieval(t *testing.T) {
var (
db, _ = ethdb.NewMemDatabase()
genesis = WriteGenesisBlockForTesting(db)
)
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
bc := newTestBlockChain()
chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
for i := range chain {
go func(block *types.Block) {
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
for {
ch := GetCanonicalHash(db, block.NumberU64())
ch := GetCanonicalHash(bc.chainDb, block.NumberU64())
if ch == (common.Hash{}) {
continue // busy wait for canonical hash to be written
}
if ch != block.Hash() {
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
}
fb := GetBlock(db, ch, block.NumberU64())
fb := GetBlock(bc.chainDb, ch, block.NumberU64())
if fb == nil {
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
}
@ -1124,7 +984,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
}
}(chain[i])
blockchain.InsertChain(types.Blocks{chain[i]})
bc.InsertChain(types.Blocks{chain[i]})
}
}
@ -1136,13 +996,16 @@ func TestEIP155Transition(t *testing.T) {
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
deleteAddr = common.Address{1}
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}, GenesisAccount{deleteAddr, new(big.Int)})
config = &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
mux event.TypeMux
gspec = &Genesis{
Config: &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
}
genesis = gspec.MustCommit(db)
mux event.TypeMux
)
blockchain, _ := NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{})
blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
err error
@ -1164,7 +1027,7 @@ func TestEIP155Transition(t *testing.T) {
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
if err != nil {
t.Fatal(err)
}
@ -1176,7 +1039,7 @@ func TestEIP155Transition(t *testing.T) {
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
if err != nil {
t.Fatal(err)
}
@ -1204,7 +1067,7 @@ func TestEIP155Transition(t *testing.T) {
}
// generate an invalid chain id transaction
config = &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
config := &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
@ -1236,22 +1099,24 @@ func TestEIP161AccountRemoval(t *testing.T) {
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
theAddr = common.Address{1}
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds})
config = &params.ChainConfig{
ChainId: big.NewInt(1),
HomesteadBlock: new(big.Int),
EIP155Block: new(big.Int),
EIP158Block: big.NewInt(2),
gspec = &Genesis{
Config: &params.ChainConfig{
ChainId: big.NewInt(1),
HomesteadBlock: new(big.Int),
EIP155Block: new(big.Int),
EIP158Block: big.NewInt(2),
},
Alloc: GenesisAlloc{address: {Balance: funds}},
}
mux event.TypeMux
blockchain, _ = NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{})
genesis = gspec.MustCommit(db)
mux event.TypeMux
blockchain, _ = NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
)
blocks, _ := GenerateChain(config, genesis, db, 3, func(i int, block *BlockGen) {
blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) {
var (
tx *types.Transaction
err error
signer = types.NewEIP155Signer(config.ChainId)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
)
switch i {
case 0:
@ -1279,7 +1144,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
t.Fatal(err)
}
if blockchain.stateCache.Exist(theAddr) {
t.Error("account should not expect")
t.Error("account should not exist")
}
// account musn't be created post eip 161
@ -1287,6 +1152,6 @@ func TestEIP161AccountRemoval(t *testing.T) {
t.Fatal(err)
}
if blockchain.stateCache.Exist(theAddr) {
t.Error("account should not expect")
t.Error("account should not exist")
}
}

View File

@ -30,19 +30,6 @@ import (
"github.com/ethereum/go-ethereum/pow"
)
/*
* TODO: move this to another package.
*/
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
func MakeChainConfig() *params.ChainConfig {
return &params.ChainConfig{
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
}
}
// So we can deterministically seed different blockchains
var (
canonicalSeed = 1
@ -154,7 +141,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
panic("block time out of range")
}
b.header.Difficulty = CalcDifficulty(MakeChainConfig(), b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
b.header.Difficulty = CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
}
// GenerateChain creates a chain of n blocks. The first block's
@ -170,14 +157,13 @@ func (b *BlockGen) OffsetTime(seconds int64) {
// values. Inserting them into BlockChain requires use of FakePow or
// a similar non-validating proof of work implementation.
func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
if config == nil {
config = params.TestChainConfig
}
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
// Mutate the state and block according to any hard-fork specs
if config == nil {
config = MakeChainConfig()
}
if daoBlock := config.DAOForkBlock; daoBlock != nil {
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
@ -226,7 +212,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(),
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
Difficulty: CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
GasLimit: CalcGasLimit(parent),
GasUsed: new(big.Int),
Number: new(big.Int).Add(parent.Number(), common.Big1),
@ -238,14 +224,12 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
// chain. Depending on the full flag, if creates either a full block chain or a
// header only chain.
func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
// Create the new chain database
db, _ := ethdb.NewMemDatabase()
evmux := &event.TypeMux{}
// Initialize a fresh chain with only a genesis block
genesis, _ := WriteTestNetGenesisBlock(db)
gspec := new(Genesis)
db, _ := ethdb.NewMemDatabase()
genesis := gspec.MustCommit(db)
blockchain, _ := NewBlockChain(db, MakeChainConfig(), pow.FakePow{}, evmux, vm.Config{})
blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, pow.FakePow{}, new(event.TypeMux), vm.Config{})
// Create and inject the requested chain
if n == 0 {
return db, blockchain, nil

View File

@ -30,9 +30,6 @@ import (
)
func ExampleGenerateChain() {
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
@ -41,19 +38,20 @@ func ExampleGenerateChain() {
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase()
signer = types.HomesteadSigner{}
)
chainConfig := &params.ChainConfig{
HomesteadBlock: new(big.Int),
}
// Ensure that key1 has some funds in the genesis block.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
gspec := &Genesis{
Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
}
genesis := gspec.MustCommit(db)
// This call generates a chain of 5 blocks. The function runs for
// each block and adds different features to gen based on the
// block index.
chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
signer := types.HomesteadSigner{}
chain, _ := GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
switch i {
case 0:
// In block 1, addr1 sends addr2 some ether.
@ -83,7 +81,7 @@ func ExampleGenerateChain() {
// Import the chain. This runs all block validation rules.
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, chainConfig, pow.FakePow{}, evmux, vm.Config{})
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
if i, err := blockchain.InsertChain(chain); err != nil {
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
return

View File

@ -67,7 +67,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
}
// Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList {
for _, addr := range params.DAODrainList() {
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
statedb.SetBalance(addr, new(big.Int))
}

View File

@ -34,17 +34,18 @@ func TestDAOForkRangeExtradata(t *testing.T) {
// Generate a common prefix for both pro-forkers and non-forkers
db, _ := ethdb.NewMemDatabase()
genesis := WriteGenesisBlockForTesting(db)
gspec := new(Genesis)
genesis := gspec.MustCommit(db)
prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
// Create the concurrent, conflicting two nodes
proDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(proDb)
gspec.MustCommit(proDb)
proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
conDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(conDb)
gspec.MustCommit(conDb)
conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
@ -58,7 +59,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
// Create a pro-fork block, and try to feed into the no-fork chain
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
gspec.MustCommit(db)
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
@ -79,7 +80,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
}
// Create a no-fork block, and try to feed into the pro-fork chain
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
gspec.MustCommit(db)
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
@ -101,7 +102,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
}
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
gspec.MustCommit(db)
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
@ -117,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
}
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
gspec.MustCommit(db)
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))

View File

@ -562,7 +562,7 @@ func TestMipmapChain(t *testing.T) {
)
defer db.Close()
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
genesis := testGenesis(addr, big.NewInt(1000000)).MustCommit(db)
chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
var receipts types.Receipts
switch i {

File diff suppressed because one or more lines are too long

106
core/gen_genesis.go Normal file
View File

@ -0,0 +1,106 @@
// generated by github.com/fjl/gencodec, do not edit.
package core
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
)
func (g *Genesis) MarshalJSON() ([]byte, error) {
type GenesisJSON struct {
ChainConfig *params.ChainConfig `json:"config" optional:"true"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
Timestamp *math.HexOrDecimal64 `json:"timestamp" optional:"true"`
ParentHash *common.Hash `json:"parentHash" optional:"true"`
ExtraData hexutil.Bytes `json:"extraData" optional:"true"`
GasLimit *math.HexOrDecimal64 `json:"gasLimit"`
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
Mixhash *common.Hash `json:"mixHash" optional:"true"`
Coinbase *common.Address `json:"coinbase" optional:"true"`
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
}
var enc GenesisJSON
enc.ChainConfig = g.Config
enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
enc.Timestamp = (*math.HexOrDecimal64)(&g.Timestamp)
enc.ParentHash = &g.ParentHash
if g.ExtraData != nil {
enc.ExtraData = g.ExtraData
}
enc.GasLimit = (*math.HexOrDecimal64)(&g.GasLimit)
enc.Difficulty = (*math.HexOrDecimal256)(g.Difficulty)
enc.Mixhash = &g.Mixhash
enc.Coinbase = &g.Coinbase
if g.Alloc != nil {
enc.Alloc = make(map[common.UnprefixedAddress]GenesisAccount, len(g.Alloc))
for k, v := range g.Alloc {
enc.Alloc[common.UnprefixedAddress(k)] = v
}
}
return json.Marshal(&enc)
}
func (g *Genesis) UnmarshalJSON(input []byte) error {
type GenesisJSON struct {
ChainConfig *params.ChainConfig `json:"config" optional:"true"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
Timestamp *math.HexOrDecimal64 `json:"timestamp" optional:"true"`
ParentHash *common.Hash `json:"parentHash" optional:"true"`
ExtraData hexutil.Bytes `json:"extraData" optional:"true"`
GasLimit *math.HexOrDecimal64 `json:"gasLimit"`
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
Mixhash *common.Hash `json:"mixHash" optional:"true"`
Coinbase *common.Address `json:"coinbase" optional:"true"`
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
}
var dec GenesisJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x Genesis
if dec.ChainConfig != nil {
x.Config = dec.ChainConfig
}
if dec.Nonce != nil {
x.Nonce = uint64(*dec.Nonce)
}
if dec.Timestamp != nil {
x.Timestamp = uint64(*dec.Timestamp)
}
if dec.ParentHash != nil {
x.ParentHash = *dec.ParentHash
}
if dec.ExtraData != nil {
x.ExtraData = dec.ExtraData
}
if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for Genesis")
}
x.GasLimit = uint64(*dec.GasLimit)
if dec.Difficulty == nil {
return errors.New("missing required field 'difficulty' for Genesis")
}
x.Difficulty = (*big.Int)(dec.Difficulty)
if dec.Mixhash != nil {
x.Mixhash = *dec.Mixhash
}
if dec.Coinbase != nil {
x.Coinbase = *dec.Coinbase
}
if dec.Alloc == nil {
return errors.New("missing required field 'alloc' for Genesis")
}
x.Alloc = make(GenesisAlloc, len(dec.Alloc))
for k, v := range dec.Alloc {
x.Alloc[common.Address(k)] = v
}
*g = x
return nil
}

View File

@ -0,0 +1,61 @@
// generated by github.com/fjl/gencodec, do not edit.
package core
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
)
func (g *GenesisAccount) MarshalJSON() ([]byte, error) {
type GenesisAccountJSON struct {
Code hexutil.Bytes `json:"code" optional:"true"`
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
Balance *math.HexOrDecimal256 `json:"balance"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
}
var enc GenesisAccountJSON
if g.Code != nil {
enc.Code = g.Code
}
if g.Storage != nil {
enc.Storage = g.Storage
}
enc.Balance = (*math.HexOrDecimal256)(g.Balance)
enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
return json.Marshal(&enc)
}
func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
type GenesisAccountJSON struct {
Code hexutil.Bytes `json:"code" optional:"true"`
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
Balance *math.HexOrDecimal256 `json:"balance"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
}
var dec GenesisAccountJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x GenesisAccount
if dec.Code != nil {
x.Code = dec.Code
}
if dec.Storage != nil {
x.Storage = dec.Storage
}
if dec.Balance == nil {
return errors.New("missing required field 'balance' for GenesisAccount")
}
x.Balance = (*big.Int)(dec.Balance)
if dec.Nonce != nil {
x.Nonce = uint64(*dec.Nonce)
}
*g = x
return nil
}

View File

@ -17,230 +17,286 @@
package core
import (
"compress/bzip2"
"compress/gzip"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
// WriteGenesisBlock writes the genesis block to the database as block number 0
func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) {
contents, err := ioutil.ReadAll(reader)
//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
//go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
var errGenesisNoConfig = errors.New("genesis has no chain configuration")
// Genesis specifies the header fields, state of a genesis block. It also defines hard
// fork switch-over blocks through the chain configuration.
type Genesis struct {
Config *params.ChainConfig `json:"config" optional:"true"`
Nonce uint64 `json:"nonce" optional:"true"`
Timestamp uint64 `json:"timestamp" optional:"true"`
ParentHash common.Hash `json:"parentHash" optional:"true"`
ExtraData []byte `json:"extraData" optional:"true"`
GasLimit uint64 `json:"gasLimit"`
Difficulty *big.Int `json:"difficulty"`
Mixhash common.Hash `json:"mixHash" optional:"true"`
Coinbase common.Address `json:"coinbase" optional:"true"`
Alloc GenesisAlloc `json:"alloc"`
}
// GenesisAlloc specifies the initial state that is part of the genesis block.
type GenesisAlloc map[common.Address]GenesisAccount
// GenesisAccount is an account in the state of the genesis block.
type GenesisAccount struct {
Code []byte `json:"code" optional:"true"`
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
Balance *big.Int `json:"balance"`
Nonce uint64 `json:"nonce" optional:"true"`
}
// field type overrides for gencodec
type genesisSpecMarshaling struct {
Nonce math.HexOrDecimal64
Timestamp math.HexOrDecimal64
ExtraData hexutil.Bytes
GasLimit math.HexOrDecimal64
Difficulty *math.HexOrDecimal256
Alloc map[common.UnprefixedAddress]GenesisAccount
}
type genesisAccountMarshaling struct {
Code hexutil.Bytes
Balance *math.HexOrDecimal256
Nonce math.HexOrDecimal64
}
// GenesisMismatchError is raised when trying to overwrite an existing
// genesis block with an incompatible one.
type GenesisMismatchError struct {
Stored, New common.Hash
}
func (e *GenesisMismatchError) Error() string {
return fmt.Sprintf("wrong genesis block in database (have %x, new %x)", e.Stored[:8], e.New[:8])
}
// SetupGenesisBlock writes or updates the genesis block in db.
// The block that will be used is:
//
// genesis == nil genesis != nil
// +------------------------------------------
// db has no genesis | main-net default | genesis
// db has genesis | from DB | genesis (if compatible)
//
// The stored chain configuration will be updated if it is compatible (i.e. does not
// specify a fork block below the local head block). In case of a conflict, the
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
//
// The returned chain configuration is never nil.
func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
if genesis != nil && genesis.Config == nil {
return params.AllProtocolChanges, common.Hash{}, errGenesisNoConfig
}
// Just commit the new block if there is no stored genesis block.
stored := GetCanonicalHash(db, 0)
if (stored == common.Hash{}) {
if genesis == nil {
log.Info("Writing default main-net genesis block")
genesis = DefaultGenesisBlock()
} else {
log.Info("Writing custom genesis block")
}
block, err := genesis.Commit(db)
return genesis.Config, block.Hash(), err
}
// Check whether the genesis block is already written.
if genesis != nil {
block, _ := genesis.ToBlock()
hash := block.Hash()
if hash != stored {
return genesis.Config, block.Hash(), &GenesisMismatchError{stored, hash}
}
}
// Get the existing chain configuration.
newcfg := genesis.configOrDefault(stored)
storedcfg, err := GetChainConfig(db, stored)
if err != nil {
return nil, err
}
var genesis struct {
ChainConfig *params.ChainConfig `json:"config"`
Nonce string
Timestamp string
ParentHash string
ExtraData string
GasLimit string
Difficulty string
Mixhash string
Coinbase string
Alloc map[string]struct {
Code string
Storage map[string]string
Balance string
Nonce string
if err == ChainConfigNotFoundErr {
// This case happens if a genesis write was interrupted.
log.Warn("Found genesis block without chain config")
err = WriteChainConfig(db, stored, newcfg)
}
return newcfg, stored, err
}
// Special case: don't change the existing config of a non-mainnet chain if no new
// config is supplied. These chains would get AllProtocolChanges (and a compat error)
// if we just continued here.
if genesis == nil && stored != params.MainNetGenesisHash {
return storedcfg, stored, nil
}
if err := json.Unmarshal(contents, &genesis); err != nil {
return nil, err
// Check config compatibility and write the config. Compatibility errors
// are returned to the caller unless we're already at block zero.
height := GetBlockNumber(db, GetHeadHeaderHash(db))
if height == missingNumber {
return newcfg, stored, fmt.Errorf("missing block number for head header hash")
}
if genesis.ChainConfig == nil {
genesis.ChainConfig = params.AllProtocolChanges
compatErr := storedcfg.CheckCompatible(newcfg, height)
if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
return newcfg, stored, compatErr
}
return newcfg, stored, WriteChainConfig(db, stored, newcfg)
}
// creating with empty hash always works
statedb, _ := state.New(common.Hash{}, chainDb)
for addr, account := range genesis.Alloc {
balance, ok := math.ParseBig256(account.Balance)
if !ok {
return nil, fmt.Errorf("invalid balance for account %s: %q", addr, account.Balance)
}
nonce, ok := math.ParseUint64(account.Nonce)
if !ok {
return nil, fmt.Errorf("invalid nonce for account %s: %q", addr, account.Nonce)
}
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
switch {
case g != nil:
return g.Config
case ghash == params.MainNetGenesisHash:
return params.MainnetChainConfig
case ghash == params.TestNetGenesisHash:
return params.TestnetChainConfig
default:
return params.AllProtocolChanges
}
}
address := common.HexToAddress(addr)
statedb.AddBalance(address, balance)
statedb.SetCode(address, common.FromHex(account.Code))
statedb.SetNonce(address, nonce)
// ToBlock creates the block and state of a genesis specification.
func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
for addr, account := range g.Alloc {
statedb.AddBalance(addr, account.Balance)
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
for key, value := range account.Storage {
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
statedb.SetState(addr, key, value)
}
}
root, stateBatch := statedb.CommitBatch(false)
difficulty, ok := math.ParseBig256(genesis.Difficulty)
if !ok {
return nil, fmt.Errorf("invalid difficulty: %q", genesis.Difficulty)
}
gaslimit, ok := math.ParseUint64(genesis.GasLimit)
if !ok {
return nil, fmt.Errorf("invalid gas limit: %q", genesis.GasLimit)
}
nonce, ok := math.ParseUint64(genesis.Nonce)
if !ok {
return nil, fmt.Errorf("invalid nonce: %q", genesis.Nonce)
}
timestamp, ok := math.ParseBig256(genesis.Timestamp)
if !ok {
return nil, fmt.Errorf("invalid timestamp: %q", genesis.Timestamp)
}
block := types.NewBlock(&types.Header{
Nonce: types.EncodeNonce(nonce),
Time: timestamp,
ParentHash: common.HexToHash(genesis.ParentHash),
Extra: common.FromHex(genesis.ExtraData),
GasLimit: new(big.Int).SetUint64(gaslimit),
Difficulty: difficulty,
MixDigest: common.HexToHash(genesis.Mixhash),
Coinbase: common.HexToAddress(genesis.Coinbase),
root := statedb.IntermediateRoot(false)
head := &types.Header{
Nonce: types.EncodeNonce(g.Nonce),
Time: new(big.Int).SetUint64(g.Timestamp),
ParentHash: g.ParentHash,
Extra: g.ExtraData,
GasLimit: new(big.Int).SetUint64(g.GasLimit),
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
Coinbase: g.Coinbase,
Root: root,
}, nil, nil, nil)
if block := GetBlock(chainDb, block.Hash(), block.NumberU64()); block != nil {
log.Info("Genesis block known, writing canonical number")
err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
if err != nil {
return nil, err
}
return block, nil
}
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
}
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
}
return types.NewBlock(head, nil, nil, nil), statedb
}
if err := stateBatch.Write(); err != nil {
// Commit writes the block and state of a genesis specification to the database.
// The block is committed as the canonical head block.
func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
block, statedb := g.ToBlock()
if _, err := statedb.CommitTo(db, false); err != nil {
return nil, fmt.Errorf("cannot write state: %v", err)
}
if err := WriteTd(chainDb, block.Hash(), block.NumberU64(), difficulty); err != nil {
if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil {
return nil, err
}
if err := WriteBlock(chainDb, block); err != nil {
if err := WriteBlock(db, block); err != nil {
return nil, err
}
if err := WriteBlockReceipts(chainDb, block.Hash(), block.NumberU64(), nil); err != nil {
if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil {
return nil, err
}
if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil {
if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil {
return nil, err
}
if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil {
if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
return nil, err
}
if err := WriteChainConfig(chainDb, block.Hash(), genesis.ChainConfig); err != nil {
if err := WriteHeadHeaderHash(db, block.Hash()); err != nil {
return nil, err
}
return block, nil
config := g.Config
if config == nil {
config = params.AllProtocolChanges
}
return block, WriteChainConfig(db, block.Hash(), config)
}
// GenesisBlockForTesting creates a block in which addr has the given wei balance.
// The state trie of the block is written to db. the passed db needs to contain a state root
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
statedb, _ := state.New(common.Hash{}, db)
obj := statedb.GetOrNewStateObject(addr)
obj.SetBalance(balance)
root, err := statedb.Commit(false)
if err != nil {
panic(fmt.Sprintf("cannot write state: %v", err))
}
block := types.NewBlock(&types.Header{
Difficulty: params.GenesisDifficulty,
GasLimit: params.GenesisGasLimit,
Root: root,
}, nil, nil, nil)
return block
}
type GenesisAccount struct {
Address common.Address
Balance *big.Int
}
func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block {
accountJson := "{"
for i, account := range accounts {
if i != 0 {
accountJson += ","
}
accountJson += fmt.Sprintf(`"0x%x":{"balance":"%d"}`, account.Address, account.Balance)
}
accountJson += "}"
testGenesis := fmt.Sprintf(`{
"nonce":"0x%x",
"gasLimit":"0x%x",
"difficulty":"0x%x",
"alloc": %s
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), accountJson)
block, err := WriteGenesisBlock(db, strings.NewReader(testGenesis))
// MustCommit writes the genesis block and state to db, panicking on error.
// The block is committed as the canonical head block.
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
block, err := g.Commit(db)
if err != nil {
panic(err)
}
return block
}
// WriteDefaultGenesisBlock assembles the official Ethereum genesis block and
// writes it - along with all associated state - into a chain database.
func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
return g.MustCommit(db)
}
// WriteTestNetGenesisBlock assembles the test network genesis block and
// writes it - along with all associated state - into a chain database.
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
// DefaultGenesisBlock returns the Ethereum main net genesis block.
func DefaultGenesisBlock() *Genesis {
return &Genesis{
Config: params.MainnetChainConfig,
Nonce: 66,
ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
GasLimit: 5000,
Difficulty: big.NewInt(17179869184),
Alloc: decodePrealloc(mainnetAllocData),
}
}
// DefaultGenesisBlock assembles a JSON string representing the default Ethereum
// genesis block.
func DefaultGenesisBlock() string {
reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock)))
if err != nil {
panic(fmt.Sprintf("failed to access default genesis: %v", err))
// DefaultTestnetGenesisBlock returns the Ropsten network genesis block.
func DefaultTestnetGenesisBlock() *Genesis {
return &Genesis{
Config: params.TestnetChainConfig,
Nonce: 66,
ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"),
GasLimit: 16777216,
Difficulty: big.NewInt(1048576),
Alloc: decodePrealloc(testnetAllocData),
}
blob, err := ioutil.ReadAll(reader)
if err != nil {
panic(fmt.Sprintf("failed to load default genesis: %v", err))
}
return string(blob)
}
// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum
// test network genesis block.
func DefaultTestnetGenesisBlock() string {
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
blob, err := ioutil.ReadAll(reader)
if err != nil {
panic(fmt.Sprintf("failed to load default genesis: %v", err))
// DevGenesisBlock returns the 'geth --dev' genesis block.
func DevGenesisBlock() *Genesis {
return &Genesis{
Config: params.AllProtocolChanges,
Nonce: 42,
GasLimit: 4712388,
Difficulty: big.NewInt(131072),
Alloc: decodePrealloc(devAllocData),
}
return string(blob)
}
// DevGenesisBlock assembles a JSON string representing a local dev genesis block.
func DevGenesisBlock() string {
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
blob, err := ioutil.ReadAll(reader)
if err != nil {
panic(fmt.Sprintf("failed to load dev genesis: %v", err))
func decodePrealloc(data string) GenesisAlloc {
var p []struct{ Addr, Balance *big.Int }
if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil {
panic(err)
}
return string(blob)
ga := make(GenesisAlloc, len(p))
for _, account := range p {
ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance}
}
return ga
}

25
core/genesis_alloc.go Normal file

File diff suppressed because one or more lines are too long

161
core/genesis_test.go Normal file
View File

@ -0,0 +1,161 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"math/big"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
)
func TestDefaultGenesisBlock(t *testing.T) {
block, _ := DefaultGenesisBlock().ToBlock()
if block.Hash() != params.MainNetGenesisHash {
t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainNetGenesisHash)
}
block, _ = DefaultTestnetGenesisBlock().ToBlock()
if block.Hash() != params.TestNetGenesisHash {
t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestNetGenesisHash)
}
}
func TestSetupGenesis(t *testing.T) {
var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
},
}
oldcustomg = customg
)
oldcustomg.Config = &params.ChainConfig{HomesteadBlock: big.NewInt(2)}
tests := []struct {
name string
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
wantConfig *params.ChainConfig
wantHash common.Hash
wantErr error
}{
{
name: "genesis without ChainConfig",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, new(Genesis))
},
wantErr: errGenesisNoConfig,
wantConfig: params.AllProtocolChanges,
},
{
name: "no block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainNetGenesisHash,
wantConfig: params.MainnetChainConfig,
},
{
name: "mainnet block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
DefaultGenesisBlock().MustCommit(db)
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainNetGenesisHash,
wantConfig: params.MainnetChainConfig,
},
{
name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, nil)
},
wantHash: customghash,
wantConfig: customg.Config,
},
{
name: "custom block in DB, genesis == testnet",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestNetGenesisHash},
wantHash: params.TestNetGenesisHash,
wantConfig: params.TestnetChainConfig,
},
{
name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
oldcustomg.MustCommit(db)
return SetupGenesisBlock(db, &customg)
},
wantHash: customghash,
wantConfig: customg.Config,
},
{
name: "incompatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
// Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg.
genesis := oldcustomg.MustCommit(db)
bc, _ := NewBlockChain(db, oldcustomg.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
bc.SetValidator(bproc{})
bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
bc.CurrentBlock()
// This should return a compatibility error.
return SetupGenesisBlock(db, &customg)
},
wantHash: customghash,
wantConfig: customg.Config,
wantErr: &params.ConfigCompatError{
What: "Homestead fork block",
StoredConfig: big.NewInt(2),
NewConfig: big.NewInt(3),
RewindTo: 1,
},
},
}
for _, test := range tests {
db, _ := ethdb.NewMemDatabase()
config, hash, err := test.fn(db)
// Check the return values.
if !reflect.DeepEqual(err, test.wantErr) {
spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
}
if !reflect.DeepEqual(config, test.wantConfig) {
t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig)
}
if hash != test.wantHash {
t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
} else if err == nil {
// Check database content.
stored := GetBlock(db, test.wantHash, 0)
if stored.Hash() != test.wantHash {
t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
}
}
}
}

View File

@ -97,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
hc.genesisHeader = hc.GetHeaderByNumber(0)
if hc.genesisHeader == nil {
genesisBlock, err := WriteDefaultGenesisBlock(chainDb)
if err != nil {
return nil, err
}
log.Warn("Wrote default Ethereum genesis block")
hc.genesisHeader = genesisBlock.Header()
return nil, ErrNoGenesis
}
hc.currentHeader = hc.genesisHeader

85
core/mkalloc.go Normal file
View File

@ -0,0 +1,85 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build none
/*
The mkalloc tool creates the genesis allocation constants in genesis_alloc.go
It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples.
go run mkalloc.go genesis.json
*/
package main
import (
"encoding/json"
"fmt"
"math/big"
"os"
"sort"
"strconv"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/rlp"
)
type allocItem struct{ Addr, Balance *big.Int }
type allocList []allocItem
func (a allocList) Len() int { return len(a) }
func (a allocList) Less(i, j int) bool { return a[i].Addr.Cmp(a[j].Addr) < 0 }
func (a allocList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func makelist(g *core.Genesis) allocList {
a := make(allocList, 0, len(g.Alloc))
for addr, account := range g.Alloc {
if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
panic(fmt.Sprintf("can't encode account %x", addr))
}
a = append(a, allocItem{addr.Big(), account.Balance})
}
sort.Sort(a)
return a
}
func makealloc(g *core.Genesis) string {
a := makelist(g)
data, err := rlp.EncodeToBytes(a)
if err != nil {
panic(err)
}
return strconv.QuoteToASCII(string(data))
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "Usage: mkalloc genesis.json")
os.Exit(1)
}
g := new(core.Genesis)
file, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
if err := json.NewDecoder(file).Decode(g); err != nil {
panic(err)
}
fmt.Println("const allocData =", makealloc(g))
}

View File

@ -42,7 +42,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
statedb, _ := state.New(common.Hash{}, db)
key, _ := crypto.GenerateKey()
newPool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
newPool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
newPool.resetState()
return newPool, key
@ -91,7 +91,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc)
txpool := NewTxPool(params.TestChainConfig, mux, stateFunc, gasLimitFunc)
txpool.resetState()
nonce := txpool.State().GetNonce(address)
@ -564,7 +564,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
@ -713,7 +713,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
@ -759,7 +759,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them

View File

@ -27,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
@ -119,19 +118,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice
return &Transaction{data: d}
}
func pickSigner(rules params.Rules) Signer {
var signer Signer
switch {
case rules.IsEIP155:
signer = NewEIP155Signer(rules.ChainId)
case rules.IsHomestead:
signer = HomesteadSigner{}
default:
signer = FrontierSigner{}
}
return signer
}
// ChainId returns which chain id this transaction was signed for (if at all)
func (tx *Transaction) ChainId() *big.Int {
return deriveChainId(tx.data.V)

View File

@ -18,11 +18,9 @@
package eth
import (
"errors"
"fmt"
"math/big"
"regexp"
"strings"
"sync"
"time"
@ -60,15 +58,17 @@ var (
)
type Config struct {
ChainConfig *params.ChainConfig // chain configuration
// The genesis block, which is inserted if the database is empty.
// If nil, the Ethereum main net block is used.
Genesis *core.Genesis
NetworkId int // Network ID to use for selecting peers to connect to
Genesis string // Genesis JSON to seed the chain database with
FastSync bool // Enables the state download based fast synchronisation algorithm
LightMode bool // Running in light client mode
LightServ int // Maximum percentage of time allowed for serving LES requests
LightPeers int // Maximum number of LES client peers
MaxPeers int // Maximum number of global peers
NetworkId int // Network ID to use for selecting peers to connect to
FastSync bool // Enables the state download based fast synchronisation algorithm
LightMode bool // Running in light client mode
LightServ int // Maximum percentage of time allowed for serving LES requests
LightPeers int // Maximum number of LES client peers
MaxPeers int // Maximum number of global peers
SkipBcVersionCheck bool // e.g. blockchain export
DatabaseCache int
@ -100,9 +100,6 @@ type Config struct {
GpobaseCorrectionFactor int
EnablePreimageRecording bool
TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!)
TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
}
type LesServer interface {
@ -155,11 +152,15 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil, err
}
stopDbUpgrade := upgradeSequentialKeys(chainDb)
if err := SetupGenesisBlock(&chainDb, config); err != nil {
return nil, err
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
}
log.Info("Initialised chain configuration", "config", chainConfig)
eth := &Ethereum{
chainDb: chainDb,
chainConfig: chainConfig,
eventMux: ctx.EventMux,
accountManager: ctx.AccountManager,
pow: CreatePoW(ctx, config),
@ -184,33 +185,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
}
// load the genesis block or write a new one if no genesis
// block is prenent in the database.
genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0), 0)
if genesis == nil {
genesis, err = core.WriteDefaultGenesisBlock(chainDb)
if err != nil {
return nil, err
}
log.Warn("Wrote default Ethereum genesis block")
}
if config.ChainConfig == nil {
return nil, errors.New("missing chain config")
}
core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
eth.chainConfig = config.ChainConfig
log.Info("Initialised chain configuration", "config", eth.chainConfig)
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux(), vm.Config{EnablePreimageRecording: config.EnablePreimageRecording})
vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux, vmConfig)
if err != nil {
if err == core.ErrNoGenesis {
return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
}
return nil, err
}
// Rewind the chain in case of an incompatible config upgrade.
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
eth.blockchain.SetHead(compat.RewindTo)
core.WriteChainConfig(chainDb, genesisHash, chainConfig)
}
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
eth.txPool = newPool
@ -255,29 +241,6 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
return db, err
}
// SetupGenesisBlock initializes the genesis block for an Ethereum service
func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error {
// Load up any custom genesis block if requested
if len(config.Genesis) > 0 {
block, err := core.WriteGenesisBlock(*chainDb, strings.NewReader(config.Genesis))
if err != nil {
return err
}
log.Info("Successfully wrote custom genesis block", "hash", block.Hash())
}
// Load up a test setup if directly injected
if config.TestGenesisState != nil {
*chainDb = config.TestGenesisState
}
if config.TestGenesisBlock != nil {
core.WriteTd(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
core.WriteBlock(*chainDb, config.TestGenesisBlock)
core.WriteCanonicalHash(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
core.WriteHeadBlockHash(*chainDb, config.TestGenesisBlock.Hash())
}
return nil
}
// CreatePoW creates the required type of PoW instance for an Ethereum service
func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
switch {

View File

@ -30,7 +30,7 @@ import (
func TestMipmapUpgrade(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
addr := common.BytesToAddress([]byte("jeff"))
genesis := core.WriteGenesisBlockForTesting(db)
genesis := new(core.Genesis).MustCommit(db)
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
var receipts types.Receipts

View File

@ -72,12 +72,11 @@ func TestBlockSubscription(t *testing.T) {
t.Parallel()
var (
mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase()
backend = &testBackend{mux, db}
api = NewPublicFilterAPI(backend, false)
genesis = core.WriteGenesisBlockForTesting(db)
mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase()
backend = &testBackend{mux, db}
api = NewPublicFilterAPI(backend, false)
genesis = new(core.Genesis).MustCommit(db)
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
chainEvents = []core.ChainEvent{}
)

View File

@ -60,7 +60,7 @@ func BenchmarkMipmaps(b *testing.B) {
)
defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
genesis := core.GenesisBlockForTesting(db, addr1, big.NewInt(1000000))
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
var receipts types.Receipts
switch i {
@ -112,7 +112,7 @@ func BenchmarkMipmaps(b *testing.B) {
for i := 0; i < b.N; i++ {
logs, _ := filter.Find(context.Background())
if len(logs) != 4 {
b.Fatal("expected 4 log, got", len(logs))
b.Fatal("expected 4 logs, got", len(logs))
}
}
}
@ -138,7 +138,7 @@ func TestFilters(t *testing.T) {
)
defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000))
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
var receipts types.Receipts
switch i {

View File

@ -315,12 +315,12 @@ func testGetNodeData(t *testing.T, protocol int) {
switch i {
case 0:
// In block 1, the test bank sends account #1 some ether.
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx)
case 1:
// In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2.
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1)
block.AddTx(tx2)
@ -372,7 +372,7 @@ func testGetNodeData(t *testing.T, protocol int) {
for i := 0; i < len(data); i++ {
statedb.Put(hashes[i].Bytes(), data[i])
}
accounts := []common.Address{testBank.Address, acc1Addr, acc2Addr}
accounts := []common.Address{testBank, acc1Addr, acc2Addr}
for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb)
@ -407,12 +407,12 @@ func testGetReceipt(t *testing.T, protocol int) {
switch i {
case 0:
// In block 1, the test bank sends account #1 some ether.
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx)
case 1:
// In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2.
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1)
block.AddTx(tx2)
@ -471,8 +471,9 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
evmux = new(event.TypeMux)
pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db)
config = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
gspec = &core.Genesis{Config: config}
genesis = gspec.MustCommit(db)
blockchain, _ = core.NewBlockChain(db, config, pow, evmux, vm.Config{})
)
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)

View File

@ -42,10 +42,7 @@ import (
var (
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testBank = core.GenesisAccount{
Address: crypto.PubkeyToAddress(testBankKey.PublicKey),
Balance: big.NewInt(1000000),
}
testBank = crypto.PubkeyToAddress(testBankKey.PublicKey)
)
// newTestProtocolManager creates a new protocol manager for testing purposes,
@ -53,19 +50,22 @@ var (
// channels for different events.
func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
var (
evmux = new(event.TypeMux)
pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db, testBank)
chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
evmux = new(event.TypeMux)
pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase()
gspec = &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
}
genesis = gspec.MustCommit(db)
blockchain, _ = core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
)
chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
chain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(chain); err != nil {
panic(err)
}
pm, err := NewProtocolManager(chainConfig, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
pm, err := NewProtocolManager(gspec.Config, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@
package les
import (
"errors"
"fmt"
"time"
@ -74,15 +73,19 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
if err != nil {
return nil, err
}
if err := eth.SetupGenesisBlock(&chainDb, config); err != nil {
return nil, err
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
return nil, genesisErr
}
log.Info("Initialised chain configuration", "config", chainConfig)
odr := NewLesOdr(chainDb)
relay := NewLesTxRelay()
eth := &LightEthereum{
odr: odr,
relay: relay,
chainDb: chainDb,
chainConfig: chainConfig,
eventMux: ctx.EventMux,
accountManager: ctx.AccountManager,
pow: eth.CreatePoW(ctx, config),
@ -91,17 +94,16 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
solcPath: config.SolcPath,
}
if config.ChainConfig == nil {
return nil, errors.New("missing chain config")
}
eth.chainConfig = config.ChainConfig
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
if err != nil {
if err == core.ErrNoGenesis {
return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
}
return nil, err
}
// Rewind the chain in case of an incompatible config upgrade.
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
eth.blockchain.SetHead(compat.RewindTo)
core.WriteChainConfig(chainDb, genesisHash, chainConfig)
}
eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil {

View File

@ -134,28 +134,31 @@ func testRCL() RequestCostList {
// channels for different events.
func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) {
var (
evmux = new(event.TypeMux)
pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
odr *LesOdr
chain BlockChain
evmux = new(event.TypeMux)
pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase()
gspec = core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
}
genesis = gspec.MustCommit(db)
odr *LesOdr
chain BlockChain
)
if lightSync {
odr = NewLesOdr(db)
chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
chain, _ = light.NewLightChain(odr, gspec.Config, pow, evmux)
} else {
blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
blockchain, _ := core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err)
}
chain = blockchain
}
pm, err := NewProtocolManager(chainConfig, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
pm, err := NewProtocolManager(gspec.Config, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
if err != nil {
return nil, nil, nil, err
}

View File

@ -45,7 +45,7 @@ type LesServer struct {
}
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
pm, err := NewProtocolManager(config.ChainConfig, false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
if err != nil {
return nil, err
}

View File

@ -96,11 +96,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
if bc.genesisBlock == nil {
bc.genesisBlock, err = core.WriteDefaultGenesisBlock(odr.Database())
if err != nil {
return nil, err
}
log.Warn("Wrote default ethereum genesis block")
return nil, core.ErrNoGenesis
}
if bc.genesisBlock.Hash() == params.MainNetGenesisHash {

View File

@ -20,7 +20,6 @@ import (
"context"
"fmt"
"math/big"
"runtime"
"testing"
"github.com/ethereum/go-ethereum/common"
@ -30,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
"github.com/hashicorp/golang-lru"
)
// So we can deterministically seed different blockchains
@ -59,14 +57,10 @@ func testChainConfig() *params.ChainConfig {
// chain. Depending on the full flag, if creates either a full block chain or a
// header only chain.
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
// Create te new chain database
db, _ := ethdb.NewMemDatabase()
evmux := &event.TypeMux{}
// Initialize a fresh chain with only a genesis block
genesis, _ := core.WriteTestNetGenesisBlock(db)
blockchain, _ := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, evmux)
gspec := core.Genesis{Config: testChainConfig()}
genesis := gspec.MustCommit(db)
blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
// Create and inject the requested chain
if n == 0 {
return db, blockchain, nil
@ -77,21 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
return db, blockchain, err
}
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
func theLightChain(db ethdb.Database, t *testing.T) *LightChain {
var eventMux event.TypeMux
core.WriteTestNetGenesisBlock(db)
LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.NewTestEthash(), &eventMux)
if err != nil {
t.Error("failed creating LightChain:", err)
t.FailNow()
return nil
// newTestLightChain creates a LightChain that doesn't validate anything.
func newTestLightChain() *LightChain {
db, _ := ethdb.NewMemDatabase()
gspec := &core.Genesis{
Difficulty: big.NewInt(1),
Config: testChainConfig(),
}
return LightChain
gspec.MustCommit(db)
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
if err != nil {
panic(err)
}
lc.SetValidator(bproc{})
return lc
}
// Test fork of length N starting from block i
@ -302,20 +295,6 @@ func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
return nil
}
func chm(genesis *types.Block, db ethdb.Database) *LightChain {
odr := &dummyOdr{db: db}
var eventMux event.TypeMux
bc := &LightChain{odr: odr, chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: pow.FakePow{}}
bc.hc, _ = core.NewHeaderChain(db, testChainConfig(), bc.Validator, bc.getProcInterrupt)
bc.bodyCache, _ = lru.New(100)
bc.bodyRLPCache, _ = lru.New(100)
bc.blockCache, _ = lru.New(100)
bc.SetValidator(bproc{})
bc.ResetWithGenesisBlock(genesis)
return bc
}
// Tests that reorganizing a long difficult chain after a short easy one
// overwrites the canonical numbers and links in the database.
func TestReorgLongHeaders(t *testing.T) {
@ -329,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) {
}
func testReorg(t *testing.T, first, second []int, td int64) {
// Create a pristine block chain
db, _ := ethdb.NewMemDatabase()
genesis, _ := core.WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
bc := newTestLightChain()
// Insert an easy and a difficult chain afterwards
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
// Check that the chain is valid number and link wise
prev := bc.CurrentHeader()
for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
@ -345,7 +321,7 @@ func testReorg(t *testing.T, first, second []int, td int64) {
}
}
// Make sure the chain total difficulty is the correct one
want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td))
want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
}
@ -353,14 +329,11 @@ func testReorg(t *testing.T, first, second []int, td int64) {
// Tests that the insertion functions detect banned hashes.
func TestBadHeaderHashes(t *testing.T) {
// Create a pristine block chain
db, _ := ethdb.NewMemDatabase()
genesis, _ := core.WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
bc := newTestLightChain()
// Create a chain, ban a hash and try to import
var err error
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
core.BadHashes[headers[2].Hash()] = true
_, err = bc.InsertHeaderChain(headers, 1)
if !core.IsBadHashError(err) {
@ -371,13 +344,10 @@ func TestBadHeaderHashes(t *testing.T) {
// Tests that bad hashes are detected on boot, and the chan rolled back to a
// good state prior to the bad hash.
func TestReorgBadHeaderHashes(t *testing.T) {
// Create a pristine block chain
db, _ := ethdb.NewMemDatabase()
genesis, _ := core.WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
bc := newTestLightChain()
// Create a chain, import and ban aferwards
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
t.Fatalf("failed to import headers: %v", err)
@ -387,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) {
}
core.BadHashes[headers[3].Hash()] = true
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
// Create a new chain manager and check it rolled back the state
ncm, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
// Create a new LightChain and check that it rolled back the state.
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
if err != nil {
t.Fatalf("failed to create new chain manager: %v", err)
}

View File

@ -251,9 +251,10 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
pow = new(pow.FakePow)
sdb, _ = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb)
)
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
gspec.MustCommit(ldb)
// Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}

View File

@ -86,9 +86,10 @@ func TestTxPool(t *testing.T) {
pow = new(pow.FakePow)
sdb, _ = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb)
)
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
gspec.MustCommit(ldb)
// Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}

View File

@ -20,10 +20,12 @@
package geth
import (
"encoding/json"
"fmt"
"math/big"
"path/filepath"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethstats"
@ -92,6 +94,18 @@ func NewNodeConfig() *NodeConfig {
return &config
}
// SetMainnet sets up the node for use on the Ethereum mainnet.
func (cfg *NodeConfig) SetMainnet() {
cfg.EthereumGenesis = ""
cfg.EthereumChainConfig = MainnetChainConfig()
}
// SetTestnet sets up the node for use on the Ethereum testnet.
func (cfg *NodeConfig) SetTestnet() {
cfg.EthereumGenesis = TestnetGenesis()
cfg.EthereumChainConfig = TestnetChainConfig()
}
// Node represents a Geth Ethereum node instance.
type Node struct {
node *node.Node
@ -127,20 +141,34 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
if err != nil {
return nil, err
}
var genesis *core.Genesis
if config.EthereumGenesis != "" {
genesis = new(core.Genesis)
if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil {
return nil, fmt.Errorf("invalid EthereumGenesis: %v", err)
}
}
if config.EthereumChainConfig != nil {
if genesis == nil {
genesis = core.DefaultGenesisBlock()
}
genesis.Config = &params.ChainConfig{
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
}
}
// Register the Ethereum protocol if requested
if config.EthereumEnabled {
ethConf := &eth.Config{
ChainConfig: &params.ChainConfig{
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
},
Genesis: config.EthereumGenesis,
Genesis: genesis,
LightMode: true,
DatabaseCache: config.EthereumDatabaseCache,
NetworkId: config.EthereumNetworkID,

View File

@ -19,6 +19,8 @@
package geth
import (
"encoding/json"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/params"
@ -60,7 +62,11 @@ func TestnetChainConfig() *ChainConfig {
// TestnetGenesis returns the JSON spec to use for the Ethereum test network.
func TestnetGenesis() string {
return core.DefaultTestnetGenesisBlock()
enc, err := json.Marshal(core.DefaultTestnetGenesisBlock())
if err != nil {
panic(err)
}
return string(enc)
}
// ChainConfig is the core config which determines the blockchain settings.

View File

@ -23,39 +23,43 @@ import (
"github.com/ethereum/go-ethereum/common"
)
// MainnetChainConfig is the chain parameters to run a node on the main network.
var MainnetChainConfig = &ChainConfig{
ChainId: MainNetChainID,
HomesteadBlock: MainNetHomesteadBlock,
DAOForkBlock: MainNetDAOForkBlock,
DAOForkSupport: true,
EIP150Block: MainNetHomesteadGasRepriceBlock,
EIP150Hash: MainNetHomesteadGasRepriceHash,
EIP155Block: MainNetSpuriousDragon,
EIP158Block: MainNetSpuriousDragon,
}
var (
// MainnetChainConfig is the chain parameters to run a node on the main network.
MainnetChainConfig = &ChainConfig{
ChainId: MainNetChainID,
HomesteadBlock: MainNetHomesteadBlock,
DAOForkBlock: MainNetDAOForkBlock,
DAOForkSupport: true,
EIP150Block: MainNetHomesteadGasRepriceBlock,
EIP150Hash: MainNetHomesteadGasRepriceHash,
EIP155Block: MainNetSpuriousDragon,
EIP158Block: MainNetSpuriousDragon,
}
// TestnetChainConfig is the chain parameters to run a node on the test network.
var TestnetChainConfig = &ChainConfig{
ChainId: big.NewInt(3),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP155Block: big.NewInt(10),
EIP158Block: big.NewInt(10),
}
// TestnetChainConfig contains the chain parameters to run a node on the ropsten test network.
TestnetChainConfig = &ChainConfig{
ChainId: big.NewInt(3),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP155Block: big.NewInt(10),
EIP158Block: big.NewInt(10),
}
// AllProtocolChanges contains every protocol change (EIPs)
// introduced and accepted by the Ethereum core developers.
//
// This configuration is intentionally not using keyed fields.
// This configuration must *always* have all forks enabled, which
// means that all fields must be set at all times. This forces
// anyone adding flags to the config to also have to set these
// fields.
var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
// AllProtocolChanges contains every protocol change (EIPs)
// introduced and accepted by the Ethereum core developers.
// TestChainConfig is like AllProtocolChanges but has chain ID 1.
//
// This configuration is intentionally not using keyed fields.
// This configuration must *always* have all forks enabled, which
// means that all fields must be set at all times. This forces
// anyone adding flags to the config to also have to set these
// fields.
AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
)
// ChainConfig is the core config which determines the blockchain settings.
//
@ -77,7 +81,7 @@ type ChainConfig struct {
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
}
// String implements the Stringer interface.
// String implements the fmt.Stringer interface.
func (c *ChainConfig) String() string {
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
c.ChainId,
@ -90,17 +94,26 @@ func (c *ChainConfig) String() string {
)
}
var (
TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
TestRules = TestChainConfig.Rules(new(big.Int))
)
// IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
if c.HomesteadBlock == nil || num == nil {
return false
}
return num.Cmp(c.HomesteadBlock) >= 0
return isForked(c.HomesteadBlock, num)
}
// IsDAO returns whether num is either equal to the DAO fork block or greater.
func (c *ChainConfig) IsDAOFork(num *big.Int) bool {
return isForked(c.DAOForkBlock, num)
}
func (c *ChainConfig) IsEIP150(num *big.Int) bool {
return isForked(c.EIP150Block, num)
}
func (c *ChainConfig) IsEIP155(num *big.Int) bool {
return isForked(c.EIP155Block, num)
}
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
return isForked(c.EIP158Block, num)
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
@ -110,51 +123,110 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
if num == nil {
return GasTableHomestead
}
switch {
case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0:
case c.IsEIP158(num):
return GasTableEIP158
case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0:
case c.IsEIP150(num):
return GasTableHomesteadGasRepriceFork
default:
return GasTableHomestead
}
}
func (c *ChainConfig) IsEIP150(num *big.Int) bool {
if c.EIP150Block == nil || num == nil {
// CheckCompatible checks whether scheduled fork transitions have been imported
// with a mismatching chain configuration.
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
bhead := new(big.Int).SetUint64(height)
// Iterate checkCompatible to find the lowest conflict.
var lasterr *ConfigCompatError
for {
err := c.checkCompatible(newcfg, bhead)
if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
break
}
lasterr = err
bhead.SetUint64(err.RewindTo)
}
return lasterr
}
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
}
if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
}
if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport {
return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock)
}
if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
}
if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
}
if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
}
if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) {
return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
}
return nil
}
// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to
// block s2 because head is already past the fork.
func isForkIncompatible(s1, s2, head *big.Int) bool {
return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2)
}
// isForked returns whether a fork scheduled at block s is active at the given head block.
func isForked(s, head *big.Int) bool {
if s == nil || head == nil {
return false
}
return num.Cmp(c.EIP150Block) >= 0
return s.Cmp(head) <= 0
}
func (c *ChainConfig) IsEIP155(num *big.Int) bool {
if c.EIP155Block == nil || num == nil {
return false
func configNumEqual(x, y *big.Int) bool {
if x == nil {
return y == nil
}
return num.Cmp(c.EIP155Block) >= 0
}
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
if c.EIP158Block == nil || num == nil {
return false
if y == nil {
return x == nil
}
return num.Cmp(c.EIP158Block) >= 0
return x.Cmp(y) == 0
}
// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
// that do not have or require information about the block.
//
// Rules is a one time interface meaning that it shouldn't be used in between transition
// phases.
type Rules struct {
ChainId *big.Int
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
// ConfigCompatError is raised if the locally-stored blockchain is initialised with a
// ChainConfig that would alter the past.
type ConfigCompatError struct {
What string
// block numbers of the stored and new configurations
StoredConfig, NewConfig *big.Int
// the block number to which the local chain must be rewound to correct the error
RewindTo uint64
}
func (c *ChainConfig) Rules(num *big.Int) Rules {
return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)}
func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
var rew *big.Int
switch {
case storedblock == nil:
rew = newblock
case newblock == nil || storedblock.Cmp(newblock) < 0:
rew = storedblock
default:
rew = newblock
}
err := &ConfigCompatError{what, storedblock, newblock, 0}
if rew != nil && rew.Sign() > 0 {
err.RewindTo = rew.Uint64() - 1
}
return err
}
func (err *ConfigCompatError) Error() string {
return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
}

81
params/config_test.go Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import (
"math/big"
"reflect"
"testing"
)
func TestCheckCompatible(t *testing.T) {
type test struct {
stored, new *ChainConfig
head uint64
wantErr *ConfigCompatError
}
tests := []test{
{stored: AllProtocolChanges, new: AllProtocolChanges, head: 0, wantErr: nil},
{stored: AllProtocolChanges, new: AllProtocolChanges, head: 100, wantErr: nil},
{
stored: &ChainConfig{EIP150Block: big.NewInt(10)},
new: &ChainConfig{EIP150Block: big.NewInt(20)},
head: 9,
wantErr: nil,
},
{
stored: AllProtocolChanges,
new: &ChainConfig{HomesteadBlock: nil},
head: 3,
wantErr: &ConfigCompatError{
What: "Homestead fork block",
StoredConfig: big.NewInt(0),
NewConfig: nil,
RewindTo: 0,
},
},
{
stored: AllProtocolChanges,
new: &ChainConfig{HomesteadBlock: big.NewInt(1)},
head: 3,
wantErr: &ConfigCompatError{
What: "Homestead fork block",
StoredConfig: big.NewInt(0),
NewConfig: big.NewInt(1),
RewindTo: 0,
},
},
{
stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)},
new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)},
head: 25,
wantErr: &ConfigCompatError{
What: "EIP150 fork block",
StoredConfig: big.NewInt(10),
NewConfig: big.NewInt(20),
RewindTo: 9,
},
},
}
for _, test := range tests {
err := test.stored.CheckCompatible(test.new, test.head)
if !reflect.DeepEqual(err, test.wantErr) {
t.Errorf("error mismatch:\nstored: %v\nnew: %v\nhead: %v\nerr: %v\nwant: %v", test.stored, test.new, test.head, err, test.wantErr)
}
}
}

View File

@ -17,8 +17,6 @@
package params
import (
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@ -47,372 +45,123 @@ var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d2
// DAODrainList is the list of accounts whose full balances will be moved into a
// refund contract at the beginning of the dao-fork block.
var DAODrainList []common.Address
func init() {
// Parse the list of DAO accounts to drain
var list []map[string]string
if err := json.Unmarshal([]byte(daoDrainListJSON), &list); err != nil {
panic(fmt.Errorf("Failed to parse DAO drain list: %v", err))
}
// Collect all the accounts that need draining
for _, dao := range list {
DAODrainList = append(DAODrainList, common.HexToAddress(dao["address"]))
DAODrainList = append(DAODrainList, common.HexToAddress(dao["extraBalanceAccount"]))
func DAODrainList() []common.Address {
return []common.Address{
common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"),
common.HexToAddress("0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"),
common.HexToAddress("0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f"),
common.HexToAddress("0xecd135fa4f61a655311e86238c92adcd779555d2"),
common.HexToAddress("0x1975bd06d486162d5dc297798dfc41edd5d160a7"),
common.HexToAddress("0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"),
common.HexToAddress("0x319f70bab6845585f412ec7724b744fec6095c85"),
common.HexToAddress("0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"),
common.HexToAddress("0x5c8536898fbb74fc7445814902fd08422eac56d0"),
common.HexToAddress("0x6966ab0d485353095148a2155858910e0965b6f9"),
common.HexToAddress("0x779543a0491a837ca36ce8c635d6154e3c4911a6"),
common.HexToAddress("0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"),
common.HexToAddress("0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5"),
common.HexToAddress("0x9c50426be05db97f5d64fc54bf89eff947f0a321"),
common.HexToAddress("0x200450f06520bdd6c527622a273333384d870efb"),
common.HexToAddress("0xbe8539bfe837b67d1282b2b1d61c3f723966f049"),
common.HexToAddress("0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb"),
common.HexToAddress("0xf1385fb24aad0cd7432824085e42aff90886fef5"),
common.HexToAddress("0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091"),
common.HexToAddress("0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"),
common.HexToAddress("0x51e0ddd9998364a2eb38588679f0d2c42653e4a6"),
common.HexToAddress("0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"),
common.HexToAddress("0xf0b1aa0eb660754448a7937c022e30aa692fe0c5"),
common.HexToAddress("0x24c4d950dfd4dd1902bbed3508144a54542bba94"),
common.HexToAddress("0x9f27daea7aca0aa0446220b98d028715e3bc803d"),
common.HexToAddress("0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"),
common.HexToAddress("0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b"),
common.HexToAddress("0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"),
common.HexToAddress("0x6f6704e5a10332af6672e50b3d9754dc460dfa4d"),
common.HexToAddress("0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"),
common.HexToAddress("0x492ea3bb0f3315521c31f273e565b868fc090f17"),
common.HexToAddress("0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"),
common.HexToAddress("0x9ea779f907f0b315b364b0cfc39a0fde5b02a416"),
common.HexToAddress("0xceaeb481747ca6c540a000c1f3641f8cef161fa7"),
common.HexToAddress("0xcc34673c6c40e791051898567a1222daf90be287"),
common.HexToAddress("0x579a80d909f346fbfb1189493f521d7f48d52238"),
common.HexToAddress("0xe308bd1ac5fda103967359b2712dd89deffb7973"),
common.HexToAddress("0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"),
common.HexToAddress("0xac1ecab32727358dba8962a0f3b261731aad9723"),
common.HexToAddress("0x4fd6ace747f06ece9c49699c7cabc62d02211f75"),
common.HexToAddress("0x440c59b325d2997a134c2c7c60a8c61611212bad"),
common.HexToAddress("0x4486a3d68fac6967006d7a517b889fd3f98c102b"),
common.HexToAddress("0x9c15b54878ba618f494b38f0ae7443db6af648ba"),
common.HexToAddress("0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"),
common.HexToAddress("0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241"),
common.HexToAddress("0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"),
common.HexToAddress("0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b"),
common.HexToAddress("0xb9637156d330c0d605a791f1c31ba5890582fe1c"),
common.HexToAddress("0x6131c42fa982e56929107413a9d526fd99405560"),
common.HexToAddress("0x1591fc0f688c81fbeb17f5426a162a7024d430c2"),
common.HexToAddress("0x542a9515200d14b68e934e9830d91645a980dd7a"),
common.HexToAddress("0xc4bbd073882dd2add2424cf47d35213405b01324"),
common.HexToAddress("0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4"),
common.HexToAddress("0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"),
common.HexToAddress("0x3ba4d81db016dc2890c81f3acec2454bff5aada5"),
common.HexToAddress("0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"),
common.HexToAddress("0xe4ae1efdfc53b73893af49113d8694a057b9c0d1"),
common.HexToAddress("0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"),
common.HexToAddress("0x0737a6b837f97f46ebade41b9bc3e1c509c85c53"),
common.HexToAddress("0x97f43a37f595ab5dd318fb46e7a155eae057317a"),
common.HexToAddress("0x52c5317c848ba20c7504cb2c8052abd1fde29d03"),
common.HexToAddress("0x4863226780fe7c0356454236d3b1c8792785748d"),
common.HexToAddress("0x5d2b2e6fcbe3b11d26b525e085ff818dae332479"),
common.HexToAddress("0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"),
common.HexToAddress("0x057b56736d32b86616a10f619859c6cd6f59092a"),
common.HexToAddress("0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"),
common.HexToAddress("0x304a554a310c7e546dfe434669c62820b7d83490"),
common.HexToAddress("0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"),
common.HexToAddress("0x4deb0033bb26bc534b197e61d19e0733e5679784"),
common.HexToAddress("0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"),
common.HexToAddress("0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b"),
common.HexToAddress("0x4fa802324e929786dbda3b8820dc7834e9134a2a"),
common.HexToAddress("0x9da397b9e80755301a3b32173283a91c0ef6c87e"),
common.HexToAddress("0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"),
common.HexToAddress("0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9"),
common.HexToAddress("0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"),
common.HexToAddress("0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76"),
common.HexToAddress("0x12e626b0eebfe86a56d633b9864e389b45dcb260"),
common.HexToAddress("0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7"),
common.HexToAddress("0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"),
common.HexToAddress("0xd164b088bd9108b60d0ca3751da4bceb207b0782"),
common.HexToAddress("0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"),
common.HexToAddress("0x1cba23d343a983e9b5cfd19496b9a9701ada385f"),
common.HexToAddress("0xa82f360a8d3455c5c41366975bde739c37bfeb8a"),
common.HexToAddress("0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339"),
common.HexToAddress("0x005f5cee7a43331d5a3d3eec71305925a62f34b6"),
common.HexToAddress("0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d"),
common.HexToAddress("0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"),
common.HexToAddress("0xbc07118b9ac290e4622f5e77a0853539789effbe"),
common.HexToAddress("0x47e7aa56d6bdf3f36be34619660de61275420af8"),
common.HexToAddress("0xacd87e28b0c9d1254e868b81cba4cc20d9a32225"),
common.HexToAddress("0xadf80daec7ba8dcf15392f1ac611fff65d94f880"),
common.HexToAddress("0x5524c55fb03cf21f549444ccbecb664d0acad706"),
common.HexToAddress("0x40b803a9abce16f50f36a77ba41180eb90023925"),
common.HexToAddress("0xfe24cdd8648121a43a7c86d289be4dd2951ed49f"),
common.HexToAddress("0x17802f43a0137c506ba92291391a8a8f207f487d"),
common.HexToAddress("0x253488078a4edf4d6f42f113d1e62836a942cf1a"),
common.HexToAddress("0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"),
common.HexToAddress("0xb136707642a4ea12fb4bae820f03d2562ebff487"),
common.HexToAddress("0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"),
common.HexToAddress("0xf14c14075d6c4ed84b86798af0956deef67365b5"),
common.HexToAddress("0xca544e5c4687d109611d0f8f928b53a25af72448"),
common.HexToAddress("0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c"),
common.HexToAddress("0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"),
common.HexToAddress("0x6d87578288b6cb5549d5076a207456a1f6a63dc0"),
common.HexToAddress("0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"),
common.HexToAddress("0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6"),
common.HexToAddress("0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"),
common.HexToAddress("0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a"),
common.HexToAddress("0xd343b217de44030afaa275f54d31a9317c7f441e"),
common.HexToAddress("0x84ef4b2357079cd7a7c69fd7a37cd0609a679106"),
common.HexToAddress("0xda2fef9e4a3230988ff17df2165440f37e8b1708"),
common.HexToAddress("0xf4c64518ea10f995918a454158c6b61407ea345c"),
common.HexToAddress("0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"),
common.HexToAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413"),
common.HexToAddress("0x807640a13483f8ac783c557fcdf27be11ea4ac7a"),
}
}
// daoDrainListJSON is the JSON encoded list of accounts whose full balances will
// be moved into a refund contract at the beginning of the dao-fork block.
const daoDrainListJSON = `
[
{
"address":"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"balance":"186cc8bfaefb7be",
"extraBalance":"0",
"extraBalanceAccount":"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"
},
{
"address":"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"balance":"b14e8feab1ff435",
"extraBalance":"0",
"extraBalanceAccount":"0xecd135fa4f61a655311e86238c92adcd779555d2"
},
{
"address":"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"balance":"359d26614cb5070c77",
"extraBalance":"0",
"extraBalanceAccount":"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"
},
{
"address":"0x319f70bab6845585f412ec7724b744fec6095c85",
"balance":"6e075cd846d2cb1d42",
"extraBalance":"13d34fd41b545b81",
"extraBalanceAccount":"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"
},
{
"address":"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"balance":"b1e5593558008fd78",
"extraBalance":"0",
"extraBalanceAccount":"0x6966ab0d485353095148a2155858910e0965b6f9"
},
{
"address":"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"balance":"392eaa20d1aad59a4c",
"extraBalance":"426938826a96c9",
"extraBalanceAccount":"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"
},
{
"address":"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"balance":"2875d22b29793d4ba7",
"extraBalance":"0",
"extraBalanceAccount":"0x9c50426be05db97f5d64fc54bf89eff947f0a321"
},
{
"address":"0x200450f06520bdd6c527622a273333384d870efb",
"balance":"43c341d9f96954c049",
"extraBalance":"0",
"extraBalanceAccount":"0xbe8539bfe837b67d1282b2b1d61c3f723966f049"
},
{
"address":"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"balance":"75251057154d70fa816",
"extraBalance":"0",
"extraBalanceAccount":"0xf1385fb24aad0cd7432824085e42aff90886fef5"
},
{
"address":"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"balance":"392409769296cf67f36",
"extraBalance":"0",
"extraBalanceAccount":"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"
},
{
"address":"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"balance":"8ac72eccbf4e8083",
"extraBalance":"0",
"extraBalanceAccount":"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"
},
{
"address":"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"balance":"82289c3bb3e8c98799",
"extraBalance":"0",
"extraBalanceAccount":"0x24c4d950dfd4dd1902bbed3508144a54542bba94"
},
{
"address":"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"balance":"56bc29049ebed40fd",
"extraBalance":"0",
"extraBalanceAccount":"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"
},
{
"address":"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"balance":"56bc7d3ff79110524",
"extraBalance":"0",
"extraBalanceAccount":"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"
},
{
"address":"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"balance":"23b651bd48cbc70cc",
"extraBalance":"0",
"extraBalanceAccount":"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"
},
{
"address":"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"balance":"13ea6d4fee651dd7c9",
"extraBalance":"0",
"extraBalanceAccount":"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"
},
{
"address":"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"balance":"35ac471a3836ae7de5a",
"extraBalance":"0",
"extraBalanceAccount":"0xceaeb481747ca6c540a000c1f3641f8cef161fa7"
},
{
"address":"0xcc34673c6c40e791051898567a1222daf90be287",
"balance":"d529c0b76b7aa0",
"extraBalance":"0",
"extraBalanceAccount":"0x579a80d909f346fbfb1189493f521d7f48d52238"
},
{
"address":"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"balance":"5cd9e7df3a8e5cdd3",
"extraBalance":"0",
"extraBalanceAccount":"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"
},
{
"address":"0xac1ecab32727358dba8962a0f3b261731aad9723",
"balance":"2c8442fe35363313b93",
"extraBalance":"0",
"extraBalanceAccount":"0x4fd6ace747f06ece9c49699c7cabc62d02211f75"
},
{
"address":"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"balance":"e77583a3958130e53",
"extraBalance":"0",
"extraBalanceAccount":"0x4486a3d68fac6967006d7a517b889fd3f98c102b"
},
{
"address":"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"balance":"1f0b6ade348ca998",
"extraBalance":"0",
"extraBalanceAccount":"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"
},
{
"address":"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"balance":"61725880736659",
"extraBalance":"0",
"extraBalanceAccount":"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"
},
{
"address":"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"balance":"42948d8dc7ddbc22d",
"extraBalance":"0",
"extraBalanceAccount":"0xb9637156d330c0d605a791f1c31ba5890582fe1c"
},
{
"address":"0x6131c42fa982e56929107413a9d526fd99405560",
"balance":"7306683851d1eafbfa",
"extraBalance":"0",
"extraBalanceAccount":"0x1591fc0f688c81fbeb17f5426a162a7024d430c2"
},
{
"address":"0x542a9515200d14b68e934e9830d91645a980dd7a",
"balance":"2a8457d0d8432e21d0c",
"extraBalance":"0",
"extraBalanceAccount":"0xc4bbd073882dd2add2424cf47d35213405b01324"
},
{
"address":"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"balance":"d8d7391feaeaa8cdb",
"extraBalance":"0",
"extraBalanceAccount":"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"
},
{
"address":"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"balance":"1",
"extraBalance":"0",
"extraBalanceAccount":"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"
},
{
"address":"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"
},
{
"address":"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"balance":"6324dcb7126ecbef",
"extraBalance":"0",
"extraBalanceAccount":"0x97f43a37f595ab5dd318fb46e7a155eae057317a"
},
{
"address":"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"balance":"6c3419b0705c01cd0d",
"extraBalance":"0",
"extraBalanceAccount":"0x4863226780fe7c0356454236d3b1c8792785748d"
},
{
"address":"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"
},
{
"address":"0x057b56736d32b86616a10f619859c6cd6f59092a",
"balance":"232c025bb44b46",
"extraBalance":"0",
"extraBalanceAccount":"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"
},
{
"address":"0x304a554a310c7e546dfe434669c62820b7d83490",
"balance":"3034f5ca7d45e17df199b",
"extraBalance":"f7d15162c44e97b6e",
"extraBalanceAccount":"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"
},
{
"address":"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"balance":"4417e96ed796591e09",
"extraBalance":"0",
"extraBalanceAccount":"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"
},
{
"address":"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"balance":"d3ff7771412bbcc9",
"extraBalance":"0",
"extraBalanceAccount":"0x4fa802324e929786dbda3b8820dc7834e9134a2a"
},
{
"address":"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"balance":"32ae324c233816b4c2",
"extraBalance":"0",
"extraBalanceAccount":"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"
},
{
"address":"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"balance":"1e530695b705f037c6",
"extraBalance":"0",
"extraBalanceAccount":"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"
},
{
"address":"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"balance":"68013bad5b4b1133fc5",
"extraBalance":"0",
"extraBalanceAccount":"0x12e626b0eebfe86a56d633b9864e389b45dcb260"
},
{
"address":"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"
},
{
"address":"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"balance":"3635ce47fabaaa336e",
"extraBalance":"0",
"extraBalanceAccount":"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"
},
{
"address":"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"balance":"f3abd9906c170a",
"extraBalance":"0",
"extraBalanceAccount":"0xa82f360a8d3455c5c41366975bde739c37bfeb8a"
},
{
"address":"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"balance":"4c6679d9d9b95a4e08",
"extraBalance":"0",
"extraBalanceAccount":"0x005f5cee7a43331d5a3d3eec71305925a62f34b6"
},
{
"address":"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"balance":"40f622936475de31849",
"extraBalance":"671e1bbabded39754",
"extraBalanceAccount":"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"
},
{
"address":"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"balance":"1316ccfa4a35db5e58f",
"extraBalance":"0",
"extraBalanceAccount":"0x47e7aa56d6bdf3f36be34619660de61275420af8"
},
{
"address":"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"balance":"b3ad6bb72000bab9f",
"extraBalance":"0",
"extraBalanceAccount":"0xadf80daec7ba8dcf15392f1ac611fff65d94f880"
},
{
"address":"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"balance":"16f2da372a5c8a70967",
"extraBalance":"0",
"extraBalanceAccount":"0x40b803a9abce16f50f36a77ba41180eb90023925"
},
{
"address":"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"balance":"ea0b1bdc78f500a43",
"extraBalance":"0",
"extraBalanceAccount":"0x17802f43a0137c506ba92291391a8a8f207f487d"
},
{
"address":"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"balance":"3060e3aed135cc80",
"extraBalance":"0",
"extraBalanceAccount":"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"
},
{
"address":"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"balance":"6050bdeb3354b5c98adc3",
"extraBalance":"0",
"extraBalanceAccount":"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"
},
{
"address":"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"balance":"1d77844e94c25ba2",
"extraBalance":"0",
"extraBalanceAccount":"0xca544e5c4687d109611d0f8f928b53a25af72448"
},
{
"address":"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"balance":"2e93a72de4fc5ec0ed",
"extraBalance":"0",
"extraBalanceAccount":"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"
},
{
"address":"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"balance":"1afd340799e48c18",
"extraBalance":"0",
"extraBalanceAccount":"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"
},
{
"address":"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"balance":"14d0944eb3be947a8",
"extraBalance":"0",
"extraBalanceAccount":"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"
},
{
"address":"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"balance":"6202b236a200e365eba",
"extraBalance":"11979be9020f03ec4ec",
"extraBalanceAccount":"0xd343b217de44030afaa275f54d31a9317c7f441e"
},
{
"address":"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"balance":"7ed634ebbba531901e07",
"extraBalance":"f9c5eff28cb08720c85",
"extraBalanceAccount":"0xda2fef9e4a3230988ff17df2165440f37e8b1708"
},
{
"address":"0xf4c64518ea10f995918a454158c6b61407ea345c",
"balance":"39152e15508a96ff894a",
"extraBalance":"14041ca908bcc185c8",
"extraBalanceAccount":"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"
},
{
"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"balance":"1",
"extraBalance":"5553ebc",
"extraBalanceAccount":"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
}
]
`