update top level tests

This commit is contained in:
Ian Norden 2020-05-13 14:02:32 -05:00
parent 93781fba83
commit 347a7ba0e8
7 changed files with 374 additions and 356 deletions

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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()

View File

@ -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)
} }
} }

View File

@ -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)
}
} }

View File

@ -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
} }

View File

@ -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