Compare commits

...

6 Commits

Author SHA1 Message Date
Péter Szilágyi
98be7cd833 Merge pull request #2735 from ethereum/release/1.4
Geth 1.4.8 "DAO Wars"
2016-06-24 18:17:12 +03:00
Péter Szilágyi
eaf706b73c VERSION, cmd/geth: bumped version 1.4.8 2016-06-24 16:20:43 +03:00
Péter Szilágyi
b170a80cdc [release/1.4.8] core: update the DAO soft fork proposal to the final block
(cherry picked from commit 1e3a7d4fab)
2016-06-24 16:20:36 +03:00
Péter Szilágyi
aefffc9ed8 [release/1.4.8] core: update DAO soft-fork number, clean up the code
(cherry picked from commit ba784bdf36)
2016-06-24 13:18:31 +03:00
Péter Szilágyi
f31a3a251a [release/1.4.8] core: add voting and result tracking for the dao soft-fork
(cherry picked from commit c4de28938f)
2016-06-24 13:18:28 +03:00
Jeffrey Wilcke
a9c94cbf48 [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)
2016-06-24 13:18:25 +03:00
15 changed files with 475 additions and 11 deletions

View File

@@ -1 +1 @@
1.4.7 1.4.8

View File

@@ -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 }

View File

@@ -50,7 +50,7 @@ const (
clientIdentifier = "Geth" // Client identifier to advertise over the network clientIdentifier = "Geth" // Client identifier to advertise over the network
versionMajor = 1 // Major version component of the current release versionMajor = 1 // Major version component of the current release
versionMinor = 4 // Minor version component of the current release versionMinor = 4 // Minor version component of the current release
versionPatch = 7 // Patch version component of the current release versionPatch = 8 // Patch version component of the current release
versionMeta = "stable" // Version metadata to append to the version string versionMeta = "stable" // Version metadata to append to the version string
versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle
@@ -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,

View File

@@ -128,6 +128,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.TargetGasLimitFlag, utils.TargetGasLimitFlag,
utils.GasPriceFlag, utils.GasPriceFlag,
utils.ExtraDataFlag, utils.ExtraDataFlag,
utils.DAOSoftForkFlag,
}, },
}, },
{ {

View File

@@ -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

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -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

View File

@@ -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 {

View File

@@ -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"
@@ -30,6 +32,23 @@ 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(1800000) // 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.GetHeader(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.GetHeader(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)

View File

@@ -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

View File

@@ -175,6 +175,7 @@ func NewEnv(noJit, forceJit bool) *Env {
return env return env
} }
func (self *Env) MarkCodeHash(common.Hash) {}
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} } func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
func (self *Env) Vm() Vm { return self.evm } func (self *Env) Vm() Vm { return self.evm }
func (self *Env) Origin() common.Address { return common.Address{} } func (self *Env) Origin() common.Address { return common.Address{} }

View File

@@ -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 }

View File

@@ -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 }

View File

@@ -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 }