update top level tests
This commit is contained in:
parent
93781fba83
commit
347a7ba0e8
@ -98,10 +98,9 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, intermed
|
|||||||
}
|
}
|
||||||
|
|
||||||
return StateDiff{
|
return StateDiff{
|
||||||
BlockNumber: args.BlockNumber,
|
BlockNumber: args.BlockNumber,
|
||||||
BlockHash: args.BlockHash,
|
BlockHash: args.BlockHash,
|
||||||
LeafNodes: append(append(updatedAccounts, createdAccounts...), deletedAccounts...),
|
Nodes: append(append(append(append(updatedAccounts, createdAccounts...), deletedAccounts...), createdOrUpdatedIntermediateNodes...), deletedIntermediateNodes...),
|
||||||
IntermediateNodes: append(createdOrUpdatedIntermediateNodes, deletedIntermediateNodes...),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +147,7 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args Args, param
|
|||||||
return StateDiff{
|
return StateDiff{
|
||||||
BlockNumber: args.BlockNumber,
|
BlockNumber: args.BlockNumber,
|
||||||
BlockHash: args.BlockHash,
|
BlockHash: args.BlockHash,
|
||||||
LeafNodes: append(append(updatedAccounts, createdAccounts...), deletedAccounts...),
|
Nodes: append(append(updatedAccounts, createdAccounts...), deletedAccounts...),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
// TODO: add test that filters on address
|
// TODO: add test that filters on address
|
||||||
var (
|
var (
|
||||||
contractLeafKey []byte
|
contractLeafKey []byte
|
||||||
emptyAccounts = make([]statediff.StateNode, 0)
|
emptyDiffs = make([]statediff.StateNode, 0)
|
||||||
emptyStorage = make([]statediff.StorageNode, 0)
|
emptyStorage = make([]statediff.StorageNode, 0)
|
||||||
block0, block1, block2, block3 *types.Block
|
block0, block1, block2, block3 *types.Block
|
||||||
builder statediff.Builder
|
builder statediff.Builder
|
||||||
@ -266,60 +266,49 @@ var (
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
type arguments struct {
|
|
||||||
oldStateRoot common.Hash
|
|
||||||
newStateRoot common.Hash
|
|
||||||
blockNumber *big.Int
|
|
||||||
blockHash common.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuilder(t *testing.T) {
|
func TestBuilder(t *testing.T) {
|
||||||
blockHashes, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
|
BlockHashes, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
|
||||||
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
|
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
block0 = blockMap[blockHashes[3]]
|
block0 = blockMap[BlockHashes[3]]
|
||||||
block1 = blockMap[blockHashes[2]]
|
block1 = blockMap[BlockHashes[2]]
|
||||||
block2 = blockMap[blockHashes[1]]
|
block2 = blockMap[BlockHashes[1]]
|
||||||
block3 = blockMap[blockHashes[0]]
|
block3 = blockMap[BlockHashes[0]]
|
||||||
config := statediff.Config{
|
params := statediff.Params{}
|
||||||
IntermediateNodes: false,
|
builder = statediff.NewBuilder(chain.StateCache())
|
||||||
}
|
|
||||||
builder = statediff.NewBuilder(chain, config)
|
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
startingArguments arguments
|
startingArguments statediff.Args
|
||||||
expected *statediff.StateDiff
|
expected *statediff.StateDiff
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"testEmptyDiff",
|
"testEmptyDiff",
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block0.Root(),
|
OldStateRoot: block0.Root(),
|
||||||
newStateRoot: block0.Root(),
|
NewStateRoot: block0.Root(),
|
||||||
blockNumber: block0.Number(),
|
|
||||||
blockHash: block0.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
CreatedNodes: emptyAccounts,
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: emptyAccounts,
|
BlockNumber: block0.Number(),
|
||||||
|
BlockHash: block0.Hash(),
|
||||||
|
Nodes: emptyDiffs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock0",
|
"testBlock0",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: testhelpers.NullHash,
|
OldStateRoot: testhelpers.NullHash,
|
||||||
newStateRoot: block0.Root(),
|
NewStateRoot: block0.Root(),
|
||||||
blockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
blockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{},
|
Path: []byte{},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -328,23 +317,21 @@ func TestBuilder(t *testing.T) {
|
|||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: emptyAccounts,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock1",
|
"testBlock1",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block0.Root(),
|
OldStateRoot: block0.Root(),
|
||||||
newStateRoot: block1.Root(),
|
NewStateRoot: block1.Root(),
|
||||||
blockNumber: block1.Number(),
|
BlockNumber: block1.Number(),
|
||||||
blockHash: block1.Hash(),
|
BlockHash: block1.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block1.Number(),
|
BlockNumber: block1.Number(),
|
||||||
BlockHash: block1.Hash(),
|
BlockHash: block1.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{'\x00'},
|
Path: []byte{'\x00'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -367,16 +354,6 @@ func TestBuilder(t *testing.T) {
|
|||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DeletedNodes: []statediff.StateNode{ // This leaf appears to be deleted since it is turned into a branch node and the account is moved to \x00
|
|
||||||
{ // It would instead show up in the UpdateAccounts as new branch node IF intermediate node diffing was turned on (as it is in the test below)
|
|
||||||
Path: []byte{},
|
|
||||||
NodeType: statediff.Removed,
|
|
||||||
LeafKey: testhelpers.BankLeafKey,
|
|
||||||
NodeValue: []byte{},
|
|
||||||
StorageDiffs: emptyStorage,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
UpdatedNodes: emptyAccounts,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -384,16 +361,37 @@ func TestBuilder(t *testing.T) {
|
|||||||
// 1000 transferred from testBankAddress to account1Addr
|
// 1000 transferred from testBankAddress to account1Addr
|
||||||
// 1000 transferred from account1Addr to account2Addr
|
// 1000 transferred from account1Addr to account2Addr
|
||||||
// account1addr creates a new contract
|
// account1addr creates a new contract
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block1.Root(),
|
OldStateRoot: block1.Root(),
|
||||||
newStateRoot: block2.Root(),
|
NewStateRoot: block2.Root(),
|
||||||
blockNumber: block2.Number(),
|
BlockNumber: block2.Number(),
|
||||||
blockHash: block2.Hash(),
|
BlockHash: block2.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block2.Number(),
|
BlockNumber: block2.Number(),
|
||||||
BlockHash: block2.Hash(),
|
BlockHash: block2.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
|
{
|
||||||
|
Path: []byte{'\x00'},
|
||||||
|
NodeType: statediff.Leaf,
|
||||||
|
LeafKey: testhelpers.BankLeafKey,
|
||||||
|
NodeValue: bankAccountAtBlock2LeafNode,
|
||||||
|
StorageDiffs: emptyStorage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: []byte{'\x05'},
|
||||||
|
NodeType: statediff.Leaf,
|
||||||
|
LeafKey: minerLeafKey,
|
||||||
|
NodeValue: minerAccountAtBlock2LeafNode,
|
||||||
|
StorageDiffs: emptyStorage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: []byte{'\x0e'},
|
||||||
|
NodeType: statediff.Leaf,
|
||||||
|
LeafKey: testhelpers.Account1LeafKey,
|
||||||
|
NodeValue: account1AtBlock2LeafNode,
|
||||||
|
StorageDiffs: emptyStorage,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Path: []byte{'\x06'},
|
Path: []byte{'\x06'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -416,48 +414,22 @@ func TestBuilder(t *testing.T) {
|
|||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: []statediff.StateNode{
|
|
||||||
{
|
|
||||||
Path: []byte{'\x00'},
|
|
||||||
NodeType: statediff.Leaf,
|
|
||||||
LeafKey: testhelpers.BankLeafKey,
|
|
||||||
NodeValue: bankAccountAtBlock2LeafNode,
|
|
||||||
StorageDiffs: emptyStorage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Path: []byte{'\x05'},
|
|
||||||
NodeType: statediff.Leaf,
|
|
||||||
LeafKey: minerLeafKey,
|
|
||||||
NodeValue: minerAccountAtBlock2LeafNode,
|
|
||||||
StorageDiffs: emptyStorage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Path: []byte{'\x0e'},
|
|
||||||
NodeType: statediff.Leaf,
|
|
||||||
LeafKey: testhelpers.Account1LeafKey,
|
|
||||||
NodeValue: account1AtBlock2LeafNode,
|
|
||||||
StorageDiffs: emptyStorage,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock3",
|
"testBlock3",
|
||||||
//the contract's storage is changed
|
//the contract's storage is changed
|
||||||
//and the block is mined by account 2
|
//and the block is mined by account 2
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block2.Root(),
|
OldStateRoot: block2.Root(),
|
||||||
newStateRoot: block3.Root(),
|
NewStateRoot: block3.Root(),
|
||||||
blockNumber: block3.Number(),
|
|
||||||
blockHash: block3.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block3.Number(),
|
BlockNumber: block3.Number(),
|
||||||
BlockHash: block3.Hash(),
|
BlockHash: block3.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: []statediff.StateNode{
|
BlockNumber: block3.Number(),
|
||||||
|
BlockHash: block3.Hash(),
|
||||||
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{'\x00'},
|
Path: []byte{'\x00'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -498,8 +470,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
arguments := test.startingArguments
|
diff, err := builder.BuildStateDiff(test.startingArguments, params)
|
||||||
diff, err := builder.BuildStateDiff(arguments.oldStateRoot, arguments.newStateRoot, arguments.blockNumber, arguments.blockHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -521,52 +492,51 @@ func TestBuilder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBuilderWithIntermediateNodes(t *testing.T) {
|
func TestBuilderWithIntermediateNodes(t *testing.T) {
|
||||||
blockHashes, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
|
BlockHashes, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
|
||||||
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
|
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
block0 = blockMap[blockHashes[3]]
|
block0 = blockMap[BlockHashes[3]]
|
||||||
block1 = blockMap[blockHashes[2]]
|
block1 = blockMap[BlockHashes[2]]
|
||||||
block2 = blockMap[blockHashes[1]]
|
block2 = blockMap[BlockHashes[1]]
|
||||||
block3 = blockMap[blockHashes[0]]
|
block3 = blockMap[BlockHashes[0]]
|
||||||
config := statediff.Config{
|
params := statediff.Params{
|
||||||
IntermediateNodes: true,
|
IntermediateStateNodes: true,
|
||||||
|
IntermediateStorageNodes: true,
|
||||||
}
|
}
|
||||||
builder = statediff.NewBuilder(chain, config)
|
builder = statediff.NewBuilder(chain.StateCache())
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
startingArguments arguments
|
startingArguments statediff.Args
|
||||||
expected *statediff.StateDiff
|
expected *statediff.StateDiff
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"testEmptyDiff",
|
"testEmptyDiff",
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block0.Root(),
|
OldStateRoot: block0.Root(),
|
||||||
newStateRoot: block0.Root(),
|
NewStateRoot: block0.Root(),
|
||||||
blockNumber: block0.Number(),
|
|
||||||
blockHash: block0.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
CreatedNodes: emptyAccounts,
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: emptyAccounts,
|
BlockNumber: block0.Number(),
|
||||||
|
BlockHash: block0.Hash(),
|
||||||
|
Nodes: emptyDiffs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock0",
|
"testBlock0",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: testhelpers.NullHash,
|
OldStateRoot: testhelpers.NullHash,
|
||||||
newStateRoot: block0.Root(),
|
NewStateRoot: block0.Root(),
|
||||||
blockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
blockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{},
|
Path: []byte{},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -575,23 +545,27 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: emptyAccounts,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock1",
|
"testBlock1",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block0.Root(),
|
OldStateRoot: block0.Root(),
|
||||||
newStateRoot: block1.Root(),
|
NewStateRoot: block1.Root(),
|
||||||
blockNumber: block1.Number(),
|
BlockNumber: block1.Number(),
|
||||||
blockHash: block1.Hash(),
|
BlockHash: block1.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block1.Number(),
|
BlockNumber: block1.Number(),
|
||||||
BlockHash: block1.Hash(),
|
BlockHash: block1.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
|
{
|
||||||
|
Path: []byte{},
|
||||||
|
NodeType: statediff.Branch,
|
||||||
|
NodeValue: block1BranchNode,
|
||||||
|
StorageDiffs: emptyStorage,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Path: []byte{'\x00'},
|
Path: []byte{'\x00'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -614,15 +588,6 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: []statediff.StateNode{
|
|
||||||
{
|
|
||||||
Path: []byte{},
|
|
||||||
NodeType: statediff.Branch,
|
|
||||||
NodeValue: block1BranchNode,
|
|
||||||
StorageDiffs: emptyStorage,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -630,40 +595,16 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
// 1000 transferred from testBankAddress to account1Addr
|
// 1000 transferred from testBankAddress to account1Addr
|
||||||
// 1000 transferred from account1Addr to account2Addr
|
// 1000 transferred from account1Addr to account2Addr
|
||||||
// account1addr creates a new contract
|
// account1addr creates a new contract
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block1.Root(),
|
OldStateRoot: block1.Root(),
|
||||||
newStateRoot: block2.Root(),
|
NewStateRoot: block2.Root(),
|
||||||
blockNumber: block2.Number(),
|
BlockNumber: block2.Number(),
|
||||||
blockHash: block2.Hash(),
|
BlockHash: block2.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block2.Number(),
|
BlockNumber: block2.Number(),
|
||||||
BlockHash: block2.Hash(),
|
BlockHash: block2.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
{
|
|
||||||
Path: []byte{'\x06'},
|
|
||||||
NodeType: statediff.Leaf,
|
|
||||||
LeafKey: contractLeafKey,
|
|
||||||
NodeValue: contractAccountAtBlock2LeafNode,
|
|
||||||
StorageDiffs: []statediff.StorageNode{
|
|
||||||
{
|
|
||||||
Path: []byte{},
|
|
||||||
NodeType: statediff.Leaf,
|
|
||||||
LeafKey: originalStorageKey,
|
|
||||||
NodeValue: originalStorageLeafNode,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Path: []byte{'\x0c'},
|
|
||||||
NodeType: statediff.Leaf,
|
|
||||||
LeafKey: testhelpers.Account2LeafKey,
|
|
||||||
NodeValue: account2AtBlock2LeafNode,
|
|
||||||
StorageDiffs: emptyStorage,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: []statediff.StateNode{
|
|
||||||
{
|
{
|
||||||
Path: []byte{},
|
Path: []byte{},
|
||||||
NodeType: statediff.Branch,
|
NodeType: statediff.Branch,
|
||||||
@ -691,6 +632,27 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
NodeValue: account1AtBlock2LeafNode,
|
NodeValue: account1AtBlock2LeafNode,
|
||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Path: []byte{'\x06'},
|
||||||
|
NodeType: statediff.Leaf,
|
||||||
|
LeafKey: contractLeafKey,
|
||||||
|
NodeValue: contractAccountAtBlock2LeafNode,
|
||||||
|
StorageDiffs: []statediff.StorageNode{
|
||||||
|
{
|
||||||
|
Path: []byte{},
|
||||||
|
NodeType: statediff.Leaf,
|
||||||
|
LeafKey: originalStorageKey,
|
||||||
|
NodeValue: originalStorageLeafNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: []byte{'\x0c'},
|
||||||
|
NodeType: statediff.Leaf,
|
||||||
|
LeafKey: testhelpers.Account2LeafKey,
|
||||||
|
NodeValue: account2AtBlock2LeafNode,
|
||||||
|
StorageDiffs: emptyStorage,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -698,18 +660,16 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
"testBlock3",
|
"testBlock3",
|
||||||
//the contract's storage is changed
|
//the contract's storage is changed
|
||||||
//and the block is mined by account 2
|
//and the block is mined by account 2
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block2.Root(),
|
OldStateRoot: block2.Root(),
|
||||||
newStateRoot: block3.Root(),
|
NewStateRoot: block3.Root(),
|
||||||
blockNumber: block3.Number(),
|
|
||||||
blockHash: block3.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block3.Number(),
|
BlockNumber: block3.Number(),
|
||||||
BlockHash: block3.Hash(),
|
BlockHash: block3.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: []statediff.StateNode{
|
BlockNumber: block3.Number(),
|
||||||
|
BlockHash: block3.Hash(),
|
||||||
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{},
|
Path: []byte{},
|
||||||
NodeType: statediff.Branch,
|
NodeType: statediff.Branch,
|
||||||
@ -761,8 +721,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
arguments := test.startingArguments
|
diff, err := builder.BuildStateDiff(test.startingArguments, params)
|
||||||
diff, err := builder.BuildStateDiff(arguments.oldStateRoot, arguments.newStateRoot, arguments.blockNumber, arguments.blockHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -784,70 +743,65 @@ func TestBuilderWithIntermediateNodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBuilderWithWatchedAddressList(t *testing.T) {
|
func TestBuilderWithWatchedAddressList(t *testing.T) {
|
||||||
blockHashes, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
|
BlockHashes, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
|
||||||
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
|
contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
block0 = blockMap[blockHashes[3]]
|
block0 = blockMap[BlockHashes[3]]
|
||||||
block1 = blockMap[blockHashes[2]]
|
block1 = blockMap[BlockHashes[2]]
|
||||||
block2 = blockMap[blockHashes[1]]
|
block2 = blockMap[BlockHashes[1]]
|
||||||
block3 = blockMap[blockHashes[0]]
|
block3 = blockMap[BlockHashes[0]]
|
||||||
config := statediff.Config{
|
params := statediff.Params{
|
||||||
IntermediateNodes: false,
|
WatchedAddresses: []string{testhelpers.Account1Addr.Hex(), testhelpers.ContractAddr.Hex()},
|
||||||
WatchedAddresses: []string{testhelpers.Account1Addr.Hex(), testhelpers.ContractAddr.Hex()},
|
|
||||||
}
|
}
|
||||||
builder = statediff.NewBuilder(chain, config)
|
builder = statediff.NewBuilder(chain.StateCache())
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
startingArguments arguments
|
startingArguments statediff.Args
|
||||||
expected *statediff.StateDiff
|
expected *statediff.StateDiff
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"testEmptyDiff",
|
"testEmptyDiff",
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block0.Root(),
|
OldStateRoot: block0.Root(),
|
||||||
newStateRoot: block0.Root(),
|
NewStateRoot: block0.Root(),
|
||||||
blockNumber: block0.Number(),
|
|
||||||
blockHash: block0.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
CreatedNodes: emptyAccounts,
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: emptyAccounts,
|
BlockNumber: block0.Number(),
|
||||||
|
BlockHash: block0.Hash(),
|
||||||
|
Nodes: emptyDiffs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock0",
|
"testBlock0",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: testhelpers.NullHash,
|
OldStateRoot: testhelpers.NullHash,
|
||||||
newStateRoot: block0.Root(),
|
NewStateRoot: block0.Root(),
|
||||||
blockNumber: block0.Number(),
|
|
||||||
blockHash: block0.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block0.Number(),
|
BlockNumber: block0.Number(),
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
CreatedNodes: emptyAccounts,
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: emptyAccounts,
|
BlockNumber: block0.Number(),
|
||||||
|
BlockHash: block0.Hash(),
|
||||||
|
Nodes: emptyDiffs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock1",
|
"testBlock1",
|
||||||
//10000 transferred from testBankAddress to account1Addr
|
//10000 transferred from testBankAddress to account1Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block0.Root(),
|
OldStateRoot: block0.Root(),
|
||||||
newStateRoot: block1.Root(),
|
NewStateRoot: block1.Root(),
|
||||||
blockNumber: block1.Number(),
|
BlockNumber: block1.Number(),
|
||||||
blockHash: block1.Hash(),
|
BlockHash: block1.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block1.Number(),
|
BlockNumber: block1.Number(),
|
||||||
BlockHash: block1.Hash(),
|
BlockHash: block1.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{'\x0e'},
|
Path: []byte{'\x0e'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -856,24 +810,22 @@ func TestBuilderWithWatchedAddressList(t *testing.T) {
|
|||||||
StorageDiffs: emptyStorage,
|
StorageDiffs: emptyStorage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: []statediff.StateNode{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testBlock2",
|
"testBlock2",
|
||||||
//1000 transferred from testBankAddress to account1Addr
|
//1000 transferred from testBankAddress to account1Addr
|
||||||
//1000 transferred from account1Addr to account2Addr
|
//1000 transferred from account1Addr to account2Addr
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block1.Root(),
|
OldStateRoot: block1.Root(),
|
||||||
newStateRoot: block2.Root(),
|
NewStateRoot: block2.Root(),
|
||||||
blockNumber: block2.Number(),
|
BlockNumber: block2.Number(),
|
||||||
blockHash: block2.Hash(),
|
BlockHash: block2.Hash(),
|
||||||
},
|
},
|
||||||
&statediff.StateDiff{
|
&statediff.StateDiff{
|
||||||
BlockNumber: block2.Number(),
|
BlockNumber: block2.Number(),
|
||||||
BlockHash: block2.Hash(),
|
BlockHash: block2.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{'\x06'},
|
Path: []byte{'\x06'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -888,9 +840,6 @@ func TestBuilderWithWatchedAddressList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
DeletedNodes: emptyAccounts,
|
|
||||||
UpdatedNodes: []statediff.StateNode{
|
|
||||||
{
|
{
|
||||||
Path: []byte{'\x0e'},
|
Path: []byte{'\x0e'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -905,18 +854,16 @@ func TestBuilderWithWatchedAddressList(t *testing.T) {
|
|||||||
"testBlock3",
|
"testBlock3",
|
||||||
//the contract's storage is changed
|
//the contract's storage is changed
|
||||||
//and the block is mined by account 2
|
//and the block is mined by account 2
|
||||||
arguments{
|
statediff.Args{
|
||||||
oldStateRoot: block2.Root(),
|
OldStateRoot: block2.Root(),
|
||||||
newStateRoot: block3.Root(),
|
NewStateRoot: block3.Root(),
|
||||||
blockNumber: block3.Number(),
|
|
||||||
blockHash: block3.Hash(),
|
|
||||||
},
|
|
||||||
&statediff.StateDiff{
|
|
||||||
BlockNumber: block3.Number(),
|
BlockNumber: block3.Number(),
|
||||||
BlockHash: block3.Hash(),
|
BlockHash: block3.Hash(),
|
||||||
CreatedNodes: []statediff.StateNode{},
|
},
|
||||||
DeletedNodes: emptyAccounts,
|
&statediff.StateDiff{
|
||||||
UpdatedNodes: []statediff.StateNode{
|
BlockNumber: block3.Number(),
|
||||||
|
BlockHash: block3.Hash(),
|
||||||
|
Nodes: []statediff.StateNode{
|
||||||
{
|
{
|
||||||
Path: []byte{'\x06'},
|
Path: []byte{'\x06'},
|
||||||
NodeType: statediff.Leaf,
|
NodeType: statediff.Leaf,
|
||||||
@ -943,8 +890,7 @@ func TestBuilderWithWatchedAddressList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
arguments := test.startingArguments
|
diff, err := builder.BuildStateDiff(test.startingArguments, params)
|
||||||
diff, err := builder.BuildStateDiff(arguments.oldStateRoot, arguments.newStateRoot, arguments.blockNumber, arguments.blockHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,8 @@ func (sds *Service) Loop(chainEventCh chan core.ChainEvent) {
|
|||||||
sds.streamStateDiff(currentBlock, parentBlock.Root())
|
sds.streamStateDiff(currentBlock, parentBlock.Root())
|
||||||
case err := <-errCh:
|
case err := <-errCh:
|
||||||
log.Warn("Error from chain event subscription", "error", err)
|
log.Warn("Error from chain event subscription", "error", err)
|
||||||
|
sds.close()
|
||||||
|
return
|
||||||
case <-sds.QuitChan:
|
case <-sds.QuitChan:
|
||||||
log.Info("Quitting the statediffing process")
|
log.Info("Quitting the statediffing process")
|
||||||
sds.close()
|
sds.close()
|
||||||
|
@ -72,23 +72,30 @@ var (
|
|||||||
event1 = core.ChainEvent{Block: testBlock1}
|
event1 = core.ChainEvent{Block: testBlock1}
|
||||||
event2 = core.ChainEvent{Block: testBlock2}
|
event2 = core.ChainEvent{Block: testBlock2}
|
||||||
event3 = core.ChainEvent{Block: testBlock3}
|
event3 = core.ChainEvent{Block: testBlock3}
|
||||||
|
|
||||||
|
defaultParams = statediff.Params{
|
||||||
|
IncludeBlock: true,
|
||||||
|
IncludeReceipts: true,
|
||||||
|
IncludeTD: true,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func testErrorInChainEventLoop(t *testing.T) {
|
func testErrorInChainEventLoop(t *testing.T) {
|
||||||
//the first chain event causes and error (in blockchain mock)
|
//the first chain event causes and error (in blockchain mock)
|
||||||
builder := mocks.Builder{}
|
builder := mocks.Builder{}
|
||||||
blockChain := mocks.BlockChain{}
|
blockChain := mocks.BlockChain{}
|
||||||
|
serviceQuit := make(chan bool)
|
||||||
service := statediff.Service{
|
service := statediff.Service{
|
||||||
Mutex: sync.Mutex{},
|
Mutex: sync.Mutex{},
|
||||||
Builder: &builder,
|
Builder: &builder,
|
||||||
BlockChain: &blockChain,
|
BlockChain: &blockChain,
|
||||||
QuitChan: make(chan bool),
|
QuitChan: serviceQuit,
|
||||||
Subscriptions: make(map[rpc.ID]statediff.Subscription),
|
Subscriptions: make(map[common.Hash]map[rpc.ID]statediff.Subscription),
|
||||||
StreamBlock: true,
|
SubscriptionTypes: make(map[common.Hash]statediff.Params),
|
||||||
}
|
}
|
||||||
payloadChan := make(chan statediff.Payload, 2)
|
payloadChan := make(chan statediff.Payload, 2)
|
||||||
quitChan := make(chan bool)
|
quitChan := make(chan bool)
|
||||||
service.Subscribe(rpc.NewID(), payloadChan, quitChan)
|
service.Subscribe(rpc.NewID(), payloadChan, quitChan, defaultParams)
|
||||||
testRoot2 = common.HexToHash("0xTestRoot2")
|
testRoot2 = common.HexToHash("0xTestRoot2")
|
||||||
blockMapping := make(map[common.Hash]*types.Block)
|
blockMapping := make(map[common.Hash]*types.Block)
|
||||||
blockMapping[parentBlock1.Hash()] = parentBlock1
|
blockMapping[parentBlock1.Hash()] = parentBlock1
|
||||||
@ -99,7 +106,7 @@ func testErrorInChainEventLoop(t *testing.T) {
|
|||||||
blockChain.SetReceiptsForHash(testBlock2.Hash(), testReceipts2)
|
blockChain.SetReceiptsForHash(testBlock2.Hash(), testReceipts2)
|
||||||
|
|
||||||
payloads := make([]statediff.Payload, 0, 2)
|
payloads := make([]statediff.Payload, 0, 2)
|
||||||
wg := sync.WaitGroup{}
|
wg := new(sync.WaitGroup)
|
||||||
go func() {
|
go func() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
@ -111,7 +118,6 @@ func testErrorInChainEventLoop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
service.Loop(eventsChannel)
|
service.Loop(eventsChannel)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
if len(payloads) != 2 {
|
if len(payloads) != 2 {
|
||||||
@ -135,23 +141,27 @@ func testErrorInChainEventLoop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(builder.BlockHash, testBlock2.Hash()) {
|
if !reflect.DeepEqual(builder.Params, defaultParams) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual blockhash does not equal expected.\nactual:%+v\nexpected: %+v", builder.BlockHash, testBlock2.Hash())
|
t.Logf("Actual params does not equal expected.\nactual:%+v\nexpected: %+v", builder.Params, defaultParams)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.OldStateRoot.Bytes(), parentBlock2.Root().Bytes()) {
|
if !bytes.Equal(builder.Args.BlockHash.Bytes(), testBlock2.Hash().Bytes()) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual root does not equal expected.\nactual:%+v\nexpected: %+v", builder.OldStateRoot, parentBlock2.Root())
|
t.Logf("Actual blockhash does not equal expected.\nactual:%x\nexpected: %x", builder.Args.BlockHash.Bytes(), testBlock2.Hash().Bytes())
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.NewStateRoot.Bytes(), testBlock2.Root().Bytes()) {
|
if !bytes.Equal(builder.Args.OldStateRoot.Bytes(), parentBlock2.Root().Bytes()) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual root does not equal expected.\nactual:%+v\nexpected: %+v", builder.NewStateRoot, testBlock2.Root())
|
t.Logf("Actual root does not equal expected.\nactual:%x\nexpected: %x", builder.Args.OldStateRoot.Bytes(), parentBlock2.Root().Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Equal(builder.Args.NewStateRoot.Bytes(), testBlock2.Root().Bytes()) {
|
||||||
|
t.Error("Test failure:", t.Name())
|
||||||
|
t.Logf("Actual root does not equal expected.\nactual:%x\nexpected: %x", builder.Args.NewStateRoot.Bytes(), testBlock2.Root().Bytes())
|
||||||
}
|
}
|
||||||
//look up the parent block from its hash
|
//look up the parent block from its hash
|
||||||
expectedHashes := []common.Hash{testBlock1.ParentHash(), testBlock2.ParentHash()}
|
expectedHashes := []common.Hash{testBlock1.ParentHash(), testBlock2.ParentHash()}
|
||||||
if !reflect.DeepEqual(blockChain.HashesLookedUp, expectedHashes) {
|
if !reflect.DeepEqual(blockChain.HashesLookedUp, expectedHashes) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual parent hash does not equal expected.\nactual:%+v\nexpected: %+v", blockChain.HashesLookedUp, expectedHashes)
|
t.Logf("Actual looked up parent hashes does not equal expected.\nactual:%+v\nexpected: %+v", blockChain.HashesLookedUp, expectedHashes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,14 +170,15 @@ func testErrorInBlockLoop(t *testing.T) {
|
|||||||
builder := mocks.Builder{}
|
builder := mocks.Builder{}
|
||||||
blockChain := mocks.BlockChain{}
|
blockChain := mocks.BlockChain{}
|
||||||
service := statediff.Service{
|
service := statediff.Service{
|
||||||
Builder: &builder,
|
Builder: &builder,
|
||||||
BlockChain: &blockChain,
|
BlockChain: &blockChain,
|
||||||
QuitChan: make(chan bool),
|
QuitChan: make(chan bool),
|
||||||
Subscriptions: make(map[rpc.ID]statediff.Subscription),
|
Subscriptions: make(map[common.Hash]map[rpc.ID]statediff.Subscription),
|
||||||
|
SubscriptionTypes: make(map[common.Hash]statediff.Params),
|
||||||
}
|
}
|
||||||
payloadChan := make(chan statediff.Payload)
|
payloadChan := make(chan statediff.Payload)
|
||||||
quitChan := make(chan bool)
|
quitChan := make(chan bool)
|
||||||
service.Subscribe(rpc.NewID(), payloadChan, quitChan)
|
service.Subscribe(rpc.NewID(), payloadChan, quitChan, defaultParams)
|
||||||
blockMapping := make(map[common.Hash]*types.Block)
|
blockMapping := make(map[common.Hash]*types.Block)
|
||||||
blockMapping[parentBlock1.Hash()] = parentBlock1
|
blockMapping[parentBlock1.Hash()] = parentBlock1
|
||||||
blockChain.SetBlocksForHashes(blockMapping)
|
blockChain.SetBlocksForHashes(blockMapping)
|
||||||
@ -180,18 +191,21 @@ func testErrorInBlockLoop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
service.Loop(eventsChannel)
|
service.Loop(eventsChannel)
|
||||||
|
if !reflect.DeepEqual(builder.Params, defaultParams) {
|
||||||
if !bytes.Equal(builder.BlockHash.Bytes(), testBlock1.Hash().Bytes()) {
|
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", builder.BlockHash, testBlock1.Hash())
|
t.Logf("Actual params does not equal expected.\nactual:%+v\nexpected: %+v", builder.Params, defaultParams)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.OldStateRoot.Bytes(), parentBlock1.Root().Bytes()) {
|
if !bytes.Equal(builder.Args.BlockHash.Bytes(), testBlock1.Hash().Bytes()) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", builder.OldStateRoot, parentBlock1.Root())
|
t.Logf("Actual blockhash does not equal expected.\nactual:%+v\nexpected: %x", builder.Args.BlockHash.Bytes(), testBlock1.Hash().Bytes())
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.NewStateRoot.Bytes(), testBlock1.Root().Bytes()) {
|
if !bytes.Equal(builder.Args.OldStateRoot.Bytes(), parentBlock1.Root().Bytes()) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", builder.NewStateRoot, testBlock1.Root())
|
t.Logf("Actual old state root does not equal expected.\nactual:%+v\nexpected: %x", builder.Args.OldStateRoot.Bytes(), parentBlock1.Root().Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Equal(builder.Args.NewStateRoot.Bytes(), testBlock1.Root().Bytes()) {
|
||||||
|
t.Error("Test failure:", t.Name())
|
||||||
|
t.Logf("Actual new state root does not equal expected.\nactual:%+v\nexpected: %x", builder.Args.NewStateRoot.Bytes(), testBlock1.Root().Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,14 +248,14 @@ func testErrorInStateDiffAt(t *testing.T) {
|
|||||||
blockChain.SetBlockForNumber(testBlock1, testBlock1.NumberU64())
|
blockChain.SetBlockForNumber(testBlock1, testBlock1.NumberU64())
|
||||||
blockChain.SetReceiptsForHash(testBlock1.Hash(), testReceipts1)
|
blockChain.SetReceiptsForHash(testBlock1.Hash(), testReceipts1)
|
||||||
service := statediff.Service{
|
service := statediff.Service{
|
||||||
Mutex: sync.Mutex{},
|
Mutex: sync.Mutex{},
|
||||||
Builder: &builder,
|
Builder: &builder,
|
||||||
BlockChain: &blockChain,
|
BlockChain: &blockChain,
|
||||||
QuitChan: make(chan bool),
|
QuitChan: make(chan bool),
|
||||||
Subscriptions: make(map[rpc.ID]statediff.Subscription),
|
Subscriptions: make(map[common.Hash]map[rpc.ID]statediff.Subscription),
|
||||||
StreamBlock: true,
|
SubscriptionTypes: make(map[common.Hash]statediff.Params),
|
||||||
}
|
}
|
||||||
stateDiffPayload, err := service.StateDiffAt(testBlock1.NumberU64())
|
stateDiffPayload, err := service.StateDiffAt(testBlock1.NumberU64(), defaultParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -249,20 +263,24 @@ func testErrorInStateDiffAt(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.BlockHash.Bytes(), testBlock1.Hash().Bytes()) {
|
if !reflect.DeepEqual(builder.Params, defaultParams) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", builder.BlockHash, testBlock1.Hash())
|
t.Logf("Actual params does not equal expected.\nactual:%+v\nexpected: %+v", builder.Params, defaultParams)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.OldStateRoot.Bytes(), parentBlock1.Root().Bytes()) {
|
if !bytes.Equal(builder.Args.BlockHash.Bytes(), testBlock1.Hash().Bytes()) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", builder.OldStateRoot, parentBlock1.Root())
|
t.Logf("Actual blockhash does not equal expected.\nactual:%+v\nexpected: %x", builder.Args.BlockHash.Bytes(), testBlock1.Hash().Bytes())
|
||||||
}
|
}
|
||||||
if !bytes.Equal(builder.NewStateRoot.Bytes(), testBlock1.Root().Bytes()) {
|
if !bytes.Equal(builder.Args.OldStateRoot.Bytes(), parentBlock1.Root().Bytes()) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", builder.NewStateRoot, testBlock1.Root())
|
t.Logf("Actual old state root does not equal expected.\nactual:%+v\nexpected: %x", builder.Args.OldStateRoot.Bytes(), parentBlock1.Root().Bytes())
|
||||||
|
}
|
||||||
|
if !bytes.Equal(builder.Args.NewStateRoot.Bytes(), testBlock1.Root().Bytes()) {
|
||||||
|
t.Error("Test failure:", t.Name())
|
||||||
|
t.Logf("Actual new state root does not equal expected.\nactual:%+v\nexpected: %x", builder.Args.NewStateRoot.Bytes(), testBlock1.Root().Bytes())
|
||||||
}
|
}
|
||||||
if !bytes.Equal(expectedStateDiffPayloadRlp, stateDiffPayloadRlp) {
|
if !bytes.Equal(expectedStateDiffPayloadRlp, stateDiffPayloadRlp) {
|
||||||
t.Error("Test failure:", t.Name())
|
t.Error("Test failure:", t.Name())
|
||||||
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", expectedStateDiffPayload, stateDiffPayload)
|
t.Logf("Actual state diff payload does not equal expected.\nactual:%+v\nexpected: %+v", expectedStateDiffPayload, stateDiffPayload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
@ -35,15 +37,15 @@ import (
|
|||||||
// MockStateDiffService is a mock state diff service
|
// MockStateDiffService is a mock state diff service
|
||||||
type MockStateDiffService struct {
|
type MockStateDiffService struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
Builder statediff.Builder
|
Builder statediff.Builder
|
||||||
BlockChain *BlockChain
|
BlockChain *BlockChain
|
||||||
ReturnProtocol []p2p.Protocol
|
ReturnProtocol []p2p.Protocol
|
||||||
ReturnAPIs []rpc.API
|
ReturnAPIs []rpc.API
|
||||||
BlockChan chan *types.Block
|
BlockChan chan *types.Block
|
||||||
ParentBlockChan chan *types.Block
|
ParentBlockChan chan *types.Block
|
||||||
QuitChan chan bool
|
QuitChan chan bool
|
||||||
Subscriptions map[rpc.ID]statediff.Subscription
|
Subscriptions map[common.Hash]map[rpc.ID]statediff.Subscription
|
||||||
streamBlock bool
|
SubscriptionTypes map[common.Hash]statediff.Params
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protocols mock method
|
// Protocols mock method
|
||||||
@ -78,12 +80,7 @@ func (sds *MockStateDiffService) Loop(chan core.ChainEvent) {
|
|||||||
"current block number", currentBlock.Number())
|
"current block number", currentBlock.Number())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
payload, err := sds.processStateDiff(currentBlock, parentBlock)
|
sds.streamStateDiff(currentBlock, parentBlock.Root())
|
||||||
if err != nil {
|
|
||||||
log.Error("Error building statediff", "block number", currentBlock.Number(), "error", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sds.send(*payload)
|
|
||||||
case <-sds.QuitChan:
|
case <-sds.QuitChan:
|
||||||
log.Debug("Quitting the statediff block channel")
|
log.Debug("Quitting the statediff block channel")
|
||||||
sds.close()
|
sds.close()
|
||||||
@ -92,13 +89,46 @@ func (sds *MockStateDiffService) Loop(chan core.ChainEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// processStateDiff method builds the state diff payload from the current and parent block and streams it to listening subscriptions
|
// streamStateDiff method builds the state diff payload for each subscription according to their subscription type and sends them the result
|
||||||
func (sds *MockStateDiffService) processStateDiff(currentBlock, parentBlock *types.Block) (*statediff.Payload, error) {
|
func (sds *MockStateDiffService) streamStateDiff(currentBlock *types.Block, parentRoot common.Hash) {
|
||||||
stateDiff, err := sds.Builder.BuildStateDiff(parentBlock.Root(), currentBlock.Root(), currentBlock.Number(), currentBlock.Hash())
|
sds.Lock()
|
||||||
|
for ty, subs := range sds.Subscriptions {
|
||||||
|
params, ok := sds.SubscriptionTypes[ty]
|
||||||
|
if !ok {
|
||||||
|
log.Error(fmt.Sprintf("subscriptions type %s do not have a parameter set associated with them", ty.Hex()))
|
||||||
|
sds.closeType(ty)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// create payload for this subscription type
|
||||||
|
payload, err := sds.processStateDiff(currentBlock, parentRoot, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("statediff processing error for subscriptions with parameters: %+v", params))
|
||||||
|
sds.closeType(ty)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for id, sub := range subs {
|
||||||
|
select {
|
||||||
|
case sub.PayloadChan <- *payload:
|
||||||
|
log.Debug(fmt.Sprintf("sending statediff payload to subscription %s", id))
|
||||||
|
default:
|
||||||
|
log.Info(fmt.Sprintf("unable to send statediff payload to subscription %s; channel has no receiver", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sds.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
stateDiff, err := sds.Builder.BuildStateDiff(statediff.Args{
|
||||||
|
NewStateRoot: currentBlock.Root(),
|
||||||
|
OldStateRoot: parentRoot,
|
||||||
|
BlockHash: currentBlock.Hash(),
|
||||||
|
BlockNumber: currentBlock.Number(),
|
||||||
|
}, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stateDiffRlp, err := rlp.EncodeToBytes(stateDiff)
|
stateDiffRlp, err := rlp.EncodeToBytes(stateDiff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -106,13 +136,17 @@ func (sds *MockStateDiffService) processStateDiff(currentBlock, parentBlock *typ
|
|||||||
payload := statediff.Payload{
|
payload := statediff.Payload{
|
||||||
StateDiffRlp: stateDiffRlp,
|
StateDiffRlp: stateDiffRlp,
|
||||||
}
|
}
|
||||||
if sds.streamBlock {
|
if params.IncludeBlock {
|
||||||
rlpBuff := new(bytes.Buffer)
|
blockBuff := new(bytes.Buffer)
|
||||||
if err = currentBlock.EncodeRLP(rlpBuff); err != nil {
|
if err = currentBlock.EncodeRLP(blockBuff); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payload.BlockRlp = rlpBuff.Bytes()
|
payload.BlockRlp = blockBuff.Bytes()
|
||||||
|
}
|
||||||
|
if params.IncludeTD {
|
||||||
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(currentBlock.Hash())
|
payload.TotalDifficulty = sds.BlockChain.GetTdByHash(currentBlock.Hash())
|
||||||
|
}
|
||||||
|
if params.IncludeReceipts {
|
||||||
receiptBuff := new(bytes.Buffer)
|
receiptBuff := new(bytes.Buffer)
|
||||||
receipts := sds.BlockChain.GetReceiptsByHash(currentBlock.Hash())
|
receipts := sds.BlockChain.GetReceiptsByHash(currentBlock.Hash())
|
||||||
if err = rlp.Encode(receiptBuff, receipts); err != nil {
|
if err = rlp.Encode(receiptBuff, receipts); err != nil {
|
||||||
@ -123,53 +157,68 @@ func (sds *MockStateDiffService) processStateDiff(currentBlock, parentBlock *typ
|
|||||||
return &payload, nil
|
return &payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe mock method
|
// Subscribe is used by the API to subscribe to the service loop
|
||||||
func (sds *MockStateDiffService) Subscribe(id rpc.ID, sub chan<- statediff.Payload, quitChan chan<- bool) {
|
func (sds *MockStateDiffService) Subscribe(id rpc.ID, sub chan<- statediff.Payload, quitChan chan<- bool, params statediff.Params) {
|
||||||
log.Info("Subscribing to the mock statediff service")
|
// Subscription type is defined as the hash of the rlp-serialized subscription params
|
||||||
|
by, err := rlp.EncodeToBytes(params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subscriptionType := crypto.Keccak256Hash(by)
|
||||||
|
// Add subscriber
|
||||||
sds.Lock()
|
sds.Lock()
|
||||||
sds.Subscriptions[id] = statediff.Subscription{
|
if sds.Subscriptions[subscriptionType] == nil {
|
||||||
|
sds.Subscriptions[subscriptionType] = make(map[rpc.ID]statediff.Subscription)
|
||||||
|
}
|
||||||
|
sds.Subscriptions[subscriptionType][id] = statediff.Subscription{
|
||||||
PayloadChan: sub,
|
PayloadChan: sub,
|
||||||
QuitChan: quitChan,
|
QuitChan: quitChan,
|
||||||
}
|
}
|
||||||
|
sds.SubscriptionTypes[subscriptionType] = params
|
||||||
sds.Unlock()
|
sds.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsubscribe mock method
|
// Unsubscribe is used to unsubscribe from the service loop
|
||||||
func (sds *MockStateDiffService) Unsubscribe(id rpc.ID) error {
|
func (sds *MockStateDiffService) Unsubscribe(id rpc.ID) error {
|
||||||
log.Info("Unsubscribing from the mock statediff service")
|
|
||||||
sds.Lock()
|
sds.Lock()
|
||||||
_, ok := sds.Subscriptions[id]
|
for ty := range sds.Subscriptions {
|
||||||
if !ok {
|
delete(sds.Subscriptions[ty], id)
|
||||||
return fmt.Errorf("cannot unsubscribe; subscription for id %s does not exist", id)
|
if len(sds.Subscriptions[ty]) == 0 {
|
||||||
|
// If we removed the last subscription of this type, remove the subscription type outright
|
||||||
|
delete(sds.Subscriptions, ty)
|
||||||
|
delete(sds.SubscriptionTypes, ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete(sds.Subscriptions, id)
|
|
||||||
sds.Unlock()
|
sds.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sds *MockStateDiffService) send(payload statediff.Payload) {
|
// StateDiffAt mock method
|
||||||
sds.Lock()
|
func (sds *MockStateDiffService) StateDiffAt(blockNumber uint64, params statediff.Params) (*statediff.Payload, error) {
|
||||||
for id, sub := range sds.Subscriptions {
|
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
||||||
select {
|
log.Info(fmt.Sprintf("sending state diff at %d", blockNumber))
|
||||||
case sub.PayloadChan <- payload:
|
if blockNumber == 0 {
|
||||||
log.Info("sending state diff payload to subscription %s", id)
|
return sds.processStateDiff(currentBlock, common.Hash{}, params)
|
||||||
default:
|
|
||||||
log.Info("unable to send payload to subscription %s; channel has no receiver", id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sds.Unlock()
|
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
|
||||||
|
return sds.processStateDiff(currentBlock, parentBlock.Root(), params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close is used to close all listening subscriptions
|
||||||
func (sds *MockStateDiffService) close() {
|
func (sds *MockStateDiffService) close() {
|
||||||
sds.Lock()
|
sds.Lock()
|
||||||
for id, sub := range sds.Subscriptions {
|
for ty, subs := range sds.Subscriptions {
|
||||||
select {
|
for id, sub := range subs {
|
||||||
case sub.QuitChan <- true:
|
select {
|
||||||
delete(sds.Subscriptions, id)
|
case sub.QuitChan <- true:
|
||||||
log.Info("closing subscription %s", id)
|
log.Info(fmt.Sprintf("closing subscription %s", id))
|
||||||
default:
|
default:
|
||||||
log.Info("unable to close subscription %s; channel has no receiver", id)
|
log.Info(fmt.Sprintf("unable to close subscription %s; channel has no receiver", id))
|
||||||
|
}
|
||||||
|
delete(sds.Subscriptions[ty], id)
|
||||||
}
|
}
|
||||||
|
delete(sds.Subscriptions, ty)
|
||||||
|
delete(sds.SubscriptionTypes, ty)
|
||||||
}
|
}
|
||||||
sds.Unlock()
|
sds.Unlock()
|
||||||
}
|
}
|
||||||
@ -193,10 +242,22 @@ func (sds *MockStateDiffService) Stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateDiffAt mock method
|
// closeType is used to close all subscriptions of given type
|
||||||
func (sds *MockStateDiffService) StateDiffAt(blockNumber uint64) (*statediff.Payload, error) {
|
// closeType needs to be called with subscription access locked
|
||||||
currentBlock := sds.BlockChain.GetBlockByNumber(blockNumber)
|
func (sds *MockStateDiffService) closeType(subType common.Hash) {
|
||||||
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
|
subs := sds.Subscriptions[subType]
|
||||||
log.Info(fmt.Sprintf("sending state diff at %d", blockNumber))
|
for id, sub := range subs {
|
||||||
return sds.processStateDiff(currentBlock, parentBlock)
|
sendNonBlockingQuit(id, sub)
|
||||||
|
}
|
||||||
|
delete(sds.Subscriptions, subType)
|
||||||
|
delete(sds.SubscriptionTypes, subType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendNonBlockingQuit(id rpc.ID, sub statediff.Subscription) {
|
||||||
|
select {
|
||||||
|
case sub.QuitChan <- true:
|
||||||
|
log.Info(fmt.Sprintf("closing subscription %s", id))
|
||||||
|
default:
|
||||||
|
log.Info("unable to close subscription %s; channel has no receiver", id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,28 +17,21 @@
|
|||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/statediff"
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Builder is a mock state diff builder
|
// Builder is a mock state diff builder
|
||||||
type Builder struct {
|
type Builder struct {
|
||||||
OldStateRoot common.Hash
|
Args statediff.Args
|
||||||
NewStateRoot common.Hash
|
Params statediff.Params
|
||||||
BlockNumber *big.Int
|
|
||||||
BlockHash common.Hash
|
|
||||||
stateDiff statediff.StateDiff
|
stateDiff statediff.StateDiff
|
||||||
builderError error
|
builderError error
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildStateDiff mock method
|
// BuildStateDiff mock method
|
||||||
func (builder *Builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber *big.Int, blockHash common.Hash) (statediff.StateDiff, error) {
|
func (builder *Builder) BuildStateDiff(args statediff.Args, params statediff.Params) (statediff.StateDiff, error) {
|
||||||
builder.OldStateRoot = oldStateRoot
|
builder.Args = args
|
||||||
builder.NewStateRoot = newStateRoot
|
builder.Params = params
|
||||||
builder.BlockNumber = blockNumber
|
|
||||||
builder.BlockHash = blockHash
|
|
||||||
|
|
||||||
return builder.stateDiff, builder.builderError
|
return builder.stateDiff, builder.builderError
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,9 @@ func (sd *Payload) Encode() ([]byte, error) {
|
|||||||
|
|
||||||
// StateDiff is the final output structure from the builder
|
// StateDiff is the final output structure from the builder
|
||||||
type StateDiff struct {
|
type StateDiff 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"`
|
||||||
LeafNodes []StateNode `json:"leafNodes" gencodec:"required"`
|
Nodes []StateNode `json:"Nodes" gencodec:"required"`
|
||||||
IntermediateNodes []StateNode `json:"intermediateNodes" gencodec:"required"`
|
|
||||||
|
|
||||||
encoded []byte
|
encoded []byte
|
||||||
err error
|
err error
|
||||||
|
Loading…
Reference in New Issue
Block a user