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