From 21668ef719005b35ab7b95679eb8eb766a0715ab Mon Sep 17 00:00:00 2001 From: 0xZensh Date: Tue, 2 Jan 2024 21:39:03 +0800 Subject: [PATCH] chore: improve ns-inscriber --- crates/ns-inscriber/sample.env | 3 +- crates/ns-inscriber/src/bin/main.rs | 10 ++-- crates/ns-inscriber/src/bitcoin.rs | 12 +++-- crates/ns-inscriber/src/inscriber.rs | 80 ++++++++++++++++------------ crates/ns-protocol/src/ns.rs | 6 +++ 5 files changed, 70 insertions(+), 41 deletions(-) diff --git a/crates/ns-inscriber/sample.env b/crates/ns-inscriber/sample.env index 01d16a2..49fc829 100644 --- a/crates/ns-inscriber/sample.env +++ b/crates/ns-inscriber/sample.env @@ -4,4 +4,5 @@ INSCRIBER_KEYS_DIR="./keys" BITCOIN_NETWORK=regtest # Allowed values: main, test, signet, regtest BITCOIN_RPC_URL=http://127.0.0.1:18443 BITCOIN_RPC_USER=test -BITCOIN_RPC_PASSWORD=123456 \ No newline at end of file +BITCOIN_RPC_PASSWORD=123456 +BITCOIN_RPC_TOKEN="" \ No newline at end of file diff --git a/crates/ns-inscriber/src/bin/main.rs b/crates/ns-inscriber/src/bin/main.rs index c6f3de8..f1b52d3 100644 --- a/crates/ns-inscriber/src/bin/main.rs +++ b/crates/ns-inscriber/src/bin/main.rs @@ -567,12 +567,12 @@ async fn main() -> anyhow::Result<()> { &ns, fee_rate, &keypair.secret_key(), - &vec![UnspentTxOut { + &UnspentTxOut { txid, vout: vout as u32, amount: txout.value, script_pubkey: txout.script_pubkey.clone(), - }], + }, ) .await?; @@ -634,14 +634,16 @@ impl KekEncryptor { async fn get_inscriber(network: Network) -> anyhow::Result { let rpcurl = std::env::var("BITCOIN_RPC_URL").unwrap(); - let rpcuser = std::env::var("BITCOIN_RPC_USER").unwrap(); - let rpcpassword = std::env::var("BITCOIN_RPC_PASSWORD").unwrap(); + let rpcuser = std::env::var("BITCOIN_RPC_USER").unwrap_or_default(); + let rpcpassword = std::env::var("BITCOIN_RPC_PASSWORD").unwrap_or_default(); + let rpctoken = std::env::var("BITCOIN_RPC_TOKEN").unwrap_or_default(); let inscriber = Inscriber::new(&InscriberOptions { bitcoin: BitCoinRPCOptions { rpcurl, rpcuser, rpcpassword, + rpctoken, network, }, })?; diff --git a/crates/ns-inscriber/src/bitcoin.rs b/crates/ns-inscriber/src/bitcoin.rs index 9c7047b..8852886 100644 --- a/crates/ns-inscriber/src/bitcoin.rs +++ b/crates/ns-inscriber/src/bitcoin.rs @@ -29,6 +29,7 @@ pub struct BitCoinRPCOptions { pub rpcurl: String, pub rpcuser: String, pub rpcpassword: String, + pub rpctoken: String, pub network: Network, } @@ -73,7 +74,10 @@ impl BitcoinRPC { common_headers.insert(header::ACCEPT_ENCODING, "gzip".parse()?); let url = reqwest::Url::parse(&opts.rpcurl)?; - if !opts.rpcuser.is_empty() { + if !opts.rpctoken.is_empty() { + let auth = format!("Bearer {}", opts.rpctoken); + common_headers.insert(header::AUTHORIZATION, auth.parse()?); + } else if !opts.rpcuser.is_empty() && !opts.rpcpassword.is_empty() { let auth = format!("{}:{}", opts.rpcuser, opts.rpcpassword); let auth = format!( "Basic {}", @@ -292,13 +296,15 @@ mod tests { dotenvy::from_filename("sample.env").expect(".env file not found"); let rpcurl = std::env::var("BITCOIN_RPC_URL").unwrap(); - let rpcuser = std::env::var("BITCOIN_RPC_USER").unwrap(); - let rpcpassword = std::env::var("BITCOIN_RPC_PASSWORD").unwrap(); + let rpcuser = std::env::var("BITCOIN_RPC_USER").unwrap_or_default(); + let rpcpassword = std::env::var("BITCOIN_RPC_PASSWORD").unwrap_or_default(); + let rpctoken = std::env::var("BITCOIN_RPC_PASSWORD").unwrap_or_default(); let cli = BitcoinRPC::new(&BitCoinRPCOptions { rpcurl, rpcuser, rpcpassword, + rpctoken, network: Network::Regtest, }) .unwrap(); diff --git a/crates/ns-inscriber/src/inscriber.rs b/crates/ns-inscriber/src/inscriber.rs index 83a6aae..835266b 100644 --- a/crates/ns-inscriber/src/inscriber.rs +++ b/crates/ns-inscriber/src/inscriber.rs @@ -58,12 +58,35 @@ impl Inscriber { names: &Vec, fee_rate: Amount, secret: &SecretKey, - unspent_txouts: &Vec, + unspent_txout: &UnspentTxOut, ) -> anyhow::Result { + let (signed_commit_tx, signed_reveal_tx) = self + .build_signed_inscription(names, fee_rate, secret, unspent_txout) + .await?; + + let commit = self.bitcoin.send_transaction(&signed_commit_tx).await?; + let reveal = self + .bitcoin + .send_transaction(&signed_reveal_tx) + .await + .map_err(|err| { + anyhow::anyhow!("failed to send reveal transaction: {err}\ncommit tx: {commit}") + })?; + + Ok(reveal) + } + + pub async fn build_signed_inscription( + &self, + names: &Vec, + fee_rate: Amount, + secret: &SecretKey, + unspent_txout: &UnspentTxOut, + ) -> anyhow::Result<(Transaction, Transaction)> { let keypair = Keypair::from_secret_key(&self.secp, secret); - let (unspent_txout, unsigned_commit_tx, signed_reveal_tx) = self - .build_inscription_transactions(names, fee_rate, unspent_txouts, Some(keypair)) + let (unsigned_commit_tx, signed_reveal_tx) = self + .build_inscription_transactions(names, fee_rate, unspent_txout, Some(keypair)) .await?; let mut signed_commit_tx = unsigned_commit_tx; @@ -130,16 +153,7 @@ impl Inscriber { } } - let commit = self.bitcoin.send_transaction(&signed_commit_tx).await?; - let reveal = self - .bitcoin - .send_transaction(&signed_reveal_tx) - .await - .map_err(|err| { - anyhow::anyhow!("failed to send reveal transaction: {err}\ncommit tx: {commit}") - })?; - - Ok(reveal) + Ok((signed_commit_tx, signed_reveal_tx)) } pub async fn send_sats( @@ -263,18 +277,15 @@ impl Inscriber { &self, names: &Vec, fee_rate: Amount, - unspent_txouts: &Vec, + unspent_txout: &UnspentTxOut, inscription_keypair: Option, - ) -> anyhow::Result<(UnspentTxOut, Transaction, Transaction)> { + ) -> anyhow::Result<(Transaction, Transaction)> { if names.is_empty() { anyhow::bail!("no names to inscribe"); } if fee_rate.to_sat() == 0 { anyhow::bail!("fee rate cannot be zero"); } - if unspent_txouts.is_empty() { - anyhow::bail!("no unspent transaction out"); - } if let Some(name) = check_duplicate(names) { anyhow::bail!("duplicate name {}", name); @@ -286,21 +297,12 @@ impl Inscriber { } } - let (_, _, p_value) = Inscriber::preview_inscription_transactions(names, fee_rate)?; - let mut unspent_tx = &unspent_txouts[0]; - // select a befitting unspent transaction out - for tx in unspent_txouts { - if tx.amount > p_value && tx.amount < unspent_tx.amount { - unspent_tx = &tx; - } - } - let keypair = inscription_keypair .unwrap_or_else(|| Keypair::new(&self.secp, &mut rand::thread_rng())); let (unsigned_commit_tx, signed_reveal_tx) = - self.create_inscription_transactions(names, fee_rate, unspent_tx, &keypair)?; - Ok((unspent_tx.to_owned(), unsigned_commit_tx, signed_reveal_tx)) + self.create_inscription_transactions(names, fee_rate, unspent_txout, &keypair)?; + Ok((unsigned_commit_tx, signed_reveal_tx)) } pub fn preview_inscription_transactions( @@ -625,8 +627,9 @@ mod tests { dotenvy::from_filename("sample.env").expect(".env file not found"); let rpcurl = std::env::var("BITCOIN_RPC_URL").unwrap(); - let rpcuser = std::env::var("BITCOIN_RPC_USER").unwrap(); - let rpcpassword = std::env::var("BITCOIN_RPC_PASSWORD").unwrap(); + let rpcuser = std::env::var("BITCOIN_RPC_USER").unwrap_or_default(); + let rpcpassword = std::env::var("BITCOIN_RPC_PASSWORD").unwrap_or_default(); + let rpctoken = std::env::var("BITCOIN_RPC_TOKEN").unwrap_or_default(); let network = Network::from_core_arg(&std::env::var("BITCOIN_NETWORK").unwrap_or_default()) .unwrap_or(Network::Regtest); @@ -645,6 +648,7 @@ mod tests { rpcurl, rpcuser, rpcpassword, + rpctoken, network, }, }) @@ -702,7 +706,12 @@ mod tests { let names = vec![get_name("0")]; let fee_rate = Amount::from_sat(20); let txid = inscriber - .inscribe(&names, fee_rate, &keypair.secret_key(), &unspent_txs) + .inscribe( + &names, + fee_rate, + &keypair.secret_key(), + &unspent_txs.first().unwrap(), + ) .await .unwrap(); println!("txid: {}", txid); @@ -762,7 +771,12 @@ mod tests { assert_eq!("z", names[35].name); let txid = inscriber - .inscribe(&names, fee_rate, &keypair.secret_key(), &unspent_txs) + .inscribe( + &names, + fee_rate, + &keypair.secret_key(), + &unspent_txs.first().unwrap(), + ) .await .unwrap(); println!("txid: {}", txid); diff --git a/crates/ns-protocol/src/ns.rs b/crates/ns-protocol/src/ns.rs index 566065b..056486b 100644 --- a/crates/ns-protocol/src/ns.rs +++ b/crates/ns-protocol/src/ns.rs @@ -911,6 +911,12 @@ mod tests { assert!(name.verify(¶ms, ThresholdLevel::Strict).is_err()); assert!(name.verify(¶ms, ThresholdLevel::All).is_err()); + let mut invalid_name = name.clone(); + invalid_name.sequence = 1; + assert!(invalid_name + .verify(¶ms, ThresholdLevel::Single) + .is_err()); + name.sign(¶ms, ThresholdLevel::Default, &signers) .unwrap(); assert!(name.validate().is_ok());