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
|
||||
// TODO: refactor CPU vs GPU mining flags
|
||||
IllegalCodeHashesFlag = cli.StringFlag{
|
||||
Name: "illegal-code-hashes",
|
||||
BlockedCodeHashesFlag = cli.StringFlag{
|
||||
Name: "blocked-code-hashes",
|
||||
Usage: "Comma separated list of code-hashes to ignore any interaction from",
|
||||
}
|
||||
MiningEnabledFlag = cli.BoolFlag{
|
||||
@ -644,9 +644,9 @@ func MakePasswordList(ctx *cli.Context) []string {
|
||||
return lines
|
||||
}
|
||||
|
||||
// ParseIllegalCodeHashes parses a comma separated list of hashes.
|
||||
func ParseIllegalCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
|
||||
splittedHexHashes := strings.Split(ctx.GlobalString(IllegalCodeHashesFlag.Name), ",")
|
||||
// MakeBlockedCodeHashes parses a comma separated list of hashes.
|
||||
func MakeBlockedCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
|
||||
splittedHexHashes := strings.Split(ctx.GlobalString(BlockedCodeHashesFlag.Name), ",")
|
||||
illegalCodeHashes := make(map[common.Hash]struct{})
|
||||
for _, hexHash := range splittedHexHashes {
|
||||
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
|
||||
accman := MakeAccountManager(ctx)
|
||||
// parse the illegal code hashes and set them to the core package.
|
||||
core.IllegalCodeHashes = ParseIllegalCodeHashes(ctx)
|
||||
// parse the blocked code hashes and set them to the core package.
|
||||
core.BlockedCodeHashes = MakeBlockedCodeHashes(ctx)
|
||||
|
||||
// initialise new random number generator
|
||||
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
|
||||
}
|
||||
|
||||
if value.Cmp(common.Big0) > 0 {
|
||||
env.MarkCodeHash(env.Db().GetCodeHash(caller.Address()))
|
||||
}
|
||||
snapshot := env.MakeSnapshot()
|
||||
|
||||
var to vm.Account
|
||||
|
@ -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)
|
||||
|
@ -25,7 +25,9 @@ import (
|
||||
"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
|
||||
// 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
|
||||
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
|
||||
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 {
|
||||
env := &VMEnv{
|
||||
chainConfig: chainConfig,
|
||||
codeHashes: make(map[common.Hash]struct{}),
|
||||
chain: chain,
|
||||
state: state,
|
||||
header: header,
|
||||
@ -76,7 +79,8 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
|
||||
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) Vm() vm.Vm { return self.evm }
|
||||
|
Loading…
Reference in New Issue
Block a user