From 7df396d9cec05a2fdf347afc65a6b7848d5f82a0 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 17 Nov 2017 19:14:13 +0000 Subject: [PATCH 1/4] eth, internal: Implement using trie diffs --- eth/api.go | 30 ++++++++++++++++++++++++++++++ internal/web3ext/web3ext.go | 12 ++++++++++++ 2 files changed, 42 insertions(+) diff --git a/eth/api.go b/eth/api.go index e91f51bb9969..bf06796ce4c3 100644 --- a/eth/api.go +++ b/eth/api.go @@ -636,3 +636,33 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu } return result } + +func (api *PrivateDebugAPI) GetDirtyAccountsByNumber(startNum, endNum uint64) ([]common.Address, error) { + return api.getDirtyAccounts(api.eth.blockchain.GetBlockByNumber(startNum), api.eth.blockchain.GetBlockByNumber(endNum)) +} + +func (api *PrivateDebugAPI) GetDirtyAccountsByHash(startHash, endHash common.Hash) ([]common.Address, error) { + return api.getDirtyAccounts( + api.eth.blockchain.GetBlockByHash(startHash), + api.eth.blockchain.GetBlockByHash(endHash)) +} + +func (api *PrivateDebugAPI) getDirtyAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { + oldTrie, err := trie.NewSecure(startBlock.Root(), api.eth.chainDb, 0) + if err != nil { + return nil, err + } + + newTrie, err := trie.NewSecure(endBlock.Root(), api.eth.chainDb, 0) + if err != nil { + return nil, err + } + + diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{})) + iter := trie.NewIterator(diff) + var dirty []common.Address + for iter.Next() { + dirty = append(dirty, common.BytesToAddress(newTrie.GetKey(iter.Key))) + } + return dirty, nil +} diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1ae6e2d738a9..fa81472e2cc1 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -354,6 +354,18 @@ web3._extend({ call: 'debug_storageRangeAt', params: 5, }), + new web3._extend.Method({ + name: 'getDirtyAccountsByNumber', + call: 'debug_getDirtyAccountsByNumber', + params: 2, + inputFormatter: [null, null], + }), + new web3._extend.Method({ + name: 'getDirtyAccountsByHash', + call: 'debug_getDirtyAccountsByHash', + params: 2, + inputFormatter:[web3._extend.formatters.inputAddressFormatter, web3._extend.formatters.inputAddressFormatter], + }), ], properties: [] }); From f45aabf843922480ac374285e3242a397b30a200 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Sun, 19 Nov 2017 14:36:46 +0100 Subject: [PATCH 2/4] eth, internal: Changes in response to review --- eth/api.go | 39 +++++++++++++++++++++++++++++++------ internal/web3ext/web3ext.go | 10 +++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/eth/api.go b/eth/api.go index bf06796ce4c3..81138b7862f2 100644 --- a/eth/api.go +++ b/eth/api.go @@ -637,17 +637,40 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu return result } -func (api *PrivateDebugAPI) GetDirtyAccountsByNumber(startNum, endNum uint64) ([]common.Address, error) { - return api.getDirtyAccounts(api.eth.blockchain.GetBlockByNumber(startNum), api.eth.blockchain.GetBlockByNumber(endNum)) +// GetModifiedAccountsByumber returns all accounts that have changed between the +// two blocks specified. A change is defined as a difference in nonce, balance, +// code hash, or storage hash. +// With one parameter, returns the list of accounts modified in the specified block. +func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum, endNum *uint64) ([]common.Address, error) { + // With one argument, compare x-1 with x + if endNum == nil { + return api.getModifiedAccounts( + api.eth.blockchain.GetBlockByNumber(*startNum - 1), + api.eth.blockchain.GetBlockByNumber(*startNum)) + } else { + return api.getModifiedAccounts( + api.eth.blockchain.GetBlockByNumber(*startNum), + api.eth.blockchain.GetBlockByNumber(*endNum)) + } } -func (api *PrivateDebugAPI) GetDirtyAccountsByHash(startHash, endHash common.Hash) ([]common.Address, error) { - return api.getDirtyAccounts( +// GetModifiedAccountsByHash returns all accounts that have changed between the +// two blocks specified. A change is defined as a difference in nonce, balance, +// code hash, or storage hash. +func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash, endHash common.Hash) ([]common.Address, error) { + return api.getModifiedAccounts( api.eth.blockchain.GetBlockByHash(startHash), api.eth.blockchain.GetBlockByHash(endHash)) } -func (api *PrivateDebugAPI) getDirtyAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { +func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { + if startBlock == nil || endBlock == nil { + return nil, fmt.Errorf("Both start block and end block are required") + } + if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { + return nil, fmt.Errorf("Start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) + } + oldTrie, err := trie.NewSecure(startBlock.Root(), api.eth.chainDb, 0) if err != nil { return nil, err @@ -662,7 +685,11 @@ func (api *PrivateDebugAPI) getDirtyAccounts(startBlock, endBlock *types.Block) iter := trie.NewIterator(diff) var dirty []common.Address for iter.Next() { - dirty = append(dirty, common.BytesToAddress(newTrie.GetKey(iter.Key))) + key := newTrie.GetKey(iter.Key) + if(key == nil) { + return nil, fmt.Errorf("No preimage found for hash %x", iter.Key) + } + dirty = append(dirty, common.BytesToAddress(key)) } return dirty, nil } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index fa81472e2cc1..ef0d2b4e6ee6 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -355,16 +355,16 @@ web3._extend({ params: 5, }), new web3._extend.Method({ - name: 'getDirtyAccountsByNumber', - call: 'debug_getDirtyAccountsByNumber', + name: 'getModifiedAccountsByNumber', + call: 'debug_getModifiedAccountsByNumber', params: 2, inputFormatter: [null, null], }), new web3._extend.Method({ - name: 'getDirtyAccountsByHash', - call: 'debug_getDirtyAccountsByHash', + name: 'getModifiedAccountsByHash', + call: 'debug_getModifiedAccountsByHash', params: 2, - inputFormatter:[web3._extend.formatters.inputAddressFormatter, web3._extend.formatters.inputAddressFormatter], + inputFormatter:[null, null], }), ], properties: [] From c0108a45aa4f5872ec7fe9ee417ab389d5b7e8f0 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Mon, 20 Nov 2017 13:01:41 +0000 Subject: [PATCH 3/4] eth: More fixes to getModifiedAccountsBy* --- eth/api.go | 55 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/eth/api.go b/eth/api.go index 81138b7862f2..d342bfb0b320 100644 --- a/eth/api.go +++ b/eth/api.go @@ -641,32 +641,57 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu // two blocks specified. A change is defined as a difference in nonce, balance, // code hash, or storage hash. // With one parameter, returns the list of accounts modified in the specified block. -func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum, endNum *uint64) ([]common.Address, error) { - // With one argument, compare x-1 with x +func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) { + var startBlock, endBlock *types.Block + + startBlock = api.eth.blockchain.GetBlockByNumber(startNum) + if startBlock == nil { + return nil, fmt.Errorf("Start block %x not found", startNum) + } + if endNum == nil { - return api.getModifiedAccounts( - api.eth.blockchain.GetBlockByNumber(*startNum - 1), - api.eth.blockchain.GetBlockByNumber(*startNum)) + endBlock = startBlock + startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) + if startBlock == nil { + return nil, fmt.Errorf("Block %x has no parent", endBlock.Number()) + } } else { - return api.getModifiedAccounts( - api.eth.blockchain.GetBlockByNumber(*startNum), - api.eth.blockchain.GetBlockByNumber(*endNum)) + endBlock = api.eth.blockchain.GetBlockByNumber(*endNum) + if endBlock == nil { + return nil, fmt.Errorf("End block %d not found", *endNum) + } } + + return api.getModifiedAccounts(startBlock, endBlock) } // GetModifiedAccountsByHash returns all accounts that have changed between the // two blocks specified. A change is defined as a difference in nonce, balance, // code hash, or storage hash. -func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash, endHash common.Hash) ([]common.Address, error) { - return api.getModifiedAccounts( - api.eth.blockchain.GetBlockByHash(startHash), - api.eth.blockchain.GetBlockByHash(endHash)) +func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) { + var startBlock, endBlock *types.Block + startBlock = api.eth.blockchain.GetBlockByHash(startHash) + if startBlock == nil { + return nil, fmt.Errorf("Start block %x not found", startHash) + } + + if endHash == nil { + endBlock = startBlock + startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) + if startBlock == nil { + return nil, fmt.Errorf("Block %x has no parent", endBlock.Number()) + } + } else { + endBlock = api.eth.blockchain.GetBlockByHash(*endHash) + if endBlock == nil { + return nil, fmt.Errorf("End block %x not found", *endHash) + } + } + + return api.getModifiedAccounts(startBlock, endBlock) } func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { - if startBlock == nil || endBlock == nil { - return nil, fmt.Errorf("Both start block and end block are required") - } if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { return nil, fmt.Errorf("Start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) } From 98b8134d682d7f753e825009ca116c46b50baa10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Nov 2017 16:22:30 +0200 Subject: [PATCH 4/4] eth: minor polishes on error capitalization --- eth/api.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/eth/api.go b/eth/api.go index d342bfb0b320..12448a6a11dd 100644 --- a/eth/api.go +++ b/eth/api.go @@ -640,67 +640,67 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu // GetModifiedAccountsByumber returns all accounts that have changed between the // two blocks specified. A change is defined as a difference in nonce, balance, // code hash, or storage hash. +// // With one parameter, returns the list of accounts modified in the specified block. func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) { var startBlock, endBlock *types.Block startBlock = api.eth.blockchain.GetBlockByNumber(startNum) if startBlock == nil { - return nil, fmt.Errorf("Start block %x not found", startNum) + return nil, fmt.Errorf("start block %x not found", startNum) } if endNum == nil { endBlock = startBlock startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) if startBlock == nil { - return nil, fmt.Errorf("Block %x has no parent", endBlock.Number()) + return nil, fmt.Errorf("block %x has no parent", endBlock.Number()) } } else { endBlock = api.eth.blockchain.GetBlockByNumber(*endNum) if endBlock == nil { - return nil, fmt.Errorf("End block %d not found", *endNum) + return nil, fmt.Errorf("end block %d not found", *endNum) } } - return api.getModifiedAccounts(startBlock, endBlock) } // GetModifiedAccountsByHash returns all accounts that have changed between the // two blocks specified. A change is defined as a difference in nonce, balance, // code hash, or storage hash. +// +// With one parameter, returns the list of accounts modified in the specified block. func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) { var startBlock, endBlock *types.Block startBlock = api.eth.blockchain.GetBlockByHash(startHash) if startBlock == nil { - return nil, fmt.Errorf("Start block %x not found", startHash) + return nil, fmt.Errorf("start block %x not found", startHash) } if endHash == nil { endBlock = startBlock startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) if startBlock == nil { - return nil, fmt.Errorf("Block %x has no parent", endBlock.Number()) + return nil, fmt.Errorf("block %x has no parent", endBlock.Number()) } } else { endBlock = api.eth.blockchain.GetBlockByHash(*endHash) if endBlock == nil { - return nil, fmt.Errorf("End block %x not found", *endHash) + return nil, fmt.Errorf("end block %x not found", *endHash) } } - return api.getModifiedAccounts(startBlock, endBlock) } func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { - return nil, fmt.Errorf("Start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) + return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) } oldTrie, err := trie.NewSecure(startBlock.Root(), api.eth.chainDb, 0) if err != nil { return nil, err } - newTrie, err := trie.NewSecure(endBlock.Root(), api.eth.chainDb, 0) if err != nil { return nil, err @@ -708,11 +708,12 @@ func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Bloc diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{})) iter := trie.NewIterator(diff) + var dirty []common.Address for iter.Next() { key := newTrie.GetKey(iter.Key) - if(key == nil) { - return nil, fmt.Errorf("No preimage found for hash %x", iter.Key) + if key == nil { + return nil, fmt.Errorf("no preimage found for hash %x", iter.Key) } dirty = append(dirty, common.BytesToAddress(key)) }