Skip to content

Consolidate shared functions for stateless and manager - #175

Merged
bennyhodl merged 2 commits into
masterfrom
splice-matrix
Aug 5, 2026
Merged

Consolidate shared functions for stateless and manager#175
bennyhodl merged 2 commits into
masterfrom
splice-matrix

Conversation

@bennyhodl

Copy link
Copy Markdown
Owner

No description provided.

The stateless splice tests ran one contract shape: an enum contract over
a single oracle, spliced by the party that offered it. The manager path
covers both shapes, several oracles, thresholds below the oracle count
and either party initiating. A splice builds a new contract, so the shape
of what it produces is what the CET selection and the adaptor signatures
then work on, and none of that was exercised.

The stateless splice section is now one driver. It takes a contract
shape, the rounds to run — who offers each replacement, and which way the
collateral moves — and the party that settles the last one. Every
contract in the chain is built from that shape over an event of its own,
so each round settles on its own attestation.

`ContractShape` and `ShapedContract` in stateless_utils carry the shape:
enum, numeric, numeric that tolerates an oracle spread, and disjoint,
each over any oracle count and threshold. A `ShapedContract` keeps the
oracles it announced with, so the scenario that funded the contract
attests the event afterwards without tracking them.

That takes the stateless splice tests from 6 to 19: enum over one, three
and five oracles, numeric over one and three, numeric with difference
over five, a disjoint contract settled on either of its two events,
accept-party splices at multi-oracle and numeric shapes, either party
settling, and four chains.

The manager splice path had two holes of its own. It always settled from
the party that offered the first contract, so the accepting party never
broadcast the CET of a spliced contract. And accept-party splices only
ran on an enum contract over one oracle. `TestPath::Splice` now carries a
`SplicePath` that names the settling party, and seven tests cover the
rest: accept-party splices on enum 3-of-5, numerical with difference
3-of-5 and a disjoint contract, accept-party settlement on enum 3-of-3
and numerical 3-of-3, an accept-party splice closed by hand, and the two
existing chains now settle from the accepting side.

15 of these ran against a live regtest chain here, including every new
shape and both settling parties.
Both suites built the same things by hand: oracles announcing an enum
event over the same four outcomes and a digit decomposition event over
the same base and digit count, an enum descriptor that pays alternating
parties, a numeric descriptor rounded to the satoshi, and the contract
those descriptors go into.

What kept them apart is the layer each hands the contract to.
`ddk-manager` takes a `ContractInput`, which names oracles by public key
and event id. `ddk::contract` takes the wire `ContractInfo`, which
carries the announcements themselves. `ddk_testenv::dlc::ContractLeg`
builds either form from one descriptor: an announcement already carries
the oracle public key and the event id, which is all the manager form
needs.

The new module holds the constants, the oracle mechanics — announce,
sign, collect attestations — both descriptor builders, the two contract
forms, and `SpliceDelta`. It sits behind the `dlc` feature of
`ddk-testenv`, already a dev-dependency of both crates and of nothing
else. That feature depends on `ddk`, which depends on `ddk-manager`, both
of which depend on `ddk-testenv` in turn: a cycle cargo allows because
theirs are dev-dependencies.

Policy stays with each suite, because they differ on purpose. The manager
tests pick a random outcome and a random oracle subset above the
threshold; the stateless tests settle on a fixed outcome with the first
`threshold` oracles. The payout curves differ too — the manager tests
build polynomial and hyperbola pieces, the stateless tests take a
straight line from `ddk-payouts` — so `numeric_descriptor` takes the
curve instead of choosing one.

One behaviour is kept deliberately. `attest_numeric_event` offers every
candidate outcome to every oracle and lets the first one stand, because
an oracle that already signed an event refuses the rest. The shared
signing functions ignore that refusal for the same reason, and
`attestations` asserts an oracle really signed before its attestation is
used.

The two harnesses drop 481 lines and add back 209 that call into the 436
line module they now share.

Verified on a live regtest chain after the move: 7 manager execution
paths (enum, disjoint with and without difference, numerical 3-of-3,
single funded, refund, and a numerical splice), 4 stateless ones (enum,
numeric with difference 3-of-5, disjoint settled on its numeric event,
and a numeric splice), and the 31 offline stateless tests.
@bennyhodl
bennyhodl merged commit 232f048 into master Aug 5, 2026
134 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant