3636 nullHashBytes = common .Hex2Bytes ("0000000000000000000000000000000000000000000000000000000000000000" )
3737 emptyNode , _ = rlp .EncodeToBytes ([]byte {})
3838 emptyContractRoot = crypto .Keccak256Hash (emptyNode )
39+ nullCodeHash = crypto .Keccak256Hash ([]byte {}).Bytes ()
3940)
4041
4142// Builder interface exposes the method for building a state diff between two blocks
@@ -62,19 +63,21 @@ func (sdb *builder) BuildStateTrieObject(current *types.Block) (StateObject, err
6263 return StateObject {}, fmt .Errorf ("error creating trie for block %d: %v" , current .Number (), err )
6364 }
6465 it := currentTrie .NodeIterator ([]byte {})
65- stateNodes , err := sdb .buildStateTrie (it )
66+ stateNodes , codeAndCodeHashes , err := sdb .buildStateTrie (it )
6667 if err != nil {
6768 return StateObject {}, fmt .Errorf ("error collecting state nodes for block %d: %v" , current .Number (), err )
6869 }
6970 return StateObject {
70- BlockNumber : current .Number (),
71- BlockHash : current .Hash (),
72- Nodes : stateNodes ,
71+ BlockNumber : current .Number (),
72+ BlockHash : current .Hash (),
73+ Nodes : stateNodes ,
74+ CodeAndCodeHashes : codeAndCodeHashes ,
7375 }, nil
7476}
7577
76- func (sdb * builder ) buildStateTrie (it trie.NodeIterator ) ([]StateNode , error ) {
78+ func (sdb * builder ) buildStateTrie (it trie.NodeIterator ) ([]StateNode , [] CodeAndCodeHash , error ) {
7779 stateNodes := make ([]StateNode , 0 )
80+ codeAndCodeHashes := make ([]CodeAndCodeHash , 0 )
7881 for it .Next (true ) {
7982 // skip value nodes
8083 if it .Leaf () {
@@ -87,48 +90,62 @@ func (sdb *builder) buildStateTrie(it trie.NodeIterator) ([]StateNode, error) {
8790 copy (nodePath , it .Path ())
8891 node , err := sdb .stateCache .TrieDB ().Node (it .Hash ())
8992 if err != nil {
90- return nil , err
93+ return nil , nil , err
9194 }
9295 var nodeElements []interface {}
9396 if err := rlp .DecodeBytes (node , & nodeElements ); err != nil {
94- return nil , err
97+ return nil , nil , err
9598 }
9699 ty , err := CheckKeyType (nodeElements )
97100 if err != nil {
98- return nil , err
101+ return nil , nil , err
99102 }
100103 switch ty {
101104 case Leaf :
102105 var account state.Account
103106 if err := rlp .DecodeBytes (nodeElements [1 ].([]byte ), & account ); err != nil {
104- return nil , fmt .Errorf ("error decoding account for leaf node at path %x nerror: %v" , nodePath , err )
107+ return nil , nil , fmt .Errorf ("error decoding account for leaf node at path %x nerror: %v" , nodePath , err )
105108 }
106109 partialPath := trie .CompactToHex (nodeElements [0 ].([]byte ))
107110 valueNodePath := append (nodePath , partialPath ... )
108111 encodedPath := trie .HexToCompact (valueNodePath )
109112 leafKey := encodedPath [1 :]
110- storageNodes , err := sdb .buildStorageNodesEventual (account .Root , nil , true )
111- if err != nil {
112- return nil , fmt .Errorf ("failed building eventual storage diffs for account %+v\r \n error: %v" , account , err )
113+ node := StateNode {
114+ NodeType : ty ,
115+ Path : nodePath ,
116+ LeafKey : leafKey ,
117+ NodeValue : node ,
113118 }
114- stateNodes = append (stateNodes , StateNode {
115- NodeType : ty ,
116- Path : nodePath ,
117- LeafKey : leafKey ,
118- NodeValue : node ,
119- StorageNodes : storageNodes ,
120- })
119+ if ! bytes .Equal (account .CodeHash , nullCodeHash ) {
120+ storageNodes , err := sdb .buildStorageNodesEventual (account .Root , nil , true )
121+ if err != nil {
122+ return nil , nil , fmt .Errorf ("failed building eventual storage diffs for account %+v\r \n error: %v" , account , err )
123+ }
124+ node .StorageNodes = storageNodes
125+ // emit codehash => code mappings for cod
126+ codeHash := common .BytesToHash (account .CodeHash )
127+ addrHash := common .BytesToHash (leafKey )
128+ code , err := sdb .stateCache .ContractCode (addrHash , codeHash )
129+ if err != nil {
130+ return nil , nil , fmt .Errorf ("failed to retrieve code for codehash %s for account with leafkey %s\r \n error: %v" , codeHash .String (), addrHash .String (), err )
131+ }
132+ codeAndCodeHashes = append (codeAndCodeHashes , CodeAndCodeHash {
133+ Hash : codeHash ,
134+ Code : code ,
135+ })
136+ }
137+ stateNodes = append (stateNodes , node )
121138 case Extension , Branch :
122139 stateNodes = append (stateNodes , StateNode {
123140 NodeType : ty ,
124141 Path : nodePath ,
125142 NodeValue : node ,
126143 })
127144 default :
128- return nil , fmt .Errorf ("unexpected node type %s" , ty )
145+ return nil , nil , fmt .Errorf ("unexpected node type %s" , ty )
129146 }
130147 }
131- return stateNodes , it .Error ()
148+ return stateNodes , codeAndCodeHashes , it .Error ()
132149}
133150
134151// BuildStateDiffObject builds a statediff object from two blocks and the provided parameters
@@ -181,16 +198,17 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P
181198 return StateObject {}, fmt .Errorf ("error building diff for updated accounts: %v" , err )
182199 }
183200 // build the diff nodes for created accounts
184- createdAccounts , err := sdb .buildAccountCreations (diffAccountsAtB , params .WatchedStorageSlots , params .IntermediateStorageNodes )
201+ createdAccounts , codeAndCodeHashes , err := sdb .buildAccountCreations (diffAccountsAtB , params .WatchedStorageSlots , params .IntermediateStorageNodes )
185202 if err != nil {
186203 return StateObject {}, fmt .Errorf ("error building diff for created accounts: %v" , err )
187204 }
188205
189206 // assemble all of the nodes into the statediff object, including the intermediate nodes
190207 return StateObject {
191- BlockNumber : args .BlockNumber ,
192- BlockHash : args .BlockHash ,
193- Nodes : append (append (append (updatedAccounts , createdAccounts ... ), createdOrUpdatedIntermediateNodes ... ), emptiedPaths ... ),
208+ BlockNumber : args .BlockNumber ,
209+ BlockHash : args .BlockHash ,
210+ Nodes : append (append (append (updatedAccounts , createdAccounts ... ), createdOrUpdatedIntermediateNodes ... ), emptiedPaths ... ),
211+ CodeAndCodeHashes : codeAndCodeHashes ,
194212 }, nil
195213}
196214
@@ -235,16 +253,17 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, param
235253 return StateObject {}, fmt .Errorf ("error building diff for updated accounts: %v" , err )
236254 }
237255 // build the diff nodes for created accounts
238- createdAccounts , err := sdb .buildAccountCreations (diffAccountsAtB , params .WatchedStorageSlots , params .IntermediateStorageNodes )
256+ createdAccounts , codeAndCodeHashes , err := sdb .buildAccountCreations (diffAccountsAtB , params .WatchedStorageSlots , params .IntermediateStorageNodes )
239257 if err != nil {
240258 return StateObject {}, fmt .Errorf ("error building diff for created accounts: %v" , err )
241259 }
242260
243261 // assemble all of the nodes into the statediff object
244262 return StateObject {
245- BlockNumber : args .BlockNumber ,
246- BlockHash : args .BlockHash ,
247- Nodes : append (append (updatedAccounts , createdAccounts ... ), emptiedPaths ... ),
263+ BlockNumber : args .BlockNumber ,
264+ BlockHash : args .BlockHash ,
265+ Nodes : append (append (updatedAccounts , createdAccounts ... ), emptiedPaths ... ),
266+ CodeAndCodeHashes : codeAndCodeHashes ,
248267 }, nil
249268}
250269
@@ -470,24 +489,40 @@ func (sdb *builder) buildAccountUpdates(creations, deletions AccountMap, updated
470489}
471490
472491// buildAccountCreations returns the statediff node objects for all the accounts that exist at B but not at A
473- func (sdb * builder ) buildAccountCreations (accounts AccountMap , watchedStorageKeys []common.Hash , intermediateStorageNodes bool ) ([]StateNode , error ) {
492+ // it also returns the code and codehash for created contract accounts
493+ func (sdb * builder ) buildAccountCreations (accounts AccountMap , watchedStorageKeys []common.Hash , intermediateStorageNodes bool ) ([]StateNode , []CodeAndCodeHash , error ) {
474494 accountDiffs := make ([]StateNode , 0 , len (accounts ))
495+ codeAndCodeHashes := make ([]CodeAndCodeHash , 0 )
475496 for _ , val := range accounts {
476- // For account creations, any storage node contained is a diff
477- storageDiffs , err := sdb .buildStorageNodesEventual (val .Account .Root , watchedStorageKeys , intermediateStorageNodes )
478- if err != nil {
479- return nil , fmt .Errorf ("failed building eventual storage diffs for node %x\r \n error: %v" , val .Path , err )
497+ diff := StateNode {
498+ NodeType : val .NodeType ,
499+ Path : val .Path ,
500+ LeafKey : val .LeafKey ,
501+ NodeValue : val .NodeValue ,
502+ }
503+ if ! bytes .Equal (val .Account .CodeHash , nullCodeHash ) {
504+ // For contract creations, any storage node contained is a diff
505+ storageDiffs , err := sdb .buildStorageNodesEventual (val .Account .Root , watchedStorageKeys , intermediateStorageNodes )
506+ if err != nil {
507+ return nil , nil , fmt .Errorf ("failed building eventual storage diffs for node %x\r \n error: %v" , val .Path , err )
508+ }
509+ diff .StorageNodes = storageDiffs
510+ // emit codehash => code mappings for cod
511+ codeHash := common .BytesToHash (val .Account .CodeHash )
512+ addrHash := common .BytesToHash (val .LeafKey )
513+ code , err := sdb .stateCache .ContractCode (addrHash , codeHash )
514+ if err != nil {
515+ return nil , nil , fmt .Errorf ("failed to retrieve code for codehash %s for account with leafkey %s\r \n error: %v" , codeHash .String (), addrHash .String (), err )
516+ }
517+ codeAndCodeHashes = append (codeAndCodeHashes , CodeAndCodeHash {
518+ Hash : codeHash ,
519+ Code : code ,
520+ })
480521 }
481- accountDiffs = append (accountDiffs , StateNode {
482- NodeType : val .NodeType ,
483- Path : val .Path ,
484- LeafKey : val .LeafKey ,
485- NodeValue : val .NodeValue ,
486- StorageNodes : storageDiffs ,
487- })
522+ accountDiffs = append (accountDiffs , diff )
488523 }
489524
490- return accountDiffs , nil
525+ return accountDiffs , codeAndCodeHashes , nil
491526}
492527
493528// buildStorageNodesEventual builds the storage diff node objects for a created account
0 commit comments