diff options
Diffstat (limited to 'core/state_processor.go')
-rw-r--r-- | core/state_processor.go | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/core/state_processor.go b/core/state_processor.go index 95b3057bb..d17bbd8de 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -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,25 @@ import ( ) var ( - big8 = big.NewInt(8) - big32 = big.NewInt(32) + big8 = big.NewInt(8) + 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 @@ -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 // 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 } + // 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 usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas) |