From 84f9db9ca240d19a587558abc0d1c4309b464766 Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Fri, 2 Oct 2026 19:04:11 +0900 Subject: [PATCH 1/5] =?UTF-8?q?fix(executor):=20require=20free=20memory=20?= =?UTF-8?q?before=20exec=5Fprompt=20=F0=9F=94=92=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fail with out-of-memory when less than EXEC_PROMPT_MIN_SPACE (128 MiB) of the contract budget is left, as web calls already do --- executor/codegen/data/internal-constants.json | 1 + executor/crates/common/src/internal_constants.rs | 1 + executor/src/wasi/genlayer_sdk/mod.rs | 8 ++++++++ 3 files changed, 10 insertions(+) diff --git a/executor/codegen/data/internal-constants.json b/executor/codegen/data/internal-constants.json index a3185832..4c2c826b 100644 --- a/executor/codegen/data/internal-constants.json +++ b/executor/codegen/data/internal-constants.json @@ -28,6 +28,7 @@ "vm_recursion": 512, "web_request_min_space": 65536, "web_render_min_space": 134217728, + "exec_prompt_min_space": 134217728, "max_fds": 1024, "max_runners": 128, "wasm_call_depth": 1024, diff --git a/executor/crates/common/src/internal_constants.rs b/executor/crates/common/src/internal_constants.rs index 993a03af..cabc1335 100644 --- a/executor/crates/common/src/internal_constants.rs +++ b/executor/crates/common/src/internal_constants.rs @@ -23,6 +23,7 @@ pub mod top_limits { pub const VM_RECURSION: u32 = 512; pub const WEB_REQUEST_MIN_SPACE: u32 = 65536; pub const WEB_RENDER_MIN_SPACE: u32 = 134217728; + pub const EXEC_PROMPT_MIN_SPACE: u32 = 134217728; pub const MAX_FDS: u32 = 1024; pub const MAX_RUNNERS: u32 = 128; pub const WASM_CALL_DEPTH: u32 = 1024; diff --git a/executor/src/wasi/genlayer_sdk/mod.rs b/executor/src/wasi/genlayer_sdk/mod.rs index d1de2707..0cfac600 100644 --- a/executor/src/wasi/genlayer_sdk/mod.rs +++ b/executor/src/wasi/genlayer_sdk/mod.rs @@ -951,6 +951,14 @@ impl ContextVFS<'_> { return Err(generated::types::Errno::Inval.into()); } + let space_left = self.context.limiter.get_remaining_memory(); + if space_left < top_limits::EXEC_PROMPT_MIN_SPACE { + log_warn!(@user, space_left = space_left; "not enough memory for exec prompt"); + return Err(generated::types::Error::trap(crate::anyhow_to_wasmtime( + rt::errors::Error::vm(abi::consts::VmError::out_of().memory().val()).into(), + ))); + } + let host_remaining_time_fee_gen_wei = self .context .data From c476c2b4b8d10f50e79db328db1171b087a5ffdc Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Fri, 2 Oct 2026 20:54:17 +0900 Subject: [PATCH 2/5] =?UTF-8?q?test(executor):=20bootstrap=20by=20repointi?= =?UTF-8?q?ng=20the=20code=20slot=20=E2=9C=85=20-=20`finish`=20sets=20the?= =?UTF-8?q?=20root=20`code=5Fslot`=20to=20the=20slot=20`push=5Fcode`=20fil?= =?UTF-8?q?led=20instead=20of=20copying=20the=20code=20into=20the=20defaul?= =?UTF-8?q?t=20code=20slot;=20writes=20aimed=20at=20the=20default=20code?= =?UTF-8?q?=20slot=20land=20in=20that=20slot=20-=20When=20the=20default=20?= =?UTF-8?q?code=20slot=20is=20locked,=20the=20pushed=20code=20slot=20is=20?= =?UTF-8?q?locked=20too?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/bootstrapper/bootstrapper.0.hash | 2 +- .../bootstrapper/bootstrapper.0_0.hash | 2 +- .../bootstrapper/bootstrapper.0_0_0.hash | 2 +- .../bootstrapper/bootstrapper.0_0_0_0.hash | 2 +- .../bootstrapper/bootstrapper.0_0_0_0_0.hash | 2 +- .../bootstrapper.0_0_0_0_0_0.hash | 2 +- .../storage/bootstrapper/bootstrapper.jsonnet | 2 +- .../storage/bootstrapper/bootstrapper.py | 32 +++++++++++-------- 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/tests/integration/storage/bootstrapper/bootstrapper.0.hash b/tests/integration/storage/bootstrapper/bootstrapper.0.hash index 8ce60f5c..89bac9fc 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.0.hash +++ b/tests/integration/storage/bootstrapper/bootstrapper.0.hash @@ -1 +1 @@ -K/8QAglun1vEpQIY4wuAmhd0eeTLjoyyYu6CGkNapII= +bHp5Cw7n6xVZTxpXZ90QKI9QWOCkY5LMCf7JDDD/dIM= diff --git a/tests/integration/storage/bootstrapper/bootstrapper.0_0.hash b/tests/integration/storage/bootstrapper/bootstrapper.0_0.hash index 3c2b974f..520c2123 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.0_0.hash +++ b/tests/integration/storage/bootstrapper/bootstrapper.0_0.hash @@ -1 +1 @@ -pNSr7iF5woowsByVP0kwLFPgsuypy/wlXjlUOOIYfgM= +37dzXTgDVTV4BHAJOKgq5+ukkmdObZAw7gpnCFH9jlo= diff --git a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0.hash b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0.hash index 367bfd22..57442a7d 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0.hash +++ b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0.hash @@ -1 +1 @@ -uq9i8BxfkuhhWYhYvsAsZYvHKsbMAtA4JkEJg6cq6/0= +rzseHXRlKCYTjZzpwPy+hbt24e9JbtR83Gd6yoFQvhw= diff --git a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0.hash b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0.hash index 0b5a2f0a..1326cba2 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0.hash +++ b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0.hash @@ -1 +1 @@ -RL6N5zAHJ8vPkIJ2SDAn1X3m8862bjUtQtEgmtLyivQ= +dI8Um0bRXJaC+dbfYPkh2DsEcb5qs1rI2/5gJq12tSU= diff --git a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0.hash b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0.hash index c8bf89b4..42edec96 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0.hash +++ b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0.hash @@ -1 +1 @@ -UUuSzGtnBF/bwOyCz9s1IxvTPApNaC6g4K/LsZ0RP5I= +drGVwvoLUMdK05wgcMPXpXE2jw09GDrUcvEwFlsjsvs= diff --git a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0_0.hash b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0_0.hash index 8a177357..c2e04a0d 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0_0.hash +++ b/tests/integration/storage/bootstrapper/bootstrapper.0_0_0_0_0_0.hash @@ -1 +1 @@ -wAzDfxLZFzASX8qfb0VtOwtEiRnXnmLwd9XpQLuOrvg= +3cOLqwQVKcIPTPLh1dzTbqFK2DR1h7AV0eq1ssDVCV0= diff --git a/tests/integration/storage/bootstrapper/bootstrapper.jsonnet b/tests/integration/storage/bootstrapper/bootstrapper.jsonnet index add3973f..6e06d547 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.jsonnet +++ b/tests/integration/storage/bootstrapper/bootstrapper.jsonnet @@ -35,7 +35,7 @@ local contract_instance_slot = 'e1ae23412792df6b6a98fb7c9839701fb8b02b6fc7ed0228 {"": "push_code", "args": [code[len(code)//2:].encode()]} |||, }, - // finish bootstrapping (copies code from temp slot to code slot) + // finish bootstrapping (points the root code slot at the pushed code) s { code: null, calldata: ||| diff --git a/tests/integration/storage/bootstrapper/bootstrapper.py b/tests/integration/storage/bootstrapper/bootstrapper.py index 7dc01e05..5b3feb9e 100644 --- a/tests/integration/storage/bootstrapper/bootstrapper.py +++ b/tests/integration/storage/bootstrapper/bootstrapper.py @@ -20,12 +20,14 @@ gl.vm.ABI.root_offsets.MAJOR ) -SPECIAL_SLOTS = [gl.storage.ROOT_SLOT_ID, CODE_SLOT, LOCKED_SLOT] +SPECIAL_SLOTS = [gl.storage.ROOT_SLOT_ID, LOCKED_SLOT] SPECIAL_SLOTS_TWINS = { slt: VACANT_SLOT.indirect(i).id for i, slt in enumerate(SPECIAL_SLOTS) } +CODE_TARGET_SLOT = VACANT_SLOT.indirect(len(SPECIAL_SLOTS)).id + def get_twin_vla(slot_id: bytes) -> gl.storage.VLA[gl.types.u8]: return gl.storage.cast_slot( @@ -72,17 +74,19 @@ def write(self, data: list[typing.Any]): """ for slot, offset, slice in data: - if slot in SPECIAL_SLOTS_TWINS.values(): - gl.vm.UserError.immediate('Cannot write to the temporary code slots') + if slot in SPECIAL_SLOTS_TWINS.values() or slot == CODE_TARGET_SLOT: + gl.vm.UserError.immediate('Cannot write to the temporary slots') if twin := SPECIAL_SLOTS_TWINS.get(slot): write_to_twin(twin, offset, slice) else: + if slot == CODE_SLOT: + slot = CODE_TARGET_SLOT gl.storage.Root.MANAGER.get_store_slot(slot).write(offset, slice) @gl.public.write def push_code(self, code: bytes): """ - Push code to the contract. This will write the code to a temporary slot, which can be copied to the code slot in the ``finish`` method. + Push code to the contract. This will append the code to a slot, which the ``finish`` method makes the code slot. :param code: code to push @@ -91,19 +95,14 @@ def push_code(self, code: bytes): otherwise the contract may be left in undefined state """ - twin_slot_id = SPECIAL_SLOTS_TWINS[CODE_SLOT] - code_twin_vla = get_twin_vla(twin_slot_id) - code_vla = gl.storage.cast_slot( - gl.storage.VLA[gl.types.u8], gl.storage.Root.MANAGER, twin_slot_id, 4 - ) - code_vla.extend(code) - new_len = len(code_vla) - code_twin_vla.set_length(new_len + 4) + gl.storage.cast_slot( + gl.storage.VLA[gl.types.u8], gl.storage.Root.MANAGER, CODE_TARGET_SLOT, 0 + ).extend(code) @gl.public.write def finish(self): """ - Finish bootstrapping. This will copy the code from the temporary slot to the code slot and make it available for execution. + Finish bootstrapping. This will copy the root and locked slots from their temporary slots and point the root at the pushed code, making it available for execution. """ BUF_SIZE = 65536 for dst, src in SPECIAL_SLOTS_TWINS.items(): @@ -114,3 +113,10 @@ def finish(self): chunk_size = min(BUF_SIZE, copy_len - offset) data = vla_from.slot().read(vla_from.data_offset() + offset, chunk_size) to.write(offset, data) + + root = gl.storage.Root.get() + code_target = int.from_bytes(CODE_TARGET_SLOT, 'little') + root.code_slot = code_target + locked = root.locked_slots.get() + if int.from_bytes(CODE_SLOT, 'little') in locked: + locked.append(code_target) From be2fe81793a27376427a6a42f58f76a5d506e2b4 Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Fri, 2 Oct 2026 22:16:06 +0900 Subject: [PATCH 3/5] =?UTF-8?q?build(deps):=20bump=20wasmtime=20to=2048.0.?= =?UTF-8?q?3=20=E2=AC=86=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rebase the wasmtime patch series onto v48.0.3, which fixes GHSA-jqpg-j7w6-42pr and GHSA-m63x-6p34-q65x; the executor reaches neither, as it runs without fuel and outside the component model - The stack-limit restore in catch blocks now follows upstream's new fuel reload; the patches are otherwise unchanged --- .git-third-party/manifest.json | 12 ++-- .../{r6518c8dxghpkhsj => fvfcbfxe3ng3djg8} | 8 +-- .../{zsjxmza3dms0hr10 => mgz066ws46rvhghv} | 2 +- .../{6xy06vg0d71czwmm => nwdw669v5p3aamta} | 18 +++--- .../{gbm0xv16dc1fs2km => wyqzzn2hxndgbxbx} | 26 ++++---- .../{4rr93pqjtwm5m701 => x77t41kns34hzzhb} | 2 +- executor/Cargo.lock | 62 +++++++++---------- 7 files changed, 65 insertions(+), 65 deletions(-) rename .git-third-party/patches/executor/third-party/wasmtime/{r6518c8dxghpkhsj => fvfcbfxe3ng3djg8} (96%) rename .git-third-party/patches/executor/third-party/wasmtime/{zsjxmza3dms0hr10 => mgz066ws46rvhghv} (99%) rename .git-third-party/patches/executor/third-party/wasmtime/{6xy06vg0d71czwmm => nwdw669v5p3aamta} (99%) rename .git-third-party/patches/executor/third-party/wasmtime/{gbm0xv16dc1fs2km => wyqzzn2hxndgbxbx} (99%) rename .git-third-party/patches/executor/third-party/wasmtime/{4rr93pqjtwm5m701 => x77t41kns34hzzhb} (98%) diff --git a/.git-third-party/manifest.json b/.git-third-party/manifest.json index fee3a719..45c210b8 100644 --- a/.git-third-party/manifest.json +++ b/.git-third-party/manifest.json @@ -2,13 +2,13 @@ "repos": { "executor/third-party/wasmtime": { "url": "https://github.com/bytecodealliance/wasmtime.git", - "commit": "7bac2c2775808aaec5d4aa5627a5e447b51102cf", + "commit": "ebf20ab7cbf35fa3fbd8202562017fda6a541021", "patches": [ - "gbm0xv16dc1fs2km", - "zsjxmza3dms0hr10", - "4rr93pqjtwm5m701", - "r6518c8dxghpkhsj", - "6xy06vg0d71czwmm" + "wyqzzn2hxndgbxbx", + "mgz066ws46rvhghv", + "x77t41kns34hzzhb", + "fvfcbfxe3ng3djg8", + "nwdw669v5p3aamta" ], "submodules": [] }, diff --git a/.git-third-party/patches/executor/third-party/wasmtime/r6518c8dxghpkhsj b/.git-third-party/patches/executor/third-party/wasmtime/fvfcbfxe3ng3djg8 similarity index 96% rename from .git-third-party/patches/executor/third-party/wasmtime/r6518c8dxghpkhsj rename to .git-third-party/patches/executor/third-party/wasmtime/fvfcbfxe3ng3djg8 index 9de42312..646f8811 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/r6518c8dxghpkhsj +++ b/.git-third-party/patches/executor/third-party/wasmtime/fvfcbfxe3ng3djg8 @@ -45,10 +45,10 @@ index 80dcb86..342489f 100644 #[repr(C)] diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs -index fe1b8d8..7dea98f 100644 +index dbe4e3f..266938b 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs -@@ -5218,9 +5218,9 @@ impl FuncEnvironment<'_> { +@@ -5228,9 +5228,9 @@ impl FuncEnvironment<'_> { self.fuel_save_from_var(builder); } @@ -76,10 +76,10 @@ index 1511a65..5669ddb 100644 /// Creates a new cranelift `Signature` with no wasm params/results for the /// given calling convention. diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index 0a02c4d..772f112 100644 +index 0e12a52..d4c2afd 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs -@@ -4764,6 +4764,6 @@ fn float_op_unreachable_check(environ: &mut FuncEnvironment<'_>, builder: &mut F +@@ -4765,6 +4765,6 @@ fn float_op_unreachable_check(environ: &mut FuncEnvironment<'_>, builder: &mut F if environ.are_floats_enabled() { return false; } diff --git a/.git-third-party/patches/executor/third-party/wasmtime/zsjxmza3dms0hr10 b/.git-third-party/patches/executor/third-party/wasmtime/mgz066ws46rvhghv similarity index 99% rename from .git-third-party/patches/executor/third-party/wasmtime/zsjxmza3dms0hr10 rename to .git-third-party/patches/executor/third-party/wasmtime/mgz066ws46rvhghv index b66b8435..ff010451 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/zsjxmza3dms0hr10 +++ b/.git-third-party/patches/executor/third-party/wasmtime/mgz066ws46rvhghv @@ -17,7 +17,7 @@ store after execution finishes. 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs -index b0a53c5..c657833 100644 +index ad9f759..94da452 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs @@ -1462,7 +1462,9 @@ use std::collections::BTreeMap; diff --git a/.git-third-party/patches/executor/third-party/wasmtime/6xy06vg0d71czwmm b/.git-third-party/patches/executor/third-party/wasmtime/nwdw669v5p3aamta similarity index 99% rename from .git-third-party/patches/executor/third-party/wasmtime/6xy06vg0d71czwmm rename to .git-third-party/patches/executor/third-party/wasmtime/nwdw669v5p3aamta index 0160cdac..42eddc7d 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/6xy06vg0d71czwmm +++ b/.git-third-party/patches/executor/third-party/wasmtime/nwdw669v5p3aamta @@ -158,7 +158,7 @@ index afa5ab6..5f3fdee 100644 let mut validator = validator.into_validator(mem::take(&mut compiler.cx.validator_allocations)); diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs -index 7dea98f..ee471b7 100644 +index 266938b..dadf341 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -52,6 +52,14 @@ pub(crate) enum Extension { @@ -197,7 +197,7 @@ index 7dea98f..ee471b7 100644 stack_switching_handler_list_buffer: None, stack_switching_values_buffer: None, -@@ -5144,25 +5149,42 @@ impl FuncEnvironment<'_> { +@@ -5154,25 +5159,42 @@ impl FuncEnvironment<'_> { self.update_state_slot_vmctx(builder); @@ -256,7 +256,7 @@ index 7dea98f..ee471b7 100644 // Additionally we initialize `fuel_var` if it will get used. if self.tunables.consume_fuel { -@@ -5225,22 +5247,44 @@ impl FuncEnvironment<'_> { +@@ -5235,22 +5257,44 @@ impl FuncEnvironment<'_> { } pub fn before_return(&mut self, builder: &mut FunctionBuilder) { @@ -317,7 +317,7 @@ index 7dea98f..ee471b7 100644 pub fn translate_cont_bind( diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index 772f112..a7bf09c 100644 +index d4c2afd..fdff6a5 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs @@ -368,22 +368,17 @@ pub fn translate_operator( @@ -1091,15 +1091,15 @@ index 772f112..a7bf09c 100644 let (a, b) = env.stacks.pop2(); let bitcast_a = optionally_bitcast_vector(a, needed_type, builder); let bitcast_b = optionally_bitcast_vector(b, needed_type, builder); -@@ -4720,6 +4848,7 @@ fn create_catch_block( - let block = builder.create_block(); +@@ -4721,6 +4849,7 @@ fn create_catch_block( let exn_ref = builder.append_block_param(block, exn_payload_ty); builder.switch_to_block(block); + environ.on_catch_block_entry(builder); + environ.restore_semantic_stack_limits_after_exception(builder); debug_assert!(exn_ref_ty.bits() <= exn_payload_ty.bits()); let exn_ref = if exn_ref_ty.bits() < exn_payload_ty.bits() { builder.ins().ireduce(exn_ref_ty, exn_ref) -@@ -4760,7 +4889,10 @@ fn create_catch_block( +@@ -4761,7 +4890,10 @@ fn create_catch_block( Ok(block) } @@ -1281,7 +1281,7 @@ index bd8f42f..b90a75d 100644 memory_init_cow, other.memory_init_cow, diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs -index c657833..b129bed 100644 +index 94da452..30f7016 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs @@ -1509,7 +1509,10 @@ impl<'a, T: 'static> StoreContextMut<'a, T> { @@ -1342,7 +1342,7 @@ index f7ab83b..cad9d79 100644 continuations: Vec::new(), instances: TryPrimaryMap::new(), diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs -index 4509bc4..a086355 100644 +index 44cee91..781007d 100644 --- a/crates/wasmtime/src/runtime/vm/vmcontext.rs +++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs @@ -721,6 +721,14 @@ const _: () = { diff --git a/.git-third-party/patches/executor/third-party/wasmtime/gbm0xv16dc1fs2km b/.git-third-party/patches/executor/third-party/wasmtime/wyqzzn2hxndgbxbx similarity index 99% rename from .git-third-party/patches/executor/third-party/wasmtime/gbm0xv16dc1fs2km rename to .git-third-party/patches/executor/third-party/wasmtime/wyqzzn2hxndgbxbx index c10b52b9..406e6445 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/gbm0xv16dc1fs2km +++ b/.git-third-party/patches/executor/third-party/wasmtime/wyqzzn2hxndgbxbx @@ -35,10 +35,10 @@ Subject: [PATCH] feat: rebase genvm 28 files changed, 466 insertions(+), 52 deletions(-) diff --git a/Cargo.toml b/Cargo.toml -index 83b09c9..4560d95 100644 +index 69b668d..36c85f5 100644 --- a/Cargo.toml +++ b/Cargo.toml -@@ -375,18 +375,18 @@ wit-bindgen = { version = "0.60.0", default-features = false } +@@ -370,18 +370,18 @@ wit-bindgen = { version = "0.60.0", default-features = false } wit-bindgen-rust-macro = { version = "0.60.0", default-features = false } # wasm-tools family: @@ -181,7 +181,7 @@ index 5f3fdee..afa5ab6 100644 let mut validator = validator.into_validator(mem::take(&mut compiler.cx.validator_allocations)); diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs -index 64e9642..fe1b8d8 100644 +index b72e825..dbe4e3f 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -211,6 +211,9 @@ pub struct FuncEnvironment<'module_environment> { @@ -204,7 +204,7 @@ index 64e9642..fe1b8d8 100644 stack_switching_handler_list_buffer: None, stack_switching_values_buffer: None, -@@ -3444,6 +3450,7 @@ impl FuncEnvironment<'_> { +@@ -3445,6 +3451,7 @@ impl FuncEnvironment<'_> { sig_ref: ir::SigRef, call_args: &[ir::Value], ) -> WasmResult<()> { @@ -212,7 +212,7 @@ index 64e9642..fe1b8d8 100644 Call::new_tail(builder, self, srcloc).direct_call(callee_index, sig_ref, call_args)?; Ok(()) } -@@ -3458,6 +3465,7 @@ impl FuncEnvironment<'_> { +@@ -3459,6 +3466,7 @@ impl FuncEnvironment<'_> { callee: ir::Value, call_args: &[ir::Value], ) -> WasmResult<()> { @@ -220,7 +220,7 @@ index 64e9642..fe1b8d8 100644 Call::new_tail(builder, self, srcloc).indirect_call( table_index, ty_index, -@@ -3476,6 +3484,7 @@ impl FuncEnvironment<'_> { +@@ -3477,6 +3485,7 @@ impl FuncEnvironment<'_> { callee: ir::Value, call_args: &[ir::Value], ) -> WasmResult<()> { @@ -228,7 +228,7 @@ index 64e9642..fe1b8d8 100644 Call::new_tail(builder, self, srcloc).call_ref(sig_ref, callee, call_args)?; Ok(()) } -@@ -5135,6 +5144,26 @@ impl FuncEnvironment<'_> { +@@ -5145,6 +5154,26 @@ impl FuncEnvironment<'_> { self.update_state_slot_vmctx(builder); @@ -255,7 +255,7 @@ index 64e9642..fe1b8d8 100644 // Additionally we initialize `fuel_var` if it will get used. if self.tunables.consume_fuel { self.fuel_function_entry(builder); -@@ -5177,6 +5206,43 @@ impl FuncEnvironment<'_> { +@@ -5187,6 +5216,43 @@ impl FuncEnvironment<'_> { self.isa.triple().architecture == target_lexicon::Architecture::X86_64 } @@ -299,7 +299,7 @@ index 64e9642..fe1b8d8 100644 pub fn translate_cont_bind( &mut self, builder: &mut FunctionBuilder<'_>, -@@ -5334,6 +5400,7 @@ impl FuncEnvironment<'_> { +@@ -5344,6 +5410,7 @@ impl FuncEnvironment<'_> { } pub fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) { @@ -321,7 +321,7 @@ index 50c0b26..1511a65 100644 /// Creates a new cranelift `Signature` with no wasm params/results for the /// given calling convention. diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index 7de3ab3..5c33b47 100644 +index dcb41ff..925a145 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs @@ -1071,120 +1071,145 @@ pub fn translate_operator( @@ -830,7 +830,7 @@ index 7de3ab3..5c33b47 100644 } /// Generate a `jump` instruction, but first cast all 128-bit vector values to I8X16 if they -@@ -4669,3 +4758,11 @@ fn create_catch_block( +@@ -4670,3 +4759,11 @@ fn create_catch_block( Ok(block) } @@ -1129,7 +1129,7 @@ index f3f0a3f..698ffc6 100644 fn _assertions_lib() { diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs -index d847800..b0a53c5 100644 +index b9520fd..ad9f759 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs @@ -1446,6 +1446,32 @@ impl Func { @@ -1312,7 +1312,7 @@ index a081654..9911f9d 100644 impl fmt::Debug for Store { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs -index 9324674..4509bc4 100644 +index 0a9c934..44cee91 100644 --- a/crates/wasmtime/src/runtime/vm/vmcontext.rs +++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs @@ -810,8 +810,10 @@ impl Default for VMStoreContext { diff --git a/.git-third-party/patches/executor/third-party/wasmtime/4rr93pqjtwm5m701 b/.git-third-party/patches/executor/third-party/wasmtime/x77t41kns34hzzhb similarity index 98% rename from .git-third-party/patches/executor/third-party/wasmtime/4rr93pqjtwm5m701 rename to .git-third-party/patches/executor/third-party/wasmtime/x77t41kns34hzzhb index c387d36a..baff824c 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/4rr93pqjtwm5m701 +++ b/.git-third-party/patches/executor/third-party/wasmtime/x77t41kns34hzzhb @@ -16,7 +16,7 @@ place, so trapping on them broke real numpy code paths. 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index 5c33b47..0a02c4d 100644 +index 925a145..0e12a52 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs @@ -1804,7 +1804,8 @@ pub fn translate_operator( diff --git a/executor/Cargo.lock b/executor/Cargo.lock index 414f259d..2d18e54d 100644 --- a/executor/Cargo.lock +++ b/executor/Cargo.lock @@ -456,21 +456,21 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-entity", "wasmtime-internal-core", @@ -478,7 +478,7 @@ dependencies = [ [[package]] name = "cranelift-bitset" -version = "0.135.1" +version = "0.135.3" dependencies = [ "serde", "serde_derive", @@ -487,7 +487,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.135.1" +version = "0.135.3" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -516,7 +516,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -527,18 +527,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.135.1" +version = "0.135.3" [[package]] name = "cranelift-control" -version = "0.135.1" +version = "0.135.3" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-bitset", "serde", @@ -548,7 +548,7 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-codegen", "hashbrown 0.17.1", @@ -559,11 +559,11 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.135.1" +version = "0.135.3" [[package]] name = "cranelift-native" -version = "0.135.1" +version = "0.135.3" dependencies = [ "cranelift-codegen", "libc", @@ -572,7 +572,7 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.135.1" +version = "0.135.3" [[package]] name = "crc32fast" @@ -1780,7 +1780,7 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "48.0.1" +version = "48.0.3" dependencies = [ "cranelift-bitset", "log", @@ -1790,7 +1790,7 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "48.0.1" +version = "48.0.3" dependencies = [ "proc-macro2", "quote", @@ -2719,7 +2719,7 @@ dependencies = [ [[package]] name = "wasmtime" -version = "48.0.1" +version = "48.0.3" dependencies = [ "addr2line 0.26.0", "async-trait", @@ -2759,7 +2759,7 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "48.0.1" +version = "48.0.3" dependencies = [ "anyhow", "cpp_demangle", @@ -2788,7 +2788,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-cache" -version = "48.0.1" +version = "48.0.3" dependencies = [ "base64", "directories-next", @@ -2806,7 +2806,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "48.0.1" +version = "48.0.3" dependencies = [ "anyhow", "proc-macro2", @@ -2819,11 +2819,11 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-util" -version = "48.0.1" +version = "48.0.3" [[package]] name = "wasmtime-internal-core" -version = "48.0.1" +version = "48.0.3" dependencies = [ "anyhow", "hashbrown 0.17.1", @@ -2833,7 +2833,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-cranelift" -version = "48.0.1" +version = "48.0.3" dependencies = [ "cranelift-codegen", "cranelift-control", @@ -2857,7 +2857,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-fiber" -version = "48.0.1" +version = "48.0.3" dependencies = [ "cc", "libc", @@ -2869,7 +2869,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "48.0.1" +version = "48.0.3" dependencies = [ "cc", "wasmtime-internal-versioned-export-macros", @@ -2877,7 +2877,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "48.0.1" +version = "48.0.3" dependencies = [ "libc", "wasmtime-internal-core", @@ -2886,7 +2886,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-unwinder" -version = "48.0.1" +version = "48.0.3" dependencies = [ "cranelift-codegen", "log", @@ -2896,7 +2896,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "48.0.1" +version = "48.0.3" dependencies = [ "proc-macro2", "quote", @@ -2905,7 +2905,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "48.0.1" +version = "48.0.3" dependencies = [ "anyhow", "bitflags", @@ -2926,7 +2926,7 @@ dependencies = [ [[package]] name = "wiggle" -version = "48.0.1" +version = "48.0.3" dependencies = [ "bitflags", "thiserror 2.0.19", @@ -2938,7 +2938,7 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "48.0.1" +version = "48.0.3" dependencies = [ "heck", "proc-macro2", @@ -2950,7 +2950,7 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "48.0.1" +version = "48.0.3" dependencies = [ "proc-macro2", "quote", From 3cd91d26d7cf4d1a4e5de096dcb71ad333dd0c07 Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Fri, 2 Oct 2026 22:16:18 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix(executor):=20let=20a=20zero-budget=20ex?= =?UTF-8?q?act=20key=20shadow=20internal=20wildcards=20=F0=9F=90=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Consensus resolves internal allocation keys by presence, so an exact key with no budget left still wins over a funded `call_key` wildcard and its phase still decides; emission then fails with `out_of message_fee allocation_budget internal` without charging the wildcard - External messages keep skipping zero-budget chain keys and fall back as before Co-authored-by: Edgars --- executor/src/wasi/genlayer_sdk/message.rs | 9 ++-- executor/src/wasi/genlayer_sdk/tests.rs | 57 +++++++++++++---------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/executor/src/wasi/genlayer_sdk/message.rs b/executor/src/wasi/genlayer_sdk/message.rs index 8eed67e0..8b7cd4db 100644 --- a/executor/src/wasi/genlayer_sdk/message.rs +++ b/executor/src/wasi/genlayer_sdk/message.rs @@ -5,11 +5,6 @@ fn allocation_match_priority( recipient: calldata::Address, call_key: genvm_modules_interfaces::abi_stub::CallKey, ) -> Option { - // Consensus resolves only keys with a nonzero budget - if node.recipient.is_some() && node.budget.is_some_and(|budget| budget.is_zero()) { - return None; - } - let recipient_priority = match node.recipient { Some(candidate) if candidate == recipient => 0, Some(_) => return None, @@ -71,6 +66,10 @@ pub(super) fn external_allocation_candidates( genvm_modules_interfaces::fees::MessageAllocationNodeParams::External(_) ) }) + // Consensus resolves external chain keys only with a nonzero budget + .filter(|(_, node)| { + node.recipient.is_none() || node.budget.is_none_or(|budget| !budget.is_zero()) + }) .filter_map(|(index, node)| { allocation_match_priority(node, recipient, call_key).map(|priority| (priority, index)) }) diff --git a/executor/src/wasi/genlayer_sdk/tests.rs b/executor/src/wasi/genlayer_sdk/tests.rs index 82b5aae3..e6e629b4 100644 --- a/executor/src/wasi/genlayer_sdk/tests.rs +++ b/executor/src/wasi/genlayer_sdk/tests.rs @@ -134,7 +134,7 @@ fn internal_allocation_prefers_exact_key_over_earlier_wildcard() { } #[test] -fn internal_allocation_skips_zero_budget_chain_keys() { +fn internal_zero_remaining_exact_shadows_funded_wildcard() { let recipient = calldata::Address::from([7; 20]); let call_key = genvm_modules_interfaces::abi_stub::CallKey([8; 32]); let mut wildcard = internal_message_allocation(); @@ -151,21 +151,25 @@ fn internal_allocation_skips_zero_budget_chain_keys() { recipient, call_key, ) - .expect("wildcard allocation should match after skipping zero-budget exact"); - assert_eq!(matched, 0); + .expect("the stored exact key must shadow the funded wildcard"); + assert_eq!(matched, 1); nodes[0].budget = Some(U256::zero()); - assert!(resolve_internal_allocation( - &nodes, - genvm_modules_interfaces::On::Finalized, - recipient, - call_key, - ) - .is_none()); + assert_eq!( + resolve_internal_allocation( + &nodes, + genvm_modules_interfaces::On::Finalized, + recipient, + call_key, + ) + .expect("exact key still exists at zero remaining budget") + .0, + 1 + ); } #[test] -fn internal_allocation_zero_budget_exact_ignores_its_phase() { +fn internal_zero_remaining_exact_phase_blocks_wildcard() { let recipient = calldata::Address::from([7; 20]); let call_key = genvm_modules_interfaces::abi_stub::CallKey([8; 32]); let mut wildcard = internal_message_allocation(); @@ -176,14 +180,13 @@ fn internal_allocation_zero_budget_exact_ignores_its_phase() { exact.budget = Some(U256::zero()); let nodes = vec![wildcard, exact]; - let (matched, _) = resolve_internal_allocation( + assert!(resolve_internal_allocation( &nodes, genvm_modules_interfaces::On::Finalized, recipient, call_key, ) - .expect("zero-budget exact allocation should not block the wildcard"); - assert_eq!(matched, 0); + .is_none()); } #[test] @@ -676,7 +679,7 @@ fn trap_message(error: generated::types::Error) -> String { } #[tokio::test] -async fn internal_zero_budget_chain_keys_are_absent() { +async fn internal_zero_remaining_exact_fails_before_using_wildcard() { for emission in [ MessageEmission::InternalAllocation, MessageEmission::DeployAllocation, @@ -696,10 +699,23 @@ async fn internal_zero_budget_chain_keys_are_absent() { accumulator.message_fee_allocation = vec![exact, wildcard]; accumulator.message_fee_allocation_consumed = vec![U256::zero(); 2]; - test.emit_message(emission).await.unwrap(); + let error = trap_message(test.emit_message(emission).await.unwrap_err()); + assert!( + error.contains("out_of message_fee allocation_budget # internal"), + "{error}" + ); let accumulator = &test.context.data.accumulator; assert_eq!(accumulator.message_fee_allocation_consumed[0], U256::zero()); - assert!(!accumulator.message_fee_allocation_consumed[1].is_zero()); + assert_eq!(accumulator.message_fee_allocation_consumed[1], U256::zero()); + assert!(accumulator.emissions.is_empty()); + + // The wildcard can fund this emission only when no exact key exists. + let accumulator = &mut test.context.data.accumulator; + accumulator.message_fee_allocation.remove(0); + accumulator.message_fee_allocation_consumed.remove(0); + test.emit_message(emission).await.unwrap(); + let accumulator = &test.context.data.accumulator; + assert!(!accumulator.message_fee_allocation_consumed[0].is_zero()); match &accumulator.emissions[0] { domain::ExecutionEmission::InternalMessage { subtree, .. } | domain::ExecutionEmission::InternalDeployMessage { subtree, .. } => { @@ -708,13 +724,6 @@ async fn internal_zero_budget_chain_keys_are_absent() { other => panic!("unexpected emission: {other:?}"), } - test.context.data.accumulator.message_fee_allocation[1].budget = Some(U256::zero()); - let error = trap_message(test.emit_message(emission).await.unwrap_err()); - assert!( - error.contains("fee no_matching_allocation # internal"), - "{error}" - ); - assert_eq!(test.context.data.accumulator.emissions.len(), 1); test.shutdown().await; } } From 49aa5746603f9a1b41a0144a87698de62a28282a Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Fri, 2 Oct 2026 22:31:01 +0900 Subject: [PATCH 5/5] =?UTF-8?q?test(executor):=20pin=20a=20zero-budget=20r?= =?UTF-8?q?ecipient=20wildcard=20over=20a=20synthetic=20one=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- executor/src/wasi/genlayer_sdk/tests.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/executor/src/wasi/genlayer_sdk/tests.rs b/executor/src/wasi/genlayer_sdk/tests.rs index e6e629b4..98feca33 100644 --- a/executor/src/wasi/genlayer_sdk/tests.rs +++ b/executor/src/wasi/genlayer_sdk/tests.rs @@ -205,6 +205,26 @@ fn internal_allocation_keeps_zero_budget_synthetic_wildcard() { .is_some()); } +#[test] +fn internal_zero_budget_recipient_wildcard_shadows_synthetic_wildcard() { + let recipient = calldata::Address::from([7; 20]); + let call_key = genvm_modules_interfaces::abi_stub::CallKey([8; 32]); + let synthetic = internal_message_allocation(); + let mut wildcard = synthetic.clone(); + wildcard.recipient = Some(recipient); + wildcard.budget = Some(U256::zero()); + let nodes = vec![synthetic, wildcard]; + + let (matched, _) = resolve_internal_allocation( + &nodes, + genvm_modules_interfaces::On::Finalized, + recipient, + call_key, + ) + .expect("the stored recipient wildcard must shadow the synthetic one"); + assert_eq!(matched, 1); +} + #[test] fn internal_allocation_keeps_uncapped_exact_key() { let recipient = calldata::Address::from([7; 20]);