Statediff for full node #6

Merged
elizabethengelman merged 9 commits from statediff-for-full-node into statediff-for-archive-node 2019-02-21 20:36:04 +00:00
14 changed files with 250 additions and 105 deletions

View File

@ -155,8 +155,14 @@ func makeFullNode(ctx *cli.Context) *node.Node {
if ctx.GlobalIsSet(utils.ConstantinopleOverrideFlag.Name) { if ctx.GlobalIsSet(utils.ConstantinopleOverrideFlag.Name) {
cfg.Eth.ConstantinopleOverride = new(big.Int).SetUint64(ctx.GlobalUint64(utils.ConstantinopleOverrideFlag.Name)) cfg.Eth.ConstantinopleOverride = new(big.Int).SetUint64(ctx.GlobalUint64(utils.ConstantinopleOverrideFlag.Name))
} }
utils.RegisterEthService(stack, &cfg.Eth) utils.RegisterEthService(stack, &cfg.Eth)
if ctx.GlobalBool(utils.StateDiffFlag.Name) {
cfg.Eth.StateDiff = true
rmulhol commented 2019-02-12 22:39:39 +00:00 (Migrated from github.com)
Review

would it make sense to combine this with the RegisterStateDiffService call, if both are based off of the call to ctx.GlobalBool(utils.StateDiffFlag.Name)?

would it make sense to combine this with the `RegisterStateDiffService` call, if both are based off of the call to `ctx.GlobalBool(utils.StateDiffFlag.Name`)?
elizabethengelman commented 2019-02-14 21:45:08 +00:00 (Migrated from github.com)
Review

yeah, good call!

yeah, good call!
utils.RegisterStateDiffService(stack, ctx)
}
if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit) utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
} }
@ -181,9 +187,6 @@ func makeFullNode(ctx *cli.Context) *node.Node {
utils.RegisterEthStatsService(stack, cfg.Ethstats.URL) utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
} }
if ctx.GlobalBool(utils.StateDiffFlag.Name) {
utils.RegisterStateDiffService(stack, ctx)
}
return stack return stack
} }

View File

@ -71,10 +71,11 @@ const (
// CacheConfig contains the configuration values for the trie caching/pruning // CacheConfig contains the configuration values for the trie caching/pruning
// that's resident in a blockchain. // that's resident in a blockchain.
type CacheConfig struct { type CacheConfig struct {
Disabled bool // Whether to disable trie write caching (archive node) Disabled bool // Whether to disable trie write caching (archive node)
TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory
TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk
TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk 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 // BlockChain represents the canonical chain given a database with a genesis
@ -136,6 +137,8 @@ type BlockChain struct {
badBlocks *lru.Cache // Bad block cache badBlocks *lru.Cache // Bad block cache
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
stateDiffsProcessed map[common.Hash]int
} }
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
@ -155,24 +158,26 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
blockCache, _ := lru.New(blockCacheLimit) blockCache, _ := lru.New(blockCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks) futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit) badBlocks, _ := lru.New(badBlockLimit)
stateDiffsProcessed := make(map[common.Hash]int)
bc := &BlockChain{ bc := &BlockChain{
chainConfig: chainConfig, chainConfig: chainConfig,
cacheConfig: cacheConfig, cacheConfig: cacheConfig,
db: db, db: db,
triegc: prque.New(nil), triegc: prque.New(nil),
stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit), stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit),
quit: make(chan struct{}), quit: make(chan struct{}),
shouldPreserve: shouldPreserve, shouldPreserve: shouldPreserve,
bodyCache: bodyCache, bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache, bodyRLPCache: bodyRLPCache,
receiptsCache: receiptsCache, receiptsCache: receiptsCache,
blockCache: blockCache, blockCache: blockCache,
futureBlocks: futureBlocks, futureBlocks: futureBlocks,
engine: engine, engine: engine,
vmConfig: vmConfig, vmConfig: vmConfig,
badBlocks: badBlocks, badBlocks: badBlocks,
stateDiffsProcessed: stateDiffsProcessed,
} }
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@ -922,6 +927,11 @@ func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (e
return nil return nil
} }
func (bc *BlockChain) AddToStateDiffProcessedCollection(hash common.Hash) {
count := bc.stateDiffsProcessed[hash]
bc.stateDiffsProcessed[hash] = count + 1
}
// WriteBlockWithState writes the block and all associated state to the database. // WriteBlockWithState writes the block and all associated state to the database.
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) {
bc.wg.Add(1) bc.wg.Add(1)
@ -994,6 +1004,16 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
bc.triegc.Push(root, number) bc.triegc.Push(root, number)
break break
} }
if bc.cacheConfig.ProcessingStateDiffs {
if !bc.allowedRootToBeDereferenced(root.(common.Hash)) {
bc.triegc.Push(root, number)
break
} else {
rmulhol commented 2019-02-14 16:49:22 +00:00 (Migrated from github.com)
Review

Maybe worth putting 1 and 2 behind variables/constants to clarify what's going on here? My understanding is that a hash needs to be added once as the current hash, and once as the parent hash - and then we're done. Is that right? Do reorgs potentially complicate that expectation?

Maybe worth putting `1` and `2` behind variables/constants to clarify what's going on here? My understanding is that a hash needs to be added once as the current hash, and once as the parent hash - and then we're done. Is that right? Do reorgs potentially complicate that expectation?
rmulhol commented 2019-02-14 16:52:01 +00:00 (Migrated from github.com)
Review

Do we want to retain all these logging statements when we merge?

Do we want to retain all these logging statements when we merge?
elizabethengelman commented 2019-02-14 21:51:13 +00:00 (Migrated from github.com)
Review

probably a good idea to remove some of them 👍

probably a good idea to remove some of them 👍
elizabethengelman commented 2019-02-14 22:48:01 +00:00 (Migrated from github.com)
Review

That's a really good catch. Yeah, my intention was that when we processes a state diff for a given hash, it gets added to the stateDiffsProcessed collection. It then gets added again when the state diff is processed when it is the parent, so we'll need to make sure it isn't pruned before these diffs have been processed.

Considering reorgs is a really good thought, I'm honestly not sure how that would affect this expectation. I think I'd need to spend some time digging into this - do you think it makes sense to hold off merging this in? Or, merging it, and creating a new story to take a look in the future?

That's a really good catch. Yeah, my intention was that when we processes a state diff for a given hash, it gets added to the `stateDiffsProcessed` collection. It then gets added again when the state diff is processed when it is the parent, so we'll need to make sure it isn't pruned before these diffs have been processed. Considering reorgs is a really good thought, I'm honestly not sure how that would affect this expectation. I think I'd need to spend some time digging into this - do you think it makes sense to hold off merging this in? Or, merging it, and creating a new story to take a look in the future?
rmulhol commented 2019-02-15 00:31:09 +00:00 (Migrated from github.com)
Review

Definitely sounds like another story to me, and a bit hard to simulate without getting to the head of the chain and watching it execute in the middle of one.

Definitely sounds like another story to me, and a bit hard to simulate without getting to the head of the chain and watching it execute in the middle of one.
elizabethengelman commented 2019-02-15 15:12:05 +00:00 (Migrated from github.com)
Review

Yeah, it definitely will be tricky. I've added another story so we can make sure to circle back: https://makerdao.atlassian.net/browse/VDB-393

Yeah, it definitely will be tricky. I've added another story so we can make sure to circle back: https://makerdao.atlassian.net/browse/VDB-393
delete(bc.stateDiffsProcessed, root.(common.Hash))
}
}
triedb.Dereference(root.(common.Hash)) triedb.Dereference(root.(common.Hash))
} }
} }
@ -1048,6 +1068,15 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
return status, nil return status, nil
} }
// since we need the state tries of the current block and its parent in-memory
// in order to process statediffs, we should avoid dereferencing roots until
// its statediff and its child have been processed
m0ar commented 2019-02-19 12:42:42 +00:00 (Migrated from github.com)
Review

