In what ways can storage history be accessed?

AronVanAmmersAronVanAmmers Amsterdam, NetherlandsMember Posts: 40 ✭✭
Ethereum contracts run on a blockchain and therefore have the characteristics of blockchains: all transactions (state transitions) are traceable and can be replayed by any node in the system. In fact they are replayed by any node downloading the blockchain from scratch. When the node is up to date, all current storage of the contracts can be queried from a DApp, JSON RPC etc.

How can the history of the storage be queried?

To give an example, if one were to build a subcurrency using the Subcurrency example, we would effectively have an altcoin running on Ethereum. Securely transacting with these "coins" is a matter of sending Ethereum transactions to the contract calling its send function.

But how would we do things such as:
  • Show the transaction history of an address in terms of the subcurrency
  • Show transaction details in terms of the subcurrency, i.e. "On 2015-01-05 11:28 an amount of 33 subcoins were transferred from address X to address Y, executed in Ethereum transaction 0x12345 in block 82324"
  • Search for addresses that have transacted in the subcoin, even if they don't currently possess coins anymore

Comments

  • AronVanAmmersAronVanAmmers Amsterdam, NetherlandsMember Posts: 40 ✭✭
    To partially answer my own question, web3.eth.defaultBlock seems to be the key to navigating history.

    It's applied to for example web3.eth.getStorageAt() and web3.eth.call(). Without having tested the latest release I would assume the following is possible:
    1. web3.eth.getStorageAt() allows the parameter defaultBlock to be passed. This should allow for getting a storage value at some earlier block. In the case of the Subcurrency example this would allow for checking someone's balance in a past block.
    2. As web3.eth.getStorageAt() and web3.eth.call() respect web3.eth.defaultBlock, I would asssume that calls to Contract objects (e.g. from Solidity) are executed as if they were in the state of a certiain past block.
    3. Furthermore, web3.eth.getBlock() allows fetching data about the eth blocks/transactions. The raw input data passed with the transaction is returned, so working with this data requires parsing (i.e. is not as developer friendly as sending the transaction in the first place).
    Based on the above I would assume the following is possible in terms of the subcurrency example:
    // Instantiate contract from ABI
    var Subcurrency = web3.eth.contract([ABI array]);
    var mySubCur = Subcurrency.at([contract address]);
    
    // Get the subcurrency balance at the latest block.
    var currentBalance = subCurrency.queryBalance("0x12345");
    
    // Make all calls and storage access return the state from this block instead of the latest.
    web3.eth.defaultBlock = 100;
    
    // Get the subcurrency balance for an address in block 100
    var balanceInOldBlock = subCurrency.queryBalance("0x12345");
    
    This seems to offer quite a range of options to navigate history. I'll report further on my experiences, also about the performance characteristics of these functions.

    Please correct me if I'm wrong, and supplement with your experiences or tips. Perhaps @chriseth or @KenK can have a look to see if my line of thinking makes sense?
  • feindurafeindura BerlinMember Posts: 7
    edited May 2015
    The answer is "logs".

    You need your alt coin to generate logs by specifying events in solidity when money is send.

    event Send(address from, address to, uint value);

    Then you're able to trace all the send from and to and even filter the logs by specifying and address it was send from or to.

    This allows you to get all the past transactions of that currency as well.

    Example:

    // Instantiate contract from ABI
    var Subcurrency = web3.eth.contract([ABI array]);
    var mySubCur = Subcurrency.at([contract address]);

    var sendEvent = mySubCur.Send({from: sendFromAddress}, {fromBlock: 0, toBlock: 'latest'});

    sendEvent.watch(function(error, log){
    console.log(log);
    });
    P.s. i updated the Subcurrency example
    Post edited by feindura on
  • AronVanAmmersAronVanAmmers Amsterdam, NetherlandsMember Posts: 40 ✭✭
    @feindura tx. I knew about events, not that they allowed for getting historical info as well. Looks like a good way to get specific transaction info that is know up front.

    Also, with the fromBlock/toBlock it allows for consistent DApp behaviour when the DApp is not continuously running (as with almost all DApps). The DApp can track of the latest block it saw and processed in the UX (for example, notifying the user of transactions in the subcurrency), and store this in e.g. localStorage. When opening the DApp again after say a week, it asks for logged events since the last block it processed and will get all relevant transactions in that week.
  • FabianVogelstellerFabianVogelsteller Berlin, GermanyMember Posts: 13
    Yes. thats what i do as well.

    Actually you have to be even more careful, as small chain reorganisations happen all the time.

    I check the last block.parentHash i get compare it with the previous ones hash. If there is a mismatch i have a small fork and remove all logs - 100(0) and re-fetch if via filters, to make sure i show the latest correct version of the chain.
  • LarsPensjoLarsPensjo SwedenMember Posts: 35
    feindura said:

    You need your alt coin to generate logs by specifying events in solidity when money is send.

    Doesn't the blockchain already contain a complete log (indirectly)? As you are able to unwind the blockchain, in the case of a fork, you can restore past states. And if you can do that, you should be able to create a complete log from the blockchain?

    If you save a local log to a computer somewhere, you no longer have a decentralized solution, with the usual trust issues.
  • FabianVogelstellerFabianVogelsteller Berlin, GermanyMember Posts: 13
    To improve performance of you dapp, dapp developers will use local storage or other means to store past history.

    Sure they should validate with the current blockchain and update data accordingly, but if every dapp would always get all past data of millions of blocks from the node, the node would be under heavy stress, thats for sure :)
  • SmithgiftSmithgift Member Posts: 64
    Event filters can be sub-filtered to only include events with a specific argument. A subcoin wallet could ask for all deposit events from the beginning of time, but only if they are to the current address.
  • brianricebrianrice Member Posts: 1
    FabianVogelsteller, Can you provide an example of how you do this..."I check the last block.parentHash i get compare it with the previous ones hash. If there is a mismatch i have a small fork and remove all logs - 100(0) and re-fetch if via filters, to make sure i show the latest correct version of the chain."

    Many Thanks!
  • FabianVogelstellerFabianVogelsteller Berlin, GermanyMember Posts: 13
    You create a web3.filter('latest', function(blockHash){....}), and then you compare it to the last one you got.
  • SeanC52111SeanC52111 Member Posts: 2
    edited April 2018
    I have tried to change the defaultBlock and made calls. It seems that the result of the call remains the same as the 'latest' one. @AronVanAmmers
Sign In or Register to comment.