Skip to content

ConditionMultisig integration test #33

Description

@louisinger

PR #30 adds support for ConditionMultisigClosure to ReadArkadeScript by replacing the hardcoded MultisigClosure-only decoder with a scriptlib.DecodeClosure() switch covering all closure types. We should add an e2e integration test exercising the ConditionMultisigClosure path end-to-end with introspector.


Background

Before PR #30, pkg/arkade/script.go had a hardcoded MultisigClosure decoder and would reject any VTXO using a different closure type with "spendingtapscript is not a MultisigClosure". PR #30 replaced that with a scriptlib.DecodeClosure() switch, adding handling for:

What is ConditionMultisigClosure?

A ConditionMultisigClosure tapscript leaf is structured as:

<condition_subscript> OP_VERIFY <multisig_script>

The condition is an arbitrary subscript that must evaluate to true before the multisig is checked. The witness must satisfy both the condition and the multisig. Pubkeys are extracted from the embedded MultisigClosure.

Real-world use: This is the VHTLC claim closure in Fulmine. The ClaimClosure is a ConditionMultisigClosure where the condition is a preimage check:

// fulmine/pkg/vhtlc/vhtlc.go
ClaimClosure: &script.ConditionMultisigClosure{
    MultisigClosure: script.MultisigClosure{
        PubKeys: []*btcec.PublicKey{opts.Receiver, opts.Server},
    },
    Condition: preimageConditionScript, // OP_SHA256 <hash> OP_EQUAL
}

A receiver claims the VTXO by providing the preimage in the witness, satisfying the condition, alongside their multisig signature.

What needs to be tested

An integration test (suggested location: test/condition_multisig_test.go, parallel to test/tx_test.go) that:

  1. Constructs a ConditionMultisigClosure tapscript — e.g., a preimage condition (OP_SHA256 <hash> OP_EQUALVERIFY) combined with a multisig over Bob and the introspector key
  2. Builds a VTXO tapscript tree that includes this closure (via createVtxoScriptWithArkadeScript or equivalent)
  3. Funds a VTXO to that tapscript via alice.SendOffChain
  4. Constructs an offchain tx spending via the ConditionMultisigClosure leaf, providing the preimage in the witness
  5. Submits to introspector via introspectorClient.SubmitTx or introspectorClient.SubmitIntent
  6. Verifies introspector decodes the ConditionMultisigClosure, extracts the owner pubkey from c.PubKeys, finds the tweaked key, and produces a valid signature
  7. Verifies the signed tx is accepted by arkd
  8. (Bonus) Verifies introspector rejects the tx if the wrong preimage is provided (condition fails), or if the preimage is omitted entirely

Relevant code paths

  • pkg/arkade/script.goReadArkadeScript / ConditionMultisigClosure branch (PR Support every type of tapscript closure #30, line ~70)
  • pkg/arkade/script_test.go + testdata/read_arkade_script.json — unit-level decode test data (reference for valid/invalid fixtures)
  • test/tx_test.goTestOffchain: reference for full e2e test structure (setup, VTXO creation, introspector client, tx submission)
  • test/utils_test.gocreateVtxoScriptWithArkadeScript, setupIntrospectorClient, setupBobWallet, regtest helpers
  • arkade-os/arkd/pkg/ark-lib/script/closure.goConditionMultisigClosure definition and DecodeClosure switch order
  • fulmine/pkg/vhtlc/ — real-world ConditionMultisigClosure usage as claim closure (good reference for preimage condition construction)

Key distinctions from other closure types

MultisigClosure ConditionMultisigClosure ConditionCSVMultisigClosure
Condition None Arbitrary (e.g. preimage) Arbitrary + CSV timelock
Witness Signatures only Preimage + signatures Preimage + signatures (after CSV)
Pubkey source c.PubKeys c.PubKeys (via embedded MultisigClosure) c.PubKeys (via embedded CSVMultisigClosure)
Use case in Ark Collaborative exit VHTLC claim VHTLC unilateral claim

The key subtlety: introspector's ReadArkadeScript only checks that its own tweaked pubkey appears in c.PubKeys. It does not evaluate the condition subscript — that is left to Bitcoin script execution. The test should confirm the introspector correctly signs without needing to evaluate the preimage itself.

Why this matters

ConditionMultisigClosure is the mechanism behind VHTLC claims — the core of Fulmine's Lightning bridge. If introspector silently fails to sign a ConditionMultisigClosure leaf (e.g. due to a future refactor of DecodeClosure), any VHTLC that includes the introspector in its claim multisig loses its ability to settle. This test ensures that regression cannot happen silently.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions