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:
parent
67c47459f2
commit
37dd9086ec
|
@ -37,9 +37,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
|
|
||||||
var chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
|
|
||||||
|
|
||||||
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
||||||
|
@ -60,11 +57,12 @@ type SimulatedBackend struct {
|
||||||
|
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
// for testing purposes.
|
// for testing purposes.
|
||||||
func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend {
|
func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
|
||||||
database, _ := ethdb.NewMemDatabase()
|
database, _ := ethdb.NewMemDatabase()
|
||||||
core.WriteGenesisBlockForTesting(database, accounts...)
|
genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
|
||||||
blockchain, _ := core.NewBlockChain(database, chainConfig, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
genesis.MustCommit(database)
|
||||||
backend := &SimulatedBackend{database: database, blockchain: blockchain}
|
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()
|
backend.rollback()
|
||||||
return backend
|
return backend
|
||||||
}
|
}
|
||||||
|
@ -90,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
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.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
|
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)
|
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// 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)
|
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
return ret, gasUsed, err
|
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))
|
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() {
|
for _, tx := range b.pendingBlock.Transactions() {
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy an interaction tester contract and call a transaction on it
|
||||||
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
|
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
|
||||||
|
@ -210,7 +210,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
_, _, getter, err := DeployGetter(auth, sim)
|
_, _, getter, err := DeployGetter(auth, sim)
|
||||||
|
@ -242,7 +242,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
_, _, tupler, err := DeployTupler(auth, sim)
|
_, _, tupler, err := DeployTupler(auth, sim)
|
||||||
|
@ -284,7 +284,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy a slice tester contract and execute a n array call on it
|
||||||
_, _, slicer, err := DeploySlicer(auth, sim)
|
_, _, slicer, err := DeploySlicer(auth, sim)
|
||||||
|
@ -318,7 +318,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy a default method invoker contract and execute its default method
|
||||||
_, _, defaulter, err := DeployDefaulter(auth, sim)
|
_, _, defaulter, err := DeployDefaulter(auth, sim)
|
||||||
|
@ -351,7 +351,7 @@ var bindTests = []struct {
|
||||||
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
|
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
|
||||||
`
|
`
|
||||||
// Create a simulator and wrap a non-deployed contract
|
// Create a simulator and wrap a non-deployed contract
|
||||||
sim := backends.NewSimulatedBackend()
|
sim := backends.NewSimulatedBackend(nil)
|
||||||
|
|
||||||
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -387,7 +387,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy a funky gas pattern contract
|
||||||
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
|
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
|
||||||
|
@ -423,7 +423,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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
|
// Deploy a sender tester contract and execute a structured call on it
|
||||||
_, _, callfrom, err := DeployCallFrom(auth, sim)
|
_, _, callfrom, err := DeployCallFrom(auth, sim)
|
||||||
|
@ -458,7 +458,7 @@ func TestBindings(t *testing.T) {
|
||||||
t.Skip("go sdk not found for testing")
|
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)
|
// 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)
|
linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed check for goimports symlink bug: %v", err)
|
t.Fatalf("failed check for goimports symlink bug: %v", err)
|
||||||
|
|
|
@ -53,9 +53,8 @@ var waitDeployedTests = map[string]struct {
|
||||||
|
|
||||||
func TestWaitDeployed(t *testing.T) {
|
func TestWaitDeployed(t *testing.T) {
|
||||||
for name, test := range waitDeployedTests {
|
for name, test := range waitDeployedTests {
|
||||||
backend := backends.NewSimulatedBackend(core.GenesisAccount{
|
backend := backends.NewSimulatedBackend(core.GenesisAlloc{
|
||||||
Address: crypto.PubkeyToAddress(testKey.PublicKey),
|
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
|
||||||
Balance: big.NewInt(10000000000),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create the transaction.
|
// Create the transaction.
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -110,17 +111,22 @@ func initGenesis(ctx *cli.Context) error {
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
chaindb := utils.MakeChainDatabase(ctx, stack)
|
chaindb := utils.MakeChainDatabase(ctx, stack)
|
||||||
|
|
||||||
genesisFile, err := os.Open(genesisPath)
|
file, err := os.Open(genesisPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("failed to read genesis file: %v", err)
|
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 {
|
if err != nil {
|
||||||
utils.Fatalf("failed to write genesis block: %v", err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -786,7 +786,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
|
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
Etherbase: MakeEtherbase(ks, ctx),
|
Etherbase: MakeEtherbase(ks, ctx),
|
||||||
ChainConfig: MakeChainConfig(ctx, stack),
|
|
||||||
FastSync: ctx.GlobalBool(FastSyncFlag.Name),
|
FastSync: ctx.GlobalBool(FastSyncFlag.Name),
|
||||||
LightMode: ctx.GlobalBool(LightModeFlag.Name),
|
LightMode: ctx.GlobalBool(LightModeFlag.Name),
|
||||||
LightServ: ctx.GlobalInt(LightServFlag.Name),
|
LightServ: ctx.GlobalInt(LightServFlag.Name),
|
||||||
|
@ -822,7 +821,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
ethConf.NetworkId = 3
|
ethConf.NetworkId = 3
|
||||||
}
|
}
|
||||||
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
||||||
|
|
||||||
case ctx.GlobalBool(DevModeFlag.Name):
|
case ctx.GlobalBool(DevModeFlag.Name):
|
||||||
ethConf.Genesis = core.DevGenesisBlock()
|
ethConf.Genesis = core.DevGenesisBlock()
|
||||||
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
||||||
|
@ -884,67 +882,6 @@ func SetupNetwork(ctx *cli.Context) {
|
||||||
params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name))
|
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 {
|
func ChainDbName(ctx *cli.Context) string {
|
||||||
if ctx.GlobalBool(LightModeFlag.Name) {
|
if ctx.GlobalBool(LightModeFlag.Name) {
|
||||||
return "lightchaindata"
|
return "lightchaindata"
|
||||||
|
@ -968,26 +905,34 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
|
||||||
return chainDb
|
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.
|
// MakeChain creates a chain manager from set command line flags.
|
||||||
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
|
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
|
||||||
var err error
|
var err error
|
||||||
chainDb = MakeChainDatabase(ctx, stack)
|
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{})
|
seal := pow.PoW(pow.FakePow{})
|
||||||
if !ctx.GlobalBool(FakePoWFlag.Name) {
|
if !ctx.GlobalBool(FakePoWFlag.Name) {
|
||||||
seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
|
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 {
|
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
|
return chain, chainDb
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,17 +21,16 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/internal/jsre"
|
"github.com/ethereum/go-ethereum/internal/jsre"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -97,7 +96,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
|
||||||
t.Fatalf("failed to create node: %v", err)
|
t.Fatalf("failed to create node: %v", err)
|
||||||
}
|
}
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
ChainConfig: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
|
Genesis: core.DevGenesisBlock(),
|
||||||
Etherbase: common.HexToAddress(testAddress),
|
Etherbase: common.HexToAddress(testAddress),
|
||||||
PowTest: true,
|
PowTest: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newTestBackend() *backends.SimulatedBackend {
|
func newTestBackend() *backends.SimulatedBackend {
|
||||||
return backends.NewSimulatedBackend(
|
return backends.NewSimulatedBackend(core.GenesisAlloc{
|
||||||
core.GenesisAccount{Address: addr0, Balance: big.NewInt(1000000000)},
|
addr0: {Balance: big.NewInt(1000000000)},
|
||||||
core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000000)},
|
addr1: {Balance: big.NewInt(1000000000)},
|
||||||
core.GenesisAccount{Address: addr2, Balance: big.NewInt(1000000000)},
|
addr2: {Balance: big.NewInt(1000000000)},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
|
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestENS(t *testing.T) {
|
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)
|
transactOpts := bind.NewKeyedTransactor(key)
|
||||||
// Workaround for bug estimating gas in the call to Register
|
// Workaround for bug estimating gas in the call to Register
|
||||||
transactOpts.GasLimit = big.NewInt(1000000)
|
transactOpts.GasLimit = big.NewInt(1000000)
|
||||||
|
|
|
@ -35,11 +35,11 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
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 {
|
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
|
// Deploy a version oracle contract, commit and return
|
||||||
_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})
|
_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})
|
||||||
|
|
|
@ -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
|
// Generate a chain of b.N blocks using the supplied block
|
||||||
// generator function.
|
// generator function.
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
|
gspec := Genesis{
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
|
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.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
evmux := new(event.TypeMux)
|
evmux := new(event.TypeMux)
|
||||||
chainman, _ := NewBlockChain(db, ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, pow.FakePow{}, evmux, vm.Config{})
|
chainman, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
@ -282,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
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 {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,51 +17,36 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testChainConfig() *params.ChainConfig {
|
func testGenesis(account common.Address, balance *big.Int) *Genesis {
|
||||||
return params.TestChainConfig
|
return &Genesis{
|
||||||
//return ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{account: {Balance: balance}},
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
return blockchain.validator, blockchain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNumber(t *testing.T) {
|
func TestNumber(t *testing.T) {
|
||||||
_, chain := proc()
|
chain := newTestBlockChain()
|
||||||
|
|
||||||
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
||||||
cfg := testChainConfig()
|
header := makeHeader(chain.config, chain.Genesis(), statedb)
|
||||||
header := makeHeader(cfg, chain.Genesis(), statedb)
|
|
||||||
header.Number = big.NewInt(3)
|
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 {
|
if err != BlockNumberErr {
|
||||||
t.Errorf("expected block number error, got %q", err)
|
t.Errorf("expected block number error, got %q", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
header = makeHeader(cfg, chain.Genesis(), statedb)
|
header = makeHeader(chain.config, chain.Genesis(), statedb)
|
||||||
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 {
|
if err == BlockNumberErr {
|
||||||
t.Errorf("didn't expect block number error")
|
t.Errorf("didn't expect block number error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -36,24 +32,21 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// newTestBlockChain creates a blockchain without validation.
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
func newTestBlockChain() *BlockChain {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
gspec := &Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Difficulty: big.NewInt(1),
|
||||||
}
|
}
|
||||||
|
gspec.MustCommit(db)
|
||||||
func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain {
|
blockchain, err := NewBlockChain(db, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
var eventMux event.TypeMux
|
|
||||||
WriteTestNetGenesisBlock(db)
|
|
||||||
blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &eventMux, vm.Config{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("failed creating blockchain:", err)
|
panic(err)
|
||||||
t.FailNow()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
blockchain.SetValidator(bproc{})
|
||||||
return blockchain
|
return blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,21 +164,6 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
|
||||||
return nil
|
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) {
|
func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {
|
||||||
_, err := blockchain.InsertChain(chain)
|
_, err := blockchain.InsertChain(chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -196,12 +174,10 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLastBlock(t *testing.T) {
|
func TestLastBlock(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
bchain := newTestBlockChain()
|
||||||
|
block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
|
||||||
bchain := theBlockChain(db, t)
|
|
||||||
block := makeBlockChain(bchain.CurrentBlock(), 1, db, 0)[0]
|
|
||||||
bchain.insert(block)
|
bchain.insert(block)
|
||||||
if block.Hash() != GetHeadBlockHash(db) {
|
if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
|
||||||
t.Errorf("Write/Get HeadBlockHash failed")
|
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{}
|
type bproc struct{}
|
||||||
|
|
||||||
func (bproc) ValidateBlock(*types.Block) error { return nil }
|
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,
|
UncleHash: types.EmptyUncleHash,
|
||||||
TxHash: types.EmptyRootHash,
|
TxHash: types.EmptyRootHash,
|
||||||
ReceiptHash: types.EmptyRootHash,
|
ReceiptHash: types.EmptyRootHash,
|
||||||
|
Time: big.NewInt(int64(i) + 1),
|
||||||
}
|
}
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
header.ParentHash = genesis.Hash()
|
header.ParentHash = genesis.Hash()
|
||||||
|
@ -464,29 +359,6 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
|
||||||
return chain
|
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
|
// Tests that reorganising a long difficult chain after a short easy one
|
||||||
// overwrites the canonical numbers and links in the database.
|
// overwrites the canonical numbers and links in the database.
|
||||||
func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
|
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) {
|
func testReorg(t *testing.T, first, second []int, td int64, full bool) {
|
||||||
// Create a pristine block chain
|
bc := newTestBlockChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Insert an easy and a difficult chain afterwards
|
// Insert an easy and a difficult chain afterwards
|
||||||
if full {
|
if full {
|
||||||
bc.InsertChain(makeBlockChainWithDiff(genesis, first, 11))
|
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11))
|
||||||
bc.InsertChain(makeBlockChainWithDiff(genesis, second, 22))
|
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22))
|
||||||
} else {
|
} else {
|
||||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
|
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
|
||||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
|
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
|
||||||
}
|
}
|
||||||
// Check that the chain is valid number and link wise
|
// Check that the chain is valid number and link wise
|
||||||
if full {
|
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
|
// 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 full {
|
||||||
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {
|
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {
|
||||||
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
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 TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
|
||||||
|
|
||||||
func testBadHashes(t *testing.T, full bool) {
|
func testBadHashes(t *testing.T, full bool) {
|
||||||
// Create a pristine block chain
|
bc := newTestBlockChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Create a chain, ban a hash and try to import
|
// Create a chain, ban a hash and try to import
|
||||||
var err error
|
var err error
|
||||||
if full {
|
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
|
BadHashes[blocks[2].Header().Hash()] = true
|
||||||
_, err = bc.InsertChain(blocks)
|
_, err = bc.InsertChain(blocks)
|
||||||
} else {
|
} else {
|
||||||
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
|
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
|
||||||
BadHashes[headers[2].Hash()] = true
|
BadHashes[headers[2].Hash()] = true
|
||||||
_, err = bc.InsertHeaderChain(headers, 1)
|
_, 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 TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
|
||||||
|
|
||||||
func testReorgBadHashes(t *testing.T, full bool) {
|
func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
// Create a pristine block chain
|
bc := newTestBlockChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Create a chain, import and ban afterwards
|
// Create a chain, import and ban afterwards
|
||||||
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
|
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
|
||||||
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
|
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
|
||||||
|
|
||||||
if full {
|
if full {
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
|
@ -608,8 +471,9 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
BadHashes[headers[3].Hash()] = true
|
BadHashes[headers[3].Hash()] = true
|
||||||
defer func() { delete(BadHashes, headers[3].Hash()) }()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
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()
|
failHash = headers[failAt].Hash()
|
||||||
|
|
||||||
blockchain.pow = failPow{failNum}
|
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)
|
failRes, err = blockchain.InsertHeaderChain(headers, 1)
|
||||||
}
|
}
|
||||||
|
@ -705,10 +569,11 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
genesis = GenesisBlockForTesting(gendb, address, funds)
|
gspec = testGenesis(address, funds)
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
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})
|
block.SetCoinbase(common.Address{0x00})
|
||||||
|
|
||||||
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
// 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
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb, _ := ethdb.NewMemDatabase()
|
archiveDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
|
gspec.MustCommit(archiveDb)
|
||||||
|
archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb, _ := ethdb.NewMemDatabase()
|
fastDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
@ -788,10 +653,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
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)
|
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
|
// Configure a subchain to roll back
|
||||||
remove := []common.Hash{}
|
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
|
// Import the chain as an archive node and ensure all pointers are updated
|
||||||
archiveDb, _ := ethdb.NewMemDatabase()
|
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 {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
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
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb, _ := ethdb.NewMemDatabase()
|
fastDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range 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
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb, _ := ethdb.NewMemDatabase()
|
lightDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds})
|
gspec.MustCommit(lightDb)
|
||||||
light, _ := NewBlockChain(lightDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
light, _ := NewBlockChain(lightDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
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.
|
// Tests that chain reorganisations handle transaction removals and reinsertions.
|
||||||
func TestChainTxReorgs(t *testing.T) {
|
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 (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
@ -868,13 +731,19 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
gspec = &Genesis{
|
||||||
)
|
Config: params.TestChainConfig,
|
||||||
genesis := WriteGenesisBlockForTesting(db,
|
GasLimit: 3141592,
|
||||||
GenesisAccount{addr1, big.NewInt(1000000)},
|
Alloc: GenesisAlloc{
|
||||||
GenesisAccount{addr2, big.NewInt(1000000)},
|
addr1: {Balance: big.NewInt(1000000)},
|
||||||
GenesisAccount{addr3, 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:
|
// Create two transactions shared between the chains:
|
||||||
// - postponed: transaction included at a later block in the forked chain
|
// - postponed: transaction included at a later block in the forked chain
|
||||||
// - swapped: transaction included at the same block number 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
|
// - futureAdd: transaction added after the reorg has already finished
|
||||||
var pastAdd, freshAdd, futureAdd *types.Transaction
|
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 {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
|
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.
|
// Import the chain. This runs all block validation rules.
|
||||||
evmux := &event.TypeMux{}
|
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 {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// overwrite the old chain
|
// 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 {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
|
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
|
||||||
|
@ -969,8 +838,6 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogReorgs(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 (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
@ -978,14 +845,13 @@ func TestLogReorgs(t *testing.T) {
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
// this code generates a log
|
// this code generates a log
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
||||||
)
|
genesis = gspec.MustCommit(db)
|
||||||
genesis := WriteGenesisBlockForTesting(db,
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
GenesisAccount{addr1, big.NewInt(10000000000000)},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
evmux := &event.TypeMux{}
|
var evmux event.TypeMux
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &evmux, vm.Config{})
|
||||||
|
|
||||||
subs := evmux.Subscribe(RemovedLogsEvent{})
|
subs := evmux.Subscribe(RemovedLogsEvent{})
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
||||||
|
@ -1017,19 +883,20 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
|
gspec = testGenesis(addr1, big.NewInt(10000000000000))
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
genesis = gspec.MustCommit(db)
|
||||||
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
)
|
)
|
||||||
|
|
||||||
evmux := &event.TypeMux{}
|
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 {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert chain: %v", err)
|
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)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
|
||||||
if i == 2 {
|
if i == 2 {
|
||||||
gen.OffsetTime(-1)
|
gen.OffsetTime(-1)
|
||||||
|
@ -1092,28 +959,21 @@ done:
|
||||||
|
|
||||||
// Tests if the canonical block can be fetched from the database during chain insertion.
|
// Tests if the canonical block can be fetched from the database during chain insertion.
|
||||||
func TestCanonicalBlockRetrieval(t *testing.T) {
|
func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
var (
|
bc := newTestBlockChain()
|
||||||
db, _ = ethdb.NewMemDatabase()
|
chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
|
||||||
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) {})
|
|
||||||
|
|
||||||
for i := range chain {
|
for i := range chain {
|
||||||
go func(block *types.Block) {
|
go func(block *types.Block) {
|
||||||
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
||||||
for {
|
for {
|
||||||
ch := GetCanonicalHash(db, block.NumberU64())
|
ch := GetCanonicalHash(bc.chainDb, block.NumberU64())
|
||||||
if ch == (common.Hash{}) {
|
if ch == (common.Hash{}) {
|
||||||
continue // busy wait for canonical hash to be written
|
continue // busy wait for canonical hash to be written
|
||||||
}
|
}
|
||||||
if ch != block.Hash() {
|
if ch != block.Hash() {
|
||||||
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
|
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 {
|
if fb == nil {
|
||||||
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
|
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])
|
}(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)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
deleteAddr = common.Address{1}
|
deleteAddr = common.Address{1}
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}, GenesisAccount{deleteAddr, new(big.Int)})
|
gspec = &Genesis{
|
||||||
config = ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
Config: ¶ms.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
|
mux event.TypeMux
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
|
||||||
blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
|
@ -1164,7 +1027,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
||||||
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
|
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1176,7 +1039,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
||||||
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
|
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1204,7 +1067,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate an invalid chain id transaction
|
// generate an invalid chain id transaction
|
||||||
config = ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
config := ¶ms.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) {
|
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
|
@ -1236,22 +1099,24 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
theAddr = common.Address{1}
|
theAddr = common.Address{1}
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds})
|
gspec = &Genesis{
|
||||||
config = ¶ms.ChainConfig{
|
Config: ¶ms.ChainConfig{
|
||||||
ChainId: big.NewInt(1),
|
ChainId: big.NewInt(1),
|
||||||
HomesteadBlock: new(big.Int),
|
HomesteadBlock: new(big.Int),
|
||||||
EIP155Block: new(big.Int),
|
EIP155Block: new(big.Int),
|
||||||
EIP158Block: big.NewInt(2),
|
EIP158Block: big.NewInt(2),
|
||||||
|
},
|
||||||
|
Alloc: GenesisAlloc{address: {Balance: funds}},
|
||||||
}
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
mux event.TypeMux
|
mux event.TypeMux
|
||||||
|
blockchain, _ = NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
|
||||||
blockchain, _ = NewBlockChain(db, 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 (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
signer = types.NewEIP155Signer(config.ChainId)
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
)
|
)
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -1279,7 +1144,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if blockchain.stateCache.Exist(theAddr) {
|
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
|
// account musn't be created post eip 161
|
||||||
|
@ -1287,6 +1152,6 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if blockchain.stateCache.Exist(theAddr) {
|
if blockchain.stateCache.Exist(theAddr) {
|
||||||
t.Error("account should not expect")
|
t.Error("account should not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,19 +30,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"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 ¶ms.ChainConfig{
|
|
||||||
HomesteadBlock: big.NewInt(0),
|
|
||||||
DAOForkBlock: nil,
|
|
||||||
DAOForkSupport: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// So we can deterministically seed different blockchains
|
// So we can deterministically seed different blockchains
|
||||||
var (
|
var (
|
||||||
canonicalSeed = 1
|
canonicalSeed = 1
|
||||||
|
@ -154,7 +141,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
||||||
panic("block time out of range")
|
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
|
// 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
|
// values. Inserting them into BlockChain requires use of FakePow or
|
||||||
// a similar non-validating proof of work implementation.
|
// 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) {
|
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)
|
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||||
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
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}
|
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
|
// Mutate the state and block according to any hard-fork specs
|
||||||
if config == nil {
|
|
||||||
config = MakeChainConfig()
|
|
||||||
}
|
|
||||||
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
||||||
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
|
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
|
||||||
if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
|
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())),
|
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
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),
|
GasLimit: CalcGasLimit(parent),
|
||||||
GasUsed: new(big.Int),
|
GasUsed: new(big.Int),
|
||||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
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
|
// chain. Depending on the full flag, if creates either a full block chain or a
|
||||||
// header only chain.
|
// header only chain.
|
||||||
func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
|
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
|
// 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
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
|
|
@ -30,9 +30,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleGenerateChain() {
|
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 (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
@ -41,19 +38,20 @@ func ExampleGenerateChain() {
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
signer = types.HomesteadSigner{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
chainConfig := ¶ms.ChainConfig{
|
|
||||||
HomesteadBlock: new(big.Int),
|
|
||||||
}
|
|
||||||
// Ensure that key1 has some funds in the genesis block.
|
// Ensure that key1 has some funds in the genesis block.
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
|
gspec := &Genesis{
|
||||||
|
Config: ¶ms.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
|
// This call generates a chain of 5 blocks. The function runs for
|
||||||
// each block and adds different features to gen based on the
|
// each block and adds different features to gen based on the
|
||||||
// block index.
|
// 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 {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, addr1 sends addr2 some ether.
|
// In block 1, addr1 sends addr2 some ether.
|
||||||
|
@ -83,7 +81,7 @@ func ExampleGenerateChain() {
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
evmux := &event.TypeMux{}
|
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 {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -67,7 +67,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move every DAO account and extra-balance account funds into the refund contract
|
// 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.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
|
||||||
statedb.SetBalance(addr, new(big.Int))
|
statedb.SetBalance(addr, new(big.Int))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,17 +34,18 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
|
|
||||||
// Generate a common prefix for both pro-forkers and non-forkers
|
// Generate a common prefix for both pro-forkers and non-forkers
|
||||||
db, _ := ethdb.NewMemDatabase()
|
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) {})
|
prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
// Create the concurrent, conflicting two nodes
|
// Create the concurrent, conflicting two nodes
|
||||||
proDb, _ := ethdb.NewMemDatabase()
|
proDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(proDb)
|
gspec.MustCommit(proDb)
|
||||||
proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
|
proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
|
||||||
proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
conDb, _ := ethdb.NewMemDatabase()
|
conDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(conDb)
|
gspec.MustCommit(conDb)
|
||||||
conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
|
conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
|
||||||
conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
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++ {
|
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
|
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
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
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
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
|
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
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
||||||
|
|
|
@ -562,7 +562,7 @@ func TestMipmapChain(t *testing.T) {
|
||||||
)
|
)
|
||||||
defer db.Close()
|
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) {
|
chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
390
core/genesis.go
390
core/genesis.go
|
@ -17,230 +17,286 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/bzip2"
|
"errors"
|
||||||
"compress/gzip"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteGenesisBlock writes the genesis block to the database as block number 0
|
//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
||||||
func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) {
|
//go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
|
||||||
contents, err := ioutil.ReadAll(reader)
|
|
||||||
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
var genesis struct {
|
// Check config compatibility and write the config. Compatibility errors
|
||||||
ChainConfig *params.ChainConfig `json:"config"`
|
// are returned to the caller unless we're already at block zero.
|
||||||
Nonce string
|
height := GetBlockNumber(db, GetHeadHeaderHash(db))
|
||||||
Timestamp string
|
if height == missingNumber {
|
||||||
ParentHash string
|
return newcfg, stored, fmt.Errorf("missing block number for head header hash")
|
||||||
ExtraData string
|
}
|
||||||
GasLimit string
|
compatErr := storedcfg.CheckCompatible(newcfg, height)
|
||||||
Difficulty string
|
if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
|
||||||
Mixhash string
|
return newcfg, stored, compatErr
|
||||||
Coinbase string
|
}
|
||||||
Alloc map[string]struct {
|
return newcfg, stored, WriteChainConfig(db, stored, newcfg)
|
||||||
Code string
|
}
|
||||||
Storage map[string]string
|
|
||||||
Balance string
|
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
|
||||||
Nonce string
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(contents, &genesis); err != nil {
|
// ToBlock creates the block and state of a genesis specification.
|
||||||
return nil, err
|
func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) {
|
||||||
}
|
db, _ := ethdb.NewMemDatabase()
|
||||||
if genesis.ChainConfig == nil {
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
genesis.ChainConfig = params.AllProtocolChanges
|
for addr, account := range g.Alloc {
|
||||||
}
|
statedb.AddBalance(addr, account.Balance)
|
||||||
|
statedb.SetCode(addr, account.Code)
|
||||||
// creating with empty hash always works
|
statedb.SetNonce(addr, account.Nonce)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
address := common.HexToAddress(addr)
|
|
||||||
statedb.AddBalance(address, balance)
|
|
||||||
statedb.SetCode(address, common.FromHex(account.Code))
|
|
||||||
statedb.SetNonce(address, nonce)
|
|
||||||
for key, value := range account.Storage {
|
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)
|
root := statedb.IntermediateRoot(false)
|
||||||
|
head := &types.Header{
|
||||||
difficulty, ok := math.ParseBig256(genesis.Difficulty)
|
Nonce: types.EncodeNonce(g.Nonce),
|
||||||
if !ok {
|
Time: new(big.Int).SetUint64(g.Timestamp),
|
||||||
return nil, fmt.Errorf("invalid difficulty: %q", genesis.Difficulty)
|
ParentHash: g.ParentHash,
|
||||||
}
|
Extra: g.ExtraData,
|
||||||
gaslimit, ok := math.ParseUint64(genesis.GasLimit)
|
GasLimit: new(big.Int).SetUint64(g.GasLimit),
|
||||||
if !ok {
|
Difficulty: g.Difficulty,
|
||||||
return nil, fmt.Errorf("invalid gas limit: %q", genesis.GasLimit)
|
MixDigest: g.Mixhash,
|
||||||
}
|
Coinbase: g.Coinbase,
|
||||||
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: root,
|
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)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteBlock(chainDb, block); err != nil {
|
if err := WriteBlock(db, block); err != nil {
|
||||||
return nil, err
|
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
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil {
|
if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
|
||||||
return nil, err
|
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 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.
|
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||||
// The state trie of the block is written to db. the passed db needs to contain a state root
|
// The block is committed as the canonical head block.
|
||||||
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
|
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
block, err := g.Commit(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))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteDefaultGenesisBlock assembles the official Ethereum genesis block and
|
// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
|
||||||
// writes it - along with all associated state - into a chain database.
|
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
|
||||||
func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
|
||||||
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
|
return g.MustCommit(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTestNetGenesisBlock assembles the test network genesis block and
|
// DefaultGenesisBlock returns the Ethereum main net genesis block.
|
||||||
// writes it - along with all associated state - into a chain database.
|
func DefaultGenesisBlock() *Genesis {
|
||||||
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
return &Genesis{
|
||||||
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
|
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
|
// DefaultTestnetGenesisBlock returns the Ropsten network genesis block.
|
||||||
// genesis block.
|
func DefaultTestnetGenesisBlock() *Genesis {
|
||||||
func DefaultGenesisBlock() string {
|
return &Genesis{
|
||||||
reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock)))
|
Config: params.TestnetChainConfig,
|
||||||
if err != nil {
|
Nonce: 66,
|
||||||
panic(fmt.Sprintf("failed to access default genesis: %v", err))
|
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
|
// DevGenesisBlock returns the 'geth --dev' genesis block.
|
||||||
// test network genesis block.
|
func DevGenesisBlock() *Genesis {
|
||||||
func DefaultTestnetGenesisBlock() string {
|
return &Genesis{
|
||||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
|
Config: params.AllProtocolChanges,
|
||||||
blob, err := ioutil.ReadAll(reader)
|
Nonce: 42,
|
||||||
if err != nil {
|
GasLimit: 4712388,
|
||||||
panic(fmt.Sprintf("failed to load default genesis: %v", err))
|
Difficulty: big.NewInt(131072),
|
||||||
|
Alloc: decodePrealloc(devAllocData),
|
||||||
}
|
}
|
||||||
return string(blob)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DevGenesisBlock assembles a JSON string representing a local dev genesis block.
|
func decodePrealloc(data string) GenesisAlloc {
|
||||||
func DevGenesisBlock() string {
|
var p []struct{ Addr, Balance *big.Int }
|
||||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
|
if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil {
|
||||||
blob, err := ioutil.ReadAll(reader)
|
panic(err)
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to load dev genesis: %v", err))
|
|
||||||
}
|
}
|
||||||
return string(blob)
|
ga := make(GenesisAlloc, len(p))
|
||||||
|
for _, account := range p {
|
||||||
|
ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance}
|
||||||
|
}
|
||||||
|
return ga
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)},
|
||||||
|
Alloc: GenesisAlloc{
|
||||||
|
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
oldcustomg = customg
|
||||||
|
)
|
||||||
|
oldcustomg.Config = ¶ms.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: ¶ms.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -97,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
|
||||||
|
|
||||||
hc.genesisHeader = hc.GetHeaderByNumber(0)
|
hc.genesisHeader = hc.GetHeaderByNumber(0)
|
||||||
if hc.genesisHeader == nil {
|
if hc.genesisHeader == nil {
|
||||||
genesisBlock, err := WriteDefaultGenesisBlock(chainDb)
|
return nil, ErrNoGenesis
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
log.Warn("Wrote default Ethereum genesis block")
|
|
||||||
hc.genesisHeader = genesisBlock.Header()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.currentHeader = hc.genesisHeader
|
hc.currentHeader = hc.genesisHeader
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
|
|
||||||
key, _ := crypto.GenerateKey()
|
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()
|
newPool.resetState()
|
||||||
|
|
||||||
return newPool, key
|
return newPool, key
|
||||||
|
@ -91,7 +91,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
|
||||||
|
|
||||||
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
|
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
|
||||||
|
|
||||||
txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc)
|
txpool := NewTxPool(params.TestChainConfig, mux, stateFunc, gasLimitFunc)
|
||||||
txpool.resetState()
|
txpool.resetState()
|
||||||
|
|
||||||
nonce := txpool.State().GetNonce(address)
|
nonce := txpool.State().GetNonce(address)
|
||||||
|
@ -564,7 +564,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
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()
|
pool.resetState()
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
// Create a number of test accounts and fund them
|
||||||
|
@ -713,7 +713,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
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()
|
pool.resetState()
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
// Create a number of test accounts and fund them
|
||||||
|
@ -759,7 +759,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
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()
|
pool.resetState()
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
// Create a number of test accounts and fund them
|
||||||
|
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,19 +118,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice
|
||||||
return &Transaction{data: d}
|
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)
|
// ChainId returns which chain id this transaction was signed for (if at all)
|
||||||
func (tx *Transaction) ChainId() *big.Int {
|
func (tx *Transaction) ChainId() *big.Int {
|
||||||
return deriveChainId(tx.data.V)
|
return deriveChainId(tx.data.V)
|
||||||
|
|
|
@ -18,11 +18,9 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -60,10 +58,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
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
|
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
|
FastSync bool // Enables the state download based fast synchronisation algorithm
|
||||||
LightMode bool // Running in light client mode
|
LightMode bool // Running in light client mode
|
||||||
LightServ int // Maximum percentage of time allowed for serving LES requests
|
LightServ int // Maximum percentage of time allowed for serving LES requests
|
||||||
|
@ -100,9 +100,6 @@ type Config struct {
|
||||||
GpobaseCorrectionFactor int
|
GpobaseCorrectionFactor int
|
||||||
|
|
||||||
EnablePreimageRecording bool
|
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 {
|
type LesServer interface {
|
||||||
|
@ -155,11 +152,15 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stopDbUpgrade := upgradeSequentialKeys(chainDb)
|
stopDbUpgrade := upgradeSequentialKeys(chainDb)
|
||||||
if err := SetupGenesisBlock(&chainDb, config); err != nil {
|
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
|
||||||
return nil, err
|
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
||||||
|
return nil, genesisErr
|
||||||
}
|
}
|
||||||
|
log.Info("Initialised chain configuration", "config", chainConfig)
|
||||||
|
|
||||||
eth := &Ethereum{
|
eth := &Ethereum{
|
||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
|
chainConfig: chainConfig,
|
||||||
eventMux: ctx.EventMux,
|
eventMux: ctx.EventMux,
|
||||||
accountManager: ctx.AccountManager,
|
accountManager: ctx.AccountManager,
|
||||||
pow: CreatePoW(ctx, config),
|
pow: CreatePoW(ctx, config),
|
||||||
|
@ -184,33 +185,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
|
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the genesis block or write a new one if no genesis
|
vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
|
||||||
// block is prenent in the database.
|
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux, vmConfig)
|
||||||
genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0), 0)
|
|
||||||
if genesis == nil {
|
|
||||||
genesis, err = core.WriteDefaultGenesisBlock(chainDb)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Warn("Wrote default Ethereum genesis block")
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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})
|
|
||||||
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
|
|
||||||
}
|
|
||||||
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
|
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
|
||||||
eth.txPool = newPool
|
eth.txPool = newPool
|
||||||
|
|
||||||
|
@ -255,29 +241,6 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
|
||||||
return db, err
|
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
|
// CreatePoW creates the required type of PoW instance for an Ethereum service
|
||||||
func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
|
func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
func TestMipmapUpgrade(t *testing.T) {
|
func TestMipmapUpgrade(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
addr := common.BytesToAddress([]byte("jeff"))
|
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) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
|
|
|
@ -76,8 +76,7 @@ func TestBlockSubscription(t *testing.T) {
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
backend = &testBackend{mux, db}
|
backend = &testBackend{mux, db}
|
||||||
api = NewPublicFilterAPI(backend, false)
|
api = NewPublicFilterAPI(backend, false)
|
||||||
|
genesis = new(core.Genesis).MustCommit(db)
|
||||||
genesis = core.WriteGenesisBlockForTesting(db)
|
|
||||||
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
|
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
|
||||||
chainEvents = []core.ChainEvent{}
|
chainEvents = []core.ChainEvent{}
|
||||||
)
|
)
|
||||||
|
|
|
@ -60,7 +60,7 @@ func BenchmarkMipmaps(b *testing.B) {
|
||||||
)
|
)
|
||||||
defer db.Close()
|
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) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
|
@ -112,7 +112,7 @@ func BenchmarkMipmaps(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
logs, _ := filter.Find(context.Background())
|
logs, _ := filter.Find(context.Background())
|
||||||
if len(logs) != 4 {
|
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()
|
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) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
|
|
|
@ -315,12 +315,12 @@ func testGetNodeData(t *testing.T, protocol int) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, the test bank sends account #1 some ether.
|
// 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)
|
block.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, the test bank sends some more ether to account #1.
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
// acc1Addr passes it on to account #2.
|
// 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)
|
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
|
@ -372,7 +372,7 @@ func testGetNodeData(t *testing.T, protocol int) {
|
||||||
for i := 0; i < len(data); i++ {
|
for i := 0; i < len(data); i++ {
|
||||||
statedb.Put(hashes[i].Bytes(), 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++ {
|
for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
|
||||||
trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb)
|
trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb)
|
||||||
|
|
||||||
|
@ -407,12 +407,12 @@ func testGetReceipt(t *testing.T, protocol int) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, the test bank sends account #1 some ether.
|
// 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)
|
block.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, the test bank sends some more ether to account #1.
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
// acc1Addr passes it on to account #2.
|
// 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)
|
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
|
@ -471,8 +471,9 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
pow = new(pow.FakePow)
|
pow = new(pow.FakePow)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.WriteGenesisBlockForTesting(db)
|
|
||||||
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
config = ¶ms.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{})
|
blockchain, _ = core.NewBlockChain(db, config, pow, evmux, vm.Config{})
|
||||||
)
|
)
|
||||||
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
|
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
|
||||||
|
|
|
@ -42,10 +42,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
testBank = core.GenesisAccount{
|
testBank = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
||||||
Address: crypto.PubkeyToAddress(testBankKey.PublicKey),
|
|
||||||
Balance: big.NewInt(1000000),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// newTestProtocolManager creates a new protocol manager for testing purposes,
|
// newTestProtocolManager creates a new protocol manager for testing purposes,
|
||||||
|
@ -56,16 +53,19 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
pow = new(pow.FakePow)
|
pow = new(pow.FakePow)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.WriteGenesisBlockForTesting(db, testBank)
|
gspec = &core.Genesis{
|
||||||
chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
|
Config: params.TestChainConfig,
|
||||||
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
|
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 {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
panic(err)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package les
|
package les
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -74,15 +73,19 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := eth.SetupGenesisBlock(&chainDb, config); err != nil {
|
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
|
||||||
return nil, err
|
if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
|
||||||
|
return nil, genesisErr
|
||||||
}
|
}
|
||||||
|
log.Info("Initialised chain configuration", "config", chainConfig)
|
||||||
|
|
||||||
odr := NewLesOdr(chainDb)
|
odr := NewLesOdr(chainDb)
|
||||||
relay := NewLesTxRelay()
|
relay := NewLesTxRelay()
|
||||||
eth := &LightEthereum{
|
eth := &LightEthereum{
|
||||||
odr: odr,
|
odr: odr,
|
||||||
relay: relay,
|
relay: relay,
|
||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
|
chainConfig: chainConfig,
|
||||||
eventMux: ctx.EventMux,
|
eventMux: ctx.EventMux,
|
||||||
accountManager: ctx.AccountManager,
|
accountManager: ctx.AccountManager,
|
||||||
pow: eth.CreatePoW(ctx, config),
|
pow: eth.CreatePoW(ctx, config),
|
||||||
|
@ -91,17 +94,16 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
||||||
solcPath: config.SolcPath,
|
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)
|
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
|
||||||
if err != nil {
|
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
|
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)
|
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 {
|
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil {
|
||||||
|
|
|
@ -137,25 +137,28 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
pow = new(pow.FakePow)
|
pow = new(pow.FakePow)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
gspec = core.Genesis{
|
||||||
chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
|
||||||
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
odr *LesOdr
|
odr *LesOdr
|
||||||
chain BlockChain
|
chain BlockChain
|
||||||
)
|
)
|
||||||
|
|
||||||
if lightSync {
|
if lightSync {
|
||||||
odr = NewLesOdr(db)
|
odr = NewLesOdr(db)
|
||||||
chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
|
chain, _ = light.NewLightChain(odr, gspec.Config, pow, evmux)
|
||||||
} else {
|
} else {
|
||||||
blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
|
blockchain, _ := core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
|
||||||
gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
|
gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
chain = blockchain
|
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 {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ type LesServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,11 +96,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
|
||||||
|
|
||||||
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
|
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
|
||||||
if bc.genesisBlock == nil {
|
if bc.genesisBlock == nil {
|
||||||
bc.genesisBlock, err = core.WriteDefaultGenesisBlock(odr.Database())
|
return nil, core.ErrNoGenesis
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
log.Warn("Wrote default ethereum genesis block")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
|
if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -30,7 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// So we can deterministically seed different blockchains
|
// 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
|
// chain. Depending on the full flag, if creates either a full block chain or a
|
||||||
// header only chain.
|
// header only chain.
|
||||||
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
||||||
// Create te new chain database
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
evmux := &event.TypeMux{}
|
gspec := core.Genesis{Config: testChainConfig()}
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
// Initialize a fresh chain with only a genesis block
|
blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
|
||||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
|
||||||
|
|
||||||
blockchain, _ := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, evmux)
|
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
@ -77,21 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
||||||
return db, blockchain, err
|
return db, blockchain, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
// newTestLightChain creates a LightChain that doesn't validate anything.
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
func newTestLightChain() *LightChain {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
gspec := &core.Genesis{
|
||||||
|
Difficulty: big.NewInt(1),
|
||||||
|
Config: testChainConfig(),
|
||||||
}
|
}
|
||||||
|
gspec.MustCommit(db)
|
||||||
func theLightChain(db ethdb.Database, t *testing.T) *LightChain {
|
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
|
||||||
var eventMux event.TypeMux
|
|
||||||
core.WriteTestNetGenesisBlock(db)
|
|
||||||
LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.NewTestEthash(), &eventMux)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("failed creating LightChain:", err)
|
panic(err)
|
||||||
t.FailNow()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
lc.SetValidator(bproc{})
|
||||||
return LightChain
|
return lc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test fork of length N starting from block i
|
// 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
|
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
|
// Tests that reorganizing a long difficult chain after a short easy one
|
||||||
// overwrites the canonical numbers and links in the database.
|
// overwrites the canonical numbers and links in the database.
|
||||||
func TestReorgLongHeaders(t *testing.T) {
|
func TestReorgLongHeaders(t *testing.T) {
|
||||||
|
@ -329,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testReorg(t *testing.T, first, second []int, td int64) {
|
func testReorg(t *testing.T, first, second []int, td int64) {
|
||||||
// Create a pristine block chain
|
bc := newTestLightChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Insert an easy and a difficult chain afterwards
|
// Insert an easy and a difficult chain afterwards
|
||||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
|
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
|
||||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
|
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
|
||||||
// Check that the chain is valid number and link wise
|
// Check that the chain is valid number and link wise
|
||||||
prev := bc.CurrentHeader()
|
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) {
|
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
|
// 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 {
|
if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {
|
||||||
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
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.
|
// Tests that the insertion functions detect banned hashes.
|
||||||
func TestBadHeaderHashes(t *testing.T) {
|
func TestBadHeaderHashes(t *testing.T) {
|
||||||
// Create a pristine block chain
|
bc := newTestLightChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Create a chain, ban a hash and try to import
|
// Create a chain, ban a hash and try to import
|
||||||
var err error
|
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
|
core.BadHashes[headers[2].Hash()] = true
|
||||||
_, err = bc.InsertHeaderChain(headers, 1)
|
_, err = bc.InsertHeaderChain(headers, 1)
|
||||||
if !core.IsBadHashError(err) {
|
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
|
// Tests that bad hashes are detected on boot, and the chan rolled back to a
|
||||||
// good state prior to the bad hash.
|
// good state prior to the bad hash.
|
||||||
func TestReorgBadHeaderHashes(t *testing.T) {
|
func TestReorgBadHeaderHashes(t *testing.T) {
|
||||||
// Create a pristine block chain
|
bc := newTestLightChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Create a chain, import and ban aferwards
|
// 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 {
|
if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to import headers: %v", err)
|
t.Fatalf("failed to import headers: %v", err)
|
||||||
|
@ -387,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) {
|
||||||
}
|
}
|
||||||
core.BadHashes[headers[3].Hash()] = true
|
core.BadHashes[headers[3].Hash()] = true
|
||||||
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,9 +251,10 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
|
||||||
pow = new(pow.FakePow)
|
pow = new(pow.FakePow)
|
||||||
sdb, _ = ethdb.NewMemDatabase()
|
sdb, _ = ethdb.NewMemDatabase()
|
||||||
ldb, _ = 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
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
|
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
|
||||||
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
||||||
|
|
|
@ -86,9 +86,10 @@ func TestTxPool(t *testing.T) {
|
||||||
pow = new(pow.FakePow)
|
pow = new(pow.FakePow)
|
||||||
sdb, _ = ethdb.NewMemDatabase()
|
sdb, _ = ethdb.NewMemDatabase()
|
||||||
ldb, _ = 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
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
|
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
|
||||||
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
||||||
|
|
|
@ -20,10 +20,12 @@
|
||||||
package geth
|
package geth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/ethstats"
|
"github.com/ethereum/go-ethereum/ethstats"
|
||||||
|
@ -92,6 +94,18 @@ func NewNodeConfig() *NodeConfig {
|
||||||
return &config
|
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.
|
// Node represents a Geth Ethereum node instance.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
node *node.Node
|
node *node.Node
|
||||||
|
@ -127,10 +141,19 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Register the Ethereum protocol if requested
|
|
||||||
if config.EthereumEnabled {
|
var genesis *core.Genesis
|
||||||
ethConf := ð.Config{
|
if config.EthereumGenesis != "" {
|
||||||
ChainConfig: ¶ms.ChainConfig{
|
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 = ¶ms.ChainConfig{
|
||||||
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
|
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
|
||||||
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
|
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
|
||||||
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
|
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
|
||||||
|
@ -139,8 +162,13 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
|
||||||
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
|
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
|
||||||
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
|
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
|
||||||
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
|
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
|
||||||
},
|
}
|
||||||
Genesis: config.EthereumGenesis,
|
}
|
||||||
|
|
||||||
|
// Register the Ethereum protocol if requested
|
||||||
|
if config.EthereumEnabled {
|
||||||
|
ethConf := ð.Config{
|
||||||
|
Genesis: genesis,
|
||||||
LightMode: true,
|
LightMode: true,
|
||||||
DatabaseCache: config.EthereumDatabaseCache,
|
DatabaseCache: config.EthereumDatabaseCache,
|
||||||
NetworkId: config.EthereumNetworkID,
|
NetworkId: config.EthereumNetworkID,
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
package geth
|
package geth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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.
|
// TestnetGenesis returns the JSON spec to use for the Ethereum test network.
|
||||||
func TestnetGenesis() string {
|
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.
|
// ChainConfig is the core config which determines the blockchain settings.
|
||||||
|
|
154
params/config.go
154
params/config.go
|
@ -23,8 +23,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// MainnetChainConfig is the chain parameters to run a node on the main network.
|
// MainnetChainConfig is the chain parameters to run a node on the main network.
|
||||||
var MainnetChainConfig = &ChainConfig{
|
MainnetChainConfig = &ChainConfig{
|
||||||
ChainId: MainNetChainID,
|
ChainId: MainNetChainID,
|
||||||
HomesteadBlock: MainNetHomesteadBlock,
|
HomesteadBlock: MainNetHomesteadBlock,
|
||||||
DAOForkBlock: MainNetDAOForkBlock,
|
DAOForkBlock: MainNetDAOForkBlock,
|
||||||
|
@ -35,8 +36,8 @@ var MainnetChainConfig = &ChainConfig{
|
||||||
EIP158Block: MainNetSpuriousDragon,
|
EIP158Block: MainNetSpuriousDragon,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestnetChainConfig is the chain parameters to run a node on the test network.
|
// TestnetChainConfig contains the chain parameters to run a node on the ropsten test network.
|
||||||
var TestnetChainConfig = &ChainConfig{
|
TestnetChainConfig = &ChainConfig{
|
||||||
ChainId: big.NewInt(3),
|
ChainId: big.NewInt(3),
|
||||||
HomesteadBlock: big.NewInt(0),
|
HomesteadBlock: big.NewInt(0),
|
||||||
DAOForkBlock: nil,
|
DAOForkBlock: nil,
|
||||||
|
@ -49,13 +50,16 @@ var TestnetChainConfig = &ChainConfig{
|
||||||
|
|
||||||
// AllProtocolChanges contains every protocol change (EIPs)
|
// AllProtocolChanges contains every protocol change (EIPs)
|
||||||
// introduced and accepted by the Ethereum core developers.
|
// 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 is intentionally not using keyed fields.
|
||||||
// This configuration must *always* have all forks enabled, which
|
// This configuration must *always* have all forks enabled, which
|
||||||
// means that all fields must be set at all times. This forces
|
// means that all fields must be set at all times. This forces
|
||||||
// anyone adding flags to the config to also have to set these
|
// anyone adding flags to the config to also have to set these
|
||||||
// fields.
|
// fields.
|
||||||
var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
|
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.
|
// 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
|
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the Stringer interface.
|
// String implements the fmt.Stringer interface.
|
||||||
func (c *ChainConfig) String() string {
|
func (c *ChainConfig) String() string {
|
||||||
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
|
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
|
||||||
c.ChainId,
|
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.
|
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
||||||
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
||||||
if c.HomesteadBlock == nil || num == nil {
|
return isForked(c.HomesteadBlock, num)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return num.Cmp(c.HomesteadBlock) >= 0
|
|
||||||
|
// 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).
|
// 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 {
|
if num == nil {
|
||||||
return GasTableHomestead
|
return GasTableHomestead
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0:
|
case c.IsEIP158(num):
|
||||||
return GasTableEIP158
|
return GasTableEIP158
|
||||||
case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0:
|
case c.IsEIP150(num):
|
||||||
return GasTableHomesteadGasRepriceFork
|
return GasTableHomesteadGasRepriceFork
|
||||||
default:
|
default:
|
||||||
return GasTableHomestead
|
return GasTableHomestead
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChainConfig) IsEIP150(num *big.Int) bool {
|
// CheckCompatible checks whether scheduled fork transitions have been imported
|
||||||
if c.EIP150Block == nil || num == nil {
|
// 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 false
|
||||||
}
|
}
|
||||||
return num.Cmp(c.EIP150Block) >= 0
|
return s.Cmp(head) <= 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChainConfig) IsEIP155(num *big.Int) bool {
|
func configNumEqual(x, y *big.Int) bool {
|
||||||
if c.EIP155Block == nil || num == nil {
|
if x == nil {
|
||||||
return false
|
return y == nil
|
||||||
}
|
}
|
||||||
return num.Cmp(c.EIP155Block) >= 0
|
if y == nil {
|
||||||
|
return x == nil
|
||||||
|
}
|
||||||
|
return x.Cmp(y) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
|
// ConfigCompatError is raised if the locally-stored blockchain is initialised with a
|
||||||
if c.EIP158Block == nil || num == nil {
|
// ChainConfig that would alter the past.
|
||||||
return false
|
type ConfigCompatError struct {
|
||||||
}
|
What string
|
||||||
return num.Cmp(c.EIP158Block) >= 0
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
|
func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
|
||||||
// that do not have or require information about the block.
|
var rew *big.Int
|
||||||
//
|
switch {
|
||||||
// Rules is a one time interface meaning that it shouldn't be used in between transition
|
case storedblock == nil:
|
||||||
// phases.
|
rew = newblock
|
||||||
type Rules struct {
|
case newblock == nil || storedblock.Cmp(newblock) < 0:
|
||||||
ChainId *big.Int
|
rew = storedblock
|
||||||
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
default:
|
||||||
|
rew = newblock
|
||||||
|
}
|
||||||
|
err := &ConfigCompatError{what, storedblock, newblock, 0}
|
||||||
|
if rew != nil && rew.Sign() > 0 {
|
||||||
|
err.RewindTo = rew.Uint64() - 1
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChainConfig) Rules(num *big.Int) Rules {
|
func (err *ConfigCompatError) Error() string {
|
||||||
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)}
|
return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
487
params/dao.go
487
params/dao.go
|
@ -17,8 +17,6 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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
|
// DAODrainList is the list of accounts whose full balances will be moved into a
|
||||||
// refund contract at the beginning of the dao-fork block.
|
// refund contract at the beginning of the dao-fork block.
|
||||||
var DAODrainList []common.Address
|
func DAODrainList() []common.Address {
|
||||||
|
return []common.Address{
|
||||||
func init() {
|
common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"),
|
||||||
// Parse the list of DAO accounts to drain
|
common.HexToAddress("0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"),
|
||||||
var list []map[string]string
|
common.HexToAddress("0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f"),
|
||||||
if err := json.Unmarshal([]byte(daoDrainListJSON), &list); err != nil {
|
common.HexToAddress("0xecd135fa4f61a655311e86238c92adcd779555d2"),
|
||||||
panic(fmt.Errorf("Failed to parse DAO drain list: %v", err))
|
common.HexToAddress("0x1975bd06d486162d5dc297798dfc41edd5d160a7"),
|
||||||
}
|
common.HexToAddress("0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"),
|
||||||
// Collect all the accounts that need draining
|
common.HexToAddress("0x319f70bab6845585f412ec7724b744fec6095c85"),
|
||||||
for _, dao := range list {
|
common.HexToAddress("0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"),
|
||||||
DAODrainList = append(DAODrainList, common.HexToAddress(dao["address"]))
|
common.HexToAddress("0x5c8536898fbb74fc7445814902fd08422eac56d0"),
|
||||||
DAODrainList = append(DAODrainList, common.HexToAddress(dao["extraBalanceAccount"]))
|
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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
`
|
|
||||||
|
|
Loading…
Reference in New Issue