Skip to content

Commit

Permalink
feat: implement hardhat_setNonce (#101)
Browse files Browse the repository at this point in the history
* feat: impl `hardhat_setNonce`

* docs: add docs for `hardhat_setNonce`

* chore: clippy
  • Loading branch information
grw-ms authored Sep 7, 2023
1 parent 8013425 commit 14ef9bb
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 3 deletions.
35 changes: 34 additions & 1 deletion SUPPORTED_APIS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ The `status` options are:
| `HARDHAT` | `hardhat_setMinGasPrice` | `NOT IMPLEMENTED` | Sets the minimum gas price |
| `HARDHAT` | `hardhat_setNextBlockBaseFeePerGas` | `NOT IMPLEMENTED` | Sets the base fee per gas for the next block |
| `HARDHAT` | `hardhat_setPrevRandao` | `NOT IMPLEMENTED` | Sets the PREVRANDAO value of the next block |
| `HARDHAT` | `hardhat_setNonce` | `NOT IMPLEMENTED`<br />[GitHub Issue #77](https://github.com/matter-labs/era-test-node/issues/77) | Sets the nonce of a given account |
| [`HARDHAT`](#hardhat-namespace) | [`hardhat_setNonce`](#hardhat_setnonce) | `SUPPORTED` | Sets the nonce of a given account |
| `HARDHAT` | `hardhat_setStorageAt` | `NOT IMPLEMENTED` | Sets the storage value at a given key for a given account |
| `HARDHAT` | `hardhat_stopImpersonatingAccount` | `NOT IMPLEMENTED`<br />[GitHub Issue #74](https://github.com/matter-labs/era-test-node/issues/74) | Stop impersonating an account after having previously used `hardhat_impersonateAccount` |
| [`NETWORK`](#network-namespace) | [`net_version`](#net_version) | `SUPPORTED` | Returns the current network id <br />_(default is `260`)_ |
Expand Down Expand Up @@ -717,6 +717,39 @@ curl --request POST \
}'
```

### `hardhat_setNonce`

[source](src/hardhat.rs)

Modifies an account's nonce by overwriting it.
The new nonce must be greater than the existing nonce.

#### Arguments

+ `address: Address` - The `Address` whose nonce is to be changed
+ `nonce: U256` - The new nonce

#### Status

`SUPPORTED`

#### Example

```bash
curl --request POST \
--url http://localhost:8011/ \
--header 'content-type: application/json' \
--data '{
"jsonrpc": "2.0",
"id": "1",
"method": "hardhat_setNonce",
"params": [
"0x36615Cf349d7F6344891B1e7CA7C72883F5dc049",
"0x1337"
]
}'
```

## `ZKS NAMESPACE`

### `zks_estimateFee`
Expand Down
83 changes: 81 additions & 2 deletions src/hardhat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_derive::rpc;
use zksync_basic_types::{Address, U256};
use zksync_core::api_server::web3::backend_jsonrpc::error::into_jsrpc_error;
use zksync_types::utils::storage_key_for_eth_balance;
use zksync_utils::u256_to_h256;
use zksync_state::ReadStorage;
use zksync_types::{
get_nonce_key,
utils::{decompose_full_nonce, nonces_to_full_nonce, storage_key_for_eth_balance},
};
use zksync_utils::{h256_to_u256, u256_to_h256};
use zksync_web3_decl::error::Web3Error;

/// Implementation of HardhatNamespaceImpl
Expand Down Expand Up @@ -35,6 +39,19 @@ pub trait HardhatNamespaceT {
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[rpc(name = "hardhat_setBalance")]
fn set_balance(&self, address: Address, balance: U256) -> BoxFuture<Result<bool>>;

/// Modifies an account's nonce by overwriting it.
///
/// # Arguments
///
/// * `address` - The `Address` whose nonce is to be changed
/// * `nonce` - The new nonce
///
/// # Returns
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[rpc(name = "hardhat_setNonce")]
fn set_nonce(&self, address: Address, balance: U256) -> BoxFuture<Result<bool>>;
}

impl<S: Send + Sync + 'static + ForkSource + std::fmt::Debug> HardhatNamespaceT
Expand Down Expand Up @@ -67,6 +84,48 @@ impl<S: Send + Sync + 'static + ForkSource + std::fmt::Debug> HardhatNamespaceT
}
})
}

fn set_nonce(
&self,
address: Address,
nonce: U256,
) -> jsonrpc_core::BoxFuture<jsonrpc_core::Result<bool>> {
let inner = Arc::clone(&self.node);
Box::pin(async move {
match inner.write() {
Ok(mut inner_guard) => {
let nonce_key = get_nonce_key(&address);
let full_nonce = inner_guard.fork_storage.read_value(&nonce_key);
let (mut account_nonce, mut deployment_nonce) =
decompose_full_nonce(h256_to_u256(full_nonce));
if account_nonce >= nonce {
return Err(jsonrpc_core::Error::invalid_params(format!(
"Account Nonce is already set to a higher value ({}, requested {})",
account_nonce, nonce
)));
}
account_nonce = nonce;
if deployment_nonce >= nonce {
return Err(jsonrpc_core::Error::invalid_params(format!(
"Deployment Nonce is already set to a higher value ({}, requested {})",
deployment_nonce, nonce
)));
}
deployment_nonce = nonce;
let enforced_full_nonce = nonces_to_full_nonce(account_nonce, deployment_nonce);
println!(
"👷 Nonces for address {:?} have been set to {}",
address, nonce
);
inner_guard
.fork_storage
.set_value(nonce_key, u256_to_h256(enforced_full_nonce));
Ok(true)
}
Err(_) => Err(into_jsrpc_error(Web3Error::InternalError)),
}
})
}
}

#[cfg(test)]
Expand Down Expand Up @@ -94,4 +153,24 @@ mod tests {
assert_eq!(balance_after, U256::from(1337));
assert_ne!(balance_before, balance_after);
}

#[tokio::test]
async fn test_set_nonce() {
let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap();
let node = InMemoryNode::<HttpForkSource>::default();
let hardhat = HardhatNamespaceImpl::new(node.get_inner());

let nonce_before = node.get_transaction_count(address, None).await.unwrap();

let result = hardhat.set_nonce(address, U256::from(1337)).await.unwrap();
assert!(result);

let nonce_after = node.get_transaction_count(address, None).await.unwrap();
assert_eq!(nonce_after, U256::from(1337));
assert_ne!(nonce_before, nonce_after);

// setting nonce lower than the current one should fail
let result = hardhat.set_nonce(address, U256::from(1336)).await;
assert!(result.is_err());
}
}
14 changes: 14 additions & 0 deletions test_endpoints.http
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,20 @@ content-type: application/json
POST http://localhost:8011
content-type: application/json

{
"jsonrpc": "2.0",
"id": "2",
"method": "hardhat_setNonce",
"params": [
"0x36615Cf349d7F6344891B1e7CA7C72883F5dc049",
"0x56"
]
}

###
POST http://localhost:8011
content-type: application/json

{
"jsonrpc": "2.0",
"id": "1",
Expand Down

0 comments on commit 14ef9bb

Please sign in to comment.