core: add voting and result tracking for the dao soft-fork
This commit is contained in:
parent
7a5b571c67
commit
c4de28938f
@ -163,8 +163,8 @@ var (
|
|||||||
}
|
}
|
||||||
// Miner settings
|
// Miner settings
|
||||||
// TODO: refactor CPU vs GPU mining flags
|
// TODO: refactor CPU vs GPU mining flags
|
||||||
IllegalCodeHashesFlag = cli.StringFlag{
|
BlockedCodeHashesFlag = cli.StringFlag{
|
||||||
Name: "illegal-code-hashes",
|
Name: "blocked-code-hashes",
|
||||||
Usage: "Comma separated list of code-hashes to ignore any interaction from",
|
Usage: "Comma separated list of code-hashes to ignore any interaction from",
|
||||||
}
|
}
|
||||||
MiningEnabledFlag = cli.BoolFlag{
|
MiningEnabledFlag = cli.BoolFlag{
|
||||||
@ -644,9 +644,9 @@ func MakePasswordList(ctx *cli.Context) []string {
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseIllegalCodeHashes parses a comma separated list of hashes.
|
// MakeBlockedCodeHashes parses a comma separated list of hashes.
|
||||||
func ParseIllegalCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
|
func MakeBlockedCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
|
||||||
splittedHexHashes := strings.Split(ctx.GlobalString(IllegalCodeHashesFlag.Name), ",")
|
splittedHexHashes := strings.Split(ctx.GlobalString(BlockedCodeHashesFlag.Name), ",")
|
||||||
illegalCodeHashes := make(map[common.Hash]struct{})
|
illegalCodeHashes := make(map[common.Hash]struct{})
|
||||||
for _, hexHash := range splittedHexHashes {
|
for _, hexHash := range splittedHexHashes {
|
||||||
illegalCodeHashes[common.HexToHash(strings.TrimSpace(hexHash))] = struct{}{}
|
illegalCodeHashes[common.HexToHash(strings.TrimSpace(hexHash))] = struct{}{}
|
||||||
@ -690,8 +690,8 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
|
|||||||
}
|
}
|
||||||
// Configure the Ethereum service
|
// Configure the Ethereum service
|
||||||
accman := MakeAccountManager(ctx)
|
accman := MakeAccountManager(ctx)
|
||||||
// parse the illegal code hashes and set them to the core package.
|
// parse the blocked code hashes and set them to the core package.
|
||||||
core.IllegalCodeHashes = ParseIllegalCodeHashes(ctx)
|
core.BlockedCodeHashes = MakeBlockedCodeHashes(ctx)
|
||||||
|
|
||||||
// initialise new random number generator
|
// initialise new random number generator
|
||||||
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
358
core/dao_test.go
Normal file
358
core/dao_test.go
Normal file
File diff suppressed because one or more lines are too long
@ -149,6 +149,9 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA
|
|||||||
return nil, common.Address{}, vm.DepthError
|
return nil, common.Address{}, vm.DepthError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if value.Cmp(common.Big0) > 0 {
|
||||||
|
env.MarkCodeHash(env.Db().GetCodeHash(caller.Address()))
|
||||||
|
}
|
||||||
snapshot := env.MakeSnapshot()
|
snapshot := env.MakeSnapshot()
|
||||||
|
|
||||||
var to vm.Account
|
var to vm.Account
|
||||||
|
@ -32,13 +32,20 @@ import (
|
|||||||
var (
|
var (
|
||||||
big8 = big.NewInt(8)
|
big8 = big.NewInt(8)
|
||||||
big32 = big.NewInt(32)
|
big32 = big.NewInt(32)
|
||||||
illegalCodeHashErr = errors.New("core: Illegal code-hash found during execution")
|
blockedCodeHashErr = errors.New("core: blocked code-hash found during execution")
|
||||||
// XXX remove me
|
|
||||||
daoHash = common.HexToHash("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba")
|
// DAO attack chain rupture mechanism
|
||||||
whitelist = map[common.Address]bool{
|
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("Da4a4626d3E16e094De3225A751aAb7128e96526"): true, // multisig
|
||||||
common.HexToAddress("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334"): true, // attack contract
|
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
|
||||||
@ -101,14 +108,58 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb
|
|||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, codeHash := range env.CodeHashes {
|
// Check whether the DAO needs to be blocked or not
|
||||||
_, illegalHash := IllegalCodeHashes[codeHash]
|
if bc != nil { // Test chain maker uses nil to construct the potential chain
|
||||||
to := tx.To()
|
blockRuptureCodes := false
|
||||||
if illegalHash && to != nil && !whitelist[*to] {
|
|
||||||
return nil, nil, nil, illegalCodeHashErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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
|
// 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)
|
||||||
|
@ -25,7 +25,9 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var IllegalCodeHashes map[common.Hash]struct{}
|
// BlockedCodeHashes is a set of EVM code hashes that this node should block
|
||||||
|
// sending funds from.
|
||||||
|
var BlockedCodeHashes map[common.Hash]struct{}
|
||||||
|
|
||||||
// GetHashFn returns a function for which the VM env can query block hashes through
|
// GetHashFn returns a function for which the VM env can query block hashes through
|
||||||
// up to the limit defined by the Yellow Paper and uses the given block chain
|
// up to the limit defined by the Yellow Paper and uses the given block chain
|
||||||
@ -49,7 +51,7 @@ type VMEnv struct {
|
|||||||
depth int // Current execution depth
|
depth int // Current execution depth
|
||||||
msg Message // Message appliod
|
msg Message // Message appliod
|
||||||
|
|
||||||
CodeHashes []common.Hash // code hashes collected during execution
|
codeHashes map[common.Hash]struct{} // code hashes collected during execution
|
||||||
|
|
||||||
header *types.Header // Header information
|
header *types.Header // Header information
|
||||||
chain *BlockChain // Blockchain handle
|
chain *BlockChain // Blockchain handle
|
||||||
@ -60,6 +62,7 @@ type VMEnv struct {
|
|||||||
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
||||||
env := &VMEnv{
|
env := &VMEnv{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
|
codeHashes: make(map[common.Hash]struct{}),
|
||||||
chain: chain,
|
chain: chain,
|
||||||
state: state,
|
state: state,
|
||||||
header: header,
|
header: header,
|
||||||
@ -76,7 +79,8 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
|
|||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.CodeHashes = append(self.CodeHashes, hash) }
|
func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.codeHashes[hash] = struct{}{} }
|
||||||
|
func (self *VMEnv) GetMarkedCodeHashes() map[common.Hash]struct{} { return self.codeHashes }
|
||||||
|
|
||||||
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
|
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
||||||
|
Loading…
Reference in New Issue
Block a user