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.
This commit is contained in:
committed by
Péter Szilágyi
parent
599e3c7b3f
commit
7a5b571c67
@ -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())
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 }
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
Reference in New Issue
Block a user