aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2016-06-18 17:17:57 +0800
committerPéter Szilágyi <peterke@gmail.com>2016-06-22 16:38:25 +0800
commit7a5b571c671e70e0e4807cf971c15e2d1e09d33d (patch)
tree4ae6b6e4be80171e26aab26b88124cd87a3c53d4
parent599e3c7b3f22b157c4f643a48d391cf972384099 (diff)
downloaddexon-7a5b571c671e70e0e4807cf971c15e2d1e09d33d.tar.gz
dexon-7a5b571c671e70e0e4807cf971c15e2d1e09d33d.tar.zst
dexon-7a5b571c671e70e0e4807cf971c15e2d1e09d33d.zip
test, cmd/evm, core, core/vm: illegal code hash implementation
This implements a generic approach to enabling soft forks by allowing anyone to put in hashes of contracts that should not be interacted from. This will help "The DAO" in their endevour to stop any whithdrawals from any DAO contract by convincing the mining community to accept their code hash.
-rw-r--r--cmd/evm/main.go1
-rw-r--r--cmd/utils/flags.go16
-rw-r--r--core/execution.go5
-rw-r--r--core/state/statedb.go10
-rw-r--r--core/state_processor.go24
-rw-r--r--core/vm/environment.go3
-rw-r--r--core/vm/jit_test.go9
-rw-r--r--core/vm/runtime/env.go26
-rw-r--r--core/vm/runtime/runtime.go23
-rw-r--r--core/vm_env.go6
-rw-r--r--tests/util.go1
11 files changed, 95 insertions, 29 deletions
diff --git a/cmd/evm/main.go b/cmd/evm/main.go
index aa48f6ede..ba7d8d8a8 100644
--- a/cmd/evm/main.go
+++ b/cmd/evm/main.go
@@ -220,6 +220,7 @@ type ruleSet struct{}
func (ruleSet) IsHomestead(*big.Int) bool { return true }
+func (self *VMEnv) MarkCodeHash(common.Hash) {}
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 }
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 14898b987..802e54c73 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -163,6 +163,10 @@ var (
}
// Miner settings
// TODO: refactor CPU vs GPU mining flags
+ IllegalCodeHashesFlag = cli.StringFlag{
+ Name: "illegal-code-hashes",
+ Usage: "Comma separated list of code-hashes to ignore any interaction from",
+ }
MiningEnabledFlag = cli.BoolFlag{
Name: "mine",
Usage: "Enable mining",
@@ -640,6 +644,16 @@ func MakePasswordList(ctx *cli.Context) []string {
return lines
}
+// ParseIllegalCodeHashes parses a comma separated list of hashes.
+func ParseIllegalCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
+ splittedHexHashes := strings.Split(ctx.GlobalString(IllegalCodeHashesFlag.Name), ",")
+ illegalCodeHashes := make(map[common.Hash]struct{})
+ for _, hexHash := range splittedHexHashes {
+ illegalCodeHashes[common.HexToHash(strings.TrimSpace(hexHash))] = struct{}{}
+ }
+ return illegalCodeHashes
+}
+
// MakeSystemNode sets up a local node, configures the services to launch and
// assembles the P2P protocol stack.
func MakeSystemNode(name, version string, relconf release.Config, extra []byte, ctx *cli.Context) *node.Node {
@@ -676,6 +690,8 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
}
// Configure the Ethereum service
accman := MakeAccountManager(ctx)
+ // parse the illegal code hashes and set them to the core package.
+ core.IllegalCodeHashes = ParseIllegalCodeHashes(ctx)
// initialise new random number generator
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
diff --git a/core/execution.go b/core/execution.go
index 82143443c..ec04f6140 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -85,6 +85,11 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
createAccount = true
}
+ // mark the code hash if the execution is a call, callcode or delegate.
+ if value.Cmp(common.Big0) > 0 {
+ env.MarkCodeHash(env.Db().GetCodeHash(caller.Address()))
+ }
+
snapshotPreTransfer := env.MakeSnapshot()
var (
from = env.Db().GetAccount(caller.Address())
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 3e25e0c16..79cbbaee8 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -51,6 +51,8 @@ type StateDB struct {
txIndex int
logs map[common.Hash]vm.Logs
logSize uint
+
+ reducedDao bool
}
// Create a new state from a given trie
@@ -161,6 +163,14 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
return nil
}
+func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
+ stateObject := self.GetStateObject(addr)
+ if stateObject != nil {
+ return common.BytesToHash(stateObject.codeHash)
+ }
+ return common.Hash{}
+}
+
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
stateObject := self.GetStateObject(a)
if stateObject != nil {
diff --git a/core/state_processor.go b/core/state_processor.go
index 95b3057bb..55c1301eb 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -17,8 +17,10 @@
package core
import (
+ "errors"
"math/big"
+ "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -28,8 +30,15 @@ import (
)
var (
- big8 = big.NewInt(8)
- big32 = big.NewInt(32)
+ big8 = big.NewInt(8)
+ big32 = big.NewInt(32)
+ illegalCodeHashErr = errors.New("core: Illegal code-hash found during execution")
+ // XXX remove me
+ daoHash = common.HexToHash("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba")
+ whitelist = map[common.Address]bool{
+ common.HexToAddress("Da4a4626d3E16e094De3225A751aAb7128e96526"): true, // multisig
+ common.HexToAddress("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334"): true, // attack contract
+ }
)
// StateProcessor is a basic Processor, which takes care of transitioning
@@ -86,11 +95,20 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// ApplyTransactions returns the generated receipts and vm logs during the
// execution of the state transition phase.
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
- _, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp)
+ env := NewEnv(statedb, config, bc, tx, header, cfg)
+ _, gas, err := ApplyMessage(env, tx, gp)
if err != nil {
return nil, nil, nil, err
}
+ for _, codeHash := range env.CodeHashes {
+ _, illegalHash := IllegalCodeHashes[codeHash]
+ to := tx.To()
+ if illegalHash && to != nil && !whitelist[*to] {
+ return nil, nil, nil, illegalCodeHashErr
+ }
+ }
+
// Update the state with pending changes
usedGas.Add(usedGas, gas)
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
diff --git a/core/vm/environment.go b/core/vm/environment.go
index 747627565..37817be9e 100644
--- a/core/vm/environment.go
+++ b/core/vm/environment.go
@@ -73,6 +73,8 @@ type Environment interface {
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
// Create a new contract
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
+ // Mark the code hash that was executed
+ MarkCodeHash(hash common.Hash)
}
// Vm is the basic interface for an implementation of the EVM.
@@ -96,6 +98,7 @@ type Database interface {
GetCode(common.Address) []byte
SetCode(common.Address, []byte)
+ GetCodeHash(common.Address) common.Hash
AddRefund(*big.Int)
GetRefund() *big.Int
diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go
index 403c15a8d..a9ddd48a5 100644
--- a/core/vm/jit_test.go
+++ b/core/vm/jit_test.go
@@ -175,10 +175,11 @@ func NewEnv(noJit, forceJit bool) *Env {
return env
}
-func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
-func (self *Env) Vm() Vm { return self.evm }
-func (self *Env) Origin() common.Address { return common.Address{} }
-func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
+func (self *Env) MarkCodeHash(common.Hash) {}
+func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
+func (self *Env) Vm() Vm { return self.evm }
+func (self *Env) Origin() common.Address { return common.Address{} }
+func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
func (self *Env) AddStructLog(log StructLog) {
}
func (self *Env) StructLogs() []StructLog {
diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go
index d8c98e545..c510be759 100644
--- a/core/vm/runtime/env.go
+++ b/core/vm/runtime/env.go
@@ -27,9 +27,10 @@ import (
// Env is a basic runtime environment required for running the EVM.
type Env struct {
- ruleSet vm.RuleSet
- depth int
- state *state.StateDB
+ ruleSet vm.RuleSet
+ depth int
+ state *state.StateDB
+ illegalHashes []common.Hash
origin common.Address
coinbase common.Address
@@ -49,14 +50,15 @@ type Env struct {
// NewEnv returns a new vm.Environment
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
env := &Env{
- ruleSet: cfg.RuleSet,
- state: state,
- origin: cfg.Origin,
- coinbase: cfg.Coinbase,
- number: cfg.BlockNumber,
- time: cfg.Time,
- difficulty: cfg.Difficulty,
- gasLimit: cfg.GasLimit,
+ ruleSet: cfg.RuleSet,
+ illegalHashes: cfg.illegalHashes,
+ state: state,
+ origin: cfg.Origin,
+ coinbase: cfg.Coinbase,
+ number: cfg.BlockNumber,
+ time: cfg.Time,
+ difficulty: cfg.Difficulty,
+ gasLimit: cfg.GasLimit,
}
env.evm = vm.New(env, vm.Config{
Debug: cfg.Debug,
@@ -79,6 +81,8 @@ func (self *Env) AddStructLog(log vm.StructLog) {
self.logs = append(self.logs, log)
}
+func (self *Env) MarkCodeHash(hash common.Hash) {}
+
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
func (self *Env) Vm() vm.Vm { return self.evm }
func (self *Env) Origin() common.Address { return self.origin }
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index 309d508c3..9b75fcaad 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -35,17 +35,18 @@ func (ruleSet) IsHomestead(*big.Int) bool { return true }
// Config is a basic type specifying certain configuration flags for running
// the EVM.
type Config struct {
- RuleSet vm.RuleSet
- Difficulty *big.Int
- Origin common.Address
- Coinbase common.Address
- BlockNumber *big.Int
- Time *big.Int
- GasLimit *big.Int
- GasPrice *big.Int
- Value *big.Int
- DisableJit bool // "disable" so it's enabled by default
- Debug bool
+ RuleSet vm.RuleSet
+ Difficulty *big.Int
+ Origin common.Address
+ Coinbase common.Address
+ BlockNumber *big.Int
+ Time *big.Int
+ GasLimit *big.Int
+ GasPrice *big.Int
+ Value *big.Int
+ DisableJit bool // "disable" so it's enabled by default
+ Debug bool
+ illegalHashes []common.Hash
State *state.StateDB
GetHashFn func(n uint64) common.Hash
diff --git a/core/vm_env.go b/core/vm_env.go
index 599672382..1c1110280 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -25,6 +25,8 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
)
+var IllegalCodeHashes map[common.Hash]struct{}
+
// GetHashFn returns a function for which the VM env can query block hashes through
// up to the limit defined by the Yellow Paper and uses the given block chain
// to query for information.
@@ -47,6 +49,8 @@ type VMEnv struct {
depth int // Current execution depth
msg Message // Message appliod
+ CodeHashes []common.Hash // code hashes collected during execution
+
header *types.Header // Header information
chain *BlockChain // Blockchain handle
logs []vm.StructLog // Logs for the custom structured logger
@@ -72,6 +76,8 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
return env
}
+func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.CodeHashes = append(self.CodeHashes, hash) }
+
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
func (self *VMEnv) Vm() vm.Vm { return self.evm }
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
diff --git a/tests/util.go b/tests/util.go
index abc67769d..035903ccc 100644
--- a/tests/util.go
+++ b/tests/util.go
@@ -207,6 +207,7 @@ func NewEnvFromMap(ruleSet RuleSet, state *state.StateDB, envValues map[string]s
return env
}
+func (self *Env) MarkCodeHash(common.Hash) {}
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
func (self *Env) Vm() vm.Vm { return self.evm }
func (self *Env) Origin() common.Address { return self.origin }