Why? 🙃 Is it to prevent branches from GC/pruning? Worth the explicit information, that was hard to figure out and harder to guess :)

Why? :upside_down_face: Is it to prevent branches from GC/pruning? Worth the explicit information, that was hard to figure out and harder to guess :)
elizabethengelman commented 2019-02-20 15:48:04 +00:00 (Migrated from github.com)
Review

Totally makes sense! Is this more clear?

// since we need the state tries of the current block and its parent in-memory
// in order to process statediffs, we should avoid dereferencing roots until
// its statediff and its child have been processed

Totally makes sense! Is this more clear? > // since we need the state tries of the current block and its parent in-memory // in order to process statediffs, we should avoid dereferencing roots until // its statediff and its child have been processed
m0ar commented 2019-02-21 10:53:04 +00:00 (Migrated from github.com)
Review

@elizabethengelman Stellarly so! 🌟

@elizabethengelman Stellarly so! :star2:
func (bc *BlockChain) allowedRootToBeDereferenced(root common.Hash) bool {
diffProcessedForSelfAndChildCount := 2
count := bc.stateDiffsProcessed[root]
return count >= diffProcessedForSelfAndChildCount
}
// addFutureBlock checks if the block is within the max allowed window to get // addFutureBlock checks if the block is within the max allowed window to get
// accepted for future processing, and returns an error if the block is too far // accepted for future processing, and returns an error if the block is too far
// ahead and was not added. // ahead and was not added.

View File

@ -1483,3 +1483,84 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
} }
func TestProcessingStateDiffs(t *testing.T) {
defaultTrieCleanCache := 256
defaultTrieDirtyCache := 256
defaultTrieTimeout := 60 * time.Minute
cacheConfig := &CacheConfig{
Disabled: false,
TrieCleanLimit: defaultTrieCleanCache,
TrieDirtyLimit: defaultTrieDirtyCache,
TrieTimeLimit: defaultTrieTimeout,
ProcessingStateDiffs: true,
}
db := ethdb.NewMemDatabase()
genesis := new(Genesis).MustCommit(db)
numberOfBlocks := triesInMemory
engine := ethash.NewFaker()
blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil)
blocks := makeBlockChain(genesis, numberOfBlocks+1, engine, db, canonicalSeed)
_, err := blockchain.InsertChain(blocks)
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
m0ar commented 2019-02-19 12:53:45 +00:00 (Migrated from github.com)
Review

pristine

:sparkles: _pristine_ :sparkles:
}
defer blockchain.Stop()
//when adding a root hash to the collection, it will increment the count
firstStateRoot := blocks[0].Root()
blockchain.AddToStateDiffProcessedCollection(firstStateRoot)
value, ok := blockchain.stateDiffsProcessed[firstStateRoot]
if !ok {
t.Error("state root not found in collection")
}
if value != 1 {
t.Error("state root count not correct", "want", 1, "got", value)
}
blockchain.AddToStateDiffProcessedCollection(firstStateRoot)
value, ok = blockchain.stateDiffsProcessed[firstStateRoot]
if !ok {
t.Error("state root not found in collection")
}
if value != 2 {
t.Error("state root count not correct", "want", 2, "got", value)
}
moreBlocks := makeBlockChain(blocks[len(blocks)-1], 1, engine, db, canonicalSeed)
_, err = blockchain.InsertChain(moreBlocks)
//a root hash can be dereferenced when it's state diff and it's child's state diff have been processed
//(i.e. it has a count of 2 in stateDiffsProcessed)
nodes := blockchain.stateCache.TrieDB().Nodes()
if containsRootHash(nodes, firstStateRoot) {
t.Errorf("stateRoot %s in nodes, want: %t, got: %t", firstStateRoot.Hex(), false, true)
}
//a root hash should still be in the in-mem db if it's child's state diff hasn't yet been processed
//(i.e. it has a count of 1 stateDiffsProcessed)
secondStateRoot := blocks[1].Root()
blockchain.AddToStateDiffProcessedCollection(secondStateRoot)
if !containsRootHash(nodes, secondStateRoot) {
t.Errorf("stateRoot %s in nodes, want: %t, got: %t", secondStateRoot.Hex(), true, false)
}
//the stateDiffsProcessed collection is cleaned up once a hash has been dereferenced
_, ok = blockchain.stateDiffsProcessed[firstStateRoot]
if ok {
t.Errorf("stateRoot %s in stateDiffsProcessed collection, want: %t, got: %t",
firstStateRoot.Hex(),
false,
ok,
)
}
}
func containsRootHash(collection []common.Hash, hash common.Hash) bool {
for _, n := range collection {
if n == hash {
return true
}
}
return false
}
m0ar commented 2019-02-19 13:04:59 +00:00 (Migrated from github.com)
Review

