comments; explain logic

This commit is contained in:
Ian Norden 2020-05-14 16:03:36 -05:00
parent aa7c5b0869
commit 2ad905ff75

View File

@ -58,7 +58,7 @@ func (sdb *builder) BuildStateDiff(args Args, params Params) (StateDiff, error)
}
func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params Params) (StateDiff, error) {
// Generate tries for old and new states
// Load tries for old and new states
oldTrie, err := sdb.stateCache.OpenTrie(args.OldStateRoot)
if err != nil {
return StateDiff{}, fmt.Errorf("error creating trie for oldStateRoot: %v", err)
@ -68,35 +68,48 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P
return StateDiff{}, fmt.Errorf("error creating trie for newStateRoot: %v", err)
}
// collect a slice of all the intermediate nodes that were touched and exist at B
// a map of their leafkey to all the accounts that were touched and exist at B
// and a slice of all the paths for the nodes in both of the above sets
createdOrUpdatedIntermediateNodes, diffAccountsAtB, diffPathsAtB, err := sdb.createdAndUpdatedNodes(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
if err != nil {
return StateDiff{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err)
}
// collect a slice of all the intermediate nodes that existed at A but don't at B
// a map of their leafkey to all the accounts that were touched and exist at A
deletedIntermediateNodes, diffAccountsAtA, err := sdb.deletedOrUpdatedNodes(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), diffPathsAtB)
if err != nil {
return StateDiff{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
}
// Find all the diffed keys
// collect and sort the leafkey keys for both account mappings into a slice
createKeys := sortKeys(diffAccountsAtB)
deleteKeys := sortKeys(diffAccountsAtA)
// and then find the intersection of these keys
// these are the leafkeys for the accounts which exist at both A and B but are different
// this also mutates the passed in createKeys and deleteKeys, removing in intersection keys
// and leaving the truly created or deleted keys in place
updatedKeys := findIntersection(createKeys, deleteKeys)
// Build and return the statediff
// build the diff nodes for the updated accounts using the mappings at both A and B as directed by the keys found as the intersection of the two
updatedAccounts, err := sdb.buildAccountUpdates(diffAccountsAtB, diffAccountsAtA, updatedKeys, params.WatchedStorageSlots, params.IntermediateStorageNodes)
if err != nil {
return StateDiff{}, fmt.Errorf("error building diff for updated accounts: %v", err)
}
// build the diff nodes for created accounts
createdAccounts, err := sdb.buildAccountCreations(diffAccountsAtB, params.WatchedStorageSlots, params.IntermediateStorageNodes)
if err != nil {
return StateDiff{}, fmt.Errorf("error building diff for created accounts: %v", err)
}
// build the diff nodes for deleted accounts
deletedAccounts, err := sdb.buildAccountDeletions(diffAccountsAtA)
if err != nil {
return StateDiff{}, fmt.Errorf("error building diff for deleted accounts: %v", err)
}
// assemble all of the nodes into the statediff object, including the intermediate nodes
return StateDiff{
BlockNumber: args.BlockNumber,
BlockHash: args.BlockHash,
@ -105,7 +118,7 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P
}
func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, params Params) (StateDiff, error) {
// Generate tries for old and new states
// Load tries for old (A) and new (B) states
oldTrie, err := sdb.stateCache.OpenTrie(args.OldStateRoot)
if err != nil {
return StateDiff{}, fmt.Errorf("error creating trie for oldStateRoot: %v", err)
@ -115,35 +128,45 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, param
return StateDiff{}, fmt.Errorf("error creating trie for newStateRoot: %v", err)
}
// collect a map of their leafkey to all the accounts that were touched and exist at B
diffAccountsAtB, err := sdb.collectDiffAccounts(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), params.WatchedAddresses)
if err != nil {
return StateDiff{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err)
}
// collect a map of their leafkey to all the accounts that were touched and exist at A
diffAccountsAtA, err := sdb.collectDiffAccounts(newTrie.NodeIterator([]byte{}), oldTrie.NodeIterator([]byte{}), params.WatchedAddresses)
if err != nil {
return StateDiff{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
}
// Find all the diffed keys
// collect and sort the leafkeys for both account mappings into a slice
createKeys := sortKeys(diffAccountsAtB)
deleteKeys := sortKeys(diffAccountsAtA)
// and then find the intersection of these keys
// these are the leafkeys for the accounts which exist at both A and B but are different
// this also mutates the passed in createKeys and deleteKeys, removing in intersection keys
// and leaving the truly created or deleted keys in place
updatedKeys := findIntersection(createKeys, deleteKeys)
// Build and return the statediff
// build the diff nodes for the updated accounts using the mappings at both A and B as directed by the keys found as the intersection of the two
updatedAccounts, err := sdb.buildAccountUpdates(diffAccountsAtB, diffAccountsAtA, updatedKeys, params.WatchedStorageSlots, params.IntermediateStorageNodes)
if err != nil {
return StateDiff{}, fmt.Errorf("error building diff for updated accounts: %v", err)
}
// build the diff nodes for created accounts
createdAccounts, err := sdb.buildAccountCreations(diffAccountsAtB, params.WatchedStorageSlots, params.IntermediateStorageNodes)
if err != nil {
return StateDiff{}, fmt.Errorf("error building diff for created accounts: %v", err)
}
// build the diff nodes for deleted accounts
deletedAccounts, err := sdb.buildAccountDeletions(diffAccountsAtA)
if err != nil {
return StateDiff{}, fmt.Errorf("error building diff for deleted accounts: %v", err)
}
// assemble all of the nodes into the statediff object
return StateDiff{
BlockNumber: args.BlockNumber,
BlockHash: args.BlockHash,
@ -151,6 +174,8 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, param
}, nil
}
// collectDiffAccounts returns a mapping of their leafkeys to all the accounts that exist in a different state at B than A
// restricts the returned set to the watchedAddresses if any are provided
func (sdb *builder) collectDiffAccounts(a, b trie.NodeIterator, watchedAddresses []common.Address) (AccountMap, error) {
diffAcountsAtB := make(AccountMap)
it, _ := trie.NewDifferenceIterator(a, b)
@ -206,26 +231,9 @@ func (sdb *builder) collectDiffAccounts(a, b trie.NodeIterator, watchedAddresses
return diffAcountsAtB, nil
}
// isWatchedAddress is used to check if a state account corresponds to one of the addresses the builder is configured to watch
func isWatchedAddress(watchedAddresses []common.Address, stateLeafKey []byte) bool {
// If we aren't watching any specific addresses, we are watching everything
if len(watchedAddresses) == 0 {
return true
}
for _, addr := range watchedAddresses {
addrHashKey := crypto.Keccak256(addr.Bytes())
if bytes.Equal(addrHashKey, stateLeafKey) {
return true
}
}
return false
}
// createdAndUpdatedNodes returns a slice of all the intermediate nodes that are different in b than they are in a
// it also returns a map of LEAFKEY to all the leaf nodes (accounts) that are different in b than they are in a
// it also returns a list of the intermediate node paths that were touched and the leaf node PATHs that were touched
// this function should only be called b = the NodeIterator for the state trie at a.blockheight + 1
// make version for leaf nodes only
// createdAndUpdatedNodes returns a slice of all the intermediate nodes that exist in a different state at B than A
// a mapping of their leafkeys to all the accounts that exist in a different state at B than A
// and a slice of the paths for all of the nodes included in both
func (sdb *builder) createdAndUpdatedNodes(a, b trie.NodeIterator) ([]StateNode, AccountMap, map[string]bool, error) {
createdOrUpdatedIntermediateNodes := make([]StateNode, 0)
diffPathsAtB := make(map[string]bool)
@ -289,6 +297,8 @@ func (sdb *builder) createdAndUpdatedNodes(a, b trie.NodeIterator) ([]StateNode,
return createdOrUpdatedIntermediateNodes, diffAcountsAtB, diffPathsAtB, nil
}
// deletedOrUpdatedNodes returns a slice of all the intermediate nodes that exist at A but not at B
// a mapping of their leafkeys to all the accounts that exist in a different state at A than B
func (sdb *builder) deletedOrUpdatedNodes(a, b trie.NodeIterator, diffPathsAtB map[string]bool) ([]StateNode, AccountMap, error) {
deletedIntermediateNodes := make([]StateNode, 0)
diffAccountAtA := make(AccountMap)
@ -335,7 +345,8 @@ func (sdb *builder) deletedOrUpdatedNodes(a, b trie.NodeIterator, diffPathsAtB m
}
case Extension, Branch:
// if this nodePath did not show up in diffPathsAtB
// that means the node at this path at A was deleted in B
// that means the node at this path was deleted in B
// emit an empty "removed" diff to signify as such
if _, ok := diffPathsAtB[common.Bytes2Hex(nodePath)]; !ok {
deletedIntermediateNodes = append(deletedIntermediateNodes, StateNode{
NodeType: Removed,
@ -350,7 +361,9 @@ func (sdb *builder) deletedOrUpdatedNodes(a, b trie.NodeIterator, diffPathsAtB m
return deletedIntermediateNodes, diffAccountAtA, nil
}
// needs to be called before building account creations and deletions as this mutattes
// buildAccountUpdates uses the account diffs maps for A => B and B => A and the known intersection of their leafkeys
// to generate the statediff node objects for all of the accounts that existed at both A and B but in different states
// needs to be called before building account creations and deletions as this mutates
// those account maps to remove the accounts which were updated
func (sdb *builder) buildAccountUpdates(creations, deletions AccountMap, updatedKeys []string, watchedStorageKeys []common.Hash, intermediateStorageNodes bool) ([]StateNode, error) {
updatedAccounts := make([]StateNode, 0, len(updatedKeys))
@ -381,6 +394,7 @@ func (sdb *builder) buildAccountUpdates(creations, deletions AccountMap, updated
return updatedAccounts, nil
}
// buildAccountCreations returns the statediff node objects for all the accounts that exist at B but not at A
func (sdb *builder) buildAccountCreations(accounts AccountMap, watchedStorageKeys []common.Hash, intermediateStorageNodes bool) ([]StateNode, error) {
accountDiffs := make([]StateNode, 0, len(accounts))
for _, val := range accounts {
@ -401,6 +415,8 @@ func (sdb *builder) buildAccountCreations(accounts AccountMap, watchedStorageKey
return accountDiffs, nil
}
// buildAccountDeletions returns the state diff "removed" empty node objects
// to represent when an account exists at A but not at B
func (sdb *builder) buildAccountDeletions(accounts AccountMap) ([]StateNode, error) {
accountDiffs := make([]StateNode, 0, len(accounts))
for _, val := range accounts {
@ -415,6 +431,8 @@ func (sdb *builder) buildAccountDeletions(accounts AccountMap) ([]StateNode, err
return accountDiffs, nil
}
// buildStorageNodesEventual builds the storage diff node objects for a created account
// i.e. it returns all the storage nodes at this state, since there is no previous state
func (sdb *builder) buildStorageNodesEventual(sr common.Hash, watchedStorageKeys []common.Hash, intermediateNodes bool) ([]StorageNode, error) {
log.Debug("Storage Root For Eventual Diff", "root", sr.Hex())
sTrie, err := sdb.stateCache.OpenTrie(sr)
@ -426,6 +444,8 @@ func (sdb *builder) buildStorageNodesEventual(sr common.Hash, watchedStorageKeys
return sdb.buildStorageNodesFromTrie(it, watchedStorageKeys, intermediateNodes)
}
// buildStorageNodesIncremental builds the storage diff node objects for all nodes that exist in a different state at B than A
// this assumes storage leafs cannot be deleted like accounts can be due to EIP-158
func (sdb *builder) buildStorageNodesIncremental(oldSR common.Hash, newSR common.Hash, watchedStorageKeys []common.Hash, intermediateNodes bool) ([]StorageNode, error) {
log.Debug("Storage Roots for Incremental Diff", "old", oldSR.Hex(), "new", newSR.Hex())
oldTrie, err := sdb.stateCache.OpenTrie(oldSR)
@ -443,6 +463,9 @@ func (sdb *builder) buildStorageNodesIncremental(oldSR common.Hash, newSR common
return sdb.buildStorageNodesFromTrie(it, watchedStorageKeys, intermediateNodes)
}
// buildStorageNodesFromTrie returns all the storage diff node objects in the provided node interator
// if any storage keys are provided it will only return those leaf nodes
// including intermediate nodes can be turned on or off
func (sdb *builder) buildStorageNodesFromTrie(it trie.NodeIterator, watchedStorageKeys []common.Hash, intermediateNodes bool) ([]StorageNode, error) {
storageDiffs := make([]StorageNode, 0)
for it.Next(true) {
@ -496,6 +519,21 @@ func (sdb *builder) buildStorageNodesFromTrie(it trie.NodeIterator, watchedStora
return storageDiffs, nil
}
// isWatchedAddress is used to check if a state account corresponds to one of the addresses the builder is configured to watch
func isWatchedAddress(watchedAddresses []common.Address, stateLeafKey []byte) bool {
// If we aren't watching any specific addresses, we are watching everything
if len(watchedAddresses) == 0 {
return true
}
for _, addr := range watchedAddresses {
addrHashKey := crypto.Keccak256(addr.Bytes())
if bytes.Equal(addrHashKey, stateLeafKey) {
return true
}
}
return false
}
// isWatchedStorageKey is used to check if a storage leaf corresponds to one of the storage slots the builder is configured to watch
func isWatchedStorageKey(watchedKeys []common.Hash, storageLeafKey []byte) bool {
// If we aren't watching any specific addresses, we are watching everything