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 |
Table of Contents
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:
- 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).
- 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
). Thesender
andnonce
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
andnon-EthereumTransactions
(i.e.ContractCall
orContractCreate
) 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 theEthereumTransaction
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
- 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. - 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: