[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 7a5b571c67
)
This commit is contained in:
parent
d2089e46f8
commit
a9c94cbf48
|
@ -220,6 +220,7 @@ type ruleSet struct{}
|
||||||
|
|
||||||
func (ruleSet) IsHomestead(*big.Int) bool { return true }
|
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) RuleSet() vm.RuleSet { return ruleSet{} }
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
||||||
func (self *VMEnv) Db() vm.Database { return self.state }
|
func (self *VMEnv) Db() vm.Database { return self.state }
|
||||||
|
|
|
@ -163,6 +163,10 @@ var (
|
||||||
}
|
}
|
||||||
// Miner settings
|
// Miner settings
|
||||||
// TODO: refactor CPU vs GPU mining flags
|
// 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{
|
MiningEnabledFlag = cli.BoolFlag{
|
||||||
Name: "mine",
|
Name: "mine",
|
||||||
Usage: "Enable mining",
|
Usage: "Enable mining",
|
||||||
|
@ -640,6 +644,16 @@ func MakePasswordList(ctx *cli.Context) []string {
|
||||||
return lines
|
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
|
// MakeSystemNode sets up a local node, configures the services to launch and
|
||||||
// assembles the P2P protocol stack.
|
// assembles the P2P protocol stack.
|
||||||
func MakeSystemNode(name, version string, relconf release.Config, extra []byte, ctx *cli.Context) *node.Node {
|
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
|
// Configure the Ethereum service
|
||||||
accman := MakeAccountManager(ctx)
|
accman := MakeAccountManager(ctx)
|
||||||
|
// parse the illegal code hashes and set them to the core package.
|
||||||
|
core.IllegalCodeHashes = ParseIllegalCodeHashes(ctx)
|
||||||
|
|
||||||
// initialise new random number generator
|
// initialise new random number generator
|
||||||
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
|
@ -85,6 +85,11 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
|
||||||
createAccount = true
|
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()
|
snapshotPreTransfer := env.MakeSnapshot()
|
||||||
var (
|
var (
|
||||||
from = env.Db().GetAccount(caller.Address())
|
from = env.Db().GetAccount(caller.Address())
|
||||||
|
|
|
@ -51,6 +51,8 @@ type StateDB struct {
|
||||||
txIndex int
|
txIndex int
|
||||||
logs map[common.Hash]vm.Logs
|
logs map[common.Hash]vm.Logs
|
||||||
logSize uint
|
logSize uint
|
||||||
|
|
||||||
|
reducedDao bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new state from a given trie
|
// Create a new state from a given trie
|
||||||
|
@ -161,6 +163,14 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
|
||||||
return nil
|
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 {
|
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
||||||
stateObject := self.GetStateObject(a)
|
stateObject := self.GetStateObject(a)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
@ -28,8 +30,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
big8 = big.NewInt(8)
|
big8 = big.NewInt(8)
|
||||||
big32 = big.NewInt(32)
|
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
|
// 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
|
// ApplyTransactions returns the generated receipts and vm logs during the
|
||||||
// execution of the state transition phase.
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
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
|
// Update the state with pending changes
|
||||||
usedGas.Add(usedGas, gas)
|
usedGas.Add(usedGas, gas)
|
||||||
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
|
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)
|
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
|
||||||
// Create a new contract
|
// Create a new contract
|
||||||
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
|
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.
|
// Vm is the basic interface for an implementation of the EVM.
|
||||||
|
@ -96,6 +98,7 @@ type Database interface {
|
||||||
|
|
||||||
GetCode(common.Address) []byte
|
GetCode(common.Address) []byte
|
||||||
SetCode(common.Address, []byte)
|
SetCode(common.Address, []byte)
|
||||||
|
GetCodeHash(common.Address) common.Hash
|
||||||
|
|
||||||
AddRefund(*big.Int)
|
AddRefund(*big.Int)
|
||||||
GetRefund() *big.Int
|
GetRefund() *big.Int
|
||||||
|
|
|
@ -175,10 +175,11 @@ func NewEnv(noJit, forceJit bool) *Env {
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
|
func (self *Env) MarkCodeHash(common.Hash) {}
|
||||||
func (self *Env) Vm() Vm { return self.evm }
|
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
|
||||||
func (self *Env) Origin() common.Address { return common.Address{} }
|
func (self *Env) Vm() Vm { return self.evm }
|
||||||
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
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) AddStructLog(log StructLog) {
|
||||||
}
|
}
|
||||||
func (self *Env) StructLogs() []StructLog {
|
func (self *Env) StructLogs() []StructLog {
|
||||||
|
|
|
@ -27,9 +27,10 @@ import (
|
||||||
|
|
||||||
// Env is a basic runtime environment required for running the EVM.
|
// Env is a basic runtime environment required for running the EVM.
|
||||||
type Env struct {
|
type Env struct {
|
||||||
ruleSet vm.RuleSet
|
ruleSet vm.RuleSet
|
||||||
depth int
|
depth int
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
|
illegalHashes []common.Hash
|
||||||
|
|
||||||
origin common.Address
|
origin common.Address
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
|
@ -49,14 +50,15 @@ type Env struct {
|
||||||
// NewEnv returns a new vm.Environment
|
// NewEnv returns a new vm.Environment
|
||||||
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
||||||
env := &Env{
|
env := &Env{
|
||||||
ruleSet: cfg.RuleSet,
|
ruleSet: cfg.RuleSet,
|
||||||
state: state,
|
illegalHashes: cfg.illegalHashes,
|
||||||
origin: cfg.Origin,
|
state: state,
|
||||||
coinbase: cfg.Coinbase,
|
origin: cfg.Origin,
|
||||||
number: cfg.BlockNumber,
|
coinbase: cfg.Coinbase,
|
||||||
time: cfg.Time,
|
number: cfg.BlockNumber,
|
||||||
difficulty: cfg.Difficulty,
|
time: cfg.Time,
|
||||||
gasLimit: cfg.GasLimit,
|
difficulty: cfg.Difficulty,
|
||||||
|
gasLimit: cfg.GasLimit,
|
||||||
}
|
}
|
||||||
env.evm = vm.New(env, vm.Config{
|
env.evm = vm.New(env, vm.Config{
|
||||||
Debug: cfg.Debug,
|
Debug: cfg.Debug,
|
||||||
|
@ -79,6 +81,8 @@ func (self *Env) AddStructLog(log vm.StructLog) {
|
||||||
self.logs = append(self.logs, log)
|
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) RuleSet() vm.RuleSet { return self.ruleSet }
|
||||||
func (self *Env) Vm() vm.Vm { return self.evm }
|
func (self *Env) Vm() vm.Vm { return self.evm }
|
||||||
func (self *Env) Origin() common.Address { return self.origin }
|
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
|
// Config is a basic type specifying certain configuration flags for running
|
||||||
// the EVM.
|
// the EVM.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
RuleSet vm.RuleSet
|
RuleSet vm.RuleSet
|
||||||
Difficulty *big.Int
|
Difficulty *big.Int
|
||||||
Origin common.Address
|
Origin common.Address
|
||||||
Coinbase common.Address
|
Coinbase common.Address
|
||||||
BlockNumber *big.Int
|
BlockNumber *big.Int
|
||||||
Time *big.Int
|
Time *big.Int
|
||||||
GasLimit *big.Int
|
GasLimit *big.Int
|
||||||
GasPrice *big.Int
|
GasPrice *big.Int
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
DisableJit bool // "disable" so it's enabled by default
|
DisableJit bool // "disable" so it's enabled by default
|
||||||
Debug bool
|
Debug bool
|
||||||
|
illegalHashes []common.Hash
|
||||||
|
|
||||||
State *state.StateDB
|
State *state.StateDB
|
||||||
GetHashFn func(n uint64) common.Hash
|
GetHashFn func(n uint64) common.Hash
|
||||||
|
|
|
@ -25,6 +25,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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
|
// 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
|
// up to the limit defined by the Yellow Paper and uses the given block chain
|
||||||
// to query for information.
|
// to query for information.
|
||||||
|
@ -47,6 +49,8 @@ type VMEnv struct {
|
||||||
depth int // Current execution depth
|
depth int // Current execution depth
|
||||||
msg Message // Message appliod
|
msg Message // Message appliod
|
||||||
|
|
||||||
|
CodeHashes []common.Hash // code hashes collected during execution
|
||||||
|
|
||||||
header *types.Header // Header information
|
header *types.Header // Header information
|
||||||
chain *BlockChain // Blockchain handle
|
chain *BlockChain // Blockchain handle
|
||||||
logs []vm.StructLog // Logs for the custom structured logger
|
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
|
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) RuleSet() vm.RuleSet { return self.chainConfig }
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
||||||
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
|
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
|
||||||
|
|
|
@ -207,6 +207,7 @@ func NewEnvFromMap(ruleSet RuleSet, state *state.StateDB, envValues map[string]s
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Env) MarkCodeHash(common.Hash) {}
|
||||||
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
|
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
|
||||||
func (self *Env) Vm() vm.Vm { return self.evm }
|
func (self *Env) Vm() vm.Vm { return self.evm }
|
||||||
func (self *Env) Origin() common.Address { return self.origin }
|
func (self *Env) Origin() common.Address { return self.origin }
|
||||||
|
|
Loading…
Reference in New Issue