Skip to content

Commit

Permalink
Set relative lock heights on etching transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
casey committed Mar 29, 2024
1 parent fb6a2b2 commit ae0563a
Show file tree
Hide file tree
Showing 16 changed files with 104 additions and 49 deletions.
1 change: 1 addition & 0 deletions crates/ordinals/src/runestone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum Payload {

impl Runestone {
pub const MAGIC_NUMBER: opcodes::All = opcodes::all::OP_PUSHNUM_13;
pub const COMMIT_INTERVAL: u16 = 6;

pub fn from_transaction(transaction: &Transaction) -> Option<Self> {
Self::decipher(transaction).ok().flatten()
Expand Down
25 changes: 24 additions & 1 deletion crates/test-bitcoincore-rpc/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,30 @@ impl Api for Server {
fn send_raw_transaction(&self, tx: String) -> Result<String, jsonrpc_core::Error> {
let tx: Transaction = deserialize(&hex::decode(tx).unwrap()).unwrap();

self.state.lock().unwrap().mempool.push(tx.clone());
let mut state = self.state.lock().unwrap();

for tx_in in &tx.input {
if let Some(lock_time) = tx_in.sequence.to_relative_lock_time() {
match lock_time {
bitcoin::relative::LockTime::Blocks(blocks) => {
if state
.txid_to_block_height
.get(&tx_in.previous_output.txid)
.expect("input has not been miined")
+ u32::from(blocks.value())
> u32::try_from(state.hashes.len()).unwrap()
{
panic!("input is locked");
}
}
bitcoin::relative::LockTime::Time(_) => {
panic!("time-based relative locktimes are not implemented")
}
}
}
}

state.mempool.push(tx.clone());

Ok(tx.txid().to_string())
}
Expand Down
5 changes: 2 additions & 3 deletions src/index/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl Context {
..default()
});

self.mine_blocks(RUNE_COMMIT_INTERVAL.into());
self.mine_blocks(Runestone::COMMIT_INTERVAL.into());

let mut witness = Witness::new();

Expand Down Expand Up @@ -199,8 +199,7 @@ impl Context {
(
txid,
RuneId {
block: u64::try_from(block_count + usize::try_from(RUNE_COMMIT_INTERVAL).unwrap() + 1)
.unwrap(),
block: u64::try_from(block_count + Runestone::COMMIT_INTERVAL.into_usize() + 1).unwrap(),
tx: 1,
},
)
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 @@ -387,7 +387,7 @@ impl<'a, 'tx, 'client> RuneUpdater<'a, 'tx, 'client> {

let mature = tx_info
.confirmations
.map(|confirmations| confirmations >= RUNE_COMMIT_INTERVAL)
.map(|confirmations| confirmations >= Runestone::COMMIT_INTERVAL.into())
.unwrap_or_default();

if taproot && mature {
Expand Down
6 changes: 6 additions & 0 deletions src/into_usize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ pub(crate) trait IntoUsize {
fn into_usize(self) -> usize;
}

impl IntoUsize for u16 {
fn into_usize(self) -> usize {
self.try_into().unwrap()
}
}

impl IntoUsize for u32 {
fn into_usize(self) -> usize {
self.try_into().unwrap()
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ pub mod wallet;

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

const RUNE_COMMIT_INTERVAL: u32 = 6;
const TARGET_POSTAGE: Amount = Amount::from_sat(10_000);

static SHUTTING_DOWN: AtomicBool = AtomicBool::new(false);
Expand Down
13 changes: 8 additions & 5 deletions src/runes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ mod tests {

#[test]
fn runes_must_be_greater_than_or_equal_to_minimum_for_height() {
let minimum =
Rune::minimum_at_height(Chain::Regtest.network(), Height(RUNE_COMMIT_INTERVAL + 2)).0;
let minimum = Rune::minimum_at_height(
Chain::Regtest.network(),
Height((Runestone::COMMIT_INTERVAL + 2).into()),
)
.0;

{
let context = Context::builder()
Expand Down Expand Up @@ -5211,7 +5214,7 @@ mod tests {
..default()
});

context.mine_blocks(RUNE_COMMIT_INTERVAL.into());
context.mine_blocks(Runestone::COMMIT_INTERVAL.into());

let mut witness = Witness::new();

Expand Down Expand Up @@ -5271,7 +5274,7 @@ mod tests {
..default()
});

context.mine_blocks((RUNE_COMMIT_INTERVAL - 1).into());
context.mine_blocks((Runestone::COMMIT_INTERVAL - 1).into());

let mut witness = Witness::new();

Expand Down Expand Up @@ -5331,7 +5334,7 @@ mod tests {
..default()
});

context.mine_blocks(RUNE_COMMIT_INTERVAL.into());
context.mine_blocks(Runestone::COMMIT_INTERVAL.into());

let mut witness = Witness::new();

Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2117,7 +2117,7 @@ mod tests {
..default()
});

self.mine_blocks(RUNE_COMMIT_INTERVAL.into());
self.mine_blocks(Runestone::COMMIT_INTERVAL.into());

let witness = witness.unwrap_or_else(|| {
let tapscript = script::Builder::new()
Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/wallet/batch_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl Batch {

let current_height = u32::try_from(bitcoin_client.get_block_count()?).unwrap();

let reveal_height = current_height + 1 + RUNE_COMMIT_INTERVAL;
let reveal_height = current_height + 1 + u32::from(Runestone::COMMIT_INTERVAL);

if let Some(terms) = etching.terms {
if let Some((start, end)) = terms.offset.and_then(|range| range.start.zip(range.end)) {
Expand Down
15 changes: 12 additions & 3 deletions src/wallet/batch/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ impl Plan {
.into_option()?;

if let Some(transaction) = transaction {
if u32::try_from(transaction.info.confirmations).unwrap() < RUNE_COMMIT_INTERVAL {
if u32::try_from(transaction.info.confirmations).unwrap()
< Runestone::COMMIT_INTERVAL.into()
{
continue;
}
}
Expand All @@ -146,7 +148,7 @@ impl Plan {
.get_tx_out(&commit_tx.txid(), 0, Some(true))?;

if let Some(tx_out) = tx_out {
if tx_out.confirmations >= RUNE_COMMIT_INTERVAL {
if tx_out.confirmations >= Runestone::COMMIT_INTERVAL.into() {
break;
}
}
Expand Down Expand Up @@ -518,6 +520,7 @@ impl Plan {
reveal_outputs.clone(),
reveal_inputs.clone(),
&reveal_script,
rune.is_some(),
);

let mut target_value = reveal_fee;
Expand Down Expand Up @@ -562,6 +565,7 @@ impl Plan {
reveal_outputs.clone(),
reveal_inputs,
&reveal_script,
rune.is_some(),
);

for output in reveal_tx.output.iter() {
Expand Down Expand Up @@ -713,6 +717,7 @@ impl Plan {
output: Vec<TxOut>,
input: Vec<OutPoint>,
script: &Script,
etching: bool,
) -> (Transaction, Amount) {
let reveal_tx = Transaction {
input: input
Expand All @@ -721,7 +726,11 @@ impl Plan {
previous_output,
script_sig: script::Builder::new().into_script(),
witness: Witness::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
sequence: if etching {
Sequence::from_height(Runestone::COMMIT_INTERVAL)
} else {
Sequence::ENABLE_RBF_NO_LOCKTIME
},
})
.collect(),
output,
Expand Down
4 changes: 2 additions & 2 deletions tests/balances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn with_runes() {
SpacedRune::new(Rune(RUNE), 0),
vec![(
OutPoint {
txid: a.inscribe.reveal,
txid: a.output.reveal,
vout: 1
},
Pile {
Expand All @@ -73,7 +73,7 @@ fn with_runes() {
SpacedRune::new(Rune(RUNE + 1), 0),
vec![(
OutPoint {
txid: b.inscribe.reveal,
txid: b.output.reveal,
vout: 1
},
Pile {
Expand Down
18 changes: 9 additions & 9 deletions tests/json_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ fn get_runes() {

bitcoin_rpc_server.mine_blocks(1);

let response = ord_rpc_server.json_request(format!("/rune/{}", a.inscribe.rune.unwrap().rune));
let response = ord_rpc_server.json_request(format!("/rune/{}", a.output.rune.unwrap().rune));
assert_eq!(response.status(), StatusCode::OK);

let rune_json: api::Rune = serde_json::from_str(&response.text().unwrap()).unwrap();
Expand All @@ -551,7 +551,7 @@ fn get_runes() {
burned: 0,
terms: None,
divisibility: 0,
etching: a.inscribe.reveal,
etching: a.output.reveal,
mints: 0,
number: 0,
premine: 1000,
Expand All @@ -565,7 +565,7 @@ fn get_runes() {
id: RuneId { block: 11, tx: 1 },
mintable: false,
parent: Some(InscriptionId {
txid: a.inscribe.reveal,
txid: a.output.reveal,
index: 0,
}),
}
Expand All @@ -588,7 +588,7 @@ fn get_runes() {
burned: 0,
terms: None,
divisibility: 0,
etching: a.inscribe.reveal,
etching: a.output.reveal,
mints: 0,
number: 0,
premine: 1000,
Expand All @@ -607,7 +607,7 @@ fn get_runes() {
burned: 0,
terms: None,
divisibility: 0,
etching: b.inscribe.reveal,
etching: b.output.reveal,
mints: 0,
number: 1,
premine: 1000,
Expand All @@ -626,7 +626,7 @@ fn get_runes() {
burned: 0,
terms: None,
divisibility: 0,
etching: c.inscribe.reveal,
etching: c.output.reveal,
mints: 0,
number: 2,
premine: 1000,
Expand Down Expand Up @@ -670,7 +670,7 @@ fn get_runes_balances() {
rune0,
vec![(
OutPoint {
txid: e0.inscribe.reveal,
txid: e0.output.reveal,
vout: 1,
},
1000,
Expand All @@ -682,7 +682,7 @@ fn get_runes_balances() {
rune1,
vec![(
OutPoint {
txid: e1.inscribe.reveal,
txid: e1.output.reveal,
vout: 1,
},
1000,
Expand All @@ -694,7 +694,7 @@ fn get_runes_balances() {
rune2,
vec![(
OutPoint {
txid: e2.inscribe.reveal,
txid: e2.output.reveal,
vout: 1,
},
1000,
Expand Down
14 changes: 7 additions & 7 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use {
bitcoin::{
address::{Address, NetworkUnchecked},
blockdata::constants::COIN_VALUE,
Network, OutPoint, Txid, Witness,
Network, OutPoint, Sequence, Txid, Witness,
},
bitcoincore_rpc::bitcoincore_rpc_json::ListDescriptorsResult,
chrono::{DateTime, Utc},
Expand Down Expand Up @@ -157,7 +157,7 @@ fn drain(bitcoin_rpc_server: &test_bitcoincore_rpc::Handle, ord_rpc_server: &Tes

struct Etched {
id: RuneId,
inscribe: Batch,
output: Batch,
}

fn etch(
Expand Down Expand Up @@ -215,7 +215,7 @@ fn batch(

bitcoin_rpc_server.mine_blocks(6);

let inscribe = spawn.run_and_deserialize_output::<Batch>();
let output = spawn.run_and_deserialize_output::<Batch>();

bitcoin_rpc_server.mine_blocks(1);

Expand All @@ -226,8 +226,8 @@ fn batch(
tx: 1,
};

let reveal = inscribe.reveal;
let parent = inscribe.inscriptions[0].id;
let reveal = output.reveal;
let parent = output.inscriptions[0].id;

let batch::Etching {
divisibility,
Expand Down Expand Up @@ -364,7 +364,7 @@ fn batch(
destination,
location,
rune,
} = inscribe.rune.clone().unwrap();
} = output.rune.clone().unwrap();

if premine.to_integer(divisibility).unwrap() > 0 {
let destination = destination
Expand Down Expand Up @@ -417,7 +417,7 @@ fn batch(
}
}

Etched { inscribe, id }
Etched { output, id }
}

fn envelope(payload: &[&[u8]]) -> Witness {
Expand Down
6 changes: 3 additions & 3 deletions tests/runes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn one_rune() {
block: 8,
burned: 0,
divisibility: 0,
etching: etch.inscribe.reveal,
etching: etch.output.reveal,
id: RuneId { block: 8, tx: 1 },
terms: None,
mints: 0,
Expand Down Expand Up @@ -104,7 +104,7 @@ fn two_runes() {
block: 8,
burned: 0,
divisibility: 0,
etching: a.inscribe.reveal,
etching: a.output.reveal,
id: RuneId { block: 8, tx: 1 },
terms: None,
mints: 0,
Expand All @@ -126,7 +126,7 @@ fn two_runes() {
block: 16,
burned: 0,
divisibility: 0,
etching: b.inscribe.reveal,
etching: b.output.reveal,
id: RuneId { block: 16, tx: 1 },
terms: None,
mints: 0,
Expand Down
Loading

0 comments on commit ae0563a

Please sign in to comment.