diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 7815244b2..e4bb18a89 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -29,6 +29,8 @@ import (
"strings"
"time"
+ cli "gopkg.in/urfave/cli.v1"
+
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
@@ -56,9 +58,8 @@ import (
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
- "github.com/ethereum/go-ethereum/statediff/service"
+ "github.com/ethereum/go-ethereum/statediff"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
- cli "gopkg.in/urfave/cli.v1"
)
var (
@@ -1532,7 +1533,7 @@ func RegisterStateDiffService(stack *node.Node, ctx *cli.Context) {
ctx.Service(ðServ)
chainDb := ethServ.ChainDb()
blockChain := ethServ.BlockChain()
- return service.NewStateDiffService(chainDb, blockChain)
+ return statediff.NewStateDiffService(chainDb, blockChain)
}); err != nil {
Fatalf("Failed to register State Diff Service", err)
}
diff --git a/core/blockchain.go b/core/blockchain.go
index 5eebed9f4..50530fa42 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -90,12 +90,12 @@ const (
// CacheConfig contains the configuration values for the trie caching/pruning
// that's resident in a blockchain.
type CacheConfig struct {
- TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory
- TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks
- TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk
- TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node)
- TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk
- ProcessStateDiffs bool // Whether statediffs processing should be taken into a account before a trie is pruned
+ TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory
+ TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks
+ TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk
+ TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node)
+ TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk
+ ProcessingStateDiffs bool // Whether statediffs processing should be taken into a account before a trie is pruned
}
// BlockChain represents the canonical chain given a database with a genesis
@@ -1025,7 +1025,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
bc.triegc.Push(root, number)
break
}
- if bc.cacheConfig.ProcessStateDiffs {
+ if bc.cacheConfig.ProcessingStateDiffs {
if !bc.allowedRootToBeDereferenced(root.(common.Hash)) {
bc.triegc.Push(root, number)
break
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 682bab8d9..4af139a85 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -1816,13 +1816,13 @@ func TestProcessingStateDiffs(t *testing.T) {
defaultTrieDirtyCache := 256
defaultTrieTimeout := 60 * time.Minute
cacheConfig := &CacheConfig{
- Disabled: false,
+ TrieDirtyDisabled: false,
TrieCleanLimit: defaultTrieCleanCache,
TrieDirtyLimit: defaultTrieDirtyCache,
TrieTimeLimit: defaultTrieTimeout,
ProcessingStateDiffs: true,
}
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := new(Genesis).MustCommit(db)
numberOfBlocks := triesInMemory
engine := ethash.NewFaker()
diff --git a/eth/backend.go b/eth/backend.go
index 130cb44ef..1b5258c3d 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -166,11 +166,11 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
EVMInterpreter: config.EVMInterpreter,
}
cacheConfig = &core.CacheConfig{
- TrieCleanLimit: config.TrieCleanCache,
- TrieCleanNoPrefetch: config.NoPrefetch,
- TrieDirtyLimit: config.TrieDirtyCache,
- TrieDirtyDisabled: config.NoPruning,
- TrieTimeLimit: config.TrieTimeout,
+ TrieCleanLimit: config.TrieCleanCache,
+ TrieCleanNoPrefetch: config.NoPrefetch,
+ TrieDirtyLimit: config.TrieDirtyCache,
+ TrieDirtyDisabled: config.NoPruning,
+ TrieTimeLimit: config.TrieTimeout,
ProcessingStateDiffs: config.StateDiff,
}
)
diff --git a/statediff/api.go b/statediff/api.go
index c4267c1f5..19ad7cfc9 100644
--- a/statediff/api.go
+++ b/statediff/api.go
@@ -25,21 +25,24 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)
+// APIName is the namespace used for the state diffing service API
const APIName = "statediff"
+
+// APIVersion is the version of the state diffing service API
const APIVersion = "0.0.1"
// PublicStateDiffAPI provides the a websocket service
// that can be used to stream out state diffs as they
// are produced by a full node
type PublicStateDiffAPI struct {
- sds SDS
+ sds IService
mu sync.Mutex
lastUsed map[string]time.Time // keeps track when a filter was polled for the last time.
}
// NewPublicStateDiffAPI create a new state diff websocket streaming service.
-func NewPublicStateDiffAPI(sds SDS) *PublicStateDiffAPI {
+func NewPublicStateDiffAPI(sds IService) *PublicStateDiffAPI {
return &PublicStateDiffAPI{
sds: sds,
lastUsed: make(map[string]time.Time),
@@ -47,8 +50,8 @@ func NewPublicStateDiffAPI(sds SDS) *PublicStateDiffAPI {
}
}
-// StreamData set up a subscription that fires off state-diffs when they are created
-func (api *PublicStateDiffAPI) StreamStateDiffs(ctx context.Context) (*rpc.Subscription, error) {
+// Subscribe is the public method to setup a subscription that fires off state-diff payloads as they are created
+func (api *PublicStateDiffAPI) Subscribe(ctx context.Context) (*rpc.Subscription, error) {
// ensure that the RPC connection supports subscriptions
notifier, supported := rpc.NotifierFromContext(ctx)
if !supported {
@@ -57,29 +60,28 @@ func (api *PublicStateDiffAPI) StreamStateDiffs(ctx context.Context) (*rpc.Subsc
// create subscription and start waiting for statediff events
rpcSub := notifier.CreateSubscription()
- id := rpcSub.ID
go func() {
// subscribe to events from the state diff service
- payloadChannel := make(chan StateDiffPayload)
+ payloadChannel := make(chan Payload)
quitChan := make(chan bool)
- api.sds.Subscribe(id, payloadChannel, quitChan)
+ api.sds.Subscribe(rpcSub.ID, payloadChannel, quitChan)
// loop and await state diff payloads and relay them to the subscriber with then notifier
for {
select {
case packet := <-payloadChannel:
- if err := notifier.Notify(id, packet); err != nil {
+ if err := notifier.Notify(rpcSub.ID, packet); err != nil {
log.Error("Failed to send state diff packet", "err", err)
}
case <-rpcSub.Err():
- err := api.sds.Unsubscribe(id)
+ err := api.sds.Unsubscribe(rpcSub.ID)
if err != nil {
log.Error("Failed to unsubscribe from the state diff service", err)
}
return
case <-notifier.Closed():
- err := api.sds.Unsubscribe(id)
+ err := api.sds.Unsubscribe(rpcSub.ID)
if err != nil {
log.Error("Failed to unsubscribe from the state diff service", err)
}
diff --git a/statediff/builder.go b/statediff/builder.go
index 0a37fafe6..4e8ab0e21 100644
--- a/statediff/builder.go
+++ b/statediff/builder.go
@@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/trie"
)
+// Builder interface exposes the method for building a state diff between two blocks
type Builder interface {
BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber int64, blockHash common.Hash) (StateDiff, error)
}
@@ -39,13 +40,15 @@ type builder struct {
blockChain *core.BlockChain
}
-func NewBuilder(db ethdb.Database, blockChain *core.BlockChain) *builder {
+// NewBuilder is used to create a builder
+func NewBuilder(db ethdb.Database, blockChain *core.BlockChain) Builder {
return &builder{
chainDB: db,
blockChain: blockChain,
}
}
+// BuildStateDiff builds a StateDiff object from two blocks
func (sdb *builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber int64, blockHash common.Hash) (StateDiff, error) {
// Generate tries for old and new states
stateCache := sdb.blockChain.StateCache()
@@ -140,7 +143,7 @@ func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (AccountsMap, error
}
// record account to diffs (creation if we are looking at new - old; deletion if old - new)
log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
- diffAccounts[leafKeyHash] = &aw
+ diffAccounts[leafKeyHash] = aw
}
cont := it.Next(true)
if !cont {
@@ -153,14 +156,13 @@ func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (AccountsMap, error
func (sdb *builder) buildDiffEventual(accounts AccountsMap) (AccountDiffsMap, error) {
accountDiffs := make(AccountDiffsMap)
- for addr, val := range accounts {
- sr := val.Account.Root
- storageDiffs, err := sdb.buildStorageDiffsEventual(sr)
+ for _, val := range accounts {
+ storageDiffs, err := sdb.buildStorageDiffsEventual(val.Account.Root)
if err != nil {
- log.Error("Failed building eventual storage diffs", "Address", addr, "error", err)
+ log.Error("Failed building eventual storage diffs", "Address", common.BytesToHash(val.RawKey), "error", err)
return nil, err
}
- accountDiffs[addr] = AccountDiff{
+ accountDiffs[common.BytesToHash(val.RawKey)] = AccountDiff{
Key: val.RawKey,
Value: val.RawValue,
Proof: val.Proof,
@@ -179,21 +181,22 @@ func (sdb *builder) buildDiffIncremental(creations AccountsMap, deletions Accoun
deletedAcc := deletions[common.HexToHash(val)]
oldSR := deletedAcc.Account.Root
newSR := createdAcc.Account.Root
- if storageDiffs, err := sdb.buildStorageDiffsIncremental(oldSR, newSR); err != nil {
+ storageDiffs, err := sdb.buildStorageDiffsIncremental(oldSR, newSR)
+ if err != nil {
log.Error("Failed building storage diffs", "Address", val, "error", err)
return nil, err
- } else {
- updatedAccounts[common.HexToHash(val)] = AccountDiff{
- Key: createdAcc.RawKey,
- Value: createdAcc.RawValue,
- Proof: createdAcc.Proof,
- Path: createdAcc.Path,
- Storage: storageDiffs,
- }
- delete(creations, common.HexToHash(val))
- delete(deletions, common.HexToHash(val))
}
+ updatedAccounts[common.HexToHash(val)] = AccountDiff{
+ Key: createdAcc.RawKey,
+ Value: createdAcc.RawValue,
+ Proof: createdAcc.Proof,
+ Path: createdAcc.Path,
+ Storage: storageDiffs,
+ }
+ delete(creations, common.HexToHash(val))
+ delete(deletions, common.HexToHash(val))
}
+
return updatedAccounts, nil
}
@@ -263,12 +266,12 @@ func buildStorageDiffsFromTrie(it trie.NodeIterator) []StorageDiff {
func (sdb *builder) addressByPath(path []byte) (*common.Address, error) {
log.Debug("Looking up address from path", "path", hexutil.Encode(append([]byte("secure-key-"), path...)))
- if addrBytes, err := sdb.chainDB.Get(append([]byte("secure-key-"), hexToKeyBytes(path)...)); err != nil {
+ addrBytes, err := sdb.chainDB.Get(append([]byte("secure-key-"), hexToKeyBytes(path)...))
+ if err != nil {
log.Error("Error looking up address via path", "path", hexutil.Encode(append([]byte("secure-key-"), path...)), "error", err)
return nil, err
- } else {
- addr := common.BytesToAddress(addrBytes)
- log.Debug("Address found", "Address", addr)
- return &addr, nil
}
+ addr := common.BytesToAddress(addrBytes)
+ log.Debug("Address found", "Address", addr)
+ return &addr, nil
}
diff --git a/statediff/builder_test.go b/statediff/builder_test.go
index d74a285dc..b4df80f81 100644
--- a/statediff/builder_test.go
+++ b/statediff/builder_test.go
@@ -18,41 +18,20 @@ package statediff_test
import (
"bytes"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/rlp"
"math/big"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/consensus/ethash"
- "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/statediff"
"github.com/ethereum/go-ethereum/statediff/testhelpers"
)
var (
- testdb = ethdb.NewMemDatabase()
-
- testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
- testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) //0x71562b71999873DB5b286dF957af199Ec94617F7
- bankLeafKey = testhelpers.AddressToLeafKey(testBankAddress)
- testBankFunds = big.NewInt(100000000)
- genesis = core.GenesisBlockForTesting(testdb, testBankAddress, testBankFunds)
-
- account1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
- account2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
- account1Addr = crypto.PubkeyToAddress(account1Key.PublicKey) //0x703c4b2bD70c169f5717101CaeE543299Fc946C7
- account1LeafKey = testhelpers.AddressToLeafKey(account1Addr)
- account2Addr = crypto.PubkeyToAddress(account2Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
- account2LeafKey = testhelpers.AddressToLeafKey(account2Addr)
- contractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50602060405190810160405280600160ff16815250600090600161003592919061003b565b506100a5565b826064810192821561006f579160200282015b8281111561006e578251829060ff1690559160200191906001019061004e565b5b50905061007c9190610080565b5090565b6100a291905b8082111561009e576000816000905550600101610086565b5090565b90565b610124806100b46000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146054578063c16431b9146093575b600080fd5b607d60048036036020811015606857600080fd5b810190808035906020019092919050505060c8565b6040518082815260200191505060405180910390f35b60c66004803603604081101560a757600080fd5b81019080803590602001909291908035906020019092919050505060e0565b005b6000808260648110151560d757fe5b01549050919050565b8060008360648110151560ef57fe5b0181905550505056fea165627a7a7230582064e918c3140a117bf3aa65865a9b9e83fae21ad1720506e7933b2a9f54bb40260029")
- contractAddr common.Address
contractLeafKey common.Hash
emptyAccountDiffEventualMap = make(statediff.AccountDiffsMap)
emptyAccountDiffIncrementalMap = make(statediff.AccountDiffsMap)
@@ -65,19 +44,19 @@ var (
)
func TestBuilder(t *testing.T) {
- _, blockMap, chain := makeChain(3, genesis)
- contractLeafKey = testhelpers.AddressToLeafKey(contractAddr)
+ _, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
+ contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr)
defer chain.Stop()
block0Hash = common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661")
block1Hash = common.HexToHash("0xbbe88de60ba33a3f18c0caa37d827bfb70252e19e40a07cd34041696c35ecb1a")
- block2Hash = common.HexToHash("0xde75663f36a8497b4bdda2a4b52bd9540b705a2728c7391c59b8cb2cde5a2feb")
- block3Hash = common.HexToHash("0x76c6d0e39285cee40d5e5fadc6141ca88c8ab8bd1a15d46717205af2efbb4a3c")
+ block2Hash = common.HexToHash("0x34ad0fd9bb2911986b75d518c822641079dea823bc6952343ebf05da1062b6f5")
+ block3Hash = common.HexToHash("0x9872058136c560a6ebed0c0522b8d3016fc21f4fb0fb6585ddd8fd4c54f9909a")
block0 = blockMap[block0Hash]
block1 = blockMap[block1Hash]
block2 = blockMap[block2Hash]
block3 = blockMap[block3Hash]
- builder = statediff.NewBuilder(testdb, chain)
+ builder = statediff.NewBuilder(testhelpers.Testdb, chain)
type arguments struct {
oldStateRoot common.Hash
@@ -119,7 +98,7 @@ func TestBuilder(t *testing.T) {
})
bankAccount1, _ = rlp.EncodeToBytes(state.Account{
Nonce: nonce1,
- Balance: big.NewInt(testBankFunds.Int64() - balanceChange10000),
+ Balance: big.NewInt(testhelpers.TestBankFunds.Int64() - balanceChange10000),
CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Root: common.HexToHash(originalContractRoot),
})
@@ -207,8 +186,8 @@ func TestBuilder(t *testing.T) {
BlockNumber: block1.Number().Int64(),
BlockHash: block1.Hash(),
CreatedAccounts: statediff.AccountDiffsMap{
- account1LeafKey: {
- Key: account1LeafKey.Bytes(),
+ testhelpers.Account1LeafKey: {
+ Key: testhelpers.Account1LeafKey.Bytes(),
Value: account1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
{248, 107, 160, 57, 38, 219, 105, 170, 206, 213, 24, 233, 185, 240, 244, 52, 164, 115, 231, 23, 65, 9, 201, 67, 84, 139, 184, 242, 59, 228, 28, 167, 109, 154, 210, 184, 72, 248, 70, 128, 130, 39, 16, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
@@ -226,8 +205,8 @@ func TestBuilder(t *testing.T) {
},
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: statediff.AccountDiffsMap{
- bankLeafKey: {
- Key: bankLeafKey.Bytes(),
+ testhelpers.BankLeafKey: {
+ Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount1,
Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
{248, 109, 160, 48, 191, 73, 244, 64, 161, 205, 5, 39, 228, 208, 110, 39, 101, 101, 76, 15, 86, 69, 34, 87, 81, 109, 121, 58, 155, 141, 96, 77, 207, 223, 42, 184, 74, 248, 72, 1, 132, 5, 245, 185, 240, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
@@ -251,8 +230,8 @@ func TestBuilder(t *testing.T) {
BlockNumber: block2.Number().Int64(),
BlockHash: block2.Hash(),
CreatedAccounts: statediff.AccountDiffsMap{
- account2LeafKey: {
- Key: account2LeafKey.Bytes(),
+ testhelpers.Account2LeafKey: {
+ Key: testhelpers.Account2LeafKey.Bytes(),
Value: account2,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 107, 160, 57, 87, 243, 226, 240, 74, 7, 100, 195, 160, 73, 27, 23, 95, 105, 146, 109, 166, 30, 251, 204, 143, 97, 250, 20, 85, 253, 45, 43, 76, 221, 69, 184, 72, 248, 70, 128, 130, 3, 232, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
@@ -277,16 +256,16 @@ func TestBuilder(t *testing.T) {
},
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: statediff.AccountDiffsMap{
- bankLeafKey: {
- Key: bankLeafKey.Bytes(),
+ testhelpers.BankLeafKey: {
+ Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount2,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 109, 160, 48, 191, 73, 244, 64, 161, 205, 5, 39, 228, 208, 110, 39, 101, 101, 76, 15, 86, 69, 34, 87, 81, 109, 121, 58, 155, 141, 96, 77, 207, 223, 42, 184, 74, 248, 72, 2, 132, 5, 245, 182, 8, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
Path: []byte{0, 0, 11, 15, 4, 9, 15, 4, 4, 0, 10, 1, 12, 13, 0, 5, 2, 7, 14, 4, 13, 0, 6, 14, 2, 7, 6, 5, 6, 5, 4, 12, 0, 15, 5, 6, 4, 5, 2, 2, 5, 7, 5, 1, 6, 13, 7, 9, 3, 10, 9, 11, 8, 13, 6, 0, 4, 13, 12, 15, 13, 15, 2, 10, 16},
Storage: []statediff.StorageDiff{},
},
- account1LeafKey: {
- Key: account1LeafKey.Bytes(),
+ testhelpers.Account1LeafKey: {
+ Key: testhelpers.Account1LeafKey.Bytes(),
Value: account3,
Proof: [][]byte{{248, 177, 160, 177, 155, 238, 178, 242, 47, 83, 2, 49, 141, 155, 92, 149, 175, 245, 120, 233, 177, 101, 67, 46, 200, 23, 250, 41, 74, 135, 94, 61, 133, 51, 162, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 114, 57, 32, 11, 115, 232, 140, 238, 165, 222, 121, 226, 208, 2, 192, 216, 67, 198, 179, 31, 181, 27, 208, 243, 99, 202, 48, 148, 207, 107, 106, 177, 128, 128, 128, 128, 128, 160, 10, 173, 165, 125, 110, 240, 77, 112, 149, 100, 135, 237, 25, 228, 116, 7, 195, 9, 210, 166, 208, 148, 101, 23, 244, 238, 84, 84, 211, 249, 138, 137, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 107, 160, 57, 38, 219, 105, 170, 206, 213, 24, 233, 185, 240, 244, 52, 164, 115, 231, 23, 65, 9, 201, 67, 84, 139, 184, 242, 59, 228, 28, 167, 109, 154, 210, 184, 72, 248, 70, 2, 130, 39, 16, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
@@ -320,8 +299,8 @@ func TestBuilder(t *testing.T) {
CreatedAccounts: statediff.AccountDiffsMap{},
DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: statediff.AccountDiffsMap{
- account2LeafKey: {
- Key: account2LeafKey.Bytes(),
+ testhelpers.Account2LeafKey: {
+ Key: testhelpers.Account2LeafKey.Bytes(),
Value: account4,
Proof: [][]byte{{248, 177, 160, 101, 223, 138, 81, 34, 40, 229, 170, 198, 188, 136, 99, 7, 55, 33, 112, 160, 111, 181, 131, 167, 201, 131, 24, 201, 211, 177, 30, 159, 229, 246, 6, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 32, 135, 108, 213, 150, 150, 110, 44, 170, 65, 75, 154, 74, 249, 94, 65, 74, 107, 100, 115, 39, 5, 3, 26, 22, 238, 138, 114, 254, 21, 6, 171, 128, 128, 128, 128, 128, 160, 4, 228, 121, 222, 255, 218, 60, 247, 15, 0, 34, 198, 28, 229, 180, 129, 109, 157, 68, 181, 248, 229, 200, 123, 29, 81, 145, 114, 90, 209, 205, 210, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 113, 160, 57, 87, 243, 226, 240, 74, 7, 100, 195, 160, 73, 27, 23, 95, 105, 146, 109, 166, 30, 251, 204, 143, 97, 250, 20, 85, 253, 45, 43, 76, 221, 69, 184, 78, 248, 76, 128, 136, 27, 193, 109, 103, 78, 200, 3, 232, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
@@ -344,8 +323,8 @@ func TestBuilder(t *testing.T) {
},
},
},
- bankLeafKey: {
- Key: bankLeafKey.Bytes(),
+ testhelpers.BankLeafKey: {
+ Key: testhelpers.BankLeafKey.Bytes(),
Value: bankAccount3,
Proof: [][]byte{{248, 177, 160, 101, 223, 138, 81, 34, 40, 229, 170, 198, 188, 136, 99, 7, 55, 33, 112, 160, 111, 181, 131, 167, 201, 131, 24, 201, 211, 177, 30, 159, 229, 246, 6, 128, 128, 128, 128, 160, 179, 86, 53, 29, 96, 188, 152, 148, 207, 31, 29, 108, 182, 140, 129, 95, 1, 49, 213, 15, 29, 168, 60, 64, 35, 160, 158, 200, 85, 207, 255, 145, 160, 32, 135, 108, 213, 150, 150, 110, 44, 170, 65, 75, 154, 74, 249, 94, 65, 74, 107, 100, 115, 39, 5, 3, 26, 22, 238, 138, 114, 254, 21, 6, 171, 128, 128, 128, 128, 128, 160, 4, 228, 121, 222, 255, 218, 60, 247, 15, 0, 34, 198, 28, 229, 180, 129, 109, 157, 68, 181, 248, 229, 200, 123, 29, 81, 145, 114, 90, 209, 205, 210, 128, 160, 255, 115, 147, 190, 57, 135, 174, 188, 86, 51, 227, 70, 22, 253, 237, 49, 24, 19, 149, 199, 142, 195, 186, 244, 70, 51, 138, 0, 146, 148, 117, 60, 128, 128},
{248, 109, 160, 48, 191, 73, 244, 64, 161, 205, 5, 39, 228, 208, 110, 39, 101, 101, 76, 15, 86, 69, 34, 87, 81, 109, 121, 58, 155, 141, 96, 77, 207, 223, 42, 184, 74, 248, 72, 3, 132, 5, 245, 182, 8, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
@@ -393,60 +372,6 @@ func equals(actual, expected interface{}) (success bool) {
return reflect.DeepEqual(actual, expected)
}
-// makeChain creates a chain of n blocks starting at and including parent.
-// the returned hash chain is ordered head->parent. In addition, every 3rd block
-// contains a transaction and every 5th an uncle to allow testing correct block
-// reassembly.
-func makeChain(n int, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block, *core.BlockChain) {
- blocks, _ := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testdb, n, testChainGen)
- headers := make([]*types.Header, len(blocks))
- for i, block := range blocks {
- headers[i] = block.Header()
- }
- chain, _ := core.NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
-
- hashes := make([]common.Hash, n+1)
- hashes[len(hashes)-1] = parent.Hash()
- blockm := make(map[common.Hash]*types.Block, n+1)
- blockm[parent.Hash()] = parent
- for i, b := range blocks {
- hashes[len(hashes)-i-2] = b.Hash()
- blockm[b.Hash()] = b
- }
- return hashes, blockm, chain
-}
-
-func testChainGen(i int, block *core.BlockGen) {
- signer := types.HomesteadSigner{}
- switch i {
- case 0:
- // In block 1, the test bank sends account #1 some ether.
- tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), account1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
- block.AddTx(tx)
- case 1:
- // In block 2, the test bank sends some more ether to account #1.
- // account1Addr passes it on to account #2.
- // account1Addr creates a test contract.
- tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), account1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
- nonce := block.TxNonce(account1Addr)
- tx2, _ := types.SignTx(types.NewTransaction(nonce, account2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, account1Key)
- nonce++
- tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), contractCode), signer, account1Key)
- contractAddr = crypto.CreateAddress(account1Addr, nonce) //0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592
- block.AddTx(tx1)
- block.AddTx(tx2)
- block.AddTx(tx3)
- case 2:
- // Block 3 is empty but was mined by account #2.
- block.SetCoinbase(account2Addr)
- //get function: 60cd2685
- //put function: c16431b9
- data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003")
- tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), contractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey)
- block.AddTx(tx)
- }
-}
-
/*
contract test {
diff --git a/statediff/helpers.go b/statediff/helpers.go
index e1a989144..96f9ddf30 100644
--- a/statediff/helpers.go
+++ b/statediff/helpers.go
@@ -37,6 +37,22 @@ func sortKeys(data AccountsMap) []string {
return keys
}
+// BytesToNiblePath
+func bytesToNiblePath(path []byte) string {
+ if hasTerm(path) {
+ path = path[:len(path)-1]
+ }
+ nibblePath := ""
+ for i, v := range common.ToHex(path) {
+ if i%2 == 0 && i > 1 {
+ continue
+ }
+ nibblePath = nibblePath + string(v)
+ }
+
+ return nibblePath
+}
+
func findIntersection(a, b []string) []string {
lenA := len(a)
lenB := len(b)
@@ -73,22 +89,7 @@ func findIntersection(a, b []string) []string {
}
func pathToStr(it trie.NodeIterator) string {
- return BytesToNiblePath(it.Path())
-}
-
-func BytesToNiblePath(path []byte) string {
- if hasTerm(path) {
- path = path[:len(path)-1]
- }
- nibblePath := ""
- for i, v := range common.ToHex(path) {
- if i%2 == 0 && i > 1 {
- continue
- }
- nibblePath = nibblePath + string(v)
- }
-
- return nibblePath
+ return bytesToNiblePath(it.Path())
}
// Duplicated from trie/encoding.go
diff --git a/statediff/service.go b/statediff/service.go
index 0609861d5..314a8ab12 100644
--- a/statediff/service.go
+++ b/statediff/service.go
@@ -19,9 +19,11 @@ package statediff
import (
"bytes"
"fmt"
- "github.com/ethereum/go-ethereum/node"
"sync"
+ "github.com/ethereum/go-ethereum/node"
+ "github.com/ethereum/go-ethereum/rlp"
+
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
@@ -32,60 +34,69 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)
-type BlockChain interface {
+type blockChain interface {
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
GetBlockByHash(hash common.Hash) *types.Block
AddToStateDiffProcessedCollection(hash common.Hash)
}
-type SDS interface {
+// IService is the state-diffing service interface
+type IService interface {
// APIs(), Protocols(), Start() and Stop()
node.Service
// Main event loop for processing state diffs
Loop(chainEventCh chan core.ChainEvent)
// Method to subscribe to receive state diff processing output
- Subscribe(id rpc.ID, sub chan<- StateDiffPayload, quitChan chan<- bool)
+ Subscribe(id rpc.ID, sub chan<- Payload, quitChan chan<- bool)
// Method to unsubscribe from state diff processing
Unsubscribe(id rpc.ID) error
}
-type StateDiffingService struct {
+// Service is the underlying struct for the state diffing service
+type Service struct {
+ // Used to sync access to the Subscriptions
sync.Mutex
- Builder Builder
- BlockChain BlockChain
- QuitChan chan bool
- Subscriptions Subscriptions
+ // Used to build the state diff objects
+ Builder Builder
+ // Used to subscribe to chain events (blocks)
+ BlockChain blockChain
+ // Used to signal shutdown of the service
+ QuitChan chan bool
+ // A mapping of rpc.IDs to their subscription channels
+ Subscriptions map[rpc.ID]Subscription
}
-type Subscriptions map[rpc.ID]Subscription
-
+// Subscription struct holds our subscription channels
type Subscription struct {
- PayloadChan chan<- StateDiffPayload
+ PayloadChan chan<- Payload
QuitChan chan<- bool
}
-type StateDiffPayload struct {
- BlockRlp []byte `json:"block"`
- StateDiff StateDiff `json:"state_diff"`
- Err error `json:"error"`
+// Payload packages the data to send to StateDiffingService subscriptions
+type Payload struct {
+ BlockRlp []byte `json:"blockRlp" gencodec:"required"`
+ StateDiffRlp []byte `json:"stateDiffRlp" gencodec:"required"`
+ Err error `json:"error"`
}
-func NewStateDiffService(db ethdb.Database, blockChain *core.BlockChain) (*StateDiffingService, error) {
- return &StateDiffingService{
+// NewStateDiffService creates a new StateDiffingService
+func NewStateDiffService(db ethdb.Database, blockChain *core.BlockChain) (*Service, error) {
+ return &Service{
Mutex: sync.Mutex{},
BlockChain: blockChain,
Builder: NewBuilder(db, blockChain),
QuitChan: make(chan bool),
- Subscriptions: make(Subscriptions),
+ Subscriptions: make(map[rpc.ID]Subscription),
}, nil
}
-func (sds *StateDiffingService) Protocols() []p2p.Protocol {
+// Protocols exports the services p2p protocols, this service has none
+func (sds *Service) Protocols() []p2p.Protocol {
return []p2p.Protocol{}
}
-// APIs returns the RPC descriptors the Whisper implementation offers
-func (sds *StateDiffingService) APIs() []rpc.API {
+// APIs returns the RPC descriptors the StateDiffingService offers
+func (sds *Service) APIs() []rpc.API {
return []rpc.API{
{
Namespace: APIName,
@@ -96,7 +107,9 @@ func (sds *StateDiffingService) APIs() []rpc.API {
}
}
-func (sds *StateDiffingService) Loop(chainEventCh chan core.ChainEvent) {
+// Loop is the main processing method
+func (sds *Service) Loop(chainEventCh chan core.ChainEvent) {
+
chainEventSub := sds.BlockChain.SubscribeChainEvent(chainEventCh)
defer chainEventSub.Unsubscribe()
@@ -144,10 +157,11 @@ HandleBlockChLoop:
rlpBuff := new(bytes.Buffer)
currentBlock.EncodeRLP(rlpBuff)
blockRlp := rlpBuff.Bytes()
- payload := StateDiffPayload{
- BlockRlp: blockRlp,
- StateDiff: stateDiff,
- Err: err,
+ stateDiffRlp, _ := rlp.EncodeToBytes(stateDiff)
+ payload := Payload{
+ BlockRlp: blockRlp,
+ StateDiffRlp: stateDiffRlp,
+ Err: err,
}
// If we have any websocket subscription listening in, send the data to them
sds.send(payload)
@@ -159,7 +173,8 @@ HandleBlockChLoop:
}
}
-func (sds *StateDiffingService) Subscribe(id rpc.ID, sub chan<- StateDiffPayload, quitChan chan<- bool) {
+// Subscribe is used by the API to subscribe to the StateDiffingService loop
+func (sds *Service) Subscribe(id rpc.ID, sub chan<- Payload, quitChan chan<- bool) {
log.Info("Subscribing to the statediff service")
sds.Lock()
sds.Subscriptions[id] = Subscription{
@@ -169,7 +184,8 @@ func (sds *StateDiffingService) Subscribe(id rpc.ID, sub chan<- StateDiffPayload
sds.Unlock()
}
-func (sds *StateDiffingService) Unsubscribe(id rpc.ID) error {
+// Unsubscribe is used to unsubscribe to the StateDiffingService loop
+func (sds *Service) Unsubscribe(id rpc.ID) error {
log.Info("Unsubscribing from the statediff service")
sds.Lock()
_, ok := sds.Subscriptions[id]
@@ -181,7 +197,25 @@ func (sds *StateDiffingService) Unsubscribe(id rpc.ID) error {
return nil
}
-func (sds *StateDiffingService) send(payload StateDiffPayload) {
+// Start is used to begin the StateDiffingService
+func (sds *Service) Start(*p2p.Server) error {
+ log.Info("Starting statediff service")
+
+ chainEventCh := make(chan core.ChainEvent, 10)
+ go sds.Loop(chainEventCh)
+
+ return nil
+}
+
+// Stop is used to close down the StateDiffingService
+func (sds *Service) Stop() error {
+ log.Info("Stopping statediff service")
+ close(sds.QuitChan)
+ return nil
+}
+
+// send is used to fan out and serve a payload to any subscriptions
+func (sds *Service) send(payload Payload) {
sds.Lock()
for id, sub := range sds.Subscriptions {
select {
@@ -194,7 +228,8 @@ func (sds *StateDiffingService) send(payload StateDiffPayload) {
sds.Unlock()
}
-func (sds *StateDiffingService) close() {
+// close is used to close all listening subscriptions
+func (sds *Service) close() {
sds.Lock()
for id, sub := range sds.Subscriptions {
select {
@@ -207,18 +242,3 @@ func (sds *StateDiffingService) close() {
}
sds.Unlock()
}
-
-func (sds *StateDiffingService) Start(server *p2p.Server) error {
- log.Info("Starting statediff service")
-
- chainEventCh := make(chan core.ChainEvent, 10)
- go sds.Loop(chainEventCh)
-
- return nil
-}
-
-func (sds *StateDiffingService) Stop() error {
- log.Info("Stopping statediff service")
- close(sds.QuitChan)
- return nil
-}
diff --git a/statediff/service_test.go b/statediff/service_test.go
index 2221e2e66..79e2f4dbc 100644
--- a/statediff/service_test.go
+++ b/statediff/service_test.go
@@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/statediff"
"github.com/ethereum/go-ethereum/statediff/testhelpers/mocks"
)
@@ -69,11 +70,11 @@ func testErrorInChainEventLoop(t *testing.T) {
//the first chain event causes and error (in blockchain mock)
builder := mocks.Builder{}
blockChain := mocks.BlockChain{}
- service := statediff.StateDiffingService{
+ service := statediff.Service{
Builder: &builder,
BlockChain: &blockChain,
QuitChan: make(chan bool),
- Subscriptions: make(statediff.Subscriptions),
+ Subscriptions: make(map[rpc.ID]statediff.Subscription),
}
testRoot2 = common.HexToHash("0xTestRoot2")
blockChain.SetParentBlocksToReturn([]*types.Block{parentBlock1, parentBlock2})
@@ -103,11 +104,11 @@ func testErrorInBlockLoop(t *testing.T) {
//second block's parent block can't be found
builder := mocks.Builder{}
blockChain := mocks.BlockChain{}
- service := statediff.StateDiffingService{
+ service := statediff.Service{
Builder: &builder,
BlockChain: &blockChain,
QuitChan: make(chan bool),
- Subscriptions: make(statediff.Subscriptions),
+ Subscriptions: make(map[rpc.ID]statediff.Subscription),
}
blockChain.SetParentBlocksToReturn([]*types.Block{parentBlock1, nil})
diff --git a/statediff/testhelpers/helpers.go b/statediff/testhelpers/helpers.go
index 86b851f89..5126c6556 100644
--- a/statediff/testhelpers/helpers.go
+++ b/statediff/testhelpers/helpers.go
@@ -16,5 +16,68 @@
package testhelpers
-var ErrorFormatString = "Error: %s, %+v"
-var TestFailureFormatString = "Test failed: %s\nexpected %+v, got %+v\n"
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus/ethash"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+// MakeChain creates a chain of n blocks starting at and including parent.
+// the returned hash chain is ordered head->parent. In addition, every 3rd block
+// contains a transaction and every 5th an uncle to allow testing correct block
+// reassembly.
+func MakeChain(n int, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block, *core.BlockChain) {
+ blocks, _ := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), Testdb, n, testChainGen)
+ headers := make([]*types.Header, len(blocks))
+ for i, block := range blocks {
+ headers[i] = block.Header()
+ }
+ chain, _ := core.NewBlockChain(Testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
+
+ hashes := make([]common.Hash, n+1)
+ hashes[len(hashes)-1] = parent.Hash()
+ blockm := make(map[common.Hash]*types.Block, n+1)
+ blockm[parent.Hash()] = parent
+ for i, b := range blocks {
+ hashes[len(hashes)-i-2] = b.Hash()
+ blockm[b.Hash()] = b
+ }
+ return hashes, blockm, chain
+}
+
+func testChainGen(i int, block *core.BlockGen) {
+ signer := types.HomesteadSigner{}
+ switch i {
+ case 0:
+ // In block 1, the test bank sends account #1 some ether.
+ tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), Account1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, TestBankKey)
+ block.AddTx(tx)
+ case 1:
+ // In block 2, the test bank sends some more ether to account #1.
+ // account1Addr passes it on to account #2.
+ // account1Addr creates a test contract.
+ tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), Account1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, TestBankKey)
+ nonce := block.TxNonce(Account1Addr)
+ tx2, _ := types.SignTx(types.NewTransaction(nonce, Account2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, Account1Key)
+ nonce++
+ tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), ContractCode), signer, Account1Key)
+ ContractAddr = crypto.CreateAddress(Account1Addr, nonce) //0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592
+ block.AddTx(tx1)
+ block.AddTx(tx2)
+ block.AddTx(tx3)
+ case 2:
+ // Block 3 is empty but was mined by account #2.
+ block.SetCoinbase(Account2Addr)
+ //get function: 60cd2685
+ //put function: c16431b9
+ data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003")
+ tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), ContractAddr, big.NewInt(0), 100000, nil, data), signer, TestBankKey)
+ block.AddTx(tx)
+ }
+}
diff --git a/statediff/testhelpers/mocks/blockchain.go b/statediff/testhelpers/mocks/blockchain.go
index ed16c3471..cececde6f 100644
--- a/statediff/testhelpers/mocks/blockchain.go
+++ b/statediff/testhelpers/mocks/blockchain.go
@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/event"
)
+// BlockChain is a mock blockchain for testing
type BlockChain struct {
ParentHashesLookedUp []common.Hash
parentBlocksToReturn []*types.Block
@@ -34,34 +35,39 @@ type BlockChain struct {
ChainEvents []core.ChainEvent
}
-func (mc *BlockChain) AddToStateDiffProcessedCollection(hash common.Hash) {}
+// AddToStateDiffProcessedCollection mock method
+func (blockChain *BlockChain) AddToStateDiffProcessedCollection(hash common.Hash) {}
-func (mc *BlockChain) SetParentBlocksToReturn(blocks []*types.Block) {
- mc.parentBlocksToReturn = blocks
+// SetParentBlocksToReturn mock method
+func (blockChain *BlockChain) SetParentBlocksToReturn(blocks []*types.Block) {
+ blockChain.parentBlocksToReturn = blocks
}
-func (mc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {
- mc.ParentHashesLookedUp = append(mc.ParentHashesLookedUp, hash)
+// GetBlockByHash mock method
+func (blockChain *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {
+ blockChain.ParentHashesLookedUp = append(blockChain.ParentHashesLookedUp, hash)
var parentBlock *types.Block
- if len(mc.parentBlocksToReturn) > 0 {
- parentBlock = mc.parentBlocksToReturn[mc.callCount]
+ if len(blockChain.parentBlocksToReturn) > 0 {
+ parentBlock = blockChain.parentBlocksToReturn[blockChain.callCount]
}
- mc.callCount++
+ blockChain.callCount++
return parentBlock
}
-func (bc *BlockChain) SetChainEvents(chainEvents []core.ChainEvent) {
- bc.ChainEvents = chainEvents
+// SetChainEvents mock method
+func (blockChain *BlockChain) SetChainEvents(chainEvents []core.ChainEvent) {
+ blockChain.ChainEvents = chainEvents
}
-func (bc *BlockChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
+// SubscribeChainEvent mock method
+func (blockChain *BlockChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
subErr := errors.New("Subscription Error")
var eventCounter int
subscription := event.NewSubscription(func(quit <-chan struct{}) error {
- for _, chainEvent := range bc.ChainEvents {
+ for _, chainEvent := range blockChain.ChainEvents {
if eventCounter > 1 {
time.Sleep(250 * time.Millisecond)
return subErr
diff --git a/statediff/testhelpers/mocks/builder.go b/statediff/testhelpers/mocks/builder.go
index d3252fe4b..e9668629e 100644
--- a/statediff/testhelpers/mocks/builder.go
+++ b/statediff/testhelpers/mocks/builder.go
@@ -21,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/statediff"
)
+// Builder is a mock state diff builder
type Builder struct {
OldStateRoot common.Hash
NewStateRoot common.Hash
@@ -30,6 +31,7 @@ type Builder struct {
builderError error
}
+// BuildStateDiff mock method
func (builder *Builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber int64, blockHash common.Hash) (statediff.StateDiff, error) {
builder.OldStateRoot = oldStateRoot
builder.NewStateRoot = newStateRoot
@@ -39,10 +41,12 @@ func (builder *Builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, b
return builder.stateDiff, builder.builderError
}
+// SetStateDiffToBuild mock method
func (builder *Builder) SetStateDiffToBuild(stateDiff statediff.StateDiff) {
builder.stateDiff = stateDiff
}
+// SetBuilderError mock method
func (builder *Builder) SetBuilderError(err error) {
builder.builderError = err
}
diff --git a/statediff/testhelpers/mocks/error.go b/statediff/testhelpers/mocks/error.go
deleted file mode 100644
index dafb0371e..000000000
--- a/statediff/testhelpers/mocks/error.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package mocks
-
-import "errors"
-
-var Error = errors.New("mock error")
diff --git a/statediff/testhelpers/mocks/publisher.go b/statediff/testhelpers/mocks/publisher.go
index 01f4c5997..3ea18abf0 100644
--- a/statediff/testhelpers/mocks/publisher.go
+++ b/statediff/testhelpers/mocks/publisher.go
@@ -18,16 +18,19 @@ package mocks
import "github.com/ethereum/go-ethereum/statediff"
+// Publisher mock
type Publisher struct {
StateDiff *statediff.StateDiff
publisherError error
}
+// PublishStateDiff mock method
func (publisher *Publisher) PublishStateDiff(sd *statediff.StateDiff) (string, error) {
publisher.StateDiff = sd
return "", publisher.publisherError
}
+// SetPublisherError mock method
func (publisher *Publisher) SetPublisherError(err error) {
publisher.publisherError = err
}
diff --git a/statediff/testhelpers/mocks/service.go b/statediff/testhelpers/mocks/service.go
index d948091a1..5882f7e9b 100644
--- a/statediff/testhelpers/mocks/service.go
+++ b/statediff/testhelpers/mocks/service.go
@@ -26,26 +26,29 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/statediff"
)
+// MockStateDiffService is a mock state diff service
type MockStateDiffService struct {
sync.Mutex
- Builder statediff.Builder
- ReturnProtocol []p2p.Protocol
- ReturnAPIs []rpc.API
- MockBlockChan chan *types.Block
- MockParentBlockChan chan *types.Block
- QuitChan chan bool
- Subscriptions statediff.Subscriptions
+ Builder statediff.Builder
+ ReturnProtocol []p2p.Protocol
+ ReturnAPIs []rpc.API
+ BlockChan chan *types.Block
+ ParentBlockChan chan *types.Block
+ QuitChan chan bool
+ Subscriptions map[rpc.ID]statediff.Subscription
}
+// Protocols mock method
func (sds *MockStateDiffService) Protocols() []p2p.Protocol {
return []p2p.Protocol{}
}
-// APIs returns the RPC descriptors the Whisper implementation offers
+// APIs mock method
func (sds *MockStateDiffService) APIs() []rpc.API {
return []rpc.API{
{
@@ -57,14 +60,15 @@ func (sds *MockStateDiffService) APIs() []rpc.API {
}
}
+// Loop mock method
func (sds *MockStateDiffService) Loop(chan core.ChainEvent) {
//loop through chain events until no more
HandleBlockChLoop:
for {
select {
- case block := <-sds.MockBlockChan:
+ case block := <-sds.BlockChan:
currentBlock := block
- parentBlock := <-sds.MockParentBlockChan
+ parentBlock := <-sds.ParentBlockChan
parentHash := parentBlock.Hash()
if parentBlock == nil {
log.Error("Parent block is nil, skipping this block",
@@ -80,10 +84,11 @@ HandleBlockChLoop:
rlpBuff := new(bytes.Buffer)
currentBlock.EncodeRLP(rlpBuff)
blockRlp := rlpBuff.Bytes()
- payload := statediff.StateDiffPayload{
- BlockRlp: blockRlp,
- StateDiff: stateDiff,
- Err: err,
+ stateDiffRlp, _ := rlp.EncodeToBytes(stateDiff)
+ payload := statediff.Payload{
+ BlockRlp: blockRlp,
+ StateDiffRlp: stateDiffRlp,
+ Err: err,
}
// If we have any websocket subscription listening in, send the data to them
sds.send(payload)
@@ -95,7 +100,8 @@ HandleBlockChLoop:
}
}
-func (sds *MockStateDiffService) Subscribe(id rpc.ID, sub chan<- statediff.StateDiffPayload, quitChan chan<- bool) {
+// Subscribe mock method
+func (sds *MockStateDiffService) Subscribe(id rpc.ID, sub chan<- statediff.Payload, quitChan chan<- bool) {
log.Info("Subscribing to the statediff service")
sds.Lock()
sds.Subscriptions[id] = statediff.Subscription{
@@ -105,6 +111,7 @@ func (sds *MockStateDiffService) Subscribe(id rpc.ID, sub chan<- statediff.State
sds.Unlock()
}
+// Unsubscribe mock method
func (sds *MockStateDiffService) Unsubscribe(id rpc.ID) error {
log.Info("Unsubscribing from the statediff service")
sds.Lock()
@@ -117,7 +124,7 @@ func (sds *MockStateDiffService) Unsubscribe(id rpc.ID) error {
return nil
}
-func (sds *MockStateDiffService) send(payload statediff.StateDiffPayload) {
+func (sds *MockStateDiffService) send(payload statediff.Payload) {
sds.Lock()
for id, sub := range sds.Subscriptions {
select {
@@ -144,9 +151,10 @@ func (sds *MockStateDiffService) close() {
sds.Unlock()
}
+// Start mock method
func (sds *MockStateDiffService) Start(server *p2p.Server) error {
log.Info("Starting statediff service")
- if sds.MockParentBlockChan == nil || sds.MockBlockChan == nil {
+ if sds.ParentBlockChan == nil || sds.BlockChan == nil {
return errors.New("mock StateDiffingService requires preconfiguration with a MockParentBlockChan and MockBlockChan")
}
chainEventCh := make(chan core.ChainEvent, 10)
@@ -155,6 +163,7 @@ func (sds *MockStateDiffService) Start(server *p2p.Server) error {
return nil
}
+// Stop mock method
func (sds *MockStateDiffService) Stop() error {
log.Info("Stopping statediff service")
close(sds.QuitChan)
diff --git a/statediff/testhelpers/mocks/service_test.go b/statediff/testhelpers/mocks/service_test.go
new file mode 100644
index 000000000..f310eb063
--- /dev/null
+++ b/statediff/testhelpers/mocks/service_test.go
@@ -0,0 +1,127 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package mocks
+
+import (
+ "bytes"
+ "math/big"
+ "sync"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/go-ethereum/statediff"
+ "github.com/ethereum/go-ethereum/statediff/testhelpers"
+)
+
+var block0, block1 *types.Block
+var burnLeafKey = testhelpers.AddressToLeafKey(common.HexToAddress("0x0"))
+var emptyAccountDiffEventualMap = make(statediff.AccountDiffsMap)
+var account1, _ = rlp.EncodeToBytes(state.Account{
+ Nonce: uint64(0),
+ Balance: big.NewInt(10000),
+ CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
+ Root: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
+})
+var burnAccount1, _ = rlp.EncodeToBytes(state.Account{
+ Nonce: uint64(0),
+ Balance: big.NewInt(2000000000000000000),
+ CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
+ Root: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
+})
+var bankAccount1, _ = rlp.EncodeToBytes(state.Account{
+ Nonce: uint64(1),
+ Balance: big.NewInt(testhelpers.TestBankFunds.Int64() - 10000),
+ CodeHash: common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
+ Root: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
+})
+
+func TestAPI(t *testing.T) {
+ _, blockMap, chain := testhelpers.MakeChain(3, testhelpers.Genesis)
+ defer chain.Stop()
+ block0Hash := common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661")
+ block1Hash := common.HexToHash("0xbbe88de60ba33a3f18c0caa37d827bfb70252e19e40a07cd34041696c35ecb1a")
+ block0 = blockMap[block0Hash]
+ block1 = blockMap[block1Hash]
+ blockChan := make(chan *types.Block)
+ parentBlockChain := make(chan *types.Block)
+ serviceQuitChan := make(chan bool)
+ mockService := MockStateDiffService{
+ Mutex: sync.Mutex{},
+ Builder: statediff.NewBuilder(testhelpers.Testdb, chain),
+ BlockChan: blockChan,
+ ParentBlockChan: parentBlockChain,
+ QuitChan: serviceQuitChan,
+ Subscriptions: make(map[rpc.ID]statediff.Subscription),
+ }
+ mockService.Start(nil)
+ id := rpc.NewID()
+ payloadChan := make(chan statediff.Payload)
+ quitChan := make(chan bool)
+ mockService.Subscribe(id, payloadChan, quitChan)
+ blockChan <- block1
+ parentBlockChain <- block0
+ expectedBlockRlp, _ := rlp.EncodeToBytes(block1)
+ expectedStateDiff := &statediff.StateDiff{
+ BlockNumber: block1.Number().Int64(),
+ BlockHash: block1.Hash(),
+ CreatedAccounts: statediff.AccountDiffsMap{
+ testhelpers.Account1LeafKey: {
+ Key: testhelpers.Account1LeafKey.Bytes(),
+ Value: account1,
+ Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
+ {248, 107, 160, 57, 38, 219, 105, 170, 206, 213, 24, 233, 185, 240, 244, 52, 164, 115, 231, 23, 65, 9, 201, 67, 84, 139, 184, 242, 59, 228, 28, 167, 109, 154, 210, 184, 72, 248, 70, 128, 130, 39, 16, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
+ Path: []byte{14, 9, 2, 6, 13, 11, 6, 9, 10, 10, 12, 14, 13, 5, 1, 8, 14, 9, 11, 9, 15, 0, 15, 4, 3, 4, 10, 4, 7, 3, 14, 7, 1, 7, 4, 1, 0, 9, 12, 9, 4, 3, 5, 4, 8, 11, 11, 8, 15, 2, 3, 11, 14, 4, 1, 12, 10, 7, 6, 13, 9, 10, 13, 2, 16},
+ Storage: []statediff.StorageDiff{},
+ },
+ burnLeafKey: {
+ Key: burnLeafKey.Bytes(),
+ Value: burnAccount1,
+ Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
+ {248, 113, 160, 51, 128, 199, 183, 174, 129, 165, 142, 185, 141, 156, 120, 222, 74, 31, 215, 253, 149, 53, 252, 149, 62, 210, 190, 96, 45, 170, 164, 23, 103, 49, 42, 184, 78, 248, 76, 128, 136, 27, 193, 109, 103, 78, 200, 0, 0, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
+ Path: []byte{5, 3, 8, 0, 12, 7, 11, 7, 10, 14, 8, 1, 10, 5, 8, 14, 11, 9, 8, 13, 9, 12, 7, 8, 13, 14, 4, 10, 1, 15, 13, 7, 15, 13, 9, 5, 3, 5, 15, 12, 9, 5, 3, 14, 13, 2, 11, 14, 6, 0, 2, 13, 10, 10, 10, 4, 1, 7, 6, 7, 3, 1, 2, 10, 16},
+ Storage: []statediff.StorageDiff{},
+ },
+ },
+ DeletedAccounts: emptyAccountDiffEventualMap,
+ UpdatedAccounts: statediff.AccountDiffsMap{
+ testhelpers.BankLeafKey: {
+ Key: testhelpers.BankLeafKey.Bytes(),
+ Value: bankAccount1,
+ Proof: [][]byte{{248, 113, 160, 87, 118, 82, 182, 37, 183, 123, 219, 91, 247, 123, 196, 63, 49, 37, 202, 215, 70, 77, 103, 157, 21, 117, 86, 82, 119, 211, 97, 27, 128, 83, 231, 128, 128, 128, 128, 160, 254, 136, 159, 16, 229, 219, 143, 44, 43, 243, 85, 146, 129, 82, 161, 127, 110, 59, 185, 154, 146, 65, 172, 109, 132, 199, 126, 98, 100, 80, 156, 121, 128, 128, 128, 128, 128, 128, 128, 128, 160, 17, 219, 12, 218, 52, 168, 150, 218, 190, 182, 131, 155, 176, 106, 56, 244, 149, 20, 207, 164, 134, 67, 89, 132, 235, 1, 59, 125, 249, 238, 133, 197, 128, 128},
+ {248, 109, 160, 48, 191, 73, 244, 64, 161, 205, 5, 39, 228, 208, 110, 39, 101, 101, 76, 15, 86, 69, 34, 87, 81, 109, 121, 58, 155, 141, 96, 77, 207, 223, 42, 184, 74, 248, 72, 1, 132, 5, 245, 185, 240, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112}},
+ Path: []byte{0, 0, 11, 15, 4, 9, 15, 4, 4, 0, 10, 1, 12, 13, 0, 5, 2, 7, 14, 4, 13, 0, 6, 14, 2, 7, 6, 5, 6, 5, 4, 12, 0, 15, 5, 6, 4, 5, 2, 2, 5, 7, 5, 1, 6, 13, 7, 9, 3, 10, 9, 11, 8, 13, 6, 0, 4, 13, 12, 15, 13, 15, 2, 10, 16},
+ Storage: []statediff.StorageDiff{},
+ },
+ },
+ }
+ expectedStateDiffRlp, _ := rlp.EncodeToBytes(expectedStateDiff)
+ select {
+ case payload := <-payloadChan:
+ if !bytes.Equal(payload.BlockRlp, expectedBlockRlp) {
+ t.Errorf("payload does not have expected block\r\actual: %v\r\nexpected: %v", payload.BlockRlp, expectedBlockRlp)
+ }
+ if !bytes.Equal(payload.StateDiffRlp, expectedStateDiffRlp) {
+ t.Errorf("payload does not have expected state diff\r\actual: %v\r\nexpected: %v", payload.StateDiffRlp, expectedStateDiffRlp)
+ }
+ case <-quitChan:
+ t.Errorf("channel quit before delivering payload")
+ }
+}
diff --git a/statediff/testhelpers/test_data.go b/statediff/testhelpers/test_data.go
index 54c7b14ce..17dac8473 100644
--- a/statediff/testhelpers/test_data.go
+++ b/statediff/testhelpers/test_data.go
@@ -17,20 +17,24 @@
package testhelpers
import (
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/rlp"
"math/big"
"math/rand"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/statediff"
)
+// AddressToLeafKey hashes an returns an address
func AddressToLeafKey(address common.Address) common.Hash {
return common.BytesToHash(crypto.Keccak256(address[:]))
}
+// Test variables
var (
BlockNumber = rand.Int63()
BlockHash = "0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73"
@@ -58,7 +62,7 @@ var (
Root: ContractRoot,
CodeHash: CodeHash,
}
- valueBytes, err = rlp.EncodeToBytes(testAccount)
+ valueBytes, _ = rlp.EncodeToBytes(testAccount)
CreatedAccountDiffs = statediff.AccountDiffsMap{
ContractLeafKey: {
Key: ContractLeafKey.Bytes(),
@@ -91,4 +95,20 @@ var (
DeletedAccounts: DeletedAccountDiffs,
UpdatedAccounts: UpdatedAccountDiffs,
}
+ Testdb = rawdb.NewMemoryDatabase()
+
+ TestBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ TestBankAddress = crypto.PubkeyToAddress(TestBankKey.PublicKey) //0x71562b71999873DB5b286dF957af199Ec94617F7
+ BankLeafKey = AddressToLeafKey(TestBankAddress)
+ TestBankFunds = big.NewInt(100000000)
+ Genesis = core.GenesisBlockForTesting(Testdb, TestBankAddress, TestBankFunds)
+
+ Account1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
+ Account2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
+ Account1Addr = crypto.PubkeyToAddress(Account1Key.PublicKey) //0x703c4b2bD70c169f5717101CaeE543299Fc946C7
+ Account2Addr = crypto.PubkeyToAddress(Account2Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
+ Account1LeafKey = AddressToLeafKey(Account1Addr)
+ Account2LeafKey = AddressToLeafKey(Account2Addr)
+ ContractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50602060405190810160405280600160ff16815250600090600161003592919061003b565b506100a5565b826064810192821561006f579160200282015b8281111561006e578251829060ff1690559160200191906001019061004e565b5b50905061007c9190610080565b5090565b6100a291905b8082111561009e576000816000905550600101610086565b5090565b90565b610124806100b46000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146054578063c16431b9146093575b600080fd5b607d60048036036020811015606857600080fd5b810190808035906020019092919050505060c8565b6040518082815260200191505060405180910390f35b60c66004803603604081101560a757600080fd5b81019080803590602001909291908035906020019092919050505060e0565b005b6000808260648110151560d757fe5b01549050919050565b8060008360648110151560ef57fe5b0181905550505056fea165627a7a7230582064e918c3140a117bf3aa65865a9b9e83fae21ad1720506e7933b2a9f54bb40260029")
+ ContractAddr common.Address
)
diff --git a/statediff/types.go b/statediff/types.go
index 91c11335e..41e83dddb 100644
--- a/statediff/types.go
+++ b/statediff/types.go
@@ -21,12 +21,15 @@ package statediff
import (
"encoding/json"
+
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
)
-type AccountsMap map[common.Hash]*accountWrapper
+// AccountsMap is a mapping of keccak256(address) => accountWrapper
+type AccountsMap map[common.Hash]accountWrapper
+// AccountWrapper is used to temporary associate the unpacked account with its raw values
type accountWrapper struct {
Account state.Account
RawKey []byte
@@ -35,8 +38,9 @@ type accountWrapper struct {
Path []byte
}
+// StateDiff is the final output structure from the builder
type StateDiff struct {
- BlockNumber int64 `json:"blockNumber" gencodec:"required"`
+ BlockNumber int64 `json:"blockNumber" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
CreatedAccounts AccountDiffsMap `json:"createdAccounts" gencodec:"required"`
DeletedAccounts AccountDiffsMap `json:"deletedAccounts" gencodec:"required"`
@@ -46,26 +50,28 @@ type StateDiff struct {
err error
}
-func (self *StateDiff) ensureEncoded() {
- if self.encoded == nil && self.err == nil {
- self.encoded, self.err = json.Marshal(self)
+func (sd *StateDiff) ensureEncoded() {
+ if sd.encoded == nil && sd.err == nil {
+ sd.encoded, sd.err = json.Marshal(sd)
}
}
-// Implement Encoder interface for StateDiff
+// Length to implement Encoder interface for StateDiff
func (sd *StateDiff) Length() int {
sd.ensureEncoded()
return len(sd.encoded)
}
-// Implement Encoder interface for StateDiff
+// Encode to implement Encoder interface for StateDiff
func (sd *StateDiff) Encode() ([]byte, error) {
sd.ensureEncoded()
return sd.encoded, sd.err
}
+// AccountDiffsMap is a mapping of keccak256(address) => AccountDiff
type AccountDiffsMap map[common.Hash]AccountDiff
+// AccountDiff holds the data for a single state diff leaf node
type AccountDiff struct {
Key []byte `json:"key" gencodec:"required"`
Value []byte `json:"value" gencodec:"required"`
@@ -74,6 +80,7 @@ type AccountDiff struct {
Path []byte `json:"path" gencodec:"required"`
}
+// StorageDiff holds the data for a single storage diff leaf node
type StorageDiff struct {
Key []byte `json:"key" gencodec:"required"`
Value []byte `json:"value" gencodec:"required"`