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

Allow reinscribing with wallet #2432

Merged
merged 11 commits into from
Sep 11, 2023
1 change: 1 addition & 0 deletions src/subcommand/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl Preview {
satpoint: None,
dry_run: false,
no_limit: false,
reinscribe: false,
destination: None,
parent: None,
postage: Some(TransactionBuilder::TARGET_POSTAGE),
Expand Down
32 changes: 29 additions & 3 deletions src/subcommand/wallet/inscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub(crate) struct Inscribe {
pub(crate) postage: Option<Amount>,
#[clap(long, help = "Make inscription a child of <PARENT>.")]
pub(crate) parent: Option<InscriptionId>,
#[clap(long, help = "Allow reinscription.")]
pub(crate) reinscribe: bool,
}

impl Inscribe {
Expand Down Expand Up @@ -127,6 +129,7 @@ impl Inscribe {
self.commit_fee_rate.unwrap_or(self.fee_rate),
self.fee_rate,
self.no_limit,
self.reinscribe,
match self.postage {
Some(postage) => postage,
_ => TransactionBuilder::TARGET_POSTAGE,
Expand Down Expand Up @@ -209,6 +212,7 @@ impl Inscribe {
commit_fee_rate: FeeRate,
reveal_fee_rate: FeeRate,
no_limit: bool,
reinscribe: bool,
postage: Amount,
) -> Result<(Transaction, Transaction, TweakedKeyPair, u64)> {
let satpoint = if let Some(satpoint) = satpoint {
Expand All @@ -229,9 +233,16 @@ impl Inscribe {
.ok_or_else(|| anyhow!("wallet contains no cardinal utxos"))?
};

let mut reinscription = false;

for (inscribed_satpoint, inscription_id) in &inscriptions {
if inscribed_satpoint == &satpoint {
return Err(anyhow!("sat at {} already inscribed", satpoint));
if *inscribed_satpoint == satpoint {
reinscription = true;
if reinscribe {
continue;
} else {
return Err(anyhow!("sat at {} already inscribed", satpoint));
}
}

if inscribed_satpoint.outpoint == satpoint.outpoint {
Expand All @@ -242,6 +253,12 @@ impl Inscribe {
}
}

if reinscribe && !reinscription {
return Err(anyhow!(
"reinscribe flag set but this would not be a reinscription"
));
}

let secp256k1 = Secp256k1::new();
let key_pair = UntweakedKeyPair::new(&secp256k1, &mut rand::thread_rng());
let (public_key, _parity) = XOnlyPublicKey::from_keypair(&key_pair);
Expand Down Expand Up @@ -527,6 +544,7 @@ mod tests {
FeeRate::try_from(1.0).unwrap(),
FeeRate::try_from(1.0).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap();
Expand All @@ -542,7 +560,7 @@ mod tests {
}

#[test]
fn inscript_tansactions_opt_in_to_rbf() {
fn inscribe_tansactions_opt_in_to_rbf() {
let utxos = vec![(outpoint(1), Amount::from_sat(20000))];
let inscription = inscription("text/plain", "ord");
let commit_address = change(0);
Expand All @@ -560,6 +578,7 @@ mod tests {
FeeRate::try_from(1.0).unwrap(),
FeeRate::try_from(1.0).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap();
Expand Down Expand Up @@ -597,6 +616,7 @@ mod tests {
FeeRate::try_from(1.0).unwrap(),
FeeRate::try_from(1.0).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap_err()
Expand Down Expand Up @@ -641,6 +661,7 @@ mod tests {
FeeRate::try_from(1.0).unwrap(),
FeeRate::try_from(1.0).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.is_ok())
Expand Down Expand Up @@ -679,6 +700,7 @@ mod tests {
FeeRate::try_from(fee_rate).unwrap(),
FeeRate::try_from(fee_rate).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap();
Expand Down Expand Up @@ -750,6 +772,7 @@ mod tests {
FeeRate::try_from(fee_rate).unwrap(),
FeeRate::try_from(fee_rate).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap();
Expand Down Expand Up @@ -825,6 +848,7 @@ mod tests {
FeeRate::try_from(commit_fee_rate).unwrap(),
FeeRate::try_from(fee_rate).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap();
Expand Down Expand Up @@ -876,6 +900,7 @@ mod tests {
FeeRate::try_from(1.0).unwrap(),
FeeRate::try_from(1.0).unwrap(),
false,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap_err()
Expand Down Expand Up @@ -909,6 +934,7 @@ mod tests {
FeeRate::try_from(1.0).unwrap(),
FeeRate::try_from(1.0).unwrap(),
true,
false,
TransactionBuilder::TARGET_POSTAGE,
)
.unwrap();
Expand Down
102 changes: 102 additions & 0 deletions tests/wallet/inscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,105 @@ fn inscribe_with_parent_inscription_and_fee_rate() {
),
);
}

#[test]
fn reinscribe_with_flag() {
let rpc_server = test_bitcoincore_rpc::spawn();
rpc_server.mine_blocks(1);

assert_eq!(rpc_server.descriptors().len(), 0);

create_wallet(&rpc_server);

let inscribe = CommandBuilder::new("wallet inscribe tulip.png --fee-rate 5.0 ")
.write("tulip.png", [1; 520])
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Inscribe>();

assert_eq!(rpc_server.descriptors().len(), 3);

let txid = rpc_server.mine_blocks(1)[0].txdata[2].txid();

let ord_server = TestServer::spawn_with_args(&rpc_server, &[]);
let request = ord_server.request(format!("/content/{}", inscribe.inscription));

assert_eq!(request.status(), 200);

let reinscribe = CommandBuilder::new(format!(
"wallet inscribe orchid.png --fee-rate 1.1 --reinscribe --satpoint {txid}:0:0"
))
.write("orchid.png", [1; 520])
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Inscribe>();

rpc_server.mine_blocks(1);

let ord_server = TestServer::spawn_with_args(&rpc_server, &["--index-sats"]);
let request = ord_server.request(format!("/content/{}", reinscribe.inscription));

assert_eq!(request.status(), 200);
ord_server.assert_response_regex(
format!("/sat/{}", 50 * COIN_VALUE),
format!(
".*<dt>inscriptions</dt>.*<a href=/inscription/{}>.*<a href=/inscription/{}>.*",
inscribe.inscription, reinscribe.inscription
),
);
}

#[test]
fn with_reinscribe_flag_but_not_actually_a_reinscription() {
let rpc_server = test_bitcoincore_rpc::spawn();
rpc_server.mine_blocks(1);

assert_eq!(rpc_server.descriptors().len(), 0);

create_wallet(&rpc_server);

CommandBuilder::new("wallet inscribe tulip.png --fee-rate 5.0 ")
.write("tulip.png", [1; 520])
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Inscribe>();

let coinbase = rpc_server.mine_blocks(1)[0].txdata[0].txid();

CommandBuilder::new(format!(
"wallet inscribe orchid.png --fee-rate 1.1 --reinscribe --satpoint {coinbase}:0:0"
))
.write("orchid.png", [1; 520])
.rpc_server(&rpc_server)
.expected_exit_code(1)
.stderr_regex("error: reinscribe flag set but this would not be a reinscription.*")
.run_and_extract_stdout();
}

#[test]
fn try_reinscribe_without_flag() {
let rpc_server = test_bitcoincore_rpc::spawn();
rpc_server.mine_blocks(1);

assert_eq!(rpc_server.descriptors().len(), 0);

create_wallet(&rpc_server);

let reveal_txid = CommandBuilder::new("wallet inscribe tulip.png --fee-rate 5.0 ")
.write("tulip.png", [1; 520])
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Inscribe>()
.reveal;

assert_eq!(rpc_server.descriptors().len(), 3);

rpc_server.mine_blocks(1);

CommandBuilder::new(format!(
"wallet inscribe orchid.png --fee-rate 1.1 --satpoint {reveal_txid}:0:0"
))
.write("orchid.png", [1; 520])
.rpc_server(&rpc_server)
.expected_exit_code(1)
.stderr_regex(format!(
"error: sat at {reveal_txid}:0:0 already inscribed.*"
))
.run_and_extract_stdout();
}