Drops Protocol documentation

Conformance material

Test vectors

Every vector below is a real byte string with a real SHA-256 and a real secp256k1 key. Paste any of them into the decoder or the verifier and you will get the outcome stated here, because both tools apply the same rules rather than replaying a stored answer.

Conventions

  • All vectors use the creator key f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9, which is a valid x-only point, except where a vector is specifically about an invalid key.
  • Hex is the leaf script only: the second witness item of the reveal input. It does not include the signature or the control block.
  • Vectors named VT-n are expected to be accepted. Vectors named IV-n are expected to be rejected, with the stated reason.
  • Taproot commitment vectors are described rather than given as hex, because they need a full transaction and a chain context to be meaningful.

Valid leaves

VT-1: minimal text artifact

Marker drops, content type text/plain, an 11-byte body hello drops. Leaf script is 100 bytes.

0564726f7073750a746578742f706c61696e7520493c9d63ae9ee515d32fedc2eb37
23a1fd6c363fc5157180648d007f2a7cf0e1750b68656c6c6f2064726f7073752
0f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9ac
Expected decode
markerdrops
mimetext/plain
bodyBytes11
bodySha256493c9d63ae9ee515d32fedc2eb3723a1fd6c363fc5157180648d007f2a7cf0e1
dropmark493C9D63AE
Resultaccepted

VT-2: longer text artifact

The same shape with a 45-byte body, Sealed on Bitcoin. Dropped once, kept forever. Body hash e5581b84546ba9dfdedf87d77a8de5a4ab1541d157711bda4ef8299147097d30, dropmark E5581B8454. This is the first sample in the decoder.

VT-3: Pact Seed

Marker drops-pact, content type application/vnd.drops.pact-seed, a 184-byte body. Leaf script is 300 bytes. Load it from the decoder samples. The body decodes to:

networkmainnet (tag 0)
enforcementFloorco-signed (tag 1)
engineIdescrow
rulesetHashda08c96d9d2efadfd6da2242f984c31cf2d5046507616215dbd0969ce33790b1
abiHash62f445a2e58ecf42925f188e33028cbc719a49e3578791d0fb0187c7c96f5af8
genesisStateRoot8c49e9067dc29780e25488c5057f17159c361a093608d9b54ae50733ad7ce80c
policyRoot6ad54489e2c67d7abadfca03b41c3ab69ad6429337a9a3df09f375ef6323d21f
dataAvailabilityPolicyHash22cc683dc491cbafafcce796d5923c04f41b357f031c57dec1a8c1fc68961f12
Resultaccepted

VT-4: Pacts reference

Marker drops, content type application/vnd.drops.pacts-reference+json, a 176-byte JSON body. Leaf script is 298 bytes. Available from the decoder samples. The body must be exactly:

{"bh":"b1ece0f3fb4f7be072543180ff03e21b7b094b69fb6a7f4d48cb170282cd967a",
 "p":"pacts",
 "ph":"64879f7d6b960a01909762d911a32d4582c20010c5641ee90278b644a9e3b525",
 "t":"escrow-basic"}

Serialized with no whitespace at all. The line breaks above are for reading only; adding them to the body makes the vector invalid, because the reference profile requires a byte-exact re-serialization.

Invalid leaves

Each of these is one mutation away from a valid leaf. That is the point: the rules are designed so that a near miss is a clean rejection rather than an ambiguous partial result.

IV-1: body hash does not match the body

VT-2 with one bit flipped in the hash push. Structure is perfect; the commitment is a lie.

Expected: Drops leaf sha256 does not match its body. Rule D-13. Load it from the decoder samples.

IV-2: marker belongs to another protocol

A well-formed OP_DROP token event carried under marker bip110-op-drop. It is a valid leaf for its own protocol and must be refused by a Drops indexer.

0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e
75203c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912
e175367b2270223a226f702d64726f70222c226f70223a226d696e74222c227469
636b223a2264726f70222c22616d74223a2231303030227d7520f9308a019258c3
1049344f85f89d5229b531c845836f99b08601f113bce036f9ac

Expected: Drops leaf has an unknown marker. Rules D-6 and D-7.

IV-3: uppercase content type

Content type TEXT/plain.

0564726f7073750a544558542f706c61696e7520493c9d63ae9ee515d32fedc2eb
3723a1fd6c363fc5157180648d007f2a7cf0e1750b68656c6c6f2064726f707375
20f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9ac

Expected: Drops MIME type must be lowercase ASCII type/subtype with no parameters and at most 80 bytes. Rules D-8 and D-10.

IV-4: content type with a parameter

Content type text/plain; charset=utf-8. Parameters are never permitted, even correct ones.

0564726f70737519746578742f706c61696e3b20636861727365743d7574662d38
7520493c9d63ae9ee515d32fedc2eb3723a1fd6c363fc5157180648d007f2a7cf0
e1750b68656c6c6f2064726f70737520f9308a019258c31049344f85f89d5229b5
31c845836f99b08601f113bce036f9ac

Expected: same message as IV-3. Rule D-10.

IV-5: one-byte body with no minimal push encoding

A body of the single byte 0x01. Bitcoin Script folds that value into OP_1, so no data push can carry it minimally. The hash field is correct; the body is still unencodable.

0564726f707375186170706c69636174696f6e2f6f637465742d73747265616d75
204bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a
7501017520f9308a019258c31049344f85f89d5229b531c845836f99b08601f113
bce036f9ac

Expected: the body has no minimal data-push encoding, so it is not a Drop. Rule D-15. A body of 0x00 is valid; 0x81 and 0x01 through 0x10 are not.

IV-6: empty body

OP_0 in the body position. It is a zero-length push, and the minimum body length is one byte.

0564726f7073750a746578742f706c61696e7520e3b0c44298fc1c149afbf4c899
6fb92427ae41e4649b934ca495991b7852b85575007520f9308a019258c3104934
4f85f89d5229b531c845836f99b08601f113bce036f9ac

Expected: Drops body must be one push of 1 to 256 bytes. Rule D-14.

IV-7: body over the limit

Any leaf whose body push is 257 bytes or more. Encoded with OP_PUSHDATA2, it parses cleanly and is still rejected.

Expected: Drops body must be one push of 1 to 256 bytes. Rule D-14. Note that a body of exactly 256 bytes is valid and must use OP_PUSHDATA2, since OP_PUSHDATA1 tops out at 255.

IV-8: creator key is not a curve point

32 bytes of 0xff. That value is larger than the field prime, so it cannot be an x coordinate. A length check alone would let this through.

0564726f7073750a746578742f706c61696e7520493c9d63ae9ee515d32fedc2eb
3723a1fd6c363fc5157180648d007f2a7cf0e1750b68656c6c6f2064726f707375
20ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ac

Expected: Drops leaf requires a valid 32-byte x-only secp256k1 public key. Rule D-19.

IV-9: trailing byte after OP_CHECKSIG

VT-1 with 0x51 appended. Eleven chunks, not ten.

Expected: Drops leaf must contain exactly five pushes and five opcodes. Rule D-1.

IV-10: opcode where a push must be

OP_1 in the body position instead of a data push. It produces the value 1 on the stack, which is not the same thing as a one-byte data push.

0564726f7073750a746578742f706c61696e75204bf5122f344554c53bde2ebb8c
d2b7e3d1600ad631c385a5d7cce23c7785459a75517520f9308a019258c3104934
4f85f89d5229b531c845836f99b08601f113bce036f9ac

Expected: the body field is not a data push. Rule D-3.

Taproot commitment cases

These need a spent output and a control block, so they are described rather than given as leaf hex. Each is a distinct rejection with its own reason string.

Commitment-level vectors
CaseConstructionExpected reason
CT-1Spend a P2WSH output, not a P2TR one, with an otherwise valid witnessprevious output is not P2TR
CT-2Control block of 40 bytes, so (40 - 33) is not a multiple of 32invalid Taproot control block structure
CT-3Control block with 129 path hashes, one past the limitinvalid Taproot control block structure
CT-4Leaf version byte 0xc2, so byte & 0xfe is not 0xc0unsupported Taproot leaf version
CT-5Internal key set to 32 bytes of 0xffinvalid Taproot internal key
CT-6Valid commitment, but the parity bit in controlBlock[0] flippedTaproot control block parity mismatch
CT-7A valid leaf and control block taken from a different Taproot outputTaproot leaf does not commit to previous output
CT-8The spent output cannot be fetched from the nodemissing_previous_output, an unresolved candidate rather than a proven rejection
CT-9A four-item witness with a final item beginning 0x50Annex present, so the input is not a Drops reveal. Rule D-31
CT-10Valid leaf and commitment, reveal confirmed at a depth below the deployment's policyNot recorded yet. Not a rejection, a timing result. Rule D-40

Pact outcome vectors

These are the records the pact verifier loads as samples. The transition preimage below hashes to the commitment shown, using taggedHash("Drops/PactTransition", preimage).

PV-1: a consistent outcome
Pact id6bf9cd8175241aeb1c4006851ac4a87930b8f156d71d1adedee78f9a3673b67f
Networkmainnet (tag 0)
Sequence7 to 8
Parent state rootdba6c576f54e6be4d42834ddf5716198c645dae9a1165c45f4048aff6cfa85b0
Next state rooteb51cc2a22e9a74f20fe4b9876864feb0dbd154505df2c541d78586705db5005
Next policy root21c7fa1068eadbf4113056bd59c57d44039c8e1ae40ad7d560dfcd7fd8123a30
opDropEffectHash32 zero bytes, so no token effect
Transition commitment7d048cb0e10dcf5026dd4a8dc02088c75167e26110e10d647fe54dbde0913840
DPC1 anchor script6a24445043317d048cb0e10dcf5026dd4a8dc02088c75167e26110e10d647fe54dbde0913840
ResultP-1, P-2, P-3, P-7 and P-9 all pass
PV-2: a tampered outcome
MutationPV-1 with the successor descriptor's transition commitment changed from 7d04… to 7c04…
P-7fail PACTS_INVALID_TRANSITION: successor descriptor does not commit to the transition
P-9pass. The DPC1 anchor still carries the commitment the stated terms produce, which is what localises the tampering to the successor descriptor rather than to the terms.
P-1, P-2, P-3pass. Only one check moves, which is the useful part: the failure names exactly which record was altered.
Further Pact record vectors
CaseConstructionExpected error
PV-3Cell descriptor of 175 or 177 bytesPACTS_INVALID_CELL_LENGTH
PV-4Cell descriptor with magic other than DPCLPACTS_INVALID_CELL_MAGIC
PV-5Cell descriptor with a non-zero byte at offset 4, 6 or 7PACTS_INVALID_CELL_RESERVED
PV-6Seed record of any length other than 184PACTS_INVALID_SEED_LENGTH
PV-7Seed record with magic other than DPSEPACTS_INVALID_SEED_MAGIC
PV-8Seed record with a non-zero byte at offset 4 or 7PACTS_INVALID_SEED_RESERVED
PV-9Seed engine id with a non-zero byte after the terminating zeroThe encoding-conformance error code
PV-10Seed engine id failing ^[a-z][a-z0-9-]{0,15}$PACTS_INVALID_ENGINE
PV-11Successor sequence not exactly parent sequence plus onePACTS_INVALID_TRANSITION: cell sequence is invalid
PV-12Transition preimage of any length other than 245PACTS_INVALID_TRANSITION_LENGTH