Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore invalid script pubkeys #3432

Merged
merged 2 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 38 additions & 62 deletions crates/ordinals/src/runestone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ impl Runestone {
pub const MAGIC_NUMBER: opcodes::All = opcodes::all::OP_PUSHNUM_13;
pub const COMMIT_INTERVAL: u16 = 6;

pub fn decipher(transaction: &Transaction) -> Result<Option<Artifact>, script::Error> {
let payload = match Runestone::payload(transaction)? {
pub fn decipher(transaction: &Transaction) -> Option<Artifact> {
let payload = match Runestone::payload(transaction) {
Some(Payload::Valid(payload)) => payload,
Some(Payload::Invalid(flaw)) => {
return Ok(Some(Artifact::Cenotaph(Cenotaph {
return Some(Artifact::Cenotaph(Cenotaph {
flaws: flaw.into(),
..default()
})))
}));
}
None => return Ok(None),
None => return None,
};

let Some(integers) = Runestone::integers(&payload) else {
return Ok(Some(Artifact::Cenotaph(Cenotaph {
return Some(Artifact::Cenotaph(Cenotaph {
flaws: Flaw::Varint.into(),
..default()
})));
}));
};

let Message {
Expand Down Expand Up @@ -110,19 +110,19 @@ impl Runestone {
}

if flaws != 0 {
return Ok(Some(Artifact::Cenotaph(Cenotaph {
return Some(Artifact::Cenotaph(Cenotaph {
flaws,
mint,
etching: etching.and_then(|etching| etching.rune),
})));
}));
}

Ok(Some(Artifact::Runestone(Self {
Some(Artifact::Runestone(Self {
edicts,
etching,
mint,
pointer,
})))
}))
}

pub fn encipher(&self) -> ScriptBuf {
Expand Down Expand Up @@ -189,13 +189,13 @@ impl Runestone {
builder.into_script()
}

fn payload(transaction: &Transaction) -> Result<Option<Payload>, script::Error> {
fn payload(transaction: &Transaction) -> Option<Payload> {
// search transaction outputs for payload
for output in &transaction.output {
let mut instructions = output.script_pubkey.instructions();

// payload starts with OP_RETURN
if instructions.next().transpose()? != Some(Instruction::Op(opcodes::all::OP_RETURN)) {
if instructions.next() != Some(Ok(Instruction::Op(opcodes::all::OP_RETURN))) {
continue;
}

Expand All @@ -214,18 +214,18 @@ impl Runestone {
payload.extend_from_slice(push.as_bytes());
}
Ok(Instruction::Op(_)) => {
return Ok(Some(Payload::Invalid(Flaw::Opcode)));
return Some(Payload::Invalid(Flaw::Opcode));
}
Err(_) => {
return Ok(Some(Payload::Invalid(Flaw::InvalidScript)));
return Some(Payload::Invalid(Flaw::InvalidScript));
}
}
}

return Ok(Some(Payload::Valid(payload)));
return Some(Payload::Valid(payload));
}

Ok(None)
None
}

fn integers(payload: &[u8]) -> Option<Vec<u128>> {
Expand Down Expand Up @@ -275,7 +275,6 @@ mod tests {
version: 2,
})
.unwrap()
.unwrap()
}

fn payload(integers: &[u128]) -> Vec<u8> {
Expand All @@ -289,17 +288,19 @@ mod tests {
}

#[test]
fn decipher_returns_an_error_if_first_opcode_is_malformed() {
assert!(Runestone::decipher(&Transaction {
input: Vec::new(),
output: vec![TxOut {
script_pubkey: ScriptBuf::from_bytes(vec![opcodes::all::OP_PUSHBYTES_4.to_u8()]),
value: 0,
}],
lock_time: LockTime::ZERO,
version: 2,
})
.is_err());
fn decipher_returns_none_if_first_opcode_is_malformed() {
assert_eq!(
Runestone::decipher(&Transaction {
input: Vec::new(),
output: vec![TxOut {
script_pubkey: ScriptBuf::from_bytes(vec![opcodes::all::OP_PUSHBYTES_4.to_u8()]),
value: 0,
}],
lock_time: LockTime::ZERO,
version: 2,
}),
None,
);
}

#[test]
Expand All @@ -311,7 +312,7 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
}),
Ok(None)
None,
);
}

Expand All @@ -327,7 +328,7 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
}),
Ok(None)
None,
);
}

Expand All @@ -345,7 +346,7 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
}),
Ok(None)
None,
);
}

Expand All @@ -364,24 +365,10 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
}),
Ok(None)
None,
);
}

#[test]
fn deciphering_valid_runestone_with_invalid_script_returns_script_error() {
Runestone::decipher(&Transaction {
input: Vec::new(),
output: vec![TxOut {
script_pubkey: ScriptBuf::from_bytes(vec![opcodes::all::OP_PUSHBYTES_4.to_u8()]),
value: 0,
}],
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap_err();
}

#[test]
fn deciphering_valid_runestone_with_invalid_script_postfix_returns_invalid_payload() {
let mut script_pubkey = script::Builder::new()
Expand All @@ -402,7 +389,7 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
}),
Ok(Some(Payload::Invalid(Flaw::InvalidScript)))
Some(Payload::Invalid(Flaw::InvalidScript))
);
}

