iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🧐

Can Past Ethereum Smart Contract States Be Retrieved After Being Overwritten?

に公開

Recently, I wrote an article titled Building a Twitter-like app with Ethereum.

In that article, I casually wrote that "tweets cannot be deleted because they are saved on the blockchain." However, thinking about it more deeply, a question arose: "Since the contract state itself can be easily overwritten, is it really impossible to delete them?" So, I decided to look into it.

First, I checked the official docs: TRANSACTIONS, BLOCKS, and Ethereum Virtual Machine. While I could understand how the current state is maintained, I couldn't figure out whether it's possible to refer to an overwritten state from a specific point in the past.

Therefore, I asked this question in Wagumi, a Japanese community (Discord) for exchanging Web3-related information. Since I received some helpful answers, I've recorded the Q&A briefly below ↓

Q

Data saved in storage is persisted. In that case, is the history of changes to that data also preserved? For example, in a contract like the one below, calling changeMessage overwrites the message state. The result becomes Goodbye, World!, but is it possible to refer to the previous Hello, World! state in the blockchain history (e.g., via Etherscan)?

   contract Greeter {
     string private message;
   
     constructor() {
       message = "Hello, World!";
     }
   
     function changeMessage() public {
       message = "Goodbye, World!";
     }
   }

A

The answer is: It is accessible. Blocks with states that have been overwritten are quickly removed from Full Nodes (after the latest 128 blocks). However, by referring to an Archive Node and specifying the block ID from the point in time you want to access, you can retrieve the state at that moment, making it accessible as a result.

Excerpts of the actual answers I received ↓

The storage state is updated by transactions, but past states (state of the n-th block) remain as history (*), so they can be referenced. Utilizing this, you can fork all states of the n-th block of the mainnet using tools like Hardhat and test them locally.
Mainnet forking | Hardhat | Ethereum development environment for professionals by Nomic Labs

Note that only Archive nodes hold the entire history from the genesis block. Full nodes only hold the states of the latest 128 blocks.

The philosophy of blockchain is to keep records by stacking blocks as timestamps, so if you dig through everything, you can manage it with brute force lol

What are Full Nodes and Archive Nodes?

According to Ethhub's Running an Ethereum Node, a Full Node maintains all states and transactions, while an Archive Node further maintains all past history.

Archive nodes are only necessary if you want to check the state of an account at any given block height. For example, if you wanted to know the Ether balance an account had at block #4,000,000, you would need to run and query an archive node.

As mentioned in the Archive Nodes section, it seems you can check the state at any point in the past by querying an Archive Node while specifying a block number.

Trying it out

According to Mainnet forking | Hardhat | Ethereum development environment for professionals by Nomic Labs, you can use Hardhat's Mainnet Forking mechanism to locally retrieve an Archive Node from a specific past block and access the state at that time. Let's try it.

The subject will be the Twitter-like app created in this article. I'll check the state changes by forking at specific block IDs for one state of the tweets and then the next state.

Preparation only requires adding the following to hardhat.config.js.

module.exports = {
  solidity: "0.8.4",
  networks: {
    hardhat: {
      forking: {
        url: "https://eth-mainnet.alchemyapi.io/v2/<key>",
        blockNumber: 11574797,
      },
    },
  },
}

It is recommended to use Alchemy to access Archive Nodes.

To find the blockNumber, search for the contract ID on Ropsten Etherscan and check the transaction history. You will see a field called Block, which you should use.

Then, start the Hardhat node as usual.

npx hardhat node --network hardhat

Now, let's try launching the app in the local environment.

First, let's look at the state immediately after the contract was created and a tweet was posted. Only the "Hello!" tweet should be displayed.

As expected, only Hello! was displayed.

Next, specify the block ID (11574821) for the subsequent tweet.

Then, restart the Hardhat node.

Try accessing the app again. Along with "Hello!", one more tweet should be displayed.

It behaved exactly as expected.

This confirms that by either forking or obtaining all data from an Archive Node and specifying a blockNumber, you can access the state at any point in the past. In other words, information once written to a contract's state can be unearthed.

The expression from my initial doubt—"tweets cannot be deleted because they are saved on the blockchain"—seems to have been generally correct.

Other Links

Discussion