From ed5f8cdef2721b57e76d7d2c939a113bc1ae8d90 Mon Sep 17 00:00:00 2001 From: Tristan Wilson Date: Fri, 2 Aug 2024 12:20:36 +0200 Subject: [PATCH 001/101] DAS RPC Client Metrics This PR adds metrics to the client side of DAS batch posting (eg on the Nitro batch poster). The metrics are designed to mirror the metrics on the daserver side. There are combined metrics for both legacy and chunked Store methods: arb_das_rpcclient_store_requests: Count of initiated batch stores arb_das_rpcclient_store_success: Count of successful batch stores arb_das_rpcclient_store_failure: Count of failed batch stores arb_das_rpcclient_store_bytes: Bytes stored arb_das_rpcclient_store_duration: Histogram of total duration of batch stores (ns) There are metrics specific for chunked Store requests: arb_das_rpcclient_sendchunk_success: Count of chunks sent successfully arb_das_rpcclieny_sendchunk_failure: Count of chunks that failed --- das/dasRpcClient.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/das/dasRpcClient.go b/das/dasRpcClient.go index ca2ee8e7d4..ace975079c 100644 --- a/das/dasRpcClient.go +++ b/das/dasRpcClient.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "golang.org/x/sync/errgroup" "github.com/ethereum/go-ethereum/rpc" @@ -21,6 +22,17 @@ import ( "github.com/offchainlabs/nitro/util/signature" ) +var ( + rpcClientStoreRequestGauge = metrics.NewRegisteredGauge("arb/das/rpcclient/store/requests", nil) + rpcClientStoreSuccessGauge = metrics.NewRegisteredGauge("arb/das/rpcclient/store/success", nil) + rpcClientStoreFailureGauge = metrics.NewRegisteredGauge("arb/das/rpcclient/store/failure", nil) + rpcClientStoreStoredBytesGauge = metrics.NewRegisteredGauge("arb/das/rpcclient/store/bytes", nil) + rpcClientStoreDurationHistogram = metrics.NewRegisteredHistogram("arb/das/rpcclient/store/duration", nil, metrics.NewBoundedHistogramSample()) + + rpcClientSendChunkSuccessGauge = metrics.NewRegisteredGauge("arb/das/rpcclient/sendchunk/success", nil) + rpcClientSendChunkFailureGauge = metrics.NewRegisteredGauge("arb/das/rpcclient/sendchunk/failure", nil) +) + type DASRPCClient struct { // implements DataAvailabilityService clnt *rpc.Client url string @@ -58,7 +70,19 @@ func NewDASRPCClient(target string, signer signature.DataSignerFunc, maxStoreChu } func (c *DASRPCClient) Store(ctx context.Context, message []byte, timeout uint64) (*daprovider.DataAvailabilityCertificate, error) { - timestamp := uint64(time.Now().Unix()) + rpcClientStoreRequestGauge.Inc(1) + start := time.Now() + success := false + defer func() { + if success { + rpcClientStoreSuccessGauge.Inc(1) + } else { + rpcClientStoreFailureGauge.Inc(1) + } + rpcClientStoreDurationHistogram.Update(time.Since(start).Nanoseconds()) + }() + + timestamp := uint64(start.Unix()) nChunks := uint64(len(message)) / c.chunkSize lastChunkSize := uint64(len(message)) % c.chunkSize if lastChunkSize > 0 { @@ -115,6 +139,9 @@ func (c *DASRPCClient) Store(ctx context.Context, message []byte, timeout uint64 return nil, err } + rpcClientStoreStoredBytesGauge.Inc(int64(len(message))) + success = true + return &daprovider.DataAvailabilityCertificate{ DataHash: common.BytesToHash(storeResult.DataHash), Timeout: uint64(storeResult.Timeout), @@ -132,8 +159,10 @@ func (c *DASRPCClient) sendChunk(ctx context.Context, batchId, i uint64, chunk [ } if err := c.clnt.CallContext(ctx, nil, "das_sendChunk", hexutil.Uint64(batchId), hexutil.Uint64(i), hexutil.Bytes(chunk), hexutil.Bytes(chunkReqSig)); err != nil { + rpcClientSendChunkFailureGauge.Inc(1) return err } + rpcClientSendChunkSuccessGauge.Inc(1) return nil } From 2a403985792aba2721e0649671e21b0c2672aa19 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Wed, 7 Aug 2024 17:50:06 +0200 Subject: [PATCH 002/101] Support simpler capture and replay of ValidatorInputs There are several changes in this commit. 1. Move the `parse_inputs.rs` and `prepare.rs` files from the benchbin package to the prover. This enables the prover to ingest most of the information it needs from the `block_inputs_.json` file. 2. Add a `--json-inputs` flag to the `prover` bin which obviates several competing flags preferring to read the data from the json. 3. Write the json file to disk in the working directory before the arbitrator spawner writes the `run_prover.sh` file which is attempting to make a similar validaiton easy to reproduce. 4. Introduce a new `recordBlock` method to the tests suite which can be called once a block has been recorded to L1. 5. Wire the call to `recordBlock` into the `TestProgramStorage` to be sure to capture a block that actually uses a Stylus contract so that the prover can be shown to work with that block as well. 6. Enhance the `parse_inputs.rs` to know how to handle the `UserWasms` deserialization. To reproduce the failure state at this commit: 1. make clean && make all 2. go test -timeout 10m -tags challengetest -run ^TestProgramStorage$ github.com/offchainlabs/nitro/system_tests 3. Observe, there are now two new files in `ls system_tests/block_inputs_{2,5}.json` 4. target/bin/prover target/machines/latest/machine.wavm.br -b --json-inputs system_tests/block_inputs_5.json 5. The error is: ``` thread 'main' panicked at prover/src/machine.rs:690:58: unknown dictionary: TryFromPrimitiveError { number: 10 } ``` If you make changes to the rust code, you can quickly rebuild and install with: ``` cargo build --manifest-path arbitrator/Cargo.toml --release --bin prover && install arbitrator/target/release/prover target/bin/prover ``` --- arbitrator/Cargo.lock | 78 +---- arbitrator/arbutil/src/types.rs | 16 ++ arbitrator/bench/Cargo.toml | 1 - arbitrator/bench/src/bin.rs | 6 +- arbitrator/bench/src/lib.rs | 2 - arbitrator/prover/Cargo.toml | 2 +- arbitrator/prover/src/lib.rs | 2 + arbitrator/prover/src/main.rs | 167 ++++++----- .../{bench => prover}/src/parse_input.rs | 29 +- arbitrator/{bench => prover}/src/prepare.rs | 18 +- arbitrator/wasm-libraries/Cargo.lock | 266 +++++++++++++++--- staker/block_validator.go | 6 + staker/stateless_block_validator.go | 25 ++ system_tests/program_norace_test.go | 13 + system_tests/program_test.go | 8 +- validator/client/validation_client.go | 5 - validator/server_arb/validator_spawner.go | 6 + 17 files changed, 440 insertions(+), 210 deletions(-) delete mode 100644 arbitrator/bench/src/lib.rs rename arbitrator/{bench => prover}/src/parse_input.rs (74%) rename arbitrator/{bench => prover}/src/prepare.rs (73%) diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index 79a9117a31..2aa9864b08 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -215,7 +215,6 @@ dependencies = [ "prover", "serde", "serde_json", - "serde_with 3.9.0", ] [[package]] @@ -705,38 +704,14 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - [[package]] name = "darling" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] @@ -753,24 +728,13 @@ dependencies = [ "syn 2.0.72", ] -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", -] - [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.10", + "darling_core", "quote", "syn 2.0.72", ] @@ -928,7 +892,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" dependencies = [ - "darling 0.20.10", + "darling", "proc-macro2", "quote", "syn 2.0.72", @@ -1750,7 +1714,7 @@ dependencies = [ "rustc-demangle", "serde", "serde_json", - "serde_with 1.14.0", + "serde_with", "sha2 0.9.9", "sha3 0.9.1", "smallvec", @@ -2073,16 +2037,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" -dependencies = [ - "serde", - "serde_with_macros 1.5.2", -] - [[package]] name = "serde_with" version = "3.9.0" @@ -2097,29 +2051,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.9.0", + "serde_with_macros", "time", ] -[[package]] -name = "serde_with_macros" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" -dependencies = [ - "darling 0.13.4", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "serde_with_macros" version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ - "darling 0.20.10", + "darling", "proc-macro2", "quote", "syn 2.0.72", @@ -2226,12 +2168,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" diff --git a/arbitrator/arbutil/src/types.rs b/arbitrator/arbutil/src/types.rs index 6cf1d6cdf7..207b8ab949 100644 --- a/arbitrator/arbutil/src/types.rs +++ b/arbitrator/arbutil/src/types.rs @@ -8,6 +8,7 @@ use std::{ borrow::Borrow, fmt, ops::{Deref, DerefMut}, + str::FromStr, }; // These values must be kept in sync with `arbutil/preimage_type.go`, @@ -83,6 +84,21 @@ impl From for Bytes32 { } } +impl FromStr for Bytes32 { + type Err = hex::FromHexError; + + fn from_str(s: &str) -> Result { + let trimmed = match s.strip_prefix("0x") { + Some(t) => t, + None => s, + }; + let bytes = hex::decode(trimmed)?; + let mut b = [0u8; 32]; + b.copy_from_slice(&bytes); + Ok(Self(b)) + } +} + impl TryFrom<&[u8]> for Bytes32 { type Error = std::array::TryFromSliceError; diff --git a/arbitrator/bench/Cargo.toml b/arbitrator/bench/Cargo.toml index 3ab5b99b08..284180dc46 100644 --- a/arbitrator/bench/Cargo.toml +++ b/arbitrator/bench/Cargo.toml @@ -20,7 +20,6 @@ clap = { version = "4.4.8", features = ["derive"] } gperftools = { version = "0.2.0", optional = true } serde = { version = "1.0.130", features = ["derive", "rc"] } serde_json = "1.0.67" -serde_with = { version = "3.8.1", features = ["base64"] } [features] counters = [] diff --git a/arbitrator/bench/src/bin.rs b/arbitrator/bench/src/bin.rs index f7e69f5373..60a7036e2b 100644 --- a/arbitrator/bench/src/bin.rs +++ b/arbitrator/bench/src/bin.rs @@ -1,6 +1,5 @@ use std::{path::PathBuf, time::Duration}; -use bench::prepare::*; use clap::Parser; use eyre::bail; @@ -10,11 +9,12 @@ use gperftools::profiler::PROFILER; #[cfg(feature = "heapprof")] use gperftools::heap_profiler::HEAP_PROFILER; -use prover::machine::MachineStatus; - #[cfg(feature = "counters")] use prover::{machine, memory, merkle}; +use prover::machine::MachineStatus; +use prover::prepare::prepare_machine; + #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { diff --git a/arbitrator/bench/src/lib.rs b/arbitrator/bench/src/lib.rs deleted file mode 100644 index 5f7c024094..0000000000 --- a/arbitrator/bench/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod parse_input; -pub mod prepare; diff --git a/arbitrator/prover/Cargo.toml b/arbitrator/prover/Cargo.toml index 5475647765..da329b1cb5 100644 --- a/arbitrator/prover/Cargo.toml +++ b/arbitrator/prover/Cargo.toml @@ -19,10 +19,10 @@ num = "0.4" rustc-demangle = "0.1.21" serde = { version = "1.0.130", features = ["derive", "rc"] } serde_json = "1.0.67" +serde_with = { version = "3.8.1", features = ["base64"] } sha3 = "0.9.1" static_assertions = "1.1.0" structopt = "0.3.23" -serde_with = "1.12.1" parking_lot = "0.12.1" lazy_static.workspace = true itertools = "0.10.5" diff --git a/arbitrator/prover/src/lib.rs b/arbitrator/prover/src/lib.rs index 0f537478eb..08473c2598 100644 --- a/arbitrator/prover/src/lib.rs +++ b/arbitrator/prover/src/lib.rs @@ -11,6 +11,8 @@ pub mod machine; /// cbindgen:ignore pub mod memory; pub mod merkle; +pub mod parse_input; +pub mod prepare; mod print; pub mod programs; mod reinterpret; diff --git a/arbitrator/prover/src/main.rs b/arbitrator/prover/src/main.rs index dba32e0e72..002b693bd9 100644 --- a/arbitrator/prover/src/main.rs +++ b/arbitrator/prover/src/main.rs @@ -8,6 +8,7 @@ use eyre::{eyre, Context, Result}; use fnv::{FnvHashMap as HashMap, FnvHashSet as HashSet}; use prover::{ machine::{GlobalState, InboxIdentifier, Machine, MachineStatus, PreimageResolver, ProofInfo}, + prepare::prepare_machine, utils::{file_bytes, hash_preimage, CBytes}, wavm::Opcode, }; @@ -86,6 +87,10 @@ struct Opts { skip_until_host_io: bool, #[structopt(long)] max_steps: Option, + // JSON inputs are supercede any of the command-line inputs which could + // be specified in the JSON file. + #[structopt(long)] + json_inputs: Option, } fn file_with_stub_header(path: &Path, headerlength: usize) -> Result> { @@ -135,83 +140,8 @@ fn main() -> Result<()> { } } } - let mut inbox_contents = HashMap::default(); - let mut inbox_position = opts.inbox_position; - let mut delayed_position = opts.delayed_inbox_position; - let inbox_header_len; - let delayed_header_len; - if opts.inbox_add_stub_headers { - inbox_header_len = INBOX_HEADER_LEN; - delayed_header_len = DELAYED_HEADER_LEN + 1; - } else { - inbox_header_len = 0; - delayed_header_len = 0; - } - - for path in opts.inbox { - inbox_contents.insert( - (InboxIdentifier::Sequencer, inbox_position), - file_with_stub_header(&path, inbox_header_len)?, - ); - println!("read file {:?} to seq. inbox {}", &path, inbox_position); - inbox_position += 1; - } - for path in opts.delayed_inbox { - inbox_contents.insert( - (InboxIdentifier::Delayed, delayed_position), - file_with_stub_header(&path, delayed_header_len)?, - ); - delayed_position += 1; - } - let mut preimages: HashMap> = HashMap::default(); - if let Some(path) = opts.preimages { - let mut file = BufReader::new(File::open(path)?); - loop { - let mut ty_buf = [0u8; 1]; - match file.read_exact(&mut ty_buf) { - Ok(()) => {} - Err(e) if e.kind() == ErrorKind::UnexpectedEof => break, - Err(e) => return Err(e.into()), - } - let preimage_ty: PreimageType = ty_buf[0].try_into()?; - - let mut size_buf = [0u8; 8]; - file.read_exact(&mut size_buf)?; - let size = u64::from_le_bytes(size_buf) as usize; - let mut buf = vec![0u8; size]; - file.read_exact(&mut buf)?; - - let hash = hash_preimage(&buf, preimage_ty)?; - preimages - .entry(preimage_ty) - .or_default() - .insert(hash.into(), buf.as_slice().into()); - } - } - let preimage_resolver = - Arc::new(move |_, ty, hash| preimages.get(&ty).and_then(|m| m.get(&hash)).cloned()) - as PreimageResolver; - - let last_block_hash = decode_hex_arg(&opts.last_block_hash, "--last-block-hash")?; - let last_send_root = decode_hex_arg(&opts.last_send_root, "--last-send-root")?; - - let global_state = GlobalState { - u64_vals: [opts.inbox_position, opts.position_within_message], - bytes32_vals: [last_block_hash, last_send_root], - }; - - let mut mach = Machine::from_paths( - &opts.libraries, - &opts.binary, - true, - opts.allow_hostapi, - opts.debug_funcs, - true, - global_state, - inbox_contents, - preimage_resolver, - )?; + let mut mach = initialize_machine(&opts)?; for path in &opts.stylus_modules { let err = || eyre!("failed to read module at {}", path.to_string_lossy().red()); @@ -462,7 +392,6 @@ fn main() -> Result<()> { } } } - let opts_binary = opts.binary; let opts_libraries = opts.libraries; let format_pc = |module_num: usize, func_num: usize| -> (String, String) { @@ -543,3 +472,87 @@ fn main() -> Result<()> { } Ok(()) } + +fn initialize_machine(opts: &Opts) -> eyre::Result { + if let Some(json_inputs) = opts.json_inputs.clone() { + prepare_machine(json_inputs, opts.binary.clone()) + } else { + let mut inbox_contents = HashMap::default(); + let mut inbox_position = opts.inbox_position; + let mut delayed_position = opts.delayed_inbox_position; + let inbox_header_len; + let delayed_header_len; + if opts.inbox_add_stub_headers { + inbox_header_len = INBOX_HEADER_LEN; + delayed_header_len = DELAYED_HEADER_LEN + 1; + } else { + inbox_header_len = 0; + delayed_header_len = 0; + } + + for path in opts.inbox.clone() { + inbox_contents.insert( + (InboxIdentifier::Sequencer, inbox_position), + file_with_stub_header(&path, inbox_header_len)?, + ); + println!("read file {:?} to seq. inbox {}", &path, inbox_position); + inbox_position += 1; + } + for path in opts.delayed_inbox.clone() { + inbox_contents.insert( + (InboxIdentifier::Delayed, delayed_position), + file_with_stub_header(&path, delayed_header_len)?, + ); + delayed_position += 1; + } + + let mut preimages: HashMap> = HashMap::default(); + if let Some(path) = opts.preimages.clone() { + let mut file = BufReader::new(File::open(path)?); + loop { + let mut ty_buf = [0u8; 1]; + match file.read_exact(&mut ty_buf) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::UnexpectedEof => break, + Err(e) => return Err(e.into()), + } + let preimage_ty: PreimageType = ty_buf[0].try_into()?; + + let mut size_buf = [0u8; 8]; + file.read_exact(&mut size_buf)?; + let size = u64::from_le_bytes(size_buf) as usize; + let mut buf = vec![0u8; size]; + file.read_exact(&mut buf)?; + + let hash = hash_preimage(&buf, preimage_ty)?; + preimages + .entry(preimage_ty) + .or_default() + .insert(hash.into(), buf.as_slice().into()); + } + } + let preimage_resolver = + Arc::new(move |_, ty, hash| preimages.get(&ty).and_then(|m| m.get(&hash)).cloned()) + as PreimageResolver; + + let last_block_hash = decode_hex_arg(&opts.last_block_hash, "--last-block-hash")?; + let last_send_root = decode_hex_arg(&opts.last_send_root, "--last-send-root")?; + + let global_state = GlobalState { + u64_vals: [opts.inbox_position, opts.position_within_message], + bytes32_vals: [last_block_hash, last_send_root], + }; + + Machine::from_paths( + &opts.libraries, + &opts.binary, + true, + opts.allow_hostapi, + opts.debug_funcs, + true, + global_state, + inbox_contents, + preimage_resolver, + ) + } +} diff --git a/arbitrator/bench/src/parse_input.rs b/arbitrator/prover/src/parse_input.rs similarity index 74% rename from arbitrator/bench/src/parse_input.rs rename to arbitrator/prover/src/parse_input.rs index decc67372a..9af8652c96 100644 --- a/arbitrator/bench/src/parse_input.rs +++ b/arbitrator/prover/src/parse_input.rs @@ -35,6 +35,31 @@ mod prefixed_hex { #[derive(Debug, Clone, Deserialize, Serialize)] pub struct PreimageMap(HashMap>); +#[derive(Debug)] +pub struct UserWasm { + data: Vec, +} + +impl UserWasm { + pub fn as_vec(&self) -> Vec { + self.data.clone() + } +} + +impl AsRef<[u8]> for UserWasm { + fn as_ref(&self) -> &[u8] { + &self.data + } +} + +/// The Vec is compressed using brotli, and must be decompressed before use. +impl From> for UserWasm { + fn from(data: Vec) -> Self { + let decompressed = brotli::decompress(&data, brotli::Dictionary::Empty).unwrap(); + Self { data: decompressed } + } +} + #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "PascalCase")] pub struct BatchInfo { @@ -54,7 +79,7 @@ pub struct StartState { pub pos_in_batch: u64, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct FileData { pub id: u64, @@ -66,6 +91,8 @@ pub struct FileData { #[serde(with = "As::")] pub delayed_msg_b64: Vec, pub start_state: StartState, + #[serde(with = "As::>>")] + pub user_wasms: HashMap>>, } impl FileData { diff --git a/arbitrator/bench/src/prepare.rs b/arbitrator/prover/src/prepare.rs similarity index 73% rename from arbitrator/bench/src/prepare.rs rename to arbitrator/prover/src/prepare.rs index 741a7350ac..08bbd1476c 100644 --- a/arbitrator/bench/src/prepare.rs +++ b/arbitrator/prover/src/prepare.rs @@ -1,13 +1,13 @@ use arbutil::{Bytes32, PreimageType}; -use prover::machine::{argument_data_to_inbox, GlobalState, Machine}; -use prover::utils::CBytes; use std::collections::HashMap; use std::fs::File; use std::io::BufReader; use std::path::{Path, PathBuf}; use std::sync::Arc; +use crate::machine::{argument_data_to_inbox, GlobalState, Machine, Module}; use crate::parse_input::*; +use crate::utils::CBytes; pub fn prepare_machine(preimages: PathBuf, machines: PathBuf) -> eyre::Result { let file = File::open(preimages)?; @@ -40,6 +40,20 @@ pub fn prepare_machine(preimages: PathBuf, machines: PathBuf) -> eyre::Result.json files when WriteToFile() is called. + BlockInputsFilePath string `koanf:"block-inputs-file-path"` memoryFreeLimit int } @@ -163,6 +166,7 @@ func BlockValidatorConfigAddOptions(prefix string, f *pflag.FlagSet) { f.Bool(prefix+".failure-is-fatal", DefaultBlockValidatorConfig.FailureIsFatal, "failing a validation is treated as a fatal error") BlockValidatorDangerousConfigAddOptions(prefix+".dangerous", f) f.String(prefix+".memory-free-limit", DefaultBlockValidatorConfig.MemoryFreeLimit, "minimum free-memory limit after reaching which the blockvalidator pauses validation. Enabled by default as 1GB, to disable provide empty string") + f.String(prefix+".block-inputs-file-path", DefaultBlockValidatorConfig.BlockInputsFilePath, "directory to write block validation inputs files") } func BlockValidatorDangerousConfigAddOptions(prefix string, f *pflag.FlagSet) { @@ -181,6 +185,7 @@ var DefaultBlockValidatorConfig = BlockValidatorConfig{ PendingUpgradeModuleRoot: "latest", FailureIsFatal: true, Dangerous: DefaultBlockValidatorDangerousConfig, + BlockInputsFilePath: "./target/validation_inputs", MemoryFreeLimit: "default", } @@ -196,6 +201,7 @@ var TestBlockValidatorConfig = BlockValidatorConfig{ PendingUpgradeModuleRoot: "latest", FailureIsFatal: true, Dangerous: DefaultBlockValidatorDangerousConfig, + BlockInputsFilePath: "./target/validation_inputs", MemoryFreeLimit: "default", } diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index c8842aedc4..c2704b89ab 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -463,6 +463,31 @@ func (v *StatelessBlockValidator) ValidateResult( return true, &entry.End, nil } +func (v *StatelessBlockValidator) RecordValidationInput(ctx context.Context, pos arbutil.MessageIndex, moduleRoot common.Hash) error { + entry, err := v.CreateReadyValidationEntry(ctx, pos) + if err != nil { + return err + } + found := false + for _, spawner := range v.execSpawners { + if validator.SpawnerSupportsModule(spawner, moduleRoot) { + found = true + input, err := entry.ToInput(spawner.StylusArchs()) + if err != nil { + return err + } + _, err = spawner.WriteToFile(input, entry.End, moduleRoot).Await(ctx) + if err != nil { + return err + } + } + } + if !found { + return fmt.Errorf("validation with WasmModuleRoot %v not supported by node", moduleRoot) + } + return nil +} + func (v *StatelessBlockValidator) OverrideRecorder(t *testing.T, recorder execution.ExecutionRecorder) { v.recorder = recorder } diff --git a/system_tests/program_norace_test.go b/system_tests/program_norace_test.go index 56b2046716..2ccd77c5b5 100644 --- a/system_tests/program_norace_test.go +++ b/system_tests/program_norace_test.go @@ -104,6 +104,19 @@ func validateBlockRange( } } +// recordBlock writes a json file with all of the data needed to validate a block. +// +// This can be used as an input to the arbitrator prover to validate a block. +func recordBlock(t *testing.T, block uint64, builder *NodeBuilder) { + t.Helper() + ctx := builder.ctx + wasmModuleRoot := currentRootModule(t) + inboxPos := arbutil.MessageIndex(block) + if err := builder.L2.ConsensusNode.StatelessBlockValidator.RecordValidationInput(ctx, inboxPos, wasmModuleRoot); err != nil { + Fatal(t, "failed to record block", block, err) + } +} + func TestProgramEvmData(t *testing.T) { t.Parallel() testEvmData(t, true) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 5fa5db95c2..1327c67ab7 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -368,7 +368,7 @@ func errorTest(t *testing.T, jit bool) { func TestProgramStorage(t *testing.T) { t.Parallel() - storageTest(t, true) + storageTest(t, false) } func storageTest(t *testing.T, jit bool) { @@ -390,10 +390,13 @@ func storageTest(t *testing.T, jit bool) { key := testhelpers.RandomHash() value := testhelpers.RandomHash() tx := l2info.PrepareTxTo("Owner", &programAddress, l2info.TransferGas, nil, argsForStorageWrite(key, value)) - ensure(tx, l2client.SendTransaction(ctx, tx)) + receipt := ensure(tx, l2client.SendTransaction(ctx, tx)) + assertStorageAt(t, ctx, l2client, programAddress, key, value) validateBlocks(t, 2, jit, builder) + recordBlock(t, 2, builder) + recordBlock(t, receipt.BlockNumber.Uint64(), builder) } func TestProgramTransientStorage(t *testing.T) { @@ -1143,6 +1146,7 @@ func testActivateFails(t *testing.T, jit bool) { }) validateBlockRange(t, []uint64{blockToValidate}, jit, builder) + recordBlock(t, blockToValidate, builder) } func TestProgramSdkStorage(t *testing.T) { diff --git a/validator/client/validation_client.go b/validator/client/validation_client.go index d6743b109e..91b0c71a79 100644 --- a/validator/client/validation_client.go +++ b/validator/client/validation_client.go @@ -181,11 +181,6 @@ func (c *ExecutionClient) LatestWasmModuleRoot() containers.PromiseInterface[com func (c *ExecutionClient) WriteToFile(input *validator.ValidationInput, expOut validator.GoGlobalState, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { jsonInput := server_api.ValidationInputToJson(input) - if err := jsonInput.WriteToFile(); err != nil { - return stopwaiter.LaunchPromiseThread[struct{}](c, func(ctx context.Context) (struct{}, error) { - return struct{}{}, err - }) - } return stopwaiter.LaunchPromiseThread[struct{}](c, func(ctx context.Context) (struct{}, error) { err := c.client.CallContext(ctx, nil, server_api.Namespace+"_writeToFile", jsonInput, expOut, moduleRoot) return struct{}{}, err diff --git a/validator/server_arb/validator_spawner.go b/validator/server_arb/validator_spawner.go index 1d4126dc7c..43ad7930b6 100644 --- a/validator/server_arb/validator_spawner.go +++ b/validator/server_arb/validator_spawner.go @@ -17,6 +17,7 @@ import ( "github.com/offchainlabs/nitro/util/containers" "github.com/offchainlabs/nitro/util/stopwaiter" "github.com/offchainlabs/nitro/validator" + "github.com/offchainlabs/nitro/validator/server_api" "github.com/offchainlabs/nitro/validator/server_common" "github.com/offchainlabs/nitro/validator/valnode/redis" @@ -187,6 +188,7 @@ func (v *ArbitratorSpawner) execute( } func (v *ArbitratorSpawner) Launch(entry *validator.ValidationInput, moduleRoot common.Hash) validator.ValidationRun { + println("LAUCHING ARBITRATOR VALIDATION") v.count.Add(1) promise := stopwaiter.LaunchPromiseThread[validator.GoGlobalState](v, func(ctx context.Context) (validator.GoGlobalState, error) { defer v.count.Add(-1) @@ -207,6 +209,10 @@ var launchTime = time.Now().Format("2006_01_02__15_04") //nolint:gosec func (v *ArbitratorSpawner) writeToFile(ctx context.Context, input *validator.ValidationInput, expOut validator.GoGlobalState, moduleRoot common.Hash) error { + jsonInput := server_api.ValidationInputToJson(input) + if err := jsonInput.WriteToFile(); err != nil { + return err + } outDirPath := filepath.Join(v.locator.RootPath(), v.config().OutputPath, launchTime, fmt.Sprintf("block_%d", input.Id)) err := os.MkdirAll(outDirPath, 0755) if err != nil { From 7113c52fe3fc3d4b9843466d0cc7a33df906e99f Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Wed, 7 Aug 2024 19:10:52 +0200 Subject: [PATCH 003/101] Fix the deserialization of the UserWasm data This change also: 1. Documents the `parse_inputs.rs` file in an attempt to give context to why the deserialization is special. 2. Hardcodes the architecture to `wasm` when recording ValidationInputs for use with the prover. Previously, the `jit` validator would use the go system architecture, and the `arbitrator` validator would use `wavm`. 3. Switches the `TestStorageProgram` test back to the `jit` validator. Note: As of this commit, there is still a small problem that when running the validator using the json inputs, it does not come up with the same end has as `entry.End.Hash`. --- arbitrator/prover/src/parse_input.rs | 51 ++++++++++++++++------------ arbitrator/prover/src/prepare.rs | 18 ++++------ staker/stateless_block_validator.go | 3 +- system_tests/program_test.go | 2 +- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/arbitrator/prover/src/parse_input.rs b/arbitrator/prover/src/parse_input.rs index 9af8652c96..fa7adb4c41 100644 --- a/arbitrator/prover/src/parse_input.rs +++ b/arbitrator/prover/src/parse_input.rs @@ -1,5 +1,5 @@ use arbutil::Bytes32; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use serde_json; use serde_with::base64::Base64; use serde_with::As; @@ -9,15 +9,14 @@ use std::{ io::{self, BufRead}, }; +/// prefixed_hex deserializes hex strings which are prefixed with `0x` +/// +/// The default hex deserializer does not support prefixed hex strings. +/// +/// It is an error to use this deserializer on a string that does not +/// begin with `0x`. mod prefixed_hex { - use serde::{self, Deserialize, Deserializer, Serializer}; - - pub fn serialize(bytes: &Vec, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&format!("0x{}", hex::encode(bytes))) - } + use serde::{self, Deserialize, Deserializer}; pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where @@ -32,23 +31,25 @@ mod prefixed_hex { } } -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct PreimageMap(HashMap>); - #[derive(Debug)] -pub struct UserWasm { - data: Vec, -} +pub struct UserWasm(Vec); +/// UserWasm is a wrapper around Vec +/// +/// It is useful for decompressing a brotli-compressed wasm module. +/// +/// Note: The wrapped Vec is already Base64 decoded before +/// from(Vec) is called by serde. impl UserWasm { + /// as_vec returns the decompressed wasm module as a Vec pub fn as_vec(&self) -> Vec { - self.data.clone() + self.0.clone() } } impl AsRef<[u8]> for UserWasm { fn as_ref(&self) -> &[u8] { - &self.data + &self.0 } } @@ -56,11 +57,11 @@ impl AsRef<[u8]> for UserWasm { impl From> for UserWasm { fn from(data: Vec) -> Self { let decompressed = brotli::decompress(&data, brotli::Dictionary::Empty).unwrap(); - Self { data: decompressed } + Self(decompressed) } } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct BatchInfo { pub number: u64, @@ -68,7 +69,7 @@ pub struct BatchInfo { pub data_b64: Vec, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct StartState { #[serde(with = "prefixed_hex")] @@ -79,6 +80,14 @@ pub struct StartState { pub pos_in_batch: u64, } +/// FileData is the deserialized form of the input JSON file. +/// +/// The go JSON library in json.go uses some custom serialization and +/// compression logic that needs to be reversed when deserializing the +/// JSON in rust. +/// +/// Note: It is important to change this file whenever the go JSON +/// serialization changes. #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct FileData { @@ -92,7 +101,7 @@ pub struct FileData { pub delayed_msg_b64: Vec, pub start_state: StartState, #[serde(with = "As::>>")] - pub user_wasms: HashMap>>, + pub user_wasms: HashMap>, } impl FileData { diff --git a/arbitrator/prover/src/prepare.rs b/arbitrator/prover/src/prepare.rs index 08bbd1476c..ecfb517735 100644 --- a/arbitrator/prover/src/prepare.rs +++ b/arbitrator/prover/src/prepare.rs @@ -5,7 +5,7 @@ use std::io::BufReader; use std::path::{Path, PathBuf}; use std::sync::Arc; -use crate::machine::{argument_data_to_inbox, GlobalState, Machine, Module}; +use crate::machine::{argument_data_to_inbox, GlobalState, Machine}; use crate::parse_input::*; use crate::utils::CBytes; @@ -40,17 +40,13 @@ pub fn prepare_machine(preimages: PathBuf, machines: PathBuf) -> eyre::Result Date: Wed, 7 Aug 2024 21:11:24 +0200 Subject: [PATCH 004/101] Print the End global state This makes it easier to visually confirm the expected outcome if a human is looking at the output of the prover and knows what the expected end global state should be. --- arbitrator/prover/src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arbitrator/prover/src/main.rs b/arbitrator/prover/src/main.rs index 002b693bd9..8c90ee44a4 100644 --- a/arbitrator/prover/src/main.rs +++ b/arbitrator/prover/src/main.rs @@ -344,6 +344,13 @@ fn main() -> Result<()> { }); } + println!( + "End GlobalState:\n BlockHash: {:?}\n SendRoot: {:?}\n Batch: {}\n PosInBatch: {}", + mach.get_global_state().bytes32_vals[0], + mach.get_global_state().bytes32_vals[1], + mach.get_global_state().u64_vals[0], + mach.get_global_state().u64_vals[1] + ); println!("End machine status: {:?}", mach.get_status()); println!("End machine hash: {}", mach.hash()); println!("End machine stack: {:?}", mach.get_data_stack()); From 3eed9bf6ec46cd81f6011778cef2ff03ba2040de Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Wed, 7 Aug 2024 21:15:47 +0200 Subject: [PATCH 005/101] Remove two calls to recordBlock The thrid one is left around as an example of how to use the new method. --- system_tests/program_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index a7eb94733d..29c5099912 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -395,7 +395,8 @@ func storageTest(t *testing.T, jit bool) { assertStorageAt(t, ctx, l2client, programAddress, key, value) validateBlocks(t, 2, jit, builder) - recordBlock(t, 2, builder) + // Captures a block_input_.json file for the block that included the + // storage write transaction. recordBlock(t, receipt.BlockNumber.Uint64(), builder) } @@ -1146,7 +1147,6 @@ func testActivateFails(t *testing.T, jit bool) { }) validateBlockRange(t, []uint64{blockToValidate}, jit, builder) - recordBlock(t, blockToValidate, builder) } func TestProgramSdkStorage(t *testing.T) { From ec7a386cd6364c4dcced822e452e74de3b49c7c5 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Thu, 8 Aug 2024 11:49:14 +0200 Subject: [PATCH 006/101] A few small changes bundled together in here. 1. Remove the part of the writeToFile method on ArbitratorSpawner which was writing the bash scripts. (TODO: Write the block_inputs_.json files somewhere better.) 2. Drop the expOut from the WriteToFile signature since none of the implementations need it any more. 3. Rename some unused function arguments to "_". --- arbitrator/bench/Cargo.toml | 4 - staker/block_validator.go | 2 +- staker/stateless_block_validator.go | 2 +- system_tests/validation_mock_test.go | 2 +- validator/client/validation_client.go | 4 +- validator/interface.go | 2 +- validator/server_arb/validator_spawner.go | 133 +--------------------- validator/server_jit/jit_machine.go | 2 +- validator/valnode/validation_api.go | 4 +- 9 files changed, 13 insertions(+), 142 deletions(-) diff --git a/arbitrator/bench/Cargo.toml b/arbitrator/bench/Cargo.toml index 284180dc46..74b948aca8 100644 --- a/arbitrator/bench/Cargo.toml +++ b/arbitrator/bench/Cargo.toml @@ -3,10 +3,6 @@ name = "bench" version = "0.1.0" edition = "2021" -[lib] -name = "bench" -path = "src/lib.rs" - [[bin]] name = "benchbin" path = "src/bin.rs" diff --git a/staker/block_validator.go b/staker/block_validator.go index 8d25ddf3c9..5d37cb17bd 100644 --- a/staker/block_validator.go +++ b/staker/block_validator.go @@ -496,7 +496,7 @@ func (v *BlockValidator) writeToFile(validationEntry *validationEntry, moduleRoo } for _, spawner := range v.execSpawners { if validator.SpawnerSupportsModule(spawner, moduleRoot) { - _, err = spawner.WriteToFile(input, validationEntry.End, moduleRoot).Await(v.GetContext()) + _, err = spawner.WriteToFile(input, moduleRoot).Await(v.GetContext()) return err } } diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index d19b1e2d1a..d97b02d340 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -477,7 +477,7 @@ func (v *StatelessBlockValidator) RecordValidationInput(ctx context.Context, pos if err != nil { return err } - _, err = spawner.WriteToFile(input, entry.End, moduleRoot).Await(ctx) + _, err = spawner.WriteToFile(input, moduleRoot).Await(ctx) if err != nil { return err } diff --git a/system_tests/validation_mock_test.go b/system_tests/validation_mock_test.go index 2c6321d009..48328d778e 100644 --- a/system_tests/validation_mock_test.go +++ b/system_tests/validation_mock_test.go @@ -95,7 +95,7 @@ func (s *mockSpawner) LatestWasmModuleRoot() containers.PromiseInterface[common. return containers.NewReadyPromise[common.Hash](mockWasmModuleRoots[0], nil) } -func (s *mockSpawner) WriteToFile(input *validator.ValidationInput, expOut validator.GoGlobalState, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { +func (s *mockSpawner) WriteToFile(input *validator.ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { return containers.NewReadyPromise[struct{}](struct{}{}, nil) } diff --git a/validator/client/validation_client.go b/validator/client/validation_client.go index 91b0c71a79..5a50a9525c 100644 --- a/validator/client/validation_client.go +++ b/validator/client/validation_client.go @@ -179,10 +179,10 @@ func (c *ExecutionClient) LatestWasmModuleRoot() containers.PromiseInterface[com }) } -func (c *ExecutionClient) WriteToFile(input *validator.ValidationInput, expOut validator.GoGlobalState, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { +func (c *ExecutionClient) WriteToFile(input *validator.ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { jsonInput := server_api.ValidationInputToJson(input) return stopwaiter.LaunchPromiseThread[struct{}](c, func(ctx context.Context) (struct{}, error) { - err := c.client.CallContext(ctx, nil, server_api.Namespace+"_writeToFile", jsonInput, expOut, moduleRoot) + err := c.client.CallContext(ctx, nil, server_api.Namespace+"_writeToFile", jsonInput, moduleRoot) return struct{}{}, err }) } diff --git a/validator/interface.go b/validator/interface.go index 80aa2c1fcc..96d3d2da18 100644 --- a/validator/interface.go +++ b/validator/interface.go @@ -26,7 +26,7 @@ type ExecutionSpawner interface { ValidationSpawner CreateExecutionRun(wasmModuleRoot common.Hash, input *ValidationInput) containers.PromiseInterface[ExecutionRun] LatestWasmModuleRoot() containers.PromiseInterface[common.Hash] - WriteToFile(input *ValidationInput, expOut GoGlobalState, moduleRoot common.Hash) containers.PromiseInterface[struct{}] + WriteToFile(input *ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] } type ExecutionRun interface { diff --git a/validator/server_arb/validator_spawner.go b/validator/server_arb/validator_spawner.go index 43ad7930b6..8df390514b 100644 --- a/validator/server_arb/validator_spawner.go +++ b/validator/server_arb/validator_spawner.go @@ -2,11 +2,8 @@ package server_arb import ( "context" - "encoding/binary" "errors" "fmt" - "os" - "path/filepath" "runtime" "sync/atomic" "time" @@ -97,7 +94,7 @@ func (s *ArbitratorSpawner) Name() string { return "arbitrator" } -func (v *ArbitratorSpawner) loadEntryToMachine(ctx context.Context, entry *validator.ValidationInput, mach *ArbitratorMachine) error { +func (v *ArbitratorSpawner) loadEntryToMachine(_ context.Context, entry *validator.ValidationInput, mach *ArbitratorMachine) error { resolver := func(ty arbutil.PreimageType, hash common.Hash) ([]byte, error) { // Check if it's a known preimage if preimage, ok := entry.Preimages[ty][hash]; ok { @@ -205,139 +202,17 @@ func (v *ArbitratorSpawner) Room() int { return avail } -var launchTime = time.Now().Format("2006_01_02__15_04") - -//nolint:gosec -func (v *ArbitratorSpawner) writeToFile(ctx context.Context, input *validator.ValidationInput, expOut validator.GoGlobalState, moduleRoot common.Hash) error { +func (v *ArbitratorSpawner) writeToFile(_ context.Context, input *validator.ValidationInput, _ common.Hash) error { jsonInput := server_api.ValidationInputToJson(input) if err := jsonInput.WriteToFile(); err != nil { return err } - outDirPath := filepath.Join(v.locator.RootPath(), v.config().OutputPath, launchTime, fmt.Sprintf("block_%d", input.Id)) - err := os.MkdirAll(outDirPath, 0755) - if err != nil { - return err - } - if ctx.Err() != nil { - return ctx.Err() - } - - rootPathAssign := "" - if executable, err := os.Executable(); err == nil { - rootPathAssign = "ROOTPATH=\"" + filepath.Dir(executable) + "\"\n" - } - cmdFile, err := os.OpenFile(filepath.Join(outDirPath, "run-prover.sh"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - return err - } - defer cmdFile.Close() - _, err = cmdFile.WriteString("#!/bin/bash\n" + - fmt.Sprintf("# expected output: batch %d, postion %d, hash %s\n", expOut.Batch, expOut.PosInBatch, expOut.BlockHash) + - "MACHPATH=\"" + v.locator.GetMachinePath(moduleRoot) + "\"\n" + - rootPathAssign + - "if (( $# > 1 )); then\n" + - " if [[ $1 == \"-m\" ]]; then\n" + - " MACHPATH=$2\n" + - " shift\n" + - " shift\n" + - " fi\n" + - "fi\n" + - "${ROOTPATH}/bin/prover ${MACHPATH}/replay.wasm") - if err != nil { - return err - } - if ctx.Err() != nil { - return ctx.Err() - } - - libraries := []string{"soft-float.wasm", "wasi_stub.wasm", "go_stub.wasm", "host_io.wasm", "brotli.wasm"} - for _, module := range libraries { - _, err = cmdFile.WriteString(" -l " + "${MACHPATH}/" + module) - if err != nil { - return err - } - } - _, err = cmdFile.WriteString(fmt.Sprintf(" --inbox-position %d --position-within-message %d --last-block-hash %s", input.StartState.Batch, input.StartState.PosInBatch, input.StartState.BlockHash)) - if err != nil { - return err - } - - for _, msg := range input.BatchInfo { - if ctx.Err() != nil { - return ctx.Err() - } - sequencerFileName := fmt.Sprintf("sequencer_%d.bin", msg.Number) - err = os.WriteFile(filepath.Join(outDirPath, sequencerFileName), msg.Data, 0644) - if err != nil { - return err - } - _, err = cmdFile.WriteString(" --inbox " + sequencerFileName) - if err != nil { - return err - } - } - - preimageFile, err := os.Create(filepath.Join(outDirPath, "preimages.bin")) - if err != nil { - return err - } - defer preimageFile.Close() - for ty, preimages := range input.Preimages { - _, err = preimageFile.Write([]byte{byte(ty)}) - if err != nil { - return err - } - for _, data := range preimages { - if ctx.Err() != nil { - return ctx.Err() - } - lenbytes := make([]byte, 8) - binary.LittleEndian.PutUint64(lenbytes, uint64(len(data))) - _, err := preimageFile.Write(lenbytes) - if err != nil { - return err - } - _, err = preimageFile.Write(data) - if err != nil { - return err - } - } - } - - _, err = cmdFile.WriteString(" --preimages preimages.bin") - if err != nil { - return err - } - - if input.HasDelayedMsg { - if ctx.Err() != nil { - return ctx.Err() - } - _, err = cmdFile.WriteString(fmt.Sprintf(" --delayed-inbox-position %d", input.DelayedMsgNr)) - if err != nil { - return err - } - filename := fmt.Sprintf("delayed_%d.bin", input.DelayedMsgNr) - err = os.WriteFile(filepath.Join(outDirPath, filename), input.DelayedMsg, 0644) - if err != nil { - return err - } - _, err = cmdFile.WriteString(fmt.Sprintf(" --delayed-inbox %s", filename)) - if err != nil { - return err - } - } - - _, err = cmdFile.WriteString(" \"$@\"\n") - if err != nil { - return err - } return nil } -func (v *ArbitratorSpawner) WriteToFile(input *validator.ValidationInput, expOut validator.GoGlobalState, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { +func (v *ArbitratorSpawner) WriteToFile(input *validator.ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { return stopwaiter.LaunchPromiseThread[struct{}](v, func(ctx context.Context) (struct{}, error) { - err := v.writeToFile(ctx, input, expOut, moduleRoot) + err := v.writeToFile(ctx, input, moduleRoot) return struct{}{}, err }) } diff --git a/validator/server_jit/jit_machine.go b/validator/server_jit/jit_machine.go index e4fb840cbb..5ba011727f 100644 --- a/validator/server_jit/jit_machine.go +++ b/validator/server_jit/jit_machine.go @@ -31,7 +31,7 @@ type JitMachine struct { wasmMemoryUsageLimit int } -func createJitMachine(jitBinary string, binaryPath string, cranelift bool, wasmMemoryUsageLimit int, moduleRoot common.Hash, fatalErrChan chan error) (*JitMachine, error) { +func createJitMachine(jitBinary string, binaryPath string, cranelift bool, wasmMemoryUsageLimit int, _ common.Hash, fatalErrChan chan error) (*JitMachine, error) { invocation := []string{"--binary", binaryPath, "--forks"} if cranelift { invocation = append(invocation, "--cranelift") diff --git a/validator/valnode/validation_api.go b/validator/valnode/validation_api.go index 6245ffc5e3..6561e7f0fd 100644 --- a/validator/valnode/validation_api.go +++ b/validator/valnode/validation_api.go @@ -117,12 +117,12 @@ func (a *ExecServerAPI) Start(ctx_in context.Context) { a.CallIteratively(a.removeOldRuns) } -func (a *ExecServerAPI) WriteToFile(ctx context.Context, jsonInput *server_api.InputJSON, expOut validator.GoGlobalState, moduleRoot common.Hash) error { +func (a *ExecServerAPI) WriteToFile(ctx context.Context, jsonInput *server_api.InputJSON, moduleRoot common.Hash) error { input, err := server_api.ValidationInputFromJson(jsonInput) if err != nil { return err } - _, err = a.execSpawner.WriteToFile(input, expOut, moduleRoot).Await(ctx) + _, err = a.execSpawner.WriteToFile(input, moduleRoot).Await(ctx) return err } From e9bf293ea30261981efe6d565dfd40457214530c Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Tue, 20 Aug 2024 10:42:26 -0400 Subject: [PATCH 007/101] Use the strongly-typed rawdb.Target --- staker/stateless_block_validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index 56e41a9c20..0a979ce96b 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -473,7 +473,7 @@ func (v *StatelessBlockValidator) RecordValidationInput(ctx context.Context, pos if validator.SpawnerSupportsModule(spawner, moduleRoot) { found = true // Hardcoded to use wavm so that it can be read by the prover. - input, err := entry.ToInput([]string{"wavm"}) + input, err := entry.ToInput([]rawdb.Target{rawdb.TargetWavm}) if err != nil { return err } From 39cd0a7a89159680b63fc07d30fa4831c55895b3 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Thu, 22 Aug 2024 11:04:16 -0400 Subject: [PATCH 008/101] Finish wiring the json file writing everywhere. At this point the location of the output file is hardcoded to be in the `$HOME/.arbitrum` directory. Hopefully, this will be okay. --- arbnode/api.go | 16 ++++++++++++++ staker/block_validator.go | 15 ++++++------- staker/stateless_block_validator.go | 27 ++++++----------------- system_tests/common_test.go | 17 ++++++++++++++ system_tests/program_norace_test.go | 13 ----------- system_tests/validation_mock_test.go | 4 ---- validator/client/validation_client.go | 8 ------- validator/interface.go | 1 - validator/server_api/json.go | 24 ++++++++++++++++++-- validator/server_arb/validator_spawner.go | 16 -------------- validator/valnode/validation_api.go | 9 -------- 11 files changed, 69 insertions(+), 81 deletions(-) diff --git a/arbnode/api.go b/arbnode/api.go index 228ad51cf8..27d3509d59 100644 --- a/arbnode/api.go +++ b/arbnode/api.go @@ -10,6 +10,7 @@ import ( "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/staker" "github.com/offchainlabs/nitro/validator" + "github.com/offchainlabs/nitro/validator/server_api" ) type BlockValidatorAPI struct { @@ -54,3 +55,18 @@ func (a *BlockValidatorDebugAPI) ValidateMessageNumber( result.Valid = valid return result, err } + +func (a *BlockValidatorDebugAPI) ValidationInputsAt(ctx context.Context, msgNum hexutil.Uint64, moduleRootOptional *common.Hash, +) (server_api.InputJSON, error) { + var moduleRoot common.Hash + if moduleRootOptional != nil { + moduleRoot = *moduleRootOptional + } else { + var err error + moduleRoot, err = a.val.GetLatestWasmModuleRoot(ctx) + if err != nil { + return server_api.InputJSON{}, fmt.Errorf("no latest WasmModuleRoot configured, must provide parameter: %w", err) + } + } + return a.val.ValidationInputsAt(ctx, arbutil.MessageIndex(msgNum), moduleRoot) +} diff --git a/staker/block_validator.go b/staker/block_validator.go index 4be65c8d1d..f91d91d2e5 100644 --- a/staker/block_validator.go +++ b/staker/block_validator.go @@ -29,6 +29,7 @@ import ( "github.com/offchainlabs/nitro/util/stopwaiter" "github.com/offchainlabs/nitro/validator" "github.com/offchainlabs/nitro/validator/client/redis" + "github.com/offchainlabs/nitro/validator/server_api" "github.com/spf13/pflag" ) @@ -504,18 +505,16 @@ func (v *BlockValidator) sendRecord(s *validationStatus) error { } //nolint:gosec -func (v *BlockValidator) writeToFile(validationEntry *validationEntry, moduleRoot common.Hash) error { +func (v *BlockValidator) writeToFile(validationEntry *validationEntry) error { input, err := validationEntry.ToInput([]rawdb.Target{rawdb.TargetWavm}) if err != nil { return err } - for _, spawner := range v.execSpawners { - if validator.SpawnerSupportsModule(spawner, moduleRoot) { - _, err = spawner.WriteToFile(input, moduleRoot).Await(v.GetContext()) - return err - } + inputJson := server_api.ValidationInputToJson(input) + if err := inputJson.WriteToFile("BlockValidator"); err != nil { + return err } - return errors.New("did not find exec spawner for wasmModuleRoot") + return nil } func (v *BlockValidator) SetCurrentWasmModuleRoot(hash common.Hash) error { @@ -783,7 +782,7 @@ validationsLoop: runEnd, err := run.Current() if err == nil && runEnd != validationStatus.Entry.End { err = fmt.Errorf("validation failed: expected %v got %v", validationStatus.Entry.End, runEnd) - writeErr := v.writeToFile(validationStatus.Entry, run.WasmModuleRoot()) + writeErr := v.writeToFile(validationStatus.Entry) if writeErr != nil { log.Warn("failed to write debug results file", "err", writeErr) } diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index 0a979ce96b..bb96e6f8c2 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -24,6 +24,7 @@ import ( "github.com/offchainlabs/nitro/util/rpcclient" "github.com/offchainlabs/nitro/validator" "github.com/offchainlabs/nitro/validator/client/redis" + "github.com/offchainlabs/nitro/validator/server_api" validatorclient "github.com/offchainlabs/nitro/validator/client" ) @@ -463,30 +464,16 @@ func (v *StatelessBlockValidator) ValidateResult( return true, &entry.End, nil } -func (v *StatelessBlockValidator) RecordValidationInput(ctx context.Context, pos arbutil.MessageIndex, moduleRoot common.Hash) error { +func (v *StatelessBlockValidator) ValidationInputsAt(ctx context.Context, pos arbutil.MessageIndex, moduleRoot common.Hash) (server_api.InputJSON, error) { entry, err := v.CreateReadyValidationEntry(ctx, pos) if err != nil { - return err + return server_api.InputJSON{}, err } - found := false - for _, spawner := range v.execSpawners { - if validator.SpawnerSupportsModule(spawner, moduleRoot) { - found = true - // Hardcoded to use wavm so that it can be read by the prover. - input, err := entry.ToInput([]rawdb.Target{rawdb.TargetWavm}) - if err != nil { - return err - } - _, err = spawner.WriteToFile(input, moduleRoot).Await(ctx) - if err != nil { - return err - } - } - } - if !found { - return fmt.Errorf("validation with WasmModuleRoot %v not supported by node", moduleRoot) + input, err := entry.ToInput([]rawdb.Target{rawdb.TargetWavm}) + if err != nil { + return server_api.InputJSON{}, err } - return nil + return *server_api.ValidationInputToJson(input), nil } func (v *StatelessBlockValidator) OverrideRecorder(t *testing.T, recorder execution.ExecutionRecorder) { diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 6e7375a921..53d17c762c 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -1459,6 +1459,23 @@ func logParser[T any](t *testing.T, source string, name string) func(*types.Log) } } +// recordBlock writes a json file with all of the data needed to validate a block. +// +// This can be used as an input to the arbitrator prover to validate a block. +func recordBlock(t *testing.T, block uint64, builder *NodeBuilder) { + t.Helper() + ctx := builder.ctx + wasmModuleRoot := currentRootModule(t) + inboxPos := arbutil.MessageIndex(block) + inputJson, err := builder.L2.ConsensusNode.StatelessBlockValidator.ValidationInputsAt(ctx, inboxPos, wasmModuleRoot) + if err != nil { + Fatal(t, "failed to get validation inputs", block, err) + } + if err := inputJson.WriteToFile(t.Name()); err != nil { + Fatal(t, "failed to write validation inputs", block, err) + } +} + func populateMachineDir(t *testing.T, cr *github.ConsensusRelease) string { baseDir := t.TempDir() machineDir := baseDir + "/machines" diff --git a/system_tests/program_norace_test.go b/system_tests/program_norace_test.go index 2ccd77c5b5..56b2046716 100644 --- a/system_tests/program_norace_test.go +++ b/system_tests/program_norace_test.go @@ -104,19 +104,6 @@ func validateBlockRange( } } -// recordBlock writes a json file with all of the data needed to validate a block. -// -// This can be used as an input to the arbitrator prover to validate a block. -func recordBlock(t *testing.T, block uint64, builder *NodeBuilder) { - t.Helper() - ctx := builder.ctx - wasmModuleRoot := currentRootModule(t) - inboxPos := arbutil.MessageIndex(block) - if err := builder.L2.ConsensusNode.StatelessBlockValidator.RecordValidationInput(ctx, inboxPos, wasmModuleRoot); err != nil { - Fatal(t, "failed to record block", block, err) - } -} - func TestProgramEvmData(t *testing.T) { t.Parallel() testEvmData(t, true) diff --git a/system_tests/validation_mock_test.go b/system_tests/validation_mock_test.go index b854ec1cb3..ddf0f4c3aa 100644 --- a/system_tests/validation_mock_test.go +++ b/system_tests/validation_mock_test.go @@ -96,10 +96,6 @@ func (s *mockSpawner) LatestWasmModuleRoot() containers.PromiseInterface[common. return containers.NewReadyPromise[common.Hash](mockWasmModuleRoots[0], nil) } -func (s *mockSpawner) WriteToFile(input *validator.ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { - return containers.NewReadyPromise[struct{}](struct{}{}, nil) -} - type mockValRun struct { containers.Promise[validator.GoGlobalState] root common.Hash diff --git a/validator/client/validation_client.go b/validator/client/validation_client.go index 01e0684d70..8372731e06 100644 --- a/validator/client/validation_client.go +++ b/validator/client/validation_client.go @@ -186,14 +186,6 @@ func (c *ExecutionClient) LatestWasmModuleRoot() containers.PromiseInterface[com }) } -func (c *ExecutionClient) WriteToFile(input *validator.ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { - jsonInput := server_api.ValidationInputToJson(input) - return stopwaiter.LaunchPromiseThread[struct{}](c, func(ctx context.Context) (struct{}, error) { - err := c.client.CallContext(ctx, nil, server_api.Namespace+"_writeToFile", jsonInput, moduleRoot) - return struct{}{}, err - }) -} - func (r *ExecutionClientRun) SendKeepAlive(ctx context.Context) time.Duration { err := r.client.client.CallContext(ctx, nil, server_api.Namespace+"_execKeepAlive", r.id) if err != nil { diff --git a/validator/interface.go b/validator/interface.go index 8c2991364a..4e759545e0 100644 --- a/validator/interface.go +++ b/validator/interface.go @@ -27,7 +27,6 @@ type ExecutionSpawner interface { ValidationSpawner CreateExecutionRun(wasmModuleRoot common.Hash, input *ValidationInput) containers.PromiseInterface[ExecutionRun] LatestWasmModuleRoot() containers.PromiseInterface[common.Hash] - WriteToFile(input *ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] } type ExecutionRun interface { diff --git a/validator/server_api/json.go b/validator/server_api/json.go index dbe2bb1fee..069ab014d9 100644 --- a/validator/server_api/json.go +++ b/validator/server_api/json.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "os" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -68,12 +69,31 @@ type InputJSON struct { DebugChain bool } -func (i *InputJSON) WriteToFile() error { +// WriteToFile writes the InputJSON to a file in JSON format. +// +// The path to the file is determined in part by the slug parameter so +// callers can provide a recognizable name to differentiate various +// contexts in which the InputJSON is being written. +// +// The file is created at a path +// +// $HOME/.arbuitrum/validation-inputs///block_inputs_.json +func (i *InputJSON) WriteToFile(slug string) error { + homeDir, err := os.UserHomeDir() + if err != nil { + return err + } + t := time.Now() + tStr := t.Format("20060102_150405") + dir := fmt.Sprintf("%s/.arbitrum/validation-inputs/%s/%s", homeDir, slug, tStr) + if err = os.MkdirAll(dir, 0700); err != nil { + return err + } contents, err := json.MarshalIndent(i, "", " ") if err != nil { return err } - if err = os.WriteFile(fmt.Sprintf("block_inputs_%d.json", i.Id), contents, 0600); err != nil { + if err = os.WriteFile(fmt.Sprintf("%s/block_inputs_%d.json", dir, i.Id), contents, 0600); err != nil { return err } return nil diff --git a/validator/server_arb/validator_spawner.go b/validator/server_arb/validator_spawner.go index ae8c8be9ab..74cf77fdf5 100644 --- a/validator/server_arb/validator_spawner.go +++ b/validator/server_arb/validator_spawner.go @@ -14,7 +14,6 @@ import ( "github.com/offchainlabs/nitro/util/containers" "github.com/offchainlabs/nitro/util/stopwaiter" "github.com/offchainlabs/nitro/validator" - "github.com/offchainlabs/nitro/validator/server_api" "github.com/offchainlabs/nitro/validator/server_common" "github.com/offchainlabs/nitro/validator/valnode/redis" @@ -203,21 +202,6 @@ func (v *ArbitratorSpawner) Room() int { return avail } -func (v *ArbitratorSpawner) writeToFile(_ context.Context, input *validator.ValidationInput, _ common.Hash) error { - jsonInput := server_api.ValidationInputToJson(input) - if err := jsonInput.WriteToFile(); err != nil { - return err - } - return nil -} - -func (v *ArbitratorSpawner) WriteToFile(input *validator.ValidationInput, moduleRoot common.Hash) containers.PromiseInterface[struct{}] { - return stopwaiter.LaunchPromiseThread[struct{}](v, func(ctx context.Context) (struct{}, error) { - err := v.writeToFile(ctx, input, moduleRoot) - return struct{}{}, err - }) -} - func (v *ArbitratorSpawner) CreateExecutionRun(wasmModuleRoot common.Hash, input *validator.ValidationInput) containers.PromiseInterface[validator.ExecutionRun] { getMachine := func(ctx context.Context) (MachineInterface, error) { initialFrozenMachine, err := v.machineLoader.GetZeroStepMachine(ctx, wasmModuleRoot) diff --git a/validator/valnode/validation_api.go b/validator/valnode/validation_api.go index 68d357695b..c36d8ee62c 100644 --- a/validator/valnode/validation_api.go +++ b/validator/valnode/validation_api.go @@ -118,15 +118,6 @@ func (a *ExecServerAPI) Start(ctx_in context.Context) { a.CallIteratively(a.removeOldRuns) } -func (a *ExecServerAPI) WriteToFile(ctx context.Context, jsonInput *server_api.InputJSON, moduleRoot common.Hash) error { - input, err := server_api.ValidationInputFromJson(jsonInput) - if err != nil { - return err - } - _, err = a.execSpawner.WriteToFile(input, moduleRoot).Await(ctx) - return err -} - var errRunNotFound error = errors.New("run not found") func (a *ExecServerAPI) getRun(id uint64) (validator.ExecutionRun, error) { From 1a353b21ccc4a52f35ee0df69ba135a304a1ba17 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Fri, 23 Aug 2024 15:18:23 +0000 Subject: [PATCH 009/101] Add a hacky sleep Reviewers, please tell me the "right" way to ensure that the transaction is visible in the L1. I don't like the idea of adding sleeps in tests to ensure that some event has occurred. Is there some RPC I can call or event I can subscribe to that I can then wait for before proceeding? --- system_tests/program_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index bb6e34ec4f..9392de0c4d 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -394,6 +394,9 @@ func storageTest(t *testing.T, jit bool) { assertStorageAt(t, ctx, l2client, programAddress, key, value) validateBlocks(t, 2, jit, builder) + // Without this sleep, this test fails in the "-race" CI builds complaining that + // the block has not been seen in L1 yet. + time.Sleep(10 * time.Second) // Captures a block_input_.json file for the block that included the // storage write transaction. recordBlock(t, receipt.BlockNumber.Uint64(), builder) From bd234b8f67a799562dfea6c6aea16ddda3f07968 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Tue, 27 Aug 2024 20:51:54 -0500 Subject: [PATCH 010/101] Fix spurious refund error log to just be debug --- arbos/tx_processor.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arbos/tx_processor.go b/arbos/tx_processor.go index b08c7c5d30..ec37a61e04 100644 --- a/arbos/tx_processor.go +++ b/arbos/tx_processor.go @@ -532,6 +532,16 @@ func (p *TxProcessor) EndTxHook(gasLeft uint64, success bool) { refund := func(refundFrom common.Address, amount *big.Int) { const errLog = "fee address doesn't have enough funds to give user refund" + logMissingRefund := func(err error) { + logLevel := log.Error + isContract := p.evm.StateDB.GetCodeSize(refundFrom) > 0 + if isContract { + // It's expected that the balance might not still be in this address if it's a contract. + logLevel = log.Debug + } + logLevel(errLog, "err", err, "feeAddress", refundFrom) + } + // Refund funds to the fee refund address without overdrafting the L1 deposit. toRefundAddr := takeFunds(maxRefund, amount) err = util.TransferBalance(&refundFrom, &inner.RefundTo, toRefundAddr, p.evm, scenario, "refund") @@ -539,13 +549,13 @@ func (p *TxProcessor) EndTxHook(gasLeft uint64, success bool) { // Normally the network fee address should be holding any collected fees. // However, in theory, they could've been transferred out during the redeem attempt. // If the network fee address doesn't have the necessary balance, log an error and don't give a refund. - log.Error(errLog, "err", err, "feeAddress", refundFrom) + logMissingRefund(err) } // Any extra refund can't be given to the fee refund address if it didn't come from the L1 deposit. // Instead, give the refund to the retryable from address. err = util.TransferBalance(&refundFrom, &inner.From, arbmath.BigSub(amount, toRefundAddr), p.evm, scenario, "refund") if err != nil { - log.Error(errLog, "err", err, "feeAddress", refundFrom) + logMissingRefund(err) } } From 25af47fcc1ffb06285a87d61a8cfe0cc0c5f92a3 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Thu, 29 Aug 2024 13:43:15 +0200 Subject: [PATCH 011/101] Ensure the inbox tracker has the desired message. If the inbox is lagging behind the message, the node won't be able to create a validation entry for it. --- system_tests/common_test.go | 10 ++++++++++ system_tests/program_test.go | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 53d17c762c..7f8864ff94 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -1467,6 +1467,16 @@ func recordBlock(t *testing.T, block uint64, builder *NodeBuilder) { ctx := builder.ctx wasmModuleRoot := currentRootModule(t) inboxPos := arbutil.MessageIndex(block) + for { + time.Sleep(250 * time.Millisecond) + batches, err := builder.L2.ConsensusNode.InboxTracker.GetBatchCount() + Require(t, err) + haveMessages, err := builder.L2.ConsensusNode.InboxTracker.GetBatchMessageCount(batches - 1) + Require(t, err) + if haveMessages >= inboxPos { + break + } + } inputJson, err := builder.L2.ConsensusNode.StatelessBlockValidator.ValidationInputsAt(ctx, inboxPos, wasmModuleRoot) if err != nil { Fatal(t, "failed to get validation inputs", block, err) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 023d88a380..c5de186978 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -396,7 +396,8 @@ func storageTest(t *testing.T, jit bool) { validateBlocks(t, 2, jit, builder) // Without this sleep, this test fails in the "-race" CI builds complaining that // the block has not been seen in L1 yet. - time.Sleep(10 * time.Second) + // time.Sleep(10 * time.Second) + // Captures a block_input_.json file for the block that included the // storage write transaction. recordBlock(t, receipt.BlockNumber.Uint64(), builder) From e0d70e6aeddb02606689812dff8a92ae16c009f8 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Thu, 29 Aug 2024 13:45:07 +0200 Subject: [PATCH 012/101] Remove commented out code. Meant to do this in the previous commit. --- system_tests/program_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index c5de186978..9b3dd56ffb 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -394,9 +394,6 @@ func storageTest(t *testing.T, jit bool) { assertStorageAt(t, ctx, l2client, programAddress, key, value) validateBlocks(t, 2, jit, builder) - // Without this sleep, this test fails in the "-race" CI builds complaining that - // the block has not been seen in L1 yet. - // time.Sleep(10 * time.Second) // Captures a block_input_.json file for the block that included the // storage write transaction. From bc25dde884f0c473c72a41cff01ba2b248ef3415 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Thu, 29 Aug 2024 15:35:05 +0200 Subject: [PATCH 013/101] Separate the writer for validaiton inputs from the json. This change attempts to make the location for writing the json file more flexibly configurable by the clients without making it difficult to put the data in a resonable spot by default. --- staker/block_validator.go | 11 ++- system_tests/common_test.go | 6 +- validator/inputs/writer.go | 129 ++++++++++++++++++++++++++++++++ validator/inputs/writer_test.go | 87 +++++++++++++++++++++ validator/server_api/json.go | 33 +------- 5 files changed, 234 insertions(+), 32 deletions(-) create mode 100644 validator/inputs/writer.go create mode 100644 validator/inputs/writer_test.go diff --git a/staker/block_validator.go b/staker/block_validator.go index a7e475b4f0..a884ac81f7 100644 --- a/staker/block_validator.go +++ b/staker/block_validator.go @@ -29,6 +29,7 @@ import ( "github.com/offchainlabs/nitro/util/stopwaiter" "github.com/offchainlabs/nitro/validator" "github.com/offchainlabs/nitro/validator/client/redis" + "github.com/offchainlabs/nitro/validator/inputs" "github.com/offchainlabs/nitro/validator/server_api" "github.com/spf13/pflag" ) @@ -95,6 +96,9 @@ type BlockValidator struct { // for testing only testingProgressMadeChan chan struct{} + // For troubleshooting failed validations + validationInputsWriter *inputs.Writer + fatalErr chan<- error MemoryFreeLimitChecker resourcemanager.LimitChecker @@ -275,6 +279,11 @@ func NewBlockValidator( config: config, fatalErr: fatalErr, } + valInputsWriter, err := inputs.NewWriter() + if err != nil { + return nil, err + } + ret.validationInputsWriter = valInputsWriter.SetSlug("BlockValidator") if !config().Dangerous.ResetBlockValidation { validated, err := ret.ReadLastValidatedInfo() if err != nil { @@ -512,7 +521,7 @@ func (v *BlockValidator) writeToFile(validationEntry *validationEntry) error { return err } inputJson := server_api.ValidationInputToJson(input) - if err := inputJson.WriteToFile("BlockValidator"); err != nil { + if err := v.validationInputsWriter.Write(inputJson); err != nil { return err } return nil diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 7f8864ff94..17834b429d 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -36,6 +36,7 @@ import ( "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/util/redisutil" "github.com/offchainlabs/nitro/util/signature" + "github.com/offchainlabs/nitro/validator/inputs" "github.com/offchainlabs/nitro/validator/server_api" "github.com/offchainlabs/nitro/validator/server_common" "github.com/offchainlabs/nitro/validator/valnode" @@ -1477,11 +1478,14 @@ func recordBlock(t *testing.T, block uint64, builder *NodeBuilder) { break } } + validationInputsWriter, err := inputs.NewWriter() + Require(t, err) + validationInputsWriter.SetSlug(t.Name()) inputJson, err := builder.L2.ConsensusNode.StatelessBlockValidator.ValidationInputsAt(ctx, inboxPos, wasmModuleRoot) if err != nil { Fatal(t, "failed to get validation inputs", block, err) } - if err := inputJson.WriteToFile(t.Name()); err != nil { + if err := validationInputsWriter.Write(&inputJson); err != nil { Fatal(t, "failed to write validation inputs", block, err) } } diff --git a/validator/inputs/writer.go b/validator/inputs/writer.go new file mode 100644 index 0000000000..b8160a4fa5 --- /dev/null +++ b/validator/inputs/writer.go @@ -0,0 +1,129 @@ +package inputs + +import ( + "fmt" + "os" + "time" + + "github.com/offchainlabs/nitro/validator/server_api" +) + +// Writer is a configurable writer of InputJSON files. +// +// The default Writer will write to a path like: +// +// $HOME/.arbuitrum/validation-inputs//block_inputs_.json +// +// The path can be nested under a slug directory so callers can provide a +// recognizable name to differentiate various contexts in which the InputJSON +// is being written. If the Writer is configured by calling SetSlug, then the +// path will be like: +// +// $HOME/.arbuitrum/validation-inputs///block_inputs_.json +// +// The inclusion of a timestamp directory is on by default to avoid conflicts which +// would result in files being overwritten. However, the Writer can be configured +// to not use a timestamp directory. If the Writer is configured by calling +// SetUseTimestampDir(false), then the path will be like: +// +// $HOME/.arbuitrum/validation-inputs//block_inputs_.json +// +// Finally, to give complete control to the clients, the base directory can be +// set directly with SetBaseDir. In which case, the path will be like: +// +// /block_inputs_.json +// or +// //block_inputs_.json +// or +// ///block_inputs_.json +type Writer struct { + clock Clock + baseDir string + slug string + useTimestampDir bool +} + +// Clock is an interface for getting the current time. +type Clock interface { + Now() time.Time +} + +type realClock struct{} + +func (realClock) Now() time.Time { + return time.Now() +} + +// NewWriter creates a new Writer with default settings. +func NewWriter() (*Writer, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return nil, err + } + baseDir := fmt.Sprintf("%s/.arbitrum/validation-inputs", homeDir) + return &Writer{ + clock: realClock{}, + baseDir: baseDir, + slug: "", + useTimestampDir: true}, nil +} + +// SetClockForTesting sets the clock used by the Writer. +// +// This is only intended for testing. +func (w *Writer) SetClockForTesting(clock Clock) *Writer { + w.clock = clock + return w +} + +// SetSlug configures the Writer to use the given slug as a directory name. +func (w *Writer) SetSlug(slug string) *Writer { + w.slug = slug + return w +} + +// ClearSlug clears the slug configuration. +// +// This is equivalent to calling SetSlug("") but is more readable. +func (w *Writer) ClearSlug() *Writer { + w.slug = "" + return w +} + +// SetBaseDir configures the Writer to use the given base directory. +func (w *Writer) SetBaseDir(baseDir string) *Writer { + w.baseDir = baseDir + return w +} + +// SetUseTimestampDir controls the addition of a timestamp directory. +func (w *Writer) SetUseTimestampDir(useTimestampDir bool) *Writer { + w.useTimestampDir = useTimestampDir + return w +} + +// Write writes the given InputJSON to a file in JSON format. +func (w *Writer) Write(inputs *server_api.InputJSON) error { + dir := w.baseDir + if w.slug != "" { + dir = fmt.Sprintf("%s/%s", dir, w.slug) + } + if w.useTimestampDir { + t := w.clock.Now() + tStr := t.Format("20060102_150405") + dir = fmt.Sprintf("%s/%s", dir, tStr) + } + if err := os.MkdirAll(dir, 0700); err != nil { + return err + } + contents, err := inputs.Marshal() + if err != nil { + return err + } + if err = os.WriteFile( + fmt.Sprintf("%s/block_inputs_%d.json", dir, inputs.Id), + contents, 0600); err != nil { + return err + } + return nil +} diff --git a/validator/inputs/writer_test.go b/validator/inputs/writer_test.go new file mode 100644 index 0000000000..5e80b9aa3a --- /dev/null +++ b/validator/inputs/writer_test.go @@ -0,0 +1,87 @@ +package inputs + +import ( + "os" + "testing" + "time" + + "github.com/offchainlabs/nitro/validator/server_api" +) + +func TestDefaultBaseDir(t *testing.T) { + // Simply testing that the default baseDir is set relative to the user's home directory. + // This way, the other tests can all override the baseDir to a temporary directory. + w, err := NewWriter() + if err != nil { + t.Fatal(err) + } + homeDir, err := os.UserHomeDir() + if err != nil { + t.Fatal(err) + } + if w.baseDir != homeDir+"/.arbitrum/validation-inputs" { + t.Errorf("unexpected baseDir: %v", w.baseDir) + } +} + +type fakeClock struct { + now time.Time +} + +func (c fakeClock) Now() time.Time { + return c.now +} + +func TestWriting(t *testing.T) { + w, err := NewWriter() + if err != nil { + t.Fatal(err) + } + w.SetClockForTesting(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}) + dir := t.TempDir() + w.SetBaseDir(dir) + err = w.Write(&server_api.InputJSON{Id: 24601}) + if err != nil { + t.Fatal(err) + } + // The file should exist. + if _, err := os.Stat(dir + "/20210102_030405/block_inputs_24601.json"); err != nil { + t.Error(err) + } +} + +func TestWritingWithSlug(t *testing.T) { + w, err := NewWriter() + if err != nil { + t.Fatal(err) + } + w.SetClockForTesting(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}) + dir := t.TempDir() + w.SetBaseDir(dir).SetSlug("foo") + err = w.Write(&server_api.InputJSON{Id: 24601}) + if err != nil { + t.Fatal(err) + } + // The file should exist. + if _, err := os.Stat(dir + "/foo/20210102_030405/block_inputs_24601.json"); err != nil { + t.Error(err) + } +} + +func TestWritingWithoutTimestampDir(t *testing.T) { + w, err := NewWriter() + if err != nil { + t.Fatal(err) + } + w.SetClockForTesting(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}) + dir := t.TempDir() + w.SetBaseDir(dir).SetUseTimestampDir(false) + err = w.Write(&server_api.InputJSON{Id: 24601}) + if err != nil { + t.Fatal(err) + } + // The file should exist. + if _, err := os.Stat(dir + "/block_inputs_24601.json"); err != nil { + t.Error(err) + } +} diff --git a/validator/server_api/json.go b/validator/server_api/json.go index 069ab014d9..bdb19bc0ba 100644 --- a/validator/server_api/json.go +++ b/validator/server_api/json.go @@ -8,8 +8,6 @@ import ( "encoding/json" "errors" "fmt" - "os" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -69,34 +67,9 @@ type InputJSON struct { DebugChain bool } -// WriteToFile writes the InputJSON to a file in JSON format. -// -// The path to the file is determined in part by the slug parameter so -// callers can provide a recognizable name to differentiate various -// contexts in which the InputJSON is being written. -// -// The file is created at a path -// -// $HOME/.arbuitrum/validation-inputs///block_inputs_.json -func (i *InputJSON) WriteToFile(slug string) error { - homeDir, err := os.UserHomeDir() - if err != nil { - return err - } - t := time.Now() - tStr := t.Format("20060102_150405") - dir := fmt.Sprintf("%s/.arbitrum/validation-inputs/%s/%s", homeDir, slug, tStr) - if err = os.MkdirAll(dir, 0700); err != nil { - return err - } - contents, err := json.MarshalIndent(i, "", " ") - if err != nil { - return err - } - if err = os.WriteFile(fmt.Sprintf("%s/block_inputs_%d.json", dir, i.Id), contents, 0600); err != nil { - return err - } - return nil +// Marshal returns the JSON encoding of the InputJSON. +func (i *InputJSON) Marshal() ([]byte, error) { + return json.MarshalIndent(i, "", " ") } type BatchInfoJson struct { From 1ae0aff868abd8d4347433d0eef6846dfa0a2a99 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 29 Aug 2024 23:06:37 -0500 Subject: [PATCH 014/101] Check error type --- arbos/tx_processor.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arbos/tx_processor.go b/arbos/tx_processor.go index ec37a61e04..d6c35339f6 100644 --- a/arbos/tx_processor.go +++ b/arbos/tx_processor.go @@ -533,6 +533,10 @@ func (p *TxProcessor) EndTxHook(gasLeft uint64, success bool) { const errLog = "fee address doesn't have enough funds to give user refund" logMissingRefund := func(err error) { + if !errors.Is(err, vm.ErrInsufficientBalance) { + log.Error("unexpected error refunding balance", "err", err, "feeAddress", refundFrom) + return + } logLevel := log.Error isContract := p.evm.StateDB.GetCodeSize(refundFrom) > 0 if isContract { From 1468088c84ef1ff1b0fd4c852a3fd3517c852f2c Mon Sep 17 00:00:00 2001 From: Ganesh Vanahalli Date: Fri, 6 Sep 2024 17:48:57 +0530 Subject: [PATCH 015/101] Remove L1 interface and use *ethclient.Client instead --- arbnode/delayed.go | 5 ++-- arbnode/inbox_reader.go | 5 ++-- arbnode/inbox_tracker.go | 5 ++-- arbnode/node.go | 5 ++-- arbnode/sequencer_inbox.go | 9 ++++--- arbutil/correspondingl1blocknumber.go | 6 ++++- arbutil/transaction_data.go | 5 ++-- arbutil/wait_for_l1.go | 9 ++++--- cmd/nitro/init.go | 4 +-- cmd/pruning/pruning.go | 5 ++-- das/aggregator.go | 4 +-- das/chain_fetch_das.go | 4 +-- das/factory.go | 4 +-- das/rpc_aggregator.go | 4 +-- das/syncing_fallback_storage.go | 3 ++- execution/gethexec/node.go | 3 ++- staker/l1_validator.go | 5 ++-- staker/rollup_watcher.go | 10 ++++++-- staker/staker.go | 3 ++- staker/txbuilder/builder.go | 10 ++++---- staker/validatorwallet/contract.go | 4 +-- staker/validatorwallet/eoa.go | 8 +++--- staker/validatorwallet/noop.go | 8 +++--- system_tests/common_test.go | 32 +++++++++++------------- system_tests/das_test.go | 3 +-- system_tests/full_challenge_impl_test.go | 5 ++-- system_tests/wrap_transaction_test.go | 13 +++++----- util/headerreader/blob_client.go | 6 ++--- util/headerreader/header_reader.go | 7 +++--- 29 files changed, 107 insertions(+), 87 deletions(-) diff --git a/arbnode/delayed.go b/arbnode/delayed.go index c166aa2b90..aba5832146 100644 --- a/arbnode/delayed.go +++ b/arbnode/delayed.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbutil" @@ -58,11 +59,11 @@ type DelayedBridge struct { con *bridgegen.IBridge address common.Address fromBlock uint64 - client arbutil.L1Interface + client *ethclient.Client messageProviders map[common.Address]*bridgegen.IDelayedMessageProvider } -func NewDelayedBridge(client arbutil.L1Interface, addr common.Address, fromBlock uint64) (*DelayedBridge, error) { +func NewDelayedBridge(client *ethclient.Client, addr common.Address, fromBlock uint64) (*DelayedBridge, error) { con, err := bridgegen.NewIBridge(addr, client) if err != nil { return nil, err diff --git a/arbnode/inbox_reader.go b/arbnode/inbox_reader.go index fd050b5f67..f8e48bffd6 100644 --- a/arbnode/inbox_reader.go +++ b/arbnode/inbox_reader.go @@ -14,6 +14,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" flag "github.com/spf13/pflag" @@ -93,7 +94,7 @@ type InboxReader struct { delayedBridge *DelayedBridge sequencerInbox *SequencerInbox caughtUpChan chan struct{} - client arbutil.L1Interface + client *ethclient.Client l1Reader *headerreader.HeaderReader // Atomic @@ -101,7 +102,7 @@ type InboxReader struct { lastReadBatchCount atomic.Uint64 } -func NewInboxReader(tracker *InboxTracker, client arbutil.L1Interface, l1Reader *headerreader.HeaderReader, firstMessageBlock *big.Int, delayedBridge *DelayedBridge, sequencerInbox *SequencerInbox, config InboxReaderConfigFetcher) (*InboxReader, error) { +func NewInboxReader(tracker *InboxTracker, client *ethclient.Client, l1Reader *headerreader.HeaderReader, firstMessageBlock *big.Int, delayedBridge *DelayedBridge, sequencerInbox *SequencerInbox, config InboxReaderConfigFetcher) (*InboxReader, error) { err := config().Validate() if err != nil { return nil, err diff --git a/arbnode/inbox_tracker.go b/arbnode/inbox_tracker.go index fe4149c80e..7686fe413f 100644 --- a/arbnode/inbox_tracker.go +++ b/arbnode/inbox_tracker.go @@ -13,6 +13,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -599,7 +600,7 @@ type multiplexerBackend struct { positionWithinMessage uint64 ctx context.Context - client arbutil.L1Interface + client *ethclient.Client inbox *InboxTracker } @@ -639,7 +640,7 @@ func (b *multiplexerBackend) ReadDelayedInbox(seqNum uint64) (*arbostypes.L1Inco var delayedMessagesMismatch = errors.New("sequencer batch delayed messages missing or different") -func (t *InboxTracker) AddSequencerBatches(ctx context.Context, client arbutil.L1Interface, batches []*SequencerInboxBatch) error { +func (t *InboxTracker) AddSequencerBatches(ctx context.Context, client *ethclient.Client, batches []*SequencerInboxBatch) error { var nextAcc common.Hash var prevbatchmeta BatchMetadata sequenceNumberToKeep := uint64(0) diff --git a/arbnode/node.go b/arbnode/node.go index a9da4ea24b..c5b3bbe071 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -18,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -407,7 +408,7 @@ func createNodeImpl( arbDb ethdb.Database, configFetcher ConfigFetcher, l2Config *params.ChainConfig, - l1client arbutil.L1Interface, + l1client *ethclient.Client, deployInfo *chaininfo.RollupAddresses, txOptsValidator *bind.TransactOpts, txOptsBatchPoster *bind.TransactOpts, @@ -781,7 +782,7 @@ func CreateNode( arbDb ethdb.Database, configFetcher ConfigFetcher, l2Config *params.ChainConfig, - l1client arbutil.L1Interface, + l1client *ethclient.Client, deployInfo *chaininfo.RollupAddresses, txOptsValidator *bind.TransactOpts, txOptsBatchPoster *bind.TransactOpts, diff --git a/arbnode/sequencer_inbox.go b/arbnode/sequencer_inbox.go index 73e52ded53..81146ed46e 100644 --- a/arbnode/sequencer_inbox.go +++ b/arbnode/sequencer_inbox.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/offchainlabs/nitro/arbstate/daprovider" "github.com/offchainlabs/nitro/arbutil" @@ -52,10 +53,10 @@ type SequencerInbox struct { con *bridgegen.SequencerInbox address common.Address fromBlock int64 - client arbutil.L1Interface + client *ethclient.Client } -func NewSequencerInbox(client arbutil.L1Interface, addr common.Address, fromBlock int64) (*SequencerInbox, error) { +func NewSequencerInbox(client *ethclient.Client, addr common.Address, fromBlock int64) (*SequencerInbox, error) { con, err := bridgegen.NewSequencerInbox(addr, client) if err != nil { return nil, err @@ -111,7 +112,7 @@ type SequencerInboxBatch struct { serialized []byte // nil if serialization isn't cached yet } -func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client arbutil.L1Interface) ([]byte, error) { +func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client *ethclient.Client) ([]byte, error) { switch m.dataLocation { case batchDataTxInput: data, err := arbutil.GetLogEmitterTxData(ctx, client, m.rawLog) @@ -169,7 +170,7 @@ func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client arbut } } -func (m *SequencerInboxBatch) Serialize(ctx context.Context, client arbutil.L1Interface) ([]byte, error) { +func (m *SequencerInboxBatch) Serialize(ctx context.Context, client *ethclient.Client) ([]byte, error) { if m.serialized != nil { return m.serialized, nil } diff --git a/arbutil/correspondingl1blocknumber.go b/arbutil/correspondingl1blocknumber.go index d654e471e2..c8770e2034 100644 --- a/arbutil/correspondingl1blocknumber.go +++ b/arbutil/correspondingl1blocknumber.go @@ -19,7 +19,11 @@ func ParentHeaderToL1BlockNumber(header *types.Header) uint64 { return header.Number.Uint64() } -func CorrespondingL1BlockNumber(ctx context.Context, client L1Interface, parentBlockNumber uint64) (uint64, error) { +type ParentHeaderFetcher interface { + HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) +} + +func CorrespondingL1BlockNumber(ctx context.Context, client ParentHeaderFetcher, parentBlockNumber uint64) (uint64, error) { // #nosec G115 header, err := client.HeaderByNumber(ctx, big.NewInt(int64(parentBlockNumber))) if err != nil { diff --git a/arbutil/transaction_data.go b/arbutil/transaction_data.go index 8270a628bd..c5728967c7 100644 --- a/arbutil/transaction_data.go +++ b/arbutil/transaction_data.go @@ -8,9 +8,10 @@ import ( "fmt" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" ) -func GetLogTransaction(ctx context.Context, client L1Interface, log types.Log) (*types.Transaction, error) { +func GetLogTransaction(ctx context.Context, client *ethclient.Client, log types.Log) (*types.Transaction, error) { tx, err := client.TransactionInBlock(ctx, log.BlockHash, log.TxIndex) if err != nil { return nil, err @@ -22,7 +23,7 @@ func GetLogTransaction(ctx context.Context, client L1Interface, log types.Log) ( } // GetLogEmitterTxData requires that the tx's data is at least 4 bytes long -func GetLogEmitterTxData(ctx context.Context, client L1Interface, log types.Log) ([]byte, error) { +func GetLogEmitterTxData(ctx context.Context, client *ethclient.Client, log types.Log) ([]byte, error) { tx, err := GetLogTransaction(ctx, client, log) if err != nil { return nil, err diff --git a/arbutil/wait_for_l1.go b/arbutil/wait_for_l1.go index 4b4819156d..49eea6af78 100644 --- a/arbutil/wait_for_l1.go +++ b/arbutil/wait_for_l1.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" ) @@ -30,7 +31,7 @@ type L1Interface interface { Client() rpc.ClientInterface } -func SendTxAsCall(ctx context.Context, client L1Interface, tx *types.Transaction, from common.Address, blockNum *big.Int, unlimitedGas bool) ([]byte, error) { +func SendTxAsCall(ctx context.Context, client *ethclient.Client, tx *types.Transaction, from common.Address, blockNum *big.Int, unlimitedGas bool) ([]byte, error) { var gas uint64 if unlimitedGas { gas = 0 @@ -50,7 +51,7 @@ func SendTxAsCall(ctx context.Context, client L1Interface, tx *types.Transaction return client.CallContract(ctx, callMsg, blockNum) } -func GetPendingCallBlockNumber(ctx context.Context, client L1Interface) (*big.Int, error) { +func GetPendingCallBlockNumber(ctx context.Context, client *ethclient.Client) (*big.Int, error) { msg := ethereum.CallMsg{ // Pretend to be a contract deployment to execute EVM code without calling a contract. To: nil, @@ -70,7 +71,7 @@ func GetPendingCallBlockNumber(ctx context.Context, client L1Interface) (*big.In return new(big.Int).SetBytes(callRes), nil } -func DetailTxError(ctx context.Context, client L1Interface, tx *types.Transaction, txRes *types.Receipt) error { +func DetailTxError(ctx context.Context, client *ethclient.Client, tx *types.Transaction, txRes *types.Receipt) error { // Re-execute the transaction as a call to get a better error if ctx.Err() != nil { return ctx.Err() @@ -96,7 +97,7 @@ func DetailTxError(ctx context.Context, client L1Interface, tx *types.Transactio return fmt.Errorf("SendTxAsCall got: %w for tx hash %v", err, tx.Hash()) } -func DetailTxErrorUsingCallMsg(ctx context.Context, client L1Interface, txHash common.Hash, txRes *types.Receipt, callMsg ethereum.CallMsg) error { +func DetailTxErrorUsingCallMsg(ctx context.Context, client *ethclient.Client, txHash common.Hash, txRes *types.Receipt, callMsg ethereum.CallMsg) error { // Re-execute the transaction as a call to get a better error if ctx.Err() != nil { return ctx.Err() diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index a8463a7d21..956b878152 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -37,7 +38,6 @@ import ( "github.com/offchainlabs/nitro/arbnode" "github.com/offchainlabs/nitro/arbos/arbosState" "github.com/offchainlabs/nitro/arbos/arbostypes" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/cmd/conf" "github.com/offchainlabs/nitro/cmd/ipfshelper" @@ -560,7 +560,7 @@ func rebuildLocalWasm(ctx context.Context, config *gethexec.Config, l2BlockChain return chainDb, l2BlockChain, nil } -func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeConfig, chainId *big.Int, cacheConfig *core.CacheConfig, targetConfig *gethexec.StylusTargetConfig, persistentConfig *conf.PersistentConfig, l1Client arbutil.L1Interface, rollupAddrs chaininfo.RollupAddresses) (ethdb.Database, *core.BlockChain, error) { +func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeConfig, chainId *big.Int, cacheConfig *core.CacheConfig, targetConfig *gethexec.StylusTargetConfig, persistentConfig *conf.PersistentConfig, l1Client *ethclient.Client, rollupAddrs chaininfo.RollupAddresses) (ethdb.Database, *core.BlockChain, error) { if !config.Init.Force { if readOnlyDb, err := stack.OpenDatabaseWithFreezerWithExtraOptions("l2chaindata", 0, 0, config.Persistent.Ancient, "l2chaindata/", true, persistentConfig.Pebble.ExtraOptions("l2chaindata")); err == nil { if chainConfig := gethexec.TryReadStoredChainConfig(readOnlyDb); chainConfig != nil { diff --git a/cmd/pruning/pruning.go b/cmd/pruning/pruning.go index 096bb4b1ae..c5923501f0 100644 --- a/cmd/pruning/pruning.go +++ b/cmd/pruning/pruning.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/pruner" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -80,7 +81,7 @@ func (r *importantRoots) addHeader(header *types.Header, overwrite bool) error { var hashListRegex = regexp.MustCompile("^(0x)?[0-9a-fA-F]{64}(,(0x)?[0-9a-fA-F]{64})*$") // Finds important roots to retain while proving -func findImportantRoots(ctx context.Context, chainDb ethdb.Database, stack *node.Node, initConfig *conf.InitConfig, cacheConfig *core.CacheConfig, persistentConfig *conf.PersistentConfig, l1Client arbutil.L1Interface, rollupAddrs chaininfo.RollupAddresses, validatorRequired bool) ([]common.Hash, error) { +func findImportantRoots(ctx context.Context, chainDb ethdb.Database, stack *node.Node, initConfig *conf.InitConfig, cacheConfig *core.CacheConfig, persistentConfig *conf.PersistentConfig, l1Client *ethclient.Client, rollupAddrs chaininfo.RollupAddresses, validatorRequired bool) ([]common.Hash, error) { chainConfig := gethexec.TryReadStoredChainConfig(chainDb) if chainConfig == nil { return nil, errors.New("database doesn't have a chain config (was this node initialized?)") @@ -232,7 +233,7 @@ func findImportantRoots(ctx context.Context, chainDb ethdb.Database, stack *node return roots.roots, nil } -func PruneChainDb(ctx context.Context, chainDb ethdb.Database, stack *node.Node, initConfig *conf.InitConfig, cacheConfig *core.CacheConfig, persistentConfig *conf.PersistentConfig, l1Client arbutil.L1Interface, rollupAddrs chaininfo.RollupAddresses, validatorRequired bool) error { +func PruneChainDb(ctx context.Context, chainDb ethdb.Database, stack *node.Node, initConfig *conf.InitConfig, cacheConfig *core.CacheConfig, persistentConfig *conf.PersistentConfig, l1Client *ethclient.Client, rollupAddrs chaininfo.RollupAddresses, validatorRequired bool) error { if cacheConfig.StateScheme == rawdb.PathScheme { return nil } diff --git a/das/aggregator.go b/das/aggregator.go index e8972447ad..87d67cd0c4 100644 --- a/das/aggregator.go +++ b/das/aggregator.go @@ -15,11 +15,11 @@ import ( flag "github.com/spf13/pflag" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/offchainlabs/nitro/arbstate/daprovider" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/blsSignatures" "github.com/offchainlabs/nitro/das/dastree" "github.com/offchainlabs/nitro/solgen/go/bridgegen" @@ -114,7 +114,7 @@ func NewAggregator(ctx context.Context, config DataAvailabilityConfig, services func NewAggregatorWithL1Info( config DataAvailabilityConfig, services []ServiceDetails, - l1client arbutil.L1Interface, + l1client *ethclient.Client, seqInboxAddress common.Address, ) (*Aggregator, error) { seqInboxCaller, err := bridgegen.NewSequencerInboxCaller(seqInboxAddress, l1client) diff --git a/das/chain_fetch_das.go b/das/chain_fetch_das.go index 465b54f400..4de6c981cf 100644 --- a/das/chain_fetch_das.go +++ b/das/chain_fetch_das.go @@ -12,8 +12,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/das/dastree" "github.com/offchainlabs/nitro/solgen/go/bridgegen" ) @@ -42,7 +42,7 @@ type KeysetFetcher struct { keysetCache syncedKeysetCache } -func NewKeysetFetcher(l1client arbutil.L1Interface, seqInboxAddr common.Address) (*KeysetFetcher, error) { +func NewKeysetFetcher(l1client *ethclient.Client, seqInboxAddr common.Address) (*KeysetFetcher, error) { seqInbox, err := bridgegen.NewSequencerInbox(seqInboxAddr, l1client) if err != nil { return nil, err diff --git a/das/factory.go b/das/factory.go index 5742a39479..c085f78332 100644 --- a/das/factory.go +++ b/das/factory.go @@ -10,8 +10,8 @@ import ( "math" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/util/signature" @@ -113,7 +113,7 @@ func CreateBatchPosterDAS( ctx context.Context, config *DataAvailabilityConfig, dataSigner signature.DataSignerFunc, - l1Reader arbutil.L1Interface, + l1Reader *ethclient.Client, sequencerInboxAddr common.Address, ) (DataAvailabilityServiceWriter, DataAvailabilityServiceReader, *KeysetFetcher, *LifecycleManager, error) { if !config.Enable { diff --git a/das/rpc_aggregator.go b/das/rpc_aggregator.go index 24a470be5b..0a1b87e6ca 100644 --- a/das/rpc_aggregator.go +++ b/das/rpc_aggregator.go @@ -21,7 +21,7 @@ import ( "github.com/offchainlabs/nitro/util/signature" "github.com/ethereum/go-ethereum/common" - "github.com/offchainlabs/nitro/arbutil" + "github.com/ethereum/go-ethereum/ethclient" ) type BackendConfig struct { @@ -83,7 +83,7 @@ func NewRPCAggregator(ctx context.Context, config DataAvailabilityConfig, signer return NewAggregator(ctx, config, services) } -func NewRPCAggregatorWithL1Info(config DataAvailabilityConfig, l1client arbutil.L1Interface, seqInboxAddress common.Address, signer signature.DataSignerFunc) (*Aggregator, error) { +func NewRPCAggregatorWithL1Info(config DataAvailabilityConfig, l1client *ethclient.Client, seqInboxAddress common.Address, signer signature.DataSignerFunc) (*Aggregator, error) { services, err := ParseServices(config.RPCAggregator, signer) if err != nil { return nil, err diff --git a/das/syncing_fallback_storage.go b/das/syncing_fallback_storage.go index 8af46b7fc5..3fea8f3119 100644 --- a/das/syncing_fallback_storage.go +++ b/das/syncing_fallback_storage.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/offchainlabs/nitro/arbstate/daprovider" "github.com/offchainlabs/nitro/arbutil" @@ -242,7 +243,7 @@ func FindDASDataFromLog( inboxContract *bridgegen.SequencerInbox, deliveredEvent *bridgegen.SequencerInboxSequencerBatchDelivered, inboxAddr common.Address, - l1Client arbutil.L1Interface, + l1Client *ethclient.Client, batchDeliveredLog types.Log) ([]byte, error) { data := []byte{} if deliveredEvent.DataLocation == uint8(batchDataSeparateEvent) { diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index 21c2b4bece..f1ca64082d 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -173,7 +174,7 @@ func CreateExecutionNode( stack *node.Node, chainDB ethdb.Database, l2BlockChain *core.BlockChain, - l1client arbutil.L1Interface, + l1client *ethclient.Client, configFetcher ConfigFetcher, ) (*ExecutionNode, error) { config := configFetcher() diff --git a/staker/l1_validator.go b/staker/l1_validator.go index 6ea9fd8ded..5b0c211324 100644 --- a/staker/l1_validator.go +++ b/staker/l1_validator.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/rollupgen" @@ -45,7 +46,7 @@ type L1Validator struct { rollup *RollupWatcher rollupAddress common.Address validatorUtils *rollupgen.ValidatorUtils - client arbutil.L1Interface + client *ethclient.Client builder *txbuilder.Builder wallet ValidatorWalletInterface callOpts bind.CallOpts @@ -57,7 +58,7 @@ type L1Validator struct { } func NewL1Validator( - client arbutil.L1Interface, + client *ethclient.Client, wallet ValidatorWalletInterface, validatorUtilsAddress common.Address, callOpts bind.CallOpts, diff --git a/staker/rollup_watcher.go b/staker/rollup_watcher.go index 5ef28a49dc..9c51e659f5 100644 --- a/staker/rollup_watcher.go +++ b/staker/rollup_watcher.go @@ -48,12 +48,18 @@ type RollupWatcher struct { *rollupgen.RollupUserLogic address common.Address fromBlock *big.Int - client arbutil.L1Interface + client WatcherL1Interface baseCallOpts bind.CallOpts unSupportedL3Method atomic.Bool } -func NewRollupWatcher(address common.Address, client arbutil.L1Interface, callOpts bind.CallOpts) (*RollupWatcher, error) { +type WatcherL1Interface interface { + bind.ContractBackend + HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) + FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) +} + +func NewRollupWatcher(address common.Address, client WatcherL1Interface, callOpts bind.CallOpts) (*RollupWatcher, error) { con, err := rollupgen.NewRollupUserLogic(address, client) if err != nil { return nil, err diff --git a/staker/staker.go b/staker/staker.go index 6e93d27311..1d49063a89 100644 --- a/staker/staker.go +++ b/staker/staker.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rpc" @@ -281,7 +282,7 @@ type ValidatorWalletInterface interface { TxSenderAddress() *common.Address RollupAddress() common.Address ChallengeManagerAddress() common.Address - L1Client() arbutil.L1Interface + L1Client() *ethclient.Client TestTransactions(context.Context, []*types.Transaction) error ExecuteTransactions(context.Context, *txbuilder.Builder, common.Address) (*types.Transaction, error) TimeoutChallenges(context.Context, []uint64) (*types.Transaction, error) diff --git a/staker/txbuilder/builder.go b/staker/txbuilder/builder.go index 9a5e9df2b5..fa40c6a816 100644 --- a/staker/txbuilder/builder.go +++ b/staker/txbuilder/builder.go @@ -12,13 +12,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/offchainlabs/nitro/arbutil" + "github.com/ethereum/go-ethereum/ethclient" ) type ValidatorWalletInterface interface { // Address must be able to be called concurrently with other functions Address() *common.Address - L1Client() arbutil.L1Interface + L1Client() *ethclient.Client TestTransactions(context.Context, []*types.Transaction) error ExecuteTransactions(context.Context, *Builder, common.Address) (*types.Transaction, error) AuthIfEoa() *bind.TransactOpts @@ -30,7 +30,7 @@ type ValidatorWalletInterface interface { // This inherits from an eth client so it can be used as an L1Interface, // where it transparently intercepts calls to SendTransaction and queues them for the next batch. type Builder struct { - arbutil.L1Interface + *ethclient.Client transactions []*types.Transaction builderAuth *bind.TransactOpts isAuthFake bool @@ -55,7 +55,7 @@ func NewBuilder(wallet ValidatorWalletInterface) (*Builder, error) { return &Builder{ builderAuth: builderAuth, wallet: wallet, - L1Interface: wallet.L1Client(), + Client: wallet.L1Client(), isAuthFake: isAuthFake, }, nil } @@ -70,7 +70,7 @@ func (b *Builder) ClearTransactions() { func (b *Builder) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { if len(b.transactions) == 0 && !b.isAuthFake { - return b.L1Interface.EstimateGas(ctx, call) + return b.Client.EstimateGas(ctx, call) } return 0, nil } diff --git a/staker/validatorwallet/contract.go b/staker/validatorwallet/contract.go index 6346029c3a..3202d58569 100644 --- a/staker/validatorwallet/contract.go +++ b/staker/validatorwallet/contract.go @@ -16,10 +16,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbnode/dataposter" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker/txbuilder" "github.com/offchainlabs/nitro/util/arbmath" @@ -384,7 +384,7 @@ func (v *Contract) TimeoutChallenges(ctx context.Context, challenges []uint64) ( return v.dataPoster.PostSimpleTransaction(ctx, auth.Nonce.Uint64(), *v.Address(), data, gas, auth.Value) } -func (v *Contract) L1Client() arbutil.L1Interface { +func (v *Contract) L1Client() *ethclient.Client { return v.l1Reader.Client() } diff --git a/staker/validatorwallet/eoa.go b/staker/validatorwallet/eoa.go index 3ae305b36c..7c7f472579 100644 --- a/staker/validatorwallet/eoa.go +++ b/staker/validatorwallet/eoa.go @@ -10,8 +10,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/offchainlabs/nitro/arbnode/dataposter" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/challengegen" "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker/txbuilder" @@ -19,7 +19,7 @@ import ( type EOA struct { auth *bind.TransactOpts - client arbutil.L1Interface + client *ethclient.Client rollupAddress common.Address challengeManager *challengegen.ChallengeManager challengeManagerAddress common.Address @@ -27,7 +27,7 @@ type EOA struct { getExtraGas func() uint64 } -func NewEOA(dataPoster *dataposter.DataPoster, rollupAddress common.Address, l1Client arbutil.L1Interface, getExtraGas func() uint64) (*EOA, error) { +func NewEOA(dataPoster *dataposter.DataPoster, rollupAddress common.Address, l1Client *ethclient.Client, getExtraGas func() uint64) (*EOA, error) { return &EOA{ auth: dataPoster.Auth(), client: l1Client, @@ -63,7 +63,7 @@ func (w *EOA) TxSenderAddress() *common.Address { return &w.auth.From } -func (w *EOA) L1Client() arbutil.L1Interface { +func (w *EOA) L1Client() *ethclient.Client { return w.client } diff --git a/staker/validatorwallet/noop.go b/staker/validatorwallet/noop.go index b050ebe861..fec39ac2b1 100644 --- a/staker/validatorwallet/noop.go +++ b/staker/validatorwallet/noop.go @@ -10,18 +10,18 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/offchainlabs/nitro/arbnode/dataposter" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/staker/txbuilder" ) // NoOp validator wallet is used for watchtower mode. type NoOp struct { - l1Client arbutil.L1Interface + l1Client *ethclient.Client rollupAddress common.Address } -func NewNoOp(l1Client arbutil.L1Interface, rollupAddress common.Address) *NoOp { +func NewNoOp(l1Client *ethclient.Client, rollupAddress common.Address) *NoOp { return &NoOp{ l1Client: l1Client, rollupAddress: rollupAddress, @@ -46,7 +46,7 @@ func (*NoOp) TimeoutChallenges(ctx context.Context, challenges []uint64) (*types return nil, errors.New("no op validator wallet cannot timeout challenges") } -func (n *NoOp) L1Client() arbutil.L1Interface { return n.l1Client } +func (n *NoOp) L1Client() *ethclient.Client { return n.l1Client } func (n *NoOp) RollupAddress() common.Address { return n.rollupAddress } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 457dae0910..2b2f1c6407 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -69,7 +69,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/offchainlabs/nitro/arbnode" - "github.com/offchainlabs/nitro/arbutil" _ "github.com/offchainlabs/nitro/execution/nodeInterface" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/solgen/go/mocksgen" @@ -83,7 +82,6 @@ import ( ) type info = *BlockchainTestInfo -type client = arbutil.L1Interface type SecondNodeParams struct { nodeConfig *arbnode.Config @@ -540,7 +538,7 @@ func (b *NodeBuilder) BridgeBalance(t *testing.T, account string, amount *big.In return BridgeBalance(t, account, amount, b.L1Info, b.L2Info, b.L1.Client, b.L2.Client, b.ctx) } -func SendWaitTestTransactions(t *testing.T, ctx context.Context, client client, txs []*types.Transaction) { +func SendWaitTestTransactions(t *testing.T, ctx context.Context, client *ethclient.Client, txs []*types.Transaction) { t.Helper() for _, tx := range txs { Require(t, client.SendTransaction(ctx, tx)) @@ -552,14 +550,14 @@ func SendWaitTestTransactions(t *testing.T, ctx context.Context, client client, } func TransferBalance( - t *testing.T, from, to string, amount *big.Int, l2info info, client client, ctx context.Context, + t *testing.T, from, to string, amount *big.Int, l2info info, client *ethclient.Client, ctx context.Context, ) (*types.Transaction, *types.Receipt) { t.Helper() return TransferBalanceTo(t, from, l2info.GetAddress(to), amount, l2info, client, ctx) } func TransferBalanceTo( - t *testing.T, from string, to common.Address, amount *big.Int, l2info info, client client, ctx context.Context, + t *testing.T, from string, to common.Address, amount *big.Int, l2info info, client *ethclient.Client, ctx context.Context, ) (*types.Transaction, *types.Receipt) { t.Helper() tx := l2info.PrepareTxTo(from, &to, l2info.TransferGas, amount, nil) @@ -572,7 +570,7 @@ func TransferBalanceTo( // if l2client is not nil - will wait until balance appears in l2 func BridgeBalance( - t *testing.T, account string, amount *big.Int, l1info info, l2info info, l1client client, l2client client, ctx context.Context, + t *testing.T, account string, amount *big.Int, l1info info, l2info info, l1client *ethclient.Client, l2client *ethclient.Client, ctx context.Context, ) (*types.Transaction, *types.Receipt) { t.Helper() @@ -632,8 +630,8 @@ func SendSignedTxesInBatchViaL1( t *testing.T, ctx context.Context, l1info *BlockchainTestInfo, - l1client arbutil.L1Interface, - l2client arbutil.L1Interface, + l1client *ethclient.Client, + l2client *ethclient.Client, delayedTxes types.Transactions, ) types.Receipts { delayedInboxContract, err := bridgegen.NewInbox(l1info.GetAddress("Inbox"), l1client) @@ -683,8 +681,8 @@ func SendSignedTxViaL1( t *testing.T, ctx context.Context, l1info *BlockchainTestInfo, - l1client arbutil.L1Interface, - l2client arbutil.L1Interface, + l1client *ethclient.Client, + l2client *ethclient.Client, delayedTx *types.Transaction, ) *types.Receipt { delayedInboxContract, err := bridgegen.NewInbox(l1info.GetAddress("Inbox"), l1client) @@ -714,8 +712,8 @@ func SendUnsignedTxViaL1( t *testing.T, ctx context.Context, l1info *BlockchainTestInfo, - l1client arbutil.L1Interface, - l2client arbutil.L1Interface, + l1client *ethclient.Client, + l2client *ethclient.Client, templateTx *types.Transaction, ) *types.Receipt { delayedInboxContract, err := bridgegen.NewInbox(l1info.GetAddress("Inbox"), l1client) @@ -761,13 +759,13 @@ func SendUnsignedTxViaL1( return receipt } -func GetBaseFee(t *testing.T, client client, ctx context.Context) *big.Int { +func GetBaseFee(t *testing.T, client *ethclient.Client, ctx context.Context) *big.Int { header, err := client.HeaderByNumber(ctx, nil) Require(t, err) return header.BaseFee } -func GetBaseFeeAt(t *testing.T, client client, ctx context.Context, blockNum *big.Int) *big.Int { +func GetBaseFeeAt(t *testing.T, client *ethclient.Client, ctx context.Context, blockNum *big.Int) *big.Int { header, err := client.HeaderByNumber(ctx, blockNum) Require(t, err) return header.BaseFee @@ -989,7 +987,7 @@ func createTestL1BlockChain(t *testing.T, l1info info) (info, *ethclient.Client, return l1info, l1Client, l1backend, stack } -func getInitMessage(ctx context.Context, t *testing.T, l1client client, addresses *chaininfo.RollupAddresses) *arbostypes.ParsedInitMessage { +func getInitMessage(ctx context.Context, t *testing.T, l1client *ethclient.Client, addresses *chaininfo.RollupAddresses) *arbostypes.ParsedInitMessage { bridge, err := arbnode.NewDelayedBridge(l1client, addresses.Bridge, addresses.DeployedAt) Require(t, err) deployedAtBig := arbmath.UintToBig(addresses.DeployedAt) @@ -1005,7 +1003,7 @@ func getInitMessage(ctx context.Context, t *testing.T, l1client client, addresse } func DeployOnTestL1( - t *testing.T, ctx context.Context, l1info info, l1client client, chainConfig *params.ChainConfig, wasmModuleRoot common.Hash, prodConfirmPeriodBlocks bool, + t *testing.T, ctx context.Context, l1info info, l1client *ethclient.Client, chainConfig *params.ChainConfig, wasmModuleRoot common.Hash, prodConfirmPeriodBlocks bool, ) (*chaininfo.RollupAddresses, *arbostypes.ParsedInitMessage) { l1info.GenerateAccount("RollupOwner") l1info.GenerateAccount("Sequencer") @@ -1223,7 +1221,7 @@ func authorizeDASKeyset( ctx context.Context, dasSignerKey *blsSignatures.PublicKey, l1info info, - l1client arbutil.L1Interface, + l1client *ethclient.Client, ) { if dasSignerKey == nil { return diff --git a/system_tests/das_test.go b/system_tests/das_test.go index 9f4d153b6f..69872b3e62 100644 --- a/system_tests/das_test.go +++ b/system_tests/das_test.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbnode" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/blsSignatures" "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/das" @@ -37,7 +36,7 @@ func startLocalDASServer( t *testing.T, ctx context.Context, dataDir string, - l1client arbutil.L1Interface, + l1client *ethclient.Client, seqInboxAddress common.Address, ) (*http.Server, *blsSignatures.PublicKey, das.BackendConfig, *das.RestfulDasServer, string) { keyDir := t.TempDir() diff --git a/system_tests/full_challenge_impl_test.go b/system_tests/full_challenge_impl_test.go index ddc229074c..bf30c928d8 100644 --- a/system_tests/full_challenge_impl_test.go +++ b/system_tests/full_challenge_impl_test.go @@ -27,7 +27,6 @@ import ( "github.com/offchainlabs/nitro/arbnode" "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/arbstate" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/challengegen" "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/ospgen" @@ -178,7 +177,7 @@ func makeBatch(t *testing.T, l2Node *arbnode.Node, l2Info *BlockchainTestInfo, b Require(t, err, "failed to get batch metadata after adding batch:") } -func confirmLatestBlock(ctx context.Context, t *testing.T, l1Info *BlockchainTestInfo, backend arbutil.L1Interface) { +func confirmLatestBlock(ctx context.Context, t *testing.T, l1Info *BlockchainTestInfo, backend *ethclient.Client) { t.Helper() // With SimulatedBeacon running in on-demand block production mode, the // finalized block is considered to be be the nearest multiple of 32 less @@ -190,7 +189,7 @@ func confirmLatestBlock(ctx context.Context, t *testing.T, l1Info *BlockchainTes } } -func setupSequencerInboxStub(ctx context.Context, t *testing.T, l1Info *BlockchainTestInfo, l1Client arbutil.L1Interface, chainConfig *params.ChainConfig) (common.Address, *mocksgen.SequencerInboxStub, common.Address) { +func setupSequencerInboxStub(ctx context.Context, t *testing.T, l1Info *BlockchainTestInfo, l1Client *ethclient.Client, chainConfig *params.ChainConfig) (common.Address, *mocksgen.SequencerInboxStub, common.Address) { txOpts := l1Info.GetDefaultTransactOpts("deployer", ctx) bridgeAddr, tx, bridge, err := mocksgen.DeployBridgeUnproxied(&txOpts, l1Client) Require(t, err) diff --git a/system_tests/wrap_transaction_test.go b/system_tests/wrap_transaction_test.go index bd561ad5e5..36052fb2db 100644 --- a/system_tests/wrap_transaction_test.go +++ b/system_tests/wrap_transaction_test.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" "github.com/offchainlabs/nitro/arbutil" @@ -22,7 +23,7 @@ import ( "github.com/offchainlabs/nitro/util/headerreader" ) -func GetPendingBlockNumber(ctx context.Context, client arbutil.L1Interface) (*big.Int, error) { +func GetPendingBlockNumber(ctx context.Context, client *ethclient.Client) (*big.Int, error) { // Attempt to get the block number from ArbSys, if it exists arbSys, err := precompilesgen.NewArbSys(common.BigToAddress(big.NewInt(100)), client) if err != nil { @@ -37,7 +38,7 @@ func GetPendingBlockNumber(ctx context.Context, client arbutil.L1Interface) (*bi } // Will wait until txhash is in the blockchain and return its receipt -func WaitForTx(ctxinput context.Context, client arbutil.L1Interface, txhash common.Hash, timeout time.Duration) (*types.Receipt, error) { +func WaitForTx(ctxinput context.Context, client *ethclient.Client, txhash common.Hash, timeout time.Duration) (*types.Receipt, error) { ctx, cancel := context.WithTimeout(ctxinput, timeout) defer cancel() @@ -75,11 +76,11 @@ func WaitForTx(ctxinput context.Context, client arbutil.L1Interface, txhash comm } } -func EnsureTxSucceeded(ctx context.Context, client arbutil.L1Interface, tx *types.Transaction) (*types.Receipt, error) { +func EnsureTxSucceeded(ctx context.Context, client *ethclient.Client, tx *types.Transaction) (*types.Receipt, error) { return EnsureTxSucceededWithTimeout(ctx, client, tx, time.Second*5) } -func EnsureTxSucceededWithTimeout(ctx context.Context, client arbutil.L1Interface, tx *types.Transaction, timeout time.Duration) (*types.Receipt, error) { +func EnsureTxSucceededWithTimeout(ctx context.Context, client *ethclient.Client, tx *types.Transaction, timeout time.Duration) (*types.Receipt, error) { receipt, err := WaitForTx(ctx, client, tx.Hash(), timeout) if err != nil { return nil, fmt.Errorf("waitFoxTx (tx=%s) got: %w", tx.Hash().Hex(), err) @@ -103,12 +104,12 @@ func EnsureTxSucceededWithTimeout(ctx context.Context, client arbutil.L1Interfac return receipt, arbutil.DetailTxError(ctx, client, tx, receipt) } -func EnsureTxFailed(t *testing.T, ctx context.Context, client arbutil.L1Interface, tx *types.Transaction) *types.Receipt { +func EnsureTxFailed(t *testing.T, ctx context.Context, client *ethclient.Client, tx *types.Transaction) *types.Receipt { t.Helper() return EnsureTxFailedWithTimeout(t, ctx, client, tx, time.Second*5) } -func EnsureTxFailedWithTimeout(t *testing.T, ctx context.Context, client arbutil.L1Interface, tx *types.Transaction, timeout time.Duration) *types.Receipt { +func EnsureTxFailedWithTimeout(t *testing.T, ctx context.Context, client *ethclient.Client, tx *types.Transaction, timeout time.Duration) *types.Receipt { t.Helper() receipt, err := WaitForTx(ctx, client, tx.Hash(), timeout) Require(t, err) diff --git a/util/headerreader/blob_client.go b/util/headerreader/blob_client.go index 2b47a940c3..945fc27691 100644 --- a/util/headerreader/blob_client.go +++ b/util/headerreader/blob_client.go @@ -18,8 +18,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/util/blobs" "github.com/offchainlabs/nitro/util/jsonapi" "github.com/offchainlabs/nitro/util/pretty" @@ -28,7 +28,7 @@ import ( ) type BlobClient struct { - ec arbutil.L1Interface + ec *ethclient.Client beaconUrl *url.URL secondaryBeaconUrl *url.URL httpClient *http.Client @@ -63,7 +63,7 @@ func BlobClientAddOptions(prefix string, f *pflag.FlagSet) { f.String(prefix+".authorization", DefaultBlobClientConfig.Authorization, "Value to send with the HTTP Authorization: header for Beacon REST requests, must include both scheme and scheme parameters") } -func NewBlobClient(config BlobClientConfig, ec arbutil.L1Interface) (*BlobClient, error) { +func NewBlobClient(config BlobClientConfig, ec *ethclient.Client) (*BlobClient, error) { beaconUrl, err := url.Parse(config.BeaconUrl) if err != nil { return nil, fmt.Errorf("failed to parse beacon chain URL: %w", err) diff --git a/util/headerreader/header_reader.go b/util/headerreader/header_reader.go index c8041dc871..98f778dee8 100644 --- a/util/headerreader/header_reader.go +++ b/util/headerreader/header_reader.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" "github.com/offchainlabs/nitro/arbutil" @@ -33,7 +34,7 @@ type ArbSysInterface interface { type HeaderReader struct { stopwaiter.StopWaiter config ConfigFetcher - client arbutil.L1Interface + client *ethclient.Client isParentChainArbitrum bool arbSys ArbSysInterface @@ -120,7 +121,7 @@ var TestConfig = Config{ }, } -func New(ctx context.Context, client arbutil.L1Interface, config ConfigFetcher, arbSysPrecompile ArbSysInterface) (*HeaderReader, error) { +func New(ctx context.Context, client *ethclient.Client, config ConfigFetcher, arbSysPrecompile ArbSysInterface) (*HeaderReader, error) { isParentChainArbitrum := false var arbSys ArbSysInterface if arbSysPrecompile != nil { @@ -522,7 +523,7 @@ func (s *HeaderReader) LatestFinalizedBlockNr(ctx context.Context) (uint64, erro return header.Number.Uint64(), nil } -func (s *HeaderReader) Client() arbutil.L1Interface { +func (s *HeaderReader) Client() *ethclient.Client { return s.client } From fab821e384e51d744da8d1212fef7f1571c03072 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 14 Aug 2024 14:19:24 -0300 Subject: [PATCH 016/101] First step in lru to lru_mem migration in stylus cache --- arbitrator/Cargo.lock | 10 ++++++++++ arbitrator/Cargo.toml | 2 -- arbitrator/stylus/Cargo.toml | 3 ++- arbitrator/stylus/src/cache.rs | 35 +++++++++++++++++++++++++--------- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index 79a9117a31..a46e000ce2 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -1342,6 +1342,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "lru-mem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5c8c26d903a41c80d4cc171940a57a4d1bc51139ebd6aad87e2f9ae3774780" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "mach" version = "0.3.2" @@ -2277,6 +2286,7 @@ dependencies = [ "lazy_static", "libc", "lru", + "lru-mem", "num-bigint", "parking_lot", "prover", diff --git a/arbitrator/Cargo.toml b/arbitrator/Cargo.toml index 94ca08b0b5..eaafb6e439 100644 --- a/arbitrator/Cargo.toml +++ b/arbitrator/Cargo.toml @@ -24,9 +24,7 @@ repository = "https://github.com/OffchainLabs/nitro.git" rust-version = "1.67" [workspace.dependencies] -cfg-if = "1.0.0" lazy_static = "1.4.0" -lru = "0.12.3" num_enum = { version = "0.7.2", default-features = false } ruint2 = "1.9.0" wasmparser = "0.121" diff --git a/arbitrator/stylus/Cargo.toml b/arbitrator/stylus/Cargo.toml index 4717bd631a..45c06fc881 100644 --- a/arbitrator/stylus/Cargo.toml +++ b/arbitrator/stylus/Cargo.toml @@ -21,11 +21,12 @@ thiserror = "1.0.33" bincode = "1.3.3" lazy_static.workspace = true libc = "0.2.108" -lru.workspace = true eyre = "0.6.5" rand = "0.8.5" fnv = "1.0.7" hex = "0.4.3" +lru-mem = "0.3.0" +lru = "0.12.4" [dev-dependencies] num-bigint = "0.4.4" diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index fa38d45419..338dcb9dd0 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -4,16 +4,16 @@ use arbutil::Bytes32; use eyre::Result; use lazy_static::lazy_static; -use lru::LruCache; +use lru_mem::{HeapSize, LruCache}; use parking_lot::Mutex; use prover::programs::config::CompileConfig; -use std::{collections::HashMap, num::NonZeroUsize}; +use std::collections::HashMap; use wasmer::{Engine, Module, Store}; use crate::target_cache::target_native; lazy_static! { - static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256)); + static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 100_000)); } macro_rules! cache { @@ -44,6 +44,12 @@ impl CacheKey { } } +impl HeapSize for CacheKey { + fn heap_size(&self) -> usize { + 0 + } +} + #[derive(Clone)] struct CacheItem { module: Module, @@ -60,6 +66,13 @@ impl CacheItem { } } +impl HeapSize for CacheItem { + // TODO: implement heap_size + fn heap_size(&self) -> usize { + 100_000 + } +} + impl InitCache { // current implementation only has one tag that stores to the long_term // future implementations might have more, but 0 is a reserved tag @@ -69,14 +82,15 @@ impl InitCache { fn new(size: usize) -> Self { Self { long_term: HashMap::new(), - lru: LruCache::new(NonZeroUsize::new(size).unwrap()), + lru: LruCache::new(size), } } + // TODO: Check if needs to shrink capacity pub fn set_lru_size(size: u32) { cache!() .lru - .resize(NonZeroUsize::new(size.try_into().unwrap()).unwrap()) + .set_max_size(size.try_into().unwrap()) } /// Retrieves a cached value, updating items as necessary. @@ -116,7 +130,7 @@ impl InitCache { if long_term_tag == Self::ARBOS_TAG { cache.long_term.insert(key, item.clone()); } else { - cache.lru.promote(&key) + cache.lru.touch(&key) } return Ok(item.data()); } @@ -129,7 +143,8 @@ impl InitCache { let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { - cache.lru.put(key, item); + // TODO: handle result + let _ = cache.lru.insert(key, item); } else { cache.long_term.insert(key, item); } @@ -144,7 +159,8 @@ impl InitCache { let key = CacheKey::new(module_hash, version, debug); let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { - cache.lru.put(key, item); + // TODO: handle result + let _ = cache.lru.insert(key, item); } } @@ -155,7 +171,8 @@ impl InitCache { let mut cache = cache!(); let cache = &mut *cache; for (key, item) in cache.long_term.drain() { - cache.lru.put(key, item); // not all will fit, just a heuristic + // TODO: handle result + let _ = cache.lru.insert(key, item); // not all will fit, just a heuristic } } } From e4c9406c1293a3c9e119285e9ae4e8a69fd5b7a1 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 14 Aug 2024 15:22:18 -0300 Subject: [PATCH 017/101] stylus-lru-cache-size instead of stylus-lru-cache flag --- arbnode/inbox_test.go | 2 +- execution/gethexec/blockchain.go | 6 +++--- execution/gethexec/node.go | 2 +- system_tests/common_test.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arbnode/inbox_test.go b/arbnode/inbox_test.go index d579b7c278..e0c97bb871 100644 --- a/arbnode/inbox_test.go +++ b/arbnode/inbox_test.go @@ -74,7 +74,7 @@ func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (* } stylusTargetConfig := &gethexec.DefaultStylusTargetConfig Require(t, stylusTargetConfig.Validate()) // pre-processes config (i.a. parses wasmTargets) - if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCache, stylusTargetConfig); err != nil { + if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheSize, &gethexec.DefaultStylusTargetConfig); err != nil { Fail(t, err) } execSeq := &execClientWrapper{execEngine, t} diff --git a/execution/gethexec/blockchain.go b/execution/gethexec/blockchain.go index 996b87a9e6..54934dbdf3 100644 --- a/execution/gethexec/blockchain.go +++ b/execution/gethexec/blockchain.go @@ -37,7 +37,7 @@ type CachingConfig struct { SnapshotRestoreGasLimit uint64 `koanf:"snapshot-restore-gas-limit"` MaxNumberOfBlocksToSkipStateSaving uint32 `koanf:"max-number-of-blocks-to-skip-state-saving"` MaxAmountOfGasToSkipStateSaving uint64 `koanf:"max-amount-of-gas-to-skip-state-saving"` - StylusLRUCache uint32 `koanf:"stylus-lru-cache"` + StylusLRUCacheSize uint32 `koanf:"stylus-lru-cache-size"` StateScheme string `koanf:"state-scheme"` StateHistory uint64 `koanf:"state-history"` } @@ -54,7 +54,7 @@ func CachingConfigAddOptions(prefix string, f *flag.FlagSet) { f.Uint64(prefix+".snapshot-restore-gas-limit", DefaultCachingConfig.SnapshotRestoreGasLimit, "maximum gas rolled back to recover snapshot") f.Uint32(prefix+".max-number-of-blocks-to-skip-state-saving", DefaultCachingConfig.MaxNumberOfBlocksToSkipStateSaving, "maximum number of blocks to skip state saving to persistent storage (archive node only) -- warning: this option seems to cause issues") f.Uint64(prefix+".max-amount-of-gas-to-skip-state-saving", DefaultCachingConfig.MaxAmountOfGasToSkipStateSaving, "maximum amount of gas in blocks to skip saving state to Persistent storage (archive node only) -- warning: this option seems to cause issues") - f.Uint32(prefix+".stylus-lru-cache", DefaultCachingConfig.StylusLRUCache, "initialized stylus programs to keep in LRU cache") + f.Uint32(prefix+".stylus-lru-cache-size", DefaultCachingConfig.StylusLRUCacheSize, "capacity, in bytes, of the LRU cache that keeps initialized stylus programs") f.String(prefix+".state-scheme", DefaultCachingConfig.StateScheme, "scheme to use for state trie storage (hash, path)") f.Uint64(prefix+".state-history", DefaultCachingConfig.StateHistory, "number of recent blocks to retain state history for (path state-scheme only)") } @@ -75,7 +75,7 @@ var DefaultCachingConfig = CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCache: 256, + StylusLRUCacheSize: 256 * 10 * 1024, StateScheme: rawdb.HashScheme, StateHistory: getStateHistory(DefaultSequencerConfig.MaxBlockSpeed), } diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index 21c2b4bece..93bb254ed8 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -308,7 +308,7 @@ func (n *ExecutionNode) MarkFeedStart(to arbutil.MessageIndex) { func (n *ExecutionNode) Initialize(ctx context.Context) error { config := n.ConfigFetcher() - err := n.ExecEngine.Initialize(config.Caching.StylusLRUCache, &config.StylusTarget) + err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheSize, &config.StylusTarget) if err != nil { return fmt.Errorf("error initializing execution engine: %w", err) } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 457dae0910..363f1050fb 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -166,7 +166,7 @@ var TestCachingConfig = gethexec.CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCache: 0, + StylusLRUCacheSize: 0, StateScheme: env.GetTestStateScheme(), } From a3b2dd7b6c98163b57ac5c17677785ed623ee488 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 15 Aug 2024 12:32:05 -0300 Subject: [PATCH 018/101] Uses asm size estimate to define amount of heap memory used by a stylus LRU cache entry --- arbitrator/stylus/src/cache.rs | 13 +++++++------ arbitrator/stylus/src/lib.rs | 5 ++++- arbitrator/stylus/src/native.rs | 3 ++- arbos/programs/native.go | 12 +++++++----- arbos/programs/programs.go | 12 +++++++++--- arbos/programs/wasm.go | 3 ++- 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 338dcb9dd0..300f0de35a 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -13,7 +13,7 @@ use wasmer::{Engine, Module, Store}; use crate::target_cache::target_native; lazy_static! { - static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 100_000)); + static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 10 * 1024)); } macro_rules! cache { @@ -54,11 +54,12 @@ impl HeapSize for CacheKey { struct CacheItem { module: Module, engine: Engine, + asm_size_estimate: u32, } impl CacheItem { - fn new(module: Module, engine: Engine) -> Self { - Self { module, engine } + fn new(module: Module, engine: Engine, asm_size_estimate: u32) -> Self { + Self { module, engine, asm_size_estimate } } fn data(&self) -> (Module, Store) { @@ -67,9 +68,8 @@ impl CacheItem { } impl HeapSize for CacheItem { - // TODO: implement heap_size fn heap_size(&self) -> usize { - 100_000 + return self.asm_size_estimate.try_into().unwrap(); } } @@ -115,6 +115,7 @@ impl InitCache { pub fn insert( module_hash: Bytes32, module: &[u8], + asm_size_estimate: u32, version: u16, long_term_tag: u32, debug: bool, @@ -139,7 +140,7 @@ impl InitCache { let engine = CompileConfig::version(version, debug).engine(target_native()); let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; - let item = CacheItem::new(module, engine); + let item = CacheItem::new(module, engine, asm_size_estimate); let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index a252b60a01..979736054c 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -256,6 +256,7 @@ pub unsafe extern "C" fn stylus_target_set( #[no_mangle] pub unsafe extern "C" fn stylus_call( module: GoSliceData, + asm_size_estimate: u32, calldata: GoSliceData, config: StylusConfig, req_handler: NativeRequestHandler, @@ -276,6 +277,7 @@ pub unsafe extern "C" fn stylus_call( let instance = unsafe { NativeInstance::deserialize_cached( module, + asm_size_estimate, config.version, evm_api, evm_data, @@ -317,11 +319,12 @@ pub extern "C" fn stylus_cache_lru_resize(size: u32) { pub unsafe extern "C" fn stylus_cache_module( module: GoSliceData, module_hash: Bytes32, + asm_size_estimate: u32, version: u16, arbos_tag: u32, debug: bool, ) { - if let Err(error) = InitCache::insert(module_hash, module.slice(), version, arbos_tag, debug) { + if let Err(error) = InitCache::insert(module_hash, module.slice(), asm_size_estimate, version, arbos_tag, debug) { panic!("tried to cache invalid asm!: {error}"); } } diff --git a/arbitrator/stylus/src/native.rs b/arbitrator/stylus/src/native.rs index 7a82314fbc..d150d71ccc 100644 --- a/arbitrator/stylus/src/native.rs +++ b/arbitrator/stylus/src/native.rs @@ -112,6 +112,7 @@ impl> NativeInstance { /// `module` must represent a valid module. pub unsafe fn deserialize_cached( module: &[u8], + asm_size_estimate: u32, version: u16, evm: E, evm_data: EvmData, @@ -129,7 +130,7 @@ impl> NativeInstance { long_term_tag = 0; } let (module, store) = - InitCache::insert(module_hash, module, version, long_term_tag, debug)?; + InitCache::insert(module_hash, module, asm_size_estimate, version, long_term_tag, debug)?; Self::from_module(module, store, env) } diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 377e25a31e..5908741abf 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -211,6 +211,7 @@ func callProgram( address common.Address, moduleHash common.Hash, localAsm []byte, + asmSizeEstimate uint32, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, @@ -238,6 +239,7 @@ func callProgram( output := &rustBytes{} status := userStatus(C.stylus_call( goSlice(localAsm), + u32(asmSizeEstimate), goSlice(calldata), stylusParams.encode(), evmApi.cNative, @@ -280,26 +282,26 @@ func cacheProgram(db vm.StateDB, module common.Hash, program Program, addressFor panic("unable to recreate wasm") } tag := db.Database().WasmCacheTag() - state.CacheWasmRust(asm, module, program.version, tag, debug) + state.CacheWasmRust(asm, module, program.asmSize(), program.version, tag, debug) db.RecordCacheWasm(state.CacheWasm{ModuleHash: module, Version: program.version, Tag: tag, Debug: debug}) } } // Evicts a program in Rust. We write a record so that we can undo on revert, unless we don't need to (e.g. expired) // For gas estimation and eth_call, we ignore permanent updates and rely on Rust's LRU. -func evictProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, runMode core.MessageRunMode, forever bool) { +func evictProgram(db vm.StateDB, module common.Hash, asmSizeEstimate uint32, version uint16, debug bool, runMode core.MessageRunMode, forever bool) { if runMode == core.MessageCommitMode { tag := db.Database().WasmCacheTag() state.EvictWasmRust(module, version, tag, debug) if !forever { - db.RecordEvictWasm(state.EvictWasm{ModuleHash: module, Version: version, Tag: tag, Debug: debug}) + db.RecordEvictWasm(state.EvictWasm{ModuleHash: module, Version: version, Tag: tag, Debug: debug, AsmSizeEstimate: asmSizeEstimate}) } } } func init() { - state.CacheWasmRust = func(asm []byte, moduleHash common.Hash, version uint16, tag uint32, debug bool) { - C.stylus_cache_module(goSlice(asm), hashToBytes32(moduleHash), u16(version), u32(tag), cbool(debug)) + state.CacheWasmRust = func(asm []byte, moduleHash common.Hash, asmSizeEstimate uint32, version uint16, tag uint32, debug bool) { + C.stylus_cache_module(goSlice(asm), hashToBytes32(moduleHash), u32(asmSizeEstimate), u16(version), u32(tag), cbool(debug)) } state.EvictWasmRust = func(moduleHash common.Hash, version uint16, tag uint32, debug bool) { C.stylus_evict_module(hashToBytes32(moduleHash), u16(version), u32(tag), cbool(debug)) diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index 12102bac84..4e50c1fd05 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -127,7 +127,13 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, runMode c if err != nil { return 0, codeHash, common.Hash{}, nil, true, err } - evictProgram(statedb, oldModuleHash, currentVersion, debugMode, runMode, expired) + + program, err := p.getActiveProgram(codeHash, time, params) + if err != nil { + return 0, codeHash, common.Hash{}, nil, true, err + } + + evictProgram(statedb, oldModuleHash, program.asmSize(), currentVersion, debugMode, runMode, expired) } if err := p.moduleHashes.Set(codeHash, info.moduleHash); err != nil { return 0, codeHash, common.Hash{}, nil, true, err @@ -247,7 +253,7 @@ func (p Programs) CallProgram( if runmode == core.MessageCommitMode { arbos_tag = statedb.Database().WasmCacheTag() } - ret, err := callProgram(address, moduleHash, localAsm, scope, interpreter, tracingInfo, calldata, evmData, goParams, model, arbos_tag) + ret, err := callProgram(address, moduleHash, localAsm, program.asmSize(), scope, interpreter, tracingInfo, calldata, evmData, goParams, model, arbos_tag) if len(ret) > 0 && arbosVersion >= gethParams.ArbosVersion_StylusFixes { // Ensure that return data costs as least as much as it would in the EVM. evmCost := evmMemoryCost(uint64(len(ret))) @@ -433,7 +439,7 @@ func (p Programs) SetProgramCached( } cacheProgram(db, moduleHash, program, address, code, codeHash, params, debug, time, runMode) } else { - evictProgram(db, moduleHash, program.version, debug, runMode, expired) + evictProgram(db, moduleHash, program.asmSize(), program.version, debug, runMode, expired) } program.cached = cache return p.setProgram(codeHash, program) diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index f7191dca8f..df64a6fd39 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -97,7 +97,7 @@ func activateProgram( // stub any non-consensus, Rust-side caching updates func cacheProgram(db vm.StateDB, module common.Hash, program Program, addressForLogging common.Address, code []byte, codeHash common.Hash, params *StylusParams, debug bool, time uint64, runMode core.MessageRunMode) { } -func evictProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, mode core.MessageRunMode, forever bool) { +func evictProgram(db vm.StateDB, module common.Hash, asmSizeEstimate uint32, version uint16, debug bool, mode core.MessageRunMode, forever bool) { } //go:wasmimport programs new_program @@ -136,6 +136,7 @@ func callProgram( address common.Address, moduleHash common.Hash, _localAsm []byte, + _asmSizeEstimate uint32, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, From 7e0de89ca655a8c930c302ecab7049f244dc02cf Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 15 Aug 2024 16:47:41 -0300 Subject: [PATCH 019/101] Basic stylus cache metrics --- arbitrator/stylus/src/cache.rs | 26 ++++++++++++++++++++++++++ arbitrator/stylus/src/lib.rs | 8 +++++++- arbos/programs/native.go | 17 +++++++++++++++++ arbos/programs/programs.go | 1 + 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 300f0de35a..fc4cce853a 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -73,6 +73,18 @@ impl HeapSize for CacheItem { } } +#[repr(C)] +pub struct CacheContainerMetrics { + pub size_bytes: u32, + pub size_entries: u32, +} + +#[repr(C)] +pub struct CacheMetrics { + pub lru: CacheContainerMetrics, + pub long_term: CacheContainerMetrics, +} + impl InitCache { // current implementation only has one tag that stores to the long_term // future implementations might have more, but 0 is a reserved tag @@ -176,4 +188,18 @@ impl InitCache { let _ = cache.lru.insert(key, item); // not all will fit, just a heuristic } } + + pub fn get_metrics() -> CacheMetrics { + let cache = cache!(); + return CacheMetrics { + lru: CacheContainerMetrics { + size_bytes: cache.lru.current_size().try_into().unwrap(), + size_entries: cache.lru.len().try_into().unwrap(), + }, + long_term: CacheContainerMetrics { + size_bytes: 0, // not tracked at this moment + size_entries: cache.long_term.len().try_into().unwrap(), + }, + } + } } diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 979736054c..a660096045 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -11,7 +11,7 @@ use arbutil::{ format::DebugBytes, Bytes32, }; -use cache::InitCache; +use cache::{InitCache, CacheMetrics}; use evm_api::NativeRequestHandler; use eyre::ErrReport; use native::NativeInstance; @@ -357,3 +357,9 @@ pub unsafe extern "C" fn stylus_drop_vec(vec: RustBytes) { mem::drop(vec.into_vec()) } } + +/// Gets cache metrics. +#[no_mangle] +pub extern "C" fn stylus_get_cache_metrics() -> CacheMetrics { + InitCache::get_metrics() +} diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 5908741abf..b59c96e0bf 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/offchainlabs/nitro/arbos/burn" "github.com/offchainlabs/nitro/arbos/util" "github.com/offchainlabs/nitro/arbutil" @@ -45,6 +46,13 @@ type bytes32 = C.Bytes32 type rustBytes = C.RustBytes type rustSlice = C.RustSlice +var ( + stylusCacheLRUSizeBytesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size/bytes", nil) + stylusCacheLRUSizeEntriesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size/entries", nil) + + stylusCacheLongTermSizeEntriesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/longterm/size/entries", nil) +) + func activateProgram( db vm.StateDB, program common.Address, @@ -261,6 +269,15 @@ func callProgram( return data, err } +func getMetrics() { + metrics := C.stylus_get_cache_metrics() + + stylusCacheLRUSizeBytesGauge.Update(int64(metrics.lru.size_bytes)) + stylusCacheLRUSizeEntriesGauge.Update(int64(metrics.lru.size_entries)) + + stylusCacheLongTermSizeEntriesGauge.Update(int64(metrics.lru.size_entries)) +} + //export handleReqImpl func handleReqImpl(apiId usize, req_type u32, data *rustSlice, costPtr *u64, out_response *C.GoSliceData, out_raw_data *C.GoSliceData) { api := getApi(apiId) diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index 4e50c1fd05..bf2e6cc8e1 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -264,6 +264,7 @@ func (p Programs) CallProgram( maxGasToReturn := startingGas - evmCost contract.Gas = am.MinInt(contract.Gas, maxGasToReturn) } + getMetrics() return ret, err } From 9bc34deef45a27b5262ebbaa8aba9d62cec32af7 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Fri, 16 Aug 2024 10:51:17 -0300 Subject: [PATCH 020/101] clru instead of lru-mem --- arbitrator/Cargo.lock | 18 +++++++---------- arbitrator/stylus/Cargo.toml | 3 +-- arbitrator/stylus/src/cache.rs | 36 +++++++++++++++------------------- arbos/programs/native.go | 1 + arbos/programs/wasm.go | 2 ++ 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index a46e000ce2..6048733acb 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -496,6 +496,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "clru" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" + [[package]] name = "colorchoice" version = "1.0.2" @@ -1342,15 +1348,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "lru-mem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5c8c26d903a41c80d4cc171940a57a4d1bc51139ebd6aad87e2f9ae3774780" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "mach" version = "0.3.2" @@ -2279,14 +2276,13 @@ dependencies = [ "bincode", "brotli", "caller-env", + "clru", "derivative", "eyre", "fnv", "hex", "lazy_static", "libc", - "lru", - "lru-mem", "num-bigint", "parking_lot", "prover", diff --git a/arbitrator/stylus/Cargo.toml b/arbitrator/stylus/Cargo.toml index 45c06fc881..ea1d878ea0 100644 --- a/arbitrator/stylus/Cargo.toml +++ b/arbitrator/stylus/Cargo.toml @@ -25,8 +25,7 @@ eyre = "0.6.5" rand = "0.8.5" fnv = "1.0.7" hex = "0.4.3" -lru-mem = "0.3.0" -lru = "0.12.4" +clru = "0.6.2" [dev-dependencies] num-bigint = "0.4.4" diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index fc4cce853a..7b625de216 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -4,11 +4,12 @@ use arbutil::Bytes32; use eyre::Result; use lazy_static::lazy_static; -use lru_mem::{HeapSize, LruCache}; +use clru::{CLruCache, CLruCacheConfig, WeightScale}; use parking_lot::Mutex; use prover::programs::config::CompileConfig; -use std::collections::HashMap; +use std::{collections::HashMap, num::NonZeroUsize}; use wasmer::{Engine, Module, Store}; +use std::hash::RandomState; use crate::target_cache::target_native; @@ -24,7 +25,7 @@ macro_rules! cache { pub struct InitCache { long_term: HashMap, - lru: LruCache, + lru: CLruCache, } #[derive(Clone, Copy, Hash, PartialEq, Eq)] @@ -44,12 +45,6 @@ impl CacheKey { } } -impl HeapSize for CacheKey { - fn heap_size(&self) -> usize { - 0 - } -} - #[derive(Clone)] struct CacheItem { module: Module, @@ -67,9 +62,10 @@ impl CacheItem { } } -impl HeapSize for CacheItem { - fn heap_size(&self) -> usize { - return self.asm_size_estimate.try_into().unwrap(); +struct CustomWeightScale; +impl WeightScale for CustomWeightScale { + fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { + val.asm_size_estimate.try_into().unwrap() } } @@ -94,15 +90,14 @@ impl InitCache { fn new(size: usize) -> Self { Self { long_term: HashMap::new(), - lru: LruCache::new(size), + lru: CLruCache::with_config(CLruCacheConfig::new(NonZeroUsize::new(size).unwrap()).with_scale(CustomWeightScale)), } } - // TODO: Check if needs to shrink capacity pub fn set_lru_size(size: u32) { cache!() .lru - .set_max_size(size.try_into().unwrap()) + .resize(NonZeroUsize::new(size.try_into().unwrap()).unwrap()) } /// Retrieves a cached value, updating items as necessary. @@ -143,7 +138,8 @@ impl InitCache { if long_term_tag == Self::ARBOS_TAG { cache.long_term.insert(key, item.clone()); } else { - cache.lru.touch(&key) + // only calls get to move the key to the head of the LRU list + cache.lru.get(&key); } return Ok(item.data()); } @@ -157,7 +153,7 @@ impl InitCache { let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { // TODO: handle result - let _ = cache.lru.insert(key, item); + let _ = cache.lru.put_with_weight(key, item); } else { cache.long_term.insert(key, item); } @@ -173,7 +169,7 @@ impl InitCache { let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { // TODO: handle result - let _ = cache.lru.insert(key, item); + let _ = cache.lru.put_with_weight(key, item); } } @@ -185,7 +181,7 @@ impl InitCache { let cache = &mut *cache; for (key, item) in cache.long_term.drain() { // TODO: handle result - let _ = cache.lru.insert(key, item); // not all will fit, just a heuristic + let _ = cache.lru.put_with_weight(key, item); // not all will fit, just a heuristic } } @@ -193,7 +189,7 @@ impl InitCache { let cache = cache!(); return CacheMetrics { lru: CacheContainerMetrics { - size_bytes: cache.lru.current_size().try_into().unwrap(), + size_bytes: cache.lru.weight().try_into().unwrap(), size_entries: cache.lru.len().try_into().unwrap(), }, long_term: CacheContainerMetrics { diff --git a/arbos/programs/native.go b/arbos/programs/native.go index b59c96e0bf..22e5f411e3 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -271,6 +271,7 @@ func callProgram( func getMetrics() { metrics := C.stylus_get_cache_metrics() + log.Error("CacheMetrics", "metrics", metrics) stylusCacheLRUSizeBytesGauge.Update(int64(metrics.lru.size_bytes)) stylusCacheLRUSizeEntriesGauge.Update(int64(metrics.lru.size_entries)) diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index df64a6fd39..ecf685824e 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -152,6 +152,8 @@ func callProgram( return retData, err } +func getMetrics() {} + func CallProgramLoop( moduleHash common.Hash, calldata []byte, From f4c723cc9c7c25aa33929587781151f0e6f7dc91 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Fri, 16 Aug 2024 19:39:09 -0300 Subject: [PATCH 021/101] Simplifies stylus lru cache metrics retrieval --- arbitrator/stylus/src/cache.rs | 26 +++++++------------------- arbitrator/stylus/src/lib.rs | 8 ++++---- arbos/programs/native.go | 15 +++++---------- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 7b625de216..035286fc4a 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -70,15 +70,9 @@ impl WeightScale for CustomWeightScale { } #[repr(C)] -pub struct CacheContainerMetrics { - pub size_bytes: u32, - pub size_entries: u32, -} - -#[repr(C)] -pub struct CacheMetrics { - pub lru: CacheContainerMetrics, - pub long_term: CacheContainerMetrics, +pub struct LruCacheMetrics { + pub size: u64, + pub count: u64, } impl InitCache { @@ -185,17 +179,11 @@ impl InitCache { } } - pub fn get_metrics() -> CacheMetrics { + pub fn get_lru_metrics() -> LruCacheMetrics { let cache = cache!(); - return CacheMetrics { - lru: CacheContainerMetrics { - size_bytes: cache.lru.weight().try_into().unwrap(), - size_entries: cache.lru.len().try_into().unwrap(), - }, - long_term: CacheContainerMetrics { - size_bytes: 0, // not tracked at this moment - size_entries: cache.long_term.len().try_into().unwrap(), - }, + return LruCacheMetrics{ + size: cache.lru.weight().try_into().unwrap(), + count: cache.lru.len().try_into().unwrap(), } } } diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index a660096045..e983dd5320 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -11,7 +11,7 @@ use arbutil::{ format::DebugBytes, Bytes32, }; -use cache::{InitCache, CacheMetrics}; +use cache::{InitCache, LruCacheMetrics}; use evm_api::NativeRequestHandler; use eyre::ErrReport; use native::NativeInstance; @@ -358,8 +358,8 @@ pub unsafe extern "C" fn stylus_drop_vec(vec: RustBytes) { } } -/// Gets cache metrics. +/// Gets lru cache metrics. #[no_mangle] -pub extern "C" fn stylus_get_cache_metrics() -> CacheMetrics { - InitCache::get_metrics() +pub extern "C" fn stylus_get_lru_cache_metrics() -> LruCacheMetrics { + InitCache::get_lru_metrics() } diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 22e5f411e3..4b778a9e14 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -47,10 +47,8 @@ type rustBytes = C.RustBytes type rustSlice = C.RustSlice var ( - stylusCacheLRUSizeBytesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size/bytes", nil) - stylusCacheLRUSizeEntriesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size/entries", nil) - - stylusCacheLongTermSizeEntriesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/longterm/size/entries", nil) + stylusLRUCacheSizeKbGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size_kilobytes", nil) + stylusLRUCacheSizeCountGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/count", nil) ) func activateProgram( @@ -270,13 +268,10 @@ func callProgram( } func getMetrics() { - metrics := C.stylus_get_cache_metrics() - log.Error("CacheMetrics", "metrics", metrics) - - stylusCacheLRUSizeBytesGauge.Update(int64(metrics.lru.size_bytes)) - stylusCacheLRUSizeEntriesGauge.Update(int64(metrics.lru.size_entries)) + metrics := C.stylus_get_lru_cache_metrics() - stylusCacheLongTermSizeEntriesGauge.Update(int64(metrics.lru.size_entries)) + stylusLRUCacheSizeKbGauge.Update(int64(metrics.size)) + stylusLRUCacheSizeCountGauge.Update(int64(metrics.count)) } //export handleReqImpl From 098fca51ee6eb8567b6f8e8fa96533d936d630e6 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Sun, 18 Aug 2024 21:06:32 -0300 Subject: [PATCH 022/101] AsmSizeEstimate to AsmSizeEstimateKb, CLI rust cache size flag in Mb --- arbitrator/stylus/src/cache.rs | 20 ++++++++++---------- arbitrator/stylus/src/lib.rs | 4 ++-- arbnode/inbox_test.go | 2 +- arbos/programs/native.go | 18 +++++++++--------- arbos/programs/programs.go | 2 +- arbos/programs/wasm.go | 2 +- execution/gethexec/blockchain.go | 6 +++--- execution/gethexec/executionengine.go | 6 +++--- execution/gethexec/node.go | 2 +- system_tests/common_test.go | 2 +- 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 035286fc4a..3d760e40c9 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -49,12 +49,12 @@ impl CacheKey { struct CacheItem { module: Module, engine: Engine, - asm_size_estimate: u32, + asm_size_estimate_kb: u32, } impl CacheItem { - fn new(module: Module, engine: Engine, asm_size_estimate: u32) -> Self { - Self { module, engine, asm_size_estimate } + fn new(module: Module, engine: Engine, asm_size_estimate_kb: u32) -> Self { + Self { module, engine, asm_size_estimate_kb } } fn data(&self) -> (Module, Store) { @@ -65,13 +65,13 @@ impl CacheItem { struct CustomWeightScale; impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { - val.asm_size_estimate.try_into().unwrap() + val.asm_size_estimate_kb.try_into().unwrap() } } #[repr(C)] pub struct LruCacheMetrics { - pub size: u64, + pub size_kb: u64, pub count: u64, } @@ -88,10 +88,10 @@ impl InitCache { } } - pub fn set_lru_size(size: u32) { + pub fn set_lru_size(size_kb: u32) { cache!() .lru - .resize(NonZeroUsize::new(size.try_into().unwrap()).unwrap()) + .resize(NonZeroUsize::new(size_kb.try_into().unwrap()).unwrap()) } /// Retrieves a cached value, updating items as necessary. @@ -116,7 +116,7 @@ impl InitCache { pub fn insert( module_hash: Bytes32, module: &[u8], - asm_size_estimate: u32, + asm_size_estimate_kb: u32, version: u16, long_term_tag: u32, debug: bool, @@ -142,7 +142,7 @@ impl InitCache { let engine = CompileConfig::version(version, debug).engine(target_native()); let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; - let item = CacheItem::new(module, engine, asm_size_estimate); + let item = CacheItem::new(module, engine, asm_size_estimate_kb); let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { @@ -182,7 +182,7 @@ impl InitCache { pub fn get_lru_metrics() -> LruCacheMetrics { let cache = cache!(); return LruCacheMetrics{ - size: cache.lru.weight().try_into().unwrap(), + size_kb: cache.lru.weight().try_into().unwrap(), count: cache.lru.len().try_into().unwrap(), } } diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index e983dd5320..6b62e4103a 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -304,8 +304,8 @@ pub unsafe extern "C" fn stylus_call( /// resize lru #[no_mangle] -pub extern "C" fn stylus_cache_lru_resize(size: u32) { - InitCache::set_lru_size(size); +pub extern "C" fn stylus_cache_lru_resize(size_kb: u32) { + InitCache::set_lru_size(size_kb); } /// Caches an activated user program. diff --git a/arbnode/inbox_test.go b/arbnode/inbox_test.go index e0c97bb871..42661c44a6 100644 --- a/arbnode/inbox_test.go +++ b/arbnode/inbox_test.go @@ -74,7 +74,7 @@ func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (* } stylusTargetConfig := &gethexec.DefaultStylusTargetConfig Require(t, stylusTargetConfig.Validate()) // pre-processes config (i.a. parses wasmTargets) - if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheSize, &gethexec.DefaultStylusTargetConfig); err != nil { + if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheSizeMb, &gethexec.DefaultStylusTargetConfig); err != nil { Fail(t, err) } execSeq := &execClientWrapper{execEngine, t} diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 4b778a9e14..6cbf01c0cd 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -217,7 +217,7 @@ func callProgram( address common.Address, moduleHash common.Hash, localAsm []byte, - asmSizeEstimate uint32, + asmSizeEstimateKb uint32, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, @@ -245,7 +245,7 @@ func callProgram( output := &rustBytes{} status := userStatus(C.stylus_call( goSlice(localAsm), - u32(asmSizeEstimate), + u32(asmSizeEstimateKb), goSlice(calldata), stylusParams.encode(), evmApi.cNative, @@ -270,7 +270,7 @@ func callProgram( func getMetrics() { metrics := C.stylus_get_lru_cache_metrics() - stylusLRUCacheSizeKbGauge.Update(int64(metrics.size)) + stylusLRUCacheSizeKbGauge.Update(int64(metrics.size_kb)) stylusLRUCacheSizeCountGauge.Update(int64(metrics.count)) } @@ -302,27 +302,27 @@ func cacheProgram(db vm.StateDB, module common.Hash, program Program, addressFor // Evicts a program in Rust. We write a record so that we can undo on revert, unless we don't need to (e.g. expired) // For gas estimation and eth_call, we ignore permanent updates and rely on Rust's LRU. -func evictProgram(db vm.StateDB, module common.Hash, asmSizeEstimate uint32, version uint16, debug bool, runMode core.MessageRunMode, forever bool) { +func evictProgram(db vm.StateDB, module common.Hash, asmSizeEstimateKb uint32, version uint16, debug bool, runMode core.MessageRunMode, forever bool) { if runMode == core.MessageCommitMode { tag := db.Database().WasmCacheTag() state.EvictWasmRust(module, version, tag, debug) if !forever { - db.RecordEvictWasm(state.EvictWasm{ModuleHash: module, Version: version, Tag: tag, Debug: debug, AsmSizeEstimate: asmSizeEstimate}) + db.RecordEvictWasm(state.EvictWasm{ModuleHash: module, Version: version, Tag: tag, Debug: debug, AsmSizeEstimateKb: asmSizeEstimateKb}) } } } func init() { - state.CacheWasmRust = func(asm []byte, moduleHash common.Hash, asmSizeEstimate uint32, version uint16, tag uint32, debug bool) { - C.stylus_cache_module(goSlice(asm), hashToBytes32(moduleHash), u32(asmSizeEstimate), u16(version), u32(tag), cbool(debug)) + state.CacheWasmRust = func(asm []byte, moduleHash common.Hash, asmSizeEstimateKb uint32, version uint16, tag uint32, debug bool) { + C.stylus_cache_module(goSlice(asm), hashToBytes32(moduleHash), u32(asmSizeEstimateKb), u16(version), u32(tag), cbool(debug)) } state.EvictWasmRust = func(moduleHash common.Hash, version uint16, tag uint32, debug bool) { C.stylus_evict_module(hashToBytes32(moduleHash), u16(version), u32(tag), cbool(debug)) } } -func ResizeWasmLruCache(size uint32) { - C.stylus_cache_lru_resize(u32(size)) +func ResizeWasmLruCache(sizeKb uint32) { + C.stylus_cache_lru_resize(u32(sizeKb)) } const DefaultTargetDescriptionArm = "arm64-linux-unknown+neon" diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index bf2e6cc8e1..9ca43fa224 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -253,7 +253,7 @@ func (p Programs) CallProgram( if runmode == core.MessageCommitMode { arbos_tag = statedb.Database().WasmCacheTag() } - ret, err := callProgram(address, moduleHash, localAsm, program.asmSize(), scope, interpreter, tracingInfo, calldata, evmData, goParams, model, arbos_tag) + ret, err := callProgram(address, moduleHash, localAsm, program.asmEstimateKb.ToUint32(), scope, interpreter, tracingInfo, calldata, evmData, goParams, model, arbos_tag) if len(ret) > 0 && arbosVersion >= gethParams.ArbosVersion_StylusFixes { // Ensure that return data costs as least as much as it would in the EVM. evmCost := evmMemoryCost(uint64(len(ret))) diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index ecf685824e..4b9a3ad473 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -136,7 +136,7 @@ func callProgram( address common.Address, moduleHash common.Hash, _localAsm []byte, - _asmSizeEstimate uint32, + _asmSizeEstimateKb uint32, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, diff --git a/execution/gethexec/blockchain.go b/execution/gethexec/blockchain.go index 54934dbdf3..da6a22bdb4 100644 --- a/execution/gethexec/blockchain.go +++ b/execution/gethexec/blockchain.go @@ -37,7 +37,7 @@ type CachingConfig struct { SnapshotRestoreGasLimit uint64 `koanf:"snapshot-restore-gas-limit"` MaxNumberOfBlocksToSkipStateSaving uint32 `koanf:"max-number-of-blocks-to-skip-state-saving"` MaxAmountOfGasToSkipStateSaving uint64 `koanf:"max-amount-of-gas-to-skip-state-saving"` - StylusLRUCacheSize uint32 `koanf:"stylus-lru-cache-size"` + StylusLRUCacheSizeMb uint32 `koanf:"stylus-lru-cache-size"` StateScheme string `koanf:"state-scheme"` StateHistory uint64 `koanf:"state-history"` } @@ -54,7 +54,7 @@ func CachingConfigAddOptions(prefix string, f *flag.FlagSet) { f.Uint64(prefix+".snapshot-restore-gas-limit", DefaultCachingConfig.SnapshotRestoreGasLimit, "maximum gas rolled back to recover snapshot") f.Uint32(prefix+".max-number-of-blocks-to-skip-state-saving", DefaultCachingConfig.MaxNumberOfBlocksToSkipStateSaving, "maximum number of blocks to skip state saving to persistent storage (archive node only) -- warning: this option seems to cause issues") f.Uint64(prefix+".max-amount-of-gas-to-skip-state-saving", DefaultCachingConfig.MaxAmountOfGasToSkipStateSaving, "maximum amount of gas in blocks to skip saving state to Persistent storage (archive node only) -- warning: this option seems to cause issues") - f.Uint32(prefix+".stylus-lru-cache-size", DefaultCachingConfig.StylusLRUCacheSize, "capacity, in bytes, of the LRU cache that keeps initialized stylus programs") + f.Uint32(prefix+".stylus-lru-cache-size", DefaultCachingConfig.StylusLRUCacheSizeMb, "capacity, in megabytes, of the LRU cache that keeps initialized stylus programs") f.String(prefix+".state-scheme", DefaultCachingConfig.StateScheme, "scheme to use for state trie storage (hash, path)") f.Uint64(prefix+".state-history", DefaultCachingConfig.StateHistory, "number of recent blocks to retain state history for (path state-scheme only)") } @@ -75,7 +75,7 @@ var DefaultCachingConfig = CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSize: 256 * 10 * 1024, + StylusLRUCacheSizeMb: 10, StateScheme: rawdb.HashScheme, StateHistory: getStateHistory(DefaultSequencerConfig.MaxBlockSpeed), } diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 8594d5867d..42651ed800 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -182,9 +182,9 @@ func populateStylusTargetCache(targetConfig *StylusTargetConfig) error { return nil } -func (s *ExecutionEngine) Initialize(rustCacheSize uint32, targetConfig *StylusTargetConfig) error { - if rustCacheSize != 0 { - programs.ResizeWasmLruCache(rustCacheSize) +func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *StylusTargetConfig) error { + if rustCacheSizeMb != 0 { + programs.ResizeWasmLruCache(arbmath.SaturatingUMul(rustCacheSizeMb, 1024)) } if err := populateStylusTargetCache(targetConfig); err != nil { return fmt.Errorf("error populating stylus target cache: %w", err) diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index 93bb254ed8..b602dbd323 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -308,7 +308,7 @@ func (n *ExecutionNode) MarkFeedStart(to arbutil.MessageIndex) { func (n *ExecutionNode) Initialize(ctx context.Context) error { config := n.ConfigFetcher() - err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheSize, &config.StylusTarget) + err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheSizeMb, &config.StylusTarget) if err != nil { return fmt.Errorf("error initializing execution engine: %w", err) } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 363f1050fb..c1e9ff384b 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -166,7 +166,7 @@ var TestCachingConfig = gethexec.CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSize: 0, + StylusLRUCacheSizeMb: 0, StateScheme: env.GetTestStateScheme(), } From 6261168ea808ed3da2e226ce9baadadb4af822f2 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Sun, 18 Aug 2024 22:28:29 -0300 Subject: [PATCH 023/101] Fixes weight of stylus cache entry --- arbitrator/stylus/src/cache.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 3d760e40c9..e7b9c8a3dc 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -65,7 +65,13 @@ impl CacheItem { struct CustomWeightScale; impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { - val.asm_size_estimate_kb.try_into().unwrap() + let mut w = val.asm_size_estimate_kb.try_into().unwrap(); + if w > 0 { + // clru defines the weight of an entry as the number returned by this function plus one. + // Therefore, we need to subtract one from the weight to get the actual weight of the entry. + w -= 1; + } + return w; } } From a715fb4c0eaf049e142fc2029ab6f9450f9c933c Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Sun, 18 Aug 2024 22:48:29 -0300 Subject: [PATCH 024/101] Handles cache.lru.put_with_weight return --- arbitrator/stylus/src/cache.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index e7b9c8a3dc..e13c78edc1 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -152,8 +152,10 @@ impl InitCache { let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { - // TODO: handle result - let _ = cache.lru.put_with_weight(key, item); + match cache.lru.put_with_weight(key, item) { + Err(_) => println!("Failed to insert into LRU cache, item too large"), + Ok(_) => (), + }; } else { cache.long_term.insert(key, item); } @@ -168,8 +170,10 @@ impl InitCache { let key = CacheKey::new(module_hash, version, debug); let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { - // TODO: handle result - let _ = cache.lru.put_with_weight(key, item); + match cache.lru.put_with_weight(key, item) { + Err(_) => println!("Failed to insert into LRU cache, item too large"), + Ok(_) => (), + }; } } @@ -180,8 +184,11 @@ impl InitCache { let mut cache = cache!(); let cache = &mut *cache; for (key, item) in cache.long_term.drain() { - // TODO: handle result - let _ = cache.lru.put_with_weight(key, item); // not all will fit, just a heuristic + // not all will fit, just a heuristic + match cache.lru.put_with_weight(key, item) { + Err(_) => println!("Failed to insert into LRU cache, item too large"), + Ok(_) => (), + }; } } From 1c21c3a5609dadb7e3ad89979beb4770e3e60493 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 10:11:45 -0300 Subject: [PATCH 025/101] TestWasLruCache --- arbitrator/stylus/src/cache.rs | 10 +++- arbitrator/stylus/src/lib.rs | 7 +++ arbos/programs/native.go | 23 +++++++- arbos/programs/programs.go | 2 +- arbos/programs/wasm.go | 2 +- execution/gethexec/executionengine.go | 17 +++++- system_tests/program_test.go | 82 +++++++++++++++++++++++++++ 7 files changed, 137 insertions(+), 6 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index e13c78edc1..2ef674bf6e 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -194,9 +194,15 @@ impl InitCache { pub fn get_lru_metrics() -> LruCacheMetrics { let cache = cache!(); + let count = cache.lru.len(); return LruCacheMetrics{ - size_kb: cache.lru.weight().try_into().unwrap(), - count: cache.lru.len().try_into().unwrap(), + size_kb: (cache.lru.weight() + count).try_into().unwrap(), + count: count.try_into().unwrap(), } } + + // only used for testing + pub fn clear_lru_cache() { + cache!().lru.clear(); + } } diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 6b62e4103a..576d041c28 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -363,3 +363,10 @@ pub unsafe extern "C" fn stylus_drop_vec(vec: RustBytes) { pub extern "C" fn stylus_get_lru_cache_metrics() -> LruCacheMetrics { InitCache::get_lru_metrics() } + +/// Clears lru cache. +/// Only used for testing purposes. +#[no_mangle] +pub extern "C" fn stylus_clear_lru_cache() { + InitCache::clear_lru_cache() +} diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 6cbf01c0cd..c10cc50f30 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -267,7 +267,8 @@ func callProgram( return data, err } -func getMetrics() { +// exposes for testing +func GetMetrics() { metrics := C.stylus_get_lru_cache_metrics() stylusLRUCacheSizeKbGauge.Update(int64(metrics.size_kb)) @@ -325,6 +326,26 @@ func ResizeWasmLruCache(sizeKb uint32) { C.stylus_cache_lru_resize(u32(sizeKb)) } +// exported for testing +type WasmLruCacheMetrics struct { + SizeKb uint64 + Count uint64 +} + +// exported for testing +func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { + metrics := C.stylus_get_lru_cache_metrics() + return &WasmLruCacheMetrics{ + SizeKb: uint64(metrics.size_kb), + Count: uint64(metrics.count), + } +} + +// exported for testing +func ClearWasmLruCache() { + C.stylus_clear_lru_cache() +} + const DefaultTargetDescriptionArm = "arm64-linux-unknown+neon" const DefaultTargetDescriptionX86 = "x86_64-linux-unknown+sse4.2+lzcnt+bmi" diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index 9ca43fa224..3909b0fceb 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -264,7 +264,7 @@ func (p Programs) CallProgram( maxGasToReturn := startingGas - evmCost contract.Gas = am.MinInt(contract.Gas, maxGasToReturn) } - getMetrics() + GetMetrics() return ret, err } diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 4b9a3ad473..3889d47f34 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -152,7 +152,7 @@ func callProgram( return retData, err } -func getMetrics() {} +func GetMetrics() {} func CallProgramLoop( moduleHash common.Hash, diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 42651ed800..dce3639d02 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -184,7 +184,7 @@ func populateStylusTargetCache(targetConfig *StylusTargetConfig) error { func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *StylusTargetConfig) error { if rustCacheSizeMb != 0 { - programs.ResizeWasmLruCache(arbmath.SaturatingUMul(rustCacheSizeMb, 1024)) + s.ResizeWasmLruCache(arbmath.SaturatingUMul(rustCacheSizeMb, 1024)) } if err := populateStylusTargetCache(targetConfig); err != nil { return fmt.Errorf("error populating stylus target cache: %w", err) @@ -192,6 +192,21 @@ func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *Stylu return nil } +// exported for testing +func (s *ExecutionEngine) ResizeWasmLruCache(sizeKb uint32) { + programs.ResizeWasmLruCache(sizeKb) +} + +// exported for testing +func (s *ExecutionEngine) GetWasmLruCacheMetrics() *programs.WasmLruCacheMetrics { + return programs.GetWasmLruCacheMetrics() +} + +// exported for testing +func (s *ExecutionEngine) ClearWasmLruCache() { + programs.ClearWasmLruCache() +} + func (s *ExecutionEngine) SetRecorder(recorder *BlockRecorder) { if s.Started() { panic("trying to set recorder after start") diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 83c066fdb5..034e1c5fd3 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/google/go-cmp/cmp" "github.com/offchainlabs/nitro/arbcompress" "github.com/offchainlabs/nitro/arbos/programs" "github.com/offchainlabs/nitro/arbos/util" @@ -2007,3 +2008,84 @@ func checkWasmStoreContent(t *testing.T, wasmDb ethdb.KeyValueStore, targets []s } } } + +func TestWasmLruCache(t *testing.T) { + builder, auth, cleanup := setupProgramTest(t, true) + ctx := builder.ctx + l2info := builder.L2Info + l2client := builder.L2.Client + defer cleanup() + + builder.L2.ExecNode.ExecEngine.ClearWasmLruCache() + lruMetrics := builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + expectedLruMetrics := &programs.WasmLruCacheMetrics{} + if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { + t.Fatalf("lru cache metrics different than expected: %s", diff) + } + + lruCacheSize := uint32(500) + builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) + + // fallible wasm program will not be cached since its size is greater than lruCacheSize + fallibleAsmEstimateSizeKb := uint64(551) + fallibleProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("fallible")) + tx := l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) + Require(t, l2client.SendTransaction(ctx, tx)) + _, err := EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err) + lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + expectedLruMetrics = &programs.WasmLruCacheMetrics{} + if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { + t.Fatalf("lru cache metrics different than expected: %s", diff) + } + + // resize lru cache + lruCacheSize = uint32(1500) + builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) + + // fallible wasm program will be cached + tx = l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) + Require(t, l2client.SendTransaction(ctx, tx)) + _, err = EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err) + lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + expectedLruMetrics = &programs.WasmLruCacheMetrics{ + SizeKb: fallibleAsmEstimateSizeKb, + Count: 1, + } + if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { + t.Fatalf("lru cache metrics different than expected: %s", diff) + } + + // keccak wasm program will be cached + keccakAsmEstimateSizeKb := uint64(583) + keccakProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("keccak")) + tx = l2info.PrepareTxTo("Owner", &keccakProgramAddress, l2info.TransferGas, nil, []byte{0x01}) + Require(t, l2client.SendTransaction(ctx, tx)) + _, err = EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err) + lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + expectedLruMetrics = &programs.WasmLruCacheMetrics{ + SizeKb: fallibleAsmEstimateSizeKb + keccakAsmEstimateSizeKb, + Count: 2, + } + if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { + t.Fatalf("lru cache metrics different than expected: %s", diff) + } + + // math wasm program will be cached, but since (fallible + keccak + math) > lruCacheSize, fallible will be evicted + mathAsmEstimateSizeKb := uint64(560) + mathProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("math")) + tx = l2info.PrepareTxTo("Owner", &mathProgramAddress, l2info.TransferGas, nil, []byte{0x01}) + Require(t, l2client.SendTransaction(ctx, tx)) + _, err = EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err) + lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + expectedLruMetrics = &programs.WasmLruCacheMetrics{ + SizeKb: keccakAsmEstimateSizeKb + mathAsmEstimateSizeKb, + Count: 2, + } + if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { + t.Fatalf("lru cache metrics different than expected: %s", diff) + } +} From 0ab8ebeb6b00c161b578fb454a8cb686cb364740 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 10:14:14 -0300 Subject: [PATCH 026/101] Removes -Wall from #cgo CFLAGS --- arbcompress/native.go | 2 +- arbos/programs/native.go | 2 +- arbos/programs/native_api.go | 2 +- arbos/programs/testconstants.go | 2 +- execution/gethexec/executionengine.go | 2 +- validator/server_arb/machine.go | 2 +- validator/server_arb/nitro_machine.go | 2 +- validator/server_arb/preimage_resolver.go | 2 +- validator/server_arb/prover_interface.go | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arbcompress/native.go b/arbcompress/native.go index 8244010979..f7b8f0b8e0 100644 --- a/arbcompress/native.go +++ b/arbcompress/native.go @@ -7,7 +7,7 @@ package arbcompress /* -#cgo CFLAGS: -g -Wall -I${SRCDIR}/../target/include/ +#cgo CFLAGS: -g -I${SRCDIR}/../target/include/ #cgo LDFLAGS: ${SRCDIR}/../target/lib/libstylus.a -lm #include "arbitrator.h" */ diff --git a/arbos/programs/native.go b/arbos/programs/native.go index c10cc50f30..1147a29d2d 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -7,7 +7,7 @@ package programs /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #cgo LDFLAGS: ${SRCDIR}/../../target/lib/libstylus.a -ldl -lm #include "arbitrator.h" diff --git a/arbos/programs/native_api.go b/arbos/programs/native_api.go index 6fbb630ef3..6cecb8ef63 100644 --- a/arbos/programs/native_api.go +++ b/arbos/programs/native_api.go @@ -7,7 +7,7 @@ package programs /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #cgo LDFLAGS: ${SRCDIR}/../../target/lib/libstylus.a -ldl -lm #include "arbitrator.h" diff --git a/arbos/programs/testconstants.go b/arbos/programs/testconstants.go index 1ab0e6e93b..44f69a52de 100644 --- a/arbos/programs/testconstants.go +++ b/arbos/programs/testconstants.go @@ -9,7 +9,7 @@ package programs // This file exists because cgo isn't allowed in tests /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #include "arbitrator.h" */ import "C" diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index dce3639d02..789a53e8e4 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -7,7 +7,7 @@ package gethexec /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #cgo LDFLAGS: ${SRCDIR}/../../target/lib/libstylus.a -ldl -lm #include "arbitrator.h" */ diff --git a/validator/server_arb/machine.go b/validator/server_arb/machine.go index adca9695e2..1e73e6b212 100644 --- a/validator/server_arb/machine.go +++ b/validator/server_arb/machine.go @@ -4,7 +4,7 @@ package server_arb /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #include "arbitrator.h" ResolvedPreimage preimageResolverC(size_t context, uint8_t preimageType, const uint8_t* hash); diff --git a/validator/server_arb/nitro_machine.go b/validator/server_arb/nitro_machine.go index 2b2cb230b6..926b1e8930 100644 --- a/validator/server_arb/nitro_machine.go +++ b/validator/server_arb/nitro_machine.go @@ -4,7 +4,7 @@ package server_arb /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #include "arbitrator.h" #include */ diff --git a/validator/server_arb/preimage_resolver.go b/validator/server_arb/preimage_resolver.go index cd4ea40e28..f01d79f4dd 100644 --- a/validator/server_arb/preimage_resolver.go +++ b/validator/server_arb/preimage_resolver.go @@ -4,7 +4,7 @@ package server_arb /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #include "arbitrator.h" extern ResolvedPreimage preimageResolver(size_t context, uint8_t preimageType, const uint8_t* hash); diff --git a/validator/server_arb/prover_interface.go b/validator/server_arb/prover_interface.go index bdd81ed588..3010d2138d 100644 --- a/validator/server_arb/prover_interface.go +++ b/validator/server_arb/prover_interface.go @@ -4,7 +4,7 @@ package server_arb /* -#cgo CFLAGS: -g -Wall -I../target/include/ +#cgo CFLAGS: -g -I../target/include/ #cgo LDFLAGS: ${SRCDIR}/../../target/lib/libstylus.a -ldl -lm #include "arbitrator.h" #include From 708417bd1a4c69d2e805eeb9cad8dd2cda92919f Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 10:23:58 -0300 Subject: [PATCH 027/101] Improves comments on stylus cache --- arbitrator/stylus/src/cache.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 2ef674bf6e..e7b4776bcd 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -67,8 +67,8 @@ impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { let mut w = val.asm_size_estimate_kb.try_into().unwrap(); if w > 0 { - // clru defines the weight of an entry as the number returned by this function plus one. - // Therefore, we need to subtract one from the weight to get the actual weight of the entry. + // clru defines that each entry consumes (weight + 1) of the cache capacity. + // Since we only want to use the weight as the size of the entry, we need to subtract 1. w -= 1; } return w; @@ -196,6 +196,7 @@ impl InitCache { let cache = cache!(); let count = cache.lru.len(); return LruCacheMetrics{ + // add 1 to each entry to account that we subtracted 1 in the weight calculation size_kb: (cache.lru.weight() + count).try_into().unwrap(), count: count.try_into().unwrap(), } From 6af08f46806ef7cce24f0d0a859ecb705e584435 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 11:20:41 -0300 Subject: [PATCH 028/101] Avoid multiple functions in programs to get metrics --- arbos/programs/native.go | 12 ++++-------- arbos/programs/programs.go | 2 +- arbos/programs/wasm.go | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 1147a29d2d..eba16a694a 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -267,14 +267,6 @@ func callProgram( return data, err } -// exposes for testing -func GetMetrics() { - metrics := C.stylus_get_lru_cache_metrics() - - stylusLRUCacheSizeKbGauge.Update(int64(metrics.size_kb)) - stylusLRUCacheSizeCountGauge.Update(int64(metrics.count)) -} - //export handleReqImpl func handleReqImpl(apiId usize, req_type u32, data *rustSlice, costPtr *u64, out_response *C.GoSliceData, out_raw_data *C.GoSliceData) { api := getApi(apiId) @@ -335,6 +327,10 @@ type WasmLruCacheMetrics struct { // exported for testing func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { metrics := C.stylus_get_lru_cache_metrics() + + stylusLRUCacheSizeKbGauge.Update(int64(metrics.size_kb)) + stylusLRUCacheSizeCountGauge.Update(int64(metrics.count)) + return &WasmLruCacheMetrics{ SizeKb: uint64(metrics.size_kb), Count: uint64(metrics.count), diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index 3909b0fceb..b324c98d0a 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -264,7 +264,7 @@ func (p Programs) CallProgram( maxGasToReturn := startingGas - evmCost contract.Gas = am.MinInt(contract.Gas, maxGasToReturn) } - GetMetrics() + GetWasmLruCacheMetrics() return ret, err } diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 3889d47f34..849ed88f42 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -152,7 +152,7 @@ func callProgram( return retData, err } -func GetMetrics() {} +func GetWasmLruCacheMetrics() {} func CallProgramLoop( moduleHash common.Hash, From 9792757163c83b69559bc9b68b6d5b1dcf3e57a9 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 11:54:21 -0300 Subject: [PATCH 029/101] Changes TestWasLruCache comparisons --- system_tests/program_test.go | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 034e1c5fd3..0c48bf7661 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "github.com/google/go-cmp/cmp" "github.com/offchainlabs/nitro/arbcompress" "github.com/offchainlabs/nitro/arbos/programs" "github.com/offchainlabs/nitro/arbos/util" @@ -2018,9 +2017,11 @@ func TestWasmLruCache(t *testing.T) { builder.L2.ExecNode.ExecEngine.ClearWasmLruCache() lruMetrics := builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() - expectedLruMetrics := &programs.WasmLruCacheMetrics{} - if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { - t.Fatalf("lru cache metrics different than expected: %s", diff) + if lruMetrics.Count != 0 { + t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 0, lruMetrics.Count) + } + if lruMetrics.SizeKb != 0 { + t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", 0, lruMetrics.SizeKb) } lruCacheSize := uint32(500) @@ -2034,9 +2035,11 @@ func TestWasmLruCache(t *testing.T) { _, err := EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() - expectedLruMetrics = &programs.WasmLruCacheMetrics{} - if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { - t.Fatalf("lru cache metrics different than expected: %s", diff) + if lruMetrics.Count != 0 { + t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 0, lruMetrics.Count) + } + if lruMetrics.SizeKb != 0 { + t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", 0, lruMetrics.SizeKb) } // resize lru cache @@ -2049,12 +2052,11 @@ func TestWasmLruCache(t *testing.T) { _, err = EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() - expectedLruMetrics = &programs.WasmLruCacheMetrics{ - SizeKb: fallibleAsmEstimateSizeKb, - Count: 1, + if lruMetrics.Count != 1 { + t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 1, lruMetrics.Count) } - if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { - t.Fatalf("lru cache metrics different than expected: %s", diff) + if lruMetrics.SizeKb != fallibleAsmEstimateSizeKb { + t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", fallibleAsmEstimateSizeKb, lruMetrics.SizeKb) } // keccak wasm program will be cached @@ -2065,12 +2067,11 @@ func TestWasmLruCache(t *testing.T) { _, err = EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() - expectedLruMetrics = &programs.WasmLruCacheMetrics{ - SizeKb: fallibleAsmEstimateSizeKb + keccakAsmEstimateSizeKb, - Count: 2, + if lruMetrics.Count != 2 { + t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { - t.Fatalf("lru cache metrics different than expected: %s", diff) + if lruMetrics.SizeKb != fallibleAsmEstimateSizeKb+keccakAsmEstimateSizeKb { + t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", fallibleAsmEstimateSizeKb+keccakAsmEstimateSizeKb, lruMetrics.SizeKb) } // math wasm program will be cached, but since (fallible + keccak + math) > lruCacheSize, fallible will be evicted @@ -2081,11 +2082,10 @@ func TestWasmLruCache(t *testing.T) { _, err = EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() - expectedLruMetrics = &programs.WasmLruCacheMetrics{ - SizeKb: keccakAsmEstimateSizeKb + mathAsmEstimateSizeKb, - Count: 2, + if lruMetrics.Count != 2 { + t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if diff := cmp.Diff(lruMetrics, expectedLruMetrics); diff != "" { - t.Fatalf("lru cache metrics different than expected: %s", diff) + if lruMetrics.SizeKb != keccakAsmEstimateSizeKb+mathAsmEstimateSizeKb { + t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", keccakAsmEstimateSizeKb+mathAsmEstimateSizeKb, lruMetrics.SizeKb) } } From f65a08447023b7303becda0aa24f253d06694777 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 11:55:25 -0300 Subject: [PATCH 030/101] Stylus LRU cache hits, misses, does not fit metrics --- arbitrator/stylus/src/cache.rs | 45 ++++++++++++++++++++++++++++++---- arbos/programs/native.go | 24 +++++++++++++----- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index e7b4776bcd..fe04bf854d 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -23,9 +23,16 @@ macro_rules! cache { }; } +pub struct LruCounters { + pub hits: u64, + pub misses: u64, + pub does_not_fit: u64, +} + pub struct InitCache { long_term: HashMap, lru: CLruCache, + lru_counters: LruCounters, } #[derive(Clone, Copy, Hash, PartialEq, Eq)] @@ -79,6 +86,9 @@ impl WeightScale for CustomWeightScale { pub struct LruCacheMetrics { pub size_kb: u64, pub count: u64, + pub hits: u64, + pub misses: u64, + pub does_not_fit: u64, } impl InitCache { @@ -91,6 +101,11 @@ impl InitCache { Self { long_term: HashMap::new(), lru: CLruCache::with_config(CLruCacheConfig::new(NonZeroUsize::new(size).unwrap()).with_scale(CustomWeightScale)), + lru_counters: LruCounters { + hits: 0, + misses: 0, + does_not_fit: 0, + }, } } @@ -112,8 +127,11 @@ impl InitCache { // See if the item is in the LRU cache, promoting if so if let Some(item) = cache.lru.get(&key) { - return Some(item.data()); + let data = item.data(); + cache.lru_counters.hits += 1; + return Some(data); } + cache.lru_counters.misses += 1; None } @@ -153,7 +171,10 @@ impl InitCache { let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { match cache.lru.put_with_weight(key, item) { - Err(_) => println!("Failed to insert into LRU cache, item too large"), + Err(_) => { + cache.lru_counters.does_not_fit += 1; + println!("Failed to insert into LRU cache, item too large"); + } Ok(_) => (), }; } else { @@ -193,13 +214,27 @@ impl InitCache { } pub fn get_lru_metrics() -> LruCacheMetrics { - let cache = cache!(); + let mut cache = cache!(); + let count = cache.lru.len(); - return LruCacheMetrics{ + let metrics = LruCacheMetrics{ // add 1 to each entry to account that we subtracted 1 in the weight calculation size_kb: (cache.lru.weight() + count).try_into().unwrap(), count: count.try_into().unwrap(), - } + + hits: cache.lru_counters.hits, + misses: cache.lru_counters.misses, + does_not_fit: cache.lru_counters.does_not_fit, + }; + + // empty counters + cache.lru_counters = LruCounters { + hits: 0, + misses: 0, + does_not_fit: 0, + }; + + return metrics } // only used for testing diff --git a/arbos/programs/native.go b/arbos/programs/native.go index eba16a694a..ef4de07ffa 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -47,8 +47,11 @@ type rustBytes = C.RustBytes type rustSlice = C.RustSlice var ( - stylusLRUCacheSizeKbGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size_kilobytes", nil) - stylusLRUCacheSizeCountGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/count", nil) + stylusLRUCacheSizeKbGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size_kilobytes", nil) + stylusLRUCacheSizeCountGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/count", nil) + stylusLRUCacheSizeHitsCounter = metrics.NewRegisteredCounter("arb/arbos/stylus/cache/lru/hits", nil) + stylusLRUCacheSizeMissesCounter = metrics.NewRegisteredCounter("arb/arbos/stylus/cache/lru/misses", nil) + stylusLRUCacheSizeDoesNotFitCounter = metrics.NewRegisteredCounter("arb/arbos/stylus/cache/lru/does_not_fit", nil) ) func activateProgram( @@ -320,8 +323,11 @@ func ResizeWasmLruCache(sizeKb uint32) { // exported for testing type WasmLruCacheMetrics struct { - SizeKb uint64 - Count uint64 + SizeKb uint64 + Count uint64 + Hits uint64 + Misses uint64 + DoesNotFit uint64 } // exported for testing @@ -330,10 +336,16 @@ func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { stylusLRUCacheSizeKbGauge.Update(int64(metrics.size_kb)) stylusLRUCacheSizeCountGauge.Update(int64(metrics.count)) + stylusLRUCacheSizeHitsCounter.Inc(int64(metrics.hits)) + stylusLRUCacheSizeMissesCounter.Inc(int64(metrics.misses)) + stylusLRUCacheSizeDoesNotFitCounter.Inc(int64(metrics.does_not_fit)) return &WasmLruCacheMetrics{ - SizeKb: uint64(metrics.size_kb), - Count: uint64(metrics.count), + SizeKb: uint64(metrics.size_kb), + Count: uint64(metrics.count), + Hits: uint64(metrics.hits), + Misses: uint64(metrics.misses), + DoesNotFit: uint64(metrics.does_not_fit), } } From 6bf148d6c02473f68fdc2892980d1a51e5f09d8a Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 12:10:37 -0300 Subject: [PATCH 031/101] Retrieves stylus cache metrics periodically --- arbos/programs/programs.go | 1 - execution/gethexec/executionengine.go | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index b324c98d0a..32453dd529 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -264,7 +264,6 @@ func (p Programs) CallProgram( maxGasToReturn := startingGas - evmCost contract.Gas = am.MinInt(contract.Gas, maxGasToReturn) } - GetWasmLruCacheMetrics() return ret, err } diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 789a53e8e4..5ee9e2202e 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -978,4 +978,14 @@ func (s *ExecutionEngine) Start(ctx_in context.Context) { } } }) + s.LaunchThread(func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case <-time.After(time.Minute): + s.GetWasmLruCacheMetrics() + } + } + }) } From e2d9e8d24ba629f11769ba4b1eb5c5ee78291a03 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 12:12:14 -0300 Subject: [PATCH 032/101] Simplifies WasmLruCacheMetrics --- arbos/programs/native.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index ef4de07ffa..1a7b616f00 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -323,11 +323,8 @@ func ResizeWasmLruCache(sizeKb uint32) { // exported for testing type WasmLruCacheMetrics struct { - SizeKb uint64 - Count uint64 - Hits uint64 - Misses uint64 - DoesNotFit uint64 + SizeKb uint64 + Count uint64 } // exported for testing @@ -341,11 +338,8 @@ func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { stylusLRUCacheSizeDoesNotFitCounter.Inc(int64(metrics.does_not_fit)) return &WasmLruCacheMetrics{ - SizeKb: uint64(metrics.size_kb), - Count: uint64(metrics.count), - Hits: uint64(metrics.hits), - Misses: uint64(metrics.misses), - DoesNotFit: uint64(metrics.does_not_fit), + SizeKb: uint64(metrics.size_kb), + Count: uint64(metrics.count), } } From e881d2bfdfbd93ef87521a11a913b43d28ca64c9 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 12:16:34 -0300 Subject: [PATCH 033/101] Fixes clear_lru_cache --- arbitrator/stylus/src/cache.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index fe04bf854d..7e419c49b8 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -239,6 +239,12 @@ impl InitCache { // only used for testing pub fn clear_lru_cache() { - cache!().lru.clear(); + let mut cache = cache!(); + cache.lru.clear(); + cache.lru_counters = LruCounters { + hits: 0, + misses: 0, + does_not_fit: 0, + }; } } From 4ac5698fbe6b4234c9124c399f52496f03fb8239 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 14:45:36 -0300 Subject: [PATCH 034/101] Fixes testcompile.go --- arbos/programs/testcompile.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arbos/programs/testcompile.go b/arbos/programs/testcompile.go index 1daf470620..57a5ce26b1 100644 --- a/arbos/programs/testcompile.go +++ b/arbos/programs/testcompile.go @@ -9,7 +9,7 @@ package programs // This file exists because cgo isn't allowed in tests /* -#cgo CFLAGS: -g -Wall -I../../target/include/ +#cgo CFLAGS: -g -I../../target/include/ #include "arbitrator.h" typedef uint16_t u16; @@ -244,6 +244,7 @@ func testCompileLoad() error { status := userStatus(C.stylus_call( goSlice(localAsm), + u32(1), goSlice(calldata), progParams.encode(), reqHandler, From 43e0bf64d479abb386a74b4b2b32cb7a3c7f2c36 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:28:08 -0300 Subject: [PATCH 035/101] Adjusts default stylus lru cache capacity --- arbitrator/stylus/src/cache.rs | 2 +- execution/gethexec/blockchain.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 7e419c49b8..ca5212a300 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -14,7 +14,7 @@ use std::hash::RandomState; use crate::target_cache::target_native; lazy_static! { - static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 10 * 1024)); + static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 1024)); } macro_rules! cache { diff --git a/execution/gethexec/blockchain.go b/execution/gethexec/blockchain.go index da6a22bdb4..21ac04d40b 100644 --- a/execution/gethexec/blockchain.go +++ b/execution/gethexec/blockchain.go @@ -75,7 +75,7 @@ var DefaultCachingConfig = CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSizeMb: 10, + StylusLRUCacheSizeMb: 256, StateScheme: rawdb.HashScheme, StateHistory: getStateHistory(DefaultSequencerConfig.MaxBlockSpeed), } From 516eceba14897523ecdd931d186fd298b9c6a3b0 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:32:18 -0300 Subject: [PATCH 036/101] Updates comment in stylus cache weight computation --- arbitrator/stylus/src/cache.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index ca5212a300..431b021ffc 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -75,7 +75,7 @@ impl WeightScale for CustomWeightScale { let mut w = val.asm_size_estimate_kb.try_into().unwrap(); if w > 0 { // clru defines that each entry consumes (weight + 1) of the cache capacity. - // Since we only want to use the weight as the size of the entry, we need to subtract 1. + // We subtract 1 since we only want to use the weight as the size of the entry. w -= 1; } return w; @@ -220,6 +220,7 @@ impl InitCache { let metrics = LruCacheMetrics{ // add 1 to each entry to account that we subtracted 1 in the weight calculation size_kb: (cache.lru.weight() + count).try_into().unwrap(), + count: count.try_into().unwrap(), hits: cache.lru_counters.hits, From 0bf91916066934f2ce93798ecd393bb3d8a5aa6a Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:33:32 -0300 Subject: [PATCH 037/101] Rename asm_size_estimate to asm_size_estimate_kb --- arbitrator/stylus/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 576d041c28..ceb72440cb 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -319,12 +319,12 @@ pub extern "C" fn stylus_cache_lru_resize(size_kb: u32) { pub unsafe extern "C" fn stylus_cache_module( module: GoSliceData, module_hash: Bytes32, - asm_size_estimate: u32, + asm_size_estimate_kb: u32, version: u16, arbos_tag: u32, debug: bool, ) { - if let Err(error) = InitCache::insert(module_hash, module.slice(), asm_size_estimate, version, arbos_tag, debug) { + if let Err(error) = InitCache::insert(module_hash, module.slice(), asm_size_estimate_kb, version, arbos_tag, debug) { panic!("tried to cache invalid asm!: {error}"); } } From 38691b168fe9d4dc4f1c4b5a23fb40bf62c9ba4e Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:36:41 -0300 Subject: [PATCH 038/101] Improves comments on why to empty counters in get_lru_metrics call --- arbitrator/stylus/src/cache.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 431b021ffc..3683421a02 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -228,7 +228,9 @@ impl InitCache { does_not_fit: cache.lru_counters.does_not_fit, }; - // empty counters + // Empty counters. + // go side, which is the only consumer of this function besides tests, + // will read those counters and increment its own prometheus counters with them. cache.lru_counters = LruCounters { hits: 0, misses: 0, From 42631eab47fc2d4067c98b23b14939131e377509 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:38:03 -0300 Subject: [PATCH 039/101] Rename asm_size_estimate to asm_size_estimate_kb --- arbitrator/stylus/src/lib.rs | 4 ++-- arbitrator/stylus/src/native.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index ceb72440cb..25d8638764 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -256,7 +256,7 @@ pub unsafe extern "C" fn stylus_target_set( #[no_mangle] pub unsafe extern "C" fn stylus_call( module: GoSliceData, - asm_size_estimate: u32, + asm_size_estimate_kb: u32, calldata: GoSliceData, config: StylusConfig, req_handler: NativeRequestHandler, @@ -277,7 +277,7 @@ pub unsafe extern "C" fn stylus_call( let instance = unsafe { NativeInstance::deserialize_cached( module, - asm_size_estimate, + asm_size_estimate_kb, config.version, evm_api, evm_data, diff --git a/arbitrator/stylus/src/native.rs b/arbitrator/stylus/src/native.rs index d150d71ccc..7c2f7ab777 100644 --- a/arbitrator/stylus/src/native.rs +++ b/arbitrator/stylus/src/native.rs @@ -112,7 +112,7 @@ impl> NativeInstance { /// `module` must represent a valid module. pub unsafe fn deserialize_cached( module: &[u8], - asm_size_estimate: u32, + asm_size_estimate_kb: u32, version: u16, evm: E, evm_data: EvmData, @@ -130,7 +130,7 @@ impl> NativeInstance { long_term_tag = 0; } let (module, store) = - InitCache::insert(module_hash, module, asm_size_estimate, version, long_term_tag, debug)?; + InitCache::insert(module_hash, module, asm_size_estimate_kb, version, long_term_tag, debug)?; Self::from_module(module, store, env) } From fa9a932df424fe23031d1bf25e5c41f0e906d8fd Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:50:48 -0300 Subject: [PATCH 040/101] Adds comment on periodic procedure that retrieves stylus lru cache metrics --- execution/gethexec/executionengine.go | 1 + 1 file changed, 1 insertion(+) diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 5ee9e2202e..affdcec704 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -978,6 +978,7 @@ func (s *ExecutionEngine) Start(ctx_in context.Context) { } } }) + // periodically update stylus lru cache metrics s.LaunchThread(func(ctx context.Context) { for { select { From d9bf5848735214c7ad87345f06bf9d24390b3391 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:53:35 -0300 Subject: [PATCH 041/101] Updates comment TestWasmLruCache --- system_tests/program_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 0c48bf7661..c867aab824 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2074,7 +2074,7 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", fallibleAsmEstimateSizeKb+keccakAsmEstimateSizeKb, lruMetrics.SizeKb) } - // math wasm program will be cached, but since (fallible + keccak + math) > lruCacheSize, fallible will be evicted + // math wasm program will be cached, but fallible will be evicted since (fallible + keccak + math) > lruCacheSize mathAsmEstimateSizeKb := uint64(560) mathProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("math")) tx = l2info.PrepareTxTo("Owner", &mathProgramAddress, l2info.TransferGas, nil, []byte{0x01}) From ce4667625e4601f78b6af05a59225c9d3f5d79e0 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 15:56:48 -0300 Subject: [PATCH 042/101] Renames StylusLRUCacheSizeMb to StylusLRUCacheSize --- arbnode/inbox_test.go | 2 +- execution/gethexec/blockchain.go | 6 +++--- execution/gethexec/node.go | 2 +- system_tests/common_test.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arbnode/inbox_test.go b/arbnode/inbox_test.go index 42661c44a6..e0c97bb871 100644 --- a/arbnode/inbox_test.go +++ b/arbnode/inbox_test.go @@ -74,7 +74,7 @@ func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (* } stylusTargetConfig := &gethexec.DefaultStylusTargetConfig Require(t, stylusTargetConfig.Validate()) // pre-processes config (i.a. parses wasmTargets) - if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheSizeMb, &gethexec.DefaultStylusTargetConfig); err != nil { + if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheSize, &gethexec.DefaultStylusTargetConfig); err != nil { Fail(t, err) } execSeq := &execClientWrapper{execEngine, t} diff --git a/execution/gethexec/blockchain.go b/execution/gethexec/blockchain.go index 21ac04d40b..e0e907683d 100644 --- a/execution/gethexec/blockchain.go +++ b/execution/gethexec/blockchain.go @@ -37,7 +37,7 @@ type CachingConfig struct { SnapshotRestoreGasLimit uint64 `koanf:"snapshot-restore-gas-limit"` MaxNumberOfBlocksToSkipStateSaving uint32 `koanf:"max-number-of-blocks-to-skip-state-saving"` MaxAmountOfGasToSkipStateSaving uint64 `koanf:"max-amount-of-gas-to-skip-state-saving"` - StylusLRUCacheSizeMb uint32 `koanf:"stylus-lru-cache-size"` + StylusLRUCacheSize uint32 `koanf:"stylus-lru-cache-size"` StateScheme string `koanf:"state-scheme"` StateHistory uint64 `koanf:"state-history"` } @@ -54,7 +54,7 @@ func CachingConfigAddOptions(prefix string, f *flag.FlagSet) { f.Uint64(prefix+".snapshot-restore-gas-limit", DefaultCachingConfig.SnapshotRestoreGasLimit, "maximum gas rolled back to recover snapshot") f.Uint32(prefix+".max-number-of-blocks-to-skip-state-saving", DefaultCachingConfig.MaxNumberOfBlocksToSkipStateSaving, "maximum number of blocks to skip state saving to persistent storage (archive node only) -- warning: this option seems to cause issues") f.Uint64(prefix+".max-amount-of-gas-to-skip-state-saving", DefaultCachingConfig.MaxAmountOfGasToSkipStateSaving, "maximum amount of gas in blocks to skip saving state to Persistent storage (archive node only) -- warning: this option seems to cause issues") - f.Uint32(prefix+".stylus-lru-cache-size", DefaultCachingConfig.StylusLRUCacheSizeMb, "capacity, in megabytes, of the LRU cache that keeps initialized stylus programs") + f.Uint32(prefix+".stylus-lru-cache-size", DefaultCachingConfig.StylusLRUCacheSize, "capacity, in megabytes, of the LRU cache that keeps initialized stylus programs") f.String(prefix+".state-scheme", DefaultCachingConfig.StateScheme, "scheme to use for state trie storage (hash, path)") f.Uint64(prefix+".state-history", DefaultCachingConfig.StateHistory, "number of recent blocks to retain state history for (path state-scheme only)") } @@ -75,7 +75,7 @@ var DefaultCachingConfig = CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSizeMb: 256, + StylusLRUCacheSize: 256, StateScheme: rawdb.HashScheme, StateHistory: getStateHistory(DefaultSequencerConfig.MaxBlockSpeed), } diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index b602dbd323..93bb254ed8 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -308,7 +308,7 @@ func (n *ExecutionNode) MarkFeedStart(to arbutil.MessageIndex) { func (n *ExecutionNode) Initialize(ctx context.Context) error { config := n.ConfigFetcher() - err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheSizeMb, &config.StylusTarget) + err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheSize, &config.StylusTarget) if err != nil { return fmt.Errorf("error initializing execution engine: %w", err) } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index c1e9ff384b..363f1050fb 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -166,7 +166,7 @@ var TestCachingConfig = gethexec.CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSizeMb: 0, + StylusLRUCacheSize: 0, StateScheme: env.GetTestStateScheme(), } From 7cb4fa1ae84c66d9aa8f260478af75a8434b0d28 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 16:07:00 -0300 Subject: [PATCH 043/101] Updates lru cache metrics data sizes --- arbitrator/stylus/src/cache.rs | 16 ++++++++-------- arbos/programs/native.go | 8 ++++---- system_tests/program_test.go | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 3683421a02..11ec55c6a7 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -24,9 +24,9 @@ macro_rules! cache { } pub struct LruCounters { - pub hits: u64, - pub misses: u64, - pub does_not_fit: u64, + pub hits: u32, + pub misses: u32, + pub does_not_fit: u32, } pub struct InitCache { @@ -84,11 +84,11 @@ impl WeightScale for CustomWeightScale { #[repr(C)] pub struct LruCacheMetrics { - pub size_kb: u64, - pub count: u64, - pub hits: u64, - pub misses: u64, - pub does_not_fit: u64, + pub size_kb: u32, + pub count: u32, + pub hits: u32, + pub misses: u32, + pub does_not_fit: u32, } impl InitCache { diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 1a7b616f00..0f3e28287d 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -323,8 +323,8 @@ func ResizeWasmLruCache(sizeKb uint32) { // exported for testing type WasmLruCacheMetrics struct { - SizeKb uint64 - Count uint64 + SizeKb uint32 + Count uint32 } // exported for testing @@ -338,8 +338,8 @@ func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { stylusLRUCacheSizeDoesNotFitCounter.Inc(int64(metrics.does_not_fit)) return &WasmLruCacheMetrics{ - SizeKb: uint64(metrics.size_kb), - Count: uint64(metrics.count), + SizeKb: uint32(metrics.size_kb), + Count: uint32(metrics.count), } } diff --git a/system_tests/program_test.go b/system_tests/program_test.go index c867aab824..108cec6647 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2028,7 +2028,7 @@ func TestWasmLruCache(t *testing.T) { builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) // fallible wasm program will not be cached since its size is greater than lruCacheSize - fallibleAsmEstimateSizeKb := uint64(551) + fallibleAsmEstimateSizeKb := uint32(551) fallibleProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("fallible")) tx := l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2060,7 +2060,7 @@ func TestWasmLruCache(t *testing.T) { } // keccak wasm program will be cached - keccakAsmEstimateSizeKb := uint64(583) + keccakAsmEstimateSizeKb := uint32(583) keccakProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("keccak")) tx = l2info.PrepareTxTo("Owner", &keccakProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2075,7 +2075,7 @@ func TestWasmLruCache(t *testing.T) { } // math wasm program will be cached, but fallible will be evicted since (fallible + keccak + math) > lruCacheSize - mathAsmEstimateSizeKb := uint64(560) + mathAsmEstimateSizeKb := uint32(560) mathProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("math")) tx = l2info.PrepareTxTo("Owner", &mathProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) From 21217f1c5ce9261bdd525b5882424851b38260e0 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 20:38:53 -0300 Subject: [PATCH 044/101] Simplifies weight computation by using saturating_sub --- arbitrator/stylus/src/cache.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 11ec55c6a7..db199414df 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -72,13 +72,9 @@ impl CacheItem { struct CustomWeightScale; impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { - let mut w = val.asm_size_estimate_kb.try_into().unwrap(); - if w > 0 { - // clru defines that each entry consumes (weight + 1) of the cache capacity. - // We subtract 1 since we only want to use the weight as the size of the entry. - w -= 1; - } - return w; + // clru defines that each entry consumes (weight + 1) of the cache capacity. + // We subtract 1 since we only want to use the weight as the size of the entry. + val.asm_size_estimate_kb.saturating_sub(1).try_into().unwrap() } } From 7e6b7596ff5da5d707a11fcb238f5e4632e3d526 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 20:43:47 -0300 Subject: [PATCH 045/101] Uses if let instead of match --- arbitrator/stylus/src/cache.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index db199414df..6061a72cd2 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -166,12 +166,9 @@ impl InitCache { let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { - match cache.lru.put_with_weight(key, item) { - Err(_) => { - cache.lru_counters.does_not_fit += 1; - println!("Failed to insert into LRU cache, item too large"); - } - Ok(_) => (), + if let Err(_) = cache.lru.put_with_weight(key, item) { + cache.lru_counters.does_not_fit += 1; + println!("Failed to insert into LRU cache, item too large"); }; } else { cache.long_term.insert(key, item); @@ -187,10 +184,9 @@ impl InitCache { let key = CacheKey::new(module_hash, version, debug); let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { - match cache.lru.put_with_weight(key, item) { - Err(_) => println!("Failed to insert into LRU cache, item too large"), - Ok(_) => (), - }; + if let Err(_) = cache.lru.put_with_weight(key, item) { + println!("Failed to insert into LRU cache, item too large"); + } } } @@ -202,10 +198,9 @@ impl InitCache { let cache = &mut *cache; for (key, item) in cache.long_term.drain() { // not all will fit, just a heuristic - match cache.lru.put_with_weight(key, item) { - Err(_) => println!("Failed to insert into LRU cache, item too large"), - Ok(_) => (), - }; + if let Err(_) = cache.lru.put_with_weight(key, item) { + println!("Failed to insert into LRU cache, item too large"); + } } } From fe2377c75357b7aa75fda26afda9e1399d60f27e Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 20:44:19 -0300 Subject: [PATCH 046/101] Removes unused return --- arbitrator/stylus/src/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 6061a72cd2..033c65c84f 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -228,7 +228,7 @@ impl InitCache { does_not_fit: 0, }; - return metrics + metrics } // only used for testing From e439bc88c2e005c3abb11889d1f9851adf083636 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 20:54:49 -0300 Subject: [PATCH 047/101] Creates a DOES_NOT_FIT_MSG static --- arbitrator/stylus/src/cache.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 033c65c84f..831cc6f2d1 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -93,6 +93,8 @@ impl InitCache { // that will never modify long_term state const ARBOS_TAG: u32 = 1; + const DOES_NOT_FIT_MSG: &'static str = "Failed to insert into LRU cache, item too large"; + fn new(size: usize) -> Self { Self { long_term: HashMap::new(), @@ -168,7 +170,7 @@ impl InitCache { if long_term_tag != Self::ARBOS_TAG { if let Err(_) = cache.lru.put_with_weight(key, item) { cache.lru_counters.does_not_fit += 1; - println!("Failed to insert into LRU cache, item too large"); + println!("{}", Self::DOES_NOT_FIT_MSG); }; } else { cache.long_term.insert(key, item); @@ -185,7 +187,7 @@ impl InitCache { let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { if let Err(_) = cache.lru.put_with_weight(key, item) { - println!("Failed to insert into LRU cache, item too large"); + println!("{}", Self::DOES_NOT_FIT_MSG); } } } @@ -199,7 +201,7 @@ impl InitCache { for (key, item) in cache.long_term.drain() { // not all will fit, just a heuristic if let Err(_) = cache.lru.put_with_weight(key, item) { - println!("Failed to insert into LRU cache, item too large"); + println!("{}", Self::DOES_NOT_FIT_MSG); } } } From 281f608857b09bd72ba54bc8b216ae651d372aa6 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 21:18:29 -0300 Subject: [PATCH 048/101] Uses is_err instead of let Err(_) --- arbitrator/stylus/src/cache.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 831cc6f2d1..bdecdd724f 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -168,7 +168,7 @@ impl InitCache { let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { - if let Err(_) = cache.lru.put_with_weight(key, item) { + if cache.lru.put_with_weight(key, item).is_err() { cache.lru_counters.does_not_fit += 1; println!("{}", Self::DOES_NOT_FIT_MSG); }; @@ -186,7 +186,7 @@ impl InitCache { let key = CacheKey::new(module_hash, version, debug); let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { - if let Err(_) = cache.lru.put_with_weight(key, item) { + if cache.lru.put_with_weight(key, item).is_err() { println!("{}", Self::DOES_NOT_FIT_MSG); } } @@ -200,7 +200,7 @@ impl InitCache { let cache = &mut *cache; for (key, item) in cache.long_term.drain() { // not all will fit, just a heuristic - if let Err(_) = cache.lru.put_with_weight(key, item) { + if cache.lru.put_with_weight(key, item).is_err() { println!("{}", Self::DOES_NOT_FIT_MSG); } } From a2f1b6082eb1007ae8c6f7f8fa6b2a686072943a Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Tue, 20 Aug 2024 21:31:12 -0300 Subject: [PATCH 049/101] Format rs files --- arbitrator/stylus/src/cache.rs | 22 ++++++++++++++++------ arbitrator/stylus/src/lib.rs | 9 ++++++++- arbitrator/stylus/src/native.rs | 10 ++++++++-- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index bdecdd724f..ea88fe0fe9 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -2,14 +2,14 @@ // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE use arbutil::Bytes32; +use clru::{CLruCache, CLruCacheConfig, WeightScale}; use eyre::Result; use lazy_static::lazy_static; -use clru::{CLruCache, CLruCacheConfig, WeightScale}; use parking_lot::Mutex; use prover::programs::config::CompileConfig; +use std::hash::RandomState; use std::{collections::HashMap, num::NonZeroUsize}; use wasmer::{Engine, Module, Store}; -use std::hash::RandomState; use crate::target_cache::target_native; @@ -61,7 +61,11 @@ struct CacheItem { impl CacheItem { fn new(module: Module, engine: Engine, asm_size_estimate_kb: u32) -> Self { - Self { module, engine, asm_size_estimate_kb } + Self { + module, + engine, + asm_size_estimate_kb, + } } fn data(&self) -> (Module, Store) { @@ -74,7 +78,10 @@ impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { // clru defines that each entry consumes (weight + 1) of the cache capacity. // We subtract 1 since we only want to use the weight as the size of the entry. - val.asm_size_estimate_kb.saturating_sub(1).try_into().unwrap() + val.asm_size_estimate_kb + .saturating_sub(1) + .try_into() + .unwrap() } } @@ -98,7 +105,10 @@ impl InitCache { fn new(size: usize) -> Self { Self { long_term: HashMap::new(), - lru: CLruCache::with_config(CLruCacheConfig::new(NonZeroUsize::new(size).unwrap()).with_scale(CustomWeightScale)), + lru: CLruCache::with_config( + CLruCacheConfig::new(NonZeroUsize::new(size).unwrap()) + .with_scale(CustomWeightScale), + ), lru_counters: LruCounters { hits: 0, misses: 0, @@ -210,7 +220,7 @@ impl InitCache { let mut cache = cache!(); let count = cache.lru.len(); - let metrics = LruCacheMetrics{ + let metrics = LruCacheMetrics { // add 1 to each entry to account that we subtracted 1 in the weight calculation size_kb: (cache.lru.weight() + count).try_into().unwrap(), diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 25d8638764..6f7e207308 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -324,7 +324,14 @@ pub unsafe extern "C" fn stylus_cache_module( arbos_tag: u32, debug: bool, ) { - if let Err(error) = InitCache::insert(module_hash, module.slice(), asm_size_estimate_kb, version, arbos_tag, debug) { + if let Err(error) = InitCache::insert( + module_hash, + module.slice(), + asm_size_estimate_kb, + version, + arbos_tag, + debug, + ) { panic!("tried to cache invalid asm!: {error}"); } } diff --git a/arbitrator/stylus/src/native.rs b/arbitrator/stylus/src/native.rs index 7c2f7ab777..393cd951bd 100644 --- a/arbitrator/stylus/src/native.rs +++ b/arbitrator/stylus/src/native.rs @@ -129,8 +129,14 @@ impl> NativeInstance { if !env.evm_data.cached { long_term_tag = 0; } - let (module, store) = - InitCache::insert(module_hash, module, asm_size_estimate_kb, version, long_term_tag, debug)?; + let (module, store) = InitCache::insert( + module_hash, + module, + asm_size_estimate_kb, + version, + long_term_tag, + debug, + )?; Self::from_module(module, store, env) } From 761f84af54aa7135bc2801c8d8c0498e7152e465 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 21 Aug 2024 17:47:14 -0300 Subject: [PATCH 050/101] Relies on module.serialize to estimate asm size --- arbitrator/stylus/src/cache.rs | 29 ++++++++++++-------------- arbitrator/stylus/src/lib.rs | 8 ++----- arbitrator/stylus/src/native.rs | 2 -- arbos/programs/native.go | 28 ++++++++++++------------- arbos/programs/programs.go | 11 +++------- arbos/programs/testcompile.go | 1 - arbos/programs/wasm.go | 3 +-- execution/gethexec/executionengine.go | 6 +++--- system_tests/program_test.go | 30 +++++++++++++-------------- 9 files changed, 50 insertions(+), 68 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index ea88fe0fe9..5c29f61287 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -14,7 +14,7 @@ use wasmer::{Engine, Module, Store}; use crate::target_cache::target_native; lazy_static! { - static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 1024)); + static ref INIT_CACHE: Mutex = Mutex::new(InitCache::new(256 * 1024 * 1024)); } macro_rules! cache { @@ -56,15 +56,15 @@ impl CacheKey { struct CacheItem { module: Module, engine: Engine, - asm_size_estimate_kb: u32, + asm_size_estimate_bytes: usize, } impl CacheItem { - fn new(module: Module, engine: Engine, asm_size_estimate_kb: u32) -> Self { + fn new(module: Module, engine: Engine, asm_size_estimate_bytes: usize) -> Self { Self { module, engine, - asm_size_estimate_kb, + asm_size_estimate_bytes, } } @@ -78,16 +78,13 @@ impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { // clru defines that each entry consumes (weight + 1) of the cache capacity. // We subtract 1 since we only want to use the weight as the size of the entry. - val.asm_size_estimate_kb - .saturating_sub(1) - .try_into() - .unwrap() + val.asm_size_estimate_bytes.saturating_sub(1) } } #[repr(C)] pub struct LruCacheMetrics { - pub size_kb: u32, + pub size_bytes: u64, pub count: u32, pub hits: u32, pub misses: u32, @@ -102,11 +99,11 @@ impl InitCache { const DOES_NOT_FIT_MSG: &'static str = "Failed to insert into LRU cache, item too large"; - fn new(size: usize) -> Self { + fn new(size_bytes: usize) -> Self { Self { long_term: HashMap::new(), lru: CLruCache::with_config( - CLruCacheConfig::new(NonZeroUsize::new(size).unwrap()) + CLruCacheConfig::new(NonZeroUsize::new(size_bytes).unwrap()) .with_scale(CustomWeightScale), ), lru_counters: LruCounters { @@ -117,10 +114,10 @@ impl InitCache { } } - pub fn set_lru_size(size_kb: u32) { + pub fn set_lru_size(size_bytes: u64) { cache!() .lru - .resize(NonZeroUsize::new(size_kb.try_into().unwrap()).unwrap()) + .resize(NonZeroUsize::new(size_bytes.try_into().unwrap()).unwrap()) } /// Retrieves a cached value, updating items as necessary. @@ -148,7 +145,6 @@ impl InitCache { pub fn insert( module_hash: Bytes32, module: &[u8], - asm_size_estimate_kb: u32, version: u16, long_term_tag: u32, debug: bool, @@ -173,8 +169,9 @@ impl InitCache { let engine = CompileConfig::version(version, debug).engine(target_native()); let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; + let asm_size_estimate_bytes = module.serialize()?.len(); - let item = CacheItem::new(module, engine, asm_size_estimate_kb); + let item = CacheItem::new(module, engine, asm_size_estimate_bytes); let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { @@ -222,7 +219,7 @@ impl InitCache { let count = cache.lru.len(); let metrics = LruCacheMetrics { // add 1 to each entry to account that we subtracted 1 in the weight calculation - size_kb: (cache.lru.weight() + count).try_into().unwrap(), + size_bytes: (cache.lru.weight() + count).try_into().unwrap(), count: count.try_into().unwrap(), diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 6f7e207308..18ff3900d3 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -256,7 +256,6 @@ pub unsafe extern "C" fn stylus_target_set( #[no_mangle] pub unsafe extern "C" fn stylus_call( module: GoSliceData, - asm_size_estimate_kb: u32, calldata: GoSliceData, config: StylusConfig, req_handler: NativeRequestHandler, @@ -277,7 +276,6 @@ pub unsafe extern "C" fn stylus_call( let instance = unsafe { NativeInstance::deserialize_cached( module, - asm_size_estimate_kb, config.version, evm_api, evm_data, @@ -304,8 +302,8 @@ pub unsafe extern "C" fn stylus_call( /// resize lru #[no_mangle] -pub extern "C" fn stylus_cache_lru_resize(size_kb: u32) { - InitCache::set_lru_size(size_kb); +pub extern "C" fn stylus_cache_lru_resize(size_bytes: u64) { + InitCache::set_lru_size(size_bytes); } /// Caches an activated user program. @@ -319,7 +317,6 @@ pub extern "C" fn stylus_cache_lru_resize(size_kb: u32) { pub unsafe extern "C" fn stylus_cache_module( module: GoSliceData, module_hash: Bytes32, - asm_size_estimate_kb: u32, version: u16, arbos_tag: u32, debug: bool, @@ -327,7 +324,6 @@ pub unsafe extern "C" fn stylus_cache_module( if let Err(error) = InitCache::insert( module_hash, module.slice(), - asm_size_estimate_kb, version, arbos_tag, debug, diff --git a/arbitrator/stylus/src/native.rs b/arbitrator/stylus/src/native.rs index 393cd951bd..b661435e52 100644 --- a/arbitrator/stylus/src/native.rs +++ b/arbitrator/stylus/src/native.rs @@ -112,7 +112,6 @@ impl> NativeInstance { /// `module` must represent a valid module. pub unsafe fn deserialize_cached( module: &[u8], - asm_size_estimate_kb: u32, version: u16, evm: E, evm_data: EvmData, @@ -132,7 +131,6 @@ impl> NativeInstance { let (module, store) = InitCache::insert( module_hash, module, - asm_size_estimate_kb, version, long_term_tag, debug, diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 0f3e28287d..b817c55331 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -47,7 +47,7 @@ type rustBytes = C.RustBytes type rustSlice = C.RustSlice var ( - stylusLRUCacheSizeKbGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size_kilobytes", nil) + stylusLRUCacheSizeBytesGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/size_bytes", nil) stylusLRUCacheSizeCountGauge = metrics.NewRegisteredGauge("arb/arbos/stylus/cache/lru/count", nil) stylusLRUCacheSizeHitsCounter = metrics.NewRegisteredCounter("arb/arbos/stylus/cache/lru/hits", nil) stylusLRUCacheSizeMissesCounter = metrics.NewRegisteredCounter("arb/arbos/stylus/cache/lru/misses", nil) @@ -220,7 +220,6 @@ func callProgram( address common.Address, moduleHash common.Hash, localAsm []byte, - asmSizeEstimateKb uint32, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, @@ -248,7 +247,6 @@ func callProgram( output := &rustBytes{} status := userStatus(C.stylus_call( goSlice(localAsm), - u32(asmSizeEstimateKb), goSlice(calldata), stylusParams.encode(), evmApi.cNative, @@ -291,55 +289,55 @@ func cacheProgram(db vm.StateDB, module common.Hash, program Program, addressFor panic("unable to recreate wasm") } tag := db.Database().WasmCacheTag() - state.CacheWasmRust(asm, module, program.asmSize(), program.version, tag, debug) + state.CacheWasmRust(asm, module, program.version, tag, debug) db.RecordCacheWasm(state.CacheWasm{ModuleHash: module, Version: program.version, Tag: tag, Debug: debug}) } } // Evicts a program in Rust. We write a record so that we can undo on revert, unless we don't need to (e.g. expired) // For gas estimation and eth_call, we ignore permanent updates and rely on Rust's LRU. -func evictProgram(db vm.StateDB, module common.Hash, asmSizeEstimateKb uint32, version uint16, debug bool, runMode core.MessageRunMode, forever bool) { +func evictProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, runMode core.MessageRunMode, forever bool) { if runMode == core.MessageCommitMode { tag := db.Database().WasmCacheTag() state.EvictWasmRust(module, version, tag, debug) if !forever { - db.RecordEvictWasm(state.EvictWasm{ModuleHash: module, Version: version, Tag: tag, Debug: debug, AsmSizeEstimateKb: asmSizeEstimateKb}) + db.RecordEvictWasm(state.EvictWasm{ModuleHash: module, Version: version, Tag: tag, Debug: debug}) } } } func init() { - state.CacheWasmRust = func(asm []byte, moduleHash common.Hash, asmSizeEstimateKb uint32, version uint16, tag uint32, debug bool) { - C.stylus_cache_module(goSlice(asm), hashToBytes32(moduleHash), u32(asmSizeEstimateKb), u16(version), u32(tag), cbool(debug)) + state.CacheWasmRust = func(asm []byte, moduleHash common.Hash, version uint16, tag uint32, debug bool) { + C.stylus_cache_module(goSlice(asm), hashToBytes32(moduleHash), u16(version), u32(tag), cbool(debug)) } state.EvictWasmRust = func(moduleHash common.Hash, version uint16, tag uint32, debug bool) { C.stylus_evict_module(hashToBytes32(moduleHash), u16(version), u32(tag), cbool(debug)) } } -func ResizeWasmLruCache(sizeKb uint32) { - C.stylus_cache_lru_resize(u32(sizeKb)) +func ResizeWasmLruCache(sizeBytes uint64) { + C.stylus_cache_lru_resize(u64(sizeBytes)) } // exported for testing type WasmLruCacheMetrics struct { - SizeKb uint32 - Count uint32 + SizeBytes uint64 + Count uint32 } // exported for testing func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { metrics := C.stylus_get_lru_cache_metrics() - stylusLRUCacheSizeKbGauge.Update(int64(metrics.size_kb)) + stylusLRUCacheSizeBytesGauge.Update(int64(metrics.size_bytes)) stylusLRUCacheSizeCountGauge.Update(int64(metrics.count)) stylusLRUCacheSizeHitsCounter.Inc(int64(metrics.hits)) stylusLRUCacheSizeMissesCounter.Inc(int64(metrics.misses)) stylusLRUCacheSizeDoesNotFitCounter.Inc(int64(metrics.does_not_fit)) return &WasmLruCacheMetrics{ - SizeKb: uint32(metrics.size_kb), - Count: uint32(metrics.count), + SizeBytes: uint64(metrics.size_bytes), + Count: uint32(metrics.count), } } diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index 32453dd529..b3f51ecba0 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -128,12 +128,7 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, runMode c return 0, codeHash, common.Hash{}, nil, true, err } - program, err := p.getActiveProgram(codeHash, time, params) - if err != nil { - return 0, codeHash, common.Hash{}, nil, true, err - } - - evictProgram(statedb, oldModuleHash, program.asmSize(), currentVersion, debugMode, runMode, expired) + evictProgram(statedb, oldModuleHash, currentVersion, debugMode, runMode, expired) } if err := p.moduleHashes.Set(codeHash, info.moduleHash); err != nil { return 0, codeHash, common.Hash{}, nil, true, err @@ -253,7 +248,7 @@ func (p Programs) CallProgram( if runmode == core.MessageCommitMode { arbos_tag = statedb.Database().WasmCacheTag() } - ret, err := callProgram(address, moduleHash, localAsm, program.asmEstimateKb.ToUint32(), scope, interpreter, tracingInfo, calldata, evmData, goParams, model, arbos_tag) + ret, err := callProgram(address, moduleHash, localAsm, scope, interpreter, tracingInfo, calldata, evmData, goParams, model, arbos_tag) if len(ret) > 0 && arbosVersion >= gethParams.ArbosVersion_StylusFixes { // Ensure that return data costs as least as much as it would in the EVM. evmCost := evmMemoryCost(uint64(len(ret))) @@ -439,7 +434,7 @@ func (p Programs) SetProgramCached( } cacheProgram(db, moduleHash, program, address, code, codeHash, params, debug, time, runMode) } else { - evictProgram(db, moduleHash, program.asmSize(), program.version, debug, runMode, expired) + evictProgram(db, moduleHash, program.version, debug, runMode, expired) } program.cached = cache return p.setProgram(codeHash, program) diff --git a/arbos/programs/testcompile.go b/arbos/programs/testcompile.go index 57a5ce26b1..615b0f3f72 100644 --- a/arbos/programs/testcompile.go +++ b/arbos/programs/testcompile.go @@ -244,7 +244,6 @@ func testCompileLoad() error { status := userStatus(C.stylus_call( goSlice(localAsm), - u32(1), goSlice(calldata), progParams.encode(), reqHandler, diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 849ed88f42..504e3bf9fa 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -97,7 +97,7 @@ func activateProgram( // stub any non-consensus, Rust-side caching updates func cacheProgram(db vm.StateDB, module common.Hash, program Program, addressForLogging common.Address, code []byte, codeHash common.Hash, params *StylusParams, debug bool, time uint64, runMode core.MessageRunMode) { } -func evictProgram(db vm.StateDB, module common.Hash, asmSizeEstimate uint32, version uint16, debug bool, mode core.MessageRunMode, forever bool) { +func evictProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, mode core.MessageRunMode, forever bool) { } //go:wasmimport programs new_program @@ -136,7 +136,6 @@ func callProgram( address common.Address, moduleHash common.Hash, _localAsm []byte, - _asmSizeEstimateKb uint32, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index affdcec704..686e0f1a36 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -184,7 +184,7 @@ func populateStylusTargetCache(targetConfig *StylusTargetConfig) error { func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *StylusTargetConfig) error { if rustCacheSizeMb != 0 { - s.ResizeWasmLruCache(arbmath.SaturatingUMul(rustCacheSizeMb, 1024)) + s.ResizeWasmLruCache(arbmath.SaturatingUMul(uint64(rustCacheSizeMb), 1024*1024)) } if err := populateStylusTargetCache(targetConfig); err != nil { return fmt.Errorf("error populating stylus target cache: %w", err) @@ -193,8 +193,8 @@ func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *Stylu } // exported for testing -func (s *ExecutionEngine) ResizeWasmLruCache(sizeKb uint32) { - programs.ResizeWasmLruCache(sizeKb) +func (s *ExecutionEngine) ResizeWasmLruCache(sizeBytes uint64) { + programs.ResizeWasmLruCache(sizeBytes) } // exported for testing diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 108cec6647..0dd65a6bf6 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2020,15 +2020,15 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 0 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 0, lruMetrics.Count) } - if lruMetrics.SizeKb != 0 { - t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", 0, lruMetrics.SizeKb) + if lruMetrics.SizeBytes != 0 { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - lruCacheSize := uint32(500) + lruCacheSize := uint64(100_000) builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) // fallible wasm program will not be cached since its size is greater than lruCacheSize - fallibleAsmEstimateSizeKb := uint32(551) + fallibleAsmEstimateSizeBytes := uint64(118_624) fallibleProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("fallible")) tx := l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2038,12 +2038,12 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 0 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 0, lruMetrics.Count) } - if lruMetrics.SizeKb != 0 { - t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", 0, lruMetrics.SizeKb) + if lruMetrics.SizeBytes != 0 { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } // resize lru cache - lruCacheSize = uint32(1500) + lruCacheSize = uint64(350_000) builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) // fallible wasm program will be cached @@ -2055,12 +2055,12 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 1 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 1, lruMetrics.Count) } - if lruMetrics.SizeKb != fallibleAsmEstimateSizeKb { - t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", fallibleAsmEstimateSizeKb, lruMetrics.SizeKb) + if lruMetrics.SizeBytes != fallibleAsmEstimateSizeBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmEstimateSizeBytes, lruMetrics.SizeBytes) } // keccak wasm program will be cached - keccakAsmEstimateSizeKb := uint32(583) + keccakAsmEstimateSizeBytes := uint64(175_496) keccakProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("keccak")) tx = l2info.PrepareTxTo("Owner", &keccakProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2070,12 +2070,12 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if lruMetrics.SizeKb != fallibleAsmEstimateSizeKb+keccakAsmEstimateSizeKb { - t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", fallibleAsmEstimateSizeKb+keccakAsmEstimateSizeKb, lruMetrics.SizeKb) + if lruMetrics.SizeBytes != fallibleAsmEstimateSizeBytes+keccakAsmEstimateSizeBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmEstimateSizeBytes+keccakAsmEstimateSizeBytes, lruMetrics.SizeBytes) } // math wasm program will be cached, but fallible will be evicted since (fallible + keccak + math) > lruCacheSize - mathAsmEstimateSizeKb := uint32(560) + mathAsmEstimateSizeBytes := uint64(131_672) mathProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("math")) tx = l2info.PrepareTxTo("Owner", &mathProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2085,7 +2085,7 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if lruMetrics.SizeKb != keccakAsmEstimateSizeKb+mathAsmEstimateSizeKb { - t.Fatalf("lruMetrics.SizeKb, expected: %v, actual: %v", keccakAsmEstimateSizeKb+mathAsmEstimateSizeKb, lruMetrics.SizeKb) + if lruMetrics.SizeBytes != keccakAsmEstimateSizeBytes+mathAsmEstimateSizeBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", keccakAsmEstimateSizeBytes+mathAsmEstimateSizeBytes, lruMetrics.SizeBytes) } } From 21664e9b94cbffc1779e37050e48a180770f4a4f Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 21 Aug 2024 19:22:32 -0300 Subject: [PATCH 051/101] Renames resize to set capacity in stylus cache --- arbitrator/stylus/src/cache.rs | 4 ++-- arbitrator/stylus/src/lib.rs | 6 +++--- arbnode/inbox_test.go | 2 +- arbos/programs/native.go | 4 ++-- execution/gethexec/blockchain.go | 6 +++--- execution/gethexec/executionengine.go | 10 +++++----- execution/gethexec/node.go | 2 +- system_tests/common_test.go | 2 +- system_tests/program_test.go | 10 +++++----- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 5c29f61287..aeefd9c8bd 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -114,10 +114,10 @@ impl InitCache { } } - pub fn set_lru_size(size_bytes: u64) { + pub fn set_lru_capacity(capacity_bytes: u64) { cache!() .lru - .resize(NonZeroUsize::new(size_bytes.try_into().unwrap()).unwrap()) + .resize(NonZeroUsize::new(capacity_bytes.try_into().unwrap()).unwrap()) } /// Retrieves a cached value, updating items as necessary. diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 18ff3900d3..791557dd0c 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -300,10 +300,10 @@ pub unsafe extern "C" fn stylus_call( status } -/// resize lru +/// set lru cache capacity #[no_mangle] -pub extern "C" fn stylus_cache_lru_resize(size_bytes: u64) { - InitCache::set_lru_size(size_bytes); +pub extern "C" fn stylus_set_cache_lru_capacity(capacity_bytes: u64) { + InitCache::set_lru_capacity(capacity_bytes); } /// Caches an activated user program. diff --git a/arbnode/inbox_test.go b/arbnode/inbox_test.go index e0c97bb871..e588ef399b 100644 --- a/arbnode/inbox_test.go +++ b/arbnode/inbox_test.go @@ -74,7 +74,7 @@ func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (* } stylusTargetConfig := &gethexec.DefaultStylusTargetConfig Require(t, stylusTargetConfig.Validate()) // pre-processes config (i.a. parses wasmTargets) - if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheSize, &gethexec.DefaultStylusTargetConfig); err != nil { + if err := execEngine.Initialize(gethexec.DefaultCachingConfig.StylusLRUCacheCapacity, &gethexec.DefaultStylusTargetConfig); err != nil { Fail(t, err) } execSeq := &execClientWrapper{execEngine, t} diff --git a/arbos/programs/native.go b/arbos/programs/native.go index b817c55331..97b1f435ed 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -315,8 +315,8 @@ func init() { } } -func ResizeWasmLruCache(sizeBytes uint64) { - C.stylus_cache_lru_resize(u64(sizeBytes)) +func SetWasmLruCacheCapacity(capacityBytes uint64) { + C.stylus_set_cache_lru_capacity(u64(capacityBytes)) } // exported for testing diff --git a/execution/gethexec/blockchain.go b/execution/gethexec/blockchain.go index e0e907683d..1bf618bba3 100644 --- a/execution/gethexec/blockchain.go +++ b/execution/gethexec/blockchain.go @@ -37,7 +37,7 @@ type CachingConfig struct { SnapshotRestoreGasLimit uint64 `koanf:"snapshot-restore-gas-limit"` MaxNumberOfBlocksToSkipStateSaving uint32 `koanf:"max-number-of-blocks-to-skip-state-saving"` MaxAmountOfGasToSkipStateSaving uint64 `koanf:"max-amount-of-gas-to-skip-state-saving"` - StylusLRUCacheSize uint32 `koanf:"stylus-lru-cache-size"` + StylusLRUCacheCapacity uint32 `koanf:"stylus-lru-cache-capacity"` StateScheme string `koanf:"state-scheme"` StateHistory uint64 `koanf:"state-history"` } @@ -54,7 +54,7 @@ func CachingConfigAddOptions(prefix string, f *flag.FlagSet) { f.Uint64(prefix+".snapshot-restore-gas-limit", DefaultCachingConfig.SnapshotRestoreGasLimit, "maximum gas rolled back to recover snapshot") f.Uint32(prefix+".max-number-of-blocks-to-skip-state-saving", DefaultCachingConfig.MaxNumberOfBlocksToSkipStateSaving, "maximum number of blocks to skip state saving to persistent storage (archive node only) -- warning: this option seems to cause issues") f.Uint64(prefix+".max-amount-of-gas-to-skip-state-saving", DefaultCachingConfig.MaxAmountOfGasToSkipStateSaving, "maximum amount of gas in blocks to skip saving state to Persistent storage (archive node only) -- warning: this option seems to cause issues") - f.Uint32(prefix+".stylus-lru-cache-size", DefaultCachingConfig.StylusLRUCacheSize, "capacity, in megabytes, of the LRU cache that keeps initialized stylus programs") + f.Uint32(prefix+".stylus-lru-cache-capacity", DefaultCachingConfig.StylusLRUCacheCapacity, "capacity, in megabytes, of the LRU cache that keeps initialized stylus programs") f.String(prefix+".state-scheme", DefaultCachingConfig.StateScheme, "scheme to use for state trie storage (hash, path)") f.Uint64(prefix+".state-history", DefaultCachingConfig.StateHistory, "number of recent blocks to retain state history for (path state-scheme only)") } @@ -75,7 +75,7 @@ var DefaultCachingConfig = CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSize: 256, + StylusLRUCacheCapacity: 256, StateScheme: rawdb.HashScheme, StateHistory: getStateHistory(DefaultSequencerConfig.MaxBlockSpeed), } diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 686e0f1a36..5b5c9a8938 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -182,9 +182,9 @@ func populateStylusTargetCache(targetConfig *StylusTargetConfig) error { return nil } -func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *StylusTargetConfig) error { - if rustCacheSizeMb != 0 { - s.ResizeWasmLruCache(arbmath.SaturatingUMul(uint64(rustCacheSizeMb), 1024*1024)) +func (s *ExecutionEngine) Initialize(rustCacheCapacityMb uint32, targetConfig *StylusTargetConfig) error { + if rustCacheCapacityMb != 0 { + s.SetWasmLruCacheCapacity(arbmath.SaturatingUMul(uint64(rustCacheCapacityMb), 1024*1024)) } if err := populateStylusTargetCache(targetConfig); err != nil { return fmt.Errorf("error populating stylus target cache: %w", err) @@ -193,8 +193,8 @@ func (s *ExecutionEngine) Initialize(rustCacheSizeMb uint32, targetConfig *Stylu } // exported for testing -func (s *ExecutionEngine) ResizeWasmLruCache(sizeBytes uint64) { - programs.ResizeWasmLruCache(sizeBytes) +func (s *ExecutionEngine) SetWasmLruCacheCapacity(capacityBytes uint64) { + programs.SetWasmLruCacheCapacity(capacityBytes) } // exported for testing diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index 93bb254ed8..8fbbdc9762 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -308,7 +308,7 @@ func (n *ExecutionNode) MarkFeedStart(to arbutil.MessageIndex) { func (n *ExecutionNode) Initialize(ctx context.Context) error { config := n.ConfigFetcher() - err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheSize, &config.StylusTarget) + err := n.ExecEngine.Initialize(config.Caching.StylusLRUCacheCapacity, &config.StylusTarget) if err != nil { return fmt.Errorf("error initializing execution engine: %w", err) } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 363f1050fb..d4a12d536a 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -166,7 +166,7 @@ var TestCachingConfig = gethexec.CachingConfig{ SnapshotRestoreGasLimit: 300_000_000_000, MaxNumberOfBlocksToSkipStateSaving: 0, MaxAmountOfGasToSkipStateSaving: 0, - StylusLRUCacheSize: 0, + StylusLRUCacheCapacity: 0, StateScheme: env.GetTestStateScheme(), } diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 0dd65a6bf6..7aa80f43ee 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2024,8 +2024,8 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - lruCacheSize := uint64(100_000) - builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) + lruCacheCapacity := uint64(100_000) + builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity(lruCacheCapacity) // fallible wasm program will not be cached since its size is greater than lruCacheSize fallibleAsmEstimateSizeBytes := uint64(118_624) @@ -2042,9 +2042,9 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - // resize lru cache - lruCacheSize = uint64(350_000) - builder.L2.ExecNode.ExecEngine.ResizeWasmLruCache(lruCacheSize) + // set new lru cache capacity + lruCacheCapacity = uint64(350_000) + builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity(lruCacheCapacity) // fallible wasm program will be cached tx = l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) From b7a949c92666143e136a70eca727e5cbb7731e8f Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 22 Aug 2024 09:55:43 -0300 Subject: [PATCH 052/101] Don't hardcode wasm sizes in TestWasmLruCache --- arbitrator/stylus/src/cache.rs | 15 ++++-- arbitrator/stylus/src/lib.rs | 24 ++++++---- arbos/programs/native.go | 5 ++ system_tests/program_test.go | 85 +++++++++++++++++++++++++--------- 4 files changed, 97 insertions(+), 32 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index aeefd9c8bd..c2aaddb6e5 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -91,6 +91,17 @@ pub struct LruCacheMetrics { pub does_not_fit: u32, } +pub fn deserialize_module( + module: &[u8], + version: u16, + debug: bool, +) -> Result<(Module, Engine, usize)> { + let engine = CompileConfig::version(version, debug).engine(target_native()); + let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; + let asm_size_estimate_bytes = module.serialize()?.len(); + Ok((module, engine, asm_size_estimate_bytes)) +} + impl InitCache { // current implementation only has one tag that stores to the long_term // future implementations might have more, but 0 is a reserved tag @@ -167,9 +178,7 @@ impl InitCache { } drop(cache); - let engine = CompileConfig::version(version, debug).engine(target_native()); - let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; - let asm_size_estimate_bytes = module.serialize()?.len(); + let (module, engine, asm_size_estimate_bytes) = deserialize_module(module, version, debug)?; let item = CacheItem::new(module, engine, asm_size_estimate_bytes); let data = item.data(); diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 791557dd0c..e5a80f5ee5 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -11,7 +11,7 @@ use arbutil::{ format::DebugBytes, Bytes32, }; -use cache::{InitCache, LruCacheMetrics}; +use cache::{deserialize_module, InitCache, LruCacheMetrics}; use evm_api::NativeRequestHandler; use eyre::ErrReport; use native::NativeInstance; @@ -321,13 +321,7 @@ pub unsafe extern "C" fn stylus_cache_module( arbos_tag: u32, debug: bool, ) { - if let Err(error) = InitCache::insert( - module_hash, - module.slice(), - version, - arbos_tag, - debug, - ) { + if let Err(error) = InitCache::insert(module_hash, module.slice(), version, arbos_tag, debug) { panic!("tried to cache invalid asm!: {error}"); } } @@ -373,3 +367,17 @@ pub extern "C" fn stylus_get_lru_cache_metrics() -> LruCacheMetrics { pub extern "C" fn stylus_clear_lru_cache() { InitCache::clear_lru_cache() } + +/// Gets asm estimate size. +/// Only used for testing purposes. +#[no_mangle] +pub unsafe extern "C" fn stylus_get_asm_size_estimate_bytes( + module: GoSliceData, + version: u16, + debug: bool, +) -> u64 { + match deserialize_module(module.slice(), version, debug) { + Err(error) => panic!("tried to get invalid asm!: {error}"), + Ok((_, _, asm_size_estimate_bytes)) => asm_size_estimate_bytes.try_into().unwrap(), + } +} diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 97b1f435ed..33ecf7d744 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -346,6 +346,11 @@ func ClearWasmLruCache() { C.stylus_clear_lru_cache() } +// exported for testing +func GetAsmSizeEstimateBytes(module []byte, version uint16, debug bool) uint64 { + return uint64(C.stylus_get_asm_size_estimate_bytes(goSlice(module), u16(version), cbool(debug))) +} + const DefaultTargetDescriptionArm = "arm64-linux-unknown+neon" const DefaultTargetDescriptionX86 = "x86_64-linux-unknown+sse4.2+lzcnt+bmi" diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 7aa80f43ee..faa1649df9 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2008,6 +2008,45 @@ func checkWasmStoreContent(t *testing.T, wasmDb ethdb.KeyValueStore, targets []s } } +func deployWasmAndGetSizeEstimateBytes( + t *testing.T, + builder *NodeBuilder, + auth bind.TransactOpts, + wasmName string, +) (common.Address, uint64) { + ctx := builder.ctx + l2client := builder.L2.Client + + wasm, _ := readWasmFile(t, rustFile(wasmName)) + arbWasm, err := pgen.NewArbWasm(types.ArbWasmAddress, l2client) + Require(t, err, ", wasmName:", wasmName) + + programAddress := deployContract(t, ctx, auth, l2client, wasm) + tx, err := arbWasm.ActivateProgram(&auth, programAddress) + Require(t, err, ", wasmName:", wasmName) + receipt, err := EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err, ", wasmName:", wasmName) + + if len(receipt.Logs) != 1 { + Fatal(t, "expected 1 log while activating, got ", len(receipt.Logs), ", wasmName:", wasmName) + } + log, err := arbWasm.ParseProgramActivated(*receipt.Logs[0]) + Require(t, err, ", wasmName:", wasmName) + + statedb, err := builder.L2.ExecNode.Backend.ArbInterface().BlockChain().State() + Require(t, err, ", wasmName:", wasmName) + + module, err := statedb.TryGetActivatedAsm(rawdb.LocalTarget(), log.ModuleHash) + Require(t, err, ", wasmName:", wasmName) + + asmSizeEstimateBytes := programs.GetAsmSizeEstimateBytes(module, log.Version, true) + if asmSizeEstimateBytes == 0 { + // just a sanity check + Fatal(t, "asmSizeEstimateBytes is 0, wasmName:", wasmName) + } + return programAddress, asmSizeEstimateBytes +} + func TestWasmLruCache(t *testing.T) { builder, auth, cleanup := setupProgramTest(t, true) ctx := builder.ctx @@ -2015,6 +2054,19 @@ func TestWasmLruCache(t *testing.T) { l2client := builder.L2.Client defer cleanup() + auth.GasLimit = 32000000 + auth.Value = oneEth + + fallibleProgramAddress, fallibleAsmSizeEstimateBytes := deployWasmAndGetSizeEstimateBytes(t, builder, auth, "fallible") + keccakProgramAddress, keccakAsmSizeEstimateBytes := deployWasmAndGetSizeEstimateBytes(t, builder, auth, "keccak") + mathProgramAddress, mathAsmSizeEstimateBytes := deployWasmAndGetSizeEstimateBytes(t, builder, auth, "math") + t.Log( + "asmSizeEstimateBytes, ", + "fallible:", fallibleAsmSizeEstimateBytes, + "keccak:", keccakAsmSizeEstimateBytes, + "math:", mathAsmSizeEstimateBytes, + ) + builder.L2.ExecNode.ExecEngine.ClearWasmLruCache() lruMetrics := builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() if lruMetrics.Count != 0 { @@ -2024,12 +2076,8 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - lruCacheCapacity := uint64(100_000) - builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity(lruCacheCapacity) - - // fallible wasm program will not be cached since its size is greater than lruCacheSize - fallibleAsmEstimateSizeBytes := uint64(118_624) - fallibleProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("fallible")) + builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity(fallibleAsmSizeEstimateBytes - 1) + // fallible wasm program will not be cached since its size is greater than lru cache capacity tx := l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) _, err := EnsureTxSucceeded(ctx, l2client, tx) @@ -2042,10 +2090,9 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - // set new lru cache capacity - lruCacheCapacity = uint64(350_000) - builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity(lruCacheCapacity) - + builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity( + fallibleAsmSizeEstimateBytes + keccakAsmSizeEstimateBytes + mathAsmSizeEstimateBytes - 1, + ) // fallible wasm program will be cached tx = l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2055,13 +2102,11 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 1 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 1, lruMetrics.Count) } - if lruMetrics.SizeBytes != fallibleAsmEstimateSizeBytes { - t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmEstimateSizeBytes, lruMetrics.SizeBytes) + if lruMetrics.SizeBytes != fallibleAsmSizeEstimateBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmSizeEstimateBytes, lruMetrics.SizeBytes) } // keccak wasm program will be cached - keccakAsmEstimateSizeBytes := uint64(175_496) - keccakProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("keccak")) tx = l2info.PrepareTxTo("Owner", &keccakProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) _, err = EnsureTxSucceeded(ctx, l2client, tx) @@ -2070,13 +2115,11 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if lruMetrics.SizeBytes != fallibleAsmEstimateSizeBytes+keccakAsmEstimateSizeBytes { - t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmEstimateSizeBytes+keccakAsmEstimateSizeBytes, lruMetrics.SizeBytes) + if lruMetrics.SizeBytes != fallibleAsmSizeEstimateBytes+keccakAsmSizeEstimateBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmSizeEstimateBytes+keccakAsmSizeEstimateBytes, lruMetrics.SizeBytes) } - // math wasm program will be cached, but fallible will be evicted since (fallible + keccak + math) > lruCacheSize - mathAsmEstimateSizeBytes := uint64(131_672) - mathProgramAddress := deployWasm(t, ctx, auth, l2client, rustFile("math")) + // math wasm program will be cached, but fallible will be evicted since (fallible + keccak + math) > lruCacheCapacity tx = l2info.PrepareTxTo("Owner", &mathProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) _, err = EnsureTxSucceeded(ctx, l2client, tx) @@ -2085,7 +2128,7 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if lruMetrics.SizeBytes != keccakAsmEstimateSizeBytes+mathAsmEstimateSizeBytes { - t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", keccakAsmEstimateSizeBytes+mathAsmEstimateSizeBytes, lruMetrics.SizeBytes) + if lruMetrics.SizeBytes != keccakAsmSizeEstimateBytes+mathAsmSizeEstimateBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", keccakAsmSizeEstimateBytes+mathAsmSizeEstimateBytes, lruMetrics.SizeBytes) } } From bbed30a3bc8e628f926f0da6aabbb4c0ef7ad679 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 22 Aug 2024 10:02:00 -0300 Subject: [PATCH 053/101] Removes unnecessary calls to ExecutionEngine regarding Wasm LRU cache --- arbos/programs/native.go | 5 ++--- execution/gethexec/executionengine.go | 19 ++----------------- system_tests/program_test.go | 18 +++++++++--------- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 33ecf7d744..dd5cf648e9 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -325,7 +325,6 @@ type WasmLruCacheMetrics struct { Count uint32 } -// exported for testing func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { metrics := C.stylus_get_lru_cache_metrics() @@ -341,12 +340,12 @@ func GetWasmLruCacheMetrics() *WasmLruCacheMetrics { } } -// exported for testing +// Used for testing func ClearWasmLruCache() { C.stylus_clear_lru_cache() } -// exported for testing +// Used for testing func GetAsmSizeEstimateBytes(module []byte, version uint16, debug bool) uint64 { return uint64(C.stylus_get_asm_size_estimate_bytes(goSlice(module), u16(version), cbool(debug))) } diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 5b5c9a8938..2e6fff5c96 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -184,7 +184,7 @@ func populateStylusTargetCache(targetConfig *StylusTargetConfig) error { func (s *ExecutionEngine) Initialize(rustCacheCapacityMb uint32, targetConfig *StylusTargetConfig) error { if rustCacheCapacityMb != 0 { - s.SetWasmLruCacheCapacity(arbmath.SaturatingUMul(uint64(rustCacheCapacityMb), 1024*1024)) + programs.SetWasmLruCacheCapacity(arbmath.SaturatingUMul(uint64(rustCacheCapacityMb), 1024*1024)) } if err := populateStylusTargetCache(targetConfig); err != nil { return fmt.Errorf("error populating stylus target cache: %w", err) @@ -192,21 +192,6 @@ func (s *ExecutionEngine) Initialize(rustCacheCapacityMb uint32, targetConfig *S return nil } -// exported for testing -func (s *ExecutionEngine) SetWasmLruCacheCapacity(capacityBytes uint64) { - programs.SetWasmLruCacheCapacity(capacityBytes) -} - -// exported for testing -func (s *ExecutionEngine) GetWasmLruCacheMetrics() *programs.WasmLruCacheMetrics { - return programs.GetWasmLruCacheMetrics() -} - -// exported for testing -func (s *ExecutionEngine) ClearWasmLruCache() { - programs.ClearWasmLruCache() -} - func (s *ExecutionEngine) SetRecorder(recorder *BlockRecorder) { if s.Started() { panic("trying to set recorder after start") @@ -985,7 +970,7 @@ func (s *ExecutionEngine) Start(ctx_in context.Context) { case <-ctx.Done(): return case <-time.After(time.Minute): - s.GetWasmLruCacheMetrics() + programs.GetWasmLruCacheMetrics() } } }) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index faa1649df9..b943d20d7e 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2040,8 +2040,8 @@ func deployWasmAndGetSizeEstimateBytes( Require(t, err, ", wasmName:", wasmName) asmSizeEstimateBytes := programs.GetAsmSizeEstimateBytes(module, log.Version, true) + // just a sanity check if asmSizeEstimateBytes == 0 { - // just a sanity check Fatal(t, "asmSizeEstimateBytes is 0, wasmName:", wasmName) } return programAddress, asmSizeEstimateBytes @@ -2067,8 +2067,8 @@ func TestWasmLruCache(t *testing.T) { "math:", mathAsmSizeEstimateBytes, ) - builder.L2.ExecNode.ExecEngine.ClearWasmLruCache() - lruMetrics := builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + programs.ClearWasmLruCache() + lruMetrics := programs.GetWasmLruCacheMetrics() if lruMetrics.Count != 0 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 0, lruMetrics.Count) } @@ -2076,13 +2076,13 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity(fallibleAsmSizeEstimateBytes - 1) + programs.SetWasmLruCacheCapacity(fallibleAsmSizeEstimateBytes - 1) // fallible wasm program will not be cached since its size is greater than lru cache capacity tx := l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) _, err := EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) - lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + lruMetrics = programs.GetWasmLruCacheMetrics() if lruMetrics.Count != 0 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 0, lruMetrics.Count) } @@ -2090,7 +2090,7 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - builder.L2.ExecNode.ExecEngine.SetWasmLruCacheCapacity( + programs.SetWasmLruCacheCapacity( fallibleAsmSizeEstimateBytes + keccakAsmSizeEstimateBytes + mathAsmSizeEstimateBytes - 1, ) // fallible wasm program will be cached @@ -2098,7 +2098,7 @@ func TestWasmLruCache(t *testing.T) { Require(t, l2client.SendTransaction(ctx, tx)) _, err = EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) - lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + lruMetrics = programs.GetWasmLruCacheMetrics() if lruMetrics.Count != 1 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 1, lruMetrics.Count) } @@ -2111,7 +2111,7 @@ func TestWasmLruCache(t *testing.T) { Require(t, l2client.SendTransaction(ctx, tx)) _, err = EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) - lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + lruMetrics = programs.GetWasmLruCacheMetrics() if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } @@ -2124,7 +2124,7 @@ func TestWasmLruCache(t *testing.T) { Require(t, l2client.SendTransaction(ctx, tx)) _, err = EnsureTxSucceeded(ctx, l2client, tx) Require(t, err) - lruMetrics = builder.L2.ExecNode.ExecEngine.GetWasmLruCacheMetrics() + lruMetrics = programs.GetWasmLruCacheMetrics() if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } From 17a62dad358217859c210920945d45cb9b8949db Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 22 Aug 2024 10:30:24 -0300 Subject: [PATCH 054/101] Removes unsafe from stylus_get_asm_size_estimate_bytes --- arbitrator/stylus/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index e5a80f5ee5..b38bc3044b 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -371,7 +371,7 @@ pub extern "C" fn stylus_clear_lru_cache() { /// Gets asm estimate size. /// Only used for testing purposes. #[no_mangle] -pub unsafe extern "C" fn stylus_get_asm_size_estimate_bytes( +pub extern "C" fn stylus_get_asm_size_estimate_bytes( module: GoSliceData, version: u16, debug: bool, From 8a3d6efe382a210a1fb0452ac678e4c70bd9f7c1 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 22 Aug 2024 11:01:36 -0300 Subject: [PATCH 055/101] Format rs files --- arbitrator/stylus/src/native.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arbitrator/stylus/src/native.rs b/arbitrator/stylus/src/native.rs index b661435e52..7a82314fbc 100644 --- a/arbitrator/stylus/src/native.rs +++ b/arbitrator/stylus/src/native.rs @@ -128,13 +128,8 @@ impl> NativeInstance { if !env.evm_data.cached { long_term_tag = 0; } - let (module, store) = InitCache::insert( - module_hash, - module, - version, - long_term_tag, - debug, - )?; + let (module, store) = + InitCache::insert(module_hash, module, version, long_term_tag, debug)?; Self::from_module(module, store, env) } From eaa04db3708c58d8d3f32c571752f240844e4bda Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 28 Aug 2024 11:47:30 -0300 Subject: [PATCH 056/101] From println to eprintln in stylus cache --- arbitrator/stylus/src/cache.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index c2aaddb6e5..8f54b0cb10 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -186,7 +186,7 @@ impl InitCache { if long_term_tag != Self::ARBOS_TAG { if cache.lru.put_with_weight(key, item).is_err() { cache.lru_counters.does_not_fit += 1; - println!("{}", Self::DOES_NOT_FIT_MSG); + eprintln!("{}", Self::DOES_NOT_FIT_MSG); }; } else { cache.long_term.insert(key, item); @@ -203,7 +203,7 @@ impl InitCache { let mut cache = cache!(); if let Some(item) = cache.long_term.remove(&key) { if cache.lru.put_with_weight(key, item).is_err() { - println!("{}", Self::DOES_NOT_FIT_MSG); + eprintln!("{}", Self::DOES_NOT_FIT_MSG); } } } @@ -217,7 +217,7 @@ impl InitCache { for (key, item) in cache.long_term.drain() { // not all will fit, just a heuristic if cache.lru.put_with_weight(key, item).is_err() { - println!("{}", Self::DOES_NOT_FIT_MSG); + eprintln!("{}", Self::DOES_NOT_FIT_MSG); } } } From 1449a7b7fbea4c9e0dbe3df4befc7b37f354ae1d Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 28 Aug 2024 14:59:36 -0300 Subject: [PATCH 057/101] Renames asm_size_estimate_bytes to lru_entry_size_estimate_bytes --- arbitrator/stylus/src/cache.rs | 4 ++-- arbitrator/stylus/src/lib.rs | 6 ++--- arbos/programs/native.go | 4 ++-- system_tests/program_test.go | 40 +++++++++++++++++----------------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 8f54b0cb10..cc0cf5344a 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -98,8 +98,8 @@ pub fn deserialize_module( ) -> Result<(Module, Engine, usize)> { let engine = CompileConfig::version(version, debug).engine(target_native()); let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; - let asm_size_estimate_bytes = module.serialize()?.len(); - Ok((module, engine, asm_size_estimate_bytes)) + let lru_entry_size_estimate_bytes = module.serialize()?.len(); + Ok((module, engine, lru_entry_size_estimate_bytes)) } impl InitCache { diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index b38bc3044b..fc2e1dc6ea 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -368,16 +368,16 @@ pub extern "C" fn stylus_clear_lru_cache() { InitCache::clear_lru_cache() } -/// Gets asm estimate size. +/// Gets lru entry size in bytes. /// Only used for testing purposes. #[no_mangle] -pub extern "C" fn stylus_get_asm_size_estimate_bytes( +pub extern "C" fn stylus_get_lru_entry_size_estimate_bytes( module: GoSliceData, version: u16, debug: bool, ) -> u64 { match deserialize_module(module.slice(), version, debug) { Err(error) => panic!("tried to get invalid asm!: {error}"), - Ok((_, _, asm_size_estimate_bytes)) => asm_size_estimate_bytes.try_into().unwrap(), + Ok((_, _, lru_entry_size_estimate_bytes)) => lru_entry_size_estimate_bytes.try_into().unwrap(), } } diff --git a/arbos/programs/native.go b/arbos/programs/native.go index dd5cf648e9..57290dfa1e 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -346,8 +346,8 @@ func ClearWasmLruCache() { } // Used for testing -func GetAsmSizeEstimateBytes(module []byte, version uint16, debug bool) uint64 { - return uint64(C.stylus_get_asm_size_estimate_bytes(goSlice(module), u16(version), cbool(debug))) +func GetLruEntrySizeEstimateBytes(module []byte, version uint16, debug bool) uint64 { + return uint64(C.stylus_get_lru_entry_size_estimate_bytes(goSlice(module), u16(version), cbool(debug))) } const DefaultTargetDescriptionArm = "arm64-linux-unknown+neon" diff --git a/system_tests/program_test.go b/system_tests/program_test.go index b943d20d7e..1cbbf268f1 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -2008,7 +2008,7 @@ func checkWasmStoreContent(t *testing.T, wasmDb ethdb.KeyValueStore, targets []s } } -func deployWasmAndGetSizeEstimateBytes( +func deployWasmAndGetLruEntrySizeEstimateBytes( t *testing.T, builder *NodeBuilder, auth bind.TransactOpts, @@ -2039,12 +2039,12 @@ func deployWasmAndGetSizeEstimateBytes( module, err := statedb.TryGetActivatedAsm(rawdb.LocalTarget(), log.ModuleHash) Require(t, err, ", wasmName:", wasmName) - asmSizeEstimateBytes := programs.GetAsmSizeEstimateBytes(module, log.Version, true) + lruEntrySizeEstimateBytes := programs.GetLruEntrySizeEstimateBytes(module, log.Version, true) // just a sanity check - if asmSizeEstimateBytes == 0 { - Fatal(t, "asmSizeEstimateBytes is 0, wasmName:", wasmName) + if lruEntrySizeEstimateBytes == 0 { + Fatal(t, "lruEntrySizeEstimateBytes is 0, wasmName:", wasmName) } - return programAddress, asmSizeEstimateBytes + return programAddress, lruEntrySizeEstimateBytes } func TestWasmLruCache(t *testing.T) { @@ -2057,14 +2057,14 @@ func TestWasmLruCache(t *testing.T) { auth.GasLimit = 32000000 auth.Value = oneEth - fallibleProgramAddress, fallibleAsmSizeEstimateBytes := deployWasmAndGetSizeEstimateBytes(t, builder, auth, "fallible") - keccakProgramAddress, keccakAsmSizeEstimateBytes := deployWasmAndGetSizeEstimateBytes(t, builder, auth, "keccak") - mathProgramAddress, mathAsmSizeEstimateBytes := deployWasmAndGetSizeEstimateBytes(t, builder, auth, "math") + fallibleProgramAddress, fallibleLruEntrySizeEstimateBytes := deployWasmAndGetLruEntrySizeEstimateBytes(t, builder, auth, "fallible") + keccakProgramAddress, keccakLruEntrySizeEstimateBytes := deployWasmAndGetLruEntrySizeEstimateBytes(t, builder, auth, "keccak") + mathProgramAddress, mathLruEntrySizeEstimateBytes := deployWasmAndGetLruEntrySizeEstimateBytes(t, builder, auth, "math") t.Log( - "asmSizeEstimateBytes, ", - "fallible:", fallibleAsmSizeEstimateBytes, - "keccak:", keccakAsmSizeEstimateBytes, - "math:", mathAsmSizeEstimateBytes, + "lruEntrySizeEstimateBytes, ", + "fallible:", fallibleLruEntrySizeEstimateBytes, + "keccak:", keccakLruEntrySizeEstimateBytes, + "math:", mathLruEntrySizeEstimateBytes, ) programs.ClearWasmLruCache() @@ -2076,7 +2076,7 @@ func TestWasmLruCache(t *testing.T) { t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", 0, lruMetrics.SizeBytes) } - programs.SetWasmLruCacheCapacity(fallibleAsmSizeEstimateBytes - 1) + programs.SetWasmLruCacheCapacity(fallibleLruEntrySizeEstimateBytes - 1) // fallible wasm program will not be cached since its size is greater than lru cache capacity tx := l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) Require(t, l2client.SendTransaction(ctx, tx)) @@ -2091,7 +2091,7 @@ func TestWasmLruCache(t *testing.T) { } programs.SetWasmLruCacheCapacity( - fallibleAsmSizeEstimateBytes + keccakAsmSizeEstimateBytes + mathAsmSizeEstimateBytes - 1, + fallibleLruEntrySizeEstimateBytes + keccakLruEntrySizeEstimateBytes + mathLruEntrySizeEstimateBytes - 1, ) // fallible wasm program will be cached tx = l2info.PrepareTxTo("Owner", &fallibleProgramAddress, l2info.TransferGas, nil, []byte{0x01}) @@ -2102,8 +2102,8 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 1 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 1, lruMetrics.Count) } - if lruMetrics.SizeBytes != fallibleAsmSizeEstimateBytes { - t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmSizeEstimateBytes, lruMetrics.SizeBytes) + if lruMetrics.SizeBytes != fallibleLruEntrySizeEstimateBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleLruEntrySizeEstimateBytes, lruMetrics.SizeBytes) } // keccak wasm program will be cached @@ -2115,8 +2115,8 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if lruMetrics.SizeBytes != fallibleAsmSizeEstimateBytes+keccakAsmSizeEstimateBytes { - t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleAsmSizeEstimateBytes+keccakAsmSizeEstimateBytes, lruMetrics.SizeBytes) + if lruMetrics.SizeBytes != fallibleLruEntrySizeEstimateBytes+keccakLruEntrySizeEstimateBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", fallibleLruEntrySizeEstimateBytes+keccakLruEntrySizeEstimateBytes, lruMetrics.SizeBytes) } // math wasm program will be cached, but fallible will be evicted since (fallible + keccak + math) > lruCacheCapacity @@ -2128,7 +2128,7 @@ func TestWasmLruCache(t *testing.T) { if lruMetrics.Count != 2 { t.Fatalf("lruMetrics.Count, expected: %v, actual: %v", 2, lruMetrics.Count) } - if lruMetrics.SizeBytes != keccakAsmSizeEstimateBytes+mathAsmSizeEstimateBytes { - t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", keccakAsmSizeEstimateBytes+mathAsmSizeEstimateBytes, lruMetrics.SizeBytes) + if lruMetrics.SizeBytes != keccakLruEntrySizeEstimateBytes+mathLruEntrySizeEstimateBytes { + t.Fatalf("lruMetrics.SizeBytes, expected: %v, actual: %v", keccakLruEntrySizeEstimateBytes+mathLruEntrySizeEstimateBytes, lruMetrics.SizeBytes) } } From ba9e9d1c2cc5da358679081dc4456208dfac1fcc Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 28 Aug 2024 15:26:46 -0300 Subject: [PATCH 058/101] Adds extra bytes to lru_entry_size_bytes to account for overheads --- arbitrator/stylus/src/cache.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index cc0cf5344a..0bbeabcb4c 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -56,15 +56,15 @@ impl CacheKey { struct CacheItem { module: Module, engine: Engine, - asm_size_estimate_bytes: usize, + entry_size_estimate_bytes: usize, } impl CacheItem { - fn new(module: Module, engine: Engine, asm_size_estimate_bytes: usize) -> Self { + fn new(module: Module, engine: Engine, entry_size_estimate_bytes: usize) -> Self { Self { module, engine, - asm_size_estimate_bytes, + entry_size_estimate_bytes, } } @@ -78,7 +78,7 @@ impl WeightScale for CustomWeightScale { fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize { // clru defines that each entry consumes (weight + 1) of the cache capacity. // We subtract 1 since we only want to use the weight as the size of the entry. - val.asm_size_estimate_bytes.saturating_sub(1) + val.entry_size_estimate_bytes.saturating_sub(1) } } @@ -98,8 +98,12 @@ pub fn deserialize_module( ) -> Result<(Module, Engine, usize)> { let engine = CompileConfig::version(version, debug).engine(target_native()); let module = unsafe { Module::deserialize_unchecked(&engine, module)? }; - let lru_entry_size_estimate_bytes = module.serialize()?.len(); - Ok((module, engine, lru_entry_size_estimate_bytes)) + + let asm_size_estimate_bytes = module.serialize()?.len(); + // add 128 bytes for the cache item overhead + let entry_size_estimate_bytes = asm_size_estimate_bytes + 128; + + Ok((module, engine, entry_size_estimate_bytes)) } impl InitCache { @@ -178,9 +182,9 @@ impl InitCache { } drop(cache); - let (module, engine, asm_size_estimate_bytes) = deserialize_module(module, version, debug)?; + let (module, engine, entry_size_estimate_bytes) = deserialize_module(module, version, debug)?; - let item = CacheItem::new(module, engine, asm_size_estimate_bytes); + let item = CacheItem::new(module, engine, entry_size_estimate_bytes); let data = item.data(); let mut cache = cache!(); if long_term_tag != Self::ARBOS_TAG { From 5a82f007b6529033c95c981b9ad837ee622c0efe Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Wed, 28 Aug 2024 15:45:25 -0300 Subject: [PATCH 059/101] Format rs files --- arbitrator/stylus/src/cache.rs | 3 ++- arbitrator/stylus/src/lib.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arbitrator/stylus/src/cache.rs b/arbitrator/stylus/src/cache.rs index 0bbeabcb4c..c1fdaaccee 100644 --- a/arbitrator/stylus/src/cache.rs +++ b/arbitrator/stylus/src/cache.rs @@ -182,7 +182,8 @@ impl InitCache { } drop(cache); - let (module, engine, entry_size_estimate_bytes) = deserialize_module(module, version, debug)?; + let (module, engine, entry_size_estimate_bytes) = + deserialize_module(module, version, debug)?; let item = CacheItem::new(module, engine, entry_size_estimate_bytes); let data = item.data(); diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index fc2e1dc6ea..32094752fc 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -378,6 +378,8 @@ pub extern "C" fn stylus_get_lru_entry_size_estimate_bytes( ) -> u64 { match deserialize_module(module.slice(), version, debug) { Err(error) => panic!("tried to get invalid asm!: {error}"), - Ok((_, _, lru_entry_size_estimate_bytes)) => lru_entry_size_estimate_bytes.try_into().unwrap(), + Ok((_, _, lru_entry_size_estimate_bytes)) => { + lru_entry_size_estimate_bytes.try_into().unwrap() + } } } From f144eb17addcc2b45ccf889347296ad9caf1a5da Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 29 Aug 2024 10:30:47 -0300 Subject: [PATCH 060/101] Renames rustCacheCapacityMb to rustCacheCapacityMB --- execution/gethexec/executionengine.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/execution/gethexec/executionengine.go b/execution/gethexec/executionengine.go index 2e6fff5c96..4527c5f85e 100644 --- a/execution/gethexec/executionengine.go +++ b/execution/gethexec/executionengine.go @@ -182,9 +182,9 @@ func populateStylusTargetCache(targetConfig *StylusTargetConfig) error { return nil } -func (s *ExecutionEngine) Initialize(rustCacheCapacityMb uint32, targetConfig *StylusTargetConfig) error { - if rustCacheCapacityMb != 0 { - programs.SetWasmLruCacheCapacity(arbmath.SaturatingUMul(uint64(rustCacheCapacityMb), 1024*1024)) +func (s *ExecutionEngine) Initialize(rustCacheCapacityMB uint32, targetConfig *StylusTargetConfig) error { + if rustCacheCapacityMB != 0 { + programs.SetWasmLruCacheCapacity(arbmath.SaturatingUMul(uint64(rustCacheCapacityMB), 1024*1024)) } if err := populateStylusTargetCache(targetConfig); err != nil { return fmt.Errorf("error populating stylus target cache: %w", err) From 070a43a0274891f1c562b0c1489e9af6e7b25b4f Mon Sep 17 00:00:00 2001 From: Ganesh Vanahalli Date: Mon, 9 Sep 2024 13:34:52 +0530 Subject: [PATCH 061/101] update dataposter test to support *ethclient.Client --- arbnode/dataposter/data_poster.go | 4 +- arbnode/dataposter/dataposter_test.go | 63 ++++++++++++--------------- arbutil/wait_for_l1.go | 15 ------- staker/rollup_watcher.go | 6 +-- staker/txbuilder/builder.go | 4 +- 5 files changed, 34 insertions(+), 58 deletions(-) diff --git a/arbnode/dataposter/data_poster.go b/arbnode/dataposter/data_poster.go index 6a483929b2..8a9d695073 100644 --- a/arbnode/dataposter/data_poster.go +++ b/arbnode/dataposter/data_poster.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -39,7 +40,6 @@ import ( "github.com/offchainlabs/nitro/arbnode/dataposter/noop" "github.com/offchainlabs/nitro/arbnode/dataposter/slice" "github.com/offchainlabs/nitro/arbnode/dataposter/storage" - "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/blobs" "github.com/offchainlabs/nitro/util/headerreader" @@ -69,7 +69,7 @@ var ( type DataPoster struct { stopwaiter.StopWaiter headerReader *headerreader.HeaderReader - client arbutil.L1Interface + client *ethclient.Client auth *bind.TransactOpts signer signerFn config ConfigFetcher diff --git a/arbnode/dataposter/dataposter_test.go b/arbnode/dataposter/dataposter_test.go index 7f2f61c07e..5c8ab68541 100644 --- a/arbnode/dataposter/dataposter_test.go +++ b/arbnode/dataposter/dataposter_test.go @@ -2,17 +2,18 @@ package dataposter import ( "context" + "errors" "fmt" "math/big" "testing" "time" "github.com/Knetic/govaluate" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -152,46 +153,36 @@ func TestMaxFeeCapFormulaCalculation(t *testing.T) { } } -type stubL1Client struct { +type stubL1ClientInterface struct { senderNonce uint64 suggestedGasTipCap *big.Int - - // Define most of the required methods that aren't used by feeAndTipCaps - backends.SimulatedBackend -} - -func (c *stubL1Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { - return c.senderNonce, nil -} - -func (c *stubL1Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return c.suggestedGasTipCap, nil -} - -// Not used but we need to define -func (c *stubL1Client) BlockNumber(ctx context.Context) (uint64, error) { - return 0, nil -} - -func (c *stubL1Client) CallContractAtHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) ([]byte, error) { - return []byte{}, nil } -func (c *stubL1Client) CodeAtHash(ctx context.Context, address common.Address, blockHash common.Hash) ([]byte, error) { - return []byte{}, nil +func (c *stubL1ClientInterface) CallContext(ctx_in context.Context, result interface{}, method string, args ...interface{}) error { + switch method { + case "eth_getTransactionCount": + ptr, ok := result.(*hexutil.Uint64) + if !ok { + return errors.New("result is not a *hexutil.Uint64") + } + *ptr = hexutil.Uint64(c.senderNonce) + case "eth_maxPriorityFeePerGas": + ptr, ok := result.(*hexutil.Big) + if !ok { + return errors.New("result is not a *hexutil.Big") + } + *ptr = hexutil.Big(*c.suggestedGasTipCap) + } + return nil } -func (c *stubL1Client) ChainID(ctx context.Context) (*big.Int, error) { +func (c *stubL1ClientInterface) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) { return nil, nil } - -func (c *stubL1Client) Client() rpc.ClientInterface { +func (c *stubL1ClientInterface) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { return nil } - -func (c *stubL1Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { - return common.Address{}, nil -} +func (c *stubL1ClientInterface) Close() {} func TestFeeAndTipCaps_EnoughBalance_NoBacklog_NoUnconfirmed_BlobTx(t *testing.T) { conf := func() *DataPosterConfig { @@ -223,10 +214,10 @@ func TestFeeAndTipCaps_EnoughBalance_NoBacklog_NoUnconfirmed_BlobTx(t *testing.T extraBacklog: func() uint64 { return 0 }, balance: big.NewInt(0).Mul(big.NewInt(params.Ether), big.NewInt(10)), usingNoOpStorage: false, - client: &stubL1Client{ + client: ethclient.NewClient(&stubL1ClientInterface{ senderNonce: 1, suggestedGasTipCap: big.NewInt(2 * params.GWei), - }, + }), auth: &bind.TransactOpts{ From: common.Address{}, }, @@ -354,10 +345,10 @@ func TestFeeAndTipCaps_RBF_RisingBlobFee_FallingBaseFee(t *testing.T) { extraBacklog: func() uint64 { return 0 }, balance: big.NewInt(0).Mul(big.NewInt(params.Ether), big.NewInt(10)), usingNoOpStorage: false, - client: &stubL1Client{ + client: ethclient.NewClient(&stubL1ClientInterface{ senderNonce: 1, suggestedGasTipCap: big.NewInt(2 * params.GWei), - }, + }), auth: &bind.TransactOpts{ From: common.Address{}, }, diff --git a/arbutil/wait_for_l1.go b/arbutil/wait_for_l1.go index 49eea6af78..80dd356b24 100644 --- a/arbutil/wait_for_l1.go +++ b/arbutil/wait_for_l1.go @@ -10,27 +10,12 @@ import ( "math/big" "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" ) -type L1Interface interface { - bind.ContractBackend - bind.BlockHashContractCaller - ethereum.ChainReader - ethereum.ChainStateReader - ethereum.TransactionReader - TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) - BlockNumber(ctx context.Context) (uint64, error) - PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) - ChainID(ctx context.Context) (*big.Int, error) - Client() rpc.ClientInterface -} - func SendTxAsCall(ctx context.Context, client *ethclient.Client, tx *types.Transaction, from common.Address, blockNum *big.Int, unlimitedGas bool) ([]byte, error) { var gas uint64 if unlimitedGas { diff --git a/staker/rollup_watcher.go b/staker/rollup_watcher.go index 9c51e659f5..a7221d335d 100644 --- a/staker/rollup_watcher.go +++ b/staker/rollup_watcher.go @@ -48,18 +48,18 @@ type RollupWatcher struct { *rollupgen.RollupUserLogic address common.Address fromBlock *big.Int - client WatcherL1Interface + client RollupWatcherL1Interface baseCallOpts bind.CallOpts unSupportedL3Method atomic.Bool } -type WatcherL1Interface interface { +type RollupWatcherL1Interface interface { bind.ContractBackend HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) } -func NewRollupWatcher(address common.Address, client WatcherL1Interface, callOpts bind.CallOpts) (*RollupWatcher, error) { +func NewRollupWatcher(address common.Address, client RollupWatcherL1Interface, callOpts bind.CallOpts) (*RollupWatcher, error) { con, err := rollupgen.NewRollupUserLogic(address, client) if err != nil { return nil, err diff --git a/staker/txbuilder/builder.go b/staker/txbuilder/builder.go index fa40c6a816..f52b03a781 100644 --- a/staker/txbuilder/builder.go +++ b/staker/txbuilder/builder.go @@ -27,8 +27,8 @@ type ValidatorWalletInterface interface { // Builder combines any transactions sent to it via SendTransaction into one batch, // which is then sent to the validator wallet. // This lets the validator make multiple atomic transactions. -// This inherits from an eth client so it can be used as an L1Interface, -// where it transparently intercepts calls to SendTransaction and queues them for the next batch. +// This inherits from an ethclient.Client so it can be used to transparently +// intercept calls to SendTransaction and queue them for the next batch. type Builder struct { *ethclient.Client transactions []*types.Transaction From 35a22ac87ca793a0f3222ad3adeec365314afb1e Mon Sep 17 00:00:00 2001 From: Ganesh Vanahalli Date: Tue, 10 Sep 2024 16:27:10 +0530 Subject: [PATCH 062/101] address PR comments --- arbnode/dataposter/dataposter_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arbnode/dataposter/dataposter_test.go b/arbnode/dataposter/dataposter_test.go index 769919474b..7bf0f86e6f 100644 --- a/arbnode/dataposter/dataposter_test.go +++ b/arbnode/dataposter/dataposter_test.go @@ -153,12 +153,12 @@ func TestMaxFeeCapFormulaCalculation(t *testing.T) { } } -type stubL1ClientInterface struct { +type stubL1ClientInner struct { senderNonce uint64 suggestedGasTipCap *big.Int } -func (c *stubL1ClientInterface) CallContext(ctx_in context.Context, result interface{}, method string, args ...interface{}) error { +func (c *stubL1ClientInner) CallContext(ctx_in context.Context, result interface{}, method string, args ...interface{}) error { switch method { case "eth_getTransactionCount": ptr, ok := result.(*hexutil.Uint64) @@ -176,13 +176,13 @@ func (c *stubL1ClientInterface) CallContext(ctx_in context.Context, result inter return nil } -func (c *stubL1ClientInterface) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) { +func (c *stubL1ClientInner) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) { return nil, nil } -func (c *stubL1ClientInterface) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { +func (c *stubL1ClientInner) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { return nil } -func (c *stubL1ClientInterface) Close() {} +func (c *stubL1ClientInner) Close() {} func TestFeeAndTipCaps_EnoughBalance_NoBacklog_NoUnconfirmed_BlobTx(t *testing.T) { conf := func() *DataPosterConfig { @@ -214,7 +214,7 @@ func TestFeeAndTipCaps_EnoughBalance_NoBacklog_NoUnconfirmed_BlobTx(t *testing.T extraBacklog: func() uint64 { return 0 }, balance: big.NewInt(0).Mul(big.NewInt(params.Ether), big.NewInt(10)), usingNoOpStorage: false, - client: ethclient.NewClient(&stubL1ClientInterface{ + client: ethclient.NewClient(&stubL1ClientInner{ senderNonce: 1, suggestedGasTipCap: big.NewInt(2 * params.GWei), }), @@ -345,7 +345,7 @@ func TestFeeAndTipCaps_RBF_RisingBlobFee_FallingBaseFee(t *testing.T) { extraBacklog: func() uint64 { return 0 }, balance: big.NewInt(0).Mul(big.NewInt(params.Ether), big.NewInt(10)), usingNoOpStorage: false, - client: ethclient.NewClient(&stubL1ClientInterface{ + client: ethclient.NewClient(&stubL1ClientInner{ senderNonce: 1, suggestedGasTipCap: big.NewInt(2 * params.GWei), }), From ae1ceaecea9bedc48a06e43966a639bf7e069d5f Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Thu, 12 Sep 2024 18:11:30 -0300 Subject: [PATCH 063/101] Enable external-signer for batch-poster with DA When running a batch-poster with anytrust, Nitro needs to load the batch-poster parent-chain wallet config to sign the DA messages even if an external signer is also being used. --- cmd/nitro/nitro.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index e66d99b56e..61f914f14d 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -249,7 +249,7 @@ func mainImpl() int { // If sequencer and signing is enabled or batchposter is enabled without // external signing sequencer will need a key. sequencerNeedsKey := (nodeConfig.Node.Sequencer && !nodeConfig.Node.Feed.Output.DisableSigning) || - (nodeConfig.Node.BatchPoster.Enable && nodeConfig.Node.BatchPoster.DataPoster.ExternalSigner.URL == "") + (nodeConfig.Node.BatchPoster.Enable && (nodeConfig.Node.BatchPoster.DataPoster.ExternalSigner.URL == "" || nodeConfig.Node.DataAvailability.Enable)) validatorNeedsKey := nodeConfig.Node.Staker.OnlyCreateWalletContract || (nodeConfig.Node.Staker.Enable && !strings.EqualFold(nodeConfig.Node.Staker.Strategy, "watchtower") && nodeConfig.Node.Staker.DataPoster.ExternalSigner.URL == "") From 984a7f1cec03d86fa40f2a0634f1fa3fcf1c69ff Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Wed, 18 Sep 2024 15:14:58 +0200 Subject: [PATCH 064/101] Fix broken imports of ethdb and rawdb --- staker/stateless_block_validator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index 0cd97ec8d3..c4b0948e43 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -12,6 +12,7 @@ import ( "github.com/offchainlabs/nitro/arbstate/daprovider" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -468,7 +469,7 @@ func (v *StatelessBlockValidator) ValidationInputsAt(ctx context.Context, pos ar if err != nil { return server_api.InputJSON{}, err } - input, err := entry.ToInput([]rawdb.Target{rawdb.TargetWavm}) + input, err := entry.ToInput([]ethdb.WasmTarget{rawdb.TargetWavm}) if err != nil { return server_api.InputJSON{}, err } From c45d80fd4ff16fd4b25dc8e4e200be19d5f0cd7c Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Wed, 18 Sep 2024 15:35:34 +0200 Subject: [PATCH 065/101] Update Cargo.lock --- arbitrator/wasm-libraries/Cargo.lock | 195 ++++++++++++++++++++------- 1 file changed, 148 insertions(+), 47 deletions(-) diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index b234424f69..c79b389f6a 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -46,6 +46,21 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -121,6 +136,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bincode" version = "1.3.3" @@ -260,6 +281,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + [[package]] name = "clap" version = "2.34.0" @@ -281,6 +315,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "corosensei" version = "0.1.4" @@ -436,38 +476,14 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - [[package]] name = "darling" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] @@ -480,27 +496,17 @@ dependencies = [ "ident_case", "proc-macro2", "quote", + "strsim 0.11.1", "syn 2.0.72", ] -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", -] - [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.10", + "darling_core", "quote", "syn 2.0.72", ] @@ -518,6 +524,16 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -622,7 +638,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" dependencies = [ - "darling 0.20.10", + "darling", "proc-macro2", "quote", "syn 2.0.72", @@ -760,6 +776,29 @@ dependencies = [ "caller-env", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -780,6 +819,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -790,6 +830,7 @@ checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -1000,6 +1041,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -1128,6 +1175,12 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -1473,24 +1526,32 @@ dependencies = [ [[package]] name = "serde_with" -version = "1.14.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.3.0", "serde", + "serde_derive", + "serde_json", "serde_with_macros", + "time", ] [[package]] name = "serde_with_macros" -version = "1.5.2" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ - "darling 0.13.4", + "darling", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1602,9 +1663,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "structopt" @@ -1693,6 +1754,37 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -2111,6 +2203,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.33.0" From f9e6eea54e31d50834f64697b5cd029c5274e160 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Wed, 18 Sep 2024 18:32:16 +0200 Subject: [PATCH 066/101] Address review feedback --- arbitrator/arbutil/src/types.rs | 101 ++++++++++++++++++++++++++++ arbitrator/prover/src/prepare.rs | 1 - arbnode/api.go | 15 +---- staker/stateless_block_validator.go | 5 +- system_tests/common_test.go | 3 +- 5 files changed, 107 insertions(+), 18 deletions(-) diff --git a/arbitrator/arbutil/src/types.rs b/arbitrator/arbutil/src/types.rs index 207b8ab949..e92d4dfbc5 100644 --- a/arbitrator/arbutil/src/types.rs +++ b/arbitrator/arbutil/src/types.rs @@ -84,6 +84,32 @@ impl From for Bytes32 { } } +impl FromStr for Bytes32 { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + // Remove the "0x" prefix if present + let s = s.strip_prefix("0x").unwrap_or(s); + + // Pad with leading zeros if the string is shorter than 64 characters (32 bytes) + let padded = format!("{:0>64}", s); + + // Decode the hex string using the hex crate + let decoded_bytes = hex::decode(padded).map_err(|_| "Invalid hex string")?; + + // Ensure the decoded bytes is exactly 32 bytes + if decoded_bytes.len() != 32 { + return Err("Hex string too long for Bytes32"); + } + + // Create a 32-byte array and fill it with the decoded bytes. + let mut b = [0u8; 32]; + b.copy_from_slice(&decoded_bytes); + + Ok(Bytes32(b)) + } +} +/* impl FromStr for Bytes32 { type Err = hex::FromHexError; @@ -98,6 +124,7 @@ impl FromStr for Bytes32 { Ok(Self(b)) } } +*/ impl TryFrom<&[u8]> for Bytes32 { type Error = std::array::TryFromSliceError; @@ -265,3 +292,77 @@ impl From for Bytes20 { <[u8; 20]>::from(x).into() } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_bytes32() { + let b = Bytes32::from(0x12345678u32); + let expected = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x12, 0x34, 0x56, 0x78, + ]; + assert_eq!(b, Bytes32(expected)); + } + + #[test] + fn test_from_str_short() { + // Short hex string + let b = Bytes32::from_str("0x12345678").unwrap(); + let expected = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x12, 0x34, 0x56, 0x78, + ]; + assert_eq!(b, Bytes32(expected)); + } + + #[test] + fn test_from_str_very_short() { + // Short hex string + let b = Bytes32::from_str("0x1").unwrap(); + let expected = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x1, + ]; + assert_eq!(b, Bytes32(expected)); + } + + #[test] + fn test_from_str_no_prefix() { + // Short hex string + let b = Bytes32::from_str("12345678").unwrap(); + let expected = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x12, 0x34, 0x56, 0x78, + ]; + assert_eq!(b, Bytes32(expected)); + } + + #[test] + fn test_from_str_full() { + // Full-length hex string + let b = + Bytes32::from_str("0x0000000000000000000000000000000000000000000000000000000012345678") + .unwrap(); + let expected = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x12, 0x34, 0x56, 0x78, + ]; + assert_eq!(b, Bytes32(expected)); + } + + #[test] + fn test_from_str_invalid_non_hex() { + let s = "0x123g5678"; // Invalid character 'g' + assert!(Bytes32::from_str(s).is_err()); + } + + #[test] + fn test_from_str_too_big() { + let s = + "0123456789ABCDEF0123456789ABCDEF01234567890123456789ABCDEF01234567890123456789ABCDEF0"; // 65 characters + assert!(Bytes32::from_str(s).is_err()); + } +} diff --git a/arbitrator/prover/src/prepare.rs b/arbitrator/prover/src/prepare.rs index ecfb517735..a485267f39 100644 --- a/arbitrator/prover/src/prepare.rs +++ b/arbitrator/prover/src/prepare.rs @@ -42,7 +42,6 @@ pub fn prepare_machine(preimages: PathBuf, machines: PathBuf) -> eyre::Result Date: Wed, 18 Sep 2024 18:47:30 +0200 Subject: [PATCH 067/101] Remove commented out implementation. --- arbitrator/arbutil/src/types.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/arbitrator/arbutil/src/types.rs b/arbitrator/arbutil/src/types.rs index e92d4dfbc5..722a89b81e 100644 --- a/arbitrator/arbutil/src/types.rs +++ b/arbitrator/arbutil/src/types.rs @@ -109,22 +109,6 @@ impl FromStr for Bytes32 { Ok(Bytes32(b)) } } -/* -impl FromStr for Bytes32 { - type Err = hex::FromHexError; - - fn from_str(s: &str) -> Result { - let trimmed = match s.strip_prefix("0x") { - Some(t) => t, - None => s, - }; - let bytes = hex::decode(trimmed)?; - let mut b = [0u8; 32]; - b.copy_from_slice(&bytes); - Ok(Self(b)) - } -} -*/ impl TryFrom<&[u8]> for Bytes32 { type Error = std::array::TryFromSliceError; From 109098e7b1d98391c9bcaede903434ed1a7f07e8 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 18 Sep 2024 12:57:26 -0600 Subject: [PATCH 068/101] init-reorg: fix logic --- cmd/nitro/nitro.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index a13a92fdc1..26301a4e27 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -1006,14 +1006,15 @@ func initReorg(initConfig conf.InitConfig, chainConfig *params.ChainConfig, inbo return nil } // Reorg out the batch containing the next message - var missing bool + var found bool var err error - batchCount, missing, err = inboxTracker.FindInboxBatchContainingMessage(messageIndex + 1) + batchCount, found, err = inboxTracker.FindInboxBatchContainingMessage(messageIndex + 1) if err != nil { return err } - if missing { - return fmt.Errorf("cannot reorg to unknown message index %v", messageIndex) + if !found { + log.Warn("init-reorg: no need to reorg, because message ahead of chain", "messageIndex", messageIndex) + return nil } } return inboxTracker.ReorgBatchesTo(batchCount) From 2cdce538f45244c29dc409e4bac56f42dde10921 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 18 Sep 2024 14:02:39 -0500 Subject: [PATCH 069/101] Improve stability of getNodeCreationBlock for L3s --- staker/rollup_watcher.go | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/staker/rollup_watcher.go b/staker/rollup_watcher.go index 5ef28a49dc..cd7e5d059d 100644 --- a/staker/rollup_watcher.go +++ b/staker/rollup_watcher.go @@ -4,16 +4,19 @@ package staker import ( + "bytes" "context" "encoding/binary" "errors" "fmt" "math/big" + "strings" "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/util/headerreader" @@ -51,6 +54,7 @@ type RollupWatcher struct { client arbutil.L1Interface baseCallOpts bind.CallOpts unSupportedL3Method atomic.Bool + supportedL3Method atomic.Bool } func NewRollupWatcher(address common.Address, client arbutil.L1Interface, callOpts bind.CallOpts) (*RollupWatcher, error) { @@ -73,15 +77,40 @@ func (r *RollupWatcher) getCallOpts(ctx context.Context) *bind.CallOpts { return &opts } +const noNodeErr string = "NO_NODE" + +func looksLikeNoNodeError(err error) bool { + if err == nil { + return false + } + if strings.Contains(err.Error(), noNodeErr) { + return true + } + errWithData, ok := err.(rpc.DataError) + if !ok { + return false + } + dataString, ok := errWithData.ErrorData().(string) + if !ok { + return false + } + data := common.FromHex(dataString) + return bytes.Contains(data, []byte(noNodeErr)) +} + func (r *RollupWatcher) getNodeCreationBlock(ctx context.Context, nodeNum uint64) (*big.Int, error) { callOpts := r.getCallOpts(ctx) if !r.unSupportedL3Method.Load() { createdAtBlock, err := r.GetNodeCreationBlockForLogLookup(callOpts, nodeNum) if err == nil { + r.supportedL3Method.Store(true) return createdAtBlock, nil } - log.Trace("failed to call getNodeCreationBlockForLogLookup, falling back on node CreatedAtBlock field", "err", err) - if headerreader.ExecutionRevertedRegexp.MatchString(err.Error()) { + if headerreader.ExecutionRevertedRegexp.MatchString(err.Error()) && !looksLikeNoNodeError(err) { + if r.supportedL3Method.Load() { + return nil, fmt.Errorf("getNodeCreationBlockForLogLookup failed despite previously succeeding: %w", err) + } + log.Trace("failed to call getNodeCreationBlockForLogLookup, falling back on node CreatedAtBlock field", "err", err) r.unSupportedL3Method.Store(true) } else { return nil, err From 32a601ccc8ab957c285ac573b03cea8b0b6c5acc Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 18 Sep 2024 14:05:07 -0500 Subject: [PATCH 070/101] Fix linter --- staker/rollup_watcher.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staker/rollup_watcher.go b/staker/rollup_watcher.go index cd7e5d059d..3219566549 100644 --- a/staker/rollup_watcher.go +++ b/staker/rollup_watcher.go @@ -86,7 +86,8 @@ func looksLikeNoNodeError(err error) bool { if strings.Contains(err.Error(), noNodeErr) { return true } - errWithData, ok := err.(rpc.DataError) + var errWithData rpc.DataError + ok := errors.As(err, &errWithData) if !ok { return false } From 2427b619a47d8c770a100e58eabbdb3222128023 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Mon, 23 Sep 2024 16:48:59 +0530 Subject: [PATCH 071/101] Sort storage_flush_cache --- arbos/util/storage_cache.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arbos/util/storage_cache.go b/arbos/util/storage_cache.go index bf05a5824d..dfbdc0892b 100644 --- a/arbos/util/storage_cache.go +++ b/arbos/util/storage_cache.go @@ -4,7 +4,9 @@ package util import ( + "bytes" "github.com/ethereum/go-ethereum/common" + "slices" ) type storageCacheEntry struct { @@ -67,6 +69,10 @@ func (s *storageCache) Flush() []storageCacheStores { }) } } + sortFunc := func(a, b storageCacheStores) int { + return bytes.Compare(a.Key.Bytes(), b.Key.Bytes()) + } + slices.SortFunc(stores, sortFunc) return stores } From dc9a109c2e5e97c9ae292f6eb0aa3aa1b1b72c1d Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Mon, 23 Sep 2024 16:59:01 +0530 Subject: [PATCH 072/101] Only run hash state scheme in race CI --- .github/workflows/ci.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index acd6295b7c..4619e8c2fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,19 +166,6 @@ jobs: fi done - - name: run tests with race detection and path state scheme - if: matrix.test-mode == 'race' - env: - TEST_STATE_SCHEME: path - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done - - name: run tests with race detection and hash state scheme if: matrix.test-mode == 'race' env: From 660e3d9a00becfc150082615a2ae7b0ac500b9f0 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 18:39:41 +0530 Subject: [PATCH 073/101] Fix soft-float cache --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4619e8c2fe..c7d7427c63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: ~/.cargo/git/ arbitrator/target/ arbitrator/wasm-libraries/target/ - arbitrator/wasm-libraries/soft-float/SoftFloat/build + arbitrator/wasm-libraries/soft-float/ target/etc/initial-machine-cache/ key: ${{ runner.os }}-cargo-${{ steps.install-rust.outputs.rustc_hash }}-min-${{ hashFiles('arbitrator/Cargo.lock') }}-${{ matrix.test-mode }} restore-keys: ${{ runner.os }}-cargo-${{ steps.install-rust.outputs.rustc_hash }}- From 8fab4766214a0acd139524d6769bf287e02973b8 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 18:51:41 +0530 Subject: [PATCH 074/101] skip test for testing --- .github/workflows/ci.yml | 150 +++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7d7427c63..4808d0403e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,81 +140,81 @@ jobs: echo "GOGC=80" >> "$GITHUB_ENV" echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> "$GITHUB_ENV" - - name: run tests without race detection and path state scheme - if: matrix.test-mode == 'defaults' - env: - TEST_STATE_SCHEME: path - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -timeout 20m -tags=cionly > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done - - - name: run tests without race detection and hash state scheme - if: matrix.test-mode == 'defaults' - env: - TEST_STATE_SCHEME: hash - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 20m -tags=cionly; then - exit 1 - fi - done - - - name: run tests with race detection and hash state scheme - if: matrix.test-mode == 'race' - env: - TEST_STATE_SCHEME: hash - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m; then - exit 1 - fi - done - - - name: run redis tests - if: matrix.test-mode == 'defaults' - run: TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... - - - name: run challenge tests - if: matrix.test-mode == 'challenge' - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=challengetest -run=TestChallenge > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done - - - name: run stylus tests - if: matrix.test-mode == 'stylus' - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramArbitrator" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done - - - name: run long stylus tests - if: matrix.test-mode == 'long' - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramLong" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done +# - name: run tests without race detection and path state scheme +# if: matrix.test-mode == 'defaults' +# env: +# TEST_STATE_SCHEME: path +# run: | +# packages=`go list ./...` +# for package in $packages; do +# echo running tests for $package +# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -timeout 20m -tags=cionly > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then +# exit 1 +# fi +# done + +# - name: run tests without race detection and hash state scheme +# if: matrix.test-mode == 'defaults' +# env: +# TEST_STATE_SCHEME: hash +# run: | +# packages=`go list ./...` +# for package in $packages; do +# echo running tests for $package +# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 20m -tags=cionly; then +# exit 1 +# fi +# done + +# - name: run tests with race detection and hash state scheme +# if: matrix.test-mode == 'race' +# env: +# TEST_STATE_SCHEME: hash +# run: | +# packages=`go list ./...` +# for package in $packages; do +# echo running tests for $package +# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m; then +# exit 1 +# fi +# done + +# - name: run redis tests +# if: matrix.test-mode == 'defaults' +# run: TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... + +# - name: run challenge tests +# if: matrix.test-mode == 'challenge' +# run: | +# packages=`go list ./...` +# for package in $packages; do +# echo running tests for $package +# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=challengetest -run=TestChallenge > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then +# exit 1 +# fi +# done + +# - name: run stylus tests +# if: matrix.test-mode == 'stylus' +# run: | +# packages=`go list ./...` +# for package in $packages; do +# echo running tests for $package +# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramArbitrator" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then +# exit 1 +# fi +# done + +# - name: run long stylus tests +# if: matrix.test-mode == 'long' +# run: | +# packages=`go list ./...` +# for package in $packages; do +# echo running tests for $package +# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramLong" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then +# exit 1 +# fi +# done - name: Archive detailed run log uses: actions/upload-artifact@v3 From c0043e4d052df650b47f7f41b008b104a314f555 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 19:21:24 +0530 Subject: [PATCH 075/101] Trigger Build From 93c255c8f5f66034e782b4877c6775a8ebead3c8 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 19:34:12 +0530 Subject: [PATCH 076/101] Trigger Build From 009fa852ac5bf8597c1ef36a4f01943ffc871bf6 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 20:03:48 +0530 Subject: [PATCH 077/101] fix rust cache --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4808d0403e..453bd00617 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,8 +87,7 @@ jobs: uses: actions/cache@v3 with: path: | - ~/.cargo/registry/ - ~/.cargo/git/ + ~/.cargo/ arbitrator/target/ arbitrator/wasm-libraries/target/ arbitrator/wasm-libraries/soft-float/ From 556b2dfb7785479ca018de57b493ff335cdb5208 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 20:14:43 +0530 Subject: [PATCH 078/101] fix rust cache --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 453bd00617..ef9ea9e721 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,6 +92,7 @@ jobs: arbitrator/wasm-libraries/target/ arbitrator/wasm-libraries/soft-float/ target/etc/initial-machine-cache/ + /home/runner/.rustup/toolchains/ key: ${{ runner.os }}-cargo-${{ steps.install-rust.outputs.rustc_hash }}-min-${{ hashFiles('arbitrator/Cargo.lock') }}-${{ matrix.test-mode }} restore-keys: ${{ runner.os }}-cargo-${{ steps.install-rust.outputs.rustc_hash }}- From eb9af0d7f4e30c24d887e481d576986d03d8730a Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 20:32:17 +0530 Subject: [PATCH 079/101] Trigger Build From 67a66f50bce25619703ea2a93e7c499694dd6324 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 20:59:46 +0530 Subject: [PATCH 080/101] add back test --- .github/workflows/ci.yml | 150 +++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef9ea9e721..b439fe4aec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,81 +140,81 @@ jobs: echo "GOGC=80" >> "$GITHUB_ENV" echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> "$GITHUB_ENV" -# - name: run tests without race detection and path state scheme -# if: matrix.test-mode == 'defaults' -# env: -# TEST_STATE_SCHEME: path -# run: | -# packages=`go list ./...` -# for package in $packages; do -# echo running tests for $package -# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -timeout 20m -tags=cionly > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then -# exit 1 -# fi -# done - -# - name: run tests without race detection and hash state scheme -# if: matrix.test-mode == 'defaults' -# env: -# TEST_STATE_SCHEME: hash -# run: | -# packages=`go list ./...` -# for package in $packages; do -# echo running tests for $package -# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 20m -tags=cionly; then -# exit 1 -# fi -# done - -# - name: run tests with race detection and hash state scheme -# if: matrix.test-mode == 'race' -# env: -# TEST_STATE_SCHEME: hash -# run: | -# packages=`go list ./...` -# for package in $packages; do -# echo running tests for $package -# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m; then -# exit 1 -# fi -# done - -# - name: run redis tests -# if: matrix.test-mode == 'defaults' -# run: TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... - -# - name: run challenge tests -# if: matrix.test-mode == 'challenge' -# run: | -# packages=`go list ./...` -# for package in $packages; do -# echo running tests for $package -# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=challengetest -run=TestChallenge > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then -# exit 1 -# fi -# done - -# - name: run stylus tests -# if: matrix.test-mode == 'stylus' -# run: | -# packages=`go list ./...` -# for package in $packages; do -# echo running tests for $package -# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramArbitrator" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then -# exit 1 -# fi -# done - -# - name: run long stylus tests -# if: matrix.test-mode == 'long' -# run: | -# packages=`go list ./...` -# for package in $packages; do -# echo running tests for $package -# if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramLong" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then -# exit 1 -# fi -# done + - name: run tests without race detection and path state scheme + if: matrix.test-mode == 'defaults' + env: + TEST_STATE_SCHEME: path + run: | + packages=`go list ./...` + for package in $packages; do + echo running tests for $package + if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -timeout 20m -tags=cionly > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then + exit 1 + fi + done + + - name: run tests without race detection and hash state scheme + if: matrix.test-mode == 'defaults' + env: + TEST_STATE_SCHEME: hash + run: | + packages=`go list ./...` + for package in $packages; do + echo running tests for $package + if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 20m -tags=cionly; then + exit 1 + fi + done + + - name: run tests with race detection and hash state scheme + if: matrix.test-mode == 'race' + env: + TEST_STATE_SCHEME: hash + run: | + packages=`go list ./...` + for package in $packages; do + echo running tests for $package + if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m; then + exit 1 + fi + done + + - name: run redis tests + if: matrix.test-mode == 'defaults' + run: TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... + + - name: run challenge tests + if: matrix.test-mode == 'challenge' + run: | + packages=`go list ./...` + for package in $packages; do + echo running tests for $package + if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=challengetest -run=TestChallenge > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then + exit 1 + fi + done + + - name: run stylus tests + if: matrix.test-mode == 'stylus' + run: | + packages=`go list ./...` + for package in $packages; do + echo running tests for $package + if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramArbitrator" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then + exit 1 + fi + done + + - name: run long stylus tests + if: matrix.test-mode == 'long' + run: | + packages=`go list ./...` + for package in $packages; do + echo running tests for $package + if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramLong" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then + exit 1 + fi + done - name: Archive detailed run log uses: actions/upload-artifact@v3 From 3fb2b1914cdec259ab4127490de380ac50ced3ff Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 24 Sep 2024 21:29:59 +0530 Subject: [PATCH 081/101] Trigger Build From 52cac0574f46144f910b4ec0b563e0af5927bcfd Mon Sep 17 00:00:00 2001 From: Joshua Colvin Date: Tue, 24 Sep 2024 15:10:48 -0700 Subject: [PATCH 082/101] Fix typo in license --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index ea9a53da75..25768b3010 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -22,7 +22,7 @@ Additional Use Grant: You may use the Licensed Work in a production environment Expansion Program Term of Use](https://docs.arbitrum.foundation/assets/files/Arbitrum%20Expansion%20Program%20Jan182024-4f08b0c2cb476a55dc153380fa3e64b0.pdf). For purposes of this Additional Use Grant, the "Covered Arbitrum Chains" are (a) Arbitrum One (chainid:42161), Arbitrum Nova (chainid:42170), - rbitrum Rinkeby testnet/Rinkarby (chainid:421611),Arbitrum Nitro + Arbitrum Rinkeby testnet/Rinkarby (chainid:421611),Arbitrum Nitro Goerli testnet (chainid:421613), and Arbitrum Sepolia Testnet (chainid:421614); (b) any future blockchains authorized to be designated as Covered Arbitrum Chains by the decentralized autonomous From 6765ba608286c5c6473c3c0b7cb3c85759befb93 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Wed, 25 Sep 2024 15:39:26 -0300 Subject: [PATCH 083/101] Remove brotli build dir in make clean --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 0a71d64f12..c3cf1a5144 100644 --- a/Makefile +++ b/Makefile @@ -283,6 +283,7 @@ clean: rm -f arbitrator/wasm-libraries/soft-float/SoftFloat/build/Wasm-Clang/*.a rm -f arbitrator/wasm-libraries/forward/*.wat rm -rf arbitrator/stylus/tests/*/target/ arbitrator/stylus/tests/*/*.wasm + rm -rf brotli/buildfiles @rm -rf contracts/build contracts/cache solgen/go/ @rm -f .make/* From 12253bd6f4c9308707c95175188714f74ca4f3ae Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Wed, 25 Sep 2024 17:30:01 -0300 Subject: [PATCH 084/101] Fix CaptureHostIO when slices are bigger than 2^16 Support slices bigger than 2^16 when capturing a HostIO for tracing. This could be reproduced with the test case added in the commit. --- arbitrator/arbutil/src/evm/req.rs | 7 +++--- arbitrator/stylus/tests/write-result-len.wat | 24 ++++++++++++++++++++ arbos/programs/api.go | 6 ++--- system_tests/stylus_trace_test.go | 15 ++++++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 arbitrator/stylus/tests/write-result-len.wat diff --git a/arbitrator/arbutil/src/evm/req.rs b/arbitrator/arbutil/src/evm/req.rs index 1cfceda6b7..0304f2d378 100644 --- a/arbitrator/arbutil/src/evm/req.rs +++ b/arbitrator/arbutil/src/evm/req.rs @@ -298,9 +298,10 @@ impl> EvmApi for EvmApiRequestor { let mut request = Vec::with_capacity(2 * 8 + 3 * 2 + name.len() + args.len() + outs.len()); request.extend(start_ink.to_be_bytes()); request.extend(end_ink.to_be_bytes()); - request.extend((name.len() as u16).to_be_bytes()); - request.extend((args.len() as u16).to_be_bytes()); - request.extend((outs.len() as u16).to_be_bytes()); + // u32 is enough to represent the slices lengths because the WASM environment runs in 32 bits. + request.extend((name.len() as u32).to_be_bytes()); + request.extend((args.len() as u32).to_be_bytes()); + request.extend((outs.len() as u32).to_be_bytes()); request.extend(name.as_bytes()); request.extend(args); request.extend(outs); diff --git a/arbitrator/stylus/tests/write-result-len.wat b/arbitrator/stylus/tests/write-result-len.wat new file mode 100644 index 0000000000..4c9ad35087 --- /dev/null +++ b/arbitrator/stylus/tests/write-result-len.wat @@ -0,0 +1,24 @@ +;; Copyright 2024, Offchain Labs, Inc. +;; For license information, see https://github.com/nitro/blob/master/LICENSE + +(module + (import "vm_hooks" "read_args" (func $read_args (param i32))) + (import "vm_hooks" "write_result" (func $write_result (param i32 i32))) + (memory (export "memory") 2 2) + (func $main (export "user_entrypoint") (param $args_len i32) (result i32) + (local $len i32) + + ;; write args to 0x0 + (call $read_args (i32.const 0)) + + ;; treat first 4 bytes as size to write + (i32.load (i32.const 0)) + local.set $len + + ;; call write + (call $write_result (i32.const 0) (local.get $len)) + + ;; return success + i32.const 0 + ) +) diff --git a/arbos/programs/api.go b/arbos/programs/api.go index 504289322f..3e59031b2d 100644 --- a/arbos/programs/api.go +++ b/arbos/programs/api.go @@ -400,9 +400,9 @@ func newApiClosures( } startInk := takeU64() endInk := takeU64() - nameLen := takeU16() - argsLen := takeU16() - outsLen := takeU16() + nameLen := takeU32() + argsLen := takeU32() + outsLen := takeU32() name := string(takeFixed(int(nameLen))) args := takeFixed(int(argsLen)) outs := takeFixed(int(outsLen)) diff --git a/system_tests/stylus_trace_test.go b/system_tests/stylus_trace_test.go index 5c4463d9f7..52039df460 100644 --- a/system_tests/stylus_trace_test.go +++ b/system_tests/stylus_trace_test.go @@ -6,6 +6,7 @@ package arbtest import ( "bytes" "encoding/binary" + "math" "math/big" "testing" @@ -478,3 +479,17 @@ func TestStylusOpcodeTraceEquivalence(t *testing.T) { checkOpcode(t, wasmResult, 12, vm.RETURN, offset, returnLen) checkOpcode(t, evmResult, 5078, vm.RETURN, offset, returnLen) } + +func TestStylusHugeWriteResultTrace(t *testing.T) { + const jit = false + builder, auth, cleanup := setupProgramTest(t, jit) + ctx := builder.ctx + l2client := builder.L2.Client + defer cleanup() + + program := deployWasm(t, ctx, auth, l2client, watFile("write-result-len")) + const returnLen = math.MaxUint16 + 1 + args := binary.LittleEndian.AppendUint32(nil, returnLen) + result := sendAndTraceTransaction(t, builder, program, nil, args) + checkOpcode(t, result, 3, vm.RETURN, nil, intToBe32(returnLen)) +} From 61554ac54681d0c4560829c03e992594fd02a1b4 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Mon, 26 Aug 2024 12:07:57 -0300 Subject: [PATCH 085/101] Moves package iteration from ci.yml to bash script --- .github/workflows/ci.yml | 54 +++----------------- .github/workflows/gotestsum.sh | 92 ++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 48 deletions(-) create mode 100755 .github/workflows/gotestsum.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b439fe4aec..e190b62809 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -144,40 +144,19 @@ jobs: if: matrix.test-mode == 'defaults' env: TEST_STATE_SCHEME: path - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -timeout 20m -tags=cionly > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags cionly --timeout 20m --cover --write-full-log - name: run tests without race detection and hash state scheme if: matrix.test-mode == 'defaults' env: TEST_STATE_SCHEME: hash - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 20m -tags=cionly; then - exit 1 - fi - done + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags cionly --timeout 20m - name: run tests with race detection and hash state scheme if: matrix.test-mode == 'race' env: TEST_STATE_SCHEME: hash - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m; then - exit 1 - fi - done + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --race --timeout 30m - name: run redis tests if: matrix.test-mode == 'defaults' @@ -185,36 +164,15 @@ jobs: - name: run challenge tests if: matrix.test-mode == 'challenge' - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=challengetest -run=TestChallenge > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags challengetest --run TestChallenge --cover --write-full-log - name: run stylus tests if: matrix.test-mode == 'stylus' - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramArbitrator" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags stylustest --run TestProgramArbitrator --timeout 60m --cover --write-full-log - name: run long stylus tests if: matrix.test-mode == 'long' - run: | - packages=`go list ./...` - for package in $packages; do - echo running tests for $package - if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -timeout 60m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -tags=stylustest -run="TestProgramLong" > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then - exit 1 - fi - done + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags stylustest --run TestProgramLong --timeout 60m --cover --write-full-log - name: Archive detailed run log uses: actions/upload-artifact@v3 diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh new file mode 100755 index 0000000000..3c89538507 --- /dev/null +++ b/.github/workflows/gotestsum.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +check_missing_value() { + if [[ $1 -eq 0 || $2 == -* ]]; then + echo "missing $3 argument value" + exit 1 + fi +} + +timeout="" +tags="" +run="" +race=false +cover=false +write_full_log=false +while [[ $# -gt 0 ]]; do + case $1 in + --timeout) + shift + check_missing_value $# "$1" "--timeout" + timeout=$1 + shift + ;; + --tags) + shift + check_missing_value $# "$1" "--tags" + tags=$1 + shift + ;; + --run) + shift + check_missing_value $# "$1" "--run" + run=$1 + shift + ;; + --race) + race=true + shift + ;; + --cover) + cover=true + shift + ;; + --write-full-log) + write_full_log=true + shift + ;; + *) + echo "Invalid argument: $1" + exit 1 + ;; + esac +done + +packages=$(go list ./...) +for package in $packages; do + cmd="stdbuf -oL gotestsum --format short-verbose --packages=\"$package\" --rerun-fails=2 --no-color=false --" + + if [ "$timeout" != "" ]; then + cmd="$cmd -timeout $timeout" + else + cmd="$cmd -timeout 20m" + fi + + if [ "$tags" != "" ]; then + cmd="$cmd -tags=$tags" + fi + + if [ "$run" != "" ]; then + cmd="$cmd -run=$run" + fi + + if [ "$race" == true ]; then + cmd="$cmd -race" + fi + + if [ "$cover" == true ]; then + cmd="$cmd -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/..." + fi + + if [ "$write_full_log" == true ]; then + cmd="$cmd > >(stdbuf -oL tee -a full.log | grep -vE \"INFO|seal\")" + fi + + echo "" + echo running tests for "$package" + echo "$cmd" + + if ! eval "$cmd"; then + exit 1 + fi +done From a77653ed3412da048240cc3c88e60eed2f2364aa Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Thu, 29 Aug 2024 10:20:00 -0300 Subject: [PATCH 086/101] Removes default timeout in gotestsum.sh --- .github/workflows/gotestsum.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh index 3c89538507..5da16cea24 100755 --- a/.github/workflows/gotestsum.sh +++ b/.github/workflows/gotestsum.sh @@ -58,8 +58,6 @@ for package in $packages; do if [ "$timeout" != "" ]; then cmd="$cmd -timeout $timeout" - else - cmd="$cmd -timeout 20m" fi if [ "$tags" != "" ]; then From 3c38c4098bbf4d95a70db0c853226eb4baf214c4 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Mon, 23 Sep 2024 16:45:59 -0300 Subject: [PATCH 087/101] Removes --write-full-log from .github/workflows/gotestsum.sh --- .github/workflows/ci.yml | 22 +++++++++++++++------- .github/workflows/gotestsum.sh | 4 +--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e190b62809..5794580f03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -144,35 +144,43 @@ jobs: if: matrix.test-mode == 'defaults' env: TEST_STATE_SCHEME: path - run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags cionly --timeout 20m --cover --write-full-log + run: | + echo "Running tests with Path Scheme" >> full.log + ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags cionly --timeout 20m --cover - name: run tests without race detection and hash state scheme if: matrix.test-mode == 'defaults' env: TEST_STATE_SCHEME: hash - run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags cionly --timeout 20m + run: | + echo "Running tests with Hash Scheme" >> full.log + ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags cionly --timeout 20m - name: run tests with race detection and hash state scheme if: matrix.test-mode == 'race' env: TEST_STATE_SCHEME: hash - run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --race --timeout 30m + run: | + echo "Running tests with Hash Scheme" >> full.log + ${{ github.workspace }}/.github/workflows/gotestsum.sh --race --timeout 30m - name: run redis tests if: matrix.test-mode == 'defaults' - run: TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... + run: | + echo "Running redis tests" >> full.log + TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... - name: run challenge tests if: matrix.test-mode == 'challenge' - run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags challengetest --run TestChallenge --cover --write-full-log + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags challengetest --run TestChallenge --cover - name: run stylus tests if: matrix.test-mode == 'stylus' - run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags stylustest --run TestProgramArbitrator --timeout 60m --cover --write-full-log + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags stylustest --run TestProgramArbitrator --timeout 60m --cover - name: run long stylus tests if: matrix.test-mode == 'long' - run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags stylustest --run TestProgramLong --timeout 60m --cover --write-full-log + run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags stylustest --run TestProgramLong --timeout 60m --cover - name: Archive detailed run log uses: actions/upload-artifact@v3 diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh index 5da16cea24..13cfc62fa9 100755 --- a/.github/workflows/gotestsum.sh +++ b/.github/workflows/gotestsum.sh @@ -76,9 +76,7 @@ for package in $packages; do cmd="$cmd -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/..." fi - if [ "$write_full_log" == true ]; then - cmd="$cmd > >(stdbuf -oL tee -a full.log | grep -vE \"INFO|seal\")" - fi + cmd="$cmd > >(stdbuf -oL tee -a full.log | grep -vE \"INFO|seal\")" echo "" echo running tests for "$package" From 73da786ab496fdb06a155af15840931861084c07 Mon Sep 17 00:00:00 2001 From: Diego Ximenes Date: Mon, 23 Sep 2024 16:48:47 -0300 Subject: [PATCH 088/101] Removes --write-full-log flag from .github/workflows/gotestsum.sh --- .github/workflows/gotestsum.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh index 13cfc62fa9..ed631847b7 100755 --- a/.github/workflows/gotestsum.sh +++ b/.github/workflows/gotestsum.sh @@ -12,7 +12,6 @@ tags="" run="" race=false cover=false -write_full_log=false while [[ $# -gt 0 ]]; do case $1 in --timeout) @@ -41,10 +40,6 @@ while [[ $# -gt 0 ]]; do cover=true shift ;; - --write-full-log) - write_full_log=true - shift - ;; *) echo "Invalid argument: $1" exit 1 From b30eb33252b68d4e6c4cd433fc12098c4cb36b90 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Fri, 27 Sep 2024 18:31:24 +0530 Subject: [PATCH 089/101] Changes based on PR comments --- arbos/util/storage_cache.go | 3 +-- arbos/util/storage_cache_test.go | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arbos/util/storage_cache.go b/arbos/util/storage_cache.go index dfbdc0892b..9573d1ffc7 100644 --- a/arbos/util/storage_cache.go +++ b/arbos/util/storage_cache.go @@ -4,7 +4,6 @@ package util import ( - "bytes" "github.com/ethereum/go-ethereum/common" "slices" ) @@ -70,7 +69,7 @@ func (s *storageCache) Flush() []storageCacheStores { } } sortFunc := func(a, b storageCacheStores) int { - return bytes.Compare(a.Key.Bytes(), b.Key.Bytes()) + return a.Key.Cmp(b.Key) } slices.SortFunc(stores, sortFunc) return stores diff --git a/arbos/util/storage_cache_test.go b/arbos/util/storage_cache_test.go index 1cc4ea14ec..9fd452851d 100644 --- a/arbos/util/storage_cache_test.go +++ b/arbos/util/storage_cache_test.go @@ -4,7 +4,6 @@ package util import ( - "bytes" "slices" "testing" @@ -76,7 +75,7 @@ func TestStorageCache(t *testing.T) { {Key: keys[2], Value: values[2]}, } sortFunc := func(a, b storageCacheStores) int { - return bytes.Compare(a.Key.Bytes(), b.Key.Bytes()) + return a.Key.Cmp(b.Key) } slices.SortFunc(stores, sortFunc) slices.SortFunc(expected, sortFunc) From 91a974f18b98eb943946475496f06c71fd9ce71d Mon Sep 17 00:00:00 2001 From: xiaohuo Date: Fri, 27 Sep 2024 01:09:16 +0800 Subject: [PATCH 090/101] chore: remove unused variable --- arbnode/transaction_streamer.go | 4 ++-- system_tests/eth_sync_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arbnode/transaction_streamer.go b/arbnode/transaction_streamer.go index 24a0564b97..38b1c003db 100644 --- a/arbnode/transaction_streamer.go +++ b/arbnode/transaction_streamer.go @@ -1140,7 +1140,7 @@ func (s *TransactionStreamer) storeResult( // exposed for testing // return value: true if should be called again immediately -func (s *TransactionStreamer) ExecuteNextMsg(ctx context.Context, exec execution.ExecutionSequencer) bool { +func (s *TransactionStreamer) ExecuteNextMsg(ctx context.Context) bool { if ctx.Err() != nil { return false } @@ -1212,7 +1212,7 @@ func (s *TransactionStreamer) ExecuteNextMsg(ctx context.Context, exec execution } func (s *TransactionStreamer) executeMessages(ctx context.Context, ignored struct{}) time.Duration { - if s.ExecuteNextMsg(ctx, s.exec) { + if s.ExecuteNextMsg(ctx) { return 0 } return s.config().ExecuteMessageLoopDelay diff --git a/system_tests/eth_sync_test.go b/system_tests/eth_sync_test.go index 1f07f7c45f..ce9994fb1e 100644 --- a/system_tests/eth_sync_test.go +++ b/system_tests/eth_sync_test.go @@ -71,7 +71,7 @@ func TestEthSyncing(t *testing.T) { if progress == nil { Fatal(t, "eth_syncing returned nil but shouldn't have") } - for testClientB.ConsensusNode.TxStreamer.ExecuteNextMsg(ctx, testClientB.ExecNode) { + for testClientB.ConsensusNode.TxStreamer.ExecuteNextMsg(ctx) { } progress, err = testClientB.Client.SyncProgress(ctx) Require(t, err) From c550c7ed5bc17b85b181e7fb62a7b59d8315590b Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Sat, 28 Sep 2024 16:50:59 +0300 Subject: [PATCH 091/101] Switch to funcional options for the inputs.Writer This change also saves the stack argument passed to the NewStatelessBlockValidator function to a member of StatelessBlockValidator so that the BlockValidator can use the `stack.InstanceDir()` method to set a reasonable base directory for storing validation inputs as json files. --- arbitrator/wasm-libraries/Cargo.lock | 122 +++++++++++++++++++++++++++ staker/block_validator.go | 6 +- staker/stateless_block_validator.go | 2 + system_tests/common_test.go | 3 +- validator/inputs/writer.go | 70 ++++++++------- validator/inputs/writer_test.go | 29 ++++--- 6 files changed, 187 insertions(+), 45 deletions(-) diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index be2bd828f3..a5a066e5c9 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -106,6 +106,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bincode" version = "1.3.3" @@ -218,6 +224,15 @@ dependencies = [ "rand_pcg", ] +[[package]] +name = "cc" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -264,6 +279,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -324,6 +345,16 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -614,6 +645,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "keccak" version = "0.1.5" @@ -651,6 +691,12 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "lru" version = "0.12.4" @@ -857,6 +903,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -1214,6 +1266,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "simdutf8" version = "0.1.4" @@ -1509,6 +1567,61 @@ dependencies = [ "wee_alloc", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + [[package]] name = "wasm-encoder" version = "0.215.0" @@ -1599,6 +1712,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" diff --git a/staker/block_validator.go b/staker/block_validator.go index 30df20a2d2..5a1f123693 100644 --- a/staker/block_validator.go +++ b/staker/block_validator.go @@ -288,11 +288,13 @@ func NewBlockValidator( fatalErr: fatalErr, prevBatchCache: make(map[uint64][]byte), } - valInputsWriter, err := inputs.NewWriter() + valInputsWriter, err := inputs.NewWriter( + inputs.WithBaseDir(ret.stack.InstanceDir()), + inputs.WithSlug("BlockValidator")) if err != nil { return nil, err } - ret.validationInputsWriter = valInputsWriter.SetSlug("BlockValidator") + ret.validationInputsWriter = valInputsWriter if !config().Dangerous.ResetBlockValidation { validated, err := ret.ReadLastValidatedInfo() if err != nil { diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index fa34842dc9..9257c5582a 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -41,6 +41,7 @@ type StatelessBlockValidator struct { streamer TransactionStreamerInterface db ethdb.Database dapReaders []daprovider.Reader + stack *node.Node } type BlockValidatorRegistrer interface { @@ -265,6 +266,7 @@ func NewStatelessBlockValidator( db: arbdb, dapReaders: dapReaders, execSpawners: executionSpawners, + stack: stack, }, nil } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index ed098351e5..d5f65de43e 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -1712,9 +1712,8 @@ func recordBlock(t *testing.T, block uint64, builder *NodeBuilder) { break } } - validationInputsWriter, err := inputs.NewWriter() + validationInputsWriter, err := inputs.NewWriter(inputs.WithSlug(t.Name())) Require(t, err) - validationInputsWriter.SetSlug(t.Name()) inputJson, err := builder.L2.ConsensusNode.StatelessBlockValidator.ValidationInputsAt(ctx, inboxPos, rawdb.TargetWavm) if err != nil { Fatal(t, "failed to get validation inputs", block, err) diff --git a/validator/inputs/writer.go b/validator/inputs/writer.go index b8160a4fa5..1fd23dbb40 100644 --- a/validator/inputs/writer.go +++ b/validator/inputs/writer.go @@ -3,6 +3,7 @@ package inputs import ( "fmt" "os" + "path/filepath" "time" "github.com/offchainlabs/nitro/validator/server_api" @@ -43,6 +44,9 @@ type Writer struct { useTimestampDir bool } +// WriterOption is a function that configures a Writer. +type WriterOption func(*Writer) + // Clock is an interface for getting the current time. type Clock interface { Now() time.Time @@ -55,73 +59,81 @@ func (realClock) Now() time.Time { } // NewWriter creates a new Writer with default settings. -func NewWriter() (*Writer, error) { +func NewWriter(options ...WriterOption) (*Writer, error) { homeDir, err := os.UserHomeDir() if err != nil { return nil, err } baseDir := fmt.Sprintf("%s/.arbitrum/validation-inputs", homeDir) - return &Writer{ + w := &Writer{ clock: realClock{}, baseDir: baseDir, slug: "", - useTimestampDir: true}, nil + useTimestampDir: true, + } + for _, o := range options { + o(w) + } + return w, nil } -// SetClockForTesting sets the clock used by the Writer. +// withTestClock configures the Writer to use the given clock. // // This is only intended for testing. -func (w *Writer) SetClockForTesting(clock Clock) *Writer { - w.clock = clock - return w +func withTestClock(clock Clock) WriterOption { + return func(w *Writer) { + w.clock = clock + } } -// SetSlug configures the Writer to use the given slug as a directory name. -func (w *Writer) SetSlug(slug string) *Writer { - w.slug = slug - return w +// WithSlug configures the Writer to use the given slug as a directory name. +func WithSlug(slug string) WriterOption { + return func(w *Writer) { + w.slug = slug + } } -// ClearSlug clears the slug configuration. +// WithoutSlug clears the slug configuration. // -// This is equivalent to calling SetSlug("") but is more readable. -func (w *Writer) ClearSlug() *Writer { - w.slug = "" - return w +// This is equivalent to the WithSlug("") option but is more readable. +func WithoutSlug() WriterOption { + return WithSlug("") } -// SetBaseDir configures the Writer to use the given base directory. -func (w *Writer) SetBaseDir(baseDir string) *Writer { - w.baseDir = baseDir - return w +// WithBaseDir configures the Writer to use the given base directory. +func WithBaseDir(baseDir string) WriterOption { + return func(w *Writer) { + w.baseDir = baseDir + } } -// SetUseTimestampDir controls the addition of a timestamp directory. -func (w *Writer) SetUseTimestampDir(useTimestampDir bool) *Writer { - w.useTimestampDir = useTimestampDir - return w +// WithTimestampDirEnabled controls the addition of a timestamp directory. +func WithTimestampDirEnabled(useTimestampDir bool) WriterOption { + return func(w *Writer) { + w.useTimestampDir = useTimestampDir + } } // Write writes the given InputJSON to a file in JSON format. -func (w *Writer) Write(inputs *server_api.InputJSON) error { +func (w *Writer) Write(json *server_api.InputJSON) error { dir := w.baseDir if w.slug != "" { - dir = fmt.Sprintf("%s/%s", dir, w.slug) + dir = filepath.Join(dir, w.slug) } if w.useTimestampDir { t := w.clock.Now() tStr := t.Format("20060102_150405") - dir = fmt.Sprintf("%s/%s", dir, tStr) + dir = filepath.Join(dir, tStr) } if err := os.MkdirAll(dir, 0700); err != nil { return err } - contents, err := inputs.Marshal() + contents, err := json.Marshal() if err != nil { return err } if err = os.WriteFile( - fmt.Sprintf("%s/block_inputs_%d.json", dir, inputs.Id), + fmt.Sprintf("%s/block_inputs_%d.json", dir, json.Id), contents, 0600); err != nil { return err } diff --git a/validator/inputs/writer_test.go b/validator/inputs/writer_test.go index 5e80b9aa3a..59cb63dae7 100644 --- a/validator/inputs/writer_test.go +++ b/validator/inputs/writer_test.go @@ -33,13 +33,14 @@ func (c fakeClock) Now() time.Time { } func TestWriting(t *testing.T) { - w, err := NewWriter() + dir := t.TempDir() + w, err := NewWriter( + withTestClock(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}), + WithBaseDir(dir), + ) if err != nil { t.Fatal(err) } - w.SetClockForTesting(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}) - dir := t.TempDir() - w.SetBaseDir(dir) err = w.Write(&server_api.InputJSON{Id: 24601}) if err != nil { t.Fatal(err) @@ -51,13 +52,15 @@ func TestWriting(t *testing.T) { } func TestWritingWithSlug(t *testing.T) { - w, err := NewWriter() + dir := t.TempDir() + w, err := NewWriter( + withTestClock(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}), + WithBaseDir(dir), + WithSlug("foo"), + ) if err != nil { t.Fatal(err) } - w.SetClockForTesting(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}) - dir := t.TempDir() - w.SetBaseDir(dir).SetSlug("foo") err = w.Write(&server_api.InputJSON{Id: 24601}) if err != nil { t.Fatal(err) @@ -69,13 +72,15 @@ func TestWritingWithSlug(t *testing.T) { } func TestWritingWithoutTimestampDir(t *testing.T) { - w, err := NewWriter() + dir := t.TempDir() + w, err := NewWriter( + withTestClock(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}), + WithBaseDir(dir), + WithTimestampDirEnabled(false), + ) if err != nil { t.Fatal(err) } - w.SetClockForTesting(fakeClock{now: time.Date(2021, 1, 2, 3, 4, 5, 0, time.UTC)}) - dir := t.TempDir() - w.SetBaseDir(dir).SetUseTimestampDir(false) err = w.Write(&server_api.InputJSON{Id: 24601}) if err != nil { t.Fatal(err) From ea47d46d7557d3d600968c46d37674381d710081 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Sat, 28 Sep 2024 16:58:05 +0300 Subject: [PATCH 092/101] Fix two last instances of system-specific paths --- validator/inputs/writer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator/inputs/writer.go b/validator/inputs/writer.go index 1fd23dbb40..a45e584f52 100644 --- a/validator/inputs/writer.go +++ b/validator/inputs/writer.go @@ -64,7 +64,7 @@ func NewWriter(options ...WriterOption) (*Writer, error) { if err != nil { return nil, err } - baseDir := fmt.Sprintf("%s/.arbitrum/validation-inputs", homeDir) + baseDir := filepath.Join(homeDir, ".arbitrum", "validation-inputs") w := &Writer{ clock: realClock{}, baseDir: baseDir, @@ -133,7 +133,7 @@ func (w *Writer) Write(json *server_api.InputJSON) error { return err } if err = os.WriteFile( - fmt.Sprintf("%s/block_inputs_%d.json", dir, json.Id), + filepath.Join(dir, fmt.Sprintf("block_inputs_%d.json", json.Id)), contents, 0600); err != nil { return err } From 827755ee0bce0eb990e332427f6943a119558c16 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 30 Sep 2024 16:24:53 -0300 Subject: [PATCH 093/101] Use Golang version 1.23 --- .github/workflows/arbitrator-ci.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- Dockerfile | 4 ++-- Makefile | 14 ++++++++++---- go.mod | 2 +- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/arbitrator-ci.yml b/.github/workflows/arbitrator-ci.yml index 392eb876c0..7829fe4086 100644 --- a/.github/workflows/arbitrator-ci.yml +++ b/.github/workflows/arbitrator-ci.yml @@ -50,7 +50,7 @@ jobs: - name: Install go uses: actions/setup-go@v4 with: - go-version: 1.21.x + go-version: 1.23.x - name: Install custom go-ethereum run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5794580f03..a944f08f40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: - name: Install go uses: actions/setup-go@v4 with: - go-version: 1.21.x + go-version: 1.23.x - name: Install wasm-ld run: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1cde8f06b9..26447947d4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -73,7 +73,7 @@ jobs: - name: Install go uses: actions/setup-go@v4 with: - go-version: 1.21.x + go-version: 1.23.x - name: Install rust stable uses: dtolnay/rust-toolchain@stable diff --git a/Dockerfile b/Dockerfile index 9138ed30ad..aba5432254 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,7 +66,7 @@ COPY --from=wasm-libs-builder /workspace/ / FROM wasm-base AS wasm-bin-builder # pinned go version -RUN curl -L https://golang.org/dl/go1.21.10.linux-`dpkg --print-architecture`.tar.gz | tar -C /usr/local -xzf - +RUN curl -L https://golang.org/dl/go1.23.1.linux-`dpkg --print-architecture`.tar.gz | tar -C /usr/local -xzf - COPY ./Makefile ./go.mod ./go.sum ./ COPY ./arbcompress ./arbcompress COPY ./arbos ./arbos @@ -220,7 +220,7 @@ RUN ./download-machine.sh consensus-v30 0xb0de9cb89e4d944ae6023a3b62276e54804c24 RUN ./download-machine.sh consensus-v31 0x260f5fa5c3176a856893642e149cf128b5a8de9f828afec8d11184415dd8dc69 RUN ./download-machine.sh consensus-v32 0x184884e1eb9fefdc158f6c8ac912bb183bf3cf83f0090317e0bc4ac5860baa39 -FROM golang:1.21.10-bookworm AS node-builder +FROM golang:1.23.1-bookworm AS node-builder WORKDIR /workspace ARG version="" ARG datetime="" diff --git a/Makefile b/Makefile index c3cf1a5144..919eb3f4bf 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,12 @@ ifneq ($(origin NITRO_MODIFIED),undefined) GOLANG_LDFLAGS += -X github.com/offchainlabs/nitro/cmd/util/confighelpers.modified=$(NITRO_MODIFIED) endif +# As of Go 1.23, the package github.com/fjl/memsize no longer works because of a restriction added +# by the Go toolchain. The Go 1.23 compiler no longer allows access to runtime symbols via +# go:linkname, which prevents memsize from accessing the Stop-the-World functionality of the Go +# runtime. To solve that we add the following compiler directive. +GOLANG_LDFLAGS += -checklinkname=0 + ifneq ($(origin GOLANG_LDFLAGS),undefined) GOLANG_PARAMS = -ldflags="-extldflags '-ldl' $(GOLANG_LDFLAGS)" endif @@ -226,17 +232,17 @@ test-go: .make/test-go .PHONY: test-go-challenge test-go-challenge: test-go-deps - gotestsum --format short-verbose --no-color=false -- -timeout 120m ./system_tests/... -run TestChallenge -tags challengetest + gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) -timeout 120m ./system_tests/... -run TestChallenge -tags challengetest @printf $(done) .PHONY: test-go-stylus test-go-stylus: test-go-deps - gotestsum --format short-verbose --no-color=false -- -timeout 120m ./system_tests/... -run TestProgramArbitrator -tags stylustest + gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) -timeout 120m ./system_tests/... -run TestProgramArbitrator -tags stylustest @printf $(done) .PHONY: test-go-redis test-go-redis: test-go-deps - TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose --no-color=false -- -p 1 -run TestRedis ./system_tests/... ./arbnode/... + TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) -p 1 -run TestRedis ./system_tests/... ./arbnode/... @printf $(done) .PHONY: test-gen-proofs @@ -541,7 +547,7 @@ contracts/test/prover/proofs/%.json: $(arbitrator_cases)/%.wasm $(prover_bin) @touch $@ .make/test-go: $(DEP_PREDICATE) $(go_source) build-node-deps test-go-deps $(ORDER_ONLY_PREDICATE) .make - gotestsum --format short-verbose --no-color=false + gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) @touch $@ .make/test-rust: $(DEP_PREDICATE) wasm-ci-build $(ORDER_ONLY_PREDICATE) .make diff --git a/go.mod b/go.mod index da49b0d8b9..e3a6f59ef9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/offchainlabs/nitro -go 1.21 +go 1.22 replace github.com/VictoriaMetrics/fastcache => ./fastcache From b5c9f52e9b20aaa46f76a222cfd1eaf8767b5bba Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 30 Sep 2024 16:46:35 -0300 Subject: [PATCH 094/101] Add -ldflags to CI gotestsum --- .github/workflows/gotestsum.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh index ed631847b7..785d8a560a 100755 --- a/.github/workflows/gotestsum.sh +++ b/.github/workflows/gotestsum.sh @@ -49,7 +49,7 @@ done packages=$(go list ./...) for package in $packages; do - cmd="stdbuf -oL gotestsum --format short-verbose --packages=\"$package\" --rerun-fails=2 --no-color=false --" + cmd="stdbuf -oL gotestsum --format short-verbose --packages=\"$package\" --rerun-fails=2 --no-color=false -- -ldflags='-checklinkname=0'" if [ "$timeout" != "" ]; then cmd="$cmd -timeout $timeout" From 2254e64fd2c52cc6f9b0840a51c0549453a52ed1 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 30 Sep 2024 17:16:31 -0300 Subject: [PATCH 095/101] Add -ldflags to Arbitrator CI --- .github/workflows/arbitrator-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/arbitrator-ci.yml b/.github/workflows/arbitrator-ci.yml index 7829fe4086..a6f478c4b3 100644 --- a/.github/workflows/arbitrator-ci.yml +++ b/.github/workflows/arbitrator-ci.yml @@ -59,7 +59,7 @@ jobs: cd go-ethereum # Enable KZG point evaluation precompile early sed -i 's#var PrecompiledContractsBerlin = map\[common.Address\]PrecompiledContract{#\0 common.BytesToAddress([]byte{0x0a}): \&kzgPointEvaluation{},#g' core/vm/contracts.go - go build -o /usr/local/bin/geth ./cmd/geth + go build -o /usr/local/bin/geth -ldflags='-checklinkname=0' ./cmd/geth - name: Setup nodejs uses: actions/setup-node@v3 From e67b66a1161aeec749065595d04c37847fd1eba4 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 30 Sep 2024 18:05:34 -0300 Subject: [PATCH 096/101] Add -ldflags to CI redis test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a944f08f40..efeee151be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,7 +168,7 @@ jobs: if: matrix.test-mode == 'defaults' run: | echo "Running redis tests" >> full.log - TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... + TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -ldflags='-checklinkname=0' -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... - name: run challenge tests if: matrix.test-mode == 'challenge' From 0b40afb6eb5ff02376cd5ea307cd02a74d42e353 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 30 Sep 2024 21:45:52 -0500 Subject: [PATCH 097/101] Upgrade getNodeCreationBlockForLogLookup log to Info --- staker/rollup_watcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staker/rollup_watcher.go b/staker/rollup_watcher.go index 3219566549..324ec23ab9 100644 --- a/staker/rollup_watcher.go +++ b/staker/rollup_watcher.go @@ -111,7 +111,7 @@ func (r *RollupWatcher) getNodeCreationBlock(ctx context.Context, nodeNum uint64 if r.supportedL3Method.Load() { return nil, fmt.Errorf("getNodeCreationBlockForLogLookup failed despite previously succeeding: %w", err) } - log.Trace("failed to call getNodeCreationBlockForLogLookup, falling back on node CreatedAtBlock field", "err", err) + log.Info("getNodeCreationBlockForLogLookup does not seem to exist, falling back on node CreatedAtBlock field", "err", err) r.unSupportedL3Method.Store(true) } else { return nil, err From 5b27cd50d49b7f9e9d050e3a76c38e48220c39ef Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 1 Oct 2024 15:19:34 -0300 Subject: [PATCH 098/101] Remove checklinkname=0 build option --- .github/workflows/arbitrator-ci.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/gotestsum.sh | 2 +- Makefile | 14 ++++---------- go.mod | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/workflows/arbitrator-ci.yml b/.github/workflows/arbitrator-ci.yml index a6f478c4b3..7829fe4086 100644 --- a/.github/workflows/arbitrator-ci.yml +++ b/.github/workflows/arbitrator-ci.yml @@ -59,7 +59,7 @@ jobs: cd go-ethereum # Enable KZG point evaluation precompile early sed -i 's#var PrecompiledContractsBerlin = map\[common.Address\]PrecompiledContract{#\0 common.BytesToAddress([]byte{0x0a}): \&kzgPointEvaluation{},#g' core/vm/contracts.go - go build -o /usr/local/bin/geth -ldflags='-checklinkname=0' ./cmd/geth + go build -o /usr/local/bin/geth ./cmd/geth - name: Setup nodejs uses: actions/setup-node@v3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efeee151be..a944f08f40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,7 +168,7 @@ jobs: if: matrix.test-mode == 'defaults' run: | echo "Running redis tests" >> full.log - TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -ldflags='-checklinkname=0' -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... + TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose -- -p 1 -run TestRedis ./arbnode/... ./system_tests/... -coverprofile=coverage-redis.txt -covermode=atomic -coverpkg=./... - name: run challenge tests if: matrix.test-mode == 'challenge' diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh index 785d8a560a..ed631847b7 100755 --- a/.github/workflows/gotestsum.sh +++ b/.github/workflows/gotestsum.sh @@ -49,7 +49,7 @@ done packages=$(go list ./...) for package in $packages; do - cmd="stdbuf -oL gotestsum --format short-verbose --packages=\"$package\" --rerun-fails=2 --no-color=false -- -ldflags='-checklinkname=0'" + cmd="stdbuf -oL gotestsum --format short-verbose --packages=\"$package\" --rerun-fails=2 --no-color=false --" if [ "$timeout" != "" ]; then cmd="$cmd -timeout $timeout" diff --git a/Makefile b/Makefile index 919eb3f4bf..c3cf1a5144 100644 --- a/Makefile +++ b/Makefile @@ -27,12 +27,6 @@ ifneq ($(origin NITRO_MODIFIED),undefined) GOLANG_LDFLAGS += -X github.com/offchainlabs/nitro/cmd/util/confighelpers.modified=$(NITRO_MODIFIED) endif -# As of Go 1.23, the package github.com/fjl/memsize no longer works because of a restriction added -# by the Go toolchain. The Go 1.23 compiler no longer allows access to runtime symbols via -# go:linkname, which prevents memsize from accessing the Stop-the-World functionality of the Go -# runtime. To solve that we add the following compiler directive. -GOLANG_LDFLAGS += -checklinkname=0 - ifneq ($(origin GOLANG_LDFLAGS),undefined) GOLANG_PARAMS = -ldflags="-extldflags '-ldl' $(GOLANG_LDFLAGS)" endif @@ -232,17 +226,17 @@ test-go: .make/test-go .PHONY: test-go-challenge test-go-challenge: test-go-deps - gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) -timeout 120m ./system_tests/... -run TestChallenge -tags challengetest + gotestsum --format short-verbose --no-color=false -- -timeout 120m ./system_tests/... -run TestChallenge -tags challengetest @printf $(done) .PHONY: test-go-stylus test-go-stylus: test-go-deps - gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) -timeout 120m ./system_tests/... -run TestProgramArbitrator -tags stylustest + gotestsum --format short-verbose --no-color=false -- -timeout 120m ./system_tests/... -run TestProgramArbitrator -tags stylustest @printf $(done) .PHONY: test-go-redis test-go-redis: test-go-deps - TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) -p 1 -run TestRedis ./system_tests/... ./arbnode/... + TEST_REDIS=redis://localhost:6379/0 gotestsum --format short-verbose --no-color=false -- -p 1 -run TestRedis ./system_tests/... ./arbnode/... @printf $(done) .PHONY: test-gen-proofs @@ -547,7 +541,7 @@ contracts/test/prover/proofs/%.json: $(arbitrator_cases)/%.wasm $(prover_bin) @touch $@ .make/test-go: $(DEP_PREDICATE) $(go_source) build-node-deps test-go-deps $(ORDER_ONLY_PREDICATE) .make - gotestsum --format short-verbose --no-color=false -- $(GOLANG_PARAMS) + gotestsum --format short-verbose --no-color=false @touch $@ .make/test-rust: $(DEP_PREDICATE) wasm-ci-build $(ORDER_ONLY_PREDICATE) .make diff --git a/go.mod b/go.mod index e3a6f59ef9..761554ade4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/offchainlabs/nitro -go 1.22 +go 1.23 replace github.com/VictoriaMetrics/fastcache => ./fastcache From bcc7c5b1229956e34b950f937a9ca280c1bf8e07 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 1 Oct 2024 15:49:35 -0300 Subject: [PATCH 099/101] Update go-ethereum to remove memsize pkg --- go-ethereum | 2 +- go.mod | 1 - go.sum | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/go-ethereum b/go-ethereum index 17cd001675..b068464bf5 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit 17cd00167543a5a2b0b083e32820051100154c2f +Subproject commit b068464bf59ab5414f72c2d4aba855b8af5edc17 diff --git a/go.mod b/go.mod index 761554ade4..bbe851fe02 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,6 @@ require ( github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect - github.com/fjl/memsize v0.0.2 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gammazero/deque v0.2.1 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect diff --git a/go.sum b/go.sum index c0193be769..8a432408d4 100644 --- a/go.sum +++ b/go.sum @@ -233,8 +233,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= -github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= From 6a7d177ce5881e5a4295946b6c268890040bf2d7 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 30 Sep 2024 17:16:31 -0300 Subject: [PATCH 100/101] Add -ldflags to Arbitrator CI --- .github/workflows/arbitrator-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/arbitrator-ci.yml b/.github/workflows/arbitrator-ci.yml index 7829fe4086..a6f478c4b3 100644 --- a/.github/workflows/arbitrator-ci.yml +++ b/.github/workflows/arbitrator-ci.yml @@ -59,7 +59,7 @@ jobs: cd go-ethereum # Enable KZG point evaluation precompile early sed -i 's#var PrecompiledContractsBerlin = map\[common.Address\]PrecompiledContract{#\0 common.BytesToAddress([]byte{0x0a}): \&kzgPointEvaluation{},#g' core/vm/contracts.go - go build -o /usr/local/bin/geth ./cmd/geth + go build -o /usr/local/bin/geth -ldflags='-checklinkname=0' ./cmd/geth - name: Setup nodejs uses: actions/setup-node@v3 From 4dc36758d732db409e8f25513e932322bf713527 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 1 Oct 2024 16:38:05 -0300 Subject: [PATCH 101/101] Use latest geth in arbitrator CI --- .github/workflows/arbitrator-ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/arbitrator-ci.yml b/.github/workflows/arbitrator-ci.yml index a6f478c4b3..47646017ac 100644 --- a/.github/workflows/arbitrator-ci.yml +++ b/.github/workflows/arbitrator-ci.yml @@ -55,11 +55,9 @@ jobs: - name: Install custom go-ethereum run: | cd /tmp - git clone --branch v1.13.8 --depth 1 https://github.com/ethereum/go-ethereum.git + git clone --branch v1.14.11 --depth 1 https://github.com/ethereum/go-ethereum.git cd go-ethereum - # Enable KZG point evaluation precompile early - sed -i 's#var PrecompiledContractsBerlin = map\[common.Address\]PrecompiledContract{#\0 common.BytesToAddress([]byte{0x0a}): \&kzgPointEvaluation{},#g' core/vm/contracts.go - go build -o /usr/local/bin/geth -ldflags='-checklinkname=0' ./cmd/geth + go build -o /usr/local/bin/geth ./cmd/geth - name: Setup nodejs uses: actions/setup-node@v3