Motivation
linera-service/tests/fixtures/evm_call_wasm_example_counter.sol is a Solidity fixture that exercises EVM → Wasm calls into the counter-no-graphql example. Its bcs_serialize_CounterOperation function is a frozen snapshot of what serde-generate's Solidity backend would have emitted when the fixture was first authored (PR #3717): the generated output was copy-pasted into the file once and has been hand-maintained since.
That worked while CounterOperation was a stable single-variant enum with sequential uint8 discriminants. With #6314, CounterOperation now carries #[derive(StableEnum)], so its variant tag is a 4-byte ULEB128 encoding of Keccak256("Increment")[..4] rather than uint8(0). The fixture's BCS serializer was hand-edited in that PR to hardcode the tag (hex\"BFD58759\"), but this is fragile: any future rename or variant addition silently breaks the EVM→Wasm test (it manifests as a RuntimeError: unreachable Wasm trap, not a localized fixture error).
Proposal
Adopt the same pattern the bridge uses for BridgeTypes.sol / FungibleBridge.sol, scoped to this fixture:
-
Generate the types. Add a build script (in a small dedicated crate or in linera-service's own `build.rs`) that:
- Reads `examples/counter-no-graphql/tests/snapshots/format__format.snap`,
- Strips the insta header (`splitn(3, "---").nth(2)`),
- Parses the YAML into a `serde_reflection::Registry`,
- Feeds it to `serde_generate::solidity::Installer` with module name `CounterOperationTypes`,
- Writes the result to `linera-service/tests/fixtures/CounterOperationTypes.sol`.
With the workspace `[patch.crates-io]` pin to the zefchain serde-reflection fork (commit `8882df9`), the emitted code will use the correct 4-byte ULEB128 Keccak tags automatically — no hand-coded constants.
-
Split the fixture. Refactor `evm_call_wasm_example_counter.sol` so the generated content lives in `CounterOperationTypes.sol` (imported via `import "./CounterOperationTypes.sol";`). The hand-written content stays:
- `serde_json_serialize_CounterRequest` and the JSON deserializer (still hand-maintained — service queries don't go through BCS),
- The `nest_increment` / `nest_get_value` entry points,
- The fixed-width `bcs_serialize_uint64` / `bcs_deserialize_uint64` helpers if they aren't duplicated by the generated module.
-
Drift check. Add a CI step that runs the generator into a temp dir and `diff`s against the in-tree `CounterOperationTypes.sol`, mirroring the existing `LineraTypes.sol` check in `.github/workflows/rust.yml`. Alternatively, the build script itself can fail when the in-tree file is out of date.
Out of scope / open questions
- Whether to keep `serde_json_*` codegen separate or also generate it (today it's hand-rolled because no generator targets JSON-over-Solidity for query encoding).
- Whether to extend the same pattern to other potential EVM↔Wasm fixtures preemptively. Probably wait for a second instance to land before generalizing.
Links
Motivation
linera-service/tests/fixtures/evm_call_wasm_example_counter.solis a Solidity fixture that exercises EVM → Wasm calls into thecounter-no-graphqlexample. Itsbcs_serialize_CounterOperationfunction is a frozen snapshot of whatserde-generate's Solidity backend would have emitted when the fixture was first authored (PR #3717): the generated output was copy-pasted into the file once and has been hand-maintained since.That worked while
CounterOperationwas a stable single-variant enum with sequentialuint8discriminants. With #6314,CounterOperationnow carries#[derive(StableEnum)], so its variant tag is a 4-byte ULEB128 encoding ofKeccak256("Increment")[..4]rather thanuint8(0). The fixture's BCS serializer was hand-edited in that PR to hardcode the tag (hex\"BFD58759\"), but this is fragile: any future rename or variant addition silently breaks the EVM→Wasm test (it manifests as aRuntimeError: unreachableWasm trap, not a localized fixture error).Proposal
Adopt the same pattern the bridge uses for
BridgeTypes.sol/FungibleBridge.sol, scoped to this fixture:Generate the types. Add a build script (in a small dedicated crate or in
linera-service's own `build.rs`) that:With the workspace `[patch.crates-io]` pin to the zefchain serde-reflection fork (commit `8882df9`), the emitted code will use the correct 4-byte ULEB128 Keccak tags automatically — no hand-coded constants.
Split the fixture. Refactor `evm_call_wasm_example_counter.sol` so the generated content lives in `CounterOperationTypes.sol` (imported via `import "./CounterOperationTypes.sol";`). The hand-written content stays:
Drift check. Add a CI step that runs the generator into a temp dir and `diff`s against the in-tree `CounterOperationTypes.sol`, mirroring the existing `LineraTypes.sol` check in `.github/workflows/rust.yml`. Alternatively, the build script itself can fail when the in-tree file is out of date.
Out of scope / open questions
Links
StableEnumfor all ContractAbi Operation/Response enums #6314 (which introduced the StableEnum derive that surfaced this fragility).