From f11c6421a1f170dea4eb8122472beec365fddf20 Mon Sep 17 00:00:00 2001 From: Victor Farazdagi Date: Wed, 12 Oct 2016 01:56:36 +0300 Subject: [PATCH] Latest light-stable code pushed to vendors --- .../accounts/abi/bind/backends/simulated.go | 6 +- .../accounts/key_store_passphrase.go | 3 +- .../ethereum/go-ethereum/cmd/evm/main.go | 37 +- .../ethereum/go-ethereum/cmd/geth/chaincmd.go | 53 ++- .../go-ethereum/cmd/geth/consolecmd.go | 4 +- .../ethereum/go-ethereum/cmd/geth/main.go | 16 +- .../go-ethereum/cmd/geth/monitorcmd.go | 2 +- .../go-ethereum/cmd/gethrpctest/main.go | 11 +- .../go-ethereum/cmd/utils/customflags.go | 14 +- .../ethereum/go-ethereum/cmd/utils/flags.go | 66 +-- .../ethereum/go-ethereum/common/path.go | 27 -- .../ethereum/go-ethereum/core/chain_makers.go | 2 +- .../ethereum/go-ethereum/core/execution.go | 24 +- .../ethereum/go-ethereum/core/state/dump.go | 2 +- .../go-ethereum/core/state/journal.go | 117 ++++++ .../go-ethereum/core/state/state_object.go | 106 +++-- .../go-ethereum/core/state/statedb.go | 235 +++++++---- .../ethereum/go-ethereum/core/tx_pool.go | 2 +- .../ethereum/go-ethereum/core/types/block.go | 2 +- .../ethereum/go-ethereum/core/vm/contract.go | 11 +- .../go-ethereum/core/vm/environment.go | 14 +- .../go-ethereum/core/vm/instructions.go | 2 +- .../ethereum/go-ethereum/core/vm/jit.go | 2 +- .../go-ethereum/core/vm/runtime/env.go | 8 +- .../go-ethereum/core/vm/runtime/runtime.go | 2 +- .../ethereum/go-ethereum/core/vm/vm.go | 11 +- .../ethereum/go-ethereum/core/vm_env.go | 8 +- .../go-ethereum/crypto/sha3/keccakf.go | 2 + .../go-ethereum/crypto/sha3/keccakf_amd64.go | 13 + .../go-ethereum/crypto/sha3/keccakf_amd64.s | 392 ++++++++++++++++++ .../ethereum/go-ethereum/crypto/sha3/sha3.go | 2 +- .../ethereum/go-ethereum/crypto/sha3/xor.go | 2 +- .../go-ethereum/crypto/sha3/xor_unaligned.go | 2 +- .../ethereum/go-ethereum/eth/api_backend.go | 6 +- .../ethereum/go-ethereum/eth/handler.go | 21 +- .../ethereum/go-ethereum/ethdb/database.go | 5 + .../go-ethereum/internal/ethapi/api.go | 9 +- .../ethereum/go-ethereum/light/state.go | 3 +- .../go-ethereum/light/state_object.go | 4 +- .../ethereum/go-ethereum/light/vm_env.go | 63 +-- .../ethereum/go-ethereum/miner/worker.go | 6 +- .../ethereum/go-ethereum/node/api.go | 22 +- .../ethereum/go-ethereum/node/config.go | 133 ++++-- .../go-ethereum/{common => node}/defaults.go | 16 +- .../ethereum/go-ethereum/node/doc.go | 90 ++++ .../ethereum/go-ethereum/node/node.go | 175 +++++--- .../ethereum/go-ethereum/node/service.go | 19 +- .../ethereum/go-ethereum/p2p/nat/nat.go | 6 +- .../ethereum/go-ethereum/rpc/http.go | 1 + .../ethereum/go-ethereum/trie/trie.go | 12 +- 50 files changed, 1348 insertions(+), 443 deletions(-) create mode 100644 vendor/github.com/ethereum/go-ethereum/core/state/journal.go create mode 100644 vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go create mode 100644 vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s rename vendor/github.com/ethereum/go-ethereum/{common => node}/defaults.go (89%) create mode 100644 vendor/github.com/ethereum/go-ethereum/node/doc.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go index 7e09abb11..74203a468 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go @@ -172,8 +172,9 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) { b.mu.Lock() defer b.mu.Unlock() + defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) - rval, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState.Copy()) + rval, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) return rval, err } @@ -197,8 +198,9 @@ func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (*big.Int, error) { b.mu.Lock() defer b.mu.Unlock() + defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) - _, gas, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState.Copy()) + _, gas, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) return gas, err } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/key_store_passphrase.go b/vendor/github.com/ethereum/go-ethereum/accounts/key_store_passphrase.go index 700a4eadc..7758e6f27 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/key_store_passphrase.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/key_store_passphrase.go @@ -108,7 +108,8 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { return nil, err } encryptKey := derivedKey[:16] - keyBytes := crypto.FromECDSA(key.PrivateKey) + keyBytes0 := crypto.FromECDSA(key.PrivateKey) + keyBytes := common.LeftPadBytes(keyBytes0, 32) iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go index 3f44e0f3c..22707c1cc 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger/glog" "gopkg.in/urfave/cli.v1" @@ -146,7 +147,9 @@ func run(ctx *cli.Context) error { ) } else { receiver := statedb.CreateAccount(common.StringToAddress("receiver")) - receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))) + + code := common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) + receiver.SetCode(crypto.Keccak256Hash(code), code) ret, err = vmenv.Call( sender, receiver.Address(), @@ -224,22 +227,22 @@ type ruleSet struct{} func (ruleSet) IsHomestead(*big.Int) bool { return true } -func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} } -func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Db() vm.Database { return self.state } -func (self *VMEnv) MakeSnapshot() vm.Database { return self.state.Copy() } -func (self *VMEnv) SetSnapshot(db vm.Database) { self.state.Set(db.(*state.StateDB)) } -func (self *VMEnv) Origin() common.Address { return *self.transactor } -func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 } -func (self *VMEnv) Coinbase() common.Address { return *self.transactor } -func (self *VMEnv) Time() *big.Int { return self.time } -func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } -func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } -func (self *VMEnv) Value() *big.Int { return self.value } -func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } -func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } -func (self *VMEnv) Depth() int { return 0 } -func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} } +func (self *VMEnv) Vm() vm.Vm { return self.evm } +func (self *VMEnv) Db() vm.Database { return self.state } +func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() } +func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) } +func (self *VMEnv) Origin() common.Address { return *self.transactor } +func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 } +func (self *VMEnv) Coinbase() common.Address { return *self.transactor } +func (self *VMEnv) Time() *big.Int { return self.time } +func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } +func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } +func (self *VMEnv) Value() *big.Int { return self.value } +func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } +func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } +func (self *VMEnv) Depth() int { return 0 } +func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) GetHash(n uint64) common.Hash { if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 { return self.block.Hash() diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go index 293a6ffea..01fce7d1a 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go @@ -79,7 +79,8 @@ func importChain(ctx *cli.Context) error { if ctx.GlobalBool(utils.TestNetFlag.Name) { state.StartingNonce = 1048576 // (2**20) } - chain, chainDb := utils.MakeChain(ctx) + stack := makeFullNode(ctx) + chain, chainDb := utils.MakeChain(ctx, stack) start := time.Now() err := utils.ImportChain(chain, ctx.Args().First()) chainDb.Close() @@ -94,7 +95,8 @@ func exportChain(ctx *cli.Context) error { if len(ctx.Args()) < 1 { utils.Fatalf("This command requires an argument.") } - chain, _ := utils.MakeChain(ctx) + stack := makeFullNode(ctx) + chain, _ := utils.MakeChain(ctx, stack) start := time.Now() var err error @@ -122,20 +124,25 @@ func exportChain(ctx *cli.Context) error { } func removeDB(ctx *cli.Context) error { - confirm, err := console.Stdin.PromptConfirm("Remove local database?") - if err != nil { - utils.Fatalf("%v", err) + stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) + dbdir := stack.ResolvePath(utils.ChainDbName(ctx)) + if !common.FileExist(dbdir) { + fmt.Println(dbdir, "does not exist") + return nil } - if confirm { - fmt.Println("Removing chaindata...") - start := time.Now() - - os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), utils.ChainDbName(ctx))) - - fmt.Printf("Removed in %v\n", time.Since(start)) - } else { + fmt.Println(dbdir) + confirm, err := console.Stdin.PromptConfirm("Remove this database?") + switch { + case err != nil: + utils.Fatalf("%v", err) + case !confirm: fmt.Println("Operation aborted") + default: + fmt.Println("Removing...") + start := time.Now() + os.RemoveAll(dbdir) + fmt.Printf("Removed in %v\n", time.Since(start)) } return nil } @@ -143,7 +150,8 @@ func removeDB(ctx *cli.Context) error { func upgradeDB(ctx *cli.Context) error { glog.Infoln("Upgrading blockchain database") - chain, chainDb := utils.MakeChain(ctx) + stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) + chain, chainDb := utils.MakeChain(ctx, stack) bcVersion := core.GetBlockChainVersion(chainDb) if bcVersion == 0 { bcVersion = core.BlockChainVersion @@ -156,10 +164,12 @@ func upgradeDB(ctx *cli.Context) error { utils.Fatalf("Unable to export chain for reimport %s", err) } chainDb.Close() - os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), utils.ChainDbName(ctx))) + if dir := dbDirectory(chainDb); dir != "" { + os.RemoveAll(dir) + } // Import the chain file. - chain, chainDb = utils.MakeChain(ctx) + chain, chainDb = utils.MakeChain(ctx, stack) core.WriteBlockChainVersion(chainDb, core.BlockChainVersion) err := utils.ImportChain(chain, exportFile) chainDb.Close() @@ -172,8 +182,17 @@ func upgradeDB(ctx *cli.Context) error { return nil } +func dbDirectory(db ethdb.Database) string { + ldb, ok := db.(*ethdb.LDBDatabase) + if !ok { + return "" + } + return ldb.Path() +} + func dump(ctx *cli.Context) error { - chain, chainDb := utils.MakeChain(ctx) + stack := makeFullNode(ctx) + chain, chainDb := utils.MakeChain(ctx, stack) for _, arg := range ctx.Args() { var block *types.Block if hashish(arg) { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go index c3becc844..703ad04db 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go @@ -114,7 +114,7 @@ func remoteConsole(ctx *cli.Context) error { }) config := console.Config{ - DataDir: utils.MustMakeDataDir(ctx), + DataDir: utils.MakeDataDir(ctx), DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), Client: client, Preload: utils.MakeConsolePreloads(ctx), @@ -142,7 +142,7 @@ func remoteConsole(ctx *cli.Context) error { // for "geth attach" and "geth monitor" with no argument. func dialRPC(endpoint string) (*rpc.Client, error) { if endpoint == "" { - endpoint = node.DefaultIPCEndpoint() + endpoint = node.DefaultIPCEndpoint(clientIdentifier) } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { // Backwards compatibility with geth < 1.5 which required // these prefixes. diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go index f2cbd2414..724a55d27 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" @@ -47,7 +46,7 @@ import ( ) const ( - clientIdentifier = "Geth" // Client identifier to advertise over the network + clientIdentifier = "geth" // Client identifier to advertise over the network ) var ( @@ -251,17 +250,15 @@ func initGenesis(ctx *cli.Context) error { state.StartingNonce = 1048576 // (2**20) } - chainDb, err := ethdb.NewLDBDatabase(filepath.Join(utils.MustMakeDataDir(ctx), utils.ChainDbName(ctx)), 0, 0) - if err != nil { - utils.Fatalf("could not open database: %v", err) - } + stack := makeFullNode(ctx) + chaindb := utils.MakeChainDatabase(ctx, stack) genesisFile, err := os.Open(genesisPath) if err != nil { utils.Fatalf("failed to read genesis file: %v", err) } - block, err := core.WriteGenesisBlock(chainDb, genesisFile) + block, err := core.WriteGenesisBlock(chaindb, genesisFile) if err != nil { utils.Fatalf("failed to write genesis block: %v", err) } @@ -302,9 +299,6 @@ func makeFullNode(ctx *cli.Context) *node.Node { // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node) { - // Report geth version - glog.V(logger.Info).Infof("instance: Geth/%s/%s/%s\n", utils.Version, runtime.Version(), runtime.GOOS) - // Start up the node itself utils.StartNode(stack) @@ -410,7 +404,7 @@ func gpubench(ctx *cli.Context) error { } func version(c *cli.Context) error { - fmt.Println(clientIdentifier) + fmt.Println(strings.Title(clientIdentifier)) fmt.Println("Version:", utils.Version) if gitCommit != "" { fmt.Println("Git Commit:", gitCommit) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go index d1490dce2..b74315dab 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go @@ -35,7 +35,7 @@ import ( var ( monitorCommandAttachFlag = cli.StringFlag{ Name: "attach", - Value: node.DefaultIPCEndpoint(), + Value: node.DefaultIPCEndpoint(clientIdentifier), Usage: "API endpoint to attach to", } monitorCommandRowsFlag = cli.IntFlag{ diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/gethrpctest/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/gethrpctest/main.go index d267dbf58..d0d6e1618 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/gethrpctest/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/gethrpctest/main.go @@ -23,7 +23,6 @@ import ( "os" "os/signal" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -88,12 +87,12 @@ func MakeSystemNode(privkey string, test *tests.BlockTest) (*node.Node, error) { // Create a networkless protocol stack stack, err := node.New(&node.Config{ UseLightweightKDF: true, - IPCPath: node.DefaultIPCEndpoint(), - HTTPHost: common.DefaultHTTPHost, - HTTPPort: common.DefaultHTTPPort, + IPCPath: node.DefaultIPCEndpoint(""), + HTTPHost: node.DefaultHTTPHost, + HTTPPort: node.DefaultHTTPPort, HTTPModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"}, - WSHost: common.DefaultWSHost, - WSPort: common.DefaultWSPort, + WSHost: node.DefaultWSHost, + WSPort: node.DefaultWSPort, WSModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"}, NoDiscovery: true, }) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/utils/customflags.go b/vendor/github.com/ethereum/go-ethereum/cmd/utils/customflags.go index 5cbccfe98..11c92d451 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/utils/customflags.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/utils/customflags.go @@ -137,9 +137,19 @@ func (self *DirectoryFlag) Set(value string) { // Note, it has limitations, e.g. ~someuser/tmp will not be expanded func expandPath(p string) string { if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { - if user, err := user.Current(); err == nil { - p = user.HomeDir + p[1:] + if home := homeDir(); home != "" { + p = home + p[1:] } } return path.Clean(os.ExpandEnv(p)) } + +func homeDir() string { + if home := os.Getenv("HOME"); home != "" { + return home + } + if usr, err := user.Current(); err == nil { + return usr.HomeDir + } + return "" +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go b/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go index 59de43918..5c36236f3 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go @@ -108,7 +108,7 @@ var ( DataDirFlag = DirectoryFlag{ Name: "datadir", Usage: "Data directory for the databases and keystore", - Value: DirectoryString{common.DefaultDataDir()}, + Value: DirectoryString{node.DefaultDataDir()}, } KeyStoreDirFlag = DirectoryFlag{ Name: "keystore", @@ -142,7 +142,7 @@ var ( DocRootFlag = DirectoryFlag{ Name: "docroot", Usage: "Document Root for HTTPClient file scheme", - Value: DirectoryString{common.HomeDir()}, + Value: DirectoryString{homeDir()}, } CacheFlag = cli.IntFlag{ Name: "cache", @@ -266,12 +266,12 @@ var ( RPCListenAddrFlag = cli.StringFlag{ Name: "rpcaddr", Usage: "HTTP-RPC server listening interface", - Value: common.DefaultHTTPHost, + Value: node.DefaultHTTPHost, } RPCPortFlag = cli.IntFlag{ Name: "rpcport", Usage: "HTTP-RPC server listening port", - Value: common.DefaultHTTPPort, + Value: node.DefaultHTTPPort, } RPCCORSDomainFlag = cli.StringFlag{ Name: "rpccorsdomain", @@ -289,13 +289,13 @@ var ( } IPCApiFlag = cli.StringFlag{ Name: "ipcapi", - Usage: "API's offered over the IPC-RPC interface", + Usage: "APIs offered over the IPC-RPC interface", Value: rpc.DefaultIPCApis, } IPCPathFlag = DirectoryFlag{ Name: "ipcpath", Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", - Value: DirectoryString{common.DefaultIPCSocket}, + Value: DirectoryString{"geth.ipc"}, } WSEnabledFlag = cli.BoolFlag{ Name: "ws", @@ -304,12 +304,12 @@ var ( WSListenAddrFlag = cli.StringFlag{ Name: "wsaddr", Usage: "WS-RPC server listening interface", - Value: common.DefaultWSHost, + Value: node.DefaultWSHost, } WSPortFlag = cli.IntFlag{ Name: "wsport", Usage: "WS-RPC server listening port", - Value: common.DefaultWSPort, + Value: node.DefaultWSPort, } WSApiFlag = cli.StringFlag{ Name: "wsapi", @@ -428,13 +428,14 @@ func DebugSetup(ctx *cli.Context) error { return err } -// MustMakeDataDir retrieves the currently requested data directory, terminating +// MakeDataDir retrieves the currently requested data directory, terminating // if none (or the empty string) is specified. If the node is starting a testnet, // the a subdirectory of the specified datadir will be used. -func MustMakeDataDir(ctx *cli.Context) string { +func MakeDataDir(ctx *cli.Context) string { if path := ctx.GlobalString(DataDirFlag.Name); path != "" { + // TODO: choose a different location outside of the regular datadir. if ctx.GlobalBool(TestNetFlag.Name) { - return filepath.Join(path, "/testnet") + return filepath.Join(path, "testnet") } return path } @@ -479,16 +480,16 @@ func MakeNodeKey(ctx *cli.Context) *ecdsa.PrivateKey { return key } -// MakeNodeName creates a node name from a base set and the command line flags. -func MakeNodeName(client, version string, ctx *cli.Context) string { - name := common.MakeName(client, version) +// makeNodeUserIdent creates the user identifier from CLI flags. +func makeNodeUserIdent(ctx *cli.Context) string { + var comps []string if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { - name += "/" + identity + comps = append(comps, identity) } if ctx.GlobalBool(VMEnableJitFlag.Name) { - name += "/JIT" + comps = append(comps, "JIT") } - return name + return strings.Join(comps, "/") } // MakeBootstrapNodes creates a list of bootstrap nodes from the command line @@ -644,11 +645,13 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node { } config := &node.Config{ - DataDir: MustMakeDataDir(ctx), + DataDir: MakeDataDir(ctx), KeyStoreDir: ctx.GlobalString(KeyStoreDirFlag.Name), UseLightweightKDF: ctx.GlobalBool(LightKDFFlag.Name), PrivateKey: MakeNodeKey(ctx), - Name: MakeNodeName(name, vsn, ctx), + Name: name, + Version: vsn, + UserIdent: makeNodeUserIdent(ctx), NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name), BootstrapNodes: MakeBootstrapNodes(ctx), ListenAddr: MakeListenAddress(ctx), @@ -712,7 +715,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { ethConf := ð.Config{ Etherbase: MakeEtherbase(stack.AccountManager(), ctx), - ChainConfig: MustMakeChainConfig(ctx), + ChainConfig: MakeChainConfig(ctx, stack), FastSync: ctx.GlobalBool(FastSyncFlag.Name), LightMode: ctx.GlobalBool(LightModeFlag.Name), NoDefSrv: ctx.GlobalBool(NoDefSrvFlag.Name), @@ -804,16 +807,16 @@ func SetupNetwork(ctx *cli.Context) { params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name)) } -// MustMakeChainConfig reads the chain configuration from the database in ctx.Datadir. -func MustMakeChainConfig(ctx *cli.Context) *core.ChainConfig { - db := MakeChainDatabase(ctx) +// MakeChainConfig reads the chain configuration from the database in ctx.Datadir. +func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig { + db := MakeChainDatabase(ctx, stack) defer db.Close() - return MustMakeChainConfigFromDb(ctx, db) + return MakeChainConfigFromDb(ctx, db) } -// MustMakeChainConfigFromDb reads the chain configuration from the given database. -func MustMakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig { +// MakeChainConfigFromDb reads the chain configuration from the given database. +func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig { // If the chain is already initialized, use any existing chain configs config := new(core.ChainConfig) @@ -864,15 +867,14 @@ func ChainDbName(ctx *cli.Context) string { } // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. -func MakeChainDatabase(ctx *cli.Context) ethdb.Database { +func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { var ( - datadir = MustMakeDataDir(ctx) cache = ctx.GlobalInt(CacheFlag.Name) handles = MakeDatabaseHandles() name = ChainDbName(ctx) ) - chainDb, err := ethdb.NewLDBDatabase(filepath.Join(datadir, name), cache, handles) + chainDb, err := stack.OpenDatabase(name, cache, handles) if err != nil { Fatalf("Could not open database: %v", err) } @@ -880,9 +882,9 @@ func MakeChainDatabase(ctx *cli.Context) ethdb.Database { } // MakeChain creates a chain manager from set command line flags. -func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database) { +func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { var err error - chainDb = MakeChainDatabase(ctx) + chainDb = MakeChainDatabase(ctx, stack) if ctx.GlobalBool(OlympicFlag.Name) { _, err := core.WriteTestNetGenesisBlock(chainDb) @@ -890,7 +892,7 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database glog.Fatalln(err) } } - chainConfig := MustMakeChainConfigFromDb(ctx, chainDb) + chainConfig := MakeChainConfigFromDb(ctx, chainDb) pow := pow.PoW(core.FakePow{}) if !ctx.GlobalBool(FakePoWFlag.Name) { diff --git a/vendor/github.com/ethereum/go-ethereum/common/path.go b/vendor/github.com/ethereum/go-ethereum/common/path.go index cbcd13c4f..bd8da86e7 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/path.go +++ b/vendor/github.com/ethereum/go-ethereum/common/path.go @@ -19,10 +19,8 @@ package common import ( "fmt" "os" - "os/user" "path/filepath" "runtime" - "strings" ) // MakeName creates a node name that follows the ethereum convention @@ -32,21 +30,6 @@ func MakeName(name, version string) string { return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version()) } -func ExpandHomePath(p string) (path string) { - path = p - sep := string(os.PathSeparator) - - // Check in case of paths like "/something/~/something/" - if len(p) > 1 && p[:1+len(sep)] == "~"+sep { - usr, _ := user.Current() - dir := usr.HomeDir - - path = strings.Replace(p, "~", dir, 1) - } - - return -} - func FileExist(filePath string) bool { _, err := os.Stat(filePath) if err != nil && os.IsNotExist(err) { @@ -62,13 +45,3 @@ func AbsolutePath(Datadir string, filename string) string { } return filepath.Join(Datadir, filename) } - -func HomeDir() string { - if home := os.Getenv("HOME"); home != "" { - return home - } - if usr, err := user.Current(); err == nil { - return usr.HomeDir - } - return "" -} diff --git a/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go b/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go index 0b9a5f75d..e3ad9cda0 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go +++ b/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go @@ -131,7 +131,7 @@ func (b *BlockGen) AddUncheckedReceipt(receipt *types.Receipt) { // TxNonce returns the next valid transaction nonce for the // account at addr. It panics if the account does not exist. func (b *BlockGen) TxNonce(addr common.Address) uint64 { - if !b.statedb.HasAccount(addr) { + if !b.statedb.Exist(addr) { panic("account does not exist") } return b.statedb.GetNonce(addr) diff --git a/vendor/github.com/ethereum/go-ethereum/core/execution.go b/vendor/github.com/ethereum/go-ethereum/core/execution.go index 82143443c..1cb507ee7 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/execution.go +++ b/vendor/github.com/ethereum/go-ethereum/core/execution.go @@ -27,14 +27,14 @@ import ( // Call executes within the given contract func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { - ret, _, err = exec(env, caller, &addr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value) + ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value) return ret, err } // CallCode executes the given address' code as the given contract address func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { callerAddr := caller.Address() - ret, _, err = exec(env, caller, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value) + ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value) return ret, err } @@ -43,13 +43,13 @@ func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address callerAddr := caller.Address() originAddr := env.Origin() callerValue := caller.Value() - ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, callerValue) + ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, callerValue) return ret, err } // Create creates a new contract with the given code func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) { - ret, address, err = exec(env, caller, nil, nil, nil, code, gas, gasPrice, value) + ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value) // Here we get an error if we run into maximum stack depth, // See: https://github.com/ethereum/yellowpaper/pull/131 // and YP definitions for CREATE instruction @@ -59,7 +59,7 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric return ret, address, err } -func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { +func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the // limit. @@ -85,7 +85,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A createAccount = true } - snapshotPreTransfer := env.MakeSnapshot() + snapshotPreTransfer := env.SnapshotDatabase() var ( from = env.Db().GetAccount(caller.Address()) to vm.Account @@ -105,7 +105,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A // EVM. The contract is a scoped environment for this execution context // only. contract := vm.NewContract(caller, to, value, gas, gasPrice) - contract.SetCallCode(codeAddr, code) + contract.SetCallCode(codeAddr, codeHash, code) defer contract.Finalise() ret, err = evm.Run(contract, input) @@ -129,13 +129,13 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A if err != nil && (env.RuleSet().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) { contract.UseGas(contract.Gas) - env.SetSnapshot(snapshotPreTransfer) + env.RevertToSnapshot(snapshotPreTransfer) } return ret, addr, err } -func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { +func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the // limit. @@ -144,7 +144,7 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA return nil, common.Address{}, vm.DepthError } - snapshot := env.MakeSnapshot() + snapshot := env.SnapshotDatabase() var to vm.Account if !env.Db().Exist(*toAddr) { @@ -155,14 +155,14 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA // Iinitialise a new contract and make initialise the delegate values contract := vm.NewContract(caller, to, value, gas, gasPrice).AsDelegate() - contract.SetCallCode(codeAddr, code) + contract.SetCallCode(codeAddr, codeHash, code) defer contract.Finalise() ret, err = evm.Run(contract, input) if err != nil { contract.UseGas(contract.Gas) - env.SetSnapshot(snapshot) + env.RevertToSnapshot(snapshot) } return ret, addr, err diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/dump.go b/vendor/github.com/ethereum/go-ethereum/core/state/dump.go index 58ecd852b..8294d61b9 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/dump.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/dump.go @@ -52,7 +52,7 @@ func (self *StateDB) RawDump() Dump { panic(err) } - obj := NewObject(common.BytesToAddress(addr), data, nil) + obj := newObject(nil, common.BytesToAddress(addr), data, nil) account := DumpAccount{ Balance: data.Balance.String(), Nonce: data.Nonce, diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/journal.go b/vendor/github.com/ethereum/go-ethereum/core/state/journal.go new file mode 100644 index 000000000..720c821b9 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/core/state/journal.go @@ -0,0 +1,117 @@ +// Copyright 2016 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 . + +package state + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +type journalEntry interface { + undo(*StateDB) +} + +type journal []journalEntry + +type ( + // Changes to the account trie. + createObjectChange struct { + account *common.Address + } + resetObjectChange struct { + prev *StateObject + } + suicideChange struct { + account *common.Address + prev bool // whether account had already suicided + prevbalance *big.Int + } + + // Changes to individual accounts. + balanceChange struct { + account *common.Address + prev *big.Int + } + nonceChange struct { + account *common.Address + prev uint64 + } + storageChange struct { + account *common.Address + key, prevalue common.Hash + } + codeChange struct { + account *common.Address + prevcode, prevhash []byte + } + + // Changes to other state values. + refundChange struct { + prev *big.Int + } + addLogChange struct { + txhash common.Hash + } +) + +func (ch createObjectChange) undo(s *StateDB) { + s.GetStateObject(*ch.account).deleted = true + delete(s.stateObjects, *ch.account) + delete(s.stateObjectsDirty, *ch.account) +} + +func (ch resetObjectChange) undo(s *StateDB) { + s.setStateObject(ch.prev) +} + +func (ch suicideChange) undo(s *StateDB) { + obj := s.GetStateObject(*ch.account) + if obj != nil { + obj.suicided = ch.prev + obj.setBalance(ch.prevbalance) + } +} + +func (ch balanceChange) undo(s *StateDB) { + s.GetStateObject(*ch.account).setBalance(ch.prev) +} + +func (ch nonceChange) undo(s *StateDB) { + s.GetStateObject(*ch.account).setNonce(ch.prev) +} + +func (ch codeChange) undo(s *StateDB) { + s.GetStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) +} + +func (ch storageChange) undo(s *StateDB) { + s.GetStateObject(*ch.account).setState(ch.key, ch.prevalue) +} + +func (ch refundChange) undo(s *StateDB) { + s.refund = ch.prev +} + +func (ch addLogChange) undo(s *StateDB) { + logs := s.logs[ch.txhash] + if len(logs) == 1 { + delete(s.logs, ch.txhash) + } else { + s.logs[ch.txhash] = logs[:len(logs)-1] + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go b/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go index a54620d55..6eab27d9e 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go @@ -66,6 +66,7 @@ func (self Storage) Copy() Storage { type StateObject struct { address common.Address // Ethereum address of this account data Account + db *StateDB // DB error. // State objects are used by the consensus core and VM which are @@ -75,15 +76,17 @@ type StateObject struct { dbErr error // Write caches. - trie *trie.SecureTrie // storage trie, which becomes non-nil on first access - code Code // contract bytecode, which gets set when code is loaded - storage Storage // Cached storage (flushed when updated) + trie *trie.SecureTrie // storage trie, which becomes non-nil on first access + code Code // contract bytecode, which gets set when code is loaded + + cachedStorage Storage // Storage entry cache to avoid duplicate reads + dirtyStorage Storage // Storage entries that need to be flushed to disk // Cache flags. - // When an object is marked for deletion it will be delete from the trie - // during the "update" phase of the state transition + // When an object is marked suicided it will be delete from the trie + // during the "update" phase of the state transition. dirtyCode bool // true if the code was updated - remove bool + suicided bool deleted bool onDirty func(addr common.Address) // Callback method to mark a state object newly dirty } @@ -97,15 +100,15 @@ type Account struct { CodeHash []byte } -// NewObject creates a state object. -func NewObject(address common.Address, data Account, onDirty func(addr common.Address)) *StateObject { +// newObject creates a state object. +func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *StateObject { if data.Balance == nil { data.Balance = new(big.Int) } if data.CodeHash == nil { data.CodeHash = emptyCodeHash } - return &StateObject{address: address, data: data, storage: make(Storage), onDirty: onDirty} + return &StateObject{db: db, address: address, data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), onDirty: onDirty} } // EncodeRLP implements rlp.Encoder. @@ -120,8 +123,8 @@ func (self *StateObject) setError(err error) { } } -func (self *StateObject) MarkForDeletion() { - self.remove = true +func (self *StateObject) markSuicided() { + self.suicided = true if self.onDirty != nil { self.onDirty(self.Address()) self.onDirty = nil @@ -145,24 +148,38 @@ func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie { // GetState returns a value in account storage. func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash { - value, exists := self.storage[key] + value, exists := self.cachedStorage[key] if exists { return value } // Load from DB in case it is missing. - tr := self.getTrie(db) - var ret []byte - rlp.DecodeBytes(tr.Get(key[:]), &ret) - value = common.BytesToHash(ret) + if enc := self.getTrie(db).Get(key[:]); len(enc) > 0 { + _, content, _, err := rlp.Split(enc) + if err != nil { + self.setError(err) + } + value.SetBytes(content) + } if (value != common.Hash{}) { - self.storage[key] = value + self.cachedStorage[key] = value } return value } // SetState updates a value in account storage. -func (self *StateObject) SetState(key, value common.Hash) { - self.storage[key] = value +func (self *StateObject) SetState(db trie.Database, key, value common.Hash) { + self.db.journal = append(self.db.journal, storageChange{ + account: &self.address, + key: key, + prevalue: self.GetState(db, key), + }) + self.setState(key, value) +} + +func (self *StateObject) setState(key, value common.Hash) { + self.cachedStorage[key] = value + self.dirtyStorage[key] = value + if self.onDirty != nil { self.onDirty(self.Address()) self.onDirty = nil @@ -172,7 +189,8 @@ func (self *StateObject) SetState(key, value common.Hash) { // updateTrie writes cached storage modifications into the object's storage trie. func (self *StateObject) updateTrie(db trie.Database) { tr := self.getTrie(db) - for key, value := range self.storage { + for key, value := range self.dirtyStorage { + delete(self.dirtyStorage, key) if (value == common.Hash{}) { tr.Delete(key[:]) continue @@ -184,7 +202,7 @@ func (self *StateObject) updateTrie(db trie.Database) { } // UpdateRoot sets the trie root to the current root hash of -func (self *StateObject) UpdateRoot(db trie.Database) { +func (self *StateObject) updateRoot(db trie.Database) { self.updateTrie(db) self.data.Root = self.trie.Hash() } @@ -194,7 +212,6 @@ func (self *StateObject) UpdateRoot(db trie.Database) { func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) error { self.updateTrie(db) if self.dbErr != nil { - fmt.Println("dbErr:", self.dbErr) return self.dbErr } root, err := self.trie.CommitTo(dbw) @@ -227,6 +244,14 @@ func (c *StateObject) SubBalance(amount *big.Int) { } func (self *StateObject) SetBalance(amount *big.Int) { + self.db.journal = append(self.db.journal, balanceChange{ + account: &self.address, + prev: new(big.Int).Set(self.data.Balance), + }) + self.setBalance(amount) +} + +func (self *StateObject) setBalance(amount *big.Int) { self.data.Balance = amount if self.onDirty != nil { self.onDirty(self.Address()) @@ -237,12 +262,13 @@ func (self *StateObject) SetBalance(amount *big.Int) { // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *StateObject) ReturnGas(gas, price *big.Int) {} -func (self *StateObject) Copy(db trie.Database, onDirty func(addr common.Address)) *StateObject { - stateObject := NewObject(self.address, self.data, onDirty) +func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject { + stateObject := newObject(db, self.address, self.data, onDirty) stateObject.trie = self.trie stateObject.code = self.code - stateObject.storage = self.storage.Copy() - stateObject.remove = self.remove + stateObject.dirtyStorage = self.dirtyStorage.Copy() + stateObject.cachedStorage = self.dirtyStorage.Copy() + stateObject.suicided = self.suicided stateObject.dirtyCode = self.dirtyCode stateObject.deleted = self.deleted return stateObject @@ -273,9 +299,19 @@ func (self *StateObject) Code(db trie.Database) []byte { return code } -func (self *StateObject) SetCode(code []byte) { +func (self *StateObject) SetCode(codeHash common.Hash, code []byte) { + prevcode := self.Code(self.db.db) + self.db.journal = append(self.db.journal, codeChange{ + account: &self.address, + prevhash: self.CodeHash(), + prevcode: prevcode, + }) + self.setCode(codeHash, code) +} + +func (self *StateObject) setCode(codeHash common.Hash, code []byte) { self.code = code - self.data.CodeHash = crypto.Keccak256(code) + self.data.CodeHash = codeHash[:] self.dirtyCode = true if self.onDirty != nil { self.onDirty(self.Address()) @@ -284,6 +320,14 @@ func (self *StateObject) SetCode(code []byte) { } func (self *StateObject) SetNonce(nonce uint64) { + self.db.journal = append(self.db.journal, nonceChange{ + account: &self.address, + prev: self.data.Nonce, + }) + self.setNonce(nonce) +} + +func (self *StateObject) setNonce(nonce uint64) { self.data.Nonce = nonce if self.onDirty != nil { self.onDirty(self.Address()) @@ -312,15 +356,15 @@ func (self *StateObject) Value() *big.Int { func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) { // When iterating over the storage check the cache first - for h, value := range self.storage { + for h, value := range self.cachedStorage { cb(h, value) } - it := self.trie.Iterator() + it := self.getTrie(self.db.db).Iterator() for it.Next() { // ignore cached values key := common.BytesToHash(self.trie.GetKey(it.Key)) - if _, ok := self.storage[key]; !ok { + if _, ok := self.cachedStorage[key]; !ok { cb(key, common.BytesToHash(it.Value)) } } diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go b/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go index 5c51e3b59..ec9e9392f 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go @@ -20,10 +20,12 @@ package state import ( "fmt" "math/big" + "sort" "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" @@ -39,12 +41,17 @@ var StartingNonce uint64 const ( // Number of past tries to keep. The arbitrarily chosen value here // is max uncle depth + 1. - maxJournalLength = 8 + maxTrieCacheLength = 8 // Number of codehash->size associations to keep. codeSizeCacheSize = 100000 ) +type revision struct { + id int + journalIndex int +} + // StateDBs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -68,6 +75,12 @@ type StateDB struct { logs map[common.Hash]vm.Logs logSize uint + // Journal of state modifications. This is the backbone of + // Snapshot and RevertToSnapshot. + journal journal + validRevisions []revision + nextRevisionId int + lock sync.Mutex } @@ -123,12 +136,12 @@ func (self *StateDB) Reset(root common.Hash) error { self.trie = tr self.stateObjects = make(map[common.Address]*StateObject) self.stateObjectsDirty = make(map[common.Address]struct{}) - self.refund = new(big.Int) self.thash = common.Hash{} self.bhash = common.Hash{} self.txIndex = 0 self.logs = make(map[common.Hash]vm.Logs) self.logSize = 0 + self.clearJournalAndRefund() return nil } @@ -149,7 +162,7 @@ func (self *StateDB) pushTrie(t *trie.SecureTrie) { self.lock.Lock() defer self.lock.Unlock() - if len(self.pastTries) >= maxJournalLength { + if len(self.pastTries) >= maxTrieCacheLength { copy(self.pastTries, self.pastTries[1:]) self.pastTries[len(self.pastTries)-1] = t } else { @@ -164,6 +177,8 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { } func (self *StateDB) AddLog(log *vm.Log) { + self.journal = append(self.journal, addLogChange{txhash: self.thash}) + log.TxHash = self.thash log.BlockHash = self.bhash log.TxIndex = uint(self.txIndex) @@ -185,13 +200,12 @@ func (self *StateDB) Logs() vm.Logs { } func (self *StateDB) AddRefund(gas *big.Int) { + self.journal = append(self.journal, refundChange{prev: new(big.Int).Set(self.refund)}) self.refund.Add(self.refund, gas) } -func (self *StateDB) HasAccount(addr common.Address) bool { - return self.GetStateObject(addr) != nil -} - +// Exist reports whether the given account address exists in the state. +// Notably this also returns true for suicided accounts. func (self *StateDB) Exist(addr common.Address) bool { return self.GetStateObject(addr) != nil } @@ -206,7 +220,6 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int { if stateObject != nil { return stateObject.Balance() } - return common.Big0 } @@ -246,6 +259,14 @@ func (self *StateDB) GetCodeSize(addr common.Address) int { return size } +func (self *StateDB) GetCodeHash(addr common.Address) common.Hash { + stateObject := self.GetStateObject(addr) + if stateObject == nil { + return common.Hash{} + } + return common.BytesToHash(stateObject.CodeHash()) +} + func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash { stateObject := self.GetStateObject(a) if stateObject != nil { @@ -254,10 +275,10 @@ func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash { return common.Hash{} } -func (self *StateDB) IsDeleted(addr common.Address) bool { +func (self *StateDB) HasSuicided(addr common.Address) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.remove + return stateObject.suicided } return false } @@ -273,6 +294,13 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { } } +func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) { + stateObject := self.GetOrNewStateObject(addr) + if stateObject != nil { + stateObject.SetBalance(amount) + } +} + func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { @@ -283,34 +311,43 @@ func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { func (self *StateDB) SetCode(addr common.Address, code []byte) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { - stateObject.SetCode(code) + stateObject.SetCode(crypto.Keccak256Hash(code), code) } } func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { - stateObject.SetState(key, value) + stateObject.SetState(self.db, key, value) } } -func (self *StateDB) Delete(addr common.Address) bool { +// Suicide marks the given account as suicided. +// This clears the account balance. +// +// The account's state object is still available until the state is committed, +// GetStateObject will return a non-nil account after Suicide. +func (self *StateDB) Suicide(addr common.Address) bool { stateObject := self.GetStateObject(addr) - if stateObject != nil { - stateObject.MarkForDeletion() - stateObject.data.Balance = new(big.Int) - return true + if stateObject == nil { + return false } - - return false + self.journal = append(self.journal, suicideChange{ + account: &addr, + prev: stateObject.suicided, + prevbalance: new(big.Int).Set(stateObject.Balance()), + }) + stateObject.markSuicided() + stateObject.data.Balance = new(big.Int) + return true } // // Setting, updating & deleting state object methods // -// Update the given state object and apply it to state trie -func (self *StateDB) UpdateStateObject(stateObject *StateObject) { +// updateStateObject writes the given object to the trie. +func (self *StateDB) updateStateObject(stateObject *StateObject) { addr := stateObject.Address() data, err := rlp.EncodeToBytes(stateObject) if err != nil { @@ -319,10 +356,9 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) { self.trie.Update(addr[:], data) } -// Delete the given state object and delete it from the state trie -func (self *StateDB) DeleteStateObject(stateObject *StateObject) { +// deleteStateObject removes the given object from the state trie. +func (self *StateDB) deleteStateObject(stateObject *StateObject) { stateObject.deleted = true - addr := stateObject.Address() self.trie.Delete(addr[:]) } @@ -348,12 +384,12 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje return nil } // Insert into the live set. - obj := NewObject(addr, data, self.MarkStateObjectDirty) - self.SetStateObject(obj) + obj := newObject(self, addr, data, self.MarkStateObjectDirty) + self.setStateObject(obj) return obj } -func (self *StateDB) SetStateObject(object *StateObject) { +func (self *StateDB) setStateObject(object *StateObject) { self.stateObjects[object.Address()] = object } @@ -361,52 +397,55 @@ func (self *StateDB) SetStateObject(object *StateObject) { func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil || stateObject.deleted { - stateObject = self.CreateStateObject(addr) + stateObject, _ = self.createObject(addr) } - return stateObject } -// NewStateObject create a state object whether it exist in the trie or not -func (self *StateDB) newStateObject(addr common.Address) *StateObject { - if glog.V(logger.Core) { - glog.Infof("(+) %x\n", addr) - } - obj := NewObject(addr, Account{}, self.MarkStateObjectDirty) - obj.SetNonce(StartingNonce) // sets the object to dirty - self.stateObjects[addr] = obj - return obj -} - // MarkStateObjectDirty adds the specified object to the dirty map to avoid costly // state object cache iteration to find a handful of modified ones. func (self *StateDB) MarkStateObjectDirty(addr common.Address) { self.stateObjectsDirty[addr] = struct{}{} } -// Creates creates a new state object and takes ownership. -func (self *StateDB) CreateStateObject(addr common.Address) *StateObject { - // Get previous (if any) - so := self.GetStateObject(addr) - // Create a new one - newSo := self.newStateObject(addr) - - // If it existed set the balance to the new account - if so != nil { - newSo.data.Balance = so.data.Balance +// createObject creates a new state object. If there is an existing account with +// the given address, it is overwritten and returned as the second return value. +func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObject) { + prev = self.GetStateObject(addr) + newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty) + newobj.setNonce(StartingNonce) // sets the object to dirty + if prev == nil { + if glog.V(logger.Core) { + glog.Infof("(+) %x\n", addr) + } + self.journal = append(self.journal, createObjectChange{account: &addr}) + } else { + self.journal = append(self.journal, resetObjectChange{prev: prev}) } - - return newSo + self.setStateObject(newobj) + return newobj, prev } +// CreateAccount explicitly creates a state object. If a state object with the address +// already exists the balance is carried over to the new account. +// +// CreateAccount is called during the EVM CREATE operation. The situation might arise that +// a contract does the following: +// +// 1. sends funds to sha(account ++ (nonce + 1)) +// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) +// +// Carrying over the balance ensures that Ether doesn't disappear. func (self *StateDB) CreateAccount(addr common.Address) vm.Account { - return self.CreateStateObject(addr) + new, prev := self.createObject(addr) + if prev != nil { + new.setBalance(prev.data.Balance) + } + return new } -// -// Setting, copying of the state methods -// - +// Copy creates a deep, independent copy of the state. +// Snapshots of the copied state cannot be applied to the copy. func (self *StateDB) Copy() *StateDB { self.lock.Lock() defer self.lock.Unlock() @@ -425,7 +464,7 @@ func (self *StateDB) Copy() *StateDB { } // Copy the dirty states and logs for addr, _ := range self.stateObjectsDirty { - state.stateObjects[addr] = self.stateObjects[addr].Copy(self.db, state.MarkStateObjectDirty) + state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty) state.stateObjectsDirty[addr] = struct{}{} } for hash, logs := range self.logs { @@ -435,21 +474,38 @@ func (self *StateDB) Copy() *StateDB { return state } -func (self *StateDB) Set(state *StateDB) { - self.lock.Lock() - defer self.lock.Unlock() - - self.db = state.db - self.trie = state.trie - self.pastTries = state.pastTries - self.stateObjects = state.stateObjects - self.stateObjectsDirty = state.stateObjectsDirty - self.codeSizeCache = state.codeSizeCache - self.refund = state.refund - self.logs = state.logs - self.logSize = state.logSize +// Snapshot returns an identifier for the current revision of the state. +func (self *StateDB) Snapshot() int { + id := self.nextRevisionId + self.nextRevisionId++ + self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)}) + return id } +// RevertToSnapshot reverts all state changes made since the given revision. +func (self *StateDB) RevertToSnapshot(revid int) { + // Find the snapshot in the stack of valid snapshots. + idx := sort.Search(len(self.validRevisions), func(i int) bool { + return self.validRevisions[i].id >= revid + }) + if idx == len(self.validRevisions) || self.validRevisions[idx].id != revid { + panic(fmt.Errorf("revision id %v cannot be reverted", revid)) + } + snapshot := self.validRevisions[idx].journalIndex + + // Replay the journal to undo changes. + for i := len(self.journal) - 1; i >= snapshot; i-- { + self.journal[i].undo(self) + } + self.journal = self.journal[:snapshot] + + // Remove invalidated snapshots from the stack. + self.validRevisions = self.validRevisions[:idx] +} + +// GetRefund returns the current value of the refund counter. +// The return value must not be modified by the caller and will become +// invalid at the next call to AddRefund. func (self *StateDB) GetRefund() *big.Int { return self.refund } @@ -458,16 +514,17 @@ func (self *StateDB) GetRefund() *big.Int { // It is called in between transactions to get the root hash that // goes into transaction receipts. func (s *StateDB) IntermediateRoot() common.Hash { - s.refund = new(big.Int) for addr, _ := range s.stateObjectsDirty { stateObject := s.stateObjects[addr] - if stateObject.remove { - s.DeleteStateObject(stateObject) + if stateObject.suicided { + s.deleteStateObject(stateObject) } else { - stateObject.UpdateRoot(s.db) - s.UpdateStateObject(stateObject) + stateObject.updateRoot(s.db) + s.updateStateObject(stateObject) } } + // Invalidate journal because reverting across transactions is not allowed. + s.clearJournalAndRefund() return s.trie.Hash() } @@ -477,15 +534,15 @@ func (s *StateDB) IntermediateRoot() common.Hash { // DeleteSuicides should not be used for consensus related updates // under any circumstances. func (s *StateDB) DeleteSuicides() { - // Reset refund so that any used-gas calculations can use - // this method. - s.refund = new(big.Int) + // Reset refund so that any used-gas calculations can use this method. + s.clearJournalAndRefund() + for addr, _ := range s.stateObjectsDirty { stateObject := s.stateObjects[addr] // If the object has been removed by a suicide // flag the object as deleted. - if stateObject.remove { + if stateObject.suicided { stateObject.deleted = true } delete(s.stateObjectsDirty, addr) @@ -507,15 +564,21 @@ func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) { return root, batch } -func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) { +func (s *StateDB) clearJournalAndRefund() { + s.journal = nil + s.validRevisions = s.validRevisions[:0] s.refund = new(big.Int) +} + +func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) { + defer s.clearJournalAndRefund() // Commit objects to the trie. for addr, stateObject := range s.stateObjects { - if stateObject.remove { + if stateObject.suicided { // If the object has been removed, don't bother syncing it // and just mark it for deletion in the trie. - s.DeleteStateObject(stateObject) + s.deleteStateObject(stateObject) } else if _, ok := s.stateObjectsDirty[addr]; ok { // Write any contract code associated with the state object if stateObject.code != nil && stateObject.dirtyCode { @@ -529,7 +592,7 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) return common.Hash{}, err } // Update the object in the main account trie. - s.UpdateStateObject(stateObject) + s.updateStateObject(stateObject) } delete(s.stateObjectsDirty, addr) } @@ -540,7 +603,3 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) } return root, err } - -func (self *StateDB) Refunds() *big.Int { - return self.refund -} diff --git a/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go b/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go index f8b11a7ce..10a110e0b 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go +++ b/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go @@ -257,7 +257,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { // Make sure the account exist. Non existent accounts // haven't got funds and well therefor never pass. - if !currentState.HasAccount(from) { + if !currentState.Exist(from) { return ErrNonExistentAccount } diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/block.go b/vendor/github.com/ethereum/go-ethereum/core/types/block.go index 9562c8b9b..4accb0ee3 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/block.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/block.go @@ -104,7 +104,7 @@ type jsonHeader struct { Coinbase *common.Address `json:"miner"` Root *common.Hash `json:"stateRoot"` TxHash *common.Hash `json:"transactionsRoot"` - ReceiptHash *common.Hash `json:"receiptRoot"` + ReceiptHash *common.Hash `json:"receiptsRoot"` Bloom *Bloom `json:"logsBloom"` Difficulty *hexBig `json:"difficulty"` Number *hexBig `json:"number"` diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/contract.go b/vendor/github.com/ethereum/go-ethereum/core/vm/contract.go index 844d3f328..70455a4c2 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/contract.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/contract.go @@ -27,7 +27,7 @@ type ContractRef interface { ReturnGas(*big.Int, *big.Int) Address() common.Address Value() *big.Int - SetCode([]byte) + SetCode(common.Hash, []byte) ForEachStorage(callback func(key, value common.Hash) bool) } @@ -44,8 +44,9 @@ type Contract struct { jumpdests destinations // result of JUMPDEST analysis. Code []byte - Input []byte + CodeHash common.Hash CodeAddr *common.Address + Input []byte value, Gas, UsedGas, Price *big.Int @@ -143,14 +144,16 @@ func (c *Contract) Value() *big.Int { } // SetCode sets the code to the contract -func (self *Contract) SetCode(code []byte) { +func (self *Contract) SetCode(hash common.Hash, code []byte) { self.Code = code + self.CodeHash = hash } // SetCallCode sets the code of the contract and address of the backing data // object -func (self *Contract) SetCallCode(addr *common.Address, code []byte) { +func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { self.Code = code + self.CodeHash = hash self.CodeAddr = addr } diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/environment.go b/vendor/github.com/ethereum/go-ethereum/core/vm/environment.go index 4bd03de7e..a4b2ac196 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/environment.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/environment.go @@ -36,9 +36,9 @@ type Environment interface { // The state database Db() Database // Creates a restorable snapshot - MakeSnapshot() Database + SnapshotDatabase() int // Set database to previous snapshot - SetSnapshot(Database) + RevertToSnapshot(int) // Address of the original invoker (first occurrence of the VM invoker) Origin() common.Address // The block number this VM is invoked on @@ -94,6 +94,7 @@ type Database interface { GetNonce(common.Address) uint64 SetNonce(common.Address, uint64) + GetCodeHash(common.Address) common.Hash GetCodeSize(common.Address) int GetCode(common.Address) []byte SetCode(common.Address, []byte) @@ -104,9 +105,12 @@ type Database interface { GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) - Delete(common.Address) bool + Suicide(common.Address) bool + HasSuicided(common.Address) bool + + // Exist reports whether the given account exists in state. + // Notably this should also return true for suicided accounts. Exist(common.Address) bool - IsDeleted(common.Address) bool } // Account represents a contract or basic ethereum account. @@ -118,7 +122,7 @@ type Account interface { Balance() *big.Int Address() common.Address ReturnGas(*big.Int, *big.Int) - SetCode([]byte) + SetCode(common.Hash, []byte) ForEachStorage(cb func(key, value common.Hash) bool) Value() *big.Int } diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go b/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go index 849a8463c..79aee60d2 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go @@ -614,7 +614,7 @@ func opSuicide(instr instruction, pc *uint64, env Environment, contract *Contrac balance := env.Db().GetBalance(contract.Address()) env.Db().AddBalance(common.BigToAddress(stack.pop()), balance) - env.Db().Delete(contract.Address()) + env.Db().Suicide(contract.Address()) } // following functions are used by the instruction jump table diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/jit.go b/vendor/github.com/ethereum/go-ethereum/core/vm/jit.go index 460a68ddd..55d2e0477 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/jit.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/jit.go @@ -425,7 +425,7 @@ func jitCalculateGasAndSize(env Environment, contract *Contract, instr instructi } gas.Set(g) case SUICIDE: - if !statedb.IsDeleted(contract.Address()) { + if !statedb.HasSuicided(contract.Address()) { statedb.AddRefund(params.SuicideRefundGas) } case MLOAD: diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/env.go b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/env.go index a4793c98f..59fbaa792 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/env.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/env.go @@ -86,11 +86,11 @@ func (self *Env) SetDepth(i int) { self.depth = i } func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool { return self.state.GetBalance(from).Cmp(balance) >= 0 } -func (self *Env) MakeSnapshot() vm.Database { - return self.state.Copy() +func (self *Env) SnapshotDatabase() int { + return self.state.Snapshot() } -func (self *Env) SetSnapshot(copy vm.Database) { - self.state.Set(copy.(*state.StateDB)) +func (self *Env) RevertToSnapshot(snapshot int) { + self.state.RevertToSnapshot(snapshot) } func (self *Env) Transfer(from, to vm.Account, amount *big.Int) { diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go index 309d508c3..6d980cb32 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go @@ -104,7 +104,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { receiver = cfg.State.CreateAccount(common.StringToAddress("contract")) ) // set the receiver's (the executing contract) code for execution. - receiver.SetCode(code) + receiver.SetCode(crypto.Keccak256Hash(code), code) // Call the code with the given configuration. ret, err := vmenv.Call( diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/vm.go b/vendor/github.com/ethereum/go-ethereum/core/vm/vm.go index 9d7b55058..033ada21c 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/vm.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/vm.go @@ -71,10 +71,11 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { return nil, nil } - var ( - codehash = crypto.Keccak256Hash(contract.Code) // codehash is used when doing jump dest caching - program *Program - ) + codehash := contract.CodeHash // codehash is used when doing jump dest caching + if codehash == (common.Hash{}) { + codehash = crypto.Keccak256Hash(contract.Code) + } + var program *Program if evm.cfg.EnableJit { // If the JIT is enabled check the status of the JIT program, // if it doesn't exist compile a new program in a separate @@ -302,7 +303,7 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef } gas.Set(g) case SUICIDE: - if !statedb.IsDeleted(contract.Address()) { + if !statedb.HasSuicided(contract.Address()) { statedb.AddRefund(params.SuicideRefundGas) } case MLOAD: diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm_env.go b/vendor/github.com/ethereum/go-ethereum/core/vm_env.go index e541eaef4..d62eebbd9 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm_env.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm_env.go @@ -89,12 +89,12 @@ func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool { return self.state.GetBalance(from).Cmp(balance) >= 0 } -func (self *VMEnv) MakeSnapshot() vm.Database { - return self.state.Copy() +func (self *VMEnv) SnapshotDatabase() int { + return self.state.Snapshot() } -func (self *VMEnv) SetSnapshot(copy vm.Database) { - self.state.Set(copy.(*state.StateDB)) +func (self *VMEnv) RevertToSnapshot(snapshot int) { + self.state.RevertToSnapshot(snapshot) } func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go index 13e7058fa..46d03ed38 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !amd64 appengine gccgo + package sha3 // rc stores the round constants for use in the ι step. diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go new file mode 100644 index 000000000..de035c550 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!appengine,!gccgo + +package sha3 + +// This function is implemented in keccakf_amd64.s. + +//go:noescape + +func keccakF1600(state *[25]uint64) diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s new file mode 100644 index 000000000..a35335178 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s @@ -0,0 +1,392 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!appengine,!gccgo + +// This code was translated into a form compatible with 6a from the public +// domain sources at https://github.com/gvanas/KeccakCodePackage + +// Offsets in state +#define _ba (0*8) +#define _be (1*8) +#define _bi (2*8) +#define _bo (3*8) +#define _bu (4*8) +#define _ga (5*8) +#define _ge (6*8) +#define _gi (7*8) +#define _go (8*8) +#define _gu (9*8) +#define _ka (10*8) +#define _ke (11*8) +#define _ki (12*8) +#define _ko (13*8) +#define _ku (14*8) +#define _ma (15*8) +#define _me (16*8) +#define _mi (17*8) +#define _mo (18*8) +#define _mu (19*8) +#define _sa (20*8) +#define _se (21*8) +#define _si (22*8) +#define _so (23*8) +#define _su (24*8) + +// Temporary registers +#define rT1 AX + +// Round vars +#define rpState DI +#define rpStack SP + +#define rDa BX +#define rDe CX +#define rDi DX +#define rDo R8 +#define rDu R9 + +#define rBa R10 +#define rBe R11 +#define rBi R12 +#define rBo R13 +#define rBu R14 + +#define rCa SI +#define rCe BP +#define rCi rBi +#define rCo rBo +#define rCu R15 + +#define MOVQ_RBI_RCE MOVQ rBi, rCe +#define XORQ_RT1_RCA XORQ rT1, rCa +#define XORQ_RT1_RCE XORQ rT1, rCe +#define XORQ_RBA_RCU XORQ rBa, rCu +#define XORQ_RBE_RCU XORQ rBe, rCu +#define XORQ_RDU_RCU XORQ rDu, rCu +#define XORQ_RDA_RCA XORQ rDa, rCa +#define XORQ_RDE_RCE XORQ rDe, rCe + +#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \ + /* Prepare round */ \ + MOVQ rCe, rDa; \ + ROLQ $1, rDa; \ + \ + MOVQ _bi(iState), rCi; \ + XORQ _gi(iState), rDi; \ + XORQ rCu, rDa; \ + XORQ _ki(iState), rCi; \ + XORQ _mi(iState), rDi; \ + XORQ rDi, rCi; \ + \ + MOVQ rCi, rDe; \ + ROLQ $1, rDe; \ + \ + MOVQ _bo(iState), rCo; \ + XORQ _go(iState), rDo; \ + XORQ rCa, rDe; \ + XORQ _ko(iState), rCo; \ + XORQ _mo(iState), rDo; \ + XORQ rDo, rCo; \ + \ + MOVQ rCo, rDi; \ + ROLQ $1, rDi; \ + \ + MOVQ rCu, rDo; \ + XORQ rCe, rDi; \ + ROLQ $1, rDo; \ + \ + MOVQ rCa, rDu; \ + XORQ rCi, rDo; \ + ROLQ $1, rDu; \ + \ + /* Result b */ \ + MOVQ _ba(iState), rBa; \ + MOVQ _ge(iState), rBe; \ + XORQ rCo, rDu; \ + MOVQ _ki(iState), rBi; \ + MOVQ _mo(iState), rBo; \ + MOVQ _su(iState), rBu; \ + XORQ rDe, rBe; \ + ROLQ $44, rBe; \ + XORQ rDi, rBi; \ + XORQ rDa, rBa; \ + ROLQ $43, rBi; \ + \ + MOVQ rBe, rCa; \ + MOVQ rc, rT1; \ + ORQ rBi, rCa; \ + XORQ rBa, rT1; \ + XORQ rT1, rCa; \ + MOVQ rCa, _ba(oState); \ + \ + XORQ rDu, rBu; \ + ROLQ $14, rBu; \ + MOVQ rBa, rCu; \ + ANDQ rBe, rCu; \ + XORQ rBu, rCu; \ + MOVQ rCu, _bu(oState); \ + \ + XORQ rDo, rBo; \ + ROLQ $21, rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _bi(oState); \ + \ + NOTQ rBi; \ + ORQ rBa, rBu; \ + ORQ rBo, rBi; \ + XORQ rBo, rBu; \ + XORQ rBe, rBi; \ + MOVQ rBu, _bo(oState); \ + MOVQ rBi, _be(oState); \ + B_RBI_RCE; \ + \ + /* Result g */ \ + MOVQ _gu(iState), rBe; \ + XORQ rDu, rBe; \ + MOVQ _ka(iState), rBi; \ + ROLQ $20, rBe; \ + XORQ rDa, rBi; \ + ROLQ $3, rBi; \ + MOVQ _bo(iState), rBa; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDo, rBa; \ + MOVQ _me(iState), rBo; \ + MOVQ _si(iState), rBu; \ + ROLQ $28, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ga(oState); \ + G_RT1_RCA; \ + \ + XORQ rDe, rBo; \ + ROLQ $45, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ge(oState); \ + G_RT1_RCE; \ + \ + XORQ rDi, rBu; \ + ROLQ $61, rBu; \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _go(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _gu(oState); \ + NOTQ rBu; \ + G_RBA_RCU; \ + \ + ORQ rBu, rBo; \ + XORQ rBi, rBo; \ + MOVQ rBo, _gi(oState); \ + \ + /* Result k */ \ + MOVQ _be(iState), rBa; \ + MOVQ _gi(iState), rBe; \ + MOVQ _ko(iState), rBi; \ + MOVQ _mu(iState), rBo; \ + MOVQ _sa(iState), rBu; \ + XORQ rDi, rBe; \ + ROLQ $6, rBe; \ + XORQ rDo, rBi; \ + ROLQ $25, rBi; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDe, rBa; \ + ROLQ $1, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ka(oState); \ + K_RT1_RCA; \ + \ + XORQ rDu, rBo; \ + ROLQ $8, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ke(oState); \ + K_RT1_RCE; \ + \ + XORQ rDa, rBu; \ + ROLQ $18, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _ki(oState); \ + \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _ko(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _ku(oState); \ + K_RBA_RCU; \ + \ + /* Result m */ \ + MOVQ _ga(iState), rBe; \ + XORQ rDa, rBe; \ + MOVQ _ke(iState), rBi; \ + ROLQ $36, rBe; \ + XORQ rDe, rBi; \ + MOVQ _bu(iState), rBa; \ + ROLQ $10, rBi; \ + MOVQ rBe, rT1; \ + MOVQ _mi(iState), rBo; \ + ANDQ rBi, rT1; \ + XORQ rDu, rBa; \ + MOVQ _so(iState), rBu; \ + ROLQ $27, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ma(oState); \ + M_RT1_RCA; \ + \ + XORQ rDi, rBo; \ + ROLQ $15, rBo; \ + MOVQ rBi, rT1; \ + ORQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _me(oState); \ + M_RT1_RCE; \ + \ + XORQ rDo, rBu; \ + ROLQ $56, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ORQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _mi(oState); \ + \ + ORQ rBa, rBe; \ + XORQ rBu, rBe; \ + MOVQ rBe, _mu(oState); \ + \ + ANDQ rBa, rBu; \ + XORQ rBo, rBu; \ + MOVQ rBu, _mo(oState); \ + M_RBE_RCU; \ + \ + /* Result s */ \ + MOVQ _bi(iState), rBa; \ + MOVQ _go(iState), rBe; \ + MOVQ _ku(iState), rBi; \ + XORQ rDi, rBa; \ + MOVQ _ma(iState), rBo; \ + ROLQ $62, rBa; \ + XORQ rDo, rBe; \ + MOVQ _se(iState), rBu; \ + ROLQ $55, rBe; \ + \ + XORQ rDu, rBi; \ + MOVQ rBa, rDu; \ + XORQ rDe, rBu; \ + ROLQ $2, rBu; \ + ANDQ rBe, rDu; \ + XORQ rBu, rDu; \ + MOVQ rDu, _su(oState); \ + \ + ROLQ $39, rBi; \ + S_RDU_RCU; \ + NOTQ rBe; \ + XORQ rDa, rBo; \ + MOVQ rBe, rDa; \ + ANDQ rBi, rDa; \ + XORQ rBa, rDa; \ + MOVQ rDa, _sa(oState); \ + S_RDA_RCA; \ + \ + ROLQ $41, rBo; \ + MOVQ rBi, rDe; \ + ORQ rBo, rDe; \ + XORQ rBe, rDe; \ + MOVQ rDe, _se(oState); \ + S_RDE_RCE; \ + \ + MOVQ rBo, rDi; \ + MOVQ rBu, rDo; \ + ANDQ rBu, rDi; \ + ORQ rBa, rDo; \ + XORQ rBi, rDi; \ + XORQ rBo, rDo; \ + MOVQ rDi, _si(oState); \ + MOVQ rDo, _so(oState) \ + +// func keccakF1600(state *[25]uint64) +TEXT ·keccakF1600(SB), 0, $200-8 + MOVQ state+0(FP), rpState + SUBQ $(8*25), SP + + // Convert the user state into an internal state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + // Execute the KeccakF permutation + MOVQ _ba(rpState), rCa + MOVQ _be(rpState), rCe + MOVQ _bu(rpState), rCu + + XORQ _ga(rpState), rCa + XORQ _ge(rpState), rCe + XORQ _gu(rpState), rCu + + XORQ _ka(rpState), rCa + XORQ _ke(rpState), rCe + XORQ _ku(rpState), rCu + + XORQ _ma(rpState), rCa + XORQ _me(rpState), rCe + XORQ _mu(rpState), rCu + + XORQ _sa(rpState), rCa + XORQ _se(rpState), rCe + MOVQ _si(rpState), rDi + MOVQ _so(rpState), rDo + XORQ _su(rpState), rCu + + mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) + + // Revert the internal state to the user state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + ADDQ $(8*25), SP + RET diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go index c8fd31cb0..c86167c0b 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go @@ -42,7 +42,7 @@ type state struct { storage [maxRate]byte // Specific to SHA-3 and SHAKE. - fixedOutput bool // whether this is a fixed-ouput-length instance + fixedOutput bool // whether this is a fixed-output-length instance outputLen int // the default output size in bytes state spongeDirection // whether the sponge is absorbing or squeezing } diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go index d622979c1..46a0d63a6 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!386 appengine +// +build !amd64,!386,!ppc64le appengine package sha3 diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go index c7851a1d8..929a486a7 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 386 +// +build amd64 386 ppc64le // +build !appengine package sha3 diff --git a/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go b/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go index 58dd70d54..639f186c1 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go @@ -98,12 +98,12 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { } func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { - stateDb := state.(EthApiState).state.Copy() + statedb := state.(EthApiState).state addr, _ := msg.From() - from := stateDb.GetOrNewStateObject(addr) + from := statedb.GetOrNewStateObject(addr) from.SetBalance(common.MaxBig) vmError := func() error { return nil } - return core.NewEnv(stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil + return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil } func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { diff --git a/vendor/github.com/ethereum/go-ethereum/eth/handler.go b/vendor/github.com/ethereum/go-ethereum/eth/handler.go index cad9075db..f4dd3ade8 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/handler.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/handler.go @@ -17,6 +17,7 @@ package eth import ( + "encoding/json" "errors" "fmt" "math" @@ -375,14 +376,24 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } case query.Origin.Hash != (common.Hash{}) && !query.Reverse: // Hash based traversal towards the leaf block - if header := pm.blockchain.GetHeaderByNumber(origin.Number.Uint64() + query.Skip + 1); header != nil { - if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { - query.Origin.Hash = header.Hash() + var ( + current = origin.Number.Uint64() + next = current + query.Skip + 1 + ) + if next <= current { + infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ") + glog.V(logger.Warn).Infof("%v: GetBlockHeaders skip overflow attack (current %v, skip %v, next %v)\nMalicious peer infos: %s", p, current, query.Skip, next, infos) + unknown = true + } else { + if header := pm.blockchain.GetHeaderByNumber(next); header != nil { + if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { + query.Origin.Hash = header.Hash() + } else { + unknown = true + } } else { unknown = true } - } else { - unknown = true } case query.Reverse: // Number based traversal towards the genesis block diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/database.go b/vendor/github.com/ethereum/go-ethereum/ethdb/database.go index a0a6efbad..96d9a5982 100644 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/database.go +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/database.go @@ -102,6 +102,11 @@ func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) { }, nil } +// Path returns the path to the database directory. +func (db *LDBDatabase) Path() string { + return db.fn +} + // Put puts the given key / value to the queue func (self *LDBDatabase) Put(key []byte, value []byte) error { // Measure the database put latency, if requested diff --git a/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go b/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go index 53237f4e4..861e79951 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go @@ -614,7 +614,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "gasUsed": rpc.NewHexNumber(head.GasUsed), "timestamp": rpc.NewHexNumber(head.Time), "transactionsRoot": head.TxHash, - "receiptRoot": head.ReceiptHash, + "receiptsRoot": head.ReceiptHash, } if inclTx { @@ -1238,8 +1238,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction { // Resend accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the // pool and reinsert it with the new gas price and limit. -func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx *Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { - +func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { pending := s.b.GetPoolTransactions() for _, p := range pending { if pFrom, err := p.FromFrontier(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() { @@ -1252,9 +1251,9 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx *Tx, gasPrice, var newTx *types.Transaction if tx.tx.To() == nil { - newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data()) + newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data()) } else { - newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data()) + newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data()) } signedTx, err := s.sign(tx.From, newTx) diff --git a/vendor/github.com/ethereum/go-ethereum/light/state.go b/vendor/github.com/ethereum/go-ethereum/light/state.go index a2faf0ca3..fc7b36221 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/state.go +++ b/vendor/github.com/ethereum/go-ethereum/light/state.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "golang.org/x/net/context" @@ -156,7 +157,7 @@ func (self *LightState) SetNonce(ctx context.Context, addr common.Address, nonce func (self *LightState) SetCode(ctx context.Context, addr common.Address, code []byte) error { stateObject, err := self.GetOrNewStateObject(ctx, addr) if err == nil && stateObject != nil { - stateObject.SetCode(code) + stateObject.SetCode(crypto.Keccak256Hash(code), code) } return err } diff --git a/vendor/github.com/ethereum/go-ethereum/light/state_object.go b/vendor/github.com/ethereum/go-ethereum/light/state_object.go index 9cb677487..61c3888fe 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/state_object.go +++ b/vendor/github.com/ethereum/go-ethereum/light/state_object.go @@ -217,9 +217,9 @@ func (self *StateObject) Code() []byte { } // SetCode sets the contract code -func (self *StateObject) SetCode(code []byte) { +func (self *StateObject) SetCode(hash common.Hash, code []byte) { self.code = code - self.codeHash = crypto.Keccak256(code) + self.codeHash = hash[:] self.dirty = true } diff --git a/vendor/github.com/ethereum/go-ethereum/light/vm_env.go b/vendor/github.com/ethereum/go-ethereum/light/vm_env.go index 596143795..d18e97b08 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/vm_env.go +++ b/vendor/github.com/ethereum/go-ethereum/light/vm_env.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "golang.org/x/net/context" ) @@ -40,10 +41,7 @@ type VMEnv struct { msg core.Message depth int chain *LightChain - typ vm.Type - // structured logging - logs []vm.StructLog - err error + err error } // NewEnv creates a new execution environment based on an ODR capable light state @@ -53,7 +51,6 @@ func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfi chain: chain, header: header, msg: msg, - typ: vm.StdVmTy, } env.state = &VMState{ctx: ctx, state: state, env: env} @@ -69,12 +66,9 @@ func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } func (self *VMEnv) Time() *big.Int { return self.header.Time } func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } -func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) Db() vm.Database { return self.state } func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) VmType() vm.Type { return self.typ } -func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } func (self *VMEnv) GetHash(n uint64) common.Hash { for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { if header.GetNumberU64() == n { @@ -92,12 +86,12 @@ func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool { return self.state.GetBalance(from).Cmp(balance) >= 0 } -func (self *VMEnv) MakeSnapshot() vm.Database { - return &VMState{ctx: self.ctx, state: self.state.state.Copy(), env: self} +func (self *VMEnv) SnapshotDatabase() int { + return self.state.SnapshotDatabase() } -func (self *VMEnv) SetSnapshot(copy vm.Database) { - self.state.state.Set(copy.(*VMState).state) +func (self *VMEnv) RevertToSnapshot(idx int) { + self.state.RevertToSnapshot(idx) } func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { @@ -111,18 +105,14 @@ func (self *VMEnv) CallCode(me vm.ContractRef, addr common.Address, data []byte, return core.CallCode(self, me, addr, data, gas, price, value) } +func (self *VMEnv) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { + return core.DelegateCall(self, me, addr, data, gas, price) +} + func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { return core.Create(self, me, data, gas, price, value) } -func (self *VMEnv) StructLogs() []vm.StructLog { - return self.logs -} - -func (self *VMEnv) AddStructLog(log vm.StructLog) { - self.logs = append(self.logs, log) -} - // Error returns the error (if any) that happened during execution. func (self *VMEnv) Error() error { return self.err @@ -132,9 +122,10 @@ func (self *VMEnv) Error() error { // passes it to any state operation that requires it. type VMState struct { vm.Database - ctx context.Context - state *LightState - env *VMEnv + ctx context.Context + state *LightState + snapshots []*LightState + env *VMEnv } // errHandler handles and stores any state error that happens during execution. @@ -144,6 +135,16 @@ func (s *VMState) errHandler(err error) { } } +func (self *VMState) SnapshotDatabase() int { + self.snapshots = append(self.snapshots, self.state.Copy()) + return len(self.snapshots) - 1 +} + +func (self *VMState) RevertToSnapshot(idx int) { + self.state.Set(self.snapshots[idx]) + self.snapshots = self.snapshots[:idx] +} + // GetAccount returns the account object of the given account or nil if the // account does not exist func (s *VMState) GetAccount(addr common.Address) vm.Account { @@ -203,6 +204,18 @@ func (s *VMState) GetCode(addr common.Address) []byte { return res } +func (s *VMState) GetCodeHash(addr common.Address) common.Hash { + res, err := s.state.GetCode(s.ctx, addr) + s.errHandler(err) + return crypto.Keccak256Hash(res) +} + +func (s *VMState) GetCodeSize(addr common.Address) int { + res, err := s.state.GetCode(s.ctx, addr) + s.errHandler(err) + return len(res) +} + // SetCode sets the contract code at the specified account func (s *VMState) SetCode(addr common.Address, code []byte) { err := s.state.SetCode(s.ctx, addr, code) @@ -234,7 +247,7 @@ func (s *VMState) SetState(addr common.Address, key common.Hash, value common.Ha } // Delete marks an account to be removed and clears its balance -func (s *VMState) Delete(addr common.Address) bool { +func (s *VMState) Suicide(addr common.Address) bool { res, err := s.state.Delete(s.ctx, addr) s.errHandler(err) return res @@ -249,7 +262,7 @@ func (s *VMState) Exist(addr common.Address) bool { // IsDeleted returns true if the given account has been marked for deletion // or false if the account does not exist -func (s *VMState) IsDeleted(addr common.Address) bool { +func (s *VMState) HasSuicided(addr common.Address) bool { res, err := s.state.IsDeleted(s.ctx, addr) s.errHandler(err) return res diff --git a/vendor/github.com/ethereum/go-ethereum/miner/worker.go b/vendor/github.com/ethereum/go-ethereum/miner/worker.go index ac1ef5ba3..e5348cef4 100644 --- a/vendor/github.com/ethereum/go-ethereum/miner/worker.go +++ b/vendor/github.com/ethereum/go-ethereum/miner/worker.go @@ -171,7 +171,7 @@ func (self *worker) pending() (*types.Block, *state.StateDB) { self.current.receipts, ), self.current.state } - return self.current.Block, self.current.state + return self.current.Block, self.current.state.Copy() } func (self *worker) start() { @@ -618,7 +618,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB } func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) { - snap := env.state.Copy() + snap := env.state.Snapshot() // this is a bit of a hack to force jit for the miners config := env.config.VmConfig @@ -629,7 +629,7 @@ func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, g receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config) if err != nil { - env.state.Set(snap) + env.state.RevertToSnapshot(snap) return err, nil } env.txs = append(env.txs, tx) diff --git a/vendor/github.com/ethereum/go-ethereum/node/api.go b/vendor/github.com/ethereum/go-ethereum/node/api.go index 3523874ab..631e92c8e 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/api.go +++ b/vendor/github.com/ethereum/go-ethereum/node/api.go @@ -84,17 +84,17 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st } if host == nil { - h := common.DefaultHTTPHost - if api.node.httpHost != "" { - h = api.node.httpHost + h := DefaultHTTPHost + if api.node.config.HTTPHost != "" { + h = api.node.config.HTTPHost } host = &h } if port == nil { - port = rpc.NewHexNumber(api.node.httpPort) + port = rpc.NewHexNumber(api.node.config.HTTPPort) } if cors == nil { - cors = &api.node.httpCors + cors = &api.node.config.HTTPCors } modules := api.node.httpWhitelist @@ -133,20 +133,20 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr } if host == nil { - h := common.DefaultWSHost - if api.node.wsHost != "" { - h = api.node.wsHost + h := DefaultWSHost + if api.node.config.WSHost != "" { + h = api.node.config.WSHost } host = &h } if port == nil { - port = rpc.NewHexNumber(api.node.wsPort) + port = rpc.NewHexNumber(api.node.config.WSPort) } if allowedOrigins == nil { - allowedOrigins = &api.node.wsOrigins + allowedOrigins = &api.node.config.WSOrigins } - modules := api.node.wsWhitelist + modules := api.node.config.WSModules if apis != nil { modules = nil for _, m := range strings.Split(*apis, ",") { diff --git a/vendor/github.com/ethereum/go-ethereum/node/config.go b/vendor/github.com/ethereum/go-ethereum/node/config.go index 432da7015..15884a12e 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/config.go +++ b/vendor/github.com/ethereum/go-ethereum/node/config.go @@ -18,7 +18,6 @@ package node import ( "crypto/ecdsa" - "encoding/json" "fmt" "io/ioutil" "net" @@ -48,6 +47,18 @@ var ( // P2P network layer of a protocol stack. These values can be further extended by // all registered services. type Config struct { + // Name sets the instance name of the node. It must not contain the / character and is + // used in the devp2p node identifier. The instance name of geth is "geth". If no + // value is specified, the basename of the current executable is used. + Name string + + // UserIdent, if set, is used as an additional component in the devp2p node identifier. + UserIdent string + + // Version should be set to the version number of the program. It is used + // in the devp2p node identifier. + Version string + // DataDir is the file system folder the node should use for any data storage // requirements. The configured data directory will not be directly shared with // registered services, instead those can use utility methods to create/access @@ -80,10 +91,6 @@ type Config struct { // needed. PrivateKey *ecdsa.PrivateKey - // Name sets the node name of this server. Use common.MakeName to create a name - // that follows existing conventions. - Name string - // NoDiscovery specifies whether the peer discovery mechanism should be started // or not. Disabling is usually useful for protocol debugging (manual topology). NoDiscovery bool @@ -178,9 +185,23 @@ func (c *Config) IPCEndpoint() string { return c.IPCPath } +// NodeDB returns the path to the discovery node database. +func (c *Config) NodeDB() string { + if c.DataDir == "" { + return "" // ephemeral + } + return c.resolvePath("nodes") +} + // DefaultIPCEndpoint returns the IPC path used by default. -func DefaultIPCEndpoint() string { - config := &Config{DataDir: common.DefaultDataDir(), IPCPath: common.DefaultIPCSocket} +func DefaultIPCEndpoint(clientIdentifier string) string { + if clientIdentifier == "" { + clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") + if clientIdentifier == "" { + panic("empty executable name") + } + } + config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"} return config.IPCEndpoint() } @@ -195,7 +216,7 @@ func (c *Config) HTTPEndpoint() string { // DefaultHTTPEndpoint returns the HTTP endpoint used by default. func DefaultHTTPEndpoint() string { - config := &Config{HTTPHost: common.DefaultHTTPHost, HTTPPort: common.DefaultHTTPPort} + config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort} return config.HTTPEndpoint() } @@ -210,19 +231,80 @@ func (c *Config) WSEndpoint() string { // DefaultWSEndpoint returns the websocket endpoint used by default. func DefaultWSEndpoint() string { - config := &Config{WSHost: common.DefaultWSHost, WSPort: common.DefaultWSPort} + config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort} return config.WSEndpoint() } +// NodeName returns the devp2p node identifier. +func (c *Config) NodeName() string { + name := c.name() + // Backwards compatibility: previous versions used title-cased "Geth", keep that. + if name == "geth" || name == "geth-testnet" { + name = "Geth" + } + if c.UserIdent != "" { + name += "/" + c.UserIdent + } + if c.Version != "" { + name += "/v" + c.Version + } + name += "/" + runtime.GOOS + name += "/" + runtime.Version() + return name +} + +func (c *Config) name() string { + if c.Name == "" { + progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") + if progname == "" { + panic("empty executable name, set Config.Name") + } + return progname + } + return c.Name +} + +// These resources are resolved differently for the "geth" and "geth-testnet" instances. +var isOldGethResource = map[string]bool{ + "chaindata": true, + "nodes": true, + "nodekey": true, + "static-nodes.json": true, + "trusted-nodes.json": true, +} + +// resolvePath resolves path in the instance directory. +func (c *Config) resolvePath(path string) string { + if filepath.IsAbs(path) { + return path + } + if c.DataDir == "" { + return "" + } + // Backwards-compatibility: ensure that data directory files created + // by geth 1.4 are used if they exist. + if c.name() == "geth" && isOldGethResource[path] { + oldpath := "" + if c.Name == "geth" { + oldpath = filepath.Join(c.DataDir, path) + } + if oldpath != "" && common.FileExist(oldpath) { + // TODO: print warning + return oldpath + } + } + return filepath.Join(c.DataDir, c.name(), path) +} + // NodeKey retrieves the currently configured private key of the node, checking // first any manually set key, falling back to the one found in the configured // data folder. If no key can be found, a new one is generated. func (c *Config) NodeKey() *ecdsa.PrivateKey { - // Use any specifically configured key + // Use any specifically configured key. if c.PrivateKey != nil { return c.PrivateKey } - // Generate ephemeral key if no datadir is being used + // Generate ephemeral key if no datadir is being used. if c.DataDir == "" { key, err := crypto.GenerateKey() if err != nil { @@ -230,16 +312,22 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { } return key } - // Fall back to persistent key from the data directory - keyfile := filepath.Join(c.DataDir, datadirPrivateKey) + + keyfile := c.resolvePath(datadirPrivateKey) if key, err := crypto.LoadECDSA(keyfile); err == nil { return key } - // No persistent key found, generate and store a new one + // No persistent key found, generate and store a new one. key, err := crypto.GenerateKey() if err != nil { glog.Fatalf("Failed to generate node key: %v", err) } + instanceDir := filepath.Join(c.DataDir, c.name()) + if err := os.MkdirAll(instanceDir, 0700); err != nil { + glog.V(logger.Error).Infof("Failed to persist node key: %v", err) + return key + } + keyfile = filepath.Join(instanceDir, datadirPrivateKey) if err := crypto.SaveECDSA(keyfile, key); err != nil { glog.V(logger.Error).Infof("Failed to persist node key: %v", err) } @@ -248,12 +336,12 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { // StaticNodes returns a list of node enode URLs configured as static nodes. func (c *Config) StaticNodes() []*discover.Node { - return c.parsePersistentNodes(datadirStaticNodes) + return c.parsePersistentNodes(c.resolvePath(datadirStaticNodes)) } // TrusterNodes returns a list of node enode URLs configured as trusted nodes. func (c *Config) TrusterNodes() []*discover.Node { - return c.parsePersistentNodes(datadirTrustedNodes) + return c.parsePersistentNodes(c.resolvePath(datadirTrustedNodes)) } // parsePersistentNodes parses a list of discovery node URLs loaded from a .json @@ -267,15 +355,10 @@ func (c *Config) parsePersistentNodes(file string) []*discover.Node { if _, err := os.Stat(path); err != nil { return nil } - // Load the nodes from the config file - blob, err := ioutil.ReadFile(path) - if err != nil { - glog.V(logger.Error).Infof("Failed to access nodes: %v", err) - return nil - } - nodelist := []string{} - if err := json.Unmarshal(blob, &nodelist); err != nil { - glog.V(logger.Error).Infof("Failed to load nodes: %v", err) + // Load the nodes from the config file. + var nodelist []string + if err := common.LoadJSON(path, &nodelist); err != nil { + glog.V(logger.Error).Infof("Can't load node file %s: %v", path, err) return nil } // Interpret the list as a discovery node array diff --git a/vendor/github.com/ethereum/go-ethereum/common/defaults.go b/vendor/github.com/ethereum/go-ethereum/node/defaults.go similarity index 89% rename from vendor/github.com/ethereum/go-ethereum/common/defaults.go rename to vendor/github.com/ethereum/go-ethereum/node/defaults.go index 8a136fa80..bfe257c8e 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/defaults.go +++ b/vendor/github.com/ethereum/go-ethereum/node/defaults.go @@ -14,9 +14,11 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package common +package node import ( + "os" + "os/user" "path/filepath" "runtime" ) @@ -33,7 +35,7 @@ const ( // persistence requirements. func DefaultDataDir() string { // Try to place the data folder in the user's home dir - home := HomeDir() + home := homeDir() if home != "" { if runtime.GOOS == "darwin" { return filepath.Join(home, "Library", "Ethereum") @@ -46,3 +48,13 @@ func DefaultDataDir() string { // As we cannot guess a stable location, return empty and handle later return "" } + +func homeDir() string { + if home := os.Getenv("HOME"); home != "" { + return home + } + if usr, err := user.Current(); err == nil { + return usr.HomeDir + } + return "" +} diff --git a/vendor/github.com/ethereum/go-ethereum/node/doc.go b/vendor/github.com/ethereum/go-ethereum/node/doc.go new file mode 100644 index 000000000..f009e6f85 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/node/doc.go @@ -0,0 +1,90 @@ +// Copyright 2016 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 . + +/* +Package node sets up multi-protocol Ethereum nodes. + +In the model exposed by this package, a node is a collection of services which use shared +resources to provide RPC APIs. Services can also offer devp2p protocols, which are wired +up to the devp2p network when the node instance is started. + + +Resources Managed By Node + +All file-system resources used by a node instance are located in a directory called the +data directory. The location of each resource can be overridden through additional node +configuration. The data directory is optional. If it is not set and the location of a +resource is otherwise unspecified, package node will create the resource in memory. + +To access to the devp2p network, Node configures and starts p2p.Server. Each host on the +devp2p network has a unique identifier, the node key. The Node instance persists this key +across restarts. Node also loads static and trusted node lists and ensures that knowledge +about other hosts is persisted. + +JSON-RPC servers which run HTTP, WebSocket or IPC can be started on a Node. RPC modules +offered by registered services will be offered on those endpoints. Users can restrict any +endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3" +modules. + +Service implementations can open LevelDB databases through the service context. Package +node chooses the file system location of each database. If the node is configured to run +without a data directory, databases are opened in memory instead. + +Node also creates the shared store of encrypted Ethereum account keys. Services can access +the account manager through the service context. + + +Sharing Data Directory Among Instances + +Multiple node instances can share a single data directory if they have distinct instance +names (set through the Name config option). Sharing behaviour depends on the type of +resource. + +devp2p-related resources (node key, static/trusted node lists, known hosts database) are +stored in a directory with the same name as the instance. Thus, multiple node instances +using the same data directory will store this information in different subdirectories of +the data directory. + +LevelDB databases are also stored within the instance subdirectory. If multiple node +instances use the same data directory, openening the databases with identical names will +create one database for each instance. + +The account key store is shared among all node instances using the same data directory +unless its location is changed through the KeyStoreDir configuration option. + + +Data Directory Sharing Example + +In this exanple, two node instances named A and B are started with the same data +directory. Mode instance A opens the database "db", node instance B opens the databases +"db" and "db-2". The following files will be created in the data directory: + + data-directory/ + A/ + nodekey -- devp2p node key of instance A + nodes/ -- devp2p discovery knowledge database of instance A + db/ -- LevelDB content for "db" + A.ipc -- JSON-RPC UNIX domain socket endpoint of instance A + B/ + nodekey -- devp2p node key of node B + nodes/ -- devp2p discovery knowledge database of instance B + static-nodes.json -- devp2p static node list of instance B + db/ -- LevelDB content for "db" + db-2/ -- LevelDB content for "db-2" + B.ipc -- JSON-RPC UNIX domain socket endpoint of instance A + keystore/ -- account key store, used by both instances +*/ +package node diff --git a/vendor/github.com/ethereum/go-ethereum/node/node.go b/vendor/github.com/ethereum/go-ethereum/node/node.go index f3be2f763..41c9eb27f 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/node.go +++ b/vendor/github.com/ethereum/go-ethereum/node/node.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package node represents the Ethereum protocol stack container. package node import ( @@ -23,16 +22,19 @@ import ( "os" "path/filepath" "reflect" + "strings" "sync" "syscall" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" + "github.com/syndtr/goleveldb/leveldb/storage" ) var ( @@ -44,14 +46,14 @@ var ( datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} ) -// Node represents a P2P node into which arbitrary (uniquely typed) services might -// be registered. +// Node is a container on which services can be registered. type Node struct { - datadir string // Path to the currently used data directory eventmux *event.TypeMux // Event multiplexer used between the services of a stack + config *Config + accman *accounts.Manager - accman *accounts.Manager - ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop + ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop + instanceDirLock storage.Storage // prevents concurrent use of instance directory serverConfig p2p.Config server *p2p.Server // Currently running P2P networking layer @@ -66,21 +68,14 @@ type Node struct { ipcListener net.Listener // IPC RPC listener socket to serve API requests ipcHandler *rpc.Server // IPC RPC request handler to process the API requests - httpHost string // HTTP hostname - httpPort int // HTTP post httpEndpoint string // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled) httpWhitelist []string // HTTP RPC modules to allow through this endpoint - httpCors string // HTTP RPC Cross-Origin Resource Sharing header httpListener net.Listener // HTTP RPC listener socket to server API requests httpHandler *rpc.Server // HTTP RPC request handler to process the API requests - wsHost string // Websocket host - wsPort int // Websocket post - wsEndpoint string // Websocket endpoint (interface + port) to listen at (empty = websocket disabled) - wsWhitelist []string // Websocket RPC modules to allow through this endpoint - wsOrigins string // Websocket RPC allowed origin domains - wsListener net.Listener // Websocket RPC listener socket to server API requests - wsHandler *rpc.Server // Websocket RPC request handler to process the API requests + wsEndpoint string // Websocket endpoint (interface + port) to listen at (empty = websocket disabled) + wsListener net.Listener // Websocket RPC listener socket to server API requests + wsHandler *rpc.Server // Websocket RPC request handler to process the API requests stop chan struct{} // Channel to wait for termination notifications lock sync.RWMutex @@ -88,54 +83,45 @@ type Node struct { // New creates a new P2P node, ready for protocol registration. func New(conf *Config) (*Node, error) { - // Ensure the data directory exists, failing if it cannot be created + // Copy config and resolve the datadir so future changes to the current + // working directory don't affect the node. + confCopy := *conf + conf = &confCopy if conf.DataDir != "" { - if err := os.MkdirAll(conf.DataDir, 0700); err != nil { + absdatadir, err := filepath.Abs(conf.DataDir) + if err != nil { return nil, err } + conf.DataDir = absdatadir } + // Ensure that the instance name doesn't cause weird conflicts with + // other files in the data directory. + if strings.ContainsAny(conf.Name, `/\`) { + return nil, errors.New(`Config.Name must not contain '/' or '\'`) + } + if conf.Name == datadirDefaultKeyStore { + return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`) + } + if strings.HasSuffix(conf.Name, ".ipc") { + return nil, errors.New(`Config.Name cannot end in ".ipc"`) + } + // Ensure that the AccountManager method works before the node has started. + // We rely on this in cmd/geth. am, ephemeralKeystore, err := makeAccountManager(conf) if err != nil { return nil, err } - - // Assemble the networking layer and the node itself - nodeDbPath := "" - if conf.DataDir != "" { - nodeDbPath = filepath.Join(conf.DataDir, datadirNodeDatabase) - } + // Note: any interaction with Config that would create/touch files + // in the data directory or instance directory is delayed until Start. return &Node{ - datadir: conf.DataDir, accman: am, ephemeralKeystore: ephemeralKeystore, - serverConfig: p2p.Config{ - PrivateKey: conf.NodeKey(), - Name: conf.Name, - Discovery: !conf.NoDiscovery, - BootstrapNodes: conf.BootstrapNodes, - StaticNodes: conf.StaticNodes(), - TrustedNodes: conf.TrusterNodes(), - NodeDatabase: nodeDbPath, - ListenAddr: conf.ListenAddr, - NAT: conf.NAT, - Dialer: conf.Dialer, - NoDial: conf.NoDial, - MaxPeers: conf.MaxPeers, - MaxPendingPeers: conf.MaxPendingPeers, - }, - serviceFuncs: []ServiceConstructor{}, - ipcEndpoint: conf.IPCEndpoint(), - httpHost: conf.HTTPHost, - httpPort: conf.HTTPPort, - httpEndpoint: conf.HTTPEndpoint(), - httpWhitelist: conf.HTTPModules, - httpCors: conf.HTTPCors, - wsHost: conf.WSHost, - wsPort: conf.WSPort, - wsEndpoint: conf.WSEndpoint(), - wsWhitelist: conf.WSModules, - wsOrigins: conf.WSOrigins, - eventmux: new(event.TypeMux), + config: conf, + serviceFuncs: []ServiceConstructor{}, + ipcEndpoint: conf.IPCEndpoint(), + httpEndpoint: conf.HTTPEndpoint(), + wsEndpoint: conf.WSEndpoint(), + eventmux: new(event.TypeMux), }, nil } @@ -161,13 +147,36 @@ func (n *Node) Start() error { if n.server != nil { return ErrNodeRunning } - // Otherwise copy and specialize the P2P configuration + if err := n.openDataDir(); err != nil { + return err + } + + // Initialize the p2p server. This creates the node key and + // discovery databases. + n.serverConfig = p2p.Config{ + PrivateKey: n.config.NodeKey(), + Name: n.config.NodeName(), + Discovery: !n.config.NoDiscovery, + BootstrapNodes: n.config.BootstrapNodes, + StaticNodes: n.config.StaticNodes(), + TrustedNodes: n.config.TrusterNodes(), + NodeDatabase: n.config.NodeDB(), + ListenAddr: n.config.ListenAddr, + NAT: n.config.NAT, + Dialer: n.config.Dialer, + NoDial: n.config.NoDial, + MaxPeers: n.config.MaxPeers, + MaxPendingPeers: n.config.MaxPendingPeers, + } running := &p2p.Server{Config: n.serverConfig} + glog.V(logger.Info).Infoln("instance:", n.serverConfig.Name) + + // Otherwise copy and specialize the P2P configuration services := make(map[reflect.Type]Service) for _, constructor := range n.serviceFuncs { // Create a new context for the particular service ctx := &ServiceContext{ - datadir: n.datadir, + config: n.config, services: make(map[reflect.Type]Service), EventMux: n.eventmux, AccountManager: n.accman, @@ -227,6 +236,26 @@ func (n *Node) Start() error { return nil } +func (n *Node) openDataDir() error { + if n.config.DataDir == "" { + return nil // ephemeral + } + + instdir := filepath.Join(n.config.DataDir, n.config.name()) + if err := os.MkdirAll(instdir, 0700); err != nil { + return err + } + // Try to open the instance directory as LevelDB storage. This creates a lock file + // which prevents concurrent use by another instance as well as accidental use of the + // instance directory as a database. + storage, err := storage.OpenFile(instdir, true) + if err != nil { + return err + } + n.instanceDirLock = storage + return nil +} + // startRPC is a helper method to start all the various RPC endpoint during node // startup. It's not meant to be called at any time afterwards as it makes certain // assumptions about the state of the node. @@ -244,12 +273,12 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error { n.stopInProc() return err } - if err := n.startHTTP(n.httpEndpoint, apis, n.httpWhitelist, n.httpCors); err != nil { + if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil { n.stopIPC() n.stopInProc() return err } - if err := n.startWS(n.wsEndpoint, apis, n.wsWhitelist, n.wsOrigins); err != nil { + if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins); err != nil { n.stopHTTP() n.stopIPC() n.stopInProc() @@ -381,7 +410,6 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors n.httpEndpoint = endpoint n.httpListener = listener n.httpHandler = handler - n.httpCors = cors return nil } @@ -436,7 +464,6 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig n.wsEndpoint = endpoint n.wsListener = listener n.wsHandler = handler - n.wsOrigins = wsOrigins return nil } @@ -465,12 +492,12 @@ func (n *Node) Stop() error { if n.server == nil { return ErrNodeStopped } - // Otherwise terminate the API, all services and the P2P server too + + // Terminate the API, services and the p2p server. n.stopWS() n.stopHTTP() n.stopIPC() n.rpcAPIs = nil - failure := &StopError{ Services: make(map[reflect.Type]error), } @@ -480,9 +507,16 @@ func (n *Node) Stop() error { } } n.server.Stop() - n.services = nil n.server = nil + + // Release instance directory lock. + if n.instanceDirLock != nil { + n.instanceDirLock.Close() + n.instanceDirLock = nil + } + + // unblock n.Wait close(n.stop) // Remove the keystore if it was created ephemerally. @@ -566,7 +600,7 @@ func (n *Node) Service(service interface{}) error { // DataDir retrieves the current datadir used by the protocol stack. func (n *Node) DataDir() string { - return n.datadir + return n.config.DataDir } // AccountManager retrieves the account manager used by the protocol stack. @@ -595,6 +629,21 @@ func (n *Node) EventMux() *event.TypeMux { return n.eventmux } +// OpenDatabase opens an existing database with the given name (or creates one if no +// previous can be found) from within the node's instance directory. If the node is +// ephemeral, a memory database is returned. +func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { + if n.config.DataDir == "" { + return ethdb.NewMemDatabase() + } + return ethdb.NewLDBDatabase(n.config.resolvePath(name), cache, handles) +} + +// ResolvePath returns the absolute path of a resource in the instance directory. +func (n *Node) ResolvePath(x string) string { + return n.config.resolvePath(x) +} + // apis returns the collection of RPC descriptors this node offers. func (n *Node) apis() []rpc.API { return []rpc.API{ diff --git a/vendor/github.com/ethereum/go-ethereum/node/service.go b/vendor/github.com/ethereum/go-ethereum/node/service.go index 51531466b..1cd1fe808 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/service.go +++ b/vendor/github.com/ethereum/go-ethereum/node/service.go @@ -17,7 +17,6 @@ package node import ( - "path/filepath" "reflect" "github.com/ethereum/go-ethereum/accounts" @@ -31,7 +30,7 @@ import ( // the protocol stack, that is passed to all constructors to be optionally used; // as well as utility methods to operate on the service environment. type ServiceContext struct { - datadir string // Data directory for protocol persistence + config *Config services map[reflect.Type]Service // Index of the already constructed services EventMux *event.TypeMux // Event multiplexer used for decoupled notifications AccountManager *accounts.Manager // Account manager created by the node. @@ -41,10 +40,10 @@ type ServiceContext struct { // if no previous can be found) from within the node's data directory. If the // node is an ephemeral one, a memory database is returned. func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (ethdb.Database, error) { - if ctx.datadir == "" { + if ctx.config.DataDir == "" { return ethdb.NewMemDatabase() } - return ethdb.NewLDBDatabase(filepath.Join(ctx.datadir, name), cache, handles) + return ethdb.NewLDBDatabase(ctx.config.resolvePath(name), cache, handles) } // Service retrieves a currently running service registered of a specific type. @@ -64,11 +63,13 @@ type ServiceConstructor func(ctx *ServiceContext) (Service, error) // Service is an individual protocol that can be registered into a node. // // Notes: -// - Service life-cycle management is delegated to the node. The service is -// allowed to initialize itself upon creation, but no goroutines should be -// spun up outside of the Start method. -// - Restart logic is not required as the node will create a fresh instance -// every time a service is started. +// +// • Service life-cycle management is delegated to the node. The service is allowed to +// initialize itself upon creation, but no goroutines should be spun up outside of the +// Start method. +// +// • Restart logic is not required as the node will create a fresh instance +// every time a service is started. type Service interface { // Protocols retrieves the P2P protocols the service wishes to start. Protocols() []p2p.Protocol diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/nat/nat.go b/vendor/github.com/ethereum/go-ethereum/p2p/nat/nat.go index 377dc406b..f9ba93613 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/nat/nat.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/nat/nat.go @@ -197,11 +197,7 @@ type autodisc struct { func startautodisc(what string, doit func() Interface) Interface { // TODO: monitor network configuration and rerun doit when it changes. - ad := &autodisc{what: what, doit: doit} - // Start the auto discovery as early as possible so it is already - // in progress when the rest of the stack calls the methods. - go ad.wait() - return ad + return &autodisc{what: what, doit: doit} } func (n *autodisc) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error { diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/http.go b/vendor/github.com/ethereum/go-ethereum/rpc/http.go index afcdd4bd6..c923580bf 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/http.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/http.go @@ -170,6 +170,7 @@ func newCorsHandler(srv *Server, corsString string) http.Handler { c := cors.New(cors.Options{ AllowedOrigins: allowedOrigins, AllowedMethods: []string{"POST", "GET"}, + MaxAge: 600, }) return c.Handler(srv) } diff --git a/vendor/github.com/ethereum/go-ethereum/trie/trie.go b/vendor/github.com/ethereum/go-ethereum/trie/trie.go index 93e189e2e..55598af98 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/trie.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/trie.go @@ -22,7 +22,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" ) @@ -30,11 +30,14 @@ import ( var ( // This is the known root hash of an empty trie. emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - // This is the known hash of an empty state trie entry. - emptyState = crypto.Keccak256Hash(nil) + emptyState common.Hash ) +func init() { + sha3.NewKeccak256().Sum(emptyState[:0]) +} + // Database must be implemented by backing stores for the trie. type Database interface { DatabaseWriter @@ -374,6 +377,9 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // n still contains at least two values and cannot be reduced. return true, n, nil + case valueNode: + return true, nil, nil + case nil: return false, nil, nil