pub struct DoorBudget {
pub memory_limit: usize,
pub max_work_bytes: u64,
pub sig_check_floor: u64,
pub max_memory_bytes: u64,
}Expand description
The DOOR’s static work bound (bsv-low W-A gate MED-1, 2026-09-09). Bitcoin script has no loops: every opcode runs at most once, so an input’s work is bounded BEFORE execution by its opcode census times the interpreter’s element limit (the stack memory limit bounds every element, and every CAT / NUM2BIN / SPLIT result with it) plus its signature checks times the transaction’s own size or a floor, whichever is more (a BIP-143 preimage hashes the prevouts and the outputs; the EC verification costs the same whatever the transaction weighs). The estimate is computed from the bytes; nothing executes past the budget, and a budget breach is the DOOR’s verdict (inconclusive: the network judges), never the interpreter’s.
THE BODY IS NOT COUNTED (bsv-low #585, door 1). Until #585 the budget also
counted the BODY: 64 unproven transactions, 256 inputs per transaction,
512 KB per transaction, and the parse’s own size and counts. A valid BEEF
is never left unjudged for its size or its counts, so those are gone: the
walk reads the body through the streaming reader ([crate::script_door]).
TWO LIMBS, both a budget whose breach is “the network judges” and never a refusal: the WORK the interpreter will do, and the MEMORY the door will hold beside the caller’s body. Each is estimated from the bytes before it is spent.
Fields§
§memory_limit: usizeThe interpreter’s stack memory limit: bounds every element, and is the unit of the work estimate (a hash-class opcode is charged one element). Not a bound on the BEEF: a script that trips it is “the network judges”, as a breach of the work is.
max_work_bytes: u64The whole walk’s estimated work, in bytes hashed or pushed.
sig_check_floor: u64The least a signature check is charged (the doors lens E585-D12-M1).
A check is charged max(its transaction's bytes, this): the digest
hashes about the transaction, and the EC verification behind it costs
the same whatever the transaction weighs (about 95 us native). Charged
the transaction’s bytes alone, a 106 byte OP_CHECKSIG OP_NOT
transaction bought a verification for 106 bytes of budget: 90,000 of
them walked at a fifth of the budget in 9.6 s. With the floor the
budget bounds the EC verifications of one walk at
max_work_bytes / sig_check_floor.
max_memory_bytes: u64The whole walk’s estimated memory beside the body, in bytes (the doors
lens E585-D12-L3): what the index, the stream’s element in hand and
the walk’s layout of a transaction hold, estimated from the frame’s
lengths and counts by crate::stream_sizing::estimate BEFORE the
stream is opened; and, per input, what its two scripts hold once
parsed and run (the delta lens E585-D12-DELTA-M1: bsv-rs’s chunk
records, their clones, a signature’s subscript, the empty stack
entries the interpreter’s memory limit does not count), charged from
the scripts’ chunk count and bytes BEFORE either is parsed
(script_door::script_parse_charge, 512 bytes a chunk and 8 a byte).
How the two compose: the frame’s estimate is the most the walk holds at any moment apart from the input being run (what is kept, and the heaviest transaction in hand, counted once with its raw bytes and the interpreter’s raw copies of the unlocking script); the scripts’ charge is the EXPANSION of one input’s scripts past those bytes, held while that input runs and released after it. An input is run only while the frame’s estimate plus its own charge is within this limb.
Implementations§
Source§impl DoorBudget
impl DoorBudget
Sourcepub const DEFAULT: DoorBudget
pub const DEFAULT: DoorBudget
Sized for LOW’s real shapes with a wide margin. What the static census BOUNDS: hashing (hash-class ops × the element limit) and signature checks (× the transaction’s size or the floor, whichever is more; a CHECKMULTISIG weighted by its static key count when the count is a small-int push, else by the most keys the element limit admits).
THE FLOOR, 64 KiB (half the hash charge), chosen against LOW’s shapes
as the pin door_low_shapes_sit_under_a_quarter_of_the_work_budget
measures them (work, of the 64 MiB; memory, the frame’s and the
largest input’s scripts, of the 48 MiB limb; work before the floor in
brackets):
| shape | inputs | work | memory |
|---|---|---|---|
the real covenant settle (5 hash opcodes, 4 checks: a CHECKSIG and the stated OP_3 CHECKMULTISIG) | 1 | 924,112, 1.4 % (676,284) | 1,282,178, 2.55 % |
| the real covenant refund | 1 | 924,112, 1.4 % (676,284) | 1,282,178, 2.55 % |
LOW’s JOIN: two seats (bsv-low template_tx_sizes.rs:76), the real pot lock, each coin 40 unproven P2PKH hops deep (the deepest the fleet’s record names) | 82 | 16,132,638, 24.0 % | 67,026, 0.13 % |
| STRESS, not LOW’s shape: nine seats, three hops each | 36 | 7,082,619, 10.6 % (4,740,838) | 36,420, 0.07 % |
| a coin 30 P2PKH hops deep | 30 | 5,902,188, 8.8 % (3,941,856) | 23,720, 0.05 % |
A P2PKH input is charged 196,739 bytes (a hash opcode at the element limit, a check at the floor, its 131 script bytes): 341 of them are the budget, 85 a quarter of it. The bound on EC verifications per walk is 64 MiB / 64 KiB = 1,024 (1,023 with their script bytes): measured natively, 1,000 of them walk in 87 ms in the release profile (1.4 to 1.8 s in a debug build), and the lens’s 17,000 stop at the 1,024th in 108 ms. wasm32 was not measured.
THE MEMORY, 48 MiB: three eighths of a 128 MB isolate. Beside it stand,
for a 10 MB request (the figure the arithmetic is made at: since NL-6
the route caps no body, so a heavier one is the isolate’s), the
request’s body, the completed BEEF the route hands the door (a second
copy of up to as much) and the EF batch (the route’s 2 MB bound, twice
while it is serialized): 24 MB, which leaves 56 MB for the module, the
runtime, the allocator’s fragmentation and what a native estimate does
not see of wasm32. The limb bounds the walk (the door’s, and since
bsv-low #592 the submit’s own and the GASP anchor’s under
Engine::set_walk_budget) and nothing else: the route’s own
hydrated parses before it are bounded by the isolate only (the land
lens E585-LAND-M1: 1.43 GB natively for a 9.9 MB body of 900,000
minimal transactions, before the route’s 429). What
it lets through, by the door’s charges (script_door::DOOR_CHARGES,
each an upper bound: the pins measure 1.3 to 5.3 times the heap the
walk reaches): a BUMP of up to 72,944 leaves (690 bytes a level-0
leaf); a single transaction of up to about 12 MB (4 bytes a byte)
whose walked inputs’ scripts are few chunks (a script is charged 520
bytes a one-byte opcode and 8 a pushed byte: an input whose two
scripts are about 96,000 opcodes, or a 1 MB OP_NOP lock, is past
the limb before it is parsed, the network judges; LOW’s covenant leg,
6,608 script bytes, is charged 1.3 MB); a 10 MB body of one-input,
one-output P2PKH transactions (191 bytes, charged 570: 30 MB). What it
stops: 111,848 transactions of no input and no output, whatever
follows them.
THE OPEN RESIDUAL (the W-A gate’s delta-verify, 2026-09-09, measured):
the interpreter itself meters nothing, so two classes stay charged
only by their script bytes — bignum arithmetic (OP_MUL/OP_DIV/
OP_MOD on operands up to the element limit: ~1.3 ms per 30 KB×30 KB
round, linear in rounds) and OP_NUM2BIN, which
allocates its size operand BEFORE the memory limit is consulted (up to
bsv-rs’s 1 GB element size: an isolate kill, not a refusal). None of
them can refuse a spend (a breach and a trip are the door’s bound and
the request proceeds); all of them cost the beta overlay CPU until
bsv-rs meters work dynamically (a work_limit charged per op with the
real operand sizes, and a pre-allocation check in NUM2BIN) — OWED
before any PROD flip of SCRIPT_VERIFY_NETWORK_GATED. Since #585 the
count of such rounds is bounded by the body alone (the script bytes
are charged, the transactions and inputs are not counted). A third,
as before #585 (the doors lens N7): an opcode that copies an element
(OP_DUP, OP_CAT, OP_PICK) is charged its one script byte and can
copy up to the element limit. The class the floor CLOSED: a
CHECKMULTISIG whose key count is a computed value was charged the most
keys the element limit admits (3,971) at its transaction’s bytes and
run (~80 µs per key tried); at the floor those are 260 MB, past the
budget, so such an input is never run at the door (the network
judges). LOW’s covenant states its count (OP_3).