Statediff for full node #6
@ -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
|
||||||
|
|||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
Maybe worth putting 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?
Do we want to retain all these logging statements when we merge? Do we want to retain all these logging statements when we merge?
probably a good idea to remove some of them 👍 probably a good idea to remove some of them 👍
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 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?
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.
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
|
||||||
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 :)
Totally makes sense! Is this more clear?
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
@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.
|
||||||
|
@ -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)
|
||||||
✨ 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
|
||||||
|
}
|
||||||
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 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.
|
|||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
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?
The 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
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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 {
|
||||||
|
@ -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},
|
||||||
|
would it make sense to combine this with the
RegisterStateDiffService
call, if both are based off of the call toctx.GlobalBool(utils.StateDiffFlag.Name
)?yeah, good call!