Skip to content

Commit

Permalink
Add rune fuzz targets (#2526)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey committed Oct 17, 2023
1 parent e724dfc commit 5f1100e
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 17 deletions.
18 changes: 18 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,26 @@ bitcoin = { version = "0.30.0", features = ["rand"] }
libfuzzer-sys = "0.4"
ord = { path = ".." }

[[bin]]
name = "runestone-decipher"
path = "fuzz_targets/runestone_decipher.rs"
test = false
doc = false

[[bin]]
name = "transaction-builder"
path = "fuzz_targets/transaction_builder.rs"
test = false
doc = false

[[bin]]
name = "varint-encode"
path = "fuzz_targets/varint_encode.rs"
test = false
doc = false

[[bin]]
name = "varint-decode"
path = "fuzz_targets/varint_decode.rs"
test = false
doc = false
36 changes: 36 additions & 0 deletions fuzz/fuzz_targets/runestone_decipher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![no_main]

use {
bitcoin::{
locktime, opcodes,
script::{self, PushBytes},
Transaction, TxOut,
},
libfuzzer_sys::fuzz_target,
ord::runes::Runestone,
};

fuzz_target!(|input: Vec<Vec<u8>>| {
let mut builder = script::Builder::new()
.push_opcode(opcodes::all::OP_RETURN)
.push_slice(b"RUNE_TEST");

for slice in input {
let Ok(push): Result<&PushBytes, _> = slice.as_slice().try_into() else {
continue;
};
builder = builder.push_slice(push);
}

let tx = Transaction {
input: Vec::new(),
lock_time: locktime::absolute::LockTime::ZERO,
output: vec![TxOut {
script_pubkey: builder.into_script(),
value: 0,
}],
version: 0,
};

Runestone::from_transaction(&tx);
});
19 changes: 12 additions & 7 deletions fuzz/fuzz_targets/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use {
Amount, OutPoint,
},
libfuzzer_sys::fuzz_target,
ord::{FeeRate, SatPoint, TransactionBuilder},
ord::{FeeRate, SatPoint, Target, TransactionBuilder},
std::collections::BTreeMap,
};

Expand Down Expand Up @@ -62,29 +62,34 @@ fuzz_target!(|input: Input| {
.assume_checked(),
];

let Ok(fee_rate) = FeeRate::try_from(input.fee_rate) else { return; };
let Ok(fee_rate) = FeeRate::try_from(input.fee_rate) else {
return;
};

match input.output_value {
Some(output_value) => {
let _ = TransactionBuilder::build_transaction_with_value(
let _ = TransactionBuilder::new(
satpoint,
inscriptions,
amounts,
recipient,
change,
fee_rate,
Amount::from_sat(output_value),
);
Target::Value(Amount::from_sat(output_value)),
)
.build_transaction();
}
None => {
let _ = TransactionBuilder::build_transaction_with_postage(
let _ = TransactionBuilder::new(
satpoint,
inscriptions,
amounts,
recipient,
change,
fee_rate,
);
Target::Postage,
)
.build_transaction();
}
}
});
17 changes: 17 additions & 0 deletions fuzz/fuzz_targets/varint_decode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![no_main]

use {libfuzzer_sys::fuzz_target, ord::runes::varint};

fuzz_target!(|input: &[u8]| {
let mut i = 0;

while i < input.len() {
let Ok((decoded, length)) = varint::decode(&input[i..]) else {
break;
};
let mut encoded = Vec::new();
varint::encode_to_vec(decoded, &mut encoded);
assert_eq!(encoded, &input[i..i + length]);
i += length;
}
});
11 changes: 11 additions & 0 deletions fuzz/fuzz_targets/varint_encode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![no_main]

use {libfuzzer_sys::fuzz_target, ord::runes::varint};

fuzz_target!(|input: u128| {
let mut encoded = Vec::new();
varint::encode_to_vec(input, &mut encoded);
let (decoded, length) = varint::decode(&encoded).unwrap();
assert_eq!(length, encoded.len());
assert_eq!(decoded, input);
});
12 changes: 11 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,17 @@ profile-tests:
| tee test-times.txt

fuzz:
cd fuzz && cargo +nightly fuzz run transaction-builder
#!/usr/bin/env bash
set -euxo pipefail

cd fuzz

while true; do
cargo +nightly fuzz run transaction-builder -- -max_total_time=60
cargo +nightly fuzz run runestone-decipher -- -max_total_time=60
cargo +nightly fuzz run varint-decode -- -max_total_time=60
cargo +nightly fuzz run varint-encode -- -max_total_time=60
done

open:
open http:https://localhost
Expand Down
11 changes: 8 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,13 @@ use {
};

pub use crate::{
fee_rate::FeeRate, inscription::Inscription, object::Object, rarity::Rarity, sat::Sat,
sat_point::SatPoint, subcommand::wallet::transaction_builder::TransactionBuilder,
fee_rate::FeeRate,
inscription::Inscription,
object::Object,
rarity::Rarity,
sat::Sat,
sat_point::SatPoint,
subcommand::wallet::transaction_builder::{Target, TransactionBuilder},
};

#[cfg(test)]
Expand Down Expand Up @@ -121,7 +126,7 @@ mod outgoing;
mod page_config;
pub mod rarity;
mod representation;
mod runes;
pub mod runes;
pub mod sat;
mod sat_point;
pub mod subcommand;
Expand Down
8 changes: 4 additions & 4 deletions src/runes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use {self::error::Error, super::*};

pub(crate) use {
edict::Edict, etching::Etching, pile::Pile, rune::Rune, rune_id::RuneId, runestone::Runestone,
};
pub use runestone::Runestone;

pub(crate) use {edict::Edict, etching::Etching, pile::Pile, rune::Rune, rune_id::RuneId};

const MAX_DIVISIBILITY: u8 = 38;

Expand All @@ -13,7 +13,7 @@ mod pile;
mod rune;
mod rune_id;
mod runestone;
pub(crate) mod varint;
pub mod varint;

type Result<T, E = Error> = std::result::Result<T, E>;

Expand Down
4 changes: 2 additions & 2 deletions src/subcommand/wallet/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl TransactionBuilder {
pub(crate) const TARGET_POSTAGE: Amount = Amount::from_sat(10_000);
pub(crate) const MAX_POSTAGE: Amount = Amount::from_sat(2 * 10_000);

pub(crate) fn new(
pub fn new(
outgoing: SatPoint,
inscriptions: BTreeMap<SatPoint, InscriptionId>,
amounts: BTreeMap<OutPoint, Amount>,
Expand All @@ -145,7 +145,7 @@ impl TransactionBuilder {
}
}

pub(crate) fn build_transaction(self) -> Result<Transaction> {
pub fn build_transaction(self) -> Result<Transaction> {
if self.change_addresses.len() < 2 {
return Err(Error::DuplicateAddress(
self.change_addresses.first().unwrap().clone(),
Expand Down

0 comments on commit 5f1100e

Please sign in to comment.