-
Notifications
You must be signed in to change notification settings - Fork 2.2k
debug_accountRangeAt #4987
debug_accountRangeAt #4987
Conversation
libweb3jsonrpc/Debug.cpp
Outdated
{ | ||
Block block = m_eth.block(blockHash(_blockHashOrNumber)); | ||
|
||
unsigned const i = ((unsigned)_txIndex < block.pending().size()) ? (unsigned)_txIndex : block.pending().size(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use static_cast
for casting and do it once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check Debug::debug_storageRangeAt below this method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy-pasting bad code is still bad code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean should I fix that part too I suppose I should.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can but that's not required.
Here I'd do:
size_t const i = std::min(static_cast<size_t>(_txIndex), block.pending().size());
But I'm not sure this is good logic. Shouldn't we report error in case the transaction index is wrong? And txIndex == block.pending().size() seems to be also wrong.
libweb3jsonrpc/Debug.cpp
Outdated
unsigned const i = ((unsigned)_txIndex < block.pending().size()) ? (unsigned)_txIndex : block.pending().size(); | ||
State state(State::Null); | ||
createIntermediateState(state, block, i, m_eth.blockChain()); | ||
Address from(_address); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you use const
for local variables, do it everywhere.
libweb3jsonrpc/Debug.cpp
Outdated
State state(State::Null); | ||
createIntermediateState(state, block, i, m_eth.blockChain()); | ||
Address from(_address); | ||
for (auto const& addr : state.addresses()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not seem to be efficient way of filtering accounts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so the better way I see would be to sort addresses first then just select address
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at all. The problem is you have to load all accounts from database first. That's not a big deal in test chain but on the mainnet that's not feasible. You have to extend State interface to support returning a subset of addresses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also it should return hashes of addresses, not addresses, because addresses are not always available (e.g. not available after snapshot sync)
@cdetrio also mentioned it in ethereum/retesteth#5 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm. not sure what I would do with address hashes. if this function return list of hashes I wont be able to tell which address is unexpectedly exist in the post state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional is fine. I don't get how @chfast wants to optimize and select required addresses from m_state without iterating. is m_state ordered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure it's ordered, it's a trie. I think you should utilize lower_bound
method of the Trie classes. Somewhat similar to how debug_storageRangeAt
finds the point to start iterating.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gumb0 The key in the database is the hash of the address? so we cannot filter the addresses without first loading it into the cache?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chfast I think we can, we'll just have a special method for this in State
, that will not update m_cache
, but use lower-level feature of TrieDB
It's similar to State::storage(Address const& _id)
(which is used for debug_storageRangeAt
) - it iterates over the storage directly from the database, storage cache is not updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my intention here from the beginning.
Codecov Report
@@ Coverage Diff @@
## develop #4987 +/- ##
===========================================
+ Coverage 59.74% 59.76% +0.02%
===========================================
Files 346 346
Lines 26685 26870 +185
Branches 3188 3222 +34
===========================================
+ Hits 15943 16060 +117
- Misses 9692 9738 +46
- Partials 1050 1072 +22 |
Now you should be able to define a method in
|
The problem with my code there ^ discovered. |
libweb3jsonrpc/Debug.cpp
Outdated
Block block = m_eth.block(blockHash(_blockHashOrNumber)); | ||
size_t const i = std::min(static_cast<size_t>(_txIndex), block.pending().size()); | ||
State state(State::Null); | ||
if (block.info().number() >= m_eth.chainParams().byzantiumForkBlock) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be the other way around? We have to create intermediate state in Byzantium+, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createIntermediateState
works for both cases (creates state from intermediate root when available, executes previous transactions when not)
Then State::addresses()
doesn't work right for this state with re-executed transactions (the result of execution is in cache and it doesn't take into account cache)
This if
shouldn't be here and State::addresses()
should be fixed, I'm going to do it
libethereum/State.h
Outdated
@@ -207,6 +207,11 @@ class State | |||
/// @throws InterfaceNotSupported if compiled without ETH_FATDB. | |||
std::unordered_map<Address, u256> addresses() const; | |||
|
|||
/// @returns the map with maximum _maxResults elements containing hash->addresses and the next | |||
/// address hash. This method faster then addresses() const; | |||
typedef std::map<h256, Address> addressMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change to using AddressMap = std::map<h256, Address>;
libethereum/State.cpp
Outdated
@@ -234,6 +234,28 @@ unordered_map<Address, u256> State::addresses() const | |||
#endif | |||
} | |||
|
|||
std::pair<State::addressMap, h256> State::addresses(h256 const& _begin, size_t _maxResults) const | |||
{ | |||
map<h256, Address> ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use AddressMap
type.
libweb3jsonrpc/Debug.cpp
Outdated
Block block = m_eth.block(blockHash(_blockHashOrNumber)); | ||
size_t const i = std::min(static_cast<size_t>(_txIndex), block.pending().size()); | ||
State state(State::Null); | ||
if (block.info().number() >= m_eth.chainParams().byzantiumForkBlock) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createIntermediateState
works for both cases (creates state from intermediate root when available, executes previous transactions when not)
Then State::addresses()
doesn't work right for this state with re-executed transactions (the result of execution is in cache and it doesn't take into account cache)
This if
shouldn't be here and State::addresses()
should be fixed, I'm going to do it
@winsvega Please check how it now works for you
works
I still think there should be a way for optimization of eth calls. A simple transaction import runs the VM execution twice.
|
This is ok, but AppVeyor fails to test within 1 hour. |
Could the performance degraded because of the changes? AppVeyor is on the edge now. |
unit test could have added some to execution time I think. |
Debug account range at.
Get the list of accounts in the given block after given transaction index with provided account mask.
ethereum/retesteth#18