Skip to content

Commit c2c80f3

Browse files
committed
fix state diff builder: emit actual leaf nodes instead of value nodes; diff on the leaf not on the value; emit correct path for intermediate nodes
1 parent c7bfb7e commit c2c80f3

File tree

14 files changed

+365
-287
lines changed

14 files changed

+365
-287
lines changed

cmd/geth/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ var (
147147
utils.EWASMInterpreterFlag,
148148
utils.EVMInterpreterFlag,
149149
utils.StateDiffFlag,
150-
utils.StateDiffPathsAndProofs,
151150
utils.StateDiffIntermediateNodes,
152151
utils.StateDiffStreamBlock,
153152
utils.StateDiffWatchedAddresses,

cmd/geth/usage.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,6 @@ var AppHelpFlagGroups = []flagGroup{
255255
Name: "STATE DIFF",
256256
Flags: []cli.Flag{
257257
utils.StateDiffFlag,
258-
utils.StateDiffPathsAndProofs,
259258
utils.StateDiffIntermediateNodes,
260259
utils.StateDiffStreamBlock,
261260
utils.StateDiffWatchedAddresses,

cmd/utils/flags.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -761,10 +761,6 @@ var (
761761
Name: "statediff",
762762
Usage: "Enables the processing of state diffs between each block",
763763
}
764-
StateDiffPathsAndProofs = cli.BoolFlag{
765-
Name: "statediff.pathsandproofs",
766-
Usage: "Set to true to generate paths and proof sets for diffed state and storage trie leaf nodes",
767-
}
768764
StateDiffIntermediateNodes = cli.BoolFlag{
769765
Name: "statediff.intermediatenodes",
770766
Usage: "Set to include intermediate (branch and extension) nodes; default (false) processes leaf nodes only",
@@ -1651,17 +1647,15 @@ func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []st
16511647
// RegisterStateDiffService configures and registers a service to stream state diff data over RPC
16521648
func RegisterStateDiffService(stack *node.Node, ctx *cli.Context) {
16531649
config := statediff.Config{
1654-
PathsAndProofs: ctx.GlobalBool(StateDiffPathsAndProofs.Name),
16551650
IntermediateNodes: ctx.GlobalBool(StateDiffIntermediateNodes.Name),
16561651
StreamBlock: ctx.GlobalBool(StateDiffStreamBlock.Name),
16571652
WatchedAddresses: ctx.GlobalStringSlice(StateDiffWatchedAddresses.Name),
16581653
}
16591654
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
16601655
var ethServ *eth.Ethereum
16611656
ctx.Service(&ethServ)
1662-
chainDb := ethServ.ChainDb()
16631657
blockChain := ethServ.BlockChain()
1664-
return statediff.NewStateDiffService(chainDb, blockChain, config)
1658+
return statediff.NewStateDiffService(blockChain, config)
16651659
}); err != nil {
16661660
Fatalf("Failed to register State Diff Service", err)
16671661
}

statediff/builder.go

Lines changed: 103 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
"github.com/ethereum/go-ethereum/core"
2929
"github.com/ethereum/go-ethereum/core/state"
3030
"github.com/ethereum/go-ethereum/crypto"
31-
"github.com/ethereum/go-ethereum/ethdb"
3231
"github.com/ethereum/go-ethereum/log"
3332
"github.com/ethereum/go-ethereum/rlp"
3433
"github.com/ethereum/go-ethereum/trie"
@@ -42,16 +41,14 @@ type Builder interface {
4241
}
4342

4443
type builder struct {
45-
chainDB ethdb.Database
4644
config Config
4745
blockChain *core.BlockChain
4846
stateCache state.Database
4947
}
5048

5149
// NewBuilder is used to create a statediff builder
52-
func NewBuilder(db ethdb.Database, blockChain *core.BlockChain, config Config) Builder {
50+
func NewBuilder(blockChain *core.BlockChain, config Config) Builder {
5351
return &builder{
54-
chainDB: db,
5552
config: config,
5653
blockChain: blockChain,
5754
}
@@ -71,17 +68,13 @@ func (sdb *builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, block
7168
}
7269

7370
// Find created accounts
74-
oldIt := oldTrie.NodeIterator([]byte{})
75-
newIt := newTrie.NodeIterator([]byte{})
76-
creations, err := sdb.collectDiffNodes(oldIt, newIt)
71+
creations, err := sdb.collectDiffNodes(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
7772
if err != nil {
7873
return StateDiff{}, fmt.Errorf("error collecting creation diff nodes: %v", err)
7974
}
8075

8176
// Find deleted accounts
82-
oldIt = oldTrie.NodeIterator([]byte{})
83-
newIt = newTrie.NodeIterator([]byte{})
84-
deletions, err := sdb.collectDiffNodes(newIt, oldIt)
77+
deletions, err := sdb.collectDiffNodes(newTrie.NodeIterator([]byte{}), oldTrie.NodeIterator([]byte{}))
8578
if err != nil {
8679
return StateDiff{}, fmt.Errorf("error collecting deletion diff nodes: %v", err)
8780
}
@@ -131,58 +124,62 @@ func (sdb *builder) isWatchedAddress(hashKey []byte) bool {
131124
}
132125

133126
func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (AccountsMap, error) {
134-
var diffAccounts = make(AccountsMap)
127+
diffAccounts := make(AccountsMap)
135128
it, _ := trie.NewDifferenceIterator(a, b)
136-
for {
137-
log.Debug("Current Path and Hash", "path", pathToStr(it), "old hash", it.Hash())
138-
if it.Leaf() && sdb.isWatchedAddress(it.LeafKey()) {
139-
leafKey := make([]byte, len(it.LeafKey()))
140-
copy(leafKey, it.LeafKey())
141-
leafKeyHash := common.BytesToHash(leafKey)
142-
leafValue := make([]byte, len(it.LeafBlob()))
143-
copy(leafValue, it.LeafBlob())
144-
// lookup account state
129+
for it.Next(true) {
130+
// skip value nodes
131+
if it.Leaf() {
132+
continue
133+
}
134+
if bytes.Equal(nullNode, it.Hash().Bytes()) {
135+
continue
136+
}
137+
nodePath := make([]byte, len(it.Path()))
138+
copy(nodePath, it.Path())
139+
node, err := sdb.stateCache.TrieDB().Node(it.Hash())
140+
if err != nil {
141+
return nil, err
142+
}
143+
var nodeElements []interface{}
144+
if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
145+
return nil, err
146+
}
147+
ty, err := CheckKeyType(nodeElements)
148+
if err != nil {
149+
return nil, err
150+
}
151+
switch ty {
152+
case Leaf:
145153
var account state.Account
146-
if err := rlp.DecodeBytes(leafValue, &account); err != nil {
147-
return nil, fmt.Errorf("error looking up account via address %s\r\nerror: %v", leafKeyHash.Hex(), err)
148-
}
149-
aw := accountWrapper{
150-
Leaf: true,
151-
Account: &account,
152-
RawKey: leafKey,
153-
RawValue: leafValue,
154+
if err := rlp.DecodeBytes(nodeElements[1].([]byte), &account); err != nil {
155+
return nil, fmt.Errorf("error decoding account for leaf node at path %x\r\nerror: %v\r\n", nodePath, err)
154156
}
155-
if sdb.config.PathsAndProofs {
156-
leafProof := make([][]byte, len(it.LeafProof()))
157-
copy(leafProof, it.LeafProof())
158-
leafPath := make([]byte, len(it.Path()))
159-
copy(leafPath, it.Path())
160-
aw.Proof = leafProof
161-
aw.Path = leafPath
157+
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
158+
valueNodePath := append(nodePath, partialPath...)
159+
encodedPath := trie.HexToCompact(valueNodePath)
160+
leafKey := encodedPath[1:]
161+
if sdb.isWatchedAddress(leafKey) {
162+
aw := accountWrapper{
163+
NodeType: ty,
164+
Path: nodePath,
165+
NodeValue: node,
166+
LeafKey: leafKey,
167+
Account: &account,
168+
}
169+
diffAccounts[common.BytesToHash(encodedPath)] = aw
162170
}
163-
// record account to diffs (creation if we are looking at new - old; deletion if old - new)
164-
log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
165-
diffAccounts[leafKeyHash] = aw
166-
} else if sdb.config.IntermediateNodes && !bytes.Equal(nullNode, it.Hash().Bytes()) {
167-
nodeKey := it.Hash()
168-
node, err := sdb.stateCache.TrieDB().Node(nodeKey)
169-
if err != nil {
170-
return nil, fmt.Errorf("error looking up intermediate state trie node %s\r\nerror: %v", nodeKey.Hex(), err)
171+
case Extension, Branch:
172+
if sdb.config.IntermediateNodes {
173+
diffAccounts[common.BytesToHash(nodePath)] = accountWrapper{
174+
NodeType: ty,
175+
Path: nodePath,
176+
NodeValue: node,
177+
}
171178
}
172-
aw := accountWrapper{
173-
Leaf: false,
174-
RawKey: nodeKey.Bytes(),
175-
RawValue: node,
176-
}
177-
log.Debug("intermediate state trie node lookup successful", "key", nodeKey.Hex(), "value", node)
178-
diffAccounts[nodeKey] = aw
179-
}
180-
cont := it.Next(true)
181-
if !cont {
182-
break
179+
default:
180+
return nil, fmt.Errorf("unexpected node type %s", ty)
183181
}
184182
}
185-
186183
return diffAccounts, nil
187184
}
188185

@@ -195,16 +192,15 @@ func (sdb *builder) buildDiffEventual(accounts AccountsMap) ([]AccountDiff, erro
195192
if val.Account != nil {
196193
storageDiffs, err = sdb.buildStorageDiffsEventual(val.Account.Root)
197194
if err != nil {
198-
return nil, fmt.Errorf("failed building eventual storage diffs for %s\r\nerror: %v", common.BytesToHash(val.RawKey), err)
195+
return nil, fmt.Errorf("failed building eventual storage diffs for node %x\r\nerror: %v", val.Path, err)
199196
}
200197
}
201198
accountDiffs = append(accountDiffs, AccountDiff{
202-
Leaf: val.Leaf,
203-
Key: val.RawKey,
204-
Value: val.RawValue,
205-
Proof: val.Proof,
206-
Path: val.Path,
207-
Storage: storageDiffs,
199+
NodeType: val.NodeType,
200+
Path: val.Path,
201+
LeafKey: val.LeafKey,
202+
NodeValue: val.NodeValue,
203+
Storage: storageDiffs,
208204
})
209205
}
210206

@@ -228,12 +224,11 @@ func (sdb *builder) buildDiffIncremental(creations AccountsMap, deletions Accoun
228224
}
229225
}
230226
updatedAccounts = append(updatedAccounts, AccountDiff{
231-
Leaf: createdAcc.Leaf,
232-
Key: createdAcc.RawKey,
233-
Value: createdAcc.RawValue,
234-
Proof: createdAcc.Proof,
235-
Path: createdAcc.Path,
236-
Storage: storageDiffs,
227+
NodeType: createdAcc.NodeType,
228+
Path: createdAcc.Path,
229+
NodeValue: createdAcc.NodeValue,
230+
LeafKey: createdAcc.LeafKey,
231+
Storage: storageDiffs,
237232
})
238233
delete(creations, common.HexToHash(val))
239234
delete(deletions, common.HexToHash(val))
@@ -275,46 +270,52 @@ func (sdb *builder) buildStorageDiffsIncremental(oldSR common.Hash, newSR common
275270

276271
func (sdb *builder) buildStorageDiffsFromTrie(it trie.NodeIterator) ([]StorageDiff, error) {
277272
storageDiffs := make([]StorageDiff, 0)
278-
for {
279-
log.Debug("Iterating over state at path ", "path", pathToStr(it))
273+
for it.Next(true) {
274+
// skip value nodes
280275
if it.Leaf() {
281-
log.Debug("Found leaf in storage", "path", pathToStr(it))
282-
leafKey := make([]byte, len(it.LeafKey()))
283-
copy(leafKey, it.LeafKey())
284-
leafValue := make([]byte, len(it.LeafBlob()))
285-
copy(leafValue, it.LeafBlob())
276+
continue
277+
}
278+
if bytes.Equal(nullNode, it.Hash().Bytes()) {
279+
continue
280+
}
281+
nodePath := make([]byte, len(it.Path()))
282+
copy(nodePath, it.Path())
283+
node, err := sdb.stateCache.TrieDB().Node(it.Hash())
284+
if err != nil {
285+
return nil, err
286+
}
287+
var nodeElements []interface{}
288+
if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
289+
return nil, err
290+
}
291+
ty, err := CheckKeyType(nodeElements)
292+
if err != nil {
293+
return nil, err
294+
}
295+
switch ty {
296+
case Leaf:
297+
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
298+
valueNodePath := append(nodePath, partialPath...)
299+
encodedPath := trie.HexToCompact(valueNodePath)
300+
leafKey := encodedPath[1:]
286301
sd := StorageDiff{
287-
Leaf: true,
288-
Key: leafKey,
289-
Value: leafValue,
290-
}
291-
if sdb.config.PathsAndProofs {
292-
leafProof := make([][]byte, len(it.LeafProof()))
293-
copy(leafProof, it.LeafProof())
294-
leafPath := make([]byte, len(it.Path()))
295-
copy(leafPath, it.Path())
296-
sd.Proof = leafProof
297-
sd.Path = leafPath
302+
NodeType: ty,
303+
Path: nodePath,
304+
NodeValue: node,
305+
LeafKey: leafKey,
298306
}
299307
storageDiffs = append(storageDiffs, sd)
300-
} else if sdb.config.IntermediateNodes && !bytes.Equal(nullNode, it.Hash().Bytes()) {
301-
nodeKey := it.Hash()
302-
node, err := sdb.stateCache.TrieDB().Node(nodeKey)
303-
if err != nil {
304-
return nil, fmt.Errorf("error looking up intermediate storage trie node %s\r\nerror: %v", nodeKey.Hex(), err)
308+
case Extension, Branch:
309+
if sdb.config.IntermediateNodes {
310+
storageDiffs = append(storageDiffs, StorageDiff{
311+
NodeType: ty,
312+
Path: nodePath,
313+
NodeValue: node,
314+
})
305315
}
306-
storageDiffs = append(storageDiffs, StorageDiff{
307-
Leaf: false,
308-
Key: nodeKey.Bytes(),
309-
Value: node,
310-
})
311-
log.Debug("intermediate storage trie node lookup successful", "key", nodeKey.Hex(), "value", node)
312-
}
313-
cont := it.Next(true)
314-
if !cont {
315-
break
316+
default:
317+
return nil, fmt.Errorf("unexpected node type %s", ty)
316318
}
317319
}
318-
319320
return storageDiffs, nil
320321
}

0 commit comments

Comments
 (0)