Skip to content

Commit f31a3a2

Browse files
committed
[release/1.4.8] core: add voting and result tracking for the dao soft-fork
(cherry picked from commit c4de289)
1 parent a9c94cb commit f31a3a2

File tree

5 files changed

+436
-20
lines changed

5 files changed

+436
-20
lines changed

cmd/utils/flags.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ var (
163163
}
164164
// Miner settings
165165
// TODO: refactor CPU vs GPU mining flags
166-
IllegalCodeHashesFlag = cli.StringFlag{
167-
Name: "illegal-code-hashes",
166+
BlockedCodeHashesFlag = cli.StringFlag{
167+
Name: "blocked-code-hashes",
168168
Usage: "Comma separated list of code-hashes to ignore any interaction from",
169169
}
170170
MiningEnabledFlag = cli.BoolFlag{
@@ -644,9 +644,9 @@ func MakePasswordList(ctx *cli.Context) []string {
644644
return lines
645645
}
646646

647-
// ParseIllegalCodeHashes parses a comma separated list of hashes.
648-
func ParseIllegalCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
649-
splittedHexHashes := strings.Split(ctx.GlobalString(IllegalCodeHashesFlag.Name), ",")
647+
// MakeBlockedCodeHashes parses a comma separated list of hashes.
648+
func MakeBlockedCodeHashes(ctx *cli.Context) map[common.Hash]struct{} {
649+
splittedHexHashes := strings.Split(ctx.GlobalString(BlockedCodeHashesFlag.Name), ",")
650650
illegalCodeHashes := make(map[common.Hash]struct{})
651651
for _, hexHash := range splittedHexHashes {
652652
illegalCodeHashes[common.HexToHash(strings.TrimSpace(hexHash))] = struct{}{}
@@ -690,8 +690,8 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
690690
}
691691
// Configure the Ethereum service
692692
accman := MakeAccountManager(ctx)
693-
// parse the illegal code hashes and set them to the core package.
694-
core.IllegalCodeHashes = ParseIllegalCodeHashes(ctx)
693+
// parse the blocked code hashes and set them to the core package.
694+
core.BlockedCodeHashes = MakeBlockedCodeHashes(ctx)
695695

696696
// initialise new random number generator
697697
rand := rand.New(rand.NewSource(time.Now().UnixNano()))

core/dao_test.go

Lines changed: 358 additions & 0 deletions
Large diffs are not rendered by default.

core/execution.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA
149149
return nil, common.Address{}, vm.DepthError
150150
}
151151

152+
if value.Cmp(common.Big0) > 0 {
153+
env.MarkCodeHash(env.Db().GetCodeHash(caller.Address()))
154+
}
152155
snapshot := env.MakeSnapshot()
153156

154157
var to vm.Account

core/state_processor.go

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,20 @@ import (
3232
var (
3333
big8 = big.NewInt(8)
3434
big32 = big.NewInt(32)
35-
illegalCodeHashErr = errors.New("core: Illegal code-hash found during execution")
36-
// XXX remove me
37-
daoHash = common.HexToHash("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba")
38-
whitelist = map[common.Address]bool{
35+
blockedCodeHashErr = errors.New("core: blocked code-hash found during execution")
36+
37+
// DAO attack chain rupture mechanism
38+
ruptureBlock = uint64(1760000) // Block number of the voted soft fork
39+
ruptureThreshold = big.NewInt(4000000) // Gas threshold for passing a fork vote
40+
ruptureGasCache = make(map[common.Hash]*big.Int) // Amount of gas in the point of rupture
41+
ruptureCodeHashes = map[common.Hash]struct{}{
42+
common.HexToHash("6a5d24750f78441e56fec050dc52fe8e911976485b7472faac7464a176a67caa"): struct{}{},
43+
}
44+
ruptureWhitelist = map[common.Address]bool{
3945
common.HexToAddress("Da4a4626d3E16e094De3225A751aAb7128e96526"): true, // multisig
4046
common.HexToAddress("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334"): true, // attack contract
4147
}
48+
ruptureCacheLimit = 30000 // 1 epoch, 0.5 per possible fork
4249
)
4350

4451
// StateProcessor is a basic Processor, which takes care of transitioning
@@ -101,14 +108,58 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb
101108
return nil, nil, nil, err
102109
}
103110

104-
for _, codeHash := range env.CodeHashes {
105-
_, illegalHash := IllegalCodeHashes[codeHash]
106-
to := tx.To()
107-
if illegalHash && to != nil && !whitelist[*to] {
108-
return nil, nil, nil, illegalCodeHashErr
111+
// Check whether the DAO needs to be blocked or not
112+
if bc != nil { // Test chain maker uses nil to construct the potential chain
113+
blockRuptureCodes := false
114+
115+
if number := header.Number.Uint64(); number >= ruptureBlock {
116+
// We're past the rupture point, find the vote result on this chain and apply it
117+
ancestry := []common.Hash{header.Hash(), header.ParentHash}
118+
for _, ok := ruptureGasCache[ancestry[len(ancestry)-1]]; !ok && number >= ruptureBlock+uint64(len(ancestry)); {
119+
ancestry = append(ancestry, bc.GetHeader(ancestry[len(ancestry)-1]).ParentHash)
120+
}
121+
decider := ancestry[len(ancestry)-1]
122+
123+
vote, ok := ruptureGasCache[decider]
124+
if !ok {
125+
// We've reached the rupture point, retrieve the vote
126+
vote = bc.GetHeader(decider).GasLimit
127+
ruptureGasCache[decider] = vote
128+
}
129+
// Cache the vote result for all ancestors and check the DAO
130+
for _, hash := range ancestry {
131+
ruptureGasCache[hash] = vote
132+
}
133+
if ruptureGasCache[ancestry[0]].Cmp(ruptureThreshold) <= 0 {
134+
blockRuptureCodes = true
135+
}
136+
// Make sure we don't OOM long run due to too many votes caching up
137+
for len(ruptureGasCache) > ruptureCacheLimit {
138+
for hash, _ := range ruptureGasCache {
139+
delete(ruptureGasCache, hash)
140+
break
141+
}
142+
}
143+
}
144+
// Iterate over the bullshit blacklist to keep waste some time while keeping random Joe's happy
145+
if len(BlockedCodeHashes) > 0 {
146+
for hash, _ := range env.GetMarkedCodeHashes() {
147+
// Figure out whether this contract should in general be blocked
148+
if _, blocked := BlockedCodeHashes[hash]; blocked {
149+
return nil, nil, nil, blockedCodeHashErr
150+
}
151+
}
152+
}
153+
// Actually verify the DAO soft fork
154+
recipient := tx.To()
155+
if blockRuptureCodes && (recipient == nil || !ruptureWhitelist[*recipient]) {
156+
for hash, _ := range env.GetMarkedCodeHashes() {
157+
if _, blocked := ruptureCodeHashes[hash]; blocked {
158+
return nil, nil, nil, blockedCodeHashErr
159+
}
160+
}
109161
}
110162
}
111-
112163
// Update the state with pending changes
113164
usedGas.Add(usedGas, gas)
114165
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)

core/vm_env.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ import (
2525
"github.com/ethereum/go-ethereum/core/vm"
2626
)
2727

28-
var IllegalCodeHashes map[common.Hash]struct{}
28+
// BlockedCodeHashes is a set of EVM code hashes that this node should block
29+
// sending funds from.
30+
var BlockedCodeHashes map[common.Hash]struct{}
2931

3032
// GetHashFn returns a function for which the VM env can query block hashes through
3133
// up to the limit defined by the Yellow Paper and uses the given block chain
@@ -49,7 +51,7 @@ type VMEnv struct {
4951
depth int // Current execution depth
5052
msg Message // Message appliod
5153

52-
CodeHashes []common.Hash // code hashes collected during execution
54+
codeHashes map[common.Hash]struct{} // code hashes collected during execution
5355

5456
header *types.Header // Header information
5557
chain *BlockChain // Blockchain handle
@@ -60,6 +62,7 @@ type VMEnv struct {
6062
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
6163
env := &VMEnv{
6264
chainConfig: chainConfig,
65+
codeHashes: make(map[common.Hash]struct{}),
6366
chain: chain,
6467
state: state,
6568
header: header,
@@ -76,7 +79,8 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
7679
return env
7780
}
7881

79-
func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.CodeHashes = append(self.CodeHashes, hash) }
82+
func (self *VMEnv) MarkCodeHash(hash common.Hash) { self.codeHashes[hash] = struct{}{} }
83+
func (self *VMEnv) GetMarkedCodeHashes() map[common.Hash]struct{} { return self.codeHashes }
8084

8185
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
8286
func (self *VMEnv) Vm() vm.Vm { return self.evm }

0 commit comments

Comments
 (0)