make backend synchronous again, implement simple punishment handler

This commit is contained in:
f321x
2024-07-04 13:53:57 +00:00
parent c1083e0cc0
commit 72d2e51ec8
5 changed files with 202 additions and 199 deletions

View File

@ -84,10 +84,10 @@ dependencies = [
"axum-core",
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http",
"http-body",
"http-body-util",
"hyper 1.3.1",
"hyper",
"hyper-util",
"itoa",
"matchit",
@ -117,8 +117,8 @@ dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
@ -179,8 +179,6 @@ dependencies = [
"bitcoin",
"bitcoinconsensus",
"electrum-client",
"esplora-client",
"futures",
"getrandom",
"js-sys",
"log",
@ -224,12 +222,6 @@ dependencies = [
"serde",
]
[[package]]
name = "bitcoin-internals"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f9997f8650dd818369931b5672a18dbef95324d0513aa99aae758de8ce86e5b"
[[package]]
name = "bitcoin-private"
version = "0.1.0"
@ -327,7 +319,7 @@ dependencies = [
"futures-util",
"hex",
"rand",
"reqwest 0.12.5",
"reqwest",
"serde",
"sqlx",
"tokio",
@ -505,19 +497,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "esplora-client"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cb1f7f2489cce83bc3bd92784f9ba5271eeb6e729b975895fc541f78cbfcdca"
dependencies = [
"bitcoin",
"bitcoin-internals",
"log",
"reqwest 0.11.27",
"serde",
]
[[package]]
name = "etcetera"
version = "0.8.0"
@ -592,21 +571,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.30"
@ -680,7 +644,6 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
@ -728,25 +691,6 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "h2"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http 0.2.12",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "h2"
version = "0.4.5"
@ -758,7 +702,7 @@ dependencies = [
"fnv",
"futures-core",
"futures-sink",
"http 1.1.0",
"http",
"indexmap",
"slab",
"tokio",
@ -839,17 +783,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http"
version = "1.1.0"
@ -861,17 +794,6 @@ dependencies = [
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http 0.2.12",
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.0"
@ -879,7 +801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
"http 1.1.0",
"http",
]
[[package]]
@ -890,8 +812,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http",
"http-body",
"pin-project-lite",
]
@ -907,30 +829,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "0.14.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2 0.3.26",
"http 0.2.12",
"http-body 0.4.6",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper"
version = "1.3.1"
@ -940,9 +838,9 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
"h2 0.4.5",
"http 1.1.0",
"http-body 1.0.0",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
@ -959,8 +857,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
dependencies = [
"futures-util",
"http 1.1.0",
"hyper 1.3.1",
"http",
"hyper",
"hyper-util",
"rustls 0.23.10",
"rustls-pki-types",
@ -977,7 +875,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
"hyper 1.3.1",
"hyper",
"hyper-util",
"native-tls",
"tokio",
@ -994,9 +892,9 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"hyper 1.3.1",
"http",
"http-body",
"hyper",
"pin-project-lite",
"socket2",
"tokio",
@ -1526,43 +1424,6 @@ dependencies = [
"bitflags 2.6.0",
]
[[package]]
name = "reqwest"
version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.3.26",
"http 0.2.12",
"http-body 0.4.6",
"hyper 0.14.29",
"ipnet",
"js-sys",
"log",
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper 0.1.2",
"system-configuration",
"tokio",
"tokio-socks",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg 0.50.0",
]
[[package]]
name = "reqwest"
version = "0.12.5"
@ -1575,11 +1436,11 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"h2 0.4.5",
"http 1.1.0",
"http-body 1.0.0",
"h2",
"http",
"http-body",
"http-body-util",
"hyper 1.3.1",
"hyper",
"hyper-rustls",
"hyper-tls",
"hyper-util",
@ -1604,7 +1465,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg 0.52.0",
"winreg",
]
[[package]]
@ -2331,18 +2192,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-socks"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0"
dependencies = [
"either",
"futures-util",
"thiserror",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.15"
@ -2800,16 +2649,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "winreg"
version = "0.52.0"

View File

@ -6,7 +6,11 @@ edition = "2021"
[dependencies]
anyhow = "1.0.86"
axum = { version = "0.7.5", features = ["tokio", "json"] }
bdk = { version = "0.29.0", features = ["key-value-db", "bitcoinconsensus", "verify", "use-esplora-async"] }
# "use-esplora-async", "async-interface", for async esplora
bdk = { version = "0.29.0", default-features = false, features = ["key-value-db", "bitcoinconsensus", "std", "electrum", "verify"] }
# bitcoinconsensus = "0.106.0"
dotenv = "0.15.0"
futures-util = "0.3.30"
hex = "0.4.3"

View File

@ -29,8 +29,7 @@ async fn punish_trader(
// publish bond
coordinator
.coordinator_wallet
.publish_bond_tx_hex(bond_tx_hex)
.await?;
.publish_bond_tx_hex(&bond.bond_tx_hex)?; // can be made async with esplora backend if we figure out the compilation error of bdk
// remove offer from db/orderbook
Ok(())

View File

@ -1,12 +1,12 @@
mod utils;
// pub mod verify_tx;
use super::*;
use anyhow::Context;
use bdk::{
bitcoin::{self, bip32::ExtendedPrivKey, consensus::encode::deserialize, Transaction},
blockchain::{Blockchain, ElectrumBlockchain, EsploraBlockchain},
electrum_client::Client,
esplora_client::AsyncClient,
blockchain::{Blockchain, ElectrumBlockchain},
electrum_client::client::Client,
sled::{self, Tree},
template::Bip86,
wallet::verify::*,
@ -15,11 +15,12 @@ use bdk::{
use std::fmt;
use std::str::FromStr;
use utils::*;
// use verify_tx::*;
#[derive(Clone)]
pub struct CoordinatorWallet {
pub wallet: Arc<Mutex<Wallet<Tree>>>,
pub backend: Arc<EsploraBlockchain>,
pub backend: Arc<ElectrumBlockchain>,
}
#[derive(PartialEq, Debug)]
@ -34,11 +35,11 @@ impl CoordinatorWallet {
let wallet_xprv = ExtendedPrivKey::from_str(
&env::var("WALLET_XPRV").context("loading WALLET_XPRV from .env failed")?,
)?;
// let backend = ElectrumBlockchain::from(Client::new(
// &env::var("ELECTRUM_BACKEND")
// .context("Parsing ELECTRUM_BACKEND from .env failed, is it set?")?,
// )?);
let backend = EsploraBlockchain::new(&env::var("ESPLORA_BACKEND")?, 1000);
let backend = ElectrumBlockchain::from(Client::new(
&env::var("ELECTRUM_BACKEND")
.context("Parsing ELECTRUM_BACKEND from .env failed, is it set?")?,
)?);
// let backend = EsploraBlockchain::new(&env::var("ESPLORA_BACKEND")?, 1000);
let sled_db = sled::open(env::var("BDK_DB_PATH")?)?.open_tree("default_wallet")?;
let wallet = Wallet::new(
Bip86(wallet_xprv, KeychainKind::External),
@ -113,11 +114,11 @@ impl CoordinatorWallet {
Ok(())
}
pub async fn publish_bond_tx_hex(&self, bond: &str) -> Result<()> {
pub fn publish_bond_tx_hex(&self, bond: &str) -> Result<()> {
let blockchain = &*self.backend;
let tx: Transaction = deserialize(&hex::decode(bond)?)?;
blockchain.broadcast(&tx).await?;
blockchain.broadcast(&tx)?;
Ok(())
}
}

View File

@ -0,0 +1,160 @@
////////////////////////////////////////////////////////////////////////////
// copied from bdk as verify_tx does not compile with async esplora backend.
// needs to be updated in case we want to use async esplora
////////////////////////////////////////////////////////////////////////////
//! Verify transactions against the consensus rules
use std::collections::HashMap;
use std::fmt;
use bdk::bitcoin::consensus::serialize;
use bdk::bitcoin::{OutPoint, Transaction, Txid};
use bdk::blockchain::GetTx;
use bdk::database::Database;
// use bdk::error::Error;
/// Verify a transaction against the consensus rules
///
/// This function uses [`bitcoinconsensus`] to verify transactions by fetching the required data
/// either from the [`Database`] or using the [`Blockchain`].
///
/// Depending on the [capabilities](crate::blockchain::Blockchain::get_capabilities) of the
/// [`Blockchain`] backend, the method could fail when called with old "historical" transactions or
/// with unconfirmed transactions that have been evicted from the backend's memory.
///
/// [`Blockchain`]: crate::blockchain::Blockchain
pub fn verify_tx_mod<D: Database, B: GetTx>(
tx: &Transaction,
database: &D,
blockchain: &B,
) -> Result<(), VerifyError> {
// log::debug!("Verifying {}", tx.txid());
let serialized_tx = serialize(tx);
let mut tx_cache = HashMap::<_, Transaction>::new();
for (index, input) in tx.input.iter().enumerate() {
let prev_tx = if let Some(prev_tx) = tx_cache.get(&input.previous_output.txid) {
prev_tx.clone()
} else if let Some(prev_tx) = database.get_raw_tx(&input.previous_output.txid)? {
prev_tx
} else if let Some(prev_tx) = blockchain.get_tx(&input.previous_output.txid)? {
prev_tx
} else {
return Err(VerifyError::MissingInputTx(input.previous_output.txid));
};
let spent_output = prev_tx
.output
.get(input.previous_output.vout as usize)
.ok_or(VerifyError::InvalidInput(input.previous_output))?;
let res = bitcoinconsensus::verify(
&spent_output.script_pubkey.to_bytes(),
spent_output.value,
&serialized_tx,
index,
);
// Since we have a local cache we might as well cache stuff from the db, as it will very
// likely decrease latency compared to reading from disk or performing an SQL query.
tx_cache.insert(prev_tx.txid(), prev_tx);
}
Ok(())
}
/// Error during validation of a tx agains the consensus rules
#[derive(Debug)]
pub enum VerifyError {
/// The transaction being spent is not available in the database or the blockchain client
MissingInputTx(Txid),
/// The transaction being spent doesn't have the requested output
InvalidInput(OutPoint),
/// Consensus error
Consensus(bitcoinconsensus::Error),
/// Generic error
///
/// It has to be wrapped in a `Box` since `Error` has a variant that contains this enum
Global(Box<Error>),
}
impl fmt::Display for VerifyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MissingInputTx(txid) => write!(f, "The transaction being spent is not available in the database or the blockchain client: {}", txid),
Self::InvalidInput(outpoint) => write!(f, "The transaction being spent doesn't have the requested output: {}", outpoint),
Self::Consensus(err) => write!(f, "Consensus error: {:?}", err),
Self::Global(err) => write!(f, "Generic error: {}", err),
}
}
}
impl std::error::Error for VerifyError {}
impl From<Error> for VerifyError {
fn from(other: Error) -> Self {
VerifyError::Global(Box::new(other))
}
}
// impl_error!(bitcoinconsensus::Error, Consensus, VerifyError);
// #[cfg(test)]
// mod test {
// use super::*;
// use crate::database::{BatchOperations, MemoryDatabase};
// use assert_matches::assert_matches;
// use bitcoin::consensus::encode::deserialize;
// use bitcoin::hashes::hex::FromHex;
// use bitcoin::{Transaction, Txid};
// struct DummyBlockchain;
// impl GetTx for DummyBlockchain {
// fn get_tx(&self, _txid: &Txid) -> Result<Option<Transaction>, Error> {
// Ok(None)
// }
// }
// #[test]
// fn test_verify_fail_unsigned_tx() {
// // https://blockstream.info/tx/95da344585fcf2e5f7d6cbf2c3df2dcce84f9196f7a7bb901a43275cd6eb7c3f
// let prev_tx: Transaction = deserialize(&Vec::<u8>::from_hex("020000000101192dea5e66d444380e106f8e53acb171703f00d43fb6b3ae88ca5644bdb7e1000000006b48304502210098328d026ce138411f957966c1cf7f7597ccbb170f5d5655ee3e9f47b18f6999022017c3526fc9147830e1340e04934476a3d1521af5b4de4e98baf49ec4c072079e01210276f847f77ec8dd66d78affd3c318a0ed26d89dab33fa143333c207402fcec352feffffff023d0ac203000000001976a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988aca4b956050000000017a91494d5543c74a3ee98e0cf8e8caef5dc813a0f34b48768cb0700").unwrap()).unwrap();
// // https://blockstream.info/tx/aca326a724eda9a461c10a876534ecd5ae7b27f10f26c3862fb996f80ea2d45d
// let signed_tx: Transaction = deserialize(&Vec::<u8>::from_hex("02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700").unwrap()).unwrap();
// let mut database = MemoryDatabase::new();
// let blockchain = DummyBlockchain;
// let mut unsigned_tx = signed_tx.clone();
// for input in &mut unsigned_tx.input {
// input.script_sig = Default::default();
// input.witness = Default::default();
// }
// let result = verify_tx_mod(&signed_tx, &database, &blockchain);
// assert_matches!(result, Err(VerifyError::MissingInputTx(txid)) if txid == prev_tx.txid(),
// "Error should be a `MissingInputTx` error"
// );
// // insert the prev_tx
// database.set_raw_tx(&prev_tx).unwrap();
// let result = verify_tx_mod(&unsigned_tx, &database, &blockchain);
// assert_matches!(
// result,
// Err(VerifyError::Consensus(_)),
// "Error should be a `Consensus` error"
// );
// let result = verify_tx_mod(&signed_tx, &database, &blockchain);
// assert!(
// result.is_ok(),
// "Should work since the TX is correctly signed"
// );
// }
// }