Expand Down Expand Up @@ -457,7 +444,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Cenotaph(Cenotaph {
flaws: Flaw::Opcode.into(),
Expand All @@ -482,7 +468,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Cenotaph(Cenotaph {
flaws: Flaw::Opcode.into(),
Expand All @@ -506,7 +491,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Runestone(Runestone::default()),
);
Expand Down Expand Up @@ -545,7 +529,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Runestone(Runestone {
mint: Some(RuneId::new(1, 1).unwrap()),
Expand Down Expand Up @@ -776,7 +759,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Cenotaph(Cenotaph {
flaws: Flaw::Varint.into(),
Expand Down Expand Up @@ -1309,7 +1291,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Runestone(Runestone {
edicts: vec![Edict {
Expand Down Expand Up @@ -1352,7 +1333,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Runestone(Runestone {
edicts: vec![Edict {
Expand Down Expand Up @@ -1394,7 +1374,6 @@ mod tests {
lock_time: LockTime::ZERO,
version: 2,
})
.unwrap()
.unwrap(),
Artifact::Runestone(Runestone {
edicts: vec![Edict {
Expand Down Expand Up @@ -1676,7 +1655,7 @@ mod tests {
version: 2,
};

let Payload::Valid(payload) = Runestone::payload(&transaction).unwrap().unwrap() else {
let Payload::Valid(payload) = Runestone::payload(&transaction).unwrap() else {
panic!("invalid payload")
};

Expand All @@ -1692,7 +1671,7 @@ mod tests {
};

assert_eq!(
Runestone::decipher(&transaction).unwrap().unwrap(),
Runestone::decipher(&transaction).unwrap(),
Artifact::Runestone(runestone),
);
}
Expand Down Expand Up @@ -2054,8 +2033,7 @@ mod tests {
]),
value: 0,
}],
})
.unwrap(),
}),
None
);

Expand Down Expand Up @@ -2083,7 +2061,6 @@ mod tests {
}
],
})
.unwrap()
.unwrap(),
Artifact::Runestone(Runestone::default()),
);
Expand All @@ -2110,7 +2087,6 @@ mod tests {
value: 0,
}],
})
.unwrap()
.unwrap(),
Artifact::Cenotaph(Cenotaph {
flaws: Flaw::InvalidScript.into(),
Expand Down
2 changes: 1 addition & 1 deletion src/index/updater/rune_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub(super) struct RuneUpdater<'a, 'tx, 'client> {

impl<'a, 'tx, 'client> RuneUpdater<'a, 'tx, 'client> {
pub(super) fn index_runes(&mut self, tx_index: u32, tx: &Transaction, txid: Txid) -> Result<()> {
let artifact = Runestone::decipher(tx)?;
let artifact = Runestone::decipher(tx);

let mut unallocated = self.unallocated(tx)?;

Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl Decode {

let inscriptions = ParsedEnvelope::from_transaction(&transaction);

let runestone = Runestone::decipher(&transaction)?;
let runestone = Runestone::decipher(&transaction);

if self.compact {
Ok(Some(Box::new(CompactOutput {
Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/wallet/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl Mint {

assert_eq!(
Runestone::decipher(&signed_transaction),
Ok(Some(Artifact::Runestone(runestone))),
Some(Artifact::Runestone(runestone)),
);

let transaction = bitcoin_client.send_raw_transaction(&signed_transaction)?;
Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ impl Send {

assert_eq!(
Runestone::decipher(&unsigned_transaction),
Ok(Some(Artifact::Runestone(runestone))),
Some(Artifact::Runestone(runestone)),
);

Ok(unsigned_transaction)
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/batch/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ impl Plan {
let total_fees =
Self::calculate_fee(&unsigned_commit_tx, &utxos) + Self::calculate_fee(&reveal_tx, &utxos);

match (Runestone::decipher(&reveal_tx).unwrap(), runestone) {
match (Runestone::decipher(&reveal_tx), runestone) {
(Some(actual), Some(expected)) => assert_eq!(
actual,
Artifact::Runestone(expected),
Expand Down
2 changes: 1 addition & 1 deletion tests/wallet/batch_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,7 @@ fn batch_can_etch_rune() {
Sequence::from_height(Runestone::COMMIT_INTERVAL)
);

let Artifact::Runestone(runestone) = Runestone::decipher(&reveal).unwrap().unwrap() else {
let Artifact::Runestone(runestone) = Runestone::decipher(&reveal).unwrap() else {
panic!();
};

Expand Down
2 changes: 1 addition & 1 deletion tests/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ fn sending_rune_creates_transaction_with_expected_runestone() {
let tx = core.tx_by_id(output.txid);

pretty_assert_eq!(
Runestone::decipher(&tx).unwrap().unwrap(),
Runestone::decipher(&tx).unwrap(),
Artifact::Runestone(Runestone {
pointer: None,
etching: None,
Expand Down
Loading