Skip to content

Commit

Permalink
Distinguish invalid opcode and invalid script (#3400)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey committed Mar 28, 2024
1 parent 3a44161 commit bb0e7c3
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 46 deletions.
5 changes: 4 additions & 1 deletion crates/ordinals/src/cenotaph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::*;
pub enum Cenotaph {
EdictOutput,
EdictRuneId,
InvalidScript,
Opcode,
SupplyOverflow,
TrailingIntegers,
Expand All @@ -14,9 +15,10 @@ pub enum Cenotaph {
}

impl Cenotaph {
pub const ALL: [Self; 9] = [
pub const ALL: [Self; 10] = [
Self::EdictOutput,
Self::EdictRuneId,
Self::InvalidScript,
Self::Opcode,
Self::SupplyOverflow,
Self::TrailingIntegers,
Expand All @@ -36,6 +38,7 @@ impl Display for Cenotaph {
match self {
Self::EdictOutput => write!(f, "edict output greater than transaction output count"),
Self::EdictRuneId => write!(f, "invalid rune ID in edict"),
Self::InvalidScript => write!(f, "invalid script in OP_RETURN"),
Self::Opcode => write!(f, "non-pushdata opcode in OP_RETURN"),
Self::SupplyOverflow => write!(f, "supply overflows u128"),
Self::TrailingIntegers => write!(f, "trailing integers in body"),
Expand Down
128 changes: 83 additions & 45 deletions crates/ordinals/src/runestone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,16 @@ impl Runestone {
let mut payload = Vec::new();

for result in instructions {
if let Ok(Instruction::PushBytes(push)) = result {
payload.extend_from_slice(push.as_bytes());
} else {
return Ok(Some(Payload::Invalid(Cenotaph::Opcode)));
match result {
Ok(Instruction::PushBytes(push)) => {
payload.extend_from_slice(push.as_bytes());
}
Ok(Instruction::Op(_)) => {
return Ok(Some(Payload::Invalid(Cenotaph::Opcode)));
}
Err(_) => {
return Ok(Some(Payload::Invalid(Cenotaph::InvalidScript)));
}
}
}

Expand Down Expand Up @@ -431,7 +437,7 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
}),
Ok(Some(Payload::Invalid(Cenotaph::Opcode)))
Ok(Some(Payload::Invalid(Cenotaph::InvalidScript)))
);
}

Expand Down Expand Up @@ -1982,50 +1988,82 @@ mod tests {
}

#[test]
fn invalid_scripts_in_op_returns_are_ignored() {
let transaction = Transaction {
version: 2,
lock_time: LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
script_sig: ScriptBuf::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
}],
output: vec![TxOut {
script_pubkey: ScriptBuf::from(vec![
opcodes::all::OP_RETURN.to_u8(),
opcodes::all::OP_PUSHBYTES_4.to_u8(),
]),
value: 0,
}],
};

assert_eq!(Runestone::decipher(&transaction).unwrap(), None);
fn invalid_scripts_in_op_returns_without_magic_number_are_ignored() {
assert_eq!(
Runestone::decipher(&Transaction {
version: 2,
lock_time: LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
script_sig: ScriptBuf::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
}],
output: vec![TxOut {
script_pubkey: ScriptBuf::from(vec![
opcodes::all::OP_RETURN.to_u8(),
opcodes::all::OP_PUSHBYTES_4.to_u8(),
]),
value: 0,
}],
})
.unwrap(),
None
);

let transaction = Transaction {
version: 2,
lock_time: LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
script_sig: ScriptBuf::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
}],
output: vec![TxOut {
script_pubkey: ScriptBuf::from(vec![
opcodes::all::OP_RETURN.to_u8(),
Runestone::MAGIC_NUMBER.to_u8(),
opcodes::all::OP_PUSHBYTES_4.to_u8(),
]),
value: 0,
}],
};
assert_eq!(
Runestone::decipher(&Transaction {
version: 2,
lock_time: LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
script_sig: ScriptBuf::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
}],
output: vec![
TxOut {
script_pubkey: ScriptBuf::from(vec![
opcodes::all::OP_RETURN.to_u8(),
opcodes::all::OP_PUSHBYTES_4.to_u8(),
]),
value: 0,
},
TxOut {
script_pubkey: Runestone::default().encipher(),
value: 0,
}
],
})
.unwrap(),
Some(Runestone::default())
);
}

#[test]
fn invalid_scripts_in_op_returns_with_magic_number_produce_cenotaph() {
assert_eq!(
Runestone::decipher(&transaction).unwrap(),
Runestone::decipher(&Transaction {
version: 2,
lock_time: LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
script_sig: ScriptBuf::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
}],
output: vec![TxOut {
script_pubkey: ScriptBuf::from(vec![
opcodes::all::OP_RETURN.to_u8(),
Runestone::MAGIC_NUMBER.to_u8(),
opcodes::all::OP_PUSHBYTES_4.to_u8(),
]),
value: 0,
}],
})
.unwrap(),
Some(Runestone {
cenotaph: Cenotaph::Opcode.into(),
cenotaph: Cenotaph::InvalidScript.into(),
..default()
})
);
Expand Down

0 comments on commit bb0e7c3

Please sign in to comment.