iroha icon indicating copy to clipboard operation
iroha copied to clipboard

Simplify WasmInstruction I/O: enforce batched read/write

Open s8sato opened this issue 9 months ago • 0 comments

Last updated: Jun 02, 2025

Proof of Concept

Proposal

Wasm executables currently allow queries and instructions to be mixed in any order.

In practice, even fairly complex flows—like multisig—don’t need queries and instructions to alternate. A simpler model is to require all queries to run in a single batch at the start, with instructions batched at the end.

This change would reduce the number of FFI crossings—improving performance (see #4756)—and, by simplifying the architecture, enable lower transaction fees.

The diagram below illustrates the instruction lifecycle (applicable to both Wasm and built-in instructions; not transactions—see #5147).

  • This proposal only makes sense when combined with #5357.

    The executor will be reduced to a pure permission validator—or, more succinctly, an authorizer—that accepts read/write requests paired with permission tokens and returns verdicts to the host.

Instruction Lifecycle

stateDiagram-v2
    [*] --> Host
        Init --> XInit
        XToRead --> ToRead
        ToRead --> AToRead
        AReading --> Reading
        HasRead --> XHasRead
        XToWrite --> ToWrite
        ToWrite --> AToWrite
        AWriting --> Writing
    state Host {
        state instruction_variant <<choice>>
        [*] --> instruction_variant
        instruction_variant --> Init: Wasm
        instruction_variant --> ToWrite: Builtin
        ToRead --> ToRead: batch_read_requests
        Reading --> HasRead: read
        ToWrite --> ToWrite: batch_write_requests
        Writing --> HasWritten: write
        HasWritten --> [*]
    }
    state WasmInstruction {
        XInit --> XToRead: generate_read_request
        XHasRead --> XToWrite: generate_write_request
    }
    state Authorizer {
        AToRead --> AReading: seek_read_approval
        AToWrite --> AWriting: seek_write_approval
    }

Previous description

Currently, users can put queries and instructions in arbitrary order within Wasm executables:

sequenceDiagram
    autonumber
    participant X as Executable
    participant H as Host
    participant A as Executor
    %% Note over X,H: note
    %% Note over H,A: note
    %% Note over A,X: note

    H->>X: Context

    X->>H: query req
    H->>A: query req
    A->>A: query validation
    A->>H: query req
    H->>H: query exec
    H->>X: query res

    X->>H: query req
    H->>A: query req
    A->>A: query validation
    A->>H: query req
    H->>H: query exec
    H->>X: query res

    X->>H: instruction req
    H->>A: instruction req
    A->>A: instruction validation
    A->>H: instruction req
    H->>H: instruction exec
    H->>X: instruction res

    X->>H: query req
    H->>A: query req
    A->>A: query validation
    A->>H: query req
    H->>H: query exec
    H->>X: query res

    X->>H: instruction req
    H->>A: instruction req
    A->>A: instruction validation
    A->>H: instruction req
    H->>H: instruction exec
    H->>X: instruction res

    X->>H: instruction req
    H->>A: instruction req
    A->>A: instruction validation
    A->>H: instruction req
    H->>H: instruction exec
    H->>X: instruction res

    H->>H: transaction commit

However, even relatively complex logic like multisig does not require alternating queries and instructions. A possible simplification is enforcing queries to be executed at the beginning and instructions at the end:

sequenceDiagram
    autonumber
    participant X as Executable
    participant H as Host
    participant A as Authorizer
    %% Note over X,H: note
    %% Note over H,A: note
    %% Note over A,X: note
    X->>H: Event declaration
    H->>X: optional Context
    X->>H: read req
    H->>H: read exec
    H->>A: read reS
    A->>A: read validation
    A->>H: Verdict
    H->>X: read res
    X->>H: write req
    H->>A: expected Event
    A->>A: write validation
    A->>H: Verdict
    H->>H: write exec
    H->>H: compare declared & actual events
    H->>H: transaction commit

Key Considerations

  • Event declaration as a static method is required to prevent event loops: #5362
  • Read requests must be executed before validation to enable query result inspection: #5338
  • A transaction should only be committed if the actual event is a subset of the declared event.

s8sato avatar Mar 16 '25 19:03 s8sato