From 8647dd4f58d06317d3cbc1e5358962c20fe5cb0e Mon Sep 17 00:00:00 2001 From: will-bitlight Date: Wed, 17 Jul 2024 21:30:31 +0800 Subject: [PATCH] Support Testnet4 Network (#221) --- Cargo.lock | 24 +++--- Cargo.toml | 12 ++- cli/src/args.rs | 16 ++-- src/indexers/any.rs | 11 +++ src/indexers/electrum_blocking.rs | 1 + src/indexers/mempool_blocking.rs | 130 ++++++++++++++++++++++++++++++ src/indexers/mod.rs | 3 + 7 files changed, 172 insertions(+), 25 deletions(-) create mode 100644 src/indexers/mempool_blocking.rs diff --git a/Cargo.lock b/Cargo.lock index a408599..cea585d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,8 +394,7 @@ dependencies = [ [[package]] name = "bp-derive" version = "0.11.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0feca5f56441ef824fe6238c7718f28a21c74ab945e7ac1d1cc191a6b221e241" +source = "git+https://github.com/BP-WG/bp-std.git?branch=master#c291e0b54e21482e432f6836c02474c10d6b014e" dependencies = [ "amplify", "bitcoin_hashes", @@ -443,8 +442,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.11.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f051e70a99388097774781b109fc7dd4f4e9b17820be777c2655c37175981b9" +source = "git+https://github.com/BP-WG/bp-std.git?branch=master#c291e0b54e21482e432f6836c02474c10d6b014e" dependencies = [ "amplify", "bech32", @@ -473,8 +471,7 @@ dependencies = [ [[package]] name = "bp-std" version = "0.11.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573dcef793e4058c1a8c3632eb10d0486eff4979a2d753b51e8a06017922d8d7" +source = "git+https://github.com/BP-WG/bp-std.git?branch=master#c291e0b54e21482e432f6836c02474c10d6b014e" dependencies = [ "amplify", "bp-consensus", @@ -488,7 +485,7 @@ dependencies = [ [[package]] name = "bp-wallet" version = "0.11.0-beta.6.1" -source = "git+https://github.com/BP-WG/bp-wallet?branch=master#418bf29b9408f90888c9f234749b6ddc57bed9ed" +source = "git+https://github.com/BP-WG/bp-wallet?branch=master#b63b7ac79771d9dc79d17d9de11c9e2ef53e4eac" dependencies = [ "amplify", "base64", @@ -761,8 +758,7 @@ dependencies = [ [[package]] name = "descriptors" version = "0.11.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5af8b4d31550689f92ccb34142b13b635d8e4316cc4a73a0c7254cf8170d16" +source = "git+https://github.com/BP-WG/bp-std.git?branch=master#c291e0b54e21482e432f6836c02474c10d6b014e" dependencies = [ "amplify", "bp-derive", @@ -1263,8 +1259,7 @@ dependencies = [ [[package]] name = "psbt" version = "0.11.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500d928c69d44b90fa22f3209fb8d349b436ef8973754ccfa085a8db8392e422" +source = "git+https://github.com/BP-WG/bp-std.git?branch=master#c291e0b54e21482e432f6836c02474c10d6b014e" dependencies = [ "amplify", "base64", @@ -1381,8 +1376,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6b72d48f84e84792305e277f3266f06ef201b741a70a5d35b8b761ea786744" +source = "git+https://github.com/RGB-WG/rgb-interfaces.git?branch=master#05166e951f9b4b0663114d1e248f840ffbfe8f23" dependencies = [ "aluvm", "amplify", @@ -1398,7 +1392,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-std?branch=master#de91f0e72ec24f8768c66b5a86c48447a051bfed" +source = "git+https://github.com/RGB-WG/rgb-std?branch=master#48bb105d8b99d2c88dfbb574cee9ecb2021c439b" dependencies = [ "amplify", "baid64", @@ -1460,7 +1454,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-std?branch=master#de91f0e72ec24f8768c66b5a86c48447a051bfed" +source = "git+https://github.com/RGB-WG/rgb-std?branch=master#48bb105d8b99d2c88dfbb574cee9ecb2021c439b" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index 547d79b..8c79cca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,13 +82,14 @@ serde_yaml = { workspace = true, optional = true } log = { workspace = true, optional = true } [features] -default = ["esplora_blocking"] -all = ["esplora_blocking", "electrum_blocking", "serde", "log", "fs", "cli"] +default = ["esplora_blocking", "mempool_blocking"] +all = ["esplora_blocking", "electrum_blocking", "mempool_blocking", "serde", "log", "fs", "cli"] fs = ["serde", "bp-wallet/fs"] -cli = ["fs"] +cli = ["fs", "bp-wallet/cli"] esplora_blocking = ["bp-esplora"] electrum_blocking = ["bp-electrum"] serde = ["serde_crate", "serde_yaml", "bp-std/serde", "descriptors/serde", "rgb-psbt/serde"] +mempool_blocking = ["esplora_blocking"] [package.metadata.docs.rs] features = ["all"] @@ -97,3 +98,8 @@ features = ["all"] bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "master" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "master" } rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "master" } +bp-std = { git = "https://github.com/BP-WG/bp-std.git", branch = "master" } +bp-invoice = { git = "https://github.com/BP-WG/bp-std.git", branch = "master"} +psbt = { git = "https://github.com/BP-WG/bp-std.git", branch = "master" } +descriptors = { git = "https://github.com/BP-WG/bp-std.git", branch = "master" } +rgb-interfaces = { git = "https://github.com/RGB-WG/rgb-interfaces.git", branch = "master" } diff --git a/cli/src/args.rs b/cli/src/args.rs index 5032368..eb81257 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -135,13 +135,15 @@ impl RgbArgs { } pub fn resolver(&self) -> Result { - let resolver = match (&self.resolver.esplora, &self.resolver.electrum) { - (None, Some(url)) => AnyResolver::electrum_blocking(url, None), - (Some(url), None) => AnyResolver::esplora_blocking(url, None), - _ => Err(s!(" - error: no transaction resolver is specified; use either --esplora \ - or --electrum argument")), - } - .map_err(WalletError::Resolver)?; + let resolver = + match (&self.resolver.esplora, &self.resolver.electrum, &self.resolver.mempool) { + (None, Some(url), None) => AnyResolver::electrum_blocking(url, None), + (Some(url), None, None) => AnyResolver::esplora_blocking(url, None), + (None, None, Some(url)) => AnyResolver::mempool_blocking(url, None), + _ => Err(s!(" - error: no transaction resolver is specified; use either \ + --esplora --mempool or --electrum argument")), + } + .map_err(WalletError::Resolver)?; resolver.check(self.general.network)?; Ok(resolver) } diff --git a/src/indexers/any.rs b/src/indexers/any.rs index 97d4da4..e73eb5c 100644 --- a/src/indexers/any.rs +++ b/src/indexers/any.rs @@ -69,10 +69,21 @@ impl AnyResolver { }) } + #[cfg(feature = "mempool_blocking")] + pub fn mempool_blocking(url: &str, config: Option) -> Result { + Ok(AnyResolver { + inner: Box::new(super::mempool_blocking::MemPoolClient::new( + url, + config.unwrap_or_default(), + )?), + terminal_txes: Default::default(), + }) + } pub fn check(&self, network: Network) -> Result<(), String> { let expected_block_hash = match network { Network::Mainnet => "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", Network::Testnet3 => "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", + Network::Testnet4 => "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043", Network::Signet => "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6", Network::Regtest => "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", } diff --git a/src/indexers/electrum_blocking.rs b/src/indexers/electrum_blocking.rs index aca0d0b..9049821 100644 --- a/src/indexers/electrum_blocking.rs +++ b/src/indexers/electrum_blocking.rs @@ -48,6 +48,7 @@ impl RgbResolver for Client { let txid = match network { Network::Mainnet => "33e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac98799036", Network::Testnet3 => "5e6560fd518aadbed67ee4a55bdc09f19e619544f5511e9343ebba66d2f62653", + Network::Testnet4 => "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e", Network::Signet => "8153034f45e695453250a8fb7225a5e545144071d8ed7b0d3211efa1f3c92ad8", Network::Regtest => "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", }; diff --git a/src/indexers/mempool_blocking.rs b/src/indexers/mempool_blocking.rs new file mode 100644 index 0000000..3a1e440 --- /dev/null +++ b/src/indexers/mempool_blocking.rs @@ -0,0 +1,130 @@ +// RGB smart contracts for Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use bp::Tx; +use bpstd::{Network, Txid}; +use esplora::{BlockingClient, Config, Error}; +use rgbstd::WitnessAnchor; + +use super::RgbResolver; + +#[derive(Clone, Debug)] +/// Represents a client for interacting with a mempool. +// Currently, this client is wrapping an `esplora::BlockingClient` instance. +// If the mempool service changes in the future and is not compatible with +// esplora::BlockingClient, Only the internal implementation needs to be +// modified +pub struct MemPoolClient { + inner: BlockingClient, +} + +impl MemPoolClient { + /// Creates a new `MemPoolClient` instance. + /// + /// # Arguments + /// + /// * `url` - The URL of the mempool server. + /// * `config` - The configuration for the mempool client. + /// + /// # Returns + /// + /// Returns a `Result` containing the `MemPoolClient` instance if + /// successful, or an `Error` if an error occurred. + pub fn new(url: &str, config: Config) -> Result { + let inner = BlockingClient::from_config(url, config)?; + Ok(MemPoolClient { inner }) + } +} + +impl RgbResolver for MemPoolClient { + fn check(&self, network: Network, expected_block_hash: String) -> Result<(), String> { + self.inner.check(network, expected_block_hash) + } + + fn resolve_height(&mut self, txid: Txid) -> Result { + self.inner.resolve_height(txid) + } + + fn resolve_pub_witness(&self, txid: Txid) -> Result> { + self.inner.resolve_pub_witness(txid) + } +} + +#[cfg(test)] +mod test { + use esplora::Config; + #[test] + fn test_mempool_client_mainnet_tx() { + let client = super::MemPoolClient::new("https://mempool.space/api", Config::default()) + .expect("Failed to create client"); + let txid = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + .parse() + .unwrap(); + let status = client.inner.tx_status(&txid).unwrap(); + assert_eq!(status.block_height, Some(0)); + assert_eq!(status.block_time, Some(1231006505)); + } + + #[test] + fn test_mempool_client_testnet_tx() { + let client = + super::MemPoolClient::new("https://mempool.space/testnet/api", Config::default()) + .expect("Failed to create client"); + + let txid = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + .parse() + .unwrap(); + let status = client.inner.tx_status(&txid).unwrap(); + assert_eq!(status.block_height, Some(0)); + assert_eq!(status.block_time, Some(1296688602)); + } + + #[test] + fn test_mempool_client_testnet4_tx() { + let client = + super::MemPoolClient::new("https://mempool.space/testnet4/api", Config::default()) + .expect("Failed to create client"); + let txid = "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" + .parse() + .unwrap(); + let status = client.inner.tx_status(&txid).unwrap(); + assert_eq!(status.block_height, Some(0)); + assert_eq!(status.block_time, Some(1714777860)); + } + + #[test] + fn test_mempool_client_testnet4_tx_detail() { + let client = + super::MemPoolClient::new("https://mempool.space/testnet4/api", Config::default()) + .expect("Failed to create client"); + let txid = "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" + .parse() + .unwrap(); + let tx = client + .inner + .tx(&txid) + .expect("Failed to get tx") + .expect("Tx not found"); + assert!(tx.inputs.len() > 0); + assert!(tx.outputs.len() > 0); + assert_eq!(tx.outputs[0].value, 5_000_000_000); + } +} diff --git a/src/indexers/mod.rs b/src/indexers/mod.rs index 3ef5322..4566320 100644 --- a/src/indexers/mod.rs +++ b/src/indexers/mod.rs @@ -25,4 +25,7 @@ pub mod esplora_blocking; #[cfg(feature = "electrum_blocking")] pub mod electrum_blocking; +#[cfg(feature = "mempool_blocking")] +pub mod mempool_blocking; + pub use any::{AnyResolver, RgbResolver};