Skip to content

Commit a9c94cb

Browse files
obscurenkaralabe
authored andcommitted
[release/1.4.8] 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. (cherry picked from commit 7a5b571)
1 parent d2089e4 commit a9c94cb

File tree

11 files changed

+95
-29
lines changed

11 files changed

+95
-29
lines changed

cmd/evm/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ type ruleSet struct{}
220220

221221
func (ruleSet) IsHomestead(*big.Int) bool { return true }
222222

223+
func (self *VMEnv) MarkCodeHash(common.Hash) {}
223224
func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} }
224225
func (self *VMEnv) Vm() vm.Vm { return self.evm }
225226
func (self *VMEnv) Db() vm.Database { return self.state }

cmd/utils/flags.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ var (
163163
}
164164
// Miner settings
165165
// TODO: refactor CPU vs GPU mining flags
166+
IllegalCodeHashesFlag = cli.StringFlag{
167+
Name: "illegal-code-hashes",
168+
Usage: "Comma separated list of code-hashes to ignore any interaction from",
169+
}
166170
MiningEnabledFlag = cli.BoolFlag{
167171
Name: "mine",
168172
Usage: "Enable mining",
@@ -640,6 +644,16 @@ func MakePasswordList(ctx *cli.Context) []string {
640644
return lines
641645
}
642646

647+
// ParseIllegalCodeHashes parses a comma separated list of hashes.
648+
func ParseIllegalCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
649+
splittedHexHashes := strings.Split(ctx.GlobalString(IllegalCodeHashesFlag.Name), ",")
650+
illegalCodeHashes := make(map[common.Hash]struct{})
651+
for _, hexHash := range splittedHexHashes {
652+
illegalCodeHashes[common.HexToHash(strings.TrimSpace(hexHash))] = struct{}{}
653+
}
654+
return illegalCodeHashes
655+
}
656+
643657
// MakeSystemNode sets up a local node, configures the services to launch and
644658
// assembles the P2P protocol stack.
645659
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,
676690
}
677691
// Configure the Ethereum service
678692
accman := MakeAccountManager(ctx)
693+
// parse the illegal code hashes and set them to the core package.
694+
core.IllegalCodeHashes = ParseIllegalCodeHashes(ctx)
679695

680696
// initialise new random number generator
681697
rand := rand.New(rand.NewSource(time.Now().UnixNano()))

core/execution.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
8585
createAccount = true
8686
}
8787

88+
// mark the code hash if the execution is a call, callcode or delegate.
89+
if value.Cmp(common.Big0) > 0 {
90+
env.MarkCodeHash(env.Db().GetCodeHash(caller.Address()))
91+
}
92+
8893
snapshotPreTransfer := env.MakeSnapshot()
8994
var (
9095
from = env.Db().GetAccount(caller.Address())

core/state/statedb.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ type StateDB struct {
5151
txIndex int
5252
logs map[common.Hash]vm.Logs
5353
logSize uint
54+
55+
reducedDao bool
5456
}
5557

5658
// Create a new state from a given trie
@@ -161,6 +163,14 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
161163
return nil
162164
}
163165

166+
func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
167+
stateObject := self.GetStateObject(addr)
168+
if stateObject != nil {
169+
return common.BytesToHash(stateObject.codeHash)
170+
}
171+
return common.Hash{}
172+
}
173+
164174
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
165175
stateObject := self.GetStateObject(a)
166176
if stateObject != nil {

core/state_processor.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package core
1818

1919
import (
20+
"errors"
2021
"math/big"
2122

23+
"github.com/ethereum/go-ethereum/common"
2224
"github.com/ethereum/go-ethereum/core/state"
2325
"github.com/ethereum/go-ethereum/core/types"
2426
"github.com/ethereum/go-ethereum/core/vm"
@@ -28,8 +30,15 @@ import (
2830
)
2931

3032
var (
31-
big8 = big.NewInt(8)
32-
big32 = big.NewInt(32)
33+
big8 = big.NewInt(8)
34+
big32 = big.NewInt(32)
35+
illegalCodeHashErr = errors.New("core: Illegal code-hash found during execution")
36+
// XXX remove me
37+
daoHash = common.HexToHash("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba")
38+
whitelist = map[common.Address]bool{
39+
common.HexToAddress("Da4a4626d3E16e094De3225A751aAb7128e96526"): true, // multisig
40+
common.HexToAddress("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334"): true, // attack contract
41+
}
3342
)
3443

3544
// 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
8695
// ApplyTransactions returns the generated receipts and vm logs during the
8796
// execution of the state transition phase.
8897
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) {
89-
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp)
98+
env := NewEnv(statedb, config, bc, tx, header, cfg)
99+
_, gas, err := ApplyMessage(env, tx, gp)
90100
if err != nil {
91101
return nil, nil, nil, err
92102
}
93103

104+
for _, codeHash := range env.CodeHashes {
105+
_, illegalHash := IllegalCodeHashes[codeHash]
106+
to := tx.To()
107+
if illegalHash && to != nil && !whitelist[*to] {
108+
return nil, nil, nil, illegalCodeHashErr
109+
}
110+
}
111+
94112
// Update the state with pending changes
95113
usedGas.Add(usedGas, gas)
96114
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)

core/vm/environment.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ type Environment interface {
7373
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
7474
// Create a new contract
7575
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
76+
// Mark the code hash that was executed
77+
MarkCodeHash(hash common.Hash)
7678
}
7779

7880
// Vm is the basic interface for an implementation of the EVM.
@@ -96,6 +98,7 @@ type Database interface {
9698

9799
GetCode(common.Address) []byte
98100
SetCode(common.Address, []byte)
101+
GetCodeHash(common.Address) common.Hash
99102

100103
AddRefund(*big.Int)
101104
GetRefund() *big.Int

core/vm/jit_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,11 @@ func NewEnv(noJit, forceJit bool) *Env {
175175
return env
176176
}
177177

178-
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
179-
func (self *Env) Vm() Vm { return self.evm }
180-
func (self *Env) Origin() common.Address { return common.Address{} }
181-
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
178+
func (self *Env) MarkCodeHash(common.Hash) {}
179+
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
180+
func (self *Env) Vm() Vm { return self.evm }
181+
func (self *Env) Origin() common.Address { return common.Address{} }
182+
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
182183
func (self *Env) AddStructLog(log StructLog) {
183184
}
184185
func (self *Env) StructLogs() []StructLog {

core/vm/runtime/env.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ import (
2727

2828
// Env is a basic runtime environment required for running the EVM.
2929
type Env struct {
30-
ruleSet vm.RuleSet
31-
depth int
32-
state *state.StateDB
30+
ruleSet vm.RuleSet
31+
depth int
32+
state *state.StateDB
33+
illegalHashes []common.Hash
3334

3435
origin common.Address
3536
coinbase common.Address
@@ -49,14 +50,15 @@ type Env struct {
4950
// NewEnv returns a new vm.Environment
5051
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
5152
env := &Env{
52-
ruleSet: cfg.RuleSet,
53-
state: state,
54-
origin: cfg.Origin,
55-
coinbase: cfg.Coinbase,
56-
number: cfg.BlockNumber,
57-
time: cfg.Time,
58-
difficulty: cfg.Difficulty,
59-
gasLimit: cfg.GasLimit,
53+
ruleSet: cfg.RuleSet,
54+
illegalHashes: cfg.illegalHashes,
55+
state: state,
56+
origin: cfg.Origin,
57+
coinbase: cfg.Coinbase,
58+
number: cfg.BlockNumber,
59+
time: cfg.Time,
60+
difficulty: cfg.Difficulty,
61+
gasLimit: cfg.GasLimit,
6062
}
6163
env.evm = vm.New(env, vm.Config{
6264
Debug: cfg.Debug,
@@ -79,6 +81,8 @@ func (self *Env) AddStructLog(log vm.StructLog) {
7981
self.logs = append(self.logs, log)
8082
}
8183

84+
func (self *Env) MarkCodeHash(hash common.Hash) {}
85+
8286
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
8387
func (self *Env) Vm() vm.Vm { return self.evm }
8488
func (self *Env) Origin() common.Address { return self.origin }

core/vm/runtime/runtime.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,18 @@ func (ruleSet) IsHomestead(*big.Int) bool { return true }
3535
// Config is a basic type specifying certain configuration flags for running
3636
// the EVM.
3737
type Config struct {
38-
RuleSet vm.RuleSet
39-
Difficulty *big.Int
40-
Origin common.Address
41-
Coinbase common.Address
42-
BlockNumber *big.Int
43-
Time *big.Int
44-
GasLimit *big.Int
45-
GasPrice *big.Int
46-
Value *big.Int
47-
DisableJit bool // "disable" so it's enabled by default
48-
Debug bool
38+
RuleSet vm.RuleSet
39+
Difficulty *big.Int
40+
Origin common.Address
41+
Coinbase common.Address
42+
BlockNumber *big.Int
43+
Time *big.Int
44+
GasLimit *big.Int
45+
GasPrice *big.Int
46+
Value *big.Int
47+
DisableJit bool // "disable" so it's enabled by default
48+
Debug bool
49+
illegalHashes []common.Hash
4950

5051
State *state.StateDB
5152
GetHashFn func(n uint64) common.Hash

core/vm_env.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"github.com/ethereum/go-ethereum/core/vm"
2626
)
2727

28+
var IllegalCodeHashes map[common.Hash]struct{}
29+
2830
// GetHashFn returns a function for which the VM env can query block hashes through
2931
// up to the limit defined by the Yellow Paper and uses the given block chain
3032
// to query for information.
@@ -47,6 +49,8 @@ type VMEnv struct {
4749
depth int // Current execution depth
4850
msg Message // Message appliod
4951

52+
CodeHashes []common.Hash // code hashes collected during execution
53+
5054
header *types.Header // Header information
5155
chain *BlockChain // Blockchain handle
5256
logs []vm.StructLog // Logs for the custom structured logger
@@ -72,6 +76,8 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
7276
return env
7377
}
7478

79+
func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.CodeHashes = append(self.CodeHashes, hash) }
80+
7581
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
7682
func (self *VMEnv) Vm() vm.Vm { return self.evm }
7783
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }

0 commit comments

Comments
 (0)