aboutsummaryrefslogtreecommitdiffstats
path: root/core/state_processor.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/state_processor.go')
-rw-r--r--core/state_processor.go70
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)