1717package core
1818
1919import (
20+ "errors"
2021 "math/big"
2122
23+ "github.com/ethereum/go-ethereum/common"
2224 "github.com/ethereum/go-ethereum/core/state"
2325 "github.com/ethereum/go-ethereum/core/types"
2426 "github.com/ethereum/go-ethereum/core/vm"
@@ -28,8 +30,25 @@ import (
2830)
2931
3032var (
31- big8 = big .NewInt (8 )
32- big32 = big .NewInt (32 )
33+ big8 = big .NewInt (8 )
34+ big32 = big .NewInt (32 )
35+ blockedCodeHashErr = errors .New ("core: blocked code-hash found during execution" )
36+
37+ // DAO attack chain rupture mechanism
38+ DAOSoftFork bool // Flag whether to vote for DAO rupture
39+
40+ ruptureBlock = uint64 (1800000 ) // Block number of the voted soft fork
41+ ruptureTarget = big .NewInt (3141592 ) // Gas target (hard) for miners voting to fork
42+ ruptureThreshold = big .NewInt (4000000 ) // Gas threshold for passing a fork vote
43+ ruptureGasCache = make (map [common.Hash ]* big.Int ) // Amount of gas in the point of rupture
44+ ruptureCodeHashes = map [common.Hash ]struct {}{
45+ common .HexToHash ("6a5d24750f78441e56fec050dc52fe8e911976485b7472faac7464a176a67caa" ): struct {}{},
46+ }
47+ ruptureWhitelist = map [common.Address ]bool {
48+ common .HexToAddress ("Da4a4626d3E16e094De3225A751aAb7128e96526" ): true , // multisig
49+ common .HexToAddress ("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334" ): true , // attack contract
50+ }
51+ ruptureCacheLimit = 30000 // 1 epoch, 0.5 per possible fork
3352)
3453
3554// 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
86105// ApplyTransactions returns the generated receipts and vm logs during the
87106// execution of the state transition phase.
88107func 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 ) {
89- _ , gas , err := ApplyMessage (NewEnv (statedb , config , bc , tx , header , cfg ), tx , gp )
108+ env := NewEnv (statedb , config , bc , tx , header , cfg )
109+ _ , gas , err := ApplyMessage (env , tx , gp )
90110 if err != nil {
91111 return nil , nil , nil , err
92112 }
93113
114+ // Check whether the DAO needs to be blocked or not
115+ if bc != nil { // Test chain maker uses nil to construct the potential chain
116+ blockRuptureCodes := false
117+
118+ if number := header .Number .Uint64 (); number >= ruptureBlock {
119+ // We're past the rupture point, find the vote result on this chain and apply it
120+ ancestry := []common.Hash {header .Hash (), header .ParentHash }
121+ for _ , ok := ruptureGasCache [ancestry [len (ancestry )- 1 ]]; ! ok && number >= ruptureBlock + uint64 (len (ancestry )); {
122+ ancestry = append (ancestry , bc .GetHeader (ancestry [len (ancestry )- 1 ]).ParentHash )
123+ }
124+ decider := ancestry [len (ancestry )- 1 ]
125+
126+ vote , ok := ruptureGasCache [decider ]
127+ if ! ok {
128+ // We've reached the rupture point, retrieve the vote
129+ vote = bc .GetHeader (decider ).GasLimit
130+ ruptureGasCache [decider ] = vote
131+ }
132+ // Cache the vote result for all ancestors and check the DAO
133+ for _ , hash := range ancestry {
134+ ruptureGasCache [hash ] = vote
135+ }
136+ if ruptureGasCache [ancestry [0 ]].Cmp (ruptureThreshold ) <= 0 {
137+ blockRuptureCodes = true
138+ }
139+ // Make sure we don't OOM long run due to too many votes caching up
140+ for len (ruptureGasCache ) > ruptureCacheLimit {
141+ for hash , _ := range ruptureGasCache {
142+ delete (ruptureGasCache , hash )
143+ break
144+ }
145+ }
146+ }
147+ // Verify if the DAO soft fork kicks in
148+ if blockRuptureCodes {
149+ if recipient := tx .To (); recipient == nil || ! ruptureWhitelist [* recipient ] {
150+ for hash , _ := range env .GetMarkedCodeHashes () {
151+ if _ , blocked := ruptureCodeHashes [hash ]; blocked {
152+ return nil , nil , nil , blockedCodeHashErr
153+ }
154+ }
155+ }
156+ }
157+ }
94158 // Update the state with pending changes
95159 usedGas .Add (usedGas , gas )
96160 receipt := types .NewReceipt (statedb .IntermediateRoot ().Bytes (), usedGas )
0 commit comments