minor changes/fixes
This commit is contained in:
parent
7ba6efa59c
commit
97454eb6fe
@ -23,10 +23,9 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@ -154,14 +153,14 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P
|
|||||||
// collect a slice of all the intermediate nodes that were touched and exist at B
|
// 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
|
// 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
|
// and a slice of all the paths for the nodes in both of the above sets
|
||||||
createdOrUpdatedIntermediateNodes, diffAccountsAtB, diffPathsAtB, err := sdb.createdAndUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
|
createdOrUpdatedIntermediateNodes, diffAccountsAtB, diffPathsAtB, err := sdb.createdAndUpdatedStateWithIntermediateNodes(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StateObject{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err)
|
return StateObject{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect a slice of all the nodes that existed at a path in A that doesn't exist in B
|
// collect a slice of all the nodes that existed at a path in A that doesn't exist in B
|
||||||
// a map of their leafkey to all the accounts that were touched and exist at A
|
// a map of their leafkey to all the accounts that were touched and exist at A
|
||||||
deletedNodes, diffAccountsAtA, err := sdb.deletedOrUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), diffPathsAtB)
|
emptiedPaths, diffAccountsAtA, err := sdb.deletedOrUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), diffPathsAtB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StateObject{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
|
return StateObject{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
|
||||||
}
|
}
|
||||||
@ -191,7 +190,7 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P
|
|||||||
return StateObject{
|
return StateObject{
|
||||||
BlockNumber: args.BlockNumber,
|
BlockNumber: args.BlockNumber,
|
||||||
BlockHash: args.BlockHash,
|
BlockHash: args.BlockHash,
|
||||||
Nodes: append(append(append(updatedAccounts, createdAccounts...), createdOrUpdatedIntermediateNodes...), deletedNodes...),
|
Nodes: append(append(append(updatedAccounts, createdAccounts...), createdOrUpdatedIntermediateNodes...), emptiedPaths...),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,13 +206,15 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, param
|
|||||||
}
|
}
|
||||||
|
|
||||||
// collect a map of their leafkey to all the accounts that were touched and exist at B
|
// 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)
|
// and a slice of all the paths for the nodes in both of the above sets
|
||||||
|
diffAccountsAtB, diffPathsAtB, err := sdb.createdAndUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), params.WatchedAddresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StateObject{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err)
|
return StateObject{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect a map of their leafkey to all the accounts that were touched and exist at A
|
// collect a slice of all the nodes that existed at a path in A that doesn't exist in B
|
||||||
diffAccountsAtA, err := sdb.collectDiffAccounts(newTrie.NodeIterator([]byte{}), oldTrie.NodeIterator([]byte{}), params.WatchedAddresses)
|
// a map of their leafkey to all the accounts that were touched and exist at A
|
||||||
|
emptiedPaths, diffAccountsAtA, err := sdb.deletedOrUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), diffPathsAtB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StateObject{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
|
return StateObject{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
|
||||||
}
|
}
|
||||||
@ -238,23 +239,20 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, param
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return StateObject{}, fmt.Errorf("error building diff for created accounts: %v", err)
|
return StateObject{}, 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 StateObject{}, fmt.Errorf("error building diff for deleted accounts: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// assemble all of the nodes into the statediff object
|
// assemble all of the nodes into the statediff object
|
||||||
return StateObject{
|
return StateObject{
|
||||||
BlockNumber: args.BlockNumber,
|
BlockNumber: args.BlockNumber,
|
||||||
BlockHash: args.BlockHash,
|
BlockHash: args.BlockHash,
|
||||||
Nodes: append(append(updatedAccounts, createdAccounts...), deletedAccounts...),
|
Nodes: append(append(updatedAccounts, createdAccounts...), emptiedPaths...),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// collectDiffAccounts returns a mapping of their leafkeys to all the accounts that exist in a different state at B than A
|
// createdAndUpdatedState returns
|
||||||
// restricts the returned set to the watchedAddresses if any are provided
|
// a mapping of their leafkeys to all the accounts that exist in a different state at B than A
|
||||||
func (sdb *builder) collectDiffAccounts(a, b trie.NodeIterator, watchedAddresses []common.Address) (AccountMap, error) {
|
// and a slice of the paths for all of the nodes included in both
|
||||||
|
func (sdb *builder) createdAndUpdatedState(a, b trie.NodeIterator, watchedAddresses []common.Address) (AccountMap, map[string]bool, error) {
|
||||||
|
diffPathsAtB := make(map[string]bool)
|
||||||
diffAcountsAtB := make(AccountMap)
|
diffAcountsAtB := make(AccountMap)
|
||||||
it, _ := trie.NewDifferenceIterator(a, b)
|
it, _ := trie.NewDifferenceIterator(a, b)
|
||||||
for it.Next(true) {
|
for it.Next(true) {
|
||||||
@ -269,23 +267,22 @@ func (sdb *builder) collectDiffAccounts(a, b trie.NodeIterator, watchedAddresses
|
|||||||
copy(nodePath, it.Path())
|
copy(nodePath, it.Path())
|
||||||
node, err := sdb.stateCache.TrieDB().Node(it.Hash())
|
node, err := sdb.stateCache.TrieDB().Node(it.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
var nodeElements []interface{}
|
var nodeElements []interface{}
|
||||||
if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
|
if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
ty, err := CheckKeyType(nodeElements)
|
ty, err := CheckKeyType(nodeElements)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
switch ty {
|
if ty == Leaf {
|
||||||
case Leaf:
|
|
||||||
// created vs updated is important for leaf nodes since we need to diff their storage
|
// created vs updated is important for leaf nodes since we need to diff their storage
|
||||||
// so we need to map all changed accounts at B to their leafkey, since account can change pathes but not leafkey
|
// so we need to map all changed accounts at B to their leafkey, since account can change pathes but not leafkey
|
||||||
var account state.Account
|
var account state.Account
|
||||||
if err := rlp.DecodeBytes(nodeElements[1].([]byte), &account); err != nil {
|
if err := rlp.DecodeBytes(nodeElements[1].([]byte), &account); err != nil {
|
||||||
return nil, fmt.Errorf("error decoding account for leaf node at path %x nerror: %v", nodePath, err)
|
return nil, nil, fmt.Errorf("error decoding account for leaf node at path %x nerror: %v", nodePath, err)
|
||||||
}
|
}
|
||||||
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
|
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
|
||||||
valueNodePath := append(nodePath, partialPath...)
|
valueNodePath := append(nodePath, partialPath...)
|
||||||
@ -300,19 +297,18 @@ func (sdb *builder) collectDiffAccounts(a, b trie.NodeIterator, watchedAddresses
|
|||||||
Account: &account,
|
Account: &account,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Extension, Branch:
|
|
||||||
// fall through to next iteration
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unexpected node type %s", ty)
|
|
||||||
}
|
}
|
||||||
|
// add both intermediate and leaf node paths to the list of diffPathsAtB
|
||||||
|
diffPathsAtB[common.Bytes2Hex(nodePath)] = true
|
||||||
}
|
}
|
||||||
return diffAcountsAtB, nil
|
return diffAcountsAtB, diffPathsAtB, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createdAndUpdatedState returns a slice of all the intermediate nodes that exist in a different state at B than A
|
// createdAndUpdatedStateWithIntermediateNodes 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
|
// 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
|
// and a slice of the paths for all of the nodes included in both
|
||||||
func (sdb *builder) createdAndUpdatedState(a, b trie.NodeIterator) ([]StateNode, AccountMap, map[string]bool, error) {
|
func (sdb *builder) createdAndUpdatedStateWithIntermediateNodes(a, b trie.NodeIterator) ([]StateNode, AccountMap, map[string]bool, error) {
|
||||||
createdOrUpdatedIntermediateNodes := make([]StateNode, 0)
|
createdOrUpdatedIntermediateNodes := make([]StateNode, 0)
|
||||||
diffPathsAtB := make(map[string]bool)
|
diffPathsAtB := make(map[string]bool)
|
||||||
diffAcountsAtB := make(AccountMap)
|
diffAcountsAtB := make(AccountMap)
|
||||||
@ -375,10 +371,10 @@ func (sdb *builder) createdAndUpdatedState(a, b trie.NodeIterator) ([]StateNode,
|
|||||||
return createdOrUpdatedIntermediateNodes, diffAcountsAtB, diffPathsAtB, nil
|
return createdOrUpdatedIntermediateNodes, diffAcountsAtB, diffPathsAtB, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deletedOrUpdatedState returns a slice of all the nodes that exist at A but not at B
|
// deletedOrUpdatedState returns a slice of all the pathes that are emptied at B
|
||||||
// and a mapping of their leafkeys to all the accounts that exist in a different state at A than B
|
// and a mapping of their leafkeys to all the accounts that exist in a different state at A than B
|
||||||
func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB map[string]bool) ([]StateNode, AccountMap, error) {
|
func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB map[string]bool) ([]StateNode, AccountMap, error) {
|
||||||
deletedNodes := make([]StateNode, 0)
|
emptiedPaths := make([]StateNode, 0)
|
||||||
diffAccountAtA := make(AccountMap)
|
diffAccountAtA := make(AccountMap)
|
||||||
it, _ := trie.NewDifferenceIterator(b, a)
|
it, _ := trie.NewDifferenceIterator(b, a)
|
||||||
for it.Next(true) {
|
for it.Next(true) {
|
||||||
@ -395,10 +391,10 @@ func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB m
|
|||||||
// that means the node at this path was deleted (or moved) in B
|
// that means the node at this path was deleted (or moved) in B
|
||||||
// emit an empty "removed" diff to signify as such
|
// emit an empty "removed" diff to signify as such
|
||||||
if _, ok := diffPathsAtB[common.Bytes2Hex(nodePath)]; !ok {
|
if _, ok := diffPathsAtB[common.Bytes2Hex(nodePath)]; !ok {
|
||||||
deletedNodes = append(deletedNodes, StateNode{
|
emptiedPaths = append(emptiedPaths, StateNode{
|
||||||
NodeType: Removed,
|
|
||||||
Path: nodePath,
|
Path: nodePath,
|
||||||
NodeValue: []byte{},
|
NodeValue: []byte{},
|
||||||
|
NodeType: Removed,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
node, err := sdb.stateCache.TrieDB().Node(it.Hash())
|
node, err := sdb.stateCache.TrieDB().Node(it.Hash())
|
||||||
@ -437,7 +433,7 @@ func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB m
|
|||||||
return nil, nil, fmt.Errorf("unexpected node type %s", ty)
|
return nil, nil, fmt.Errorf("unexpected node type %s", ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return deletedNodes, diffAccountAtA, nil
|
return emptiedPaths, diffAccountAtA, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildAccountUpdates uses the account diffs maps for A => B and B => A and the known intersection of their leafkeys
|
// buildAccountUpdates uses the account diffs maps for A => B and B => A and the known intersection of their leafkeys
|
||||||
@ -494,21 +490,6 @@ func (sdb *builder) buildAccountCreations(accounts AccountMap, watchedStorageKey
|
|||||||
return accountDiffs, nil
|
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 {
|
|
||||||
// For account deletions, we can not have any storage or the account would not be deleted
|
|
||||||
accountDiffs = append(accountDiffs, StateNode{
|
|
||||||
NodeType: Removed,
|
|
||||||
Path: val.Path,
|
|
||||||
NodeValue: []byte{},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return accountDiffs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildStorageNodesEventual builds the storage diff node objects for a created account
|
// 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
|
// 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) {
|
func (sdb *builder) buildStorageNodesEventual(sr common.Hash, watchedStorageKeys []common.Hash, intermediateNodes bool) ([]StorageNode, error) {
|
||||||
|
@ -1968,12 +1968,11 @@ func TestBuilderWithMovedAccountOnlyLeafs(t *testing.T) {
|
|||||||
NodeType: statediff.Removed,
|
NodeType: statediff.Removed,
|
||||||
NodeValue: []byte{},
|
NodeValue: []byte{},
|
||||||
},
|
},
|
||||||
// For accounts that move up a level due to the deletion of the only other child account of a shared parent branch node,
|
{
|
||||||
// the leaf-only diffing process emits a node for the account at the new path
|
Path: []byte{'\x00'},
|
||||||
// but does not emit a "removed" node object for the now empty path
|
NodeType: statediff.Removed,
|
||||||
// Fix this, not a major issue since if you are not watching intermediate nodes you aren't worried about the complete picture in the first place
|
NodeValue: []byte{},
|
||||||
// One solution is to simply use the same process as when including intermediate nodes and simply discard the intermediate nodes
|
},
|
||||||
// But that method is significantly more memory intensive
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -479,6 +479,8 @@ func TestBuilderOnMainnetBlocks(t *testing.T) {
|
|||||||
startingArguments statediff.Args
|
startingArguments statediff.Args
|
||||||
expected *statediff.StateObject
|
expected *statediff.StateObject
|
||||||
}{
|
}{
|
||||||
|
// note that block0 (genesis) has over 1000 nodes due to the pre-allocation for the crowd-sale
|
||||||
|
// it is not feasible to write a unit test of that size at this time
|
||||||
{
|
{
|
||||||
"testBlock1",
|
"testBlock1",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
@ -172,7 +172,7 @@ func (sds *Service) streamStateDiff(currentBlock *types.Block, parentRoot common
|
|||||||
for id, sub := range subs {
|
for id, sub := range subs {
|
||||||
select {
|
select {
|
||||||
case sub.PayloadChan <- *payload:
|
case sub.PayloadChan <- *payload:
|
||||||
log.Debug(fmt.Sprintf("sending statediff payload to subscription %s", id))
|
log.Debug(fmt.Sprintf("sending statediff payload at head height %d to subscription %s", currentBlock.Number(), id))
|
||||||
default:
|
default:
|
||||||
log.Info(fmt.Sprintf("unable to send statediff payload to subscription %s; channel has no receiver", id))
|
log.Info(fmt.Sprintf("unable to send statediff payload to subscription %s; channel has no receiver", id))
|
||||||
}
|
}
|
||||||
@ -181,6 +181,18 @@ func (sds *Service) streamStateDiff(currentBlock *types.Block, parentRoot common
|
|||||||
sds.Unlock()
|
sds.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateDiffAt returns a state diff object payload at the specific blockheight
|
||||||
|
// This operation cannot be performed back past the point of db pruning; it requires an archival node for historical data
|
||||||
|
func (sds *Service) StateDiffAt(blockNumber uint64, params Params) (*Payload, error) {
|
||||||
|
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
||||||
|
log.Info(fmt.Sprintf("sending state diff at block %d", blockNumber))
|
||||||
|
if blockNumber == 0 {
|
||||||
|
return sds.processStateDiff(currentBlock, common.Hash{}, params)
|
||||||
|
}
|
||||||
|
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
|
||||||
|
return sds.processStateDiff(currentBlock, parentBlock.Root(), params)
|
||||||
|
}
|
||||||
|
|
||||||
// processStateDiff method builds the state diff payload from the current block, parent state root, and provided params
|
// processStateDiff method builds the state diff payload from the current block, parent state root, and provided params
|
||||||
func (sds *Service) processStateDiff(currentBlock *types.Block, parentRoot common.Hash, params Params) (*Payload, error) {
|
func (sds *Service) processStateDiff(currentBlock *types.Block, parentRoot common.Hash, params Params) (*Payload, error) {
|
||||||
stateDiff, err := sds.Builder.BuildStateDiffObject(Args{
|
stateDiff, err := sds.Builder.BuildStateDiffObject(Args{
|
||||||
@ -196,28 +208,52 @@ func (sds *Service) processStateDiff(currentBlock *types.Block, parentRoot commo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload := Payload{
|
return sds.newPayload(stateDiffRlp, currentBlock, params)
|
||||||
StateObjectRlp: stateDiffRlp,
|
}
|
||||||
|
|
||||||
|
func (sds *Service) newPayload(stateObject []byte, block *types.Block, params Params) (*Payload, error) {
|
||||||
|
payload := &Payload{
|
||||||
|
StateObjectRlp: stateObject,
|
||||||
}
|
}
|
||||||
if params.IncludeBlock {
|
if params.IncludeBlock {
|
||||||
blockBuff := new(bytes.Buffer)
|
blockBuff := new(bytes.Buffer)
|
||||||
if err = currentBlock.EncodeRLP(blockBuff); err != nil {
|
if err := block.EncodeRLP(blockBuff); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload.BlockRlp = blockBuff.Bytes()
|
payload.BlockRlp = blockBuff.Bytes()
|
||||||
}
|
}
|
||||||
if params.IncludeTD {
|
if params.IncludeTD {
|
||||||
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(currentBlock.Hash())
|
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(block.Hash())
|
||||||
}
|
}
|
||||||
if params.IncludeReceipts {
|
if params.IncludeReceipts {
|
||||||
receiptBuff := new(bytes.Buffer)
|
receiptBuff := new(bytes.Buffer)
|
||||||
receipts := sds.BlockChain.GetReceiptsByHash(currentBlock.Hash())
|
receipts := sds.BlockChain.GetReceiptsByHash(block.Hash())
|
||||||
if err = rlp.Encode(receiptBuff, receipts); err != nil {
|
if err := rlp.Encode(receiptBuff, receipts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload.ReceiptsRlp = receiptBuff.Bytes()
|
payload.ReceiptsRlp = receiptBuff.Bytes()
|
||||||
}
|
}
|
||||||
return &payload, nil
|
return payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateTrieAt returns a state trie object payload at the specified blockheight
|
||||||
|
// This operation cannot be performed back past the point of db pruning; it requires an archival node for historical data
|
||||||
|
func (sds *Service) StateTrieAt(blockNumber uint64, params Params) (*Payload, error) {
|
||||||
|
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
||||||
|
log.Info(fmt.Sprintf("sending state trie at block %d", blockNumber))
|
||||||
|
return sds.processStateTrie(currentBlock, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sds *Service) processStateTrie(block *types.Block, params Params) (*Payload, error) {
|
||||||
|
stateNodes, err := sds.Builder.BuildStateTrieObject(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stateTrieRlp, err := rlp.EncodeToBytes(stateNodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sds.newPayload(stateTrieRlp, block, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe is used by the API to subscribe to the service loop
|
// Subscribe is used by the API to subscribe to the service loop
|
||||||
@ -277,59 +313,6 @@ func (sds *Service) Start(*p2p.Server) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateDiffAt returns a state diff object payload at the specific blockheight
|
|
||||||
// This operation cannot be performed back past the point of db pruning; it requires an archival node for historical data
|
|
||||||
func (sds *Service) StateDiffAt(blockNumber uint64, params Params) (*Payload, error) {
|
|
||||||
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
|
||||||
log.Info(fmt.Sprintf("sending state diff at %d", blockNumber))
|
|
||||||
if blockNumber == 0 {
|
|
||||||
return sds.processStateDiff(currentBlock, common.Hash{}, params)
|
|
||||||
}
|
|
||||||
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
|
|
||||||
return sds.processStateDiff(currentBlock, parentBlock.Root(), params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateTrieAt returns a state trie object payload at the specified blockheight
|
|
||||||
// This operation cannot be performed back past the point of db pruning; it requires an archival node for historical data
|
|
||||||
func (sds *Service) StateTrieAt(blockNumber uint64, params Params) (*Payload, error) {
|
|
||||||
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
|
||||||
log.Info(fmt.Sprintf("sending state trie at %d", blockNumber))
|
|
||||||
return sds.stateTrieAt(currentBlock, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sds *Service) stateTrieAt(block *types.Block, params Params) (*Payload, error) {
|
|
||||||
stateNodes, err := sds.Builder.BuildStateTrieObject(block)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stateTrieRlp, err := rlp.EncodeToBytes(stateNodes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload := Payload{
|
|
||||||
StateObjectRlp: stateTrieRlp,
|
|
||||||
}
|
|
||||||
if params.IncludeBlock {
|
|
||||||
blockBuff := new(bytes.Buffer)
|
|
||||||
if err = block.EncodeRLP(blockBuff); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload.BlockRlp = blockBuff.Bytes()
|
|
||||||
}
|
|
||||||
if params.IncludeTD {
|
|
||||||
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(block.Hash())
|
|
||||||
}
|
|
||||||
if params.IncludeReceipts {
|
|
||||||
receiptBuff := new(bytes.Buffer)
|
|
||||||
receipts := sds.BlockChain.GetReceiptsByHash(block.Hash())
|
|
||||||
if err = rlp.Encode(receiptBuff, receipts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload.ReceiptsRlp = receiptBuff.Bytes()
|
|
||||||
}
|
|
||||||
return &payload, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop is used to close down the service
|
// Stop is used to close down the service
|
||||||
func (sds *Service) Stop() error {
|
func (sds *Service) Stop() error {
|
||||||
log.Info("Stopping statediff service")
|
log.Info("Stopping statediff service")
|
||||||
|
@ -118,6 +118,17 @@ func (sds *MockStateDiffService) streamStateDiff(currentBlock *types.Block, pare
|
|||||||
sds.Unlock()
|
sds.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateDiffAt mock method
|
||||||
|
func (sds *MockStateDiffService) StateDiffAt(blockNumber uint64, params statediff.Params) (*statediff.Payload, error) {
|
||||||
|
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
||||||
|
log.Info(fmt.Sprintf("sending state diff at %d", blockNumber))
|
||||||
|
if blockNumber == 0 {
|
||||||
|
return sds.processStateDiff(currentBlock, common.Hash{}, params)
|
||||||
|
}
|
||||||
|
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
|
||||||
|
return sds.processStateDiff(currentBlock, parentBlock.Root(), params)
|
||||||
|
}
|
||||||
|
|
||||||
// processStateDiff method builds the state diff payload from the current block, parent state root, and provided params
|
// processStateDiff method builds the state diff payload from the current block, parent state root, and provided params
|
||||||
func (sds *MockStateDiffService) processStateDiff(currentBlock *types.Block, parentRoot common.Hash, params statediff.Params) (*statediff.Payload, error) {
|
func (sds *MockStateDiffService) processStateDiff(currentBlock *types.Block, parentRoot common.Hash, params statediff.Params) (*statediff.Payload, error) {
|
||||||
stateDiff, err := sds.Builder.BuildStateDiffObject(statediff.Args{
|
stateDiff, err := sds.Builder.BuildStateDiffObject(statediff.Args{
|
||||||
@ -133,28 +144,51 @@ func (sds *MockStateDiffService) processStateDiff(currentBlock *types.Block, par
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload := statediff.Payload{
|
return sds.newPayload(stateDiffRlp, currentBlock, params)
|
||||||
StateObjectRlp: stateDiffRlp,
|
}
|
||||||
|
|
||||||
|
func (sds *MockStateDiffService) newPayload(stateObject []byte, block *types.Block, params statediff.Params) (*statediff.Payload, error) {
|
||||||
|
payload := &statediff.Payload{
|
||||||
|
StateObjectRlp: stateObject,
|
||||||
}
|
}
|
||||||
if params.IncludeBlock {
|
if params.IncludeBlock {
|
||||||
blockBuff := new(bytes.Buffer)
|
blockBuff := new(bytes.Buffer)
|
||||||
if err = currentBlock.EncodeRLP(blockBuff); err != nil {
|
if err := block.EncodeRLP(blockBuff); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload.BlockRlp = blockBuff.Bytes()
|
payload.BlockRlp = blockBuff.Bytes()
|
||||||
}
|
}
|
||||||
if params.IncludeTD {
|
if params.IncludeTD {
|
||||||
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(currentBlock.Hash())
|
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(block.Hash())
|
||||||
}
|
}
|
||||||
if params.IncludeReceipts {
|
if params.IncludeReceipts {
|
||||||
receiptBuff := new(bytes.Buffer)
|
receiptBuff := new(bytes.Buffer)
|
||||||
receipts := sds.BlockChain.GetReceiptsByHash(currentBlock.Hash())
|
receipts := sds.BlockChain.GetReceiptsByHash(block.Hash())
|
||||||
if err = rlp.Encode(receiptBuff, receipts); err != nil {
|
if err := rlp.Encode(receiptBuff, receipts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload.ReceiptsRlp = receiptBuff.Bytes()
|
payload.ReceiptsRlp = receiptBuff.Bytes()
|
||||||
}
|
}
|
||||||
return &payload, nil
|
return payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateTrieAt mock method
|
||||||
|
func (sds *MockStateDiffService) StateTrieAt(blockNumber uint64, params statediff.Params) (*statediff.Payload, error) {
|
||||||
|
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
||||||
|
log.Info(fmt.Sprintf("sending state trie at %d", blockNumber))
|
||||||
|
return sds.stateTrieAt(currentBlock, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sds *MockStateDiffService) stateTrieAt(block *types.Block, params statediff.Params) (*statediff.Payload, error) {
|
||||||
|
stateNodes, err := sds.Builder.BuildStateTrieObject(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stateTrieRlp, err := rlp.EncodeToBytes(stateNodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sds.newPayload(stateTrieRlp, block, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe is used by the API to subscribe to the service loop
|
// Subscribe is used by the API to subscribe to the service loop
|
||||||
@ -193,57 +227,6 @@ func (sds *MockStateDiffService) Unsubscribe(id rpc.ID) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateDiffAt mock method
|
|
||||||
func (sds *MockStateDiffService) StateDiffAt(blockNumber uint64, params statediff.Params) (*statediff.Payload, error) {
|
|
||||||
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
|
||||||
log.Info(fmt.Sprintf("sending state diff at %d", blockNumber))
|
|
||||||
if blockNumber == 0 {
|
|
||||||
return sds.processStateDiff(currentBlock, common.Hash{}, params)
|
|
||||||
}
|
|
||||||
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
|
|
||||||
return sds.processStateDiff(currentBlock, parentBlock.Root(), params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateTrieAt mock method
|
|
||||||
func (sds *MockStateDiffService) StateTrieAt(blockNumber uint64, params statediff.Params) (*statediff.Payload, error) {
|
|
||||||
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
|
||||||
log.Info(fmt.Sprintf("sending state trie at %d", blockNumber))
|
|
||||||
return sds.stateTrieAt(currentBlock, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sds *MockStateDiffService) stateTrieAt(block *types.Block, params statediff.Params) (*statediff.Payload, error) {
|
|
||||||
stateNodes, err := sds.Builder.BuildStateTrieObject(block)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stateTrieRlp, err := rlp.EncodeToBytes(stateNodes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload := statediff.Payload{
|
|
||||||
StateObjectRlp: stateTrieRlp,
|
|
||||||
}
|
|
||||||
if params.IncludeBlock {
|
|
||||||
blockBuff := new(bytes.Buffer)
|
|
||||||
if err = block.EncodeRLP(blockBuff); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload.BlockRlp = blockBuff.Bytes()
|
|
||||||
}
|
|
||||||
if params.IncludeTD {
|
|
||||||
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(block.Hash())
|
|
||||||
}
|
|
||||||
if params.IncludeReceipts {
|
|
||||||
receiptBuff := new(bytes.Buffer)
|
|
||||||
receipts := sds.BlockChain.GetReceiptsByHash(block.Hash())
|
|
||||||
if err = rlp.Encode(receiptBuff, receipts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload.ReceiptsRlp = receiptBuff.Bytes()
|
|
||||||
}
|
|
||||||
return &payload, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// close is used to close all listening subscriptions
|
// close is used to close all listening subscriptions
|
||||||
func (sds *MockStateDiffService) close() {
|
func (sds *MockStateDiffService) close() {
|
||||||
sds.Lock()
|
sds.Lock()
|
@ -85,9 +85,6 @@ type StateObject struct {
|
|||||||
BlockNumber *big.Int `json:"blockNumber" gencodec:"required"`
|
BlockNumber *big.Int `json:"blockNumber" gencodec:"required"`
|
||||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Nodes []StateNode `json:"nodes" gencodec:"required"`
|
Nodes []StateNode `json:"nodes" gencodec:"required"`
|
||||||
|
|
||||||
encoded []byte
|
|
||||||
err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateNode holds the data for a single state diff node
|
// StateNode holds the data for a single state diff node
|
||||||
@ -127,5 +124,5 @@ const (
|
|||||||
Leaf NodeType = "Leaf"
|
Leaf NodeType = "Leaf"
|
||||||
Extension NodeType = "Extension"
|
Extension NodeType = "Extension"
|
||||||
Branch NodeType = "Branch"
|
Branch NodeType = "Branch"
|
||||||
Removed NodeType = "Removed" // used to represent nodes which have been deleted (e.g. accounts due to EIp-158)
|
Removed NodeType = "Removed" // used to represent pathes which have been emptied
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user