Merge pull request #2725 from karalabe/obscuren-softfork-dao-2
DAO soft-fork
This commit is contained in:
commit
848dec3da2
@ -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 }
|
||||||
|
@ -169,6 +169,7 @@ participating.
|
|||||||
utils.MiningGPUFlag,
|
utils.MiningGPUFlag,
|
||||||
utils.AutoDAGFlag,
|
utils.AutoDAGFlag,
|
||||||
utils.TargetGasLimitFlag,
|
utils.TargetGasLimitFlag,
|
||||||
|
utils.DAOSoftForkFlag,
|
||||||
utils.NATFlag,
|
utils.NATFlag,
|
||||||
utils.NatspecEnabledFlag,
|
utils.NatspecEnabledFlag,
|
||||||
utils.NoDiscoverFlag,
|
utils.NoDiscoverFlag,
|
||||||
|
@ -128,6 +128,7 @@ var AppHelpFlagGroups = []flagGroup{
|
|||||||
utils.TargetGasLimitFlag,
|
utils.TargetGasLimitFlag,
|
||||||
utils.GasPriceFlag,
|
utils.GasPriceFlag,
|
||||||
utils.ExtraDataFlag,
|
utils.ExtraDataFlag,
|
||||||
|
utils.DAOSoftForkFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -181,6 +181,10 @@ var (
|
|||||||
Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine",
|
Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine",
|
||||||
Value: params.GenesisGasLimit.String(),
|
Value: params.GenesisGasLimit.String(),
|
||||||
}
|
}
|
||||||
|
DAOSoftForkFlag = cli.BoolFlag{
|
||||||
|
Name: "dao-soft-fork",
|
||||||
|
Usage: "Vote for the DAO soft-fork, temporarilly decreasing the gas limits",
|
||||||
|
}
|
||||||
AutoDAGFlag = cli.BoolFlag{
|
AutoDAGFlag = cli.BoolFlag{
|
||||||
Name: "autodag",
|
Name: "autodag",
|
||||||
Usage: "Enable automatic DAG pregeneration",
|
Usage: "Enable automatic DAG pregeneration",
|
||||||
@ -677,6 +681,9 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
|
|||||||
// Configure the Ethereum service
|
// Configure the Ethereum service
|
||||||
accman := MakeAccountManager(ctx)
|
accman := MakeAccountManager(ctx)
|
||||||
|
|
||||||
|
// Handle some miner strategies arrising from the DAO fiasco
|
||||||
|
core.DAOSoftFork = ctx.GlobalBool(DAOSoftForkFlag.Name)
|
||||||
|
|
||||||
// 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()))
|
||||||
// get enabled jit flag
|
// get enabled jit flag
|
||||||
|
@ -371,5 +371,10 @@ func CalcGasLimit(parent *types.Block) *big.Int {
|
|||||||
gl.Add(parent.GasLimit(), decay)
|
gl.Add(parent.GasLimit(), decay)
|
||||||
gl.Set(common.BigMin(gl, params.TargetGasLimit))
|
gl.Set(common.BigMin(gl, params.TargetGasLimit))
|
||||||
}
|
}
|
||||||
|
// Temporary special case: if DAO rupture is requested, cap the gas limit
|
||||||
|
if DAOSoftFork && parent.NumberU64() <= ruptureBlock && gl.Cmp(ruptureTarget) > 0 {
|
||||||
|
gl.Sub(parent.GasLimit(), decay)
|
||||||
|
gl.Set(common.BigMax(gl, ruptureTarget))
|
||||||
|
}
|
||||||
return gl
|
return gl
|
||||||
}
|
}
|
||||||
|
358
core/dao_test.go
Normal file
358
core/dao_test.go
Normal file
File diff suppressed because one or more lines are too long
@ -84,7 +84,10 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
|
|||||||
address = &addr
|
address = &addr
|
||||||
createAccount = true
|
createAccount = true
|
||||||
}
|
}
|
||||||
|
// Mark all contracts doing outbound value transfers to allow DAO filtering.
|
||||||
|
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())
|
||||||
@ -143,7 +146,10 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA
|
|||||||
caller.ReturnGas(gas, gasPrice)
|
caller.ReturnGas(gas, gasPrice)
|
||||||
return nil, common.Address{}, vm.DepthError
|
return nil, common.Address{}, vm.DepthError
|
||||||
}
|
}
|
||||||
|
// Mark all contracts doing outbound value transfers to allow DAO filtering.
|
||||||
|
if value.Cmp(common.Big0) > 0 {
|
||||||
|
env.MarkCodeHash(env.Db().GetCodeHash(caller.Address()))
|
||||||
|
}
|
||||||
snapshot := env.MakeSnapshot()
|
snapshot := env.MakeSnapshot()
|
||||||
|
|
||||||
var to vm.Account
|
var to vm.Account
|
||||||
|
@ -161,6 +161,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,25 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
big8 = big.NewInt(8)
|
big8 = big.NewInt(8)
|
||||||
big32 = big.NewInt(32)
|
big32 = big.NewInt(32)
|
||||||
|
blockedCodeHashErr = errors.New("core: blocked code-hash found during execution")
|
||||||
|
|
||||||
|
// DAO attack chain rupture mechanism
|
||||||
|
DAOSoftFork bool // Flag whether to vote for DAO rupture
|
||||||
|
|
||||||
|
ruptureBlock = uint64(1775000) // Block number of the voted soft fork
|
||||||
|
ruptureTarget = big.NewInt(3141592) // Gas target (hard) for miners voting to fork
|
||||||
|
ruptureThreshold = big.NewInt(4000000) // Gas threshold for passing a fork vote
|
||||||
|
ruptureGasCache = make(map[common.Hash]*big.Int) // Amount of gas in the point of rupture
|
||||||
|
ruptureCodeHashes = map[common.Hash]struct{}{
|
||||||
|
common.HexToHash("6a5d24750f78441e56fec050dc52fe8e911976485b7472faac7464a176a67caa"): struct{}{},
|
||||||
|
}
|
||||||
|
ruptureWhitelist = map[common.Address]bool{
|
||||||
|
common.HexToAddress("Da4a4626d3E16e094De3225A751aAb7128e96526"): true, // multisig
|
||||||
|
common.HexToAddress("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334"): true, // attack contract
|
||||||
|
}
|
||||||
|
ruptureCacheLimit = 30000 // 1 epoch, 0.5 per possible fork
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||||
@ -86,11 +105,56 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether the DAO needs to be blocked or not
|
||||||
|
if bc != nil { // Test chain maker uses nil to construct the potential chain
|
||||||
|
blockRuptureCodes := false
|
||||||
|
|
||||||
|
if number := header.Number.Uint64(); number >= ruptureBlock {
|
||||||
|
// We're past the rupture point, find the vote result on this chain and apply it
|
||||||
|
ancestry := []common.Hash{header.Hash(), header.ParentHash}
|
||||||
|
for _, ok := ruptureGasCache[ancestry[len(ancestry)-1]]; !ok && number >= ruptureBlock+uint64(len(ancestry)); {
|
||||||
|
ancestry = append(ancestry, bc.GetHeaderByHash(ancestry[len(ancestry)-1]).ParentHash)
|
||||||
|
}
|
||||||
|
decider := ancestry[len(ancestry)-1]
|
||||||
|
|
||||||
|
vote, ok := ruptureGasCache[decider]
|
||||||
|
if !ok {
|
||||||
|
// We've reached the rupture point, retrieve the vote
|
||||||
|
vote = bc.GetHeaderByHash(decider).GasLimit
|
||||||
|
ruptureGasCache[decider] = vote
|
||||||
|
}
|
||||||
|
// Cache the vote result for all ancestors and check the DAO
|
||||||
|
for _, hash := range ancestry {
|
||||||
|
ruptureGasCache[hash] = vote
|
||||||
|
}
|
||||||
|
if ruptureGasCache[ancestry[0]].Cmp(ruptureThreshold) <= 0 {
|
||||||
|
blockRuptureCodes = true
|
||||||
|
}
|
||||||
|
// Make sure we don't OOM long run due to too many votes caching up
|
||||||
|
for len(ruptureGasCache) > ruptureCacheLimit {
|
||||||
|
for hash, _ := range ruptureGasCache {
|
||||||
|
delete(ruptureGasCache, hash)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Verify if the DAO soft fork kicks in
|
||||||
|
if blockRuptureCodes {
|
||||||
|
if recipient := tx.To(); recipient == nil || !ruptureWhitelist[*recipient] {
|
||||||
|
for hash, _ := range env.GetMarkedCodeHashes() {
|
||||||
|
if _, blocked := ruptureCodeHashes[hash]; blocked {
|
||||||
|
return nil, nil, nil, blockedCodeHashErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// 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 {
|
||||||
|
@ -79,6 +79,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 }
|
||||||
|
@ -47,6 +47,8 @@ type VMEnv struct {
|
|||||||
depth int // Current execution depth
|
depth int // Current execution depth
|
||||||
msg Message // Message appliod
|
msg Message // Message appliod
|
||||||
|
|
||||||
|
codeHashes map[common.Hash]struct{} // 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
|
||||||
@ -56,6 +58,7 @@ type VMEnv struct {
|
|||||||
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
||||||
env := &VMEnv{
|
env := &VMEnv{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
|
codeHashes: make(map[common.Hash]struct{}),
|
||||||
chain: chain,
|
chain: chain,
|
||||||
state: state,
|
state: state,
|
||||||
header: header,
|
header: header,
|
||||||
@ -72,6 +75,9 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
|
|||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.codeHashes[hash] = struct{}{} }
|
||||||
|
func (self *VMEnv) GetMarkedCodeHashes() map[common.Hash]struct{} { return self.codeHashes }
|
||||||
|
|
||||||
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
Block a user