GitHub Logo HIP-729: Contract Accounts Nonce Externalization

Author Miroslav Gatsanoga
Working Group Stoyan Panayotov, Ivan Kavaldzhiev, Richard Bair, Nana Essilfie-Conduah
Requested By Limechain
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/730
Status Final
Needs Council Approval Yes
Review period ends Wed, 31 May 2023 07:00:00 +0000
Type Standards Track
Category Service
Created 2023-05-05
Updated 2023-06-07
Release v0.40.0

Abstract

The Hedera Smart Contract Service (HSCS) supports the deployment of contracts. A deployed contract A should have a nonce value that reflects the number of other contracts that were created since A’s creation. Currently this is not the observed behavior in Hedera and this HIP aims to fix that.

Motivation

In Ethereum, contract accounts have nonces, as specified by the yellow paper and EIP-161.

The EVM uses the nonce value internally, for several different operations, for example:

  1. to check whether an account exists at an address, it checks whether the nonce property stored for this address is different than 0 (it also checks the balance and code properties for the address as well, but this is out of scope for this discussion).
  2. when deploying new contracts via a CREATE operation, the address for an Ethereum contract is deterministically computed from the address of its creator (sender) and how many transactions the creator has sent (nonce). The sender and nonce are RLP encoded and then hashed with Keccak-256.

When deploying new contracts via a CREATE2 operation, the derivation of new contract addresses does not involve the nonce. Instead, a contract address can be derived using the deployer address, bytecode, and salt.

Ethereum nodes expose a JSON-RPC endpoint that can be queried for each account’s nonce value: eth_getTransactionCount

In Hedera the Mirror Node which stores historical entity and transaction information has no knowledge of contract nonces and always returns a 0 value. As a result, the JSON-RPC Relay (as described in HIP-482) which exposes the eth_getTransactionCount JSON-RPC endpoint has to query the Consensus node and not the Mirror Node to return nonce values for contract accounts. Querying the consensus node comes at a cost which differs from EVM use cases. The desired behavior would be to have a nonce value of 1 + n where n is the number of times the contract created other contracts through CREATE or CREATE2 operations exposed to the Mirror Node and clients that consume the Mirror Node APIs such as the JSON RPC relay.

Rationale

As described in HIP-482, the JSON-RPC Relay works with EthereumTransactions that it forwards to the consensus nodes. Apart from the EthereumTransaction type, the consensus nodes can also handle other types of transactions (e.g. ContractCall or ContractCreate) that do not come from the JSON-RPC Relay but can be used by developers by other means. In general, when we talk about account nonces we will need to consider all of those transaction types for both types of accounts (i.e. EOAs and contracts):

  • Contract nonce updates for both cases of EthereumTransactions and non-EthereumTransactions (i.e. ContractCall or ContractCreate) will need to be tracked and externalized to Mirror Node
  • Tracking nonces for EOAs for EthereumTransactions is not changed (currently we don’t have a specific protobuf to externalize the nonce but the nonce value is passed as part of the EthereumTransaction body, so Mirror Node can read the value from there)
  • Tracking nonces for EOAs for non-EthereumTransactions is not supported because there is no use case for it in Hedera

User stories

  1. As a user, when I make a request to the Mirror Node api/v1/contracts/{contractId} I observe a valid non-zero contract nonce value.
  2. As a user, when I make a request to eth_getTransactionCount endpoint I want to be able to get correct nonce values for contracts.

Specification

No changes to Services state will be needed because currently the nonces are currently being computed correctly there. We need to externalize these changes to Mirror Node so that it can keep a correct state representation for contract accounts.

HAPI Changes

Define new message type:

message ContractNonceInfo {

    /**
     * Id of the contract
     */
    ContractID contract_id = 1;

    /**
     * The current value of the contract account's nonce property
     */
    int64 nonce = 2;
}

Update ContractFunctionResult:

message ContractFunctionResult {
    ...

    /**
     * A list of updated contract account nonces containing the new nonce value for each contract account
     */
    repeated ContractNonceInfo contract_nonces = 14;
}

Mirror Node Changes

Mirror Node should start using the new contract_nonces field and update the state of the contract accounts with it. Additionally, the /api/v1/contracts and api/v1/contract/{contractIdOrAddress} endpoints responses should be updated to return the contract nonce value:

{
  ...,
  "nonce": 1,
  ...
}

SDK Changes

The SDKs will need to support returning the contract_nonces field in the ContractFunctionResult.

Mirror Node Explorer Changes

The mirror node explorer will need to display the contract nonce field when the mirror node rest API becomes available with this data.

Backwards Compatibility

The HIP does not introduce any changes that are backwards incompatible.

Security Implications

None.

How to Teach This

  • Additional documentation on protobufs

Reference Implementation

None.

Rejected Ideas

Track the contract nonce on each child’s function result and just have a ContractFunctionResult.nonce field.

The main consideration regarding the ContractFunctionResult.nonce approach is that in ContractFunctionResult we have the contract that is the target but we don’t have the sender (which is the one that should have it’s nonce incremented). Also in the case of revert in any of the child transactions, there will not be a record produced for them, so that’s why the contract_nonces map should be populated in the top-level parent record.

Open Issues

None.

References

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: