From 7a5b571c671e70e0e4807cf971c15e2d1e09d33d Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Sat, 18 Jun 2016 11:17:57 +0200 Subject: 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. --- core/state_processor.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'core/state_processor.go') diff --git a/core/state_processor.go b/core/state_processor.go index 95b3057bb..55c1301eb 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,15 @@ import ( ) var ( - big8 = big.NewInt(8) - big32 = big.NewInt(32) + big8 = big.NewInt(8) + big32 = big.NewInt(32) + illegalCodeHashErr = errors.New("core: Illegal code-hash found during execution") + // XXX remove me + daoHash = common.HexToHash("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba") + whitelist = map[common.Address]bool{ + common.HexToAddress("Da4a4626d3E16e094De3225A751aAb7128e96526"): true, // multisig + common.HexToAddress("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334"): true, // attack contract + } ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -86,11 +95,20 @@ 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 } + for _, codeHash := range env.CodeHashes { + _, illegalHash := IllegalCodeHashes[codeHash] + to := tx.To() + if illegalHash && to != nil && !whitelist[*to] { + return nil, nil, nil, illegalCodeHashErr + } + } + // Update the state with pending changes usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas) -- cgit From c4de28938ff8c688c4444c8b3e8e28a52cbc62ff Mon Sep 17 00:00:00 2001 From: Péter Szilágyi Date: Wed, 22 Jun 2016 11:59:28 +0300 Subject: core: add voting and result tracking for the dao soft-fork --- core/state_processor.go | 71 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 10 deletions(-) (limited to 'core/state_processor.go') diff --git a/core/state_processor.go b/core/state_processor.go index 55c1301eb..1e54eefa3 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -32,13 +32,20 @@ import ( var ( big8 = big.NewInt(8) big32 = big.NewInt(32) - illegalCodeHashErr = errors.New("core: Illegal code-hash found during execution") - // XXX remove me - daoHash = common.HexToHash("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba") - whitelist = map[common.Address]bool{ + blockedCodeHashErr = errors.New("core: blocked code-hash found during execution") + + // DAO attack chain rupture mechanism + ruptureBlock = uint64(1760000) // Block number of the voted soft 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 @@ -101,14 +108,58 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb return nil, nil, nil, err } - for _, codeHash := range env.CodeHashes { - _, illegalHash := IllegalCodeHashes[codeHash] - to := tx.To() - if illegalHash && to != nil && !whitelist[*to] { - return nil, nil, nil, illegalCodeHashErr + // 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 + } + } + } + // Iterate over the bullshit blacklist to keep waste some time while keeping random Joe's happy + if len(BlockedCodeHashes) > 0 { + for hash, _ := range env.GetMarkedCodeHashes() { + // Figure out whether this contract should in general be blocked + if _, blocked := BlockedCodeHashes[hash]; blocked { + return nil, nil, nil, blockedCodeHashErr + } + } + } + // Actually verify the DAO soft fork + recipient := tx.To() + if blockRuptureCodes && (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) -- cgit From ba784bdf36f2daf7827ec1ec864f3393ba8d86a0 Mon Sep 17 00:00:00 2001 From: Péter Szilágyi Date: Thu, 23 Jun 2016 12:47:15 +0300 Subject: core: update DAO soft-fork number, clean up the code --- core/state_processor.go | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'core/state_processor.go') diff --git a/core/state_processor.go b/core/state_processor.go index 1e54eefa3..d17bbd8de 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -35,7 +35,10 @@ var ( blockedCodeHashErr = errors.New("core: blocked code-hash found during execution") // DAO attack chain rupture mechanism - ruptureBlock = uint64(1760000) // Block number of the voted soft fork + 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{}{ @@ -141,21 +144,13 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb } } } - // Iterate over the bullshit blacklist to keep waste some time while keeping random Joe's happy - if len(BlockedCodeHashes) > 0 { - for hash, _ := range env.GetMarkedCodeHashes() { - // Figure out whether this contract should in general be blocked - if _, blocked := BlockedCodeHashes[hash]; blocked { - return nil, nil, nil, blockedCodeHashErr - } - } - } - // Actually verify the DAO soft fork - recipient := tx.To() - if blockRuptureCodes && (recipient == nil || !ruptureWhitelist[*recipient]) { - for hash, _ := range env.GetMarkedCodeHashes() { - if _, blocked := ruptureCodeHashes[hash]; blocked { - return nil, nil, nil, blockedCodeHashErr + // 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 + } } } } -- cgit