Context
#2701 / #2652 added the addOrder4 source-count guard: it reverts OrderNoSources / OrderNoHandleIO when the calculate (entrypoint 0) or handle-IO (entrypoint 1) source is absent. That guarantees both entrypoints exist, but not that the calculate source actually emits the 2 values (ratio + outputMax) the protocol needs.
Today that output-count requirement is enforced at runtime, in RaindexV6.calculateOrderIO:
// RaindexV6.sol ~L877
if (calculateOrderStack.length < CALCULATE_ORDER_MIN_OUTPUTS) {
revert UnsupportedCalculateOutputs(calculateOrderStack.length);
}
So an order like :;:; (two sources, but the calculate source emits 0 values) passes the add-time guard, is added live, and only reverts at take/clear time. testAddOrderRealZeroStackCalculateReverts asserts exactly that runtime behavior.
Idea
Extend the addOrder4 guard to also validate the calculate source's declared output count at add time — the source prefix in the serialized rain bytecode encodes the source's stack allocation / outputs, so it should be readable without evaluating (verify against the bytecode source-prefix format / LibBytecode). If the calculate source declares < CALCULATE_ORDER_MIN_OUTPUTS outputs, reject at addOrder4.
Upside: catches more unevaluable orders at submission (consistent with #2652's intent that addOrder4 reject unevaluable orders up front), and makes the runtime UnsupportedCalculateOutputs check removable — eliminating a runtime guard.
Decisions / caveats
- Behavior change:
:;:;-style orders flip from "added live, revert at take/clear" to "rejected at addOrder". testAddOrderRealZeroStackCalculateReverts would change from a runtime-revert assertion to an add-time-revert assertion. Confirm that's the desired contract.
- Feasibility: confirm the serialized bytecode reliably encodes the calculate source's output count in a way
addOrder4 can read cheaply (source prefix / stack allocation). If outputs aren't statically determinable from the bytecode, this isn't viable and the runtime check stays.
- Handle-IO is specified to emit 0 outputs, so an equivalent add-time check there is also possible but lower value.
Follow-up to #2701.
Context
#2701 / #2652 added the
addOrder4source-count guard: it revertsOrderNoSources/OrderNoHandleIOwhen the calculate (entrypoint 0) or handle-IO (entrypoint 1) source is absent. That guarantees both entrypoints exist, but not that the calculate source actually emits the 2 values (ratio + outputMax) the protocol needs.Today that output-count requirement is enforced at runtime, in
RaindexV6.calculateOrderIO:So an order like
:;:;(two sources, but the calculate source emits 0 values) passes the add-time guard, is added live, and only reverts at take/clear time.testAddOrderRealZeroStackCalculateRevertsasserts exactly that runtime behavior.Idea
Extend the
addOrder4guard to also validate the calculate source's declared output count at add time — the source prefix in the serialized rain bytecode encodes the source's stack allocation / outputs, so it should be readable without evaluating (verify against the bytecode source-prefix format /LibBytecode). If the calculate source declares< CALCULATE_ORDER_MIN_OUTPUTSoutputs, reject ataddOrder4.Upside: catches more unevaluable orders at submission (consistent with #2652's intent that
addOrder4reject unevaluable orders up front), and makes the runtimeUnsupportedCalculateOutputscheck removable — eliminating a runtime guard.Decisions / caveats
:;:;-style orders flip from "added live, revert at take/clear" to "rejected at addOrder".testAddOrderRealZeroStackCalculateRevertswould change from a runtime-revert assertion to an add-time-revert assertion. Confirm that's the desired contract.addOrder4can read cheaply (source prefix / stack allocation). If outputs aren't statically determinable from the bytecode, this isn't viable and the runtime check stays.Follow-up to #2701.