cli parameter to limit statediffing to select account addresses + test

This commit is contained in:
Ian Norden 2019-05-16 20:58:32 -05:00 committed by Rob Mulholand
parent f67a060c8c
commit 5fa40688af
11 changed files with 468 additions and 343 deletions

View File

@ -150,7 +150,9 @@ var (
utils.EVMInterpreterFlag,
utils.StateDiffFlag,
utils.StateDiffPathsAndProofs,
utils.StateDiffLeafNodesOnly,
utils.StateDiffAllNodeTypes,
utils.StateDiffStreamBlock,
utils.StateDiffWatchedAddresses,
configFileFlag,
}

View File

@ -267,8 +267,9 @@ var AppHelpFlagGroups = []flagGroup{
Flags: []cli.Flag{
utils.StateDiffFlag,
utils.StateDiffPathsAndProofs,
utils.StateDiffLeafNodesOnly,
utils.StateDiffAllNodeTypes,
utils.StateDiffWatchedAddresses,
utils.StateDiffStreamBlock,
},
},
{

View File

@ -765,16 +765,20 @@ var (
}
StateDiffPathsAndProofs = cli.BoolFlag{
Name: "statediff.pathsandproofs",
Usage: "Path and proof sets for the state and storage nodes are generated; only works with leaf nodes",
Usage: "Set to true to generate paths and proof sets for diffed state and storage trie lead nodes",
}
StateDiffLeafNodesOnly = cli.BoolFlag{
Name: "statediff.leafs",
Usage: "Consider only leaf nodes of the storage and state tries",
StateDiffAllNodeTypes = cli.BoolFlag{
Name: "statediff.allnodes",
Usage: "Set to true to consider all node types: leaf, branch, and extension; default (false) processes leaf nodes only",
}
StateDiffWatchedAddresses = cli.StringSliceFlag{
Name: "statediff.watchedaddresses",
Usage: "If provided, state diffing process is restricted to these addresses",
}
StateDiffStreamBlock = cli.BoolFlag{
Name: "statediff.streamblock",
Usage: "Set to true to stream the block data alongside state diff data",
}
)
// MakeDataDir retrieves the currently requested data directory, terminating
@ -1636,9 +1640,10 @@ func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []st
// RegisterStateDiffService configures and registers a service to stream state diff data over RPC
func RegisterStateDiffService(stack *node.Node, ctx *cli.Context) {
config := statediff.Config{
PathsAndProofs: ctx.GlobalBool(StateDiffPathsAndProofs.Name),
LeafsOnly: ctx.GlobalBool(StateDiffLeafNodesOnly.Name),
WatchedAddress: ctx.GlobalStringSlice(StateDiffWatchedAddresses.Name),
StreamBlock: ctx.GlobalBool(StateDiffStreamBlock.Name),
PathsAndProofs: ctx.GlobalBool(StateDiffPathsAndProofs.Name),
AllNodes: ctx.GlobalBool(StateDiffAllNodeTypes.Name),
WatchedAddresses: ctx.GlobalStringSlice(StateDiffWatchedAddresses.Name),
}
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
var ethServ *eth.Ethereum

View File

@ -18,8 +18,6 @@ package statediff
import (
"context"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
@ -36,17 +34,12 @@ const APIVersion = "0.0.1"
// are produced by a full node
type PublicStateDiffAPI struct {
sds IService
mu sync.Mutex
lastUsed map[string]time.Time // keeps track when a filter was polled for the last time.
}
// NewPublicStateDiffAPI create a new state diff websocket streaming service.
func NewPublicStateDiffAPI(sds IService) *PublicStateDiffAPI {
return &PublicStateDiffAPI{
sds: sds,
lastUsed: make(map[string]time.Time),
mu: sync.Mutex{},
sds: sds,
}
}

View File

@ -20,6 +20,7 @@
package statediff
import (
"bytes"
"fmt"
"math/big"
@ -27,12 +28,15 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
var nullNode = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")
// Builder interface exposes the method for building a state diff between two blocks
type Builder interface {
BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber *big.Int, blockHash common.Hash) (StateDiff, error)
@ -111,120 +115,71 @@ func (sdb *builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, block
}, nil
}
func (sdb *builder) isWatchedAddress(hashKey []byte) bool {
// If we aren't watching any addresses, we are watching everything
if len(sdb.config.WatchedAddresses) == 0 {
return true
}
for _, addrStr := range sdb.config.WatchedAddresses {
addr := common.HexToAddress(addrStr)
addrHashKey := crypto.Keccak256(addr[:])
if bytes.Equal(addrHashKey, hashKey) {
return true
}
}
return false
}
func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (AccountsMap, error) {
var diffAccounts = make(AccountsMap)
it, _ := trie.NewDifferenceIterator(a, b)
if sdb.config.PathsAndProofs {
for {
log.Debug("Current Path and Hash", "path", pathToStr(it), "old hash", it.Hash())
if it.Leaf() {
for {
log.Debug("Current Path and Hash", "path", pathToStr(it), "old hash", it.Hash())
if it.Leaf() && sdb.isWatchedAddress(it.LeafKey()) {
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafKeyHash := common.BytesToHash(leafKey)
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
// lookup account state
var account state.Account
if err := rlp.DecodeBytes(leafValue, &account); err != nil {
return nil, fmt.Errorf("error looking up account via address %s\r\nerror: %v", leafKeyHash.Hex(), err)
}
aw := accountWrapper{
Leaf: true,
Account: &account,
RawKey: leafKey,
RawValue: leafValue,
}
if sdb.config.PathsAndProofs {
leafProof := make([][]byte, len(it.LeafProof()))
copy(leafProof, it.LeafProof())
leafPath := make([]byte, len(it.Path()))
copy(leafPath, it.Path())
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafKeyHash := common.BytesToHash(leafKey)
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
// lookup account state
var account state.Account
if err := rlp.DecodeBytes(leafValue, &account); err != nil {
return nil, fmt.Errorf("error looking up account via address %s\r\nerror: %v", leafKeyHash.Hex(), err)
}
aw := accountWrapper{
Account: &account,
RawKey: leafKey,
RawValue: leafValue,
Proof: leafProof,
Path: leafPath,
}
// record account to diffs (creation if we are looking at new - old; deletion if old - new)
log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
diffAccounts[leafKeyHash] = aw
aw.Proof = leafProof
aw.Path = leafPath
}
cont := it.Next(true)
if !cont {
break
// record account to diffs (creation if we are looking at new - old; deletion if old - new)
log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
diffAccounts[leafKeyHash] = aw
} else if sdb.config.AllNodes && !bytes.Equal(nullNode, it.Hash().Bytes()) {
nodeKey := it.Hash()
node, err := sdb.stateCache.TrieDB().Node(nodeKey)
if err != nil {
return nil, fmt.Errorf("error looking up intermediate state trie node %s\r\nerror: %v", nodeKey.Hex(), err)
}
aw := accountWrapper{
Leaf: false,
RawKey: nodeKey.Bytes(),
RawValue: node,
}
log.Debug("intermediate state trie node lookup successful", "key", nodeKey.Hex(), "value", node)
diffAccounts[nodeKey] = aw
}
} else {
if sdb.config.LeafsOnly {
for {
log.Debug("Current Path and Hash", "path", pathToStr(it), "old hash", it.Hash())
if it.Leaf() {
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafKeyHash := common.BytesToHash(leafKey)
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
// lookup account state
var account state.Account
if err := rlp.DecodeBytes(leafValue, &account); err != nil {
return nil, fmt.Errorf("error looking up account via address %s\r\nerror: %v", leafKeyHash.Hex(), err)
}
aw := accountWrapper{
Account: &account,
RawKey: leafKey,
RawValue: leafValue,
Proof: nil,
Path: nil,
}
// record account to diffs (creation if we are looking at new - old; deletion if old - new)
log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
diffAccounts[leafKeyHash] = aw
}
cont := it.Next(true)
if !cont {
break
}
}
} else {
for {
log.Debug("Current Path and Hash", "path", pathToStr(it), "old hash", it.Hash())
if it.Leaf() {
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafKeyHash := common.BytesToHash(leafKey)
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
// lookup account state
var account state.Account
if err := rlp.DecodeBytes(leafValue, &account); err != nil {
return nil, fmt.Errorf("error looking up account via address %s\r\nerror: %v", leafKeyHash.Hex(), err)
}
aw := accountWrapper{
Account: &account,
RawKey: leafKey,
RawValue: leafValue,
Proof: nil,
Path: nil,
}
// record account to diffs (creation if we are looking at new - old; deletion if old - new)
log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
diffAccounts[leafKeyHash] = aw
} else {
nodeKey := it.Hash()
node, err := sdb.stateCache.TrieDB().Node(nodeKey)
if err != nil {
return nil, fmt.Errorf("error looking up intermediate state trie node %s\r\nerror: %v", nodeKey.Hex(), err)
}
aw := accountWrapper{
Account: nil,
RawKey: nodeKey.Bytes(),
RawValue: node,
Proof: nil,
Path: nil,
}
log.Debug("intermediate state trie node lookup successful", "key", nodeKey.Hex(), "value", node)
diffAccounts[nodeKey] = aw
}
cont := it.Next(true)
if !cont {
break
}
}
cont := it.Next(true)
if !cont {
break
}
}
@ -244,6 +199,7 @@ func (sdb *builder) buildDiffEventual(accounts AccountsMap) ([]AccountDiff, erro
}
}
accountDiffs = append(accountDiffs, AccountDiff{
Leaf: val.Leaf,
Key: val.RawKey,
Value: val.RawValue,
Proof: val.Proof,
@ -272,6 +228,7 @@ func (sdb *builder) buildDiffIncremental(creations AccountsMap, deletions Accoun
}
}
updatedAccounts = append(updatedAccounts, AccountDiff{
Leaf: createdAcc.Leaf,
Key: createdAcc.RawKey,
Value: createdAcc.RawValue,
Proof: createdAcc.Proof,
@ -318,87 +275,44 @@ func (sdb *builder) buildStorageDiffsIncremental(oldSR common.Hash, newSR common
func (sdb *builder) buildStorageDiffsFromTrie(it trie.NodeIterator) ([]StorageDiff, error) {
storageDiffs := make([]StorageDiff, 0)
if sdb.config.PathsAndProofs {
for {
log.Debug("Iterating over state at path ", "path", pathToStr(it))
if it.Leaf() {
log.Debug("Found leaf in storage", "path", pathToStr(it))
for {
log.Debug("Iterating over state at path ", "path", pathToStr(it))
if it.Leaf() {
log.Debug("Found leaf in storage", "path", pathToStr(it))
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
sd := StorageDiff{
Leaf: true,
Key: leafKey,
Value: leafValue,
}
if sdb.config.PathsAndProofs {
leafProof := make([][]byte, len(it.LeafProof()))
copy(leafProof, it.LeafProof())
leafPath := make([]byte, len(it.Path()))
copy(leafPath, it.Path())
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
storageDiffs = append(storageDiffs, StorageDiff{
Key: leafKey,
Value: leafValue,
Path: leafPath,
Proof: leafProof,
})
sd.Proof = leafProof
sd.Path = leafPath
}
cont := it.Next(true)
if !cont {
break
storageDiffs = append(storageDiffs, sd)
} else if sdb.config.AllNodes && !bytes.Equal(nullNode, it.Hash().Bytes()) {
nodeKey := it.Hash()
node, err := sdb.stateCache.TrieDB().Node(nodeKey)
if err != nil {
return nil, fmt.Errorf("error looking up intermediate storage trie node %s\r\nerror: %v", nodeKey.Hex(), err)
}
storageDiffs = append(storageDiffs, StorageDiff{
Leaf: false,
Key: nodeKey.Bytes(),
Value: node,
})
log.Debug("intermediate storage trie node lookup successful", "key", nodeKey.Hex(), "value", node)
}
} else {
if sdb.config.LeafsOnly {
for {
log.Debug("Iterating over state at path ", "path", pathToStr(it))
if it.Leaf() {
log.Debug("Found leaf in storage", "path", pathToStr(it))
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
storageDiffs = append(storageDiffs, StorageDiff{
Key: leafKey,
Value: leafValue,
Path: nil,
Proof: nil,
})
}
cont := it.Next(true)
if !cont {
break
}
}
} else {
for {
log.Debug("Iterating over state at path ", "path", pathToStr(it))
if it.Leaf() {
log.Debug("Found leaf in storage", "path", pathToStr(it))
leafKey := make([]byte, len(it.LeafKey()))
copy(leafKey, it.LeafKey())
leafValue := make([]byte, len(it.LeafBlob()))
copy(leafValue, it.LeafBlob())
storageDiffs = append(storageDiffs, StorageDiff{
Key: leafKey,
Value: leafValue,
Path: nil,
Proof: nil,
})
} else {
nodeKey := it.Hash()
node, err := sdb.stateCache.TrieDB().Node(nodeKey)
if err != nil {
return nil, fmt.Errorf("error looking up intermediate storage trie node %s\r\nerror: %v", nodeKey.Hex(), err)
}
storageDiffs = append(storageDiffs, StorageDiff{
Key: nodeKey.Bytes(),
Value: node,
Path: nil,
Proof: nil,
})
log.Debug("intermediate storage trie node lookup successful", "key", nodeKey.Hex(), "value", node)
}
cont := it.Next(true)
if !cont {
break
}
}
cont := it.Next(true)
if !cont {
break
}
}

View File

@ -32,130 +32,127 @@ import (
)
var (
contractLeafKey common.Hash
emptyAccountDiffEventualMap = make([]statediff.AccountDiff, 0)
emptyAccountDiffIncrementalMap = make([]statediff.AccountDiff, 0)
block0Hash, block1Hash, block2Hash, block3Hash common.Hash
block0, block1, block2, block3 *types.Block
builder statediff.Builder
miningReward = int64(2000000000000000000)
burnAddress = common.HexToAddress("0x0")
burnLeafKey = testhelpers.AddressToLeafKey(burnAddress)
contractLeafKey common.Hash
emptyAccountDiffEventualMap = make([]statediff.AccountDiff, 0)
emptyAccountDiffIncrementalMap = make([]statediff.AccountDiff, 0)
block0, block1, block2, block3 *types.Block
builder statediff.Builder
miningReward = int64(2000000000000000000)
burnAddress = common.HexToAddress("0x0")
burnLeafKey = testhelpers.AddressToLeafKey(burnAddress)
block0Hash = common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661")
block1Hash = common.HexToHash("0xbbe88de60ba33a3f18c0caa37d827bfb70252e19e40a07cd34041696c35ecb1a")
block2Hash = common.HexToHash("0x34ad0fd9bb2911986b75d518c822641079dea823bc6952343ebf05da1062b6f5")
block3Hash = common.HexToHash("0x9872058136c560a6ebed0c0522b8d3016fc21f4fb0fb6585ddd8fd4c54f9909a")
balanceChange10000 = int64(10000)
balanceChange1000 = int64(1000)
block1BankBalance = int64(99990000)
block1Account1Balance = int64(10000)
block2Account2Balance = int64(1000)
nonce0 = uint64(0)
nonce1 = uint64(1)
nonce2 = uint64(2)
nonce3 = uint64(3)
originalContractRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
contractContractRoot = "0x821e2556a290c86405f8160a2d662042a431ba456b9db265c79bb837c04be5f0"
newContractRoot = "0x71e0d14b2b93e5c7f9748e69e1fe5f17498a1c3ac3cec29f96af13d7f8a4e070"
originalStorageLocation = common.HexToHash("0")
originalStorageKey = crypto.Keccak256Hash(originalStorageLocation[:]).Bytes()
updatedStorageLocation = common.HexToHash("2")
updatedStorageKey = crypto.Keccak256Hash(updatedStorageLocation[:]).Bytes()
originalStorageValue = common.Hex2Bytes("01")
updatedStorageValue = common.Hex2Bytes("03")
account1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(balanceChange10000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
burnAccount1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(miningReward),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
bankAccount1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
Balance: big.NewInt(testhelpers.TestBankFunds.Int64() - balanceChange10000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
account2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(balanceChange1000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
contractAccount, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
Balance: big.NewInt(0),
CodeHash: common.HexToHash("0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea").Bytes(),
Root: common.HexToHash(contractContractRoot),
})
bankAccount2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce2,
Balance: big.NewInt(block1BankBalance - balanceChange1000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
account3, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce2,
Balance: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
burnAccount2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(miningReward + miningReward),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
account4, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(block2Account2Balance + miningReward),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
contractAccount2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
Balance: big.NewInt(0),
CodeHash: common.HexToHash("0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea").Bytes(),
Root: common.HexToHash(newContractRoot),
})
bankAccount3, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce3,
Balance: big.NewInt(99989000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
)
type arguments struct {
oldStateRoot common.Hash
newStateRoot common.Hash
blockNumber *big.Int
blockHash common.Hash
}
func TestBuilder(t *testing.T) {
_, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
defer chain.Stop()
block0Hash = common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661")
block1Hash = common.HexToHash("0xbbe88de60ba33a3f18c0caa37d827bfb70252e19e40a07cd34041696c35ecb1a")
block2Hash = common.HexToHash("0x34ad0fd9bb2911986b75d518c822641079dea823bc6952343ebf05da1062b6f5")
block3Hash = common.HexToHash("0x9872058136c560a6ebed0c0522b8d3016fc21f4fb0fb6585ddd8fd4c54f9909a")
block0 = blockMap[block0Hash]
block1 = blockMap[block1Hash]
block2 = blockMap[block2Hash]
block3 = blockMap[block3Hash]
config := statediff.Config{
PathsAndProofs: true,
LeafsOnly: true,
AllNodes: false,
}
builder = statediff.NewBuilder(testhelpers.Testdb, chain, config)
type arguments struct {
oldStateRoot common.Hash
newStateRoot common.Hash
blockNumber *big.Int
blockHash common.Hash
}
var (
balanceChange10000 = int64(10000)
balanceChange1000 = int64(1000)
block1BankBalance = int64(99990000)
block1Account1Balance = int64(10000)
block2Account2Balance = int64(1000)
nonce0 = uint64(0)
nonce1 = uint64(1)
nonce2 = uint64(2)
nonce3 = uint64(3)
originalContractRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
contractContractRoot = "0x821e2556a290c86405f8160a2d662042a431ba456b9db265c79bb837c04be5f0"
newContractRoot = "0x71e0d14b2b93e5c7f9748e69e1fe5f17498a1c3ac3cec29f96af13d7f8a4e070"
originalStorageLocation = common.HexToHash("0")
originalStorageKey = crypto.Keccak256Hash(originalStorageLocation[:]).Bytes()
updatedStorageLocation = common.HexToHash("2")
updatedStorageKey = crypto.Keccak256Hash(updatedStorageLocation[:]).Bytes()
originalStorageValue = common.Hex2Bytes("01")
updatedStorageValue = common.Hex2Bytes("03")
account1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(balanceChange10000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
burnAccount1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(miningReward),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
bankAccount1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
Balance: big.NewInt(testhelpers.TestBankFunds.Int64() - balanceChange10000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
account2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(balanceChange1000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
contractAccount, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
Balance: big.NewInt(0),
CodeHash: common.HexToHash("0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea").Bytes(),
Root: common.HexToHash(contractContractRoot),
})
bankAccount2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce2,
Balance: big.NewInt(block1BankBalance - balanceChange1000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
account3, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce2,
Balance: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
burnAccount2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(miningReward + miningReward),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
account4, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce0,
Balance: big.NewInt(block2Account2Balance + miningReward),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
contractAccount2, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
Balance: big.NewInt(0),
CodeHash: common.HexToHash("0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea").Bytes(),
Root: common.HexToHash(newContractRoot),
})
bankAccount3, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce3,
Balance: big.NewInt(99989000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
)
var tests = []struct {
name string
startingArguments arguments
@ -191,6 +188,7 @@ func TestBuilder(t *testing.T) {
BlockHash: block1.Hash(),
CreatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: burnLeafKey.Bytes(),
Value: burnAccount1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
@ -199,6 +197,7 @@ func TestBuilder(t *testing.T) {
Storage: []statediff.StorageDiff{},
},
{
Leaf: true,
Key: testhelpers.Account1LeafKey.Bytes(),
Value: account1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
@ -210,6 +209,7 @@ func TestBuilder(t *testing.T) {
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
@ -235,6 +235,7 @@ func TestBuilder(t *testing.T) {
BlockHash: block2.Hash(),
CreatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: contractLeafKey.Bytes(),
Value: contractAccount,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -242,6 +243,7 @@ func TestBuilder(t *testing.T) {
Path: []byte{6, 1, 1, 4, 6, 5, 8, 10, 7, 4, 13, 9, 12, 12, 9, 15, 7, 10, 12, 15, 2, 12, 5, 12, 13, 6, 9, 6, 12, 3, 4, 9, 4, 13, 7, 12, 3, 4, 4, 13, 7, 8, 11, 15, 14, 12, 3, 10, 13, 13, 0, 13, 9, 1, 14, 12, 4, 14, 8, 13, 1, 12, 4, 5, 16},
Storage: []statediff.StorageDiff{
{
Leaf: true,
Key: originalStorageKey,
Value: originalStorageValue,
Proof: [][]byte{{227, 161, 32, 41, 13, 236, 217, 84, 139, 98, 168, 214, 3, 69, 169, 136, 56, 111, 200, 75, 166, 188, 149, 72, 64, 8, 246, 54, 47, 147, 22, 14, 243, 229, 99, 1}},
@ -250,6 +252,7 @@ func TestBuilder(t *testing.T) {
},
},
{
Leaf: true,
Key: testhelpers.Account2LeafKey.Bytes(),
Value: account2,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -261,6 +264,7 @@ func TestBuilder(t *testing.T) {
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount2,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -269,6 +273,7 @@ func TestBuilder(t *testing.T) {
Storage: []statediff.StorageDiff{},
},
{
Leaf: true,
Key: burnLeafKey.Bytes(),
Value: burnAccount2,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -277,6 +282,7 @@ func TestBuilder(t *testing.T) {
Storage: []statediff.StorageDiff{},
},
{
Leaf: true,
Key: testhelpers.Account1LeafKey.Bytes(),
Value: account3,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -304,6 +310,7 @@ func TestBuilder(t *testing.T) {
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount3,
Proof: [][]byte{{248, 177, 160, 101, 223, 138, 81, 34, 40, 229, 170, 198, 188, 136, 99, 7, 55, 33, 112, 160, 111, 181, 131, 167, 201, 131, 24, 201, 211, 177, 30, 159, 229, 246, 6, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 32, 135, 108, 213, 150, 150, 110, 44, 170, 65, 75, 154, 74, 249, 94, 65, 74, 107, 100, 115, 39, 5, 3, 26, 22, 238, 138, 114, 254, 21, 6, 171, 128, 128, 128, 128, 128, 160, 4, 228, 121, 222, 255, 218, 60, 247, 15, 0, 34, 198, 28, 229, 180, 129, 109, 157, 68, 181, 248, 229, 200, 123, 29, 81, 145, 114, 90, 209, 205, 210, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -312,6 +319,7 @@ func TestBuilder(t *testing.T) {
Storage: []statediff.StorageDiff{},
},
{
Leaf: true,
Key: contractLeafKey.Bytes(),
Value: contractAccount2,
Proof: [][]byte{{248, 177, 160, 101, 223, 138, 81, 34, 40, 229, 170, 198, 188, 136, 99, 7, 55, 33, 112, 160, 111, 181, 131, 167, 201, 131, 24, 201, 211, 177, 30, 159, 229, 246, 6, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 32, 135, 108, 213, 150, 150, 110, 44, 170, 65, 75, 154, 74, 249, 94, 65, 74, 107, 100, 115, 39, 5, 3, 26, 22, 238, 138, 114, 254, 21, 6, 171, 128, 128, 128, 128, 128, 160, 4, 228, 121, 222, 255, 218, 60, 247, 15, 0, 34, 198, 28, 229, 180, 129, 109, 157, 68, 181, 248, 229, 200, 123, 29, 81, 145, 114, 90, 209, 205, 210, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -319,6 +327,7 @@ func TestBuilder(t *testing.T) {
Path: []byte{6, 1, 1, 4, 6, 5, 8, 10, 7, 4, 13, 9, 12, 12, 9, 15, 7, 10, 12, 15, 2, 12, 5, 12, 13, 6, 9, 6, 12, 3, 4, 9, 4, 13, 7, 12, 3, 4, 4, 13, 7, 8, 11, 15, 14, 12, 3, 10, 13, 13, 0, 13, 9, 1, 14, 12, 4, 14, 8, 13, 1, 12, 4, 5, 16},
Storage: []statediff.StorageDiff{
{
Leaf: true,
Key: updatedStorageKey,
Value: updatedStorageValue,
Proof: [][]byte{{248, 81, 128, 128, 160, 79, 197, 241, 58, 178, 249, 186, 12, 45, 168, 139, 1, 81, 171, 14, 124, 244, 216, 93, 8, 204, 164, 92, 205, 146, 60, 106, 183, 99, 35, 235, 40, 128, 160, 205, 69, 114, 89, 105, 97, 21, 35, 94, 100, 199, 130, 35, 52, 214, 33, 41, 226, 241, 96, 68, 37, 167, 218, 100, 148, 243, 95, 196, 91, 229, 24, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
@ -328,6 +337,7 @@ func TestBuilder(t *testing.T) {
},
},
{
Leaf: true,
Key: testhelpers.Account2LeafKey.Bytes(),
Value: account4,
Proof: [][]byte{{248, 177, 160, 101, 223, 138, 81, 34, 40, 229, 170, 198, 188, 136, 99, 7, 55, 33, 112, 160, 111, 181, 131, 167, 201, 131, 24, 201, 211, 177, 30, 159, 229, 246, 6, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 32, 135, 108, 213, 150, 150, 110, 44, 170, 65, 75, 154, 74, 249, 94, 65, 74, 107, 100, 115, 39, 5, 3, 26, 22, 238, 138, 114, 254, 21, 6, 171, 128, 128, 128, 128, 128, 160, 4, 228, 121, 222, 255, 218, 60, 247, 15, 0, 34, 198, 28, 229, 180, 129, 109, 157, 68, 181, 248, 229, 200, 123, 29, 81, 145, 114, 90, 209, 205, 210, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
@ -363,6 +373,177 @@ func TestBuilder(t *testing.T) {
}
}
func TestBuilderWithWatchedAddressList(t *testing.T) {
_, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
defer chain.Stop()
block0 = blockMap[block0Hash]
block1 = blockMap[block1Hash]
block2 = blockMap[block2Hash]
block3 = blockMap[block3Hash]
config := statediff.Config{
PathsAndProofs: true,
AllNodes: false,
WatchedAddresses: []string{testhelpers.Account1Addr.Hex(), testhelpers.ContractAddr.Hex()},
}
builder = statediff.NewBuilder(testhelpers.Testdb, chain, config)
var tests = []struct {
name string
startingArguments arguments
expected *statediff.StateDiff
}{
{
"testEmptyDiff",
arguments{
oldStateRoot: block0.Root(),
newStateRoot: block0.Root(),
blockNumber: block0.Number(),
blockHash: block0Hash,
},
&statediff.StateDiff{
BlockNumber: block0.Number(),
BlockHash: block0Hash,
CreatedAccounts: emptyAccountDiffEventualMap,
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: emptyAccountDiffIncrementalMap,
},
},
{
"testBlock1",
//10000 transferred from testBankAddress to account1Addr
arguments{
oldStateRoot: block0.Root(),
newStateRoot: block1.Root(),
blockNumber: block1.Number(),
blockHash: block1Hash,
},
&statediff.StateDiff{
BlockNumber: block1.Number(),
BlockHash: block1.Hash(),
CreatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: testhelpers.Account1LeafKey.Bytes(),
Value: account1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
{248, 107, 160, 57, 38, 219, 105, 170, 206, 213, 24, 233, 185, 240, 244, 52, 164, 115, 231, 23, 65, 9, 201, 67, 84, 139, 184, 242, 59, 228, 28, 167, 109, 154, 210, 184, 72, 248, 70, 128, 130, 39, 16, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
Path: []byte{14, 9, 2, 6, 13, 11, 6, 9, 10, 10, 12, 14, 13, 5, 1, 8, 14, 9, 11, 9, 15, 0, 15, 4, 3, 4, 10, 4, 7, 3, 14, 7, 1, 7, 4, 1, 0, 9, 12, 9, 4, 3, 5, 4, 8, 11, 11, 8, 15, 2, 3, 11, 14, 4, 1, 12, 10, 7, 6, 13, 9, 10, 13, 2, 16},
Storage: []statediff.StorageDiff{},
},
},
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{},
},
},
{
"testBlock2",
//1000 transferred from testBankAddress to account1Addr
//1000 transferred from account1Addr to account2Addr
arguments{
oldStateRoot: block1.Root(),
newStateRoot: block2.Root(),
blockNumber: block2.Number(),
blockHash: block2Hash,
},
&statediff.StateDiff{
BlockNumber: block2.Number(),
BlockHash: block2.Hash(),
CreatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: contractLeafKey.Bytes(),
Value: contractAccount,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 105, 160, 49, 20, 101, 138, 116, 217, 204, 159, 122, 207, 44, 92, 214, 150, 195, 73, 77, 124, 52, 77, 120, 191, 236, 58, 221, 13, 145, 236, 78, 141, 28, 69, 184, 70, 248, 68, 1, 128, 160, 130, 30, 37, 86, 162, 144, 200, 100, 5, 248, 22, 10, 45, 102, 32, 66, 164, 49, 186, 69, 107, 157, 178, 101, 199, 155, 184, 55, 192, 75, 229, 240, 160, 117, 63, 152, 168, 212, 50, 139, 21, 99, 110, 70, 246, 111, 44, 180, 188, 134, 1, 0, 170, 23, 150, 124, 193, 69, 252, 209, 125, 29, 71, 16, 234}},
Path: []byte{6, 1, 1, 4, 6, 5, 8, 10, 7, 4, 13, 9, 12, 12, 9, 15, 7, 10, 12, 15, 2, 12, 5, 12, 13, 6, 9, 6, 12, 3, 4, 9, 4, 13, 7, 12, 3, 4, 4, 13, 7, 8, 11, 15, 14, 12, 3, 10, 13, 13, 0, 13, 9, 1, 14, 12, 4, 14, 8, 13, 1, 12, 4, 5, 16},
Storage: []statediff.StorageDiff{
{
Leaf: true,
Key: originalStorageKey,
Value: originalStorageValue,
Proof: [][]byte{{227, 161, 32, 41, 13, 236, 217, 84, 139, 98, 168, 214, 3, 69, 169, 136, 56, 111, 200, 75, 166, 188, 149, 72, 64, 8, 246, 54, 47, 147, 22, 14, 243, 229, 99, 1}},
Path: []byte{2, 9, 0, 13, 14, 12, 13, 9, 5, 4, 8, 11, 6, 2, 10, 8, 13, 6, 0, 3, 4, 5, 10, 9, 8, 8, 3, 8, 6, 15, 12, 8, 4, 11, 10, 6, 11, 12, 9, 5, 4, 8, 4, 0, 0, 8, 15, 6, 3, 6, 2, 15, 9, 3, 1, 6, 0, 14, 15, 3, 14, 5, 6, 3, 16},
},
},
},
},
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: testhelpers.Account1LeafKey.Bytes(),
Value: account3,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 107, 160, 57, 38, 219, 105, 170, 206, 213, 24, 233, 185, 240, 244, 52, 164, 115, 231, 23, 65, 9, 201, 67, 84, 139, 184, 242, 59, 228, 28, 167, 109, 154, 210, 184, 72, 248, 70, 2, 130, 39, 16, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
Path: []byte{14, 9, 2, 6, 13, 11, 6, 9, 10, 10, 12, 14, 13, 5, 1, 8, 14, 9, 11, 9, 15, 0, 15, 4, 3, 4, 10, 4, 7, 3, 14, 7, 1, 7, 4, 1, 0, 9, 12, 9, 4, 3, 5, 4, 8, 11, 11, 8, 15, 2, 3, 11, 14, 4, 1, 12, 10, 7, 6, 13, 9, 10, 13, 2, 16},
Storage: []statediff.StorageDiff{},
},
},
},
},
{
"testBlock3",
//the contract's storage is changed
//and the block is mined by account 2
arguments{
oldStateRoot: block2.Root(),
newStateRoot: block3.Root(),
blockNumber: block3.Number(),
blockHash: block3.Hash(),
},
&statediff.StateDiff{
BlockNumber: block3.Number(),
BlockHash: block3.Hash(),
CreatedAccounts: []statediff.AccountDiff{},
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: contractLeafKey.Bytes(),
Value: contractAccount2,
Proof: [][]byte{{248, 177, 160, 101, 223, 138, 81, 34, 40, 229, 170, 198, 188, 136, 99, 7, 55, 33, 112, 160, 111, 181, 131, 167, 201, 131, 24, 201, 211, 177, 30, 159, 229, 246, 6, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 32, 135, 108, 213, 150, 150, 110, 44, 170, 65, 75, 154, 74, 249, 94, 65, 74, 107, 100, 115, 39, 5, 3, 26, 22, 238, 138, 114, 254, 21, 6, 171, 128, 128, 128, 128, 128, 160, 4, 228, 121, 222, 255, 218, 60, 247, 15, 0, 34, 198, 28, 229, 180, 129, 109, 157, 68, 181, 248, 229, 200, 123, 29, 81, 145, 114, 90, 209, 205, 210, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 105, 160, 49, 20, 101, 138, 116, 217, 204, 159, 122, 207, 44, 92, 214, 150, 195, 73, 77, 124, 52, 77, 120, 191, 236, 58, 221, 13, 145, 236, 78, 141, 28, 69, 184, 70, 248, 68, 1, 128, 160, 113, 224, 209, 75, 43, 147, 229, 199, 249, 116, 142, 105, 225, 254, 95, 23, 73, 138, 28, 58, 195, 206, 194, 159, 150, 175, 19, 215, 248, 164, 224, 112, 160, 117, 63, 152, 168, 212, 50, 139, 21, 99, 110, 70, 246, 111, 44, 180, 188, 134, 1, 0, 170, 23, 150, 124, 193, 69, 252, 209, 125, 29, 71, 16, 234}},
Path: []byte{6, 1, 1, 4, 6, 5, 8, 10, 7, 4, 13, 9, 12, 12, 9, 15, 7, 10, 12, 15, 2, 12, 5, 12, 13, 6, 9, 6, 12, 3, 4, 9, 4, 13, 7, 12, 3, 4, 4, 13, 7, 8, 11, 15, 14, 12, 3, 10, 13, 13, 0, 13, 9, 1, 14, 12, 4, 14, 8, 13, 1, 12, 4, 5, 16},
Storage: []statediff.StorageDiff{
{
Leaf: true,
Key: updatedStorageKey,
Value: updatedStorageValue,
Proof: [][]byte{{248, 81, 128, 128, 160, 79, 197, 241, 58, 178, 249, 186, 12, 45, 168, 139, 1, 81, 171, 14, 124, 244, 216, 93, 8, 204, 164, 92, 205, 146, 60, 106, 183, 99, 35, 235, 40, 128, 160, 205, 69, 114, 89, 105, 97, 21, 35, 94, 100, 199, 130, 35, 52, 214, 33, 41, 226, 241, 96, 68, 37, 167, 218, 100, 148, 243, 95, 196, 91, 229, 24, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
{226, 160, 48, 87, 135, 250, 18, 168, 35, 224, 242, 183, 99, 28, 196, 27, 59, 168, 130, 139, 51, 33, 202, 129, 17, 17, 250, 117, 205, 58, 163, 187, 90, 206, 3}},
Path: []byte{4, 0, 5, 7, 8, 7, 15, 10, 1, 2, 10, 8, 2, 3, 14, 0, 15, 2, 11, 7, 6, 3, 1, 12, 12, 4, 1, 11, 3, 11, 10, 8, 8, 2, 8, 11, 3, 3, 2, 1, 12, 10, 8, 1, 1, 1, 1, 1, 15, 10, 7, 5, 12, 13, 3, 10, 10, 3, 11, 11, 5, 10, 12, 14, 16},
},
},
},
},
},
},
}
for _, test := range tests {
arguments := test.startingArguments
diff, err := builder.BuildStateDiff(arguments.oldStateRoot, arguments.newStateRoot, arguments.blockNumber, arguments.blockHash)
if err != nil {
t.Error(err)
}
receivedStateDiffRlp, err := rlp.EncodeToBytes(diff)
if err != nil {
t.Error(err)
}
expectedStateDiffRlp, err := rlp.EncodeToBytes(test.expected)
if err != nil {
t.Error(err)
}
sort.Slice(receivedStateDiffRlp, func(i, j int) bool { return receivedStateDiffRlp[i] < receivedStateDiffRlp[j] })
sort.Slice(expectedStateDiffRlp, func(i, j int) bool { return expectedStateDiffRlp[i] < expectedStateDiffRlp[j] })
if !bytes.Equal(receivedStateDiffRlp, expectedStateDiffRlp) {
t.Logf("Test failed: %s", test.name)
t.Errorf("actual state diff rlp: %+v\nexpected state diff rlp: %+v", receivedStateDiffRlp, expectedStateDiffRlp)
}
}
}
/*
contract test {

View File

@ -18,7 +18,8 @@ package statediff
// Config is used to carry in parameters from CLI configuration
type Config struct {
PathsAndProofs bool
LeafsOnly bool
WatchedAddress []string
StreamBlock bool
PathsAndProofs bool
AllNodes bool
WatchedAddresses []string
}

View File

@ -66,6 +66,8 @@ type Service struct {
Subscriptions map[rpc.ID]Subscription
// Cache the last block so that we can avoid having to lookup the next block's parent
lastBlock *types.Block
// Whether or not the block data is streamed alongside the state diff data in the subscription payload
streamBlock bool
}
// NewStateDiffService creates a new StateDiffingService
@ -76,6 +78,7 @@ func NewStateDiffService(db ethdb.Database, blockChain *core.BlockChain, config
Builder: NewBuilder(db, blockChain, config),
QuitChan: make(chan bool),
Subscriptions: make(map[rpc.ID]Subscription),
streamBlock: config.StreamBlock,
}, nil
}
@ -143,21 +146,23 @@ func (sds *Service) process(currentBlock, parentBlock *types.Block) error {
if err != nil {
return err
}
rlpBuff := new(bytes.Buffer)
currentBlock.EncodeRLP(rlpBuff)
blockRlp := rlpBuff.Bytes()
stateDiffRlp, err := rlp.EncodeToBytes(stateDiff)
if err != nil {
return err
}
payload := Payload{
BlockRlp: blockRlp,
StateDiffRlp: stateDiffRlp,
Err: err,
}
if sds.streamBlock {
rlpBuff := new(bytes.Buffer)
if err = currentBlock.EncodeRLP(rlpBuff); err != nil {
return err
}
payload.BlockRlp = rlpBuff.Bytes()
}
// If we have any websocket subscription listening in, send the data to them
// If we have any websocket subscriptions listening in, send the data to them
sds.send(payload)
return nil
}

View File

@ -42,6 +42,7 @@ type MockStateDiffService struct {
ParentBlockChan chan *types.Block
QuitChan chan bool
Subscriptions map[rpc.ID]statediff.Subscription
streamBlock bool
}
// Protocols mock method
@ -76,25 +77,10 @@ func (sds *MockStateDiffService) Loop(chan core.ChainEvent) {
"current block number", currentBlock.Number())
continue
}
stateDiff, err := sds.Builder.BuildStateDiff(parentBlock.Root(), currentBlock.Root(), currentBlock.Number(), currentBlock.Hash())
if err != nil {
if err := sds.process(currentBlock, parentBlock); err != nil {
println(err.Error())
log.Error("Error building statediff", "block number", currentBlock.Number(), "error", err)
}
rlpBuff := new(bytes.Buffer)
currentBlock.EncodeRLP(rlpBuff)
blockRlp := rlpBuff.Bytes()
stateDiffRlp, err := rlp.EncodeToBytes(stateDiff)
if err != nil {
log.Error("Error encoding statediff", "block number", currentBlock.Number(), "error", err)
}
payload := statediff.Payload{
BlockRlp: blockRlp,
StateDiffRlp: stateDiffRlp,
Err: err,
}
// If we have any websocket subscription listening in, send the data to them
sds.send(payload)
case <-sds.QuitChan:
log.Debug("Quitting the statediff block channel")
sds.close()
@ -103,6 +89,34 @@ func (sds *MockStateDiffService) Loop(chan core.ChainEvent) {
}
}
// process method builds the state diff payload from the current and parent block and streams it to listening subscriptions
func (sds *MockStateDiffService) process(currentBlock, parentBlock *types.Block) error {
stateDiff, err := sds.Builder.BuildStateDiff(parentBlock.Root(), currentBlock.Root(), currentBlock.Number(), currentBlock.Hash())
if err != nil {
return err
}
stateDiffRlp, err := rlp.EncodeToBytes(stateDiff)
if err != nil {
return err
}
payload := statediff.Payload{
StateDiffRlp: stateDiffRlp,
Err: err,
}
if sds.streamBlock {
rlpBuff := new(bytes.Buffer)
if err = currentBlock.EncodeRLP(rlpBuff); err != nil {
return err
}
payload.BlockRlp = rlpBuff.Bytes()
}
// If we have any websocket subscription listening in, send the data to them
sds.send(payload)
return nil
}
// Subscribe mock method
func (sds *MockStateDiffService) Subscribe(id rpc.ID, sub chan<- statediff.Payload, quitChan chan<- bool) {
log.Info("Subscribing to the statediff service")

View File

@ -66,6 +66,7 @@ func TestAPI(t *testing.T) {
serviceQuitChan := make(chan bool)
config := statediff.Config{
PathsAndProofs: true,
AllNodes: false,
}
mockService := MockStateDiffService{
Mutex: sync.Mutex{},
@ -74,6 +75,7 @@ func TestAPI(t *testing.T) {
ParentBlockChan: parentBlockChain,
QuitChan: serviceQuitChan,
Subscriptions: make(map[rpc.ID]statediff.Subscription),
streamBlock: true,
}
mockService.Start(nil)
id := rpc.NewID()
@ -88,6 +90,7 @@ func TestAPI(t *testing.T) {
BlockHash: block1.Hash(),
CreatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: burnLeafKey.Bytes(),
Value: burnAccount1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
@ -96,6 +99,7 @@ func TestAPI(t *testing.T) {
Storage: []statediff.StorageDiff{},
},
{
Leaf: true,
Key: testhelpers.Account1LeafKey.Bytes(),
Value: account1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
@ -107,6 +111,7 @@ func TestAPI(t *testing.T) {
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: []statediff.AccountDiff{
{
Leaf: true,
Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},

View File

@ -23,8 +23,9 @@ import (
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/common"
)
// Subscription struct holds our subscription channels
@ -40,18 +41,6 @@ type Payload struct {
Err error `json:"error"`
}
// AccountsMap is a mapping of keccak256(address) => accountWrapper
type AccountsMap map[common.Hash]accountWrapper
// AccountWrapper is used to temporary associate the unpacked account with its raw values
type accountWrapper struct {
Account *state.Account
RawKey []byte
RawValue []byte
Proof [][]byte
Path []byte
}
// StateDiff is the final output structure from the builder
type StateDiff struct {
BlockNumber *big.Int `json:"blockNumber" gencodec:"required"`
@ -84,6 +73,7 @@ func (sd *StateDiff) Encode() ([]byte, error) {
// AccountDiff holds the data for a single state diff node
type AccountDiff struct {
Leaf bool `json:"leaf" gencodec:"required"`
Key []byte `json:"key" gencodec:"required"`
Value []byte `json:"value" gencodec:"required"`
Proof [][]byte `json:"proof" gencodec:"required"`
@ -93,8 +83,22 @@ type AccountDiff struct {
// StorageDiff holds the data for a single storage diff node
type StorageDiff struct {
Leaf bool `json:"leaf" gencodec:"required"`
Key []byte `json:"key" gencodec:"required"`
Value []byte `json:"value" gencodec:"required"`
Proof [][]byte `json:"proof" gencodec:"required"`
Path []byte `json:"path" gencodec:"required"`
}
// AccountsMap is a mapping of keccak256(address) => accountWrapper
type AccountsMap map[common.Hash]accountWrapper
// AccountWrapper is used to temporary associate the unpacked account with its raw values
type accountWrapper struct {
Account *state.Account
Leaf bool
RawKey []byte
RawValue []byte
Proof [][]byte
Path []byte
}