[Ethereum] How to obtain the state value of a variable from previous block number using web3

contract-developmentgo-ethereumweb3.pyweb3js

I have a private chain and I am running own archiving node. The node connected with --fast cache=1024 option.

For example I have a set function on my smart contract.

contract smartContract {
    uint  value;
    function set(uint input) returns (bool success) {
         value = input;
    }
    function getValue() public view
     returns (uint)
    {
        return value;
    } 

}

This function is called at block number 100 and 200.

smartContract.set(10) //deployed at block number 100
smartContract.set(20) //deployed at block number 200

At this point. if our blockchain is sync, as we know, when we call smartContract.get() it returns 20.

Here mentions that smart contact can only see the current state.

A contract can only see the current state when it executes, not
previous states. This restriction allows validating nodes to work only
with the current state, rather than needing to store and be able to
access all the previous states.

Here we can get previous blocks data. Since we can obtain previous block data, we could obtain the previous states.

[Q] Could web3 retrieve state of a value from previous block numbers instead of returning the its latest state value?

If we provide the block number such as 100, smartContract.get() at 100; somehow can web3 return value's value at block number 100 instead at latest?

Best Answer

[Q] Could web3 retrieve state of a value from previous block numbers instead of returning the its latest state value?

Yes, in web3.py v4.0+.

When making a contract call, you can specify a block number (or hash). These examples are from the web3.py docs:

# You can call your contract method at a block number:
>>> token_contract.functions.myBalance().call(block_identifier=10)

# or a number of blocks back from pending,
# in this case, the block just before the latest block:
>>> token_contract.functions.myBalance().call(block_identifier=-2)

# or a block hash:
>>> token_contract.functions.myBalance().call(block_identifier='0x4ff4a38b278ab49f7739d3a4ed4e12714386a9fdf72192f2e8f7da7822f10b4d')
>>> token_contract.functions.myBalance().call(block_identifier=b'O\xf4\xa3\x8b\'\x8a\xb4\x9fw9\xd3\xa4\xedN\x12qC\x86\xa9\xfd\xf7!\x92\xf2\xe8\xf7\xdax"\xf1\x0bM')

# Latest is the default, so this is redundant:
>>> token_contract.functions.myBalance().call(block_identifier='latest')

# You can check the state after your pending transactions (if supported by your node):
>>> token_contract.functions.myBalance().call(block_identifier='pending')