This diff shows how we should write our tests instead of that damn Ginkgo! Looks so clean, and probably runs way faster. 🐌 Why are we even using gomega assertions when we have good 'ol bool

Could probably be split up in smaller tests, but I figure the setup is a bit annoying.

This diff shows how we should write our tests instead of that damn Ginkgo! Looks so clean, and probably runs way faster. :snail: Why are we even using `gomega` assertions when we have good 'ol `bool` Could probably be split up in smaller tests, but I figure the setup is a bit annoying.

View File

@ -157,10 +157,11 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
EVMInterpreter: config.EVMInterpreter, EVMInterpreter: config.EVMInterpreter,
} }
cacheConfig = &core.CacheConfig{ cacheConfig = &core.CacheConfig{
Disabled: config.NoPruning, Disabled: config.NoPruning,
TrieCleanLimit: config.TrieCleanCache, TrieCleanLimit: config.TrieCleanCache,
TrieDirtyLimit: config.TrieDirtyCache, TrieDirtyLimit: config.TrieDirtyCache,
TrieTimeLimit: config.TrieTimeout, TrieTimeLimit: config.TrieTimeout,
ProcessingStateDiffs: config.StateDiff,
} }
) )
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve)

View File

@ -59,6 +59,8 @@ var DefaultConfig = Config{
Blocks: 20, Blocks: 20,
Percentile: 60, Percentile: 60,
}, },
StateDiff: false,
} }
func init() { func init() {
@ -135,6 +137,8 @@ type Config struct {
// Constantinople block override (TODO: remove after the fork) // Constantinople block override (TODO: remove after the fork)
ConstantinopleOverride *big.Int ConstantinopleOverride *big.Int
StateDiff bool
} }
type configMarshaling struct { type configMarshaling struct {

View File

@ -22,6 +22,7 @@ package builder
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -35,25 +36,27 @@ type Builder interface {
type builder struct { type builder struct {
chainDB ethdb.Database chainDB ethdb.Database
trieDB *trie.Database blockChain *core.BlockChain
cachedTrie *trie.Trie
} }
func NewBuilder(db ethdb.Database) *builder { type AccountsMap map[common.Hash]*state.Account
func NewBuilder(db ethdb.Database, blockChain *core.BlockChain) *builder {
return &builder{ return &builder{
chainDB: db, chainDB: db,
trieDB: trie.NewDatabase(db), blockChain: blockChain,
} }
} }
func (sdb *builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber int64, blockHash common.Hash) (*StateDiff, error) { func (sdb *builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, blockNumber int64, blockHash common.Hash) (*StateDiff, error) {
// Generate tries for old and new states // Generate tries for old and new states
oldTrie, err := trie.New(oldStateRoot, sdb.trieDB) stateCache := sdb.blockChain.StateCache()
oldTrie, err := stateCache.OpenTrie(oldStateRoot)
if err != nil { if err != nil {
log.Error("Error creating trie for oldStateRoot", "error", err) log.Error("Error creating trie for oldStateRoot", "error", err)
return nil, err return nil, err
} }
newTrie, err := trie.New(newStateRoot, sdb.trieDB) newTrie, err := stateCache.OpenTrie(newStateRoot)
if err != nil { if err != nil {
log.Error("Error creating trie for newStateRoot", "error", err) log.Error("Error creating trie for newStateRoot", "error", err)
return nil, err return nil, err
@ -108,33 +111,27 @@ func (sdb *builder) BuildStateDiff(oldStateRoot, newStateRoot common.Hash, block
}, nil }, nil
} }
func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (map[common.Address]*state.Account, error) { func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (AccountsMap, error) {
var diffAccounts = make(map[common.Address]*state.Account) var diffAccounts = make(AccountsMap)
it, _ := trie.NewDifferenceIterator(a, b) it, _ := trie.NewDifferenceIterator(a, b)
for { for {
log.Debug("Current Path and Hash", "path", pathToStr(it), "hashold", it.Hash()) log.Debug("Current Path and Hash", "path", pathToStr(it), "hashold", it.Hash())
if it.Leaf() { if it.Leaf() {
leafKey := make([]byte, len(it.LeafKey()))
// lookup address copy(leafKey, it.LeafKey())
path := make([]byte, len(it.Path())-1) leafKeyHash := common.BytesToHash(leafKey)
copy(path, it.Path())
addr, err := sdb.addressByPath(path)
if err != nil {
log.Error("Error looking up address via path", "path", path, "error", err)
return nil, err
}
// lookup account state // lookup account state
var account state.Account var account state.Account
if err := rlp.DecodeBytes(it.LeafBlob(), &account); err != nil { if err := rlp.DecodeBytes(it.LeafBlob(), &account); err != nil {
log.Error("Error looking up account via address", "address", addr, "error", err) log.Error("Error looking up account via address", "address", leafKeyHash, "error", err)
return nil, err return nil, err
} }
// record account to diffs (creation if we are looking at new - old; deletion if old - new) // record account to diffs (creation if we are looking at new - old; deletion if old - new)
log.Debug("Account lookup successful", "address", addr, "account", account) log.Debug("Account lookup successful", "address", leafKeyHash, "account", account)
diffAccounts[*addr] = &account diffAccounts[leafKeyHash] = &account
} }
cont := it.Next(true) cont := it.Next(true)
if !cont { if !cont {
@ -145,8 +142,8 @@ func (sdb *builder) collectDiffNodes(a, b trie.NodeIterator) (map[common.Address
return diffAccounts, nil return diffAccounts, nil
} }
func (sdb *builder) buildDiffEventual(accounts map[common.Address]*state.Account) (map[common.Address]AccountDiff, error) { func (sdb *builder) buildDiffEventual(accounts AccountsMap) (AccountDiffsMap, error) {
accountDiffs := make(map[common.Address]AccountDiff) accountDiffs := make(AccountDiffsMap)
for addr, val := range accounts { for addr, val := range accounts {
sr := val.Root sr := val.Root
storageDiffs, err := sdb.buildStorageDiffsEventual(sr) storageDiffs, err := sdb.buildStorageDiffsEventual(sr)
@ -172,11 +169,11 @@ func (sdb *builder) buildDiffEventual(accounts map[common.Address]*state.Account
return accountDiffs, nil return accountDiffs, nil
} }
func (sdb *builder) buildDiffIncremental(creations map[common.Address]*state.Account, deletions map[common.Address]*state.Account, updatedKeys []string) (map[common.Address]AccountDiff, error) { func (sdb *builder) buildDiffIncremental(creations AccountsMap, deletions AccountsMap, updatedKeys []string) (AccountDiffsMap, error) {
updatedAccounts := make(map[common.Address]AccountDiff) updatedAccounts := make(AccountDiffsMap)
for _, val := range updatedKeys { for _, val := range updatedKeys {
createdAcc := creations[common.HexToAddress(val)] createdAcc := creations[common.HexToHash(val)]
deletedAcc := deletions[common.HexToAddress(val)] deletedAcc := deletions[common.HexToHash(val)]
oldSR := deletedAcc.Root oldSR := deletedAcc.Root
m0ar commented 2019-02-19 13:19:30 +00:00 (Migrated from github.com)
Review

Why spend efforts duplicating the data when it's just (at a glance?) used to do a map indexing at 134?

Why spend efforts duplicating the data when it's just (at a glance?) used to do a map indexing at 134?
elizabethengelman commented 2019-02-20 16:03:50 +00:00 (Migrated from github.com)
Review

The LeafKey comment says that, "callers must not retain references to the value after calling Next" - so making a copy of it may be overkill, since I don't think we need to reference the leaf key after we convert it to a hash (on line 123).

The `LeafKey` comment says that, "callers must not retain references to the value after calling Next" - so making a copy of it may be overkill, since I don't think we need to reference the leaf key after we convert it to a hash (on line 123).
newSR := createdAcc.Root newSR := createdAcc.Root
if storageDiffs, err := sdb.buildStorageDiffsIncremental(oldSR, newSR); err != nil { if storageDiffs, err := sdb.buildStorageDiffsIncremental(oldSR, newSR); err != nil {
@ -190,15 +187,15 @@ func (sdb *builder) buildDiffIncremental(creations map[common.Address]*state.Acc
nHexRoot := createdAcc.Root.Hex() nHexRoot := createdAcc.Root.Hex()
contractRoot := DiffString{Value: &nHexRoot} contractRoot := DiffString{Value: &nHexRoot}
updatedAccounts[common.HexToAddress(val)] = AccountDiff{ updatedAccounts[common.HexToHash(val)] = AccountDiff{
Nonce: nonce, Nonce: nonce,
Balance: balance, Balance: balance,
CodeHash: codeHash, CodeHash: codeHash,
ContractRoot: contractRoot, ContractRoot: contractRoot,
Storage: storageDiffs, Storage: storageDiffs,
} }
delete(creations, common.HexToAddress(val)) delete(creations, common.HexToHash(val))
delete(deletions, common.HexToAddress(val)) delete(deletions, common.HexToHash(val))
} }
} }
return updatedAccounts, nil return updatedAccounts, nil
@ -206,7 +203,8 @@ func (sdb *builder) buildDiffIncremental(creations map[common.Address]*state.Acc
func (sdb *builder) buildStorageDiffsEventual(sr common.Hash) (map[string]DiffStorage, error) { func (sdb *builder) buildStorageDiffsEventual(sr common.Hash) (map[string]DiffStorage, error) {
log.Debug("Storage Root For Eventual Diff", "root", sr.Hex()) log.Debug("Storage Root For Eventual Diff", "root", sr.Hex())
sTrie, err := trie.New(sr, sdb.trieDB) stateCache := sdb.blockChain.StateCache()
sTrie, err := stateCache.OpenTrie(sr)
if err != nil { if err != nil {
log.Info("error in build storage diff eventual", "error", err) log.Info("error in build storage diff eventual", "error", err)
return nil, err return nil, err
@ -218,11 +216,13 @@ func (sdb *builder) buildStorageDiffsEventual(sr common.Hash) (map[string]DiffSt
func (sdb *builder) buildStorageDiffsIncremental(oldSR common.Hash, newSR common.Hash) (map[string]DiffStorage, error) { func (sdb *builder) buildStorageDiffsIncremental(oldSR common.Hash, newSR common.Hash) (map[string]DiffStorage, error) {
log.Debug("Storage Roots for Incremental Diff", "old", oldSR.Hex(), "new", newSR.Hex()) log.Debug("Storage Roots for Incremental Diff", "old", oldSR.Hex(), "new", newSR.Hex())
oldTrie, err := trie.New(oldSR, sdb.trieDB) stateCache := sdb.blockChain.StateCache()
oldTrie, err := stateCache.OpenTrie(oldSR)
if err != nil { if err != nil {
return nil, err return nil, err
} }
newTrie, err := trie.New(newSR, sdb.trieDB) newTrie, err := stateCache.OpenTrie(newSR)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -10,10 +10,12 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "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/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
b "github.com/ethereum/go-ethereum/statediff/builder" b "github.com/ethereum/go-ethereum/statediff/builder"
"github.com/ethereum/go-ethereum/statediff/testhelpers"
) )
var ( var (
@ -21,26 +23,33 @@ var (
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) //0x71562b71999873DB5b286dF957af199Ec94617F7 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) //0x71562b71999873DB5b286dF957af199Ec94617F7
bankLeafKey = testhelpers.AddressToLeafKey(testBankAddress)
testBankFunds = big.NewInt(100000000) testBankFunds = big.NewInt(100000000)
genesis = core.GenesisBlockForTesting(testdb, testBankAddress, testBankFunds) genesis = core.GenesisBlockForTesting(testdb, testBankAddress, testBankFunds)
account1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") account1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
account2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") account2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
account1Addr = crypto.PubkeyToAddress(account1Key.PublicKey) //0x703c4b2bD70c169f5717101CaeE543299Fc946C7 account1Addr = crypto.PubkeyToAddress(account1Key.PublicKey) //0x703c4b2bD70c169f5717101CaeE543299Fc946C7
account1LeafKey = testhelpers.AddressToLeafKey(account1Addr)
account2Addr = crypto.PubkeyToAddress(account2Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e account2Addr = crypto.PubkeyToAddress(account2Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
account2LeafKey = testhelpers.AddressToLeafKey(account2Addr)
contractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50602060405190810160405280600160ff16815250600090600161003592919061003b565b506100a5565b826064810192821561006f579160200282015b8281111561006e578251829060ff1690559160200191906001019061004e565b5b50905061007c9190610080565b5090565b6100a291905b8082111561009e576000816000905550600101610086565b5090565b90565b610124806100b46000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146054578063c16431b9146093575b600080fd5b607d60048036036020811015606857600080fd5b810190808035906020019092919050505060c8565b6040518082815260200191505060405180910390f35b60c66004803603604081101560a757600080fd5b81019080803590602001909291908035906020019092919050505060e0565b005b6000808260648110151560d757fe5b01549050919050565b8060008360648110151560ef57fe5b0181905550505056fea165627a7a7230582064e918c3140a117bf3aa65865a9b9e83fae21ad1720506e7933b2a9f54bb40260029") contractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50602060405190810160405280600160ff16815250600090600161003592919061003b565b506100a5565b826064810192821561006f579160200282015b8281111561006e578251829060ff1690559160200191906001019061004e565b5b50905061007c9190610080565b5090565b6100a291905b8082111561009e576000816000905550600101610086565b5090565b90565b610124806100b46000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146054578063c16431b9146093575b600080fd5b607d60048036036020811015606857600080fd5b810190808035906020019092919050505060c8565b6040518082815260200191505060405180910390f35b60c66004803603604081101560a757600080fd5b81019080803590602001909291908035906020019092919050505060e0565b005b6000808260648110151560d757fe5b01549050919050565b8060008360648110151560ef57fe5b0181905550505056fea165627a7a7230582064e918c3140a117bf3aa65865a9b9e83fae21ad1720506e7933b2a9f54bb40260029")
contractAddr common.Address contractAddr common.Address
emptyAccountDiffEventualMap = make(map[common.Address]b.AccountDiff) contractLeafKey common.Hash
emptyAccountDiffIncrementalMap = make(map[common.Address]b.AccountDiff) emptyAccountDiffEventualMap = make(b.AccountDiffsMap)
emptyAccountDiffIncrementalMap = make(b.AccountDiffsMap)
block0Hash, block1Hash, block2Hash, block3Hash common.Hash block0Hash, block1Hash, block2Hash, block3Hash common.Hash
block0, block1, block2, block3 *types.Block block0, block1, block2, block3 *types.Block
builder b.Builder builder b.Builder
miningReward = int64(2000000000000000000) miningReward = int64(2000000000000000000)
burnAddress = common.HexToAddress("0x0") burnAddress = common.HexToAddress("0x0")
burnLeafKey = testhelpers.AddressToLeafKey(burnAddress)
) )
func TestBuilder(t *testing.T) { func TestBuilder(t *testing.T) {
_, blockMap := makeChain(3, genesis) _, blockMap, chain := makeChain(3, genesis)
contractLeafKey = testhelpers.AddressToLeafKey(contractAddr)
defer chain.Stop()
block0Hash = common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661") block0Hash = common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661")
block1Hash = common.HexToHash("0xbbe88de60ba33a3f18c0caa37d827bfb70252e19e40a07cd34041696c35ecb1a") block1Hash = common.HexToHash("0xbbe88de60ba33a3f18c0caa37d827bfb70252e19e40a07cd34041696c35ecb1a")
block2Hash = common.HexToHash("0xde75663f36a8497b4bdda2a4b52bd9540b705a2728c7391c59b8cb2cde5a2feb") block2Hash = common.HexToHash("0xde75663f36a8497b4bdda2a4b52bd9540b705a2728c7391c59b8cb2cde5a2feb")
@ -50,7 +59,7 @@ func TestBuilder(t *testing.T) {
block1 = blockMap[block1Hash] block1 = blockMap[block1Hash]
block2 = blockMap[block2Hash] block2 = blockMap[block2Hash]
block3 = blockMap[block3Hash] block3 = blockMap[block3Hash]
builder = b.NewBuilder(testdb) builder = b.NewBuilder(testdb, chain)
type arguments struct { type arguments struct {
oldStateRoot common.Hash oldStateRoot common.Hash
@ -113,15 +122,15 @@ func TestBuilder(t *testing.T) {
&b.StateDiff{ &b.StateDiff{
BlockNumber: block1.Number().Int64(), BlockNumber: block1.Number().Int64(),
BlockHash: block1.Hash(), BlockHash: block1.Hash(),
CreatedAccounts: map[common.Address]b.AccountDiff{ CreatedAccounts: b.AccountDiffsMap{
account1Addr: { account1LeafKey: {
Nonce: b.DiffUint64{Value: &nonce0}, Nonce: b.DiffUint64{Value: &nonce0},
Balance: b.DiffBigInt{Value: big.NewInt(balanceChange10000)}, Balance: b.DiffBigInt{Value: big.NewInt(balanceChange10000)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
ContractRoot: b.DiffString{Value: &originalContractRoot}, ContractRoot: b.DiffString{Value: &originalContractRoot},
Storage: map[string]b.DiffStorage{}, Storage: map[string]b.DiffStorage{},
}, },
burnAddress: { burnLeafKey: {
Nonce: b.DiffUint64{Value: &nonce0}, Nonce: b.DiffUint64{Value: &nonce0},
Balance: b.DiffBigInt{Value: big.NewInt(miningReward)}, Balance: b.DiffBigInt{Value: big.NewInt(miningReward)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
@ -130,8 +139,8 @@ func TestBuilder(t *testing.T) {
}, },
}, },
DeletedAccounts: emptyAccountDiffEventualMap, DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: map[common.Address]b.AccountDiff{ UpdatedAccounts: b.AccountDiffsMap{
testBankAddress: { bankLeafKey: {
Nonce: b.DiffUint64{Value: &nonce1}, Nonce: b.DiffUint64{Value: &nonce1},
Balance: b.DiffBigInt{Value: big.NewInt(testBankFunds.Int64() - balanceChange10000)}, Balance: b.DiffBigInt{Value: big.NewInt(testBankFunds.Int64() - balanceChange10000)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
@ -154,15 +163,15 @@ func TestBuilder(t *testing.T) {
&b.StateDiff{ &b.StateDiff{
BlockNumber: block2.Number().Int64(), BlockNumber: block2.Number().Int64(),
BlockHash: block2.Hash(), BlockHash: block2.Hash(),
CreatedAccounts: map[common.Address]b.AccountDiff{ CreatedAccounts: b.AccountDiffsMap{
account2Addr: { account2LeafKey: {
Nonce: b.DiffUint64{Value: &nonce0}, Nonce: b.DiffUint64{Value: &nonce0},
Balance: b.DiffBigInt{Value: big.NewInt(balanceChange1000)}, Balance: b.DiffBigInt{Value: big.NewInt(balanceChange1000)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
ContractRoot: b.DiffString{Value: &originalContractRoot}, ContractRoot: b.DiffString{Value: &originalContractRoot},
Storage: map[string]b.DiffStorage{}, Storage: map[string]b.DiffStorage{},
}, },
contractAddr: { contractLeafKey: {
Nonce: b.DiffUint64{Value: &nonce1}, Nonce: b.DiffUint64{Value: &nonce1},
Balance: b.DiffBigInt{Value: big.NewInt(0)}, Balance: b.DiffBigInt{Value: big.NewInt(0)},
CodeHash: "0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea", CodeHash: "0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea",
@ -175,22 +184,22 @@ func TestBuilder(t *testing.T) {
}, },
}, },
DeletedAccounts: emptyAccountDiffEventualMap, DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: map[common.Address]b.AccountDiff{ UpdatedAccounts: b.AccountDiffsMap{
testBankAddress: { bankLeafKey: {
Nonce: b.DiffUint64{Value: &nonce2}, Nonce: b.DiffUint64{Value: &nonce2},
Balance: b.DiffBigInt{Value: big.NewInt(block1BankBalance - balanceChange1000)}, Balance: b.DiffBigInt{Value: big.NewInt(block1BankBalance - balanceChange1000)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
ContractRoot: b.DiffString{Value: &originalContractRoot}, ContractRoot: b.DiffString{Value: &originalContractRoot},
Storage: map[string]b.DiffStorage{}, Storage: map[string]b.DiffStorage{},
}, },
account1Addr: { account1LeafKey: {
Nonce: b.DiffUint64{Value: &nonce2}, Nonce: b.DiffUint64{Value: &nonce2},
Balance: b.DiffBigInt{Value: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000)}, Balance: b.DiffBigInt{Value: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
ContractRoot: b.DiffString{Value: &originalContractRoot}, ContractRoot: b.DiffString{Value: &originalContractRoot},
Storage: map[string]b.DiffStorage{}, Storage: map[string]b.DiffStorage{},
}, },
burnAddress: { burnLeafKey: {
Nonce: b.DiffUint64{Value: &nonce0}, Nonce: b.DiffUint64{Value: &nonce0},
Balance: b.DiffBigInt{Value: big.NewInt(miningReward + miningReward)}, Balance: b.DiffBigInt{Value: big.NewInt(miningReward + miningReward)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
@ -213,17 +222,17 @@ func TestBuilder(t *testing.T) {
&b.StateDiff{ &b.StateDiff{
BlockNumber: block3.Number().Int64(), BlockNumber: block3.Number().Int64(),
BlockHash: block3.Hash(), BlockHash: block3.Hash(),
CreatedAccounts: map[common.Address]b.AccountDiff{}, CreatedAccounts: b.AccountDiffsMap{},
DeletedAccounts: emptyAccountDiffEventualMap, DeletedAccounts: emptyAccountDiffEventualMap,
UpdatedAccounts: map[common.Address]b.AccountDiff{ UpdatedAccounts: b.AccountDiffsMap{
account2Addr: { account2LeafKey: {
Nonce: b.DiffUint64{Value: &nonce0}, Nonce: b.DiffUint64{Value: &nonce0},
Balance: b.DiffBigInt{Value: big.NewInt(block2Account2Balance + miningReward)}, Balance: b.DiffBigInt{Value: big.NewInt(block2Account2Balance + miningReward)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
ContractRoot: b.DiffString{Value: &originalContractRoot}, ContractRoot: b.DiffString{Value: &originalContractRoot},
Storage: map[string]b.DiffStorage{}, Storage: map[string]b.DiffStorage{},
}, },
contractAddr: { contractLeafKey: {
Nonce: b.DiffUint64{Value: &nonce1}, Nonce: b.DiffUint64{Value: &nonce1},
Balance: b.DiffBigInt{Value: big.NewInt(0)}, Balance: b.DiffBigInt{Value: big.NewInt(0)},
CodeHash: "0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea", CodeHash: "0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea",
@ -234,7 +243,7 @@ func TestBuilder(t *testing.T) {
Value: &updatedStorageValue}, Value: &updatedStorageValue},
}, },
}, },
testBankAddress: { bankLeafKey: {
Nonce: b.DiffUint64{Value: &nonce3}, Nonce: b.DiffUint64{Value: &nonce3},
Balance: b.DiffBigInt{Value: big.NewInt(99989000)}, Balance: b.DiffBigInt{Value: big.NewInt(99989000)},
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
@ -252,7 +261,6 @@ func TestBuilder(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
fields := []string{"BlockNumber", "BlockHash", "DeletedAccounts", "UpdatedAccounts", "CreatedAccounts"} fields := []string{"BlockNumber", "BlockHash", "DeletedAccounts", "UpdatedAccounts", "CreatedAccounts"}
for _, field := range fields { for _, field := range fields {
@ -287,8 +295,14 @@ func equals(actual, expected interface{}) (success bool) {
// the returned hash chain is ordered head->parent. In addition, every 3rd block // 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 // contains a transaction and every 5th an uncle to allow testing correct block
// reassembly. // reassembly.
func makeChain(n int, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { 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) 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 := make([]common.Hash, n+1)
hashes[len(hashes)-1] = parent.Hash() hashes[len(hashes)-1] = parent.Hash()
blockm := make(map[common.Hash]*types.Block, n+1) blockm := make(map[common.Hash]*types.Block, n+1)
@ -297,7 +311,7 @@ func makeChain(n int, parent *types.Block) ([]common.Hash, map[common.Hash]*type
hashes[len(hashes)-i-2] = b.Hash() hashes[len(hashes)-i-2] = b.Hash()
blockm[b.Hash()] = b blockm[b.Hash()] = b
} }
return hashes, blockm return hashes, blockm, chain
} }
func testChainGen(i int, block *core.BlockGen) { func testChainGen(i int, block *core.BlockGen) {

View File

@ -24,11 +24,10 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
func sortKeys(data map[common.Address]*state.Account) []string { func sortKeys(data AccountsMap) []string {
var keys []string var keys []string
for key := range data { for key := range data {
keys = append(keys, key.Hex()) keys = append(keys, key.Hex())

View File

@ -26,12 +26,13 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type AccountDiffsMap map[common.Hash]AccountDiff
type StateDiff struct { type StateDiff struct {
BlockNumber int64 `json:"blockNumber" gencodec:"required"` BlockNumber int64 `json:"blockNumber" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"` BlockHash common.Hash `json:"blockHash" gencodec:"required"`
CreatedAccounts map[common.Address]AccountDiff `json:"createdAccounts" gencodec:"required"` CreatedAccounts AccountDiffsMap `json:"createdAccounts" gencodec:"required"`
DeletedAccounts map[common.Address]AccountDiff `json:"deletedAccounts" gencodec:"required"` DeletedAccounts AccountDiffsMap `json:"deletedAccounts" gencodec:"required"`
UpdatedAccounts map[common.Address]AccountDiff `json:"updatedAccounts" gencodec:"required"` UpdatedAccounts AccountDiffsMap `json:"updatedAccounts" gencodec:"required"`
encoded []byte encoded []byte
err error err error

View File

@ -15,7 +15,7 @@ var (
Headers = []string{ Headers = []string{
"blockNumber", "blockHash", "accountAction", "codeHash", "blockNumber", "blockHash", "accountAction", "codeHash",
"nonceValue", "balanceValue", "contractRoot", "storageDiffPaths", "nonceValue", "balanceValue", "contractRoot", "storageDiffPaths",
"accountAddress", "storageKey", "storageValue", "accountLeafKey", "storageKey", "storageValue",
} }
timeStampFormat = "20060102150405.00000" timeStampFormat = "20060102150405.00000"
@ -81,7 +81,7 @@ func accumulateAccountRows(sd builder.StateDiff) [][]string {
return accountRows return accountRows
} }
func formatAccountData(accountAddr common.Address, accountDiff builder.AccountDiff, sd builder.StateDiff, accountAction string) [][]string { func formatAccountData(accountAddr common.Hash, accountDiff builder.AccountDiff, sd builder.StateDiff, accountAction string) [][]string {
blockNumberString := strconv.FormatInt(sd.BlockNumber, 10) blockNumberString := strconv.FormatInt(sd.BlockNumber, 10)
blockHash := sd.BlockHash.String() blockHash := sd.BlockHash.String()
codeHash := accountDiff.CodeHash codeHash := accountDiff.CodeHash

View File

@ -35,7 +35,7 @@ var expectedCreatedAccountRow = []string{
strconv.FormatInt(testhelpers.NewBalanceValue, 10), strconv.FormatInt(testhelpers.NewBalanceValue, 10),
testhelpers.ContractRoot, testhelpers.ContractRoot,
testhelpers.StoragePath, testhelpers.StoragePath,
testhelpers.ContractAddress, testhelpers.ContractLeafKey.Hex(),
"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001",
testhelpers.StorageValue, testhelpers.StorageValue,
} }
@ -49,7 +49,7 @@ var expectedCreatedAccountWithoutStorageUpdateRow = []string{
strconv.FormatInt(testhelpers.NewBalanceValue, 10), strconv.FormatInt(testhelpers.NewBalanceValue, 10),
testhelpers.ContractRoot, testhelpers.ContractRoot,
"", "",
testhelpers.AnotherContractAddress, testhelpers.AnotherContractLeafKey.Hex(),
"", "",
"", "",
} }
@ -63,7 +63,7 @@ var expectedUpdatedAccountRow = []string{
strconv.FormatInt(testhelpers.NewBalanceValue, 10), strconv.FormatInt(testhelpers.NewBalanceValue, 10),
testhelpers.ContractRoot, testhelpers.ContractRoot,
testhelpers.StoragePath, testhelpers.StoragePath,
testhelpers.ContractAddress, testhelpers.ContractLeafKey.Hex(),
"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001",
testhelpers.StorageValue, testhelpers.StorageValue,
} }
@ -77,7 +77,7 @@ var expectedDeletedAccountRow = []string{
strconv.FormatInt(testhelpers.NewBalanceValue, 10), strconv.FormatInt(testhelpers.NewBalanceValue, 10),
testhelpers.ContractRoot, testhelpers.ContractRoot,
testhelpers.StoragePath, testhelpers.StoragePath,
testhelpers.ContractAddress, testhelpers.ContractLeafKey.Hex(),
"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001",
testhelpers.StorageValue, testhelpers.StorageValue,
} }

View File

@ -19,6 +19,7 @@ import (
type BlockChain interface { type BlockChain interface {
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
GetBlockByHash(hash common.Hash) *types.Block GetBlockByHash(hash common.Hash) *types.Block
AddToStateDiffProcessedCollection(hash common.Hash)
} }
type StateDiffService struct { type StateDiffService struct {
@ -28,7 +29,7 @@ type StateDiffService struct {
} }
func NewStateDiffService(db ethdb.Database, blockChain *core.BlockChain, config statediff.Config) (*StateDiffService, error) { func NewStateDiffService(db ethdb.Database, blockChain *core.BlockChain, config statediff.Config) (*StateDiffService, error) {
builder := b.NewBuilder(db) builder := b.NewBuilder(db, blockChain)
publisher, err := p.NewPublisher(config) publisher, err := p.NewPublisher(config)
if err != nil { if err != nil {
return nil, err return nil, err
@ -94,6 +95,8 @@ HandleBlockChLoop:
log.Error("Error extracting statediff", "block number", currentBlock.Number(), "error", err) log.Error("Error extracting statediff", "block number", currentBlock.Number(), "error", err)
} else { } else {
log.Info("Statediff extracted", "block number", currentBlock.Number(), "location", stateDiffLocation) log.Info("Statediff extracted", "block number", currentBlock.Number(), "location", stateDiffLocation)
sds.BlockChain.AddToStateDiffProcessedCollection(parentBlock.Root())
sds.BlockChain.AddToStateDiffProcessedCollection(currentBlock.Root())
} }
case <-quitCh: case <-quitCh:
log.Debug("Quitting the statediff block channel") log.Debug("Quitting the statediff block channel")

View File

@ -3,6 +3,8 @@ package mocks
import ( import (
"errors" "errors"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -16,6 +18,8 @@ type BlockChain struct {
ChainEvents []core.ChainEvent ChainEvents []core.ChainEvent
} }
func (mc *BlockChain) AddToStateDiffProcessedCollection(hash common.Hash) {}
func (mc *BlockChain) SetParentBlocksToReturn(blocks []*types.Block) { func (mc *BlockChain) SetParentBlocksToReturn(blocks []*types.Block) {
mc.parentBlocksToReturn = blocks mc.parentBlocksToReturn = blocks
} }
@ -43,6 +47,7 @@ func (bc *BlockChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc
subscription := event.NewSubscription(func(quit <-chan struct{}) error { subscription := event.NewSubscription(func(quit <-chan struct{}) error {
for _, chainEvent := range bc.ChainEvents { for _, chainEvent := range bc.ChainEvents {
if eventCounter > 1 { if eventCounter > 1 {
time.Sleep(250 * time.Millisecond)
return subErr return subErr
} }
select { select {

View File

@ -5,9 +5,14 @@ import (
"math/rand" "math/rand"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/statediff/builder" "github.com/ethereum/go-ethereum/statediff/builder"
) )
func AddressToLeafKey(address common.Address) common.Hash {
return common.BytesToHash(crypto.Keccak256(address[:]))
}
var ( var (
BlockNumber = rand.Int63() BlockNumber = rand.Int63()
BlockHash = "0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73" BlockHash = "0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73"
@ -24,18 +29,18 @@ var (
}} }}
emptyStorage = map[string]builder.DiffStorage{} emptyStorage = map[string]builder.DiffStorage{}
address = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592") address = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592")
ContractLeafKey = AddressToLeafKey(address)
anotherAddress = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476593") anotherAddress = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476593")
ContractAddress = address.String() AnotherContractLeafKey = AddressToLeafKey(anotherAddress)
AnotherContractAddress = anotherAddress.String() CreatedAccountDiffs = builder.AccountDiffsMap{
CreatedAccountDiffs = map[common.Address]builder.AccountDiff{ ContractLeafKey: {
address: {
Nonce: builder.DiffUint64{Value: &NewNonceValue}, Nonce: builder.DiffUint64{Value: &NewNonceValue},
Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)}, Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)},
ContractRoot: builder.DiffString{Value: &ContractRoot}, ContractRoot: builder.DiffString{Value: &ContractRoot},
CodeHash: CodeHash, CodeHash: CodeHash,
Storage: storage, Storage: storage,
}, },
anotherAddress: { AnotherContractLeafKey: {
Nonce: builder.DiffUint64{Value: &NewNonceValue}, Nonce: builder.DiffUint64{Value: &NewNonceValue},
Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)}, Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)},
CodeHash: CodeHash, CodeHash: CodeHash,
@ -44,7 +49,7 @@ var (
}, },
} }
UpdatedAccountDiffs = map[common.Address]builder.AccountDiff{address: { UpdatedAccountDiffs = builder.AccountDiffsMap{ContractLeafKey: {
Nonce: builder.DiffUint64{Value: &NewNonceValue}, Nonce: builder.DiffUint64{Value: &NewNonceValue},
Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)}, Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)},
CodeHash: CodeHash, CodeHash: CodeHash,
@ -52,7 +57,7 @@ var (
Storage: storage, Storage: storage,
}} }}
DeletedAccountDiffs = map[common.Address]builder.AccountDiff{address: { DeletedAccountDiffs = builder.AccountDiffsMap{ContractLeafKey: {
Nonce: builder.DiffUint64{Value: &NewNonceValue}, Nonce: builder.DiffUint64{Value: &NewNonceValue},
Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)}, Balance: builder.DiffBigInt{Value: big.NewInt(NewBalanceValue)},
ContractRoot: builder.DiffString{Value: &ContractRoot}, ContractRoot: builder.DiffString{Value: &ContractRoot},