- 
                Notifications
    You must be signed in to change notification settings 
- Fork 2.2k
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
          
        
      |  | ||
| /// @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
          
        
      |  | ||
| 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