Latest light-stable code pushed to vendors
This commit is contained in:
parent
b55346c37e
commit
f11c6421a1
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(),
|
||||
|
@ -227,8 +230,8 @@ 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) 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 }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
@ -77,13 +78,15 @@ type StateObject struct {
|
|||
// 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)
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
if stateObject == nil {
|
||||
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
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
}
|
||||
|
||||
return newSo
|
||||
// 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})
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
13
vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go
generated
vendored
Normal file
13
vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go
generated
vendored
Normal file
|
@ -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)
|
392
vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s
generated
vendored
Normal file
392
vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s
generated
vendored
Normal file
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
@ -375,7 +376,16 @@ 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 {
|
||||
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 {
|
||||
|
@ -384,6 +394,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
} else {
|
||||
unknown = true
|
||||
}
|
||||
}
|
||||
case query.Reverse:
|
||||
// Number based traversal towards the genesis block
|
||||
if query.Origin.Number >= query.Skip+1 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,9 +41,6 @@ type VMEnv struct {
|
|||
msg core.Message
|
||||
depth int
|
||||
chain *LightChain
|
||||
typ vm.Type
|
||||
// structured logging
|
||||
logs []vm.StructLog
|
||||
err error
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -134,6 +124,7 @@ type VMState struct {
|
|||
vm.Database
|
||||
ctx context.Context
|
||||
state *LightState
|
||||
snapshots []*LightState
|
||||
env *VMEnv
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, ",") {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 ""
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
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
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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
|
||||
|
||||
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,19 +68,12 @@ 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
|
||||
|
||||
|
@ -88,53 +83,44 @@ 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,
|
||||
},
|
||||
config: conf,
|
||||
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),
|
||||
}, 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{
|
||||
|
|
|
@ -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,10 +63,12 @@ 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
|
||||
//
|
||||
// • 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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue