Skip to content

Commit

Permalink
feat: add anvil_setLoggingEnabled (#437)
Browse files Browse the repository at this point in the history
* add `anvil_setLoggingEnabled`

* lint
  • Loading branch information
itegulov authored Nov 26, 2024
1 parent ede79a3 commit 7f5b663
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 89 deletions.
1 change: 1 addition & 0 deletions SUPPORTED_APIS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The `status` options are:

| Namespace | API | <div style="width:130px">Status</div> | Description |
| --- | --- | --- | --- |
| `ANVIL` | `anvil_setLoggingEnabled` | `SUPPORTED` | Enables or disables logging |
| `ANVIL` | `anvil_snapshot` | `SUPPORTED` | Snapshot the state of the blockchain at the current block |
| `ANVIL` | `anvil_revert` | `SUPPORTED` | Revert the state of the blockchain to a previous snapshot |
| `ANVIL` | `anvil_setTime` | `SUPPORTED` | Sets the internal clock time to the given timestamp |
Expand Down
25 changes: 25 additions & 0 deletions e2e-tests/test/anvil-apis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,34 @@ import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import * as hre from "hardhat";
import { keccak256 } from "ethers/lib/utils";
import { BigNumber } from "ethers";
import * as fs from "node:fs";

const provider = getTestProvider();

describe("anvil_setLoggingEnabled", function () {
it("Should disable and enable logging", async function () {
// Arrange
const wallet = new Wallet(RichAccounts[0].PrivateKey, provider);
const userWallet = Wallet.createRandom().connect(provider);

// Act
await provider.send("anvil_setLoggingEnabled", [false]);
const logSizeBefore = fs.statSync("../era_test_node.log").size;

await wallet.sendTransaction({
to: userWallet.address,
value: ethers.utils.parseEther("0.1"),
});
const logSizeAfter = fs.statSync("../era_test_node.log").size;

// Reset
await provider.send("anvil_setLoggingEnabled", [true]);

// Assert
expect(logSizeBefore).to.equal(logSizeAfter);
});
});

describe("anvil_snapshot", function () {
it("Should return incrementing snapshot ids", async function () {
const wallet = new Wallet(RichAccounts[6].PrivateKey);
Expand Down
8 changes: 8 additions & 0 deletions src/namespaces/anvil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ use crate::utils::Numeric;

#[rpc]
pub trait AnvilNamespaceT {
/// Enable or disable logging.
///
/// # Arguments
///
/// * `enable` - if `true` logging will be enabled, disabled otherwise
#[rpc(name = "anvil_setLoggingEnabled")]
fn set_logging_enabled(&self, enable: bool) -> RpcResult<()>;

/// Snapshot the state of the blockchain at the current block. Takes no parameters. Returns the id of the snapshot
/// that was created. A snapshot can only be reverted once. After a successful `anvil_revert`, the same snapshot id cannot
/// be used again. Consider creating a new snapshot after each `anvil_revert` if you need to revert to the same
Expand Down
9 changes: 9 additions & 0 deletions src/node/anvil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ use crate::{
impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> AnvilNamespaceT
for InMemoryNode<S>
{
fn set_logging_enabled(&self, enable: bool) -> RpcResult<()> {
self.set_logging_enabled(enable)
.map_err(|err| {
tracing::error!("failed creating snapshot: {:?}", err);
into_jsrpc_error(Web3Error::InternalError(err))
})
.into_boxed_future()
}

fn snapshot(&self) -> RpcResult<U64> {
self.snapshot()
.map_err(|err| {
Expand Down
70 changes: 34 additions & 36 deletions src/node/config_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,48 +184,46 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> Configurat
}

fn config_set_log_level(&self, level: LogLevel) -> Result<bool> {
if let Some(observability) = &self
.get_inner()
.read()
.map_err(|err| {
tracing::error!("failed acquiring lock: {:?}", err);
into_jsrpc_error(Web3Error::InternalError(anyhow::Error::msg(
"Failed to acquire read lock for inner node state.",
)))
})?
.observability
{
match observability.set_log_level(level) {
Ok(_) => tracing::info!("set log level to '{}'", level),
Err(err) => {
tracing::error!("failed setting log level {:?}", err);
return Ok(false);
}
let Some(observability) = &self.observability else {
return Err(into_jsrpc_error(Web3Error::InternalError(
anyhow::Error::msg("Node's logging is not set up."),
)));
};
match observability.set_log_level(level) {
Ok(_) => {
tracing::info!("set log level to '{}'", level);
self.get_inner()
.write()
.map_err(|err| {
tracing::error!("failed acquiring lock: {:?}", err);
into_jsrpc_error(Web3Error::InternalError(anyhow::Error::msg(
"Failed to acquire write lock for inner node state.",
)))
})?
.config
.log_level = level;
Ok(true)
}
Err(err) => {
tracing::error!("failed setting log level {:?}", err);
Ok(false)
}
}
Ok(true)
}

fn config_set_logging(&self, directive: String) -> Result<bool> {
if let Some(observability) = &self
.get_inner()
.read()
.map_err(|err| {
tracing::error!("failed acquiring lock: {:?}", err);
into_jsrpc_error(Web3Error::InternalError(anyhow::Error::msg(
"Failed to acquire read lock for inner node state.",
)))
})?
.observability
{
match observability.set_logging(&directive) {
Ok(_) => tracing::info!("set logging to '{}'", directive),
Err(err) => {
tracing::error!("failed setting logging to '{}': {:?}", directive, err);
return Ok(false);
}
let Some(observability) = &self.observability else {
return Err(into_jsrpc_error(Web3Error::InternalError(
anyhow::Error::msg("Node's logging is not set up."),
)));
};
match observability.set_logging(directive.clone()) {
Ok(_) => tracing::info!("set logging to '{}'", directive),
Err(err) => {
tracing::error!("failed setting logging to '{}': {:?}", directive, err);
return Ok(false);
}
}
};
Ok(true)
}
}
24 changes: 6 additions & 18 deletions src/node/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,6 @@ pub struct InMemoryNodeInner<S> {
pub rich_accounts: HashSet<H160>,
/// Keeps track of historical states indexed via block hash. Limited to [MAX_PREVIOUS_STATES].
pub previous_states: IndexMap<H256, HashMap<StorageKey, StorageValue>>,
/// An optional handle to the observability stack
pub observability: Option<Observability>,
}

#[derive(Debug)]
Expand All @@ -238,11 +236,7 @@ pub struct TxExecutionOutput {

impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
/// Create the state to be used implementing [InMemoryNode].
pub fn new(
fork: Option<ForkDetails>,
observability: Option<Observability>,
config: &TestNodeConfig,
) -> Self {
pub fn new(fork: Option<ForkDetails>, config: &TestNodeConfig) -> Self {
let updated_config = config.clone();

if let Some(f) = &fork {
Expand Down Expand Up @@ -294,7 +288,6 @@ impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
impersonation: impersonation_manager,
rich_accounts: HashSet::new(),
previous_states: Default::default(),
observability,
}
} else {
let mut block_hashes = HashMap::<u64, H256>::new();
Expand Down Expand Up @@ -335,7 +328,6 @@ impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
impersonation: impersonation_manager,
rich_accounts: HashSet::new(),
previous_states: Default::default(),
observability,
}
}
}
Expand Down Expand Up @@ -891,6 +883,8 @@ pub struct InMemoryNode<S: Clone> {
pub(crate) system_contracts_options: system_contracts::Options,
pub(crate) time: TimestampManager,
pub(crate) impersonation: ImpersonationManager,
/// An optional handle to the observability stack
pub(crate) observability: Option<Observability>,
}

fn contract_address_from_tx_result(execution_result: &VmExecutionResultAndLogs) -> Option<H160> {
Expand All @@ -915,7 +909,7 @@ impl<S: ForkSource + std::fmt::Debug + Clone> InMemoryNode<S> {
config: &TestNodeConfig,
) -> Self {
let system_contracts_options = config.system_contracts_options;
let inner = InMemoryNodeInner::new(fork, observability, config);
let inner = InMemoryNodeInner::new(fork, config);
let time = inner.time.clone();
let impersonation = inner.impersonation.clone();
InMemoryNode {
Expand All @@ -924,6 +918,7 @@ impl<S: ForkSource + std::fmt::Debug + Clone> InMemoryNode<S> {
system_contracts_options,
time,
impersonation,
observability,
}
}

Expand Down Expand Up @@ -957,15 +952,8 @@ impl<S: ForkSource + std::fmt::Debug + Clone> InMemoryNode<S> {
}

pub fn reset(&self, fork: Option<ForkDetails>) -> Result<(), String> {
let observability = self
.inner
.read()
.map_err(|e| format!("Failed to acquire read lock: {}", e))?
.observability
.clone();

let config = self.get_config()?;
let inner = InMemoryNodeInner::new(fork, observability, &config);
let inner = InMemoryNodeInner::new(fork, &config);

let mut writer = self
.snapshots
Expand Down
28 changes: 19 additions & 9 deletions src/node/in_memory_ext.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
use crate::utils::Numeric;
use crate::{
fork::{ForkDetails, ForkSource},
namespaces::ResetRequest,
node::InMemoryNode,
utils::bytecode_to_factory_dep,
};
use anyhow::{anyhow, Context};
use std::convert::TryInto;
use zksync_types::{
Expand All @@ -8,14 +15,6 @@ use zksync_types::{
use zksync_types::{AccountTreeId, Address, U256, U64};
use zksync_utils::u256_to_h256;

use crate::utils::Numeric;
use crate::{
fork::{ForkDetails, ForkSource},
namespaces::ResetRequest,
node::InMemoryNode,
utils::bytecode_to_factory_dep,
};

type Result<T> = anyhow::Result<T>;

/// The maximum number of [Snapshot]s to store. Each snapshot represents the node state
Expand Down Expand Up @@ -350,6 +349,17 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> InMemoryNo
true
})
}

pub fn set_logging_enabled(&self, enable: bool) -> Result<()> {
let Some(observability) = &self.observability else {
anyhow::bail!("Node's logging is not set up");
};
if enable {
observability.enable_logging()
} else {
observability.disable_logging()
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -485,7 +495,6 @@ mod tests {
impersonation: Default::default(),
rich_accounts: Default::default(),
previous_states: Default::default(),
observability: None,
};
let time = old_inner.time.clone();
let impersonation = old_inner.impersonation.clone();
Expand All @@ -496,6 +505,7 @@ mod tests {
system_contracts_options: old_system_contracts_options,
time,
impersonation,
observability: None,
};

let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap();
Expand Down
Loading

0 comments on commit 7f5b663

Please sign in to comment.