Skip to content

fix(runtime): add fuel metering for engine-metered precompiles#276

Merged
dmitry123 merged 12 commits intodevelfrom
fix/charge-fuel-precompiles
Feb 12, 2026
Merged

fix(runtime): add fuel metering for engine-metered precompiles#276
dmitry123 merged 12 commits intodevelfrom
fix/charge-fuel-precompiles

Conversation

@d1r1
Copy link
Copy Markdown
Contributor

@d1r1 d1r1 commented Feb 4, 2026

NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME, and WEBAUTHN_VERIFIER were executing without charging gas because they don't self-meter via _charge_fuel syscall.

Changes:

  • Add ENGINE_METERED_PRECOMPILES list and is_engine_metered_precompile()
  • Create wasmtime engine with consume_fuel=true and syscall_fuel_params
  • Pass consume_fuel flag through executor to SystemRuntime
  • Set fuel limit before execution and read remaining fuel after

Summary by CodeRabbit

  • New Features

    • Selective fuel metering per contract/precompile with engine‑metered vs self‑metered modes; remaining fuel reported only for engine‑metered runs.
    • Added public constants and a lookup to mark engine‑metered precompiles and EIP‑2935 window parameters.
  • Bug Fixes / Behavior

    • EIP‑2935 flows updated with explicit gas‑charged reverts, stricter input validation, and consistent block‑window semantics.
    • Token module messaging and public surface cleaned up.
  • Tests

    • New end‑to‑end fuel measurement test for the verifier; tests made gas‑aware.
  • Chores

    • Testing context exposes consumed_fuel accessor; docs updated.

NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME, and WEBAUTHN_VERIFIER
were executing without charging gas because they don't self-meter via
`_charge_fuel` syscall.

Changes:
- Add ENGINE_METERED_PRECOMPILES list and is_engine_metered_precompile()
- Create wasmtime engine with consume_fuel=true and syscall_fuel_params
- Pass consume_fuel flag through executor to SystemRuntime
- Set fuel limit before execution and read remaining fuel after
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Per-contract fuel metering added: types expose engine‑metered precompiles; build sets per-contract consume_fuel; executor forwards consume_fuel to SystemRuntime; SystemRuntime compiles/instantiates with or without engine fuel metering and exposes conditional remaining_fuel; tests and contracts updated for fuel‑aware accounting. (47 words)

Changes

Cohort / File(s) Summary
Types & Genesis
crates/types/src/genesis.rs, crates/types/src/eip2935.rs
Add ENGINE_METERED_PRECOMPILES and is_engine_metered_precompile(); add EIP‑2935 window constants and related docs.
Build script
crates/genesis/build.rs
Iterate (address, contract) and set per-contract consume_fuel via is_engine_metered_precompile(address) in compilation config (applies to consume_fuel and builtins_consume_fuel).
Executor
crates/runtime/src/executor.rs
Plumb consume_fuel through BytecodeOrHash resolution; update call site to SystemRuntime::new(..., consume_fuel); Hash path returns tuple including consume flag.
System Runtime
crates/runtime/src/runtime/system_runtime.rs
Add consume_fuel field/param; compile/cache modules keyed by (code_hash, consume_fuel); select engine via wasmtime_engine_with_consume_fuel() when engine‑metered; reset/apply fuel on execute; map OutOfFuel traps; remaining_fuel() conditional.
EIP‑2935 runtime logic
crates/revm/src/eip2935.rs
Move input length and non‑zero checks to top; simplify storage key computation using history window; unify return shape.
Contracts: EIP‑2935
contracts/eip2935/lib.rs, contracts/eip2935/tests.rs
Introduce GAS_* branch constants and charge_and_panic; charge gas on revert branches; refactor tests and harness to assert consumed fuel and return gas usage.
Testing & e2e
crates/testing/src/host.rs, e2e/src/lib.rs, e2e/src/fuel.rs, e2e/src/universal_token.rs
Add TestingContextImpl::consumed_fuel(); new e2e fuel timing test; adjust module wiring/imports; tighten e2e import surface and update revert assertions.
Contracts: universal-token
contracts/universal-token/lib.rs
Remove #[inline(never)] from deploy_entry; minor comment/text edits.
Misc / Manifests & Tests
Cargo.toml, assorted test files
Register new tests/modules; imports/exports adjustments across tests and harness helpers.
sequenceDiagram
    participant Build as Build Process
    participant Types as Types/Genesis
    participant Executor as Runtime Executor
    participant SysRT as SystemRuntime
    participant WasmEngine as Wasmtime Engine

    Build->>Types: is_engine_metered_precompile(address)
    Types-->>Build: consume_fuel (bool)
    Build->>Build: set per-contract compilation config (consume_fuel)

    Executor->>Executor: resolve BytecodeOrHash (address/hash)
    Executor->>SysRT: SystemRuntime::new(module, import_linker, code_hash, ctx, consume_fuel)
    SysRT->>SysRT: compiled_module(code_hash, rwasm_module, consume_fuel)
    alt consume_fuel = true
        SysRT->>WasmEngine: use wasmtime_engine_with_consume_fuel()
    else consume_fuel = false
        SysRT->>WasmEngine: use wasmtime_engine()
    end

    SysRT->>WasmEngine: execute (reset/apply fuel if engine‑metered)
    WasmEngine-->>SysRT: result or OutOfFuel trap
    SysRT-->>Executor: return result / trap mapping
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through genesis, flag in paw,
I set each contract’s tiny law,
Some engines sip while others store,
Tests ran, meters ticked—then more,
A rabbit grins: fuel counted, hoora!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding fuel metering support for engine-metered precompiles through runtime modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/charge-fuel-precompiles

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 4, 2026

Criterion results (vs baseline)

Heads-up: runner perf is noisy; treat deltas as a smoke check.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/runtime/src/runtime/system_runtime.rs (2)

123-155: ⚠️ Potential issue | 🟡 Minor

Cache key should include consume_fuel.
COMPILED_MODULES is keyed only by code_hash. If a module is ever compiled with different consume_fuel settings, the cached module could be reused with the wrong engine, leading to incorrect metering or a panic when setting fuel.

🔧 Suggested fix
-        static COMPILED_MODULES: OnceLock<RwLock<HashMap<B256, Module>>> = OnceLock::new();
+        static COMPILED_MODULES: OnceLock<RwLock<HashMap<(B256, bool), Module>>> = OnceLock::new();
         let compiled_modules = COMPILED_MODULES.get_or_init(|| RwLock::new(HashMap::new()));
+        let cache_key = (code_hash, consume_fuel);

         // Fast path: read lock lookup.
         {
             let guard = compiled_modules.read().unwrap();
-            if let Some(module) = guard.get(&code_hash) {
+            if let Some(module) = guard.get(&cache_key) {
                 return module.clone();
             }
         }

         // Slow path: compile and insert under write lock (with re-check).
         let mut guard = compiled_modules.write().unwrap();
-        if let Some(module) = guard.get(&code_hash) {
+        if let Some(module) = guard.get(&cache_key) {
             return module.clone();
         }

         ...
-        guard.insert(code_hash, module.clone());
+        guard.insert(cache_key, module.clone());

262-293: ⚠️ Potential issue | 🟡 Minor

Remove debug logging from the hot execution path.
eprintln! on every execution will be noisy and adds overhead. Prefer a feature‑gated or structured logger.

🔧 Suggested fix
-            eprintln!("DEBUG: consume fuel");
🤖 Fix all issues with AI agents
In `@crates/genesis/build.rs`:
- Around line 89-101: The cache key must include the fuel instrumentation flag
so compiled artifacts for the same wasm bytecode but different fuel modes don't
clash: change the lookup and insertion on cache for GENESIS_CONTRACTS to use a
composite key of (contract.wasm_bytecode, should_charge_fuel) instead of only
contract.wasm_bytecode, compute should_charge_fuel via
is_engine_metered_precompile(address) before checking cache, and then continue
to call
default_compilation_config().with_consume_fuel(should_charge_fuel).with_builtins_consume_fuel(should_charge_fuel)
when compiling and store that compiled result under the composite key.

In `@crates/runtime/src/runtime/system_runtime.rs`:
- Around line 409-414: The remaining_fuel method currently prints a debug
eprintln! on the hot path; remove that eprintln! (or gate it behind a
non-hot-path debug facility) so remaining_fuel only returns the fuel.
Specifically, edit remaining_fuel to stop calling eprintln! with
compiled_runtime.store.data().fuel_limit and fuel; instead either drop the print
entirely or replace it with a conditional debug log (e.g., log::trace! or
cfg!(debug_assertions)) so compiled_runtime, store.get_fuel, and
store.data().fuel_limit are not written to stderr on every call.

In `@e2e/src/fuel.rs`:
- Around line 29-32: The seed balance uses a float-to-int cast which can lose
precision: replace U256::from(1e18 as u128) with an integer literal or other
integer constructor to avoid going through f64; update the call at
ctx.add_balance(caller, U256::from(...)) (related symbols: caller, ctx,
add_balance, U256, Address::ZERO) to use a precise integer like
1000000000000000000u128 (or construct the U256 via a safe helper) so the balance
is exact.

Comment thread crates/genesis/build.rs
Comment on lines +89 to +101
for (address, contract) in GENESIS_CONTRACTS {
if cache.contains_key(contract.wasm_bytecode) {
continue;
}
// Most system precompiles manage fuel internally via `_charge_fuel` syscall.
// However, some precompiles (NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME,
// WEBAUTHN_VERIFIER) don't self-meter, so they need fuel instrumentation.
let should_charge_fuel = is_engine_metered_precompile(address);

let config = default_compilation_config()
.with_consume_fuel(should_charge_fuel)
.with_builtins_consume_fuel(should_charge_fuel);

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Include fuel mode in the compile cache key.
The cache is keyed only by contract.wasm_bytecode, but consume_fuel depends on the address. If the same bytecode is ever reused by both engine‑metered and self‑metered precompiles, the first compiled variant would be reused with the wrong fuel settings. Consider keying by (bytecode, should_charge_fuel) and updating the later lookup accordingly.

🔧 Suggested fix
-    let mut cache = HashMap::new();
+    let mut cache: HashMap<(&'static [u8], bool), (B256, Bytes)> = HashMap::new();

-    for (address, contract) in GENESIS_CONTRACTS {
-        if cache.contains_key(contract.wasm_bytecode) {
+    for (address, contract) in GENESIS_CONTRACTS {
+        let should_charge_fuel = is_engine_metered_precompile(address);
+        let cache_key = (contract.wasm_bytecode, should_charge_fuel);
+        if cache.contains_key(&cache_key) {
             continue;
         }
-        // Most system precompiles manage fuel internally via `_charge_fuel` syscall.
-        // However, some precompiles (NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME,
-        // WEBAUTHN_VERIFIER) don't self-meter, so they need fuel instrumentation.
-        let should_charge_fuel = is_engine_metered_precompile(address);
+        // Most system precompiles manage fuel internally via `_charge_fuel` syscall.
+        // However, some precompiles (NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME,
+        // WEBAUTHN_VERIFIER) don't self-meter, so they need fuel instrumentation.

         let config = default_compilation_config()
             .with_consume_fuel(should_charge_fuel)
             .with_builtins_consume_fuel(should_charge_fuel);

         ...
-        cache.insert(contract.wasm_bytecode, result.clone());
+        cache.insert(cache_key, result.clone());
-        let (rwasm_bytecode_hash, rwasm_bytecode) =
-            rwasm_artifacts.get(contract.wasm_bytecode).unwrap().clone();
+        let should_charge_fuel = is_engine_metered_precompile(address);
+        let (rwasm_bytecode_hash, rwasm_bytecode) = rwasm_artifacts
+            .get(&(contract.wasm_bytecode, should_charge_fuel))
+            .unwrap()
+            .clone();
🤖 Prompt for AI Agents
In `@crates/genesis/build.rs` around lines 89 - 101, The cache key must include
the fuel instrumentation flag so compiled artifacts for the same wasm bytecode
but different fuel modes don't clash: change the lookup and insertion on cache
for GENESIS_CONTRACTS to use a composite key of (contract.wasm_bytecode,
should_charge_fuel) instead of only contract.wasm_bytecode, compute
should_charge_fuel via is_engine_metered_precompile(address) before checking
cache, and then continue to call
default_compilation_config().with_consume_fuel(should_charge_fuel).with_builtins_consume_fuel(should_charge_fuel)
when compiling and store that compiled result under the composite key.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be an issue, potentially

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmitry123, thanks for confirming! Since this could affect correctness if the same bytecode is ever shared between differently-metered precompiles, would you like to address it in this PR, or would you prefer to track it as a follow-up issue?

Comment thread crates/runtime/src/runtime/system_runtime.rs
Comment thread e2e/src/fuel.rs
Comment on lines +29 to +32
let caller = Address::ZERO;
let mut ctx = EvmTestingContext::default().with_full_genesis();
ctx.add_balance(caller, U256::from(1e18 as u128));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid float‑to‑int cast for the seed balance.
1e18 as u128 goes through f64 and can lose precision. Use an integer literal instead.

🐛 Suggested fix
-    ctx.add_balance(caller, U256::from(1e18 as u128));
+    ctx.add_balance(caller, U256::from(1_000_000_000_000_000_000u128));
🤖 Prompt for AI Agents
In `@e2e/src/fuel.rs` around lines 29 - 32, The seed balance uses a float-to-int
cast which can lose precision: replace U256::from(1e18 as u128) with an integer
literal or other integer constructor to avoid going through f64; update the call
at ctx.add_balance(caller, U256::from(...)) (related symbols: caller, ctx,
add_balance, U256, Address::ZERO) to use a precise integer like
1000000000000000000u128 (or construct the U256 via a safe helper) so the balance
is exact.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/runtime/src/runtime/system_runtime.rs (1)

123-156: ⚠️ Potential issue | 🟠 Major

Include consume_fuel in the compiled-module cache key.

COMPILED_MODULES is keyed only by code_hash, but the compiled module’s engine configuration differs based on consume_fuel. If the same code_hash is ever used in both modes, the cache can return a module built with the wrong fuel configuration, disabling (or incorrectly enabling) engine metering.

🔧 Proposed fix (separate cache entries by mode)
-        static COMPILED_MODULES: OnceLock<RwLock<HashMap<B256, Module>>> = OnceLock::new();
+        static COMPILED_MODULES: OnceLock<RwLock<HashMap<(B256, bool), Module>>> = OnceLock::new();

-        if let Some(module) = guard.get(&code_hash) {
+        if let Some(module) = guard.get(&(code_hash, consume_fuel)) {
             return module.clone();
         }

-        if let Some(module) = guard.get(&code_hash) {
+        if let Some(module) = guard.get(&(code_hash, consume_fuel)) {
             return module.clone();
         }

-        guard.insert(code_hash, module.clone());
+        guard.insert((code_hash, consume_fuel), module.clone());
🤖 Fix all issues with AI agents
In `@crates/runtime/src/runtime/system_runtime.rs`:
- Around line 504-531: The engine is built with syscall_fuel_params derived from
a static import_linker_v1_preview() inside wasmtime_engine_with_consume_fuel(),
which can diverge from the import_linker passed into SystemRuntime::new();
change the design so syscall_fuel_params are computed from the same ImportLinker
used for instantiation: either (a) move the engine construction out of
wasmtime_engine_with_consume_fuel() into code that receives the ImportLinker
from SystemRuntime::new() and call build_syscall_fuel_params(import_linker)
there, or (b) add an explicit assertion in SystemRuntime::new() that the passed
import_linker equals import_linker_v1_preview() and document this invariant;
update references to build_syscall_fuel_params,
wasmtime_engine_with_consume_fuel, and SystemRuntime::new accordingly so the
engine and instantiation always use the same ImportLinker for fuel parameter
calculation.

Comment on lines +504 to +531
/// Returns the shared Wasmtime engine instance with fuel metering enabled.
///
/// Used for engine-metered precompiles (NITRO, OAUTH2, WASM_RUNTIME, WEBAUTHN).
/// These precompiles don't self-meter via `_charge_fuel` syscall, so the engine
/// must automatically charge fuel for:
/// - wasm instructions (via `consume_fuel=true`)
/// - syscall/builtin calls (via `syscall_fuel_params`)
///
/// TODO(d1r1): move to rwasm crate - add async_support parameter to
/// factory_wasmtime_engine_with_linker and reuse it here
fn wasmtime_engine_with_consume_fuel() -> &'static Engine {
static ENGINE: OnceLock<Engine> = OnceLock::new();
ENGINE.get_or_init(|| {
let import_linker = fluentbase_types::import_linker_v1_preview();

let mut cfg = Config::new();
cfg.strategy(Strategy::Cranelift);
cfg.collector(wasmtime::Collector::Null);
cfg.max_wasm_stack(N_MAX_STACK_SIZE * size_of::<u32>());
cfg.async_support(false); // Must be false for sync instantiate()/call()
cfg.wasm_memory64(false);
cfg.memory_init_cow(false);
cfg.cranelift_opt_level(OptLevel::Speed);
cfg.parallel_compilation(true);
cfg.consume_fuel(true);
cfg.syscall_fuel_params(build_syscall_fuel_params(&import_linker));

Engine::new(&cfg).unwrap()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for all SystemRuntime::new call sites and related linker usage
rg -n -C5 'SystemRuntime::new\(' --type rust

Repository: fluentlabs-xyz/fluentbase

Length of output: 927


🏁 Script executed:

#!/bin/bash
# Search for import_linker_v1_preview usage across the codebase
rg -n -C3 'import_linker_v1_preview' --type rust

Repository: fluentlabs-xyz/fluentbase

Length of output: 4490


🏁 Script executed:

#!/bin/bash
# Find the SystemRuntime::new signature to understand its parameters
rg -n 'fn new\(' crates/runtime/src/runtime/system_runtime.rs -A 10

Repository: fluentlabs-xyz/fluentbase

Length of output: 528


🏁 Script executed:

#!/bin/bash
# Get the full context around wasmtime_engine_with_consume_fuel function and its usage
cat -n crates/runtime/src/runtime/system_runtime.rs | sed -n '504,531p'

Repository: fluentlabs-xyz/fluentbase

Length of output: 1581


🏁 Script executed:

#!/bin/bash
# Check if SystemRuntime::new stores or uses the passed import_linker parameter
ast-grep --pattern 'fn new($_,  import_linker: $_) {
  $$$
}'

Repository: fluentlabs-xyz/fluentbase

Length of output: 51


🏁 Script executed:

#!/bin/bash
# Get the full SystemRuntime::new implementation
cat -n crates/runtime/src/runtime/system_runtime.rs | sed -n '180,240p'

Repository: fluentlabs-xyz/fluentbase

Length of output: 2859


🏁 Script executed:

#!/bin/bash
# Check if import_linker is stored or used in SystemRuntime struct
rg -n 'struct SystemRuntime' crates/runtime/src/runtime/system_runtime.rs -A 20

Repository: fluentlabs-xyz/fluentbase

Length of output: 1091


🏁 Script executed:

#!/bin/bash
# Check how import_linker is used after being passed to new()
rg -n 'import_linker' crates/runtime/src/runtime/system_runtime.rs -B 2 -A 2

Repository: fluentlabs-xyz/fluentbase

Length of output: 2284


🏁 Script executed:

#!/bin/bash
# Check what RuntimeFactoryExecutor stores and how it's initialized
cat -n crates/runtime/src/executor.rs | sed -n '100,140p'

Repository: fluentlabs-xyz/fluentbase

Length of output: 1490


Ensure syscall fuel params match the actual ImportLinker.

The engine's syscall_fuel_params are computed from a static import_linker_v1_preview() at engine creation time (line 517), while SystemRuntime::new() accepts a separate import_linker parameter for instantiation. If the two differ, fuel metering will charge incorrect costs. Currently all callers pass import_linker_v1_preview(), but this coupling is fragile: derive syscall_fuel_params from the linker passed to SystemRuntime::new(), or guarantee via documentation/assertion that the linker is always import_linker_v1_preview().

🤖 Prompt for AI Agents
In `@crates/runtime/src/runtime/system_runtime.rs` around lines 504 - 531, The
engine is built with syscall_fuel_params derived from a static
import_linker_v1_preview() inside wasmtime_engine_with_consume_fuel(), which can
diverge from the import_linker passed into SystemRuntime::new(); change the
design so syscall_fuel_params are computed from the same ImportLinker used for
instantiation: either (a) move the engine construction out of
wasmtime_engine_with_consume_fuel() into code that receives the ImportLinker
from SystemRuntime::new() and call build_syscall_fuel_params(import_linker)
there, or (b) add an explicit assertion in SystemRuntime::new() that the passed
import_linker equals import_linker_v1_preview() and document this invariant;
update references to build_syscall_fuel_params,
wasmtime_engine_with_consume_fuel, and SystemRuntime::new accordingly so the
engine and instantiation always use the same ImportLinker for fuel parameter
calculation.

// If fuel metering is enabled, set the fuel limit before execution.
// The store is reused, so we must reset fuel for each new call.
if self.consume_fuel {
eprintln!("DEBUG: consume fuel");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove println(s) from the code

Comment thread crates/genesis/build.rs
Comment on lines +89 to +101
for (address, contract) in GENESIS_CONTRACTS {
if cache.contains_key(contract.wasm_bytecode) {
continue;
}
// Most system precompiles manage fuel internally via `_charge_fuel` syscall.
// However, some precompiles (NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME,
// WEBAUTHN_VERIFIER) don't self-meter, so they need fuel instrumentation.
let should_charge_fuel = is_engine_metered_precompile(address);

let config = default_compilation_config()
.with_consume_fuel(should_charge_fuel)
.with_builtins_consume_fuel(should_charge_fuel);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be an issue, potentially

if let Err(trap_code) = result.as_ref() {
// OutOfFuel is expected for engine-metered precompiles when fuel is exhausted.
if *trap_code == TrapCode::OutOfFuel {
return Err(TrapCode::OutOfFuel);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, yes, but we should guarantee that it never happens inside stateful runtimes (evm, svm, etc). Maybe it's better to add a comment here indicating that this is true only for stateless contracts. Statefullness means it stores intermediary state inside memory (aka can do interurptions).

///
/// TODO(d1r1): move to rwasm crate - add async_support parameter to
/// factory_wasmtime_engine_with_linker and reuse it here
fn wasmtime_engine_with_consume_fuel() -> &'static Engine {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not reuse an existing method but with an extra consume_fuel flag?

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/eip2935/tests.rs (1)

69-89: ⚠️ Potential issue | 🟡 Minor

Comment claims no mutation, but clone() shares state.
TestingContextImpl::clone uses Rc<RefCell<...>>, so input/caller/block updates mutate the shared context. Either update the comment or deep-clone if isolation is intended.

📝 Suggested doc update
-/// This helper does **not** mutate the provided `sdk` in-place. Instead, it clones it,
-/// configures the call parameters (input/caller/block number), runs the entrypoint, and then
-/// extracts the output.
+/// This helper clones the context handle (shared `Rc`), so it mutates shared state.
+/// Each call overwrites input/caller/block_number on the shared context before execution,
+/// then runs the entrypoint and extracts the output.
🧹 Nitpick comments (1)
crates/testing/src/host.rs (1)

87-89: Clarify fuel vs gas units for consumed_fuel.
This accessor returns raw fuel units; a short doc note helps prevent misuse as gas.

📝 Suggested doc clarification
+    /// Returns fuel consumed in fuel units (not gas). Divide by FUEL_DENOM_RATE to get gas.
     pub fn consumed_fuel(&self) -> u64 {
         self.inner.borrow().consumed_fuel
     }

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/runtime/src/runtime/system_runtime.rs (2)

128-156: ⚠️ Potential issue | 🔴 Critical

Cache key must include consume_fuel to avoid returning wrong module.

The COMPILED_MODULES cache uses only code_hash as the key, but modules are now compiled differently based on consume_fuel. If the same code_hash is first compiled with consume_fuel=false and later requested with consume_fuel=true, the cache will return the wrong module (without fuel metering enabled).

🐛 Proposed fix to use composite cache key
-    pub fn compiled_module(
-        code_hash: B256,
-        rwasm_module: RwasmModule,
-        consume_fuel: bool,
-    ) -> Module {
-        static COMPILED_MODULES: OnceLock<RwLock<HashMap<B256, Module>>> = OnceLock::new();
+    pub fn compiled_module(
+        code_hash: B256,
+        rwasm_module: RwasmModule,
+        consume_fuel: bool,
+    ) -> Module {
+        static COMPILED_MODULES: OnceLock<RwLock<HashMap<(B256, bool), Module>>> = OnceLock::new();
         let compiled_modules = COMPILED_MODULES.get_or_init(|| RwLock::new(HashMap::new()));
+        let cache_key = (code_hash, consume_fuel);
 
         // Fast path: read lock lookup.
         {
             let guard = compiled_modules.read().unwrap();
-            if let Some(module) = guard.get(&code_hash) {
+            if let Some(module) = guard.get(&cache_key) {
                 return module.clone();
             }
         }
 
         // Slow path: compile and insert under write lock (with re-check).
         let mut guard = compiled_modules.write().unwrap();
-        if let Some(module) = guard.get(&code_hash) {
+        if let Some(module) = guard.get(&cache_key) {
             return module.clone();
         }
 
         // ... compilation logic ...
 
-        guard.insert(code_hash, module.clone());
+        guard.insert(cache_key, module.clone());
         module
     }

100-107: ⚠️ Potential issue | 🔴 Critical

Thread-local runtime cache also needs consume_fuel in key.

Same issue as COMPILED_MODULES: the COMPILED_RUNTIMES cache uses only code_hash as the key. If the same code is executed with different consume_fuel settings, the cached runtime with the wrong fuel configuration will be returned.

🐛 Proposed fix
 thread_local! {
-    pub static COMPILED_RUNTIMES: RefCell<HashMap<B256, Rc<RefCell<CompiledRuntime>>>> =
+    pub static COMPILED_RUNTIMES: RefCell<HashMap<(B256, bool), Rc<RefCell<CompiledRuntime>>>> =
         RefCell::new(HashMap::new());
 }

And update the lookup/insert in new():

         let compiled_runtime = COMPILED_RUNTIMES.with_borrow_mut(|compiled_runtimes| {
-            if let Some(compiled_runtime) = compiled_runtimes.get(&code_hash).cloned() {
+            let cache_key = (code_hash, consume_fuel);
+            if let Some(compiled_runtime) = compiled_runtimes.get(&cache_key).cloned() {
                 return compiled_runtime;
             }
             // ... instantiation logic ...
-            compiled_runtimes.insert(code_hash, compiled_runtime.clone());
+            compiled_runtimes.insert(cache_key, compiled_runtime.clone());
             compiled_runtime
         });

Also applies to: 187-226

🤖 Fix all issues with AI agents
In `@e2e/src/universal_token.rs`:
- Around line 493-497: The test assertion uses hex! with a "0x" prefix which the
hex-literal macro rejects; update the hex literal in the assertion comparing
result.output() to remove the "0x" prefix inside the hex!("...") call (i.e.,
change hex!("0x4e48...") to hex!("4e48...") in the assert_eq! that compares
result.output().unwrap_or_default().as_ref()) so it matches other hex! usages in
universal_token.rs.

Comment on lines +493 to 497
assert!(!result.is_success());
assert_eq!(
result,
ExecutionResult::Revert {
gas_used: 22_210,
output: hex!(
"0x4e487b7100000000000000000000000000000000000000000000000000000000e450d38c"
)
.into()
}
result.output().unwrap_or_default().as_ref(),
hex!("0x4e487b7100000000000000000000000000000000000000000000000000000000e450d38c")
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

hex! macro Rust hex literals 0x prefix support

💡 Result:

  • hex_literal::hex! (RustCrypto “hex-literal”) does not support a 0x prefix. Its input strings may contain only hex digits plus a small set of ignored formatting characters (e.g., whitespace; in newer versions also :). Any other character (like x) is unsupported and will cause a compile-time error. [1], [2]

    • So write hex!("DEADBEEF"), not hex!("0xDEADBEEF"). [1], [2]
  • If you specifically want 0x...-prefixed hex strings, use a different macro/crate that supports it, e.g.:

    • hexlit::hex!, which shows hex!("0xDEADBEEF") working in its docs. [3]
    • hexhex::hex_literal!, which also documents hex_literal!("0xc0ffee"). [4]

Sources:
[1] https://docs.rs/hex-literal/latest
[2] https://docs.rs/hex-literal/
[3] https://docs.rs/hexlit
[4] https://docs.rs/hexhex


🏁 Script executed:

# Find the file and check other hex! usages
fd -t f universal_token.rs -x wc -l {}

Repository: fluentlabs-xyz/fluentbase

Length of output: 148


🏁 Script executed:

# Search for other hex! macro usages in the file to see the pattern
rg "hex!\(" e2e/src/universal_token.rs -A 1 | head -40

Repository: fluentlabs-xyz/fluentbase

Length of output: 764


Remove the 0x prefix from the hex literal—it will cause a compile-time error.

The hex! macro from hex-literal does not support the 0x prefix. All other usages in this file omit it (e.g., hex!("000000...")); this is the only occurrence with the prefix.

Fix
-        hex!("0x4e487b7100000000000000000000000000000000000000000000000000000000e450d38c")
+        hex!("4e487b7100000000000000000000000000000000000000000000000000000000e450d38c")
🤖 Prompt for AI Agents
In `@e2e/src/universal_token.rs` around lines 493 - 497, The test assertion uses
hex! with a "0x" prefix which the hex-literal macro rejects; update the hex
literal in the assertion comparing result.output() to remove the "0x" prefix
inside the hex!("...") call (i.e., change hex!("0x4e48...") to hex!("4e48...")
in the assert_eq! that compares result.output().unwrap_or_default().as_ref()) so
it matches other hex! usages in universal_token.rs.

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@contracts/eip2935/lib.rs`:
- Around line 124-128: The comment above the error-return is wrong: change the
comment referring to "Storage write" to correctly indicate that sdk.storage() is
a read operation (e.g., "Storage read can't fail..."). Also fix the fuel units
when charging on success: multiply GAS_RETRIEVE_SUCCESS_BRANCH by
FUEL_DENOM_RATE when calling sdk.charge_fuel (i.e., use result.fuel_consumed +
GAS_RETRIEVE_SUCCESS_BRANCH * FUEL_DENOM_RATE) so units match; update the
sdk.charge_fuel call accordingly.
- Line 86: The code adds GAS_SUBMIT_SUCCESS_BRANCH (EVM gas units) directly to
result.fuel_consumed (already in fuel units), causing under-charging; update the
call to sdk.charge_fuel so the gas constant is converted by FUEL_DENOM_RATE
(i.e., add GAS_SUBMIT_SUCCESS_BRANCH * FUEL_DENOM_RATE or use the same
conversion helper pattern as charge_and_panic) and ensure any necessary
casts/checked multiplication to match the fuel type; adjust within the scope of
the sdk.charge_fuel(...) invocation that references result.fuel_consumed and
GAS_SUBMIT_SUCCESS_BRANCH.

Comment thread contracts/eip2935/lib.rs Outdated
Comment thread contracts/eip2935/lib.rs Outdated
Comment on lines +124 to +128
if !result.status.is_ok() {
// Storage write here can't fail, even if it fails, it causes trap and charges all gas available
return Err(result.status);
}
// Load the hash.
let hash_key = user_requested_block_number % U256::from(EIP2935_HISTORY_SERVE_WINDOW);
let hash_value = sdk.storage(&hash_key).ok()?;
sdk.write(hash_value.to_be_bytes::<{ U256::BYTES }>());
sdk.charge_fuel(result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Same unit mismatch and incorrect comment.

Two issues in this block:

  1. Line 125: Comment says "Storage write" but sdk.storage() is a read operation (copy-paste from line 83).

  2. Line 128: Same unit mismatch as line 86 — GAS_RETRIEVE_SUCCESS_BRANCH should be multiplied by FUEL_DENOM_RATE.

🐛 Proposed fix
     let result = sdk.storage(&slot);
     if !result.status.is_ok() {
-        // Storage write here can't fail, even if it fails, it causes trap and charges all gas available
+        // Storage read here can't fail, even if it fails, it causes trap and charges all gas available
         return Err(result.status);
     }
-    sdk.charge_fuel(result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH);
+    sdk.charge_fuel(result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH * FUEL_DENOM_RATE);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if !result.status.is_ok() {
// Storage write here can't fail, even if it fails, it causes trap and charges all gas available
return Err(result.status);
}
// Load the hash.
let hash_key = user_requested_block_number % U256::from(EIP2935_HISTORY_SERVE_WINDOW);
let hash_value = sdk.storage(&hash_key).ok()?;
sdk.write(hash_value.to_be_bytes::<{ U256::BYTES }>());
sdk.charge_fuel(result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH);
if !result.status.is_ok() {
// Storage read here can't fail, even if it fails, it causes trap and charges all gas available
return Err(result.status);
}
sdk.charge_fuel(result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH * FUEL_DENOM_RATE);
🤖 Prompt for AI Agents
In `@contracts/eip2935/lib.rs` around lines 124 - 128, The comment above the
error-return is wrong: change the comment referring to "Storage write" to
correctly indicate that sdk.storage() is a read operation (e.g., "Storage read
can't fail..."). Also fix the fuel units when charging on success: multiply
GAS_RETRIEVE_SUCCESS_BRANCH by FUEL_DENOM_RATE when calling sdk.charge_fuel
(i.e., use result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH * FUEL_DENOM_RATE)
so units match; update the sdk.charge_fuel call accordingly.

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Comment thread contracts/eip2935/lib.rs Outdated
Comment on lines +20 to +50
/// ------------------------------
/// Gas accounting (Prague fork)
/// ------------------------------
/// These are "entry-to-throw" gas totals for the *read* path reverts,
/// derived from the exact opcode sequences in the EVM snippet.
///
/// Throw tail in snippet:
/// JUMPDEST (1) + PUSH0 (3) + PUSH0 (3) + REVERT (0) = 7
///
/// Prefix gate (caller != SYSADDR; jump not taken):
/// CALLER(2) + PUSH20(3) + EQ(3) + JUMPI(10) = 18
///
/// Length check block:
/// PUSH1(3) + CALLDATASIZE(2) + SUB(3) + JUMPI(10) = 18
///
/// Future-block check block:
/// PUSH0(3) + CALLDATALOAD(3) + PUSH1(3) + NUMBER(2) + SUB(3)
/// + DUP2(3) + GT(3) + JUMPI(10) = 30
///
/// Too-old check block:
/// PUSH(3) + DUP2(3) + NUMBER(2) + SUB(3) + GT(3) + JUMPI(10) = 24
///
/// Totals:
/// - Bad length: 18 + 18 + 7 = 43
/// - Future block: 18 + 18 + 30 + 7 = 73
/// - Too old block: 18 + 18 + 30 + 24 + 7 = 97
const GAS_BAD_BLOCK_INPUT_BRANCH: u64 = 43;
const GAS_INVALID_BLOCK_BRANCH: u64 = 73;
const GAS_BLOCK_TOO_OLD_BRANCH: u64 = 97;
const GAS_RETRIEVE_SUCCESS_BRANCH: u64 = 113;
const GAS_SUBMIT_SUCCESS_BRANCH: u64 = 41;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://ethereum.org/developers/docs/evm/opcodes/

GAS_BAD_BLOCK_INPUT_BRANCH = 21 + 21 + 5 = 47
GAS_INVALID_BLOCK_BRANCH = 21 + 21 + 32 + 5 = 79
GAS_BLOCK_TOO_OLD_BRANCH = 21 + 21 + 32 + 27 + 5 = 106
GAS_RETRIEVE_SUCCESS_BRANCH = 21 + 21 + 32 + 27 + 24 = 125
GAS_SUBMIT_SUCCESS_BRANCH = 21 + 22 = 43

; --- prefix gate: if caller == 0xffff..fffe jump to write-path @0x46 ---
caller                               ; 2
push20 0xfffffffffffffffffffffffffffffffffffffffe ; 3
eq                                   ; 3
push1 0x46                            ; 3
jumpi                                 ; 10
; prefix subtotal = 21


; --- read-path length gate: if (calldatasize - 0x20) != 0 then revert @0x42 ---
push1 0x20                            ; 3
calldatasize                          ; 2
sub                                   ; 3
push1 0x42                            ; 3
jumpi                                 ; 10
; length-check subtotal = 21


; --- load arg (slot selector / block number) from calldata[0:32] ---
push0                                 ; 2
calldataload                           ; 3

; --- future-block gate: if arg > (number - 1) then revert @0x42 ---
push1 0x01                            ; 3
number                                 ; 2
sub                                    ; 3
dup2                                   ; 3
gt                                     ; 3
push1 0x42                             ; 3
jumpi                                  ; 10
; future-check subtotal = 32


; --- too-old gate: if (number - arg) > 0x1fff then revert @0x42 ---
push2 0x1fff                           ; 3
dup2                                   ; 3
number                                 ; 2
sub                                    ; 3
gt                                     ; 3
push1 0x42                             ; 3
jumpi                                  ; 10
; too-old subtotal = 27


; --- read: sload[(arg mod 0x1fff)] and return it as 32 bytes ---
push2 0x1fff                           ; 3
swap1                                  ; 3
mod                                    ; 5
sload                                  ; syscall
push0                                  ; 2
mstore                                 ; 3 + memory expansion (3)            
push1 0x20                             ; 3
push0                                  ; 2
return                                 ; 0  + memory expansion (0) 


; --- revert handler @0x42 ---
jumpdest                               ; 1
push0                                  ; 2
push0                                  ; 2
revert                                 ; 0
; throw-tail subtotal = 5


; --- write-path @0x46: store (arg mod (number-1) mod 0x1fff) into s[ (number-1) mod 0x1fff ] ---
jumpdest                               ; 1
push0                                  ; 2
calldataload                           ; 3
push2 0x1fff                           ; 3
push1 0x01                             ; 3
number                                 ; 2
sub                                    ; 3
mod                                    ; 5
sstore                                 ; syscall
stop                                   ; 0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread contracts/eip2935/lib.rs Outdated
let hash_key = user_requested_block_number % U256::from(EIP2935_HISTORY_SERVE_WINDOW);
let hash_value = sdk.storage(&hash_key).ok()?;
sdk.write(hash_value.to_be_bytes::<{ U256::BYTES }>());
sdk.charge_fuel(result.fuel_consumed + GAS_RETRIEVE_SUCCESS_BRANCH * FUEL_DENOM_RATE);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that fuel_consumed is always 0 for system precompiles

impl<API: NativeAPI + CryptoAPI> StorageAPI for SystemContextImpl<API> {
    fn write_storage(&mut self, slot: U256, value: U256) -> SyscallResult<()> {
        self.state.storage.write_storage(slot, value);
        // Note: Storage write here can't fail, that's why we always return `Ok`
        SyscallResult::default()
    }

    fn storage(&self, slot: &U256) -> SyscallResult<U256> {
        if let Some(value) = self.state.storage.storage(slot) {
            return SyscallResult::new(*value, 0, 0, ExitCode::Ok);
        };
        debug_log!("a missing storage slot detected at: {}", slot);
        // We return here a `MissingStorageSlot`, but this error should be at user-level, because
        // an attacker might intentionally pass incorrect params into the function
        SyscallResult::new(U256::ZERO, 0, 0, ExitCode::MissingStorageSlot)
    }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also means that universal token runtime do not charge for any SLOADs / SSTOREs performed as the slot reads / writes occur outside of the program (in the executor)

ctx.journal_mut().sstore(*target_address, k, v)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally for sloads and sstores we should charge the gas in the executor, just before the sloads and sstore operations happen.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about the universal token runtime, the sloads and sstores there are not metered

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't charge for Universal Token, because of 2 reasons:

  1. it's cheap (~100 gas per storage read since the contract enforces access lists that makes all storage slots warm by default)
  2. it's just an implementtion detail where we can change the way how storage is managed, for example, by using metadata storage that we already have (a linear storage)

Are there any real risks if we keep these storage ops free of charge?

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
… list preparation now)

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
@dmitry123 dmitry123 merged commit 2d70363 into devel Feb 12, 2026
8 checks passed
@dmitry123 dmitry123 deleted the fix/charge-fuel-precompiles branch February 12, 2026 12:22
dmitry123 added a commit that referenced this pull request Feb 16, 2026
* docs(contracts): fix incorrect link (#189)

* fix: migrate wasm to the latest version (#193)

* fix: migrate wasm to the latest version

* fix: update lock files

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(sdk-derive): add constructor macro and docs

* refactor(router): remove function_id attribute from generated code

Remove function_id attributes from generated impl blocks and eliminate
the unnecessary import statement. The function_id attributes are already
processed during macro expansion and don't need to be present in the
final generated code.

This change makes the generated code cleaner and removes the dependency
on an empty proc macro that was only acting as a placeholder.

* fix(constructor): fix undefined variable error in deploy method

Fix the deploy method generation that was incorrectly referencing
undefined variables (param0, param1, param2) in the else branch.
The shared generate_deploy_body method now properly handles all
parameter counts without conditional branches.

Refactor duplicate code between router and constructor macros into
a shared method in ParsedMethod for better maintainability.

* refactor(derive): unify Contract and Storage macros

Remove redundant Contract implementation and unify it with Storage macro.
Both macros now share the same underlying implementation, with Contract
for main contracts and Storage for nested structures.

BREAKING CHANGE: The old Contract macro implementation has been replaced.
Projects using #[derive(Contract)] should still work but now use the
Storage implementation under the hood.

* chore: bump to v0.4.6-dev

* feat(universal-token): universal token implementation for cross-runtime interaction (#180)

* feat(svm): extract erc20 available actions to reuse inside spl-token processing

* feat(svm): fix root Makefile; fix cargo.toml of solana-program-state-usage

* feat(universal-token): universal token: refactor; get rid of custom logic (reuse as much token2022 logic as possible); added authorization validation and significantly simplified accounts reconstruction logic, instruction type validation, action type validation; adapted unite tests from token2022; added e2e tests demonstrating token creation, initialisation, transfers etc; added e2e tests showing work through solana app (using cpi)

* feat(universal-token): support multiple universal token contracts per address when creating through solana app

* feat(universal-token): split some svm codebase for reuse

* feat(universal-token): added events logging through emit_log for all significant events

* feat(universal-token): added ABI mappings + e2e tests

* feat(universal-token): added ABI mappings

* feat(universal-token): added ABI mappings

* feat(universal-token): added ABI mappings

* feat(universal-token): added benchmark

* feat(universal-token): fix benchmark

* feat(universal-token): refactor abi params

* feat(universal-token): fix tests

* feat(universal-token): added approve and revoke ABIs

* feat(universal-token): added the rest ABI mappings, some tests, parameters ser/deser impls

* feat(universal-token): tests for approve, set-authority, burn

* feat(universal-token): tests for freeze, thaw

* feat(universal-token): tests for close_account

* feat(universal-token): small fixes

* feat(universal-token): sync params for signatures; added support for allowance

* feat(universal-token): added support for requesting account decimals

* feat(universal-token): small fixes

* feat(universal-token): disable error text output checks in e2e

* feat(universal-token): cover error text output checks in e2e with feature

* feat(universal-token): replace some expects with error mapping

* feat(universal-token): cleanup

* feat(universal-token): fix bench

* feat(universal-token): fix typo

* feat(universal-token): fix balance for bench

* feat(universal-token): change settings for benches

* feat(universal-token): cleanup

* feat(universal-token): rename

* feat(universal-token): cleanup

* feat(universal-token): more tests for svm using universal token

* added more test for universal token when working through svm cpi; fix deps problem when building solana_program example

* feat(build): add standalone constructor macro support for abi generation

- Parse #[constructor] attributes in addition to #[router]
- Extract struct definitions from constructor parameters
- Prioritize standalone constructors over router-embedded ones
- Maintain backward compatibility with existing router-only contracts

* refactor(runtime): new runtime & runtime bug fixes (#191)

* refactor(runtime): make runtime lock-free, fix issue with warming up cache from a different thread, make import-linker arc, add warmup for all evm precompiled contracts in evm-e2e tests

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: fix bug with removing fuel opcodes for runtime contracts, new execution runtime w/ wasmtime disabled, fix passing full evm e2e testing suite

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(runtime): new execution runtime, add bench pipeline, run wasmtime & rwasm tests in CI/CD, new revm-rwasm with `RwasmModule` cache, temporarly disable incepstor, add heap reset extern function, fix wasmtime warmups

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: fix running bench

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: fix running bench

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(runtime): add docs for runtime crate

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: fix benches

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: update criterion (it has baseline option)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: ignore tests in benches

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: fix running benches

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* ci: let's build w/o baseline

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(revm): fix revm inspector (now it extracts stack params that are important for explorer internal transfer indexing) (#196)

* fix(revm): fix revm inspector (now it extracts stack params that are important for explorer internal transfer indexing)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: disable blake2f tests from good coverage tests

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: bump version to v0.4.7-dev

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: loosing stack for inspector in release mode (#197)

* chore: bump version to v0.4.8-dev

* fix: add missing reset `call_id` function (#198)

* fix: missing `call_id` reset for system calls (#199)

* chore: bump version to v0.4.9-dev, update rwasm dependency (w/ disabled wasmtime parallel builds)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat: implement new runtime upgrade (#200)

* fix: bump version to v0.4.10-dev

* feat(weierstrass-curves): new crypto runtime (#201)

* feat(runtime): refactoring weierstrass curves: bls, bn254, and 256k1/r1

* feat(e2e): fixed the svm compatibility

* feat(runtime): remove redundant curve implementations, tests pass

* feat(runtime)!: refactoring SyscallWeierstrassPairingAssign

* fix(contracts/bn256): removed unused imports

* fix(evn-e2e): disabled wasmtime feature

* refactor: rename weierstrass into ecc (less misleading)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): clean up the ecc syshandlers

* fix(runtime): removed the commented snippets

* refactor(runtime): moved fp/fp2 ops away from ecc

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(runtime): reimplemented ed25519 ops in the runtime

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(runtime): move edwards, refactor ecrecover, implement u256 mul ops, remove bigmodexp, make keccak256 self-free

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(runtime): add tower fields fp1/fp2 support

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(runtime): fix warnings

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(runtime): fix compilation

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(runtime): move types into sdk, remove types crate, add new crypto crate for optimized crypto ops

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(crypto): expose mods

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(crypto): rename `MathAPI` into `CryptoAPI`

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(sdk): return types crate back, refactor hashing func, refactor crypto builtins

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(sdk): fix cycle dependency, missing features, warnings, replace hashing function with the ones from new crypto crate

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(sdk): remove impossible test

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(contracts): update ecrecover to make it work

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor: update hashing, add new tests, reimplement hashing functions for eth

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(sha256): fix bug with incorrect endianess for sha256 compress/extend, enable new sha256 precompile

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: adjust block fuel for wasm applications, move

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(e2e): fix running router tests, tiny refactored artifacts

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(runtime): new syscalls for unconstrained execution and for fd write, rename remaining host syscalls to the new naming format, add uint25 syscalls into native-api

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(runtime): add rwasm-patches, Weierstrass add, double

* refactor(runtime): benches fix

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(runtime): a giant refactoring of all syscalls to make sure all params are aligned, remove all syscalls we can't support, reformat all constants

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: incorrect number of params for tower fields

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: encoding weierstrass point result, compatibility with evm bn256 tests

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: contract/bls12381 -> revm_precompile + rwasm-patches

* fix: contracts/bn256 uses the runtime implementation for add

* fix(types): fix _ed25519_decompress and _ed25519_add signatures

* fix(contracts): add the validation for the bn254_add input data

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Co-authored-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(build): reduce docker image size and persist vol

- mv example project creation to the dockerfile
- remove redundunt tools from docker image
- fix sccache usage

* chore: migrate rwasm, revm deps to crates.io

* fix(webauthn): handle secp256r1 precompile errors properly

* fix(runtime): remove unused module param from engine.resume

* refactor(docker): simplify build and improve cache warming

- Add sdk_version input for manual builds
- Auto-extract version from Cargo.toml for tagged releases
- Improve cache warming with sccache and realistic dummy contract
- Remove unused build args and submodule checkout
- Streamline Dockerfile stages

* ci: temporary disable cache

* ci: fix version and sdk derivation for manual workflow dispatch

* ci: fix version and sdk derivation for manual workflow dispatch

* ci: fix branch or version passing

* ci: fix branch or version passing

* ci: disable cache export

* chore: bump version to the v0.4.11-dev

* fix(syscall): propagate database errors in BLOCKHASH syscall (#209)

Context: BLOCKHASH was silently converting database errors to zero hash using 'unwrap_or(B256::ZERO)', violating EVM spec which requires zero only for out-of-range blocks, not database failures.

Change: Replace 'ctx.block_hash().unwrap_or()' with 'ctx.db_mut().block_hash()?' to propagate errors. Add comprehensive test suite with FailingMockDatabase to verify error propagation.

Rationale: Database I/O errors are fatal and must surface to caller. Masking them as successful zero results breaks error handling and makes debugging impossible.

Verification: Added 4 tests covering database error propagation, future blocks, and blocks older than 256. Test 'test_block_hash_database_error_is_propagated' explicitly verifies Err() is returned for DB failures.

Risk: Existing code relying on silent error suppression will now receive Err() instead of Ok(zero). This is correct behavior per EVM spec.

* chore(deps): bump actions/download-artifact from 5 to 6 (#228)

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump actions/upload-artifact from 4 to 5 (#227)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore: remove fluentbase-cli as it's no longer needed (#230)

Remove the fluentbase-cli binary and all its dependencies. The CLI
was mainly used for contract verification, which has been moved to
the blockscout-rs/fluent-verifier service.

* chore(deps): bump actions/setup-node from 5 to 6 (#212)

Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump actions/checkout from 4 to 5 (#203)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump dawidd6/action-download-artifact from 3 to 11 (#202)

Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 3 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v3...v11)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '11'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* refactor: new gas/fuel calculation model (#217)

* fix: new gas/fuel calculation model (all gas checks happen inside revm, but we sync diff in evm runtime), don't sync refunds with evm (now they're managed inside revm runtime), interruption return total gas spent, remove `is_gas_free` check from the runtime, halt execution in-case of OOG for syscalls, new rwasm where value/stack potential vulnerability is not possible physically, remove `charge_fuel_manually` system builtin from NativeAPI (we keep it only for backward compatibility),  add e2e tests for interruption OOG checks, add new balance example

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: remove unused comment

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: update rwasm with fixed `try_consume_fuel` for wasmtime mode

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: don't use wasmtime by default for evm e2e tests

* chore: run tests in makefile on make

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: don't wipe output or return data during the interruption (#218)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(syscall): handle ed25519 decompression failure gracefully (#213)

Replace 'decompress().expect()' with pattern matching to prevent panic on invalid Y coordinates. Returns 'ExitCode::MalformedBuiltinParams' instead of crashing the VM.

Prevents DoS attacks where untrusted callers provide invalid curve points (e.g., Y=2 which is not on Ed25519 curve).

Verification: Added test with mathematically invalid Y coordinate that confirms error return instead of panic.

* fix(runtime): fix offset overflow in input/output system builtins (#223)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(syscall): prevent gas abuse in EXTCODECOPY by enforcing offset an… (#208)

* fix(syscall): prevent gas abuse in EXTCODECOPY by enforcing offset and length

Context: Gas abuse vulnerability allowed requesting small length but receiving full bytecode, bypassing gas charges. Additionally, offset parameter was ignored, causing incorrect data copies and storage mismatches.

Change:
- Syscall now applies offset and length correctly, returns exact requested bytes with zero padding
- Gas charged for requested length (not actual bytecode size) prevents abuse
- Opcode handler updated to use syscall data directly without re-applying offset
- Added comprehensive unit tests covering gas abuse scenarios and edge cases

Rationale: Enforcing offset/length in syscall prevents attackers from paying for 10 bytes but receiving full contract bytecode. EVM-compatible padding ensures correct storage values and maintains protocol semantics.

Verification:
- Unit tests validate gas charging matches requested length even when bytecode is shorter
- Integration tests 'extCodeCopyBounds' and 'ExtCodeCopyTestsParis' now pass
- Gas formula verified: base_cost (100/2600) + 3 * ceil(length/32)

Impact: Fixes critical gas abuse vector and storage corruption issues. No breaking changes to legitimate usage patterns.

* chore: fix fmt issues

* test(syscall): remove redundant code_copy test cases

* fix(syscall): add static context checks to metadata syscalls (#211)

Context: Three metadata syscalls were missing 'is_static' validation, allowing state modifications during STATICCALL contexts, which violates EVM semantics where static calls must be read-only.

Change: Added 'StateChangeDuringStaticCall' guards to:
- SYSCALL_ID_METADATA_CREATE (before 'set_code')
- SYSCALL_ID_METADATA_WRITE (before metadata modification)
- SYSCALL_ID_METADATA_STORAGE_WRITE (before 'sstore')

Rationale: Aligns metadata syscalls with existing pattern used in STORAGE_WRITE, EMIT_LOG, DESTROY_ACCOUNT, and CREATE operations. Prevents malicious contracts from persisting changes through view/pure functions.

Verification: Checks placed after parameter validation but before any journal mutations, consistent with other state-changing syscalls.

Impact: Contracts attempting metadata mutations during STATICCALL will now correctly revert with StateChangeDuringStaticCall error.

* fix(syscall): replace metadata partial write with full rewrite (#210)

Context: Previous implementation used resize() with offset+length which caused unintended truncation when writing shorter data than existing metadata, leading to silent data loss.

Change: SYSCALL_ID_METADATA_WRITE now performs full metadata replacement instead of offset-based partial writes. Offset parameter is parsed but ignored for backward compatibility.

Rationale:
- Eliminates truncation bug where resize(offset+length) would silently delete trailing bytes
- Prevents DoS via large offset values causing memory exhaustion
- Simplifies logic by removing complex offset handling
- Matches actual usage pattern (always full rewrites in practice)

Verification: Added regression test that fails on old version (offset=2 produces 4 bytes) but passes on new version (full rewrite produces 4 bytes as intended).

Impact: Calls using non-zero offset will now ignore the offset and perform full replacement. Users needing partial updates must implement read-modify-write pattern.

Co-authored-by: Dmitry Savonin <3367605+dmitry123@users.noreply.github.com>

* fix(runtime): prevent call_id collision across transaction boundaries (#214)

Change: Clear recoverable_runtimes HashMap in reset_call_id_counter() to prevent dangling runtimes from failed transactions. Added overflow protection for call_id allocation and debug_assert to detect collisions. Replaced AtomicU32 with u32 since single-threaded access is guaranteed.

Rationale: Failed transactions left runtimes in HashMap. When next transaction reset counter to 1, it could collide with dangling call_id, causing HashMap.insert() to silently overwrite old runtime. This led to memory leaks and potential security issues where resume() could execute wrong runtime context.

Verification: Added test_call_id_overflow() for overflow handling.

* audit(fix-weierstrass-decompress): fix weierstrass syscall implementations (#222)

* fix(runtime): fix weierstrass decompress, remove `bn254_decompress` as it's not-supported, fix incorrect secp256k/r1 consts and compressed key encoding format

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): fix using incorrect function for secp256r1

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: incorrect input param index (#229)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(runtime): add LRU cache with memory limits to module factory (#216)

Context: Module factory was using unbounded HashMap causing memory leaks as compiled modules accumulated without eviction

Change: Replace HashMap with schnellru LruMap for both RwasmModule and wasmtime::Module caches. Implement ModuleMemoryLimiter with SizeEstimator trait for accurate memory tracking. Switch from RwLock to Mutex since LRU requires mutable access on get()

Rationale: LRU eviction prevents unbounded memory growth while keeping hot modules cached. Generic ModuleMemoryLimiter<V> with SizeEstimator trait allows different size calculations for RwasmModule (sum of sections) vs wasmtime::Module (image_range). Mutex is faster than RwLock when all operations need write access

Verification: Added tests for memory limit enforcement, eviction ordering, and LRU access pattern updates

Impact: Memory usage capped at 1 GB per cache (2 GB total). Older unused modules will be evicted automatically.

Co-authored-by: Dmitry Savonin <3367605+dmitry123@users.noreply.github.com>

* fix(syscall): prevent frontrun attacks in metadata account creation (#204)

Context: SYSCALL_ID_METADATA_CREATE was vulnerable to frontrunning
where attacker could send funds to derived address before creation,
causing legitimate create to fail on is_empty() check.

Change: Modified collision detection in SYSCALL_ID_METADATA_CREATE
to check only code_hash and nonce, excluding balance from emptiness
check. This allows creation even if address has received funds.

Rationale: Balance-based emptiness check enables DoS via frontrunning.
Checking code_hash != KECCAK_EMPTY and nonce != 0 ensures address
has no deployed code while allowing pre-funded accounts.

Verification: Added test_metadata_create() that creates ownable
account with pre-funded balance and verifies correct derivation,
owner assignment, and metadata preservation.

Risk: Accounts can now be created at addresses with existing balance.
This is intentional and matches Ethereum CREATE2 behavior.

Co-authored-by: Dmitry Savonin <3367605+dmitry123@users.noreply.github.com>

* chore: clean evm e2e debug print (#221)

* refactor(address): rename 'calc_create4_address' to 'calc_create_metadata_address' (#205)

Context: The function name 'create4' was misleading and didn't clearly convey its purpose of deriving metadata-specific addresses.

* fix: fix compilation because of create4 function call

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): disable `write_fd` syscall since it can cause node panic (#231)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): fix sub underflow for fp1/fp2 ops (#225)

* fix(runtime): fix sub underflow for fp1/fp2 ops

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: return malformed builtin params in case of underflow inside fp1/fp2 ops

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): fix missing malformed builin params check for fp2 ops

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): remove todo from fp1 syscall

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): add check for add of the same point for weierstrass curve (#224)

* fix(runtime): add check for add of the same point for weierstrass curve

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): add mod overflow check for weierstrass add operations (to make sure underflow can't happen)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(revm): unwrap code hash after bytecode check (#232)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(revm): make sure context is clear after wasm deployment (#233)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(runtime): fix BE/LE confusion for wierstrass decompress operations (add comments, docs, and convert before doing syscall) (#234)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Co-authored-by: d1r1 <61736932+d1r1@users.noreply.github.com>

* fix(fuel): add quadratic fuel charging for EXEC input to prevent DoS (#239)

* fix: reduce FUEL_DENOM_RATE from 1000 to 20 for production

Context: Previous FUEL_DENOM_RATE of 1000 was based on outdated benchmarks. New measurements show WebAssembly instructions are ~20x faster than EVM instructions, not 1000x.

Change: Updated FUEL_DENOM_RATE constant in crates/types/src/lib.rs from 1000 to 20 for production builds. Added 'fluent-testnet' feature flag across workspace to preserve legacy rate (1000) for backward compatibility with existing testnet deployments.

Rationale: Corrects gas cost calculations to match actual performance characteristics. Feature flag prevents breaking existing testnet infrastructure during transition period.

Verification: Benchmarks confirm 20x performance ratio. Feature propagation tested through build system.

Risk: Changes gas consumption calculations for all WASM contract executions
Impact: mainnet (new default), testnet (preserved via feature flag)

BREAKING CHANGE: Production FUEL_DENOM_RATE reduced by 50x affects gas costs for all WASM contracts. Testnet preserves old behavior with fluent-testnet feature.

* feat(gas): enable upper-rounding for fuel denomination charging

Context: Deprecated record_denominated_cost and record_denominated_refund methods used floor division, causing undercharging (e.g., 25 fuel → 1 gas instead of 2).

Change: Replaced deprecated methods with direct gas recording in executor.rs. Production uses ceiling division (fuel+rate-1)/rate for costs, floor division fuel/rate for refunds. Testnet (fluent-testnet feature) preserves legacy floor division for backward compatibility. Added cfg-if dependency for conditional compilation.

Rationale: Ceiling division prevents undercharging by always rounding up gas costs. Floor division for refunds prevents over-refunding. Feature flag maintains testnet compatibility during transition.

Impact: Production charges gas accurately with ceiling rounding. Testnet unchanged with fluent-testnet feature.

* test: clarify CALL_FUEL_COST in builtin gas tests

Replace magic +1 with explicit CALL_FUEL_COST constant to show that
every WASM call instruction consumes 1 fuel unit, added by the rwasm
translator during compilation.

* feat: rebase to the new gas strategy

* fix(fuel): add quadratic fuel charging for EXEC input to prevent DoS

Previously, EXEC syscall charged constant fuel regardless of input size,
allowing attackers to submit massive payloads (up to 32MB) while paying
minimal gas. This created a DoS vector where nodes performed O(L) memory
operations nearly for free.

Changes:
- Add quadratic fuel charging for EXEC input using EVM memory expansion
  formula: fuel = (3×words + words²/512) × FUEL_DENOM_RATE
- Define FUEL_MAX_QUADRATIC_X = 1.25MB safe limit to prevent i32 overflow
- Add comprehensive test verifying gas costs match EVM Yellow Paper spec

The fix ensures gas costs scale appropriately with input size, preventing
economic mismatch between metered and actual resource consumption.

* fix(block_fuel): improve fuel calculation limits and add missing crypto costs

- Update FUEL_MAX_LINEAR_X from 256KB to 128MB with proper derivation
  documenting i32 overflow constraints in WASM runtime
- Add fuel costs for secp256r1 curve operations (ADD, DOUBLE, DECOMPRESS)
- Add fuel costs for BLS12381 DECOMPRESS and DOUBLE operations
- Handle ENTER_UNCONSTRAINED, EXIT_UNCONSTRAINED, and WRITE_FD syscalls
- Remove catch-all _ => no_fuel!() pattern for exhaustive matching

* fix(types): use MAX_WORDS in linear_fuel compile-time overflow check

The compile-time check incorrectly used x directly instead of words,
causing assertion failure with large FUEL_MAX_LINEAR_X values.
Now consistent with quadratic_fuel macro and runtime calculation.

* test(e2e): update overflow test value for new FUEL_MAX_LINEAR_X limit

Increase test value from 300KB to 135MB to exceed the new 128MB limit.

* fix: audit code maintenance fixes (#243)

* fix(syscall): validate exact address length in METADATA_ACCOUNT_OWNER

Change address length check from >= 20 to == 20 to reject malformed
input data with trailing bytes.

* fix(runtime): add #[must_use] to try_consume_fuel

Prevents callers from accidentally ignoring fuel consumption errors.

* perf(syscall): skip unnecessary resize in pad_to_be

Only resize when len > bytes.len() to avoid redundant allocations.

* docs(syscall): document argument constraints for weierstrass operations

Add input format, validation behavior, and safety requirements
for add, double, and decompress curve point functions.

* fix(precompiles): pass caller's spec to inner EthPrecompiles

Previously used SpecId::default() which could cause runtime behavior
to diverge from expected fork settings.

* refactor(runtime): move TestingStore to testing crate

TestingStore contains unwrap/unreachable patterns that are acceptable
for test infrastructure but not production code. Move it to the testing
crate where it belongs.

* fix(runtime): replace unreachable!() with exhaustive match in syscall dispatcher

Remove wildcard match arm that used unreachable!() for unknown syscalls.
The match is now exhaustive, providing compile-time guarantees that all
SysFuncIdx variants are handled.

Also handle disabled WRITE_FD syscall explicitly by returning
TrapCode::UnreachableCodeReached instead of commenting it out.

* fix(syscall): fix blake3 function naming typo and consistency

Rename syscall_hashing_blak3_handler to syscall_hashing_blake3_handler
and inner function to syscall_hashing_blake3_impl for consistency
with other hashing functions.

* fix(syscall): add endianness guard for keccak256_permute

Add compile-time checks to prevent compilation on big-endian platforms
where transmute in into_lanes_le/from_lanes_le would produce incorrect results.

* fix(security): gate calldata-based precompile dispatch to testnet-only (#240)

* fix: reduce FUEL_DENOM_RATE from 1000 to 20 for production

Context: Previous FUEL_DENOM_RATE of 1000 was based on outdated benchmarks. New measurements show WebAssembly instructions are ~20x faster than EVM instructions, not 1000x.

Change: Updated FUEL_DENOM_RATE constant in crates/types/src/lib.rs from 1000 to 20 for production builds. Added 'fluent-testnet' feature flag across workspace to preserve legacy rate (1000) for backward compatibility with existing testnet deployments.

Rationale: Corrects gas cost calculations to match actual performance characteristics. Feature flag prevents breaking existing testnet infrastructure during transition period.

Verification: Benchmarks confirm 20x performance ratio. Feature propagation tested through build system.

Risk: Changes gas consumption calculations for all WASM contract executions
Impact: mainnet (new default), testnet (preserved via feature flag)

BREAKING CHANGE: Production FUEL_DENOM_RATE reduced by 50x affects gas costs for all WASM contracts. Testnet preserves old behavior with fluent-testnet feature.

* feat(gas): enable upper-rounding for fuel denomination charging

Context: Deprecated record_denominated_cost and record_denominated_refund methods used floor division, causing undercharging (e.g., 25 fuel → 1 gas instead of 2).

Change: Replaced deprecated methods with direct gas recording in executor.rs. Production uses ceiling division (fuel+rate-1)/rate for costs, floor division fuel/rate for refunds. Testnet (fluent-testnet feature) preserves legacy floor division for backward compatibility. Added cfg-if dependency for conditional compilation.

Rationale: Ceiling division prevents undercharging by always rounding up gas costs. Floor division for refunds prevents over-refunding. Feature flag maintains testnet compatibility during transition.

Impact: Production charges gas accurately with ceiling rounding. Testnet unchanged with fluent-testnet feature.

* test: clarify CALL_FUEL_COST in builtin gas tests

Replace magic +1 with explicit CALL_FUEL_COST constant to show that
every WASM call instruction consumes 1 fuel unit, added by the rwasm
translator during compilation.

* feat: rebase to the new gas strategy

* fix(security): gate calldata-based precompile dispatch to testnet-only

Restrict UPDATE_GENESIS_AUTH and calldata-based precompile dispatch behind
'fluent-testnet' feature flag to address audit findings. This prevents:
- Arbitrary bytecode deployment if privileged key is compromised
- Non-standard precompile invocation via calldata prefix (violates EIP-1352)

Changes:
- Add feature gates to frame_init() handler
- Update fuel_to_gas for mainnet ceiling division
- Disable affected tests (multicall, update_account) on mainnet
- Add comprehensive security documentation

Related: Audit recommendation to remove functionality for mainnet

---------

Co-authored-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(features): rm fluent-testing from features list

* feat(reusable-store): move system interruption processing outside of contracts entry for evm contract (#219)

* feat(reusable-store): move rust flags into .cargo config instead of build script, new evm & modexp runtime that supports reusable stores, implemented halted frames (only for system runtimes), add serde for interruption params, add error code `CreateContractStartingWithEF`, verify input params before parsing them inside syscall (to avoid potential memory ddos attack), pass params into syscall as offset/length instead of bytes, decompose entrypoint macro for better flexiability, new debug macro (more details, alloc-free, decompoiles in release)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(reusable-store): reduce default stack size to 1mb, moved precomiles to the new system runtime (blake2f, bls12381, bn256, ecrecover, eip7951, identity, kzg, modexp, ripemd160, sha256), disable several spam tests because of stack limits

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(reusable-store): fix potential stack leak in case of `OutOfFuel` trap code (replace with exit code)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(reusable-store): fix incorrect input length for metadata copy

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: put update account test under `fluent-testnet` feature

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: remove unused assert

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Co-authored-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(deps): bump actions/checkout from 5 to 6 (#238)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(feat/svm-under-feature): put svm under feature (#237)

* feat(reusable-store): move rust flags into .cargo config instead of build script, new evm & modexp runtime that supports reusable stores, implemented halted frames (only for system runtimes), add serde for interruption params, add error code `CreateContractStartingWithEF`, verify input params before parsing them inside syscall (to avoid potential memory ddos attack), pass params into syscall as offset/length instead of bytes, decompose entrypoint macro for better flexiability, new debug macro (more details, alloc-free, decompoiles in release)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(reusable-store): reduce default stack size to 1mb, moved precomiles to the new system runtime (blake2f, bls12381, bn256, ecrecover, eip7951, identity, kzg, modexp, ripemd160, sha256), disable several spam tests because of stack limits

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(reusable-store): fix potential stack leak in case of `OutOfFuel` trap code (replace with exit code)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(reusable-store): fix incorrect input length for metadata copy

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(feat/svm-under-feature): put svm under feature

* fix: update revm-primities dep

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: update lock files

* chore: fix incorrect merge

* fix: fix missing feature for update account test

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Co-authored-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: warning fixes

* feat: add calculate_syscall_fuel function

* feat: rework import linker to syscall params

* feat: rework import linker with macros

* chore: change patcher to tmp branch

* test: turn off fuel consuming for wasmtime in evm-e2e tests

* fix(block_fuel): improve fuel calculation limits and add missing crypto costs

- Update FUEL_MAX_LINEAR_X from 256KB to 128MB with proper derivation
  documenting i32 overflow constraints in WASM runtime
- Add fuel costs for secp256r1 curve operations (ADD, DOUBLE, DECOMPRESS)
- Add fuel costs for BLS12381 DECOMPRESS and DOUBLE operations
- Handle ENTER_UNCONSTRAINED, EXIT_UNCONSTRAINED, and WRITE_FD syscalls
- Remove catch-all _ => no_fuel!() pattern for exhaustive matching

* feat: add quadratic fuel for syscalls

* chore: fix dependencies

* feat: add quadratic and fuel max consts to fluentbase types crate exports

* feat: update rwasm to current branch

* feat(v102): migrated revm to version v102 (#248)

* feat(v102): migrated revm to version v102

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(v102): disable debug print

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: add fatal execution code for OOM and other cases inside system runtime (#245)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: add veridise audit report

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* feat(sdk-derive): event derive macro for solidity-compatible logs (#246)

- #[derive(Event)] generates emit() for EVM logs
- #[indexed] for topic fields, #[anonymous] for no-signature events
- compile-time selector, runtime encoding via SolidityABI
- replaces alloy-sol-types in ERC20 example

* chore(deps): bump codecov/codecov-action from 5.5.1 to 5.5.2 (#250)

Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.5.1 to 5.5.2.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.5.1...v5.5.2)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: 5.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: building contracts w/o workspace, new universal token contract, make code storage 32-byte, tiny sdk types refactoring, remove universal token perf, a lot of universal token bug fixes, remove token2022 universal token implementation (#241)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Co-authored-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(deps): bump actions/upload-artifact from 5 to 6 (#253)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump actions/download-artifact from 6 to 7 (#254)

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(sdk-derive): add #[slot(expr)] attribute for explicit storage pos (#252)

* feat(sdk-derive): add #[slot(expr)] attribute for explicit storage positioning

Support explicit storage slot placement via #[slot(U256)] field attribute.
Fields with explicit slots bypass auto-layout and are excluded from SLOTS constant.

Also adds eip1967_slot! and erc7201_slot! compile-time helper macros.

* test(sdk-derive): fix snapshots

* fix: rollback bls12-381 to the original ethereum implementation (keep old one inside legacy.rs file) (#251)

* fix: rollback bls12-381 to the original ethereum implementation (keep old one inside legacy.rs file)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: add pre-check for gas & input size for bls12-381 precompiles

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: update lock file

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(webauthn): remove redundant check for closing quote (#256)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(evm): fix wrapping mul for evm call-opcodes (#255)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: fix syscall metadata copy potential crash (#249)

* fix: fix syscall metadata copy potential crash

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: add `is_static` check for metadata-write syscalls

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: fix bytecode hard-cap check for create/create2 syscalls

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: remove redundant `StateChangeDuringStaticCall` check

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(revm): fix metadata syscall overflow

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(fairblock): remove fairblock from repository (#260)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: fix project compilation

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: update rwasm to the latest with gas strategy fixes

* chore: update rwasm branch to the devel

* chore: small sdk fixes (#257)

* chore: small sdk fixes

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: enable EIP-7951, add more docs and comments for genesis config

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: add docs & comments, rename `RwasmRuntime` into `ContractRuntime`, remove unsused code (like `GlobalExecutor` or interruption state inside `SystemRuntime`)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: remove `inter_process_lock.rs` since it's unused

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(universal-token): universal token bug fixes (#258)

* fix(universal-token): fix incorrect token/symbol ABI encoding, fix missing `is_static` check for mutable methods, formated errors to be openzeppelin-complaint, add missing `is_zero` checks for transfers, fix incorrect error and signatures for ERC20, fix incorrect padding for event logs, fix missing storage slots for constructor, improved unit tests coverage

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(universal-token): don't charge allowance if `U256::MAX` was approved

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(universal-token): new test for checking that partial storages writes are not possible

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore(deps): bump dawidd6/action-download-artifact from 11 to 12 (#262)

Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 11 to 12.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v11...v12)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '12'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(oom): add OOM handler and e2e test for OOM case (#259)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(eip2935): bug fixes and refactoring (#263)

* fix(eip2935): fix BE encoding for input/output, migrate contract to new system runtime, add unit tests for eip2935 system contract, deprecate `system_entrypoint` macro, fix e2e unit tests for eip2935

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(eip2935): remove unused debug comment

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(eip2935): fix warning

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(runtime): fix weierstrass double crash in case of modulus overflow (#265)

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(module-factory): LRU cache replacement triggers eviction (#266)

- on_replace now allows LRU eviction instead of rejecting
- Add zero-size item rejection to prevent limit bypass
- Use saturating arithmetic to prevent overflow/underflow
- Assert max_bytes > 0 on construction
- Fix on_grow to always allow table growth
- Expand test coverage for edge cases

* feat(gas-charged-before-cold-state-operations): logic validating cold load cost upfront to prevent misuse (#267)

* feat(gas-charged-before-cold-state-operations): added logic validating cold load cost upfront to prevent missuse

* feat(gas-charged-before-cold-state-operations): rewrote to keep compatibility

* feat(gas-charged-before-cold-state-operations): gas limit fixes for e2e tests

* feat(gas-charged-before-cold-state-operations): modified gas checks for SYSCALL_ID_STORAGE_WRITE

* feat(gas-charged-before-cold-state-operations): added/fixed gas checks for SYSCALL_ID_CODE_HASH, SYSCALL_ID_CODE_COPY, SYSCALL_ID_CODE_SIZE

* feat(gas-charged-before-cold-state-operations): calculated max possible values for gas in gas pre-checks for SYSCALL_ID_CODE_COPY and SYSCALL_ID_CODE_SIZE

* feat(gas-charged-before-cold-state-operations): replaced gas pre-checks with load_account_info_skip_cold_load for CODE_COPY CODE_HASH CODE_SIZE BALANCE

* feat(gas-charged-before-cold-state-operations): gas pre-check rewrite for SYSCALL_ID_DESTROY_ACCOUNT

* feat(gas-charged-before-cold-state-operations): reimplemented gas pre-checks for SYSCALL_ID_CALL by reusing contents of load_account_delegated

* feat(gas-charged-before-cold-state-operations): unified and spread gas-checked version of Journal::load_account_delegated() accross staticcall, delegatecall and callcode

* feat(gas-charged-before-cold-state-operations): reuse process_journal_load_result and renamings; removed redundand checks for staticcall callcode and delegatecall

* chore: fix warning and import format

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix(revm): incorrect db error mapping

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Co-authored-by: Stas Stepanov <stepanovstanisl@gmail.com>
Co-authored-by: Dmitry Savonin <nwtsoas@gmail.com>

* fix: replace unsafe unreachable hint with exit code error (#268)

* fix(contracts): audit nitro contract (#261)

* fix: Missing check for certificate critical extensions in nitro precompile#17 + tests

* fix: Missing check for certificate timestamp validity in nitro precompile#16

* fix: Missing validation of attestation document for nitro precompile#15

* fix: auditor's comments

* refactor(migrate-system-contracts-to-new-runtime): migrating system contracts to new system runtime (#264)

* refactor: migrate blake2f to new system runtime v2, fix bug with crashing node with oom in case of system runtime trap

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor: migrate all evm systme contracts to new system runtime v2, fix bug with loosing return data in case of precompile error

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor: migrate nitro, oauth2, wasm, webauthn to the new system runtime

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: fix compilation warnings, update sp1-curves to the latest version

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* chore: fix nitro warning unused variable

* fix: don't allow to use fatal exit codes inside wasm contracts

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor: rename `HostTestingContext` to `TestingContextImpl` to match other naming conventions

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>

* refactor(evm): migrate evm runtime to new system runtime v2, fix compilation warnings

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* refactor(evm): remove old system runtime

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* refactor: tiny refactor of revm, add new comments/docs, move tests into separate file, don't forward balances and access lists into system contracts (not in use), tiny improvements

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix/(testnet-runtime-upgrade): fix running fluent-testnet unit tests (#270)

* fix(revm): fix revm compilation for fluent-testnet feature flag, fix update account unit tests

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: add fluent-testnet tests into makefile, add new ci/cd pipeline for running fluent-testnet unit tests

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat(module-size-is-not-explicitly-bounded): added module size check for wasm contract (#269)

* feat(module-size-is-not-explicitly-bounded): added manual checks for contract size into the contract

* feat(module-size-is-not-explicitly-bounded): added manual checks for contract size into the contract

* feat(module-size-is-not-explicitly-bounded): lost features and functionality

* feat(module-size-is-not-explicitly-bounded): fixed problem with feature propagation and small changes to text errors

* feat(module-size-is-not-explicitly-bounded): fix for feature miss for release profile

* feat(module-size-is-not-explicitly-bounded): cover test with cfg(test)

* feat(module-size-is-not-explicitly-bounded): increased RWASM_MAX_CODE_SIZE test value to pass existing tests

* feat(module-size-is-not-explicitly-bounded): increased RWASM_MAX_CODE_SIZE test value to pass existing tests

* feat(module-size-is-not-explicitly-bounded): removed redundant comment + fixed params for test_locals_amplification_find_limit

* feat(module-size-is-not-explicitly-bounded): removed testing-enabled feature

* chore: remove extra constant, e2e test fixes

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat(module-size-is-not-explicitly-bounded): fix space

* fix(wasm): use exit code instead of panic, add comment for constant

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Co-authored-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: incorrect method for extend from slice in `write_fd.rs` (#273)

* fix: incorrect method for extend from slice in `write_fd.rs`

* fix: add test proving that oauth2 crash doesn't happen

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: replace atomic u64 with u32

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore: warning fixes

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore: fix print for build script

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(runtime): add fuel metering for engine-metered precompiles (#276)

* fix(runtime): add fuel metering for engine-metered precompiles

NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME, and WEBAUTHN_VERIFIER
were executing without charging gas because they don't self-meter via
`_charge_fuel` syscall.

Changes:
- Add ENGINE_METERED_PRECOMPILES list and is_engine_metered_precompile()
- Create wasmtime engine with consume_fuel=true and syscall_fuel_params
- Pass consume_fuel flag through executor to SystemRuntime
- Set fuel limit before execution and read remaining fuel after

* fix(runtime): rm debugging logs

* fix(eip2935): enable gas for EIP-2935 system smart contract

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(universal-token): enable fuel metering for universal token

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(eip2935): fix gas charge for success branches

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore: tiny comment fixes

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(eip2935): missing denom rate multiplication

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(eip2935): fix incorrect gas charge for eip2935 contract

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(wasm): fix panic if wasm compilation runs out of fuel

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(wasm): fix panic if wasm compilation runs unexpected error

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: charge gas for warmed operations with universal token and eip2935

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: remove double gas charge for eip2935 (it's charged during access list preparation now)

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Co-authored-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore(deps): bump dawidd6/action-download-artifact from 12 to 14 (#275)

Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 12 to 14.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v12...v14)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '14'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(new-rwasm-runtime): new wasmtime runtime (#277)

* fix(runtime): add fuel metering for engine-metered precompiles

NITRO_VERIFIER, OAUTH2_VERIFIER, WASM_RUNTIME, and WEBAUTHN_VERIFIER
were executing without charging gas because they don't self-meter via
`_charge_fuel` syscall.

Changes:
- Add ENGINE_METERED_PRECOMPILES list and is_engine_metered_precompile()
- Create wasmtime engine with consume_fuel=true and syscall_fuel_params
- Pass consume_fuel flag through executor to SystemRuntime
- Set fuel limit before execution and read remaining fuel after

* fix(runtime): rm debugging logs

* refactor(runtime): integrate new rwasm runtime (bring `no_std` support into runtime crate), fix incorrect tests for block fuel calculation, disable one failing evm test, enable wasmtime for evm execution by default, tiny fixes

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore: fix several typos and compilation warnings

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: integrate new rwasm runtime into revm runtime

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore: apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Co-authored-by: d1r1 <me@d1r1.me>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* feat: switch rwasm to the latest devel version, replace tiny-keccak with migrated repository

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: migrate revm to v103 (#279)

* feat: migrate revm to v103

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* chore: update revm-rwasm and wasm to the latest version

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: replace panics with ExitCode and fix typos in write_fd (#274)

* fix: use gas constants from revm v103 (#280)

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: disable svm at workspace level, bridge compatibility with reth v1.10, new fluent binary (#281)

* fix: disable svm at workspace level, bridge compatibility with reth v1.10

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: migrate fluent node binary with genesis config into fluentbase repository

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: add docker files and makefile for building fluent binary

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: remove json feature from sol-types

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: replace reth with new version

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: add workflow for building fluent node with dry-run dispatch mode

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: remove sccache wrapper

* ci: fix release pipeline

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enforce rust toolchain 1.90.0

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enforce rust toolchain 1.92.0

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enforce rust toolchain 1.90.0

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enforce rust toolchain 1.92.0

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enforce rust toolchain 1.92.0

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enforce rust toolchain 1.92.0

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: replace slashes with dashes for version

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: fix incorrect artifact path

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: fix missing gpg signature for fluent binary

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: enable apple aarch64 and amd64 builds

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: disable apple aarch64 and amd64 builds for now

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* feat: download genesis files from github releases, remove genesis from repo

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: tiny fixes for ci and docker builds

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix(reqwest-native-tls): enable native tls for reqwest (#283)

* fix: enable native tls for reqwest

* chore: change println logs for fluent

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: fix missing openssl dev for amd64 (#284)

* ci: fix missing openssl dev for amd64

* ci: fix openssl install

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: fix openssl install

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: replace native-tls with rustls

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: add missing pkgconfig

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: add docker pipeline, use native-tls for reqwest

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: downgrade reqwest to use ring tls instead of aws

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: fix incorrect build directory

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* ci: fix missing fluent artifact to be stored inside release

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

* fix: fix running benches

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>

---------

Signed-off-by: Dmitry Savonin <nwtsoas@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Dmitry Savonin <dmitry@fluentlabs.xyz>
Co-authored-by: Jaye Turner <jayeturnerjatu@gmail.com>
Co-authored-by: d1r1 <me@d1r1.me>
Co-authored-by: d1r1 <61736932+d1r1@users.noreply.github.com>
Co-authored-by: Stanislav Stepanov <105381376+bfdays@users.noreply.github.com>
Co-authored-by: chillhacker <85485830+chillhacker@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stanislav Stepanov <stanislav@fluentlabs.xyz>
Co-authored-by: easy <shinbogdan@gmail.com>
Co-authored-by: Stanislav Stepanov <truebfday@gmail.com>
Co-authored-by: Stas Stepanov <stepanovstanisl@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Emirhan Yıldız <yildiz.emrhn@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants