diff --git a/crates/ordinals/src/runestone.rs b/crates/ordinals/src/runestone.rs index feb85dd08d..8667b6059d 100644 --- a/crates/ordinals/src/runestone.rs +++ b/crates/ordinals/src/runestone.rs @@ -2104,4 +2104,83 @@ mod tests { }), ); } + + #[test] + fn all_pushdata_opcodes_are_valid() { + for i in 0..79 { + let mut script_pubkey = Vec::new(); + + script_pubkey.push(opcodes::all::OP_RETURN.to_u8()); + script_pubkey.push(Runestone::MAGIC_NUMBER.to_u8()); + script_pubkey.push(i); + + match i { + 0..=75 => { + for j in 0..i { + script_pubkey.push(if j % 2 == 0 { 1 } else { 0 }); + } + + if i % 2 == 1 { + script_pubkey.push(1); + script_pubkey.push(1); + } + } + 76 => { + script_pubkey.push(0); + } + 77 => { + script_pubkey.push(0); + script_pubkey.push(0); + } + 78 => { + script_pubkey.push(0); + script_pubkey.push(0); + script_pubkey.push(0); + script_pubkey.push(0); + } + _ => unreachable!(), + } + + assert_eq!( + Runestone::decipher(&Transaction { + version: 2, + lock_time: LockTime::ZERO, + input: default(), + output: vec![TxOut { + script_pubkey: script_pubkey.into(), + value: 0, + },], + }) + .unwrap(), + Artifact::Runestone(Runestone::default()), + ); + } + } + + #[test] + fn all_non_pushdata_opcodes_are_invalid() { + for i in 79..=u8::MAX { + assert_eq!( + Runestone::decipher(&Transaction { + version: 2, + lock_time: LockTime::ZERO, + input: default(), + output: vec![TxOut { + script_pubkey: vec![ + opcodes::all::OP_RETURN.to_u8(), + Runestone::MAGIC_NUMBER.to_u8(), + i + ] + .into(), + value: 0, + },], + }) + .unwrap(), + Artifact::Cenotaph(Cenotaph { + flaws: Flaw::Opcode.into(), + ..default() + }), + ); + } + } } diff --git a/docs/src/runes/specification.md b/docs/src/runes/specification.md index b247790bf2..77db3704af 100644 --- a/docs/src/runes/specification.md +++ b/docs/src/runes/specification.md @@ -114,9 +114,12 @@ OP_13`. If deciphering fails, later matching outputs are not considered. #### Assembling the Payload Buffer -The payload buffer is assembled by concatenating data pushes. If a non-data -push opcode is encountered, the deciphered runestone is a cenotaph with no -etching, mint, or edicts. +The payload buffer is assembled by concatenating data pushes, after `OP_13`, in +the matching script pubkey. + +Data pushes are opcodes 0 through 78 inclusive. If a non-data push opcode is +encountered, i.e., any opcode equal to or greater than opcode 79, the +deciphered runestone is a cenotaph with no etching, mint, or edicts. #### Decoding the Integer Sequence diff --git a/src/subcommand/env.rs b/src/subcommand/env.rs index 9e2a4058f3..bb04dcf387 100644 --- a/src/subcommand/env.rs +++ b/src/subcommand/env.rs @@ -53,7 +53,8 @@ impl Env { fs::write( absolute.join("bitcoin.conf"), format!( - "regtest=1 + "datacarriersize=1000000 + regtest=1 datadir={absolute_str} listen=0 txindex=1