mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-12-15 08:38:58 -05:00
build(deps): upgrade bdk, ecdsa_fun, sigma_fun, sha2, bitcoin-harness, serde
- bdk to 0.22.0 #1126
- ecdsa_fun to 7c3d592 #1127
- sigma_fun to 7c3d592 #1128
- sha2 to 0.10.2 #948
- serde to 1.0.144 #1115
- bitcoin-harness to bff9a64
Revert "ci: specify previous dprint version until fixed"
This reverts commit 11eb1737ce.
This commit is contained in:
parent
1947e441dc
commit
6e7e39eea4
18 changed files with 323 additions and 372 deletions
|
|
@ -15,9 +15,9 @@ async-trait = "0.1"
|
|||
atty = "0.2"
|
||||
backoff = { version = "0.4", features = [ "tokio" ] }
|
||||
base64 = "0.13"
|
||||
bdk = "0.16"
|
||||
bdk = "0.22"
|
||||
big-bytes = "1"
|
||||
bitcoin = { version = "0.27", features = [ "rand", "use-serde" ] }
|
||||
bitcoin = { version = "0.28", features = [ "rand", "use-serde" ] }
|
||||
bmrng = "0.5"
|
||||
comfy-table = "5.0"
|
||||
config = { version = "0.11", default-features = false, features = [ "toml" ] }
|
||||
|
|
@ -26,7 +26,7 @@ curve25519-dalek = { package = "curve25519-dalek-ng", version = "4" }
|
|||
data-encoding = "2.3"
|
||||
dialoguer = "0.10"
|
||||
directories-next = "2"
|
||||
ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "libsecp_compat", "serde" ] }
|
||||
ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "libsecp_compat", "serde", "adaptor" ] }
|
||||
ed25519-dalek = "1"
|
||||
futures = { version = "0.3", default-features = false }
|
||||
hex = "0.4"
|
||||
|
|
@ -46,8 +46,8 @@ serde = { version = "1", features = [ "derive" ] }
|
|||
serde_cbor = "0.11"
|
||||
serde_json = "1"
|
||||
serde_with = { version = "1", features = [ "macros" ] }
|
||||
sha2 = "0.9"
|
||||
sigma_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "ed25519", "serde" ] }
|
||||
sha2 = "0.10"
|
||||
sigma_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "ed25519", "serde", "secp256k1", "alloc" ] }
|
||||
sqlx = { version = "0.5", features = [ "sqlite", "runtime-tokio-rustls", "offline" ] }
|
||||
structopt = "0.3"
|
||||
strum = { version = "0.24", features = [ "derive" ] }
|
||||
|
|
@ -74,7 +74,7 @@ tokio-tar = "0.3"
|
|||
zip = "0.5"
|
||||
|
||||
[dev-dependencies]
|
||||
bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs" }
|
||||
bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs", rev = "bff9a64b5cd75dec2ce807cbfade7b98c2e1e0d4" } # waiting on crates.io release
|
||||
get-port = "3"
|
||||
hyper = "0.14"
|
||||
monero-harness = { path = "../monero-harness" }
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ pub use wallet::WalletBuilder;
|
|||
use crate::bitcoin::wallet::ScriptStatus;
|
||||
use ::bitcoin::hashes::hex::ToHex;
|
||||
use ::bitcoin::hashes::Hash;
|
||||
use ::bitcoin::{secp256k1, SigHash};
|
||||
use ::bitcoin::{secp256k1, Sighash};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bdk::miniscript::descriptor::Wsh;
|
||||
use bdk::miniscript::{Descriptor, Segwitv0};
|
||||
|
|
@ -78,7 +78,7 @@ impl SecretKey {
|
|||
self.inner.to_bytes()
|
||||
}
|
||||
|
||||
pub fn sign(&self, digest: SigHash) -> Signature {
|
||||
pub fn sign(&self, digest: Sighash) -> Signature {
|
||||
let ecdsa = ECDSA::<Deterministic<Sha256>>::default();
|
||||
|
||||
ecdsa.sign(&self.inner, &digest.into_inner())
|
||||
|
|
@ -98,7 +98,7 @@ impl SecretKey {
|
|||
// alice now has s_a and s_b and can refund monero
|
||||
|
||||
// self = a, Y = S_b, digest = tx_refund
|
||||
pub fn encsign(&self, Y: PublicKey, digest: SigHash) -> EncryptedSignature {
|
||||
pub fn encsign(&self, Y: PublicKey, digest: Sighash) -> EncryptedSignature {
|
||||
let adaptor = Adaptor::<
|
||||
HashTranscript<Sha256, rand_chacha::ChaCha20Rng>,
|
||||
Deterministic<Sha256>,
|
||||
|
|
@ -124,12 +124,12 @@ impl From<PublicKey> for Point {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<PublicKey> for ::bitcoin::PublicKey {
|
||||
fn from(from: PublicKey) -> Self {
|
||||
::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: from.0.into(),
|
||||
}
|
||||
impl TryFrom<PublicKey> for bitcoin::PublicKey {
|
||||
type Error = bitcoin::util::key::Error;
|
||||
|
||||
fn try_from(pubkey: PublicKey) -> Result<Self, Self::Error> {
|
||||
let bytes = pubkey.0.to_bytes();
|
||||
bitcoin::PublicKey::from_slice(&bytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ impl From<Scalar> for PublicKey {
|
|||
|
||||
pub fn verify_sig(
|
||||
verification_key: &PublicKey,
|
||||
transaction_sighash: &SigHash,
|
||||
transaction_sighash: &Sighash,
|
||||
sig: &Signature,
|
||||
) -> Result<()> {
|
||||
let ecdsa = ECDSA::verify_only();
|
||||
|
|
@ -185,7 +185,7 @@ pub struct InvalidSignature;
|
|||
pub fn verify_encsig(
|
||||
verification_key: PublicKey,
|
||||
encryption_key: PublicKey,
|
||||
digest: &SigHash,
|
||||
digest: &Sighash,
|
||||
encsig: &EncryptedSignature,
|
||||
) -> Result<()> {
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
|
@ -457,7 +457,7 @@ mod tests {
|
|||
// transactions have 2 signatures the weight can be up to 8 bytes less than
|
||||
// the static weight (4 bytes per signature).
|
||||
fn assert_weight(transaction: Transaction, expected_weight: usize, tx_name: &str) {
|
||||
let is_weight = transaction.get_weight();
|
||||
let is_weight = transaction.weight();
|
||||
|
||||
assert!(
|
||||
expected_weight - is_weight <= 8,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use crate::bitcoin::wallet::Watchable;
|
|||
use crate::bitcoin::{
|
||||
build_shared_output_descriptor, Address, Amount, BlockHeight, PublicKey, Transaction, TxLock,
|
||||
};
|
||||
use ::bitcoin::util::bip143::SigHashCache;
|
||||
use ::bitcoin::{OutPoint, Script, SigHash, SigHashType, TxIn, TxOut, Txid};
|
||||
use ::bitcoin::util::sighash::SighashCache;
|
||||
use ::bitcoin::{EcdsaSighashType, OutPoint, Script, Sighash, TxIn, TxOut, Txid};
|
||||
use anyhow::Result;
|
||||
use bdk::miniscript::{Descriptor, DescriptorTrait};
|
||||
use ecdsa_fun::Signature;
|
||||
|
|
@ -91,7 +91,7 @@ impl PartialEq<PunishTimelock> for u32 {
|
|||
#[derive(Debug)]
|
||||
pub struct TxCancel {
|
||||
inner: Transaction,
|
||||
digest: SigHash,
|
||||
digest: Sighash,
|
||||
pub(in crate::bitcoin) output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||
lock_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ impl TxCancel {
|
|||
previous_output: tx_lock.as_outpoint(),
|
||||
script_sig: Default::default(),
|
||||
sequence: cancel_timelock.0,
|
||||
witness: Vec::new(),
|
||||
witness: Default::default(),
|
||||
};
|
||||
|
||||
let tx_out = TxOut {
|
||||
|
|
@ -125,12 +125,14 @@ impl TxCancel {
|
|||
output: vec![tx_out],
|
||||
};
|
||||
|
||||
let digest = SigHashCache::new(&transaction).signature_hash(
|
||||
0, // Only one input: lock_input (lock transaction)
|
||||
&tx_lock.output_descriptor.script_code(),
|
||||
tx_lock.lock_amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
let digest = SighashCache::new(&transaction)
|
||||
.segwit_signature_hash(
|
||||
0, // Only one input: lock_input (lock transaction)
|
||||
&tx_lock.output_descriptor.script_code().expect("scriptcode"),
|
||||
tx_lock.lock_amount().as_sat(),
|
||||
EcdsaSighashType::All,
|
||||
)
|
||||
.expect("sighash");
|
||||
|
||||
Self {
|
||||
inner: transaction,
|
||||
|
|
@ -144,7 +146,7 @@ impl TxCancel {
|
|||
self.inner.txid()
|
||||
}
|
||||
|
||||
pub fn digest(&self) -> SigHash {
|
||||
pub fn digest(&self) -> Sighash {
|
||||
self.digest
|
||||
}
|
||||
|
||||
|
|
@ -198,16 +200,22 @@ impl TxCancel {
|
|||
|
||||
let A = ::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: A.0.into(),
|
||||
inner: A.0.into(),
|
||||
};
|
||||
let B = ::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: B.0.into(),
|
||||
inner: B.0.into(),
|
||||
};
|
||||
|
||||
// The order in which these are inserted doesn't matter
|
||||
satisfier.insert(A, (sig_a.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(B, (sig_b.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(A, ::bitcoin::EcdsaSig {
|
||||
sig: sig_a.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
satisfier.insert(B, ::bitcoin::EcdsaSig {
|
||||
sig: sig_b.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
|
||||
satisfier
|
||||
};
|
||||
|
|
@ -231,7 +239,7 @@ impl TxCancel {
|
|||
previous_output,
|
||||
script_sig: Default::default(),
|
||||
sequence: sequence.map(|seq| seq.0).unwrap_or(0xFFFF_FFFF),
|
||||
witness: Vec::new(),
|
||||
witness: Default::default(),
|
||||
};
|
||||
|
||||
let tx_out = TxOut {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ pub struct TxLock {
|
|||
}
|
||||
|
||||
impl TxLock {
|
||||
pub async fn new<B, D, C>(
|
||||
wallet: &Wallet<B, D, C>,
|
||||
pub async fn new<D, C>(
|
||||
wallet: &Wallet<D, C>,
|
||||
amount: Amount,
|
||||
A: PublicKey,
|
||||
B: PublicKey,
|
||||
|
|
@ -57,7 +57,7 @@ impl TxLock {
|
|||
B: PublicKey,
|
||||
btc: Amount,
|
||||
) -> Result<Self> {
|
||||
let shared_output_candidate = match psbt.global.unsigned_tx.output.as_slice() {
|
||||
let shared_output_candidate = match psbt.unsigned_tx.output.as_slice() {
|
||||
[shared_output_candidate, _] if shared_output_candidate.value == btc.as_sat() => {
|
||||
shared_output_candidate
|
||||
}
|
||||
|
|
@ -144,7 +144,7 @@ impl TxLock {
|
|||
previous_output,
|
||||
script_sig: Default::default(),
|
||||
sequence: sequence.unwrap_or(0xFFFF_FFFF),
|
||||
witness: Vec::new(),
|
||||
witness: Default::default(),
|
||||
};
|
||||
|
||||
let fee = spending_fee.as_sat();
|
||||
|
|
@ -212,7 +212,7 @@ mod tests {
|
|||
|
||||
let psbt = bob_make_psbt(A, B, &wallet, agreed_amount).await;
|
||||
assert_eq!(
|
||||
psbt.global.unsigned_tx.output.len(),
|
||||
psbt.unsigned_tx.output.len(),
|
||||
1,
|
||||
"psbt should only have a single output"
|
||||
);
|
||||
|
|
@ -264,7 +264,7 @@ mod tests {
|
|||
async fn bob_make_psbt(
|
||||
A: PublicKey,
|
||||
B: PublicKey,
|
||||
wallet: &Wallet<(), bdk::database::MemoryDatabase, StaticFeeRate>,
|
||||
wallet: &Wallet<bdk::database::MemoryDatabase, StaticFeeRate>,
|
||||
amount: Amount,
|
||||
) -> PartiallySignedTransaction {
|
||||
let change = wallet.new_address().await.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::bitcoin::wallet::Watchable;
|
||||
use crate::bitcoin::{self, Address, Amount, PunishTimelock, Transaction, TxCancel, Txid};
|
||||
use ::bitcoin::util::bip143::SigHashCache;
|
||||
use ::bitcoin::{SigHash, SigHashType};
|
||||
use ::bitcoin::util::sighash::SighashCache;
|
||||
use ::bitcoin::{EcdsaSighashType, Sighash};
|
||||
use anyhow::{Context, Result};
|
||||
use bdk::bitcoin::Script;
|
||||
use bdk::miniscript::{Descriptor, DescriptorTrait};
|
||||
|
|
@ -10,7 +10,7 @@ use std::collections::HashMap;
|
|||
#[derive(Debug)]
|
||||
pub struct TxPunish {
|
||||
inner: Transaction,
|
||||
digest: SigHash,
|
||||
digest: Sighash,
|
||||
cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||
watch_script: Script,
|
||||
}
|
||||
|
|
@ -25,12 +25,17 @@ impl TxPunish {
|
|||
let tx_punish =
|
||||
tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock), spending_fee);
|
||||
|
||||
let digest = SigHashCache::new(&tx_punish).signature_hash(
|
||||
0, // Only one input: cancel transaction
|
||||
&tx_cancel.output_descriptor.script_code(),
|
||||
tx_cancel.amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
let digest = SighashCache::new(&tx_punish)
|
||||
.segwit_signature_hash(
|
||||
0, // Only one input: cancel transaction
|
||||
&tx_cancel
|
||||
.output_descriptor
|
||||
.script_code()
|
||||
.expect("scriptcode"),
|
||||
tx_cancel.amount().as_sat(),
|
||||
EcdsaSighashType::All,
|
||||
)
|
||||
.expect("sighash");
|
||||
|
||||
Self {
|
||||
inner: tx_punish,
|
||||
|
|
@ -40,7 +45,7 @@ impl TxPunish {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn digest(&self) -> SigHash {
|
||||
pub fn digest(&self) -> Sighash {
|
||||
self.digest
|
||||
}
|
||||
|
||||
|
|
@ -56,12 +61,18 @@ impl TxPunish {
|
|||
let satisfier = {
|
||||
let mut satisfier = HashMap::with_capacity(2);
|
||||
|
||||
let A = a.public().into();
|
||||
let B = B.into();
|
||||
let A = a.public().try_into()?;
|
||||
let B = B.try_into()?;
|
||||
|
||||
// The order in which these are inserted doesn't matter
|
||||
satisfier.insert(A, (sig_a.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(B, (sig_b.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(A, ::bitcoin::EcdsaSig {
|
||||
sig: sig_a.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
satisfier.insert(B, ::bitcoin::EcdsaSig {
|
||||
sig: sig_b.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
|
||||
satisfier
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ use crate::bitcoin::{
|
|||
verify_encsig, verify_sig, Address, Amount, EmptyWitnessStack, EncryptedSignature, NoInputs,
|
||||
NotThreeWitnesses, PublicKey, SecretKey, TooManyInputs, Transaction, TxLock,
|
||||
};
|
||||
use ::bitcoin::util::bip143::SigHashCache;
|
||||
use ::bitcoin::{SigHash, SigHashType, Txid};
|
||||
use ::bitcoin::{Sighash, Txid};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bdk::miniscript::{Descriptor, DescriptorTrait};
|
||||
use bitcoin::Script;
|
||||
use bitcoin::secp256k1::ecdsa;
|
||||
use bitcoin::util::sighash::SighashCache;
|
||||
use bitcoin::{EcdsaSighashType, Script};
|
||||
use ecdsa_fun::adaptor::{Adaptor, HashTranscript};
|
||||
use ecdsa_fun::fun::Scalar;
|
||||
use ecdsa_fun::nonce::Deterministic;
|
||||
|
|
@ -18,7 +19,7 @@ use std::collections::HashMap;
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct TxRedeem {
|
||||
inner: Transaction,
|
||||
digest: SigHash,
|
||||
digest: Sighash,
|
||||
lock_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||
watch_script: Script,
|
||||
}
|
||||
|
|
@ -29,12 +30,14 @@ impl TxRedeem {
|
|||
// redeem transaction
|
||||
let tx_redeem = tx_lock.build_spend_transaction(redeem_address, None, spending_fee);
|
||||
|
||||
let digest = SigHashCache::new(&tx_redeem).signature_hash(
|
||||
0, // Only one input: lock_input (lock transaction)
|
||||
&tx_lock.output_descriptor.script_code(),
|
||||
tx_lock.lock_amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
let digest = SighashCache::new(&tx_redeem)
|
||||
.segwit_signature_hash(
|
||||
0, // Only one input: lock_input (lock transaction)
|
||||
&tx_lock.output_descriptor.script_code().expect("scriptcode"),
|
||||
tx_lock.lock_amount().as_sat(),
|
||||
EcdsaSighashType::All,
|
||||
)
|
||||
.expect("sighash");
|
||||
|
||||
Self {
|
||||
inner: tx_redeem,
|
||||
|
|
@ -48,7 +51,7 @@ impl TxRedeem {
|
|||
self.inner.txid()
|
||||
}
|
||||
|
||||
pub fn digest(&self) -> SigHash {
|
||||
pub fn digest(&self) -> Sighash {
|
||||
self.digest
|
||||
}
|
||||
|
||||
|
|
@ -76,16 +79,22 @@ impl TxRedeem {
|
|||
|
||||
let A = ::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: a.public.into(),
|
||||
inner: a.public.into(),
|
||||
};
|
||||
let B = ::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: B.0.into(),
|
||||
inner: B.0.into(),
|
||||
};
|
||||
|
||||
// The order in which these are inserted doesn't matter
|
||||
satisfier.insert(A, (sig_a.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(B, (sig_b.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(A, ::bitcoin::EcdsaSig {
|
||||
sig: sig_a.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
satisfier.insert(B, ::bitcoin::EcdsaSig {
|
||||
sig: sig_b.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
|
||||
satisfier
|
||||
};
|
||||
|
|
@ -108,19 +117,10 @@ impl TxRedeem {
|
|||
[inputs @ ..] => bail!(TooManyInputs(inputs.len())),
|
||||
};
|
||||
|
||||
let sigs = match input
|
||||
.witness
|
||||
.iter()
|
||||
.map(|vec| vec.as_slice())
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice()
|
||||
{
|
||||
let sigs = match input.witness.iter().collect::<Vec<_>>().as_slice() {
|
||||
[sig_1, sig_2, _script] => [sig_1, sig_2]
|
||||
.iter()
|
||||
.map(|sig| {
|
||||
bitcoin::secp256k1::Signature::from_der(&sig[..sig.len() - 1])
|
||||
.map(Signature::from)
|
||||
})
|
||||
.map(|sig| ecdsa::Signature::from_der(&sig[..sig.len() - 1]).map(Signature::from))
|
||||
.collect::<std::result::Result<Vec<_>, _>>(),
|
||||
[] => bail!(EmptyWitnessStack),
|
||||
[witnesses @ ..] => bail!(NotThreeWitnesses(witnesses.len())),
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ use crate::bitcoin::{
|
|||
TooManyInputs, Transaction, TxCancel,
|
||||
};
|
||||
use crate::{bitcoin, monero};
|
||||
use ::bitcoin::util::bip143::SigHashCache;
|
||||
use ::bitcoin::{Script, SigHash, SigHashType, Txid};
|
||||
use ::bitcoin::secp256k1::ecdsa;
|
||||
use ::bitcoin::util::sighash::SighashCache;
|
||||
use ::bitcoin::{EcdsaSighashType, Script, Sighash, Txid};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bdk::miniscript::{Descriptor, DescriptorTrait};
|
||||
use ecdsa_fun::Signature;
|
||||
|
|
@ -14,7 +15,7 @@ use std::collections::HashMap;
|
|||
#[derive(Debug)]
|
||||
pub struct TxRefund {
|
||||
inner: Transaction,
|
||||
digest: SigHash,
|
||||
digest: Sighash,
|
||||
cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||
watch_script: Script,
|
||||
}
|
||||
|
|
@ -23,12 +24,17 @@ impl TxRefund {
|
|||
pub fn new(tx_cancel: &TxCancel, refund_address: &Address, spending_fee: Amount) -> Self {
|
||||
let tx_refund = tx_cancel.build_spend_transaction(refund_address, None, spending_fee);
|
||||
|
||||
let digest = SigHashCache::new(&tx_refund).signature_hash(
|
||||
0, // Only one input: cancel transaction
|
||||
&tx_cancel.output_descriptor.script_code(),
|
||||
tx_cancel.amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
let digest = SighashCache::new(&tx_refund)
|
||||
.segwit_signature_hash(
|
||||
0, // Only one input: cancel transaction
|
||||
&tx_cancel
|
||||
.output_descriptor
|
||||
.script_code()
|
||||
.expect("scriptcode"),
|
||||
tx_cancel.amount().as_sat(),
|
||||
EcdsaSighashType::All,
|
||||
)
|
||||
.expect("sighash");
|
||||
|
||||
Self {
|
||||
inner: tx_refund,
|
||||
|
|
@ -42,7 +48,7 @@ impl TxRefund {
|
|||
self.inner.txid()
|
||||
}
|
||||
|
||||
pub fn digest(&self) -> SigHash {
|
||||
pub fn digest(&self) -> Sighash {
|
||||
self.digest
|
||||
}
|
||||
|
||||
|
|
@ -56,16 +62,22 @@ impl TxRefund {
|
|||
|
||||
let A = ::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: A.0.into(),
|
||||
inner: A.0.into(),
|
||||
};
|
||||
let B = ::bitcoin::PublicKey {
|
||||
compressed: true,
|
||||
key: B.0.into(),
|
||||
inner: B.0.into(),
|
||||
};
|
||||
|
||||
// The order in which these are inserted doesn't matter
|
||||
satisfier.insert(A, (sig_a.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(B, (sig_b.into(), ::bitcoin::SigHashType::All));
|
||||
satisfier.insert(A, ::bitcoin::EcdsaSig {
|
||||
sig: sig_a.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
satisfier.insert(B, ::bitcoin::EcdsaSig {
|
||||
sig: sig_b.into(),
|
||||
hash_ty: EcdsaSighashType::All,
|
||||
});
|
||||
|
||||
satisfier
|
||||
};
|
||||
|
|
@ -112,19 +124,10 @@ impl TxRefund {
|
|||
[inputs @ ..] => bail!(TooManyInputs(inputs.len())),
|
||||
};
|
||||
|
||||
let sigs = match input
|
||||
.witness
|
||||
.iter()
|
||||
.map(|vec| vec.as_slice())
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice()
|
||||
{
|
||||
let sigs = match input.witness.iter().collect::<Vec<_>>().as_slice() {
|
||||
[sig_1, sig_2, _script] => [sig_1, sig_2]
|
||||
.iter()
|
||||
.map(|sig| {
|
||||
bitcoin::secp256k1::Signature::from_der(&sig[..sig.len() - 1])
|
||||
.map(Signature::from)
|
||||
})
|
||||
.map(|sig| ecdsa::Signature::from_der(&sig[..sig.len() - 1]).map(Signature::from))
|
||||
.collect::<std::result::Result<Vec<_>, _>>(),
|
||||
[] => bail!(EmptyWitnessStack),
|
||||
[witnesses @ ..] => bail!(NotThreeWitnesses(witnesses.len())),
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ use crate::env;
|
|||
use ::bitcoin::util::psbt::PartiallySignedTransaction;
|
||||
use ::bitcoin::Txid;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bdk::blockchain::{noop_progress, Blockchain, ElectrumBlockchain};
|
||||
use bdk::blockchain::{Blockchain, ElectrumBlockchain, GetTx};
|
||||
use bdk::database::BatchDatabase;
|
||||
use bdk::descriptor::Segwitv0;
|
||||
use bdk::electrum_client::{ElectrumApi, GetHistoryRes};
|
||||
use bdk::keys::DerivableKey;
|
||||
use bdk::wallet::export::WalletExport;
|
||||
use bdk::wallet::export::FullyNodedExport;
|
||||
use bdk::wallet::AddressIndex;
|
||||
use bdk::{FeeRate, KeychainKind, SignOptions};
|
||||
use bdk::{FeeRate, KeychainKind, SignOptions, SyncOptions};
|
||||
use bitcoin::{Network, Script};
|
||||
use reqwest::Url;
|
||||
use rust_decimal::prelude::*;
|
||||
|
|
@ -33,9 +33,9 @@ const MAX_RELATIVE_TX_FEE: Decimal = dec!(0.03);
|
|||
const MAX_ABSOLUTE_TX_FEE: Decimal = dec!(100_000);
|
||||
const DUST_AMOUNT: u64 = 546;
|
||||
|
||||
pub struct Wallet<B = ElectrumBlockchain, D = bdk::sled::Tree, C = Client> {
|
||||
pub struct Wallet<D = bdk::sled::Tree, C = Client> {
|
||||
client: Arc<Mutex<C>>,
|
||||
wallet: Arc<Mutex<bdk::Wallet<B, D>>>,
|
||||
wallet: Arc<Mutex<bdk::Wallet<D>>>,
|
||||
finality_confirmations: u32,
|
||||
network: Network,
|
||||
target_block: usize,
|
||||
|
|
@ -49,12 +49,6 @@ impl Wallet {
|
|||
env_config: env::Config,
|
||||
target_block: usize,
|
||||
) -> Result<Self> {
|
||||
let config = bdk::electrum_client::ConfigBuilder::default()
|
||||
.retry(5)
|
||||
.build();
|
||||
let client = bdk::electrum_client::Client::from_config(electrum_rpc_url.as_str(), config)
|
||||
.context("Failed to initialize Electrum RPC client")?;
|
||||
|
||||
let db = bdk::sled::open(wallet_dir)?.open_tree(SLED_TREE_NAME)?;
|
||||
|
||||
let wallet = bdk::Wallet::new(
|
||||
|
|
@ -62,19 +56,14 @@ impl Wallet {
|
|||
Some(bdk::template::Bip84(key, KeychainKind::Internal)),
|
||||
env_config.bitcoin_network,
|
||||
db,
|
||||
ElectrumBlockchain::from(client),
|
||||
)?;
|
||||
|
||||
let electrum = bdk::electrum_client::Client::new(electrum_rpc_url.as_str())
|
||||
.context("Failed to initialize Electrum RPC client")?;
|
||||
let client = Client::new(electrum_rpc_url, env_config.bitcoin_sync_interval())?;
|
||||
|
||||
let network = wallet.network();
|
||||
|
||||
Ok(Self {
|
||||
client: Arc::new(Mutex::new(Client::new(
|
||||
electrum,
|
||||
env_config.bitcoin_sync_interval(),
|
||||
)?)),
|
||||
client: Arc::new(Mutex::new(client)),
|
||||
wallet: Arc::new(Mutex::new(wallet)),
|
||||
finality_confirmations: env_config.bitcoin_finality_confirmations,
|
||||
network,
|
||||
|
|
@ -99,13 +88,12 @@ impl Wallet {
|
|||
.subscribe_to((txid, transaction.output[0].script_pubkey.clone()))
|
||||
.await;
|
||||
|
||||
self.wallet
|
||||
.lock()
|
||||
.await
|
||||
.broadcast(&transaction)
|
||||
.with_context(|| {
|
||||
format!("Failed to broadcast Bitcoin {} transaction {}", kind, txid)
|
||||
})?;
|
||||
let client = self.client.lock().await;
|
||||
let blockchain = client.blockchain();
|
||||
|
||||
blockchain.broadcast(&transaction).with_context(|| {
|
||||
format!("Failed to broadcast Bitcoin {} transaction {}", kind, txid)
|
||||
})?;
|
||||
|
||||
tracing::info!(%txid, %kind, "Published Bitcoin transaction");
|
||||
|
||||
|
|
@ -179,9 +167,9 @@ impl Wallet {
|
|||
sub
|
||||
}
|
||||
|
||||
pub async fn wallet_export(&self, role: &str) -> Result<WalletExport> {
|
||||
pub async fn wallet_export(&self, role: &str) -> Result<FullyNodedExport> {
|
||||
let wallet = self.wallet.lock().await;
|
||||
match bdk::wallet::export::WalletExport::export_wallet(
|
||||
match bdk::wallet::export::FullyNodedExport::export_wallet(
|
||||
&wallet,
|
||||
&format!("{}-{}", role, self.network),
|
||||
true,
|
||||
|
|
@ -269,7 +257,7 @@ impl Subscription {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B, D, C> Wallet<B, D, C>
|
||||
impl<D, C> Wallet<D, C>
|
||||
where
|
||||
C: EstimateFeeRate,
|
||||
D: BatchDatabase,
|
||||
|
|
@ -293,6 +281,7 @@ where
|
|||
Ok(tx)
|
||||
}
|
||||
|
||||
/// Returns the total Bitcoin balance, which includes pending funds
|
||||
pub async fn balance(&self) -> Result<Amount> {
|
||||
let balance = self
|
||||
.wallet
|
||||
|
|
@ -301,7 +290,7 @@ where
|
|||
.get_balance()
|
||||
.context("Failed to calculate Bitcoin balance")?;
|
||||
|
||||
Ok(Amount::from_sat(balance))
|
||||
Ok(Amount::from_sat(balance.get_total()))
|
||||
}
|
||||
|
||||
pub async fn new_address(&self) -> Result<Address> {
|
||||
|
|
@ -362,11 +351,11 @@ where
|
|||
let (psbt, _details) = tx_builder.finish()?;
|
||||
let mut psbt: PartiallySignedTransaction = psbt;
|
||||
|
||||
match psbt.global.unsigned_tx.output.as_mut_slice() {
|
||||
match psbt.unsigned_tx.output.as_mut_slice() {
|
||||
// our primary output is the 2nd one? reverse the vectors
|
||||
[_, second_txout] if second_txout.script_pubkey == script => {
|
||||
psbt.outputs.reverse();
|
||||
psbt.global.unsigned_tx.output.reverse();
|
||||
psbt.unsigned_tx.output.reverse();
|
||||
}
|
||||
[first_txout, _] if first_txout.script_pubkey == script => {
|
||||
// no need to do anything
|
||||
|
|
@ -378,7 +367,7 @@ where
|
|||
}
|
||||
|
||||
if let ([_, change], [_, psbt_output], Some(change_override)) = (
|
||||
&mut psbt.global.unsigned_tx.output.as_mut_slice(),
|
||||
&mut psbt.unsigned_tx.output.as_mut_slice(),
|
||||
&mut psbt.outputs.as_mut_slice(),
|
||||
change_override,
|
||||
) {
|
||||
|
|
@ -399,13 +388,13 @@ where
|
|||
pub async fn max_giveable(&self, locking_script_size: usize) -> Result<Amount> {
|
||||
let wallet = self.wallet.lock().await;
|
||||
let balance = wallet.get_balance()?;
|
||||
if balance < DUST_AMOUNT {
|
||||
if balance.get_total() < DUST_AMOUNT {
|
||||
return Ok(Amount::ZERO);
|
||||
}
|
||||
let client = self.client.lock().await;
|
||||
let min_relay_fee = client.min_relay_fee()?.as_sat();
|
||||
|
||||
if balance < min_relay_fee {
|
||||
if balance.get_total() < min_relay_fee {
|
||||
return Ok(Amount::ZERO);
|
||||
}
|
||||
|
||||
|
|
@ -457,7 +446,7 @@ fn estimate_fee(
|
|||
if transfer_amount.as_sat() <= 546 {
|
||||
bail!("Amounts needs to be greater than Bitcoin dust amount.")
|
||||
}
|
||||
let fee_rate_svb = fee_rate.as_sat_vb();
|
||||
let fee_rate_svb = fee_rate.as_sat_per_vb();
|
||||
if fee_rate_svb <= 0.0 {
|
||||
bail!("Fee rate needs to be > 0")
|
||||
}
|
||||
|
|
@ -518,29 +507,32 @@ fn estimate_fee(
|
|||
Ok(amount)
|
||||
}
|
||||
|
||||
impl<B, D, C> Wallet<B, D, C>
|
||||
impl<D> Wallet<D>
|
||||
where
|
||||
B: Blockchain,
|
||||
D: BatchDatabase,
|
||||
{
|
||||
pub async fn get_tx(&self, txid: Txid) -> Result<Option<Transaction>> {
|
||||
let tx = self.wallet.lock().await.client().get_tx(&txid)?;
|
||||
let client = self.client.lock().await;
|
||||
let tx = client.get_tx(&txid)?;
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
pub async fn sync(&self) -> Result<()> {
|
||||
let client = self.client.lock().await;
|
||||
let blockchain = client.blockchain();
|
||||
let sync_opts = SyncOptions::default();
|
||||
self.wallet
|
||||
.lock()
|
||||
.await
|
||||
.sync(noop_progress(), None)
|
||||
.sync(blockchain, sync_opts)
|
||||
.context("Failed to sync balance of Bitcoin wallet")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, D, C> Wallet<B, D, C> {
|
||||
impl<D, C> Wallet<D, C> {
|
||||
// TODO: Get rid of this by changing bounds on bdk::Wallet
|
||||
pub fn get_network(&self) -> bitcoin::Network {
|
||||
self.network
|
||||
|
|
@ -570,6 +562,7 @@ impl EstimateFeeRate for StaticFeeRate {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Debug)]
|
||||
pub struct WalletBuilder {
|
||||
utxo_amount: u64,
|
||||
sats_per_vb: f32,
|
||||
|
|
@ -621,9 +614,9 @@ impl WalletBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn build(self) -> Wallet<(), bdk::database::MemoryDatabase, StaticFeeRate> {
|
||||
use bdk::database::MemoryDatabase;
|
||||
use bdk::testutils;
|
||||
pub fn build(self) -> Wallet<bdk::database::MemoryDatabase, StaticFeeRate> {
|
||||
use bdk::database::{BatchOperations, MemoryDatabase, SyncTime};
|
||||
use bdk::{testutils, BlockTime};
|
||||
|
||||
let descriptors = testutils!(@descriptors (&format!("wpkh({}/*)", self.key)));
|
||||
|
||||
|
|
@ -638,9 +631,14 @@ impl WalletBuilder {
|
|||
Some(100)
|
||||
);
|
||||
}
|
||||
let block_time = bdk::BlockTime {
|
||||
height: 100,
|
||||
timestamp: 0,
|
||||
};
|
||||
let sync_time = SyncTime { block_time };
|
||||
database.set_sync_time(sync_time).unwrap();
|
||||
|
||||
let wallet =
|
||||
bdk::Wallet::new_offline(&descriptors.0, None, Network::Regtest, database).unwrap();
|
||||
let wallet = bdk::Wallet::new(&descriptors.0, None, Network::Regtest, database).unwrap();
|
||||
|
||||
Wallet {
|
||||
client: Arc::new(Mutex::new(StaticFeeRate {
|
||||
|
|
@ -678,6 +676,7 @@ impl Watchable for (Txid, Script) {
|
|||
|
||||
pub struct Client {
|
||||
electrum: bdk::electrum_client::Client,
|
||||
blockchain: ElectrumBlockchain,
|
||||
latest_block_height: BlockHeight,
|
||||
last_sync: Instant,
|
||||
sync_interval: Duration,
|
||||
|
|
@ -686,15 +685,25 @@ pub struct Client {
|
|||
}
|
||||
|
||||
impl Client {
|
||||
fn new(electrum: bdk::electrum_client::Client, interval: Duration) -> Result<Self> {
|
||||
fn new(electrum_rpc_url: Url, interval: Duration) -> Result<Self> {
|
||||
let config = bdk::electrum_client::ConfigBuilder::default()
|
||||
.retry(5)
|
||||
.build();
|
||||
let electrum = bdk::electrum_client::Client::from_config(electrum_rpc_url.as_str(), config)
|
||||
.context("Failed to initialize Electrum RPC client")?;
|
||||
// Initially fetch the latest block for storing the height.
|
||||
// We do not act on this subscription after this call.
|
||||
let latest_block = electrum
|
||||
.block_headers_subscribe()
|
||||
.context("Failed to subscribe to header notifications")?;
|
||||
|
||||
let client = bdk::electrum_client::Client::new(electrum_rpc_url.as_str())
|
||||
.context("Failed to initialize Electrum RPC client")?;
|
||||
let blockchain = ElectrumBlockchain::from(client);
|
||||
|
||||
Ok(Self {
|
||||
electrum,
|
||||
blockchain,
|
||||
latest_block_height: BlockHeight::try_from(latest_block)?,
|
||||
last_sync: Instant::now(),
|
||||
sync_interval: interval,
|
||||
|
|
@ -703,6 +712,14 @@ impl Client {
|
|||
})
|
||||
}
|
||||
|
||||
fn blockchain(&self) -> &ElectrumBlockchain {
|
||||
&self.blockchain
|
||||
}
|
||||
|
||||
fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, bdk::Error> {
|
||||
self.blockchain.get_tx(txid)
|
||||
}
|
||||
|
||||
fn update_state(&mut self) -> Result<()> {
|
||||
let now = Instant::now();
|
||||
if now < self.last_sync + self.sync_interval {
|
||||
|
|
|
|||
|
|
@ -248,9 +248,8 @@ impl EventLoopHandle {
|
|||
&mut self,
|
||||
tx_redeem_encsig: EncryptedSignature,
|
||||
) -> Result<(), bmrng::error::RequestError<EncryptedSignature>> {
|
||||
Ok(self
|
||||
.encrypted_signature
|
||||
self.encrypted_signature
|
||||
.send_receive(tx_redeem_encsig)
|
||||
.await?)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use tokio_util::io::StreamReader;
|
|||
compile_error!("unsupported operating system");
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
const DOWNLOAD_URL: &str = "http://downloads.getmonero.org/cli/monero-mac-x64-v0.18.0.0.tar.bz2";
|
||||
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-x64-v0.18.0.0.tar.bz2";
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "arm"))]
|
||||
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-armv8-v0.18.0.0.tar.bz2";
|
||||
|
|
@ -142,7 +142,7 @@ impl WalletRpc {
|
|||
tracing::debug!("{}%", percent);
|
||||
notified = percent;
|
||||
}
|
||||
file.write(&bytes).await?;
|
||||
file.write_all(&bytes).await?;
|
||||
}
|
||||
|
||||
file.flush().await?;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ pub mod ecdsa_fun {
|
|||
use ::ecdsa_fun::fun::{Point, Scalar, G};
|
||||
|
||||
pub fn point() -> impl Strategy<Value = Point> {
|
||||
scalar().prop_map(|mut scalar| Point::from_scalar_mul(G, &mut scalar).mark::<Normal>())
|
||||
scalar()
|
||||
.prop_map(|mut scalar| Point::even_y_from_scalar_mul(G, &mut scalar).mark::<Normal>())
|
||||
}
|
||||
|
||||
pub fn scalar() -> impl Strategy<Value = Scalar> {
|
||||
|
|
|
|||
|
|
@ -149,9 +149,9 @@ impl State0 {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn receive<B, D, C>(
|
||||
pub async fn receive<D, C>(
|
||||
self,
|
||||
wallet: &bitcoin::Wallet<B, D, C>,
|
||||
wallet: &bitcoin::Wallet<D, C>,
|
||||
msg: Message1,
|
||||
) -> Result<State1>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ async fn mine(bitcoind_client: Client, reward_address: bitcoin::Address) -> Resu
|
|||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
bitcoind_client
|
||||
.generatetoaddress(1, reward_address.clone(), None)
|
||||
.generatetoaddress(1, reward_address.clone())
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
|
@ -920,7 +920,7 @@ async fn init_bitcoind(node_url: Url, spendable_quantity: u32) -> Result<Client>
|
|||
.await?;
|
||||
|
||||
bitcoind_client
|
||||
.generatetoaddress(101 + spendable_quantity, reward_address.clone(), None)
|
||||
.generatetoaddress(101 + spendable_quantity, reward_address.clone())
|
||||
.await?;
|
||||
let _ = tokio::spawn(mine(bitcoind_client.clone(), reward_address));
|
||||
Ok(bitcoind_client)
|
||||
|
|
@ -940,9 +940,7 @@ pub async fn mint(node_url: Url, address: bitcoin::Address, amount: bitcoin::Amo
|
|||
.with_wallet(BITCOIN_TEST_WALLET_NAME)?
|
||||
.getnewaddress(None, None)
|
||||
.await?;
|
||||
bitcoind_client
|
||||
.generatetoaddress(1, reward_address, None)
|
||||
.await?;
|
||||
bitcoind_client.generatetoaddress(1, reward_address).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue