diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 891807e..1ae4293 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -10,8 +10,8 @@ jobs: strategy: matrix: rust: - - 1.65.0 # STABLE - - 1.57.0 # MSRV + - 1.75.0 # STABLE + - 1.63.0 # MSRV steps: - name: checkout uses: actions/checkout@v2 @@ -36,15 +36,9 @@ jobs: - name: Update Cargo.lock run: cargo update - name: Pin dependencies for MSRV - if: matrix.rust == '1.57.0' + if: matrix.rust == '1.63.0' run: | - cargo update -p log:0.4.20 --precise 0.4.18 - cargo update -p tempfile --precise 3.6.0 - cargo update -p webpki:0.22.4 --precise 0.22.0 - cargo update -p rustls:0.20.9 --precise 0.20.8 - cargo update -p sct:0.7.1 --precise 0.7.0 - cargo update -p tokio:1.35.0 --precise 1.29.1 - cargo update -p byteorder:1.5.0 --precise 1.4.3 + cargo update -p home:0.5.9 --precise 0.5.5 - name: Build run: cargo build - name: Clippy diff --git a/Cargo.toml b/Cargo.toml index 8efc58d..fbd87e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,4 @@ log = "^0.4" rstest = "^0.11" bdk-testutils = "^0.4" bdk = { version = "0.28", default-features = true } -electrsd = { version = "0.21", features = ["bitcoind_22_0", "electrs_0_9_1"] } -# base64ct versions at 1.6.0 and higher have MSRV 1.60.0 -base64ct = { version = "<1.6.0", features = ["alloc"] } +electrsd = { version = "0.23", features = ["bitcoind_22_0", "electrs_0_9_1"] } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b67262c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +FROM rust:1.69-bookworm +ARG http_proxy +ENV http_proxy=$http_proxy +ENV https_proxy=$http_proxy +ENV HTTP_PROXY=$http_proxy +ENV HTTPS_PROXY=$http_proxy +RUN echo Acquire::http::Proxy "${http_proxy}"; > /etc/apt/apt.conf.d/70debconf + +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + eatmydata \ + && eatmydata apt-get -y dist-upgrade \ + && eatmydata apt-get install --no-install-recommends -y \ + build-essential \ + bash \ + ca-certificates \ + clang \ + curl \ + emscripten \ + hunspell \ + libclang-dev \ + libssl-dev \ + llvm \ + pkg-config \ + syslog-ng \ + sudo \ + && eatmydata apt -y autoremove \ + && eatmydata apt clean \ + && rm -rf /var/lib/apt/lists/* + +ARG UID +RUN useradd -m -u $UID satoshi +USER satoshi +WORKDIR /home/satoshi + +RUN rustup component add clippy-preview \ + && rustup component add rustfmt +RUN rustup target add wasm32-unknown-unknown +RUN rustup target add wasm32-wasi +RUN rustup target add wasm32-unknown-emscripten + diff --git a/Dockerfile_63 b/Dockerfile_63 new file mode 100644 index 0000000..854b1c7 --- /dev/null +++ b/Dockerfile_63 @@ -0,0 +1,39 @@ +FROM rust:1.63-buster +ARG http_proxy +ENV http_proxy=$http_proxy +ENV https_proxy=$http_proxy +ENV HTTP_PROXY=$http_proxy +ENV HTTPS_PROXY=$http_proxy +RUN echo Acquire::http::Proxy "${http_proxy}"; > /etc/apt/apt.conf.d/70debconf + +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + eatmydata \ + && eatmydata apt-get -y dist-upgrade \ + && eatmydata apt-get install --no-install-recommends -y \ + build-essential \ + bash \ + ca-certificates \ + clang \ + curl \ + hunspell \ + libclang-dev \ + libssl-dev \ + llvm \ + pkg-config \ + syslog-ng \ + sudo \ + && eatmydata apt -y autoremove \ + && eatmydata apt clean \ + && rm -rf /var/lib/apt/lists/* + +ARG UID +RUN useradd -m -u $UID satoshi +USER satoshi +WORKDIR /home/satoshi + +RUN rustup component add clippy-preview \ + && rustup component add rustfmt +RUN rustup target add wasm32-unknown-unknown +RUN rustup target add wasm32-wasi + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f6eb9a2 --- /dev/null +++ b/Makefile @@ -0,0 +1,81 @@ +TAG := bdk-reserves +TAG_57 := bdk-reserves-57 +TAG_63 := bdk-reserves-61 +http_proxy ?= http://172.17.0.1:3128 +DOCKER_RUN := docker run --interactive --rm \ + -v ${PWD}:/home/satoshi \ + +build: builder + $(DOCKER_RUN) --tty ${TAG} cargo build + +test: test_current test_63 + +test_current: builder + rm -f Cargo.lock + $(DOCKER_RUN) ${TAG} cargo test + +test_57: builder_57 + #rm -f Cargo.lock + #$(DOCKER_RUN) ${TAG_57} cargo update -p log:0.4.20 --precise 0.4.18 + #$(DOCKER_RUN) ${TAG_57} cargo update -p tempfile --precise 3.6.0 + #$(DOCKER_RUN) ${TAG_57} cargo update -p sct:0.7.1 --precise 0.7.0 + $(DOCKER_RUN) ${TAG_57} cargo update -p zip:0.6.6 --precise 0.6.3 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls:0.21.10 --precise 0.21.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls:0.21.7 --precise 0.21.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls:0.21.4 --precise 0.21.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls:0.21.2 --precise 0.21.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls:0.20.9 --precise 0.20.8 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls-webpki:0.100.3 --precise 0.100.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls-webpki:0.101.4 --precise 0.101.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustls-webpki:0.101.7 --precise 0.101.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p crossbeam-utils:0.8.18 --precise 0.8.16 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p tokio:1.35.1 --precise 1.29.1 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p rustix:0.38.9 --precise 0.38.3 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p ring:0.17.7 --precise 0.16.20 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p byteorder:1.5.0 --precise 0.4.3 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p webpki:0.22.4 --precise 0.22.0 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p crossbeam-epoch:0.9.17 --precise 0.9.15 || true + $(DOCKER_RUN) ${TAG_57} cargo update -p byteorder:1.5.0 --precise 0.4.3 || true + $(DOCKER_RUN) ${TAG_57} cargo test + +test_63: builder_63 + rm -f Cargo.lock + $(DOCKER_RUN) ${TAG_63} cargo test || true + $(DOCKER_RUN) ${TAG_63} cargo update -p home:0.5.9 --precise 0.5.5 || true + $(DOCKER_RUN) ${TAG_63} cargo test + +run: builder + $(DOCKER_RUN) --tty ${TAG} cargo run + +wasm-unknown: builder + $(DOCKER_RUN) --tty ${TAG} cargo check --target wasm32-unknown-unknown --no-default-features + +wasm-wasi: builder + $(DOCKER_RUN) --tty ${TAG} cargo check --target wasm32-wasi --no-default-features + +wasm-emscripten: builder + $(DOCKER_RUN) --tty ${TAG} cargo check --target wasm32-unknown-emscripten --no-default-features + +sh: builder + $(DOCKER_RUN) --tty ${TAG} sh + +builder: + docker build --tag ${TAG} \ + --build-arg http_proxy="${http_proxy}" \ + --build-arg UID="$(shell id -u)" \ + . + +builder_57: + docker build --tag ${TAG_57}\ + --build-arg http_proxy="${http_proxy}" \ + --build-arg UID="$(shell id -u)" \ + -f Dockerfile_57 \ + . + +builder_63: + docker build --tag ${TAG_63}\ + --build-arg http_proxy="${http_proxy}" \ + --build-arg UID="$(shell id -u)" \ + -f Dockerfile_63 \ + . + diff --git a/README.md b/README.md index 0cecf4d..1ee6ac6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ MIT or Apache-2.0 Licensed CI Status API Docs - Rustc Version 1.57.0+ + Rustc Version 1.63.0+ Chat on Discord

@@ -50,15 +50,12 @@ at your option. ## Minimum Supported Rust Version (MSRV) -This library should always compile with Rust **1.57.0**. +This library should always compile with Rust **1.63.0**. To build with the MSRV you will need to pin the below dependencies: ```shell -# log versions at 0.4.19+ have MSRV 1.60.0 -cargo update -p log:0.4.19 --precise 0.4.18 -# tempfile versions at 3.7.0+ have MSRV 1.63.0 -cargo update -p tempfile --precise 3.6.0 +cargo update -p home:0.5.9 --precise 0.5.5 ``` ## Contribution diff --git a/src/reserves.rs b/src/reserves.rs index c6f4a22..18a0d9d 100644 --- a/src/reserves.rs +++ b/src/reserves.rs @@ -24,9 +24,8 @@ use bdk::bitcoin::blockdata::transaction::{EcdsaSighashType, OutPoint, TxIn, TxO use bdk::bitcoin::consensus::encode::serialize; use bdk::bitcoin::hash_types::{PubkeyHash, Txid}; use bdk::bitcoin::hashes::{hash160, sha256d, Hash}; -use bdk::bitcoin::util::address::Payload; use bdk::bitcoin::util::psbt::{Input, PartiallySignedTransaction as PSBT}; -use bdk::bitcoin::{Address, Network, Sequence}; +use bdk::bitcoin::{Network, Sequence}; use bdk::database::BatchDatabase; use bdk::wallet::tx_builder::TxOrdering; use bdk::wallet::Wallet; @@ -119,11 +118,7 @@ where }; let pkh = PubkeyHash::from_hash(hash160::Hash::hash(&[0])); - let out_script_unspendable = Address { - payload: Payload::PubkeyHash(pkh), - network: self.network(), - } - .script_pubkey(); + let out_script_unspendable = Script::new_p2pkh(&pkh); let mut builder = self.build_tx(); builder @@ -192,7 +187,7 @@ pub fn verify_proof( psbt: &PSBT, message: &str, outpoints: Vec<(OutPoint, TxOut)>, - network: Network, + _network: Network, ) -> Result { let tx = psbt.clone().extract_tx(); @@ -258,32 +253,14 @@ pub fn verify_proof( // verify the unspendable output let pkh = PubkeyHash::from_hash(hash160::Hash::hash(&[0])); - let out_script_unspendable = Address { - payload: Payload::PubkeyHash(pkh), - network, - } - .script_pubkey(); + let out_script_unspendable = Script::new_p2pkh(&pkh); + if tx.output[0].script_pubkey != out_script_unspendable { return Err(ProofError::InvalidOutput); } let serialized_tx = serialize(&tx); - // Verify the challenge input - if let Some(utxo) = &psbt.inputs[0].witness_utxo { - if let Err(err) = bitcoinconsensus::verify( - utxo.script_pubkey.to_bytes().as_slice(), - utxo.value, - &serialized_tx, - 0, - ) { - return Err(ProofError::SignatureValidation(0, format!("{:?}", err))); - } - } else { - return Err(ProofError::SignatureValidation( - 0, - "witness_utxo not found for challenge input".to_string(), - )); - } + // Verify other inputs against prevouts. if let Some((i, res)) = tx .input @@ -335,11 +312,8 @@ fn challenge_txin(message: &str) -> TxIn { #[cfg(test)] mod test { use super::*; - use base64ct::{Base64, Encoding}; - use bdk::bitcoin::consensus::encode::deserialize; - use bdk::bitcoin::hashes::sha256; - use bdk::bitcoin::secp256k1::{ecdsa::SerializedSignature, Message, Secp256k1, SecretKey}; - use bdk::bitcoin::{Address, EcdsaSighashType, Network, Witness}; + use bdk::bitcoin::secp256k1::ecdsa::{SerializedSignature, Signature}; + use bdk::bitcoin::{EcdsaSighashType, Network, Witness}; use bdk::wallet::get_funded_wallet; use std::str::FromStr; @@ -350,8 +324,9 @@ mod test { let message = "This belongs to me."; let psbt = wallet.create_proof(message).unwrap(); - let psbt_ser = serialize(&psbt); - let psbt_b64 = Base64::encode_string(&psbt_ser); + + let psbt_b64 = psbt.to_string(); + let expected = r#"cHNidP8BAH4BAAAAAmw1RvG4UzfnSafpx62EPTyha6VslP0Er7n3TxjEpeBeAAAAAAD/////2johM0znoXIXT1lg+ySrvGrtq1IGXPJzpfi/emkV9iIAAAAAAP////8BUMMAAAAAAAAZdqkUn3/QltN+0sDj9/DPySS+70/862iIrAAAAAAAAQEKAAAAAAAAAAABUQEHAAABAR9QwwAAAAAAABYAFOzlJlcQU9qGRUyeBmd56vnRUC5qIgYDKwVYB4vsOGlKhJM9ZZMD4lddrn6RaFkRRUEVv9ZEh+ME7OUmVwAA"#; assert_eq!(psbt_b64, expected); @@ -381,8 +356,7 @@ mod test { fn get_signed_proof() -> PSBT { let psbt = "cHNidP8BAH4BAAAAAmw1RvG4UzfnSafpx62EPTyha6VslP0Er7n3TxjEpeBeAAAAAAD/////2johM0znoXIXT1lg+ySrvGrtq1IGXPJzpfi/emkV9iIAAAAAAP////8BUMMAAAAAAAAZdqkUn3/QltN+0sDj9/DPySS+70/862iIrAAAAAAAAQEKAAAAAAAAAAABUQEHAAABAR9QwwAAAAAAABYAFOzlJlcQU9qGRUyeBmd56vnRUC5qAQcAAQhrAkcwRAIgDSE4PQ57JDiZ7otGkTqz35bi/e1pexYaYKWaveuvRd4CIFzVB4sAmgtdEVz2vHzs1iXc9iRKJ+KQOQb+C2DtPyvzASEDKwVYB4vsOGlKhJM9ZZMD4lddrn6RaFkRRUEVv9ZEh+MAAA=="; - let psbt = Base64::decode_vec(psbt).unwrap(); - deserialize(&psbt).unwrap() + PSBT::from_str(psbt).unwrap() } #[test] @@ -499,20 +473,12 @@ mod test { let mut psbt = get_signed_proof(); psbt.inputs[1].final_script_sig = None; - let secp = Secp256k1::new(); - // privkey from milk sad ... - let privkey = - SecretKey::from_str("4dcaff8ed1975fe2cebbd7c03384902c2189a2e6de11f1bb1c9dc784e8e4d11e") - .expect("valid privkey"); - - let invalid_message = - Message::from_hashed_data::("Invalid signing data".as_bytes()); - let signature = secp.sign_ecdsa(&invalid_message, &privkey); + let invalid_signature = Signature::from_str("3045022100f3b7b0b1400287766edfe8ba66bc0412984cdb97da6bb4092d5dc63a84e1da6f02204da10796361dbeaeead8f68a23157dffa23b356ec14ec2c0c384ad68d582bb14").unwrap(); + let invalid_signature = SerializedSignature::from_signature(&invalid_signature); let mut invalid_witness = Witness::new(); + invalid_witness.push_bitcoin_signature(&invalid_signature, EcdsaSighashType::All); - let signature = SerializedSignature::from_signature(&signature); - invalid_witness.push_bitcoin_signature(&signature, EcdsaSighashType::All); psbt.inputs[1].final_script_witness = Some(invalid_witness); wallet.verify_proof(&psbt, message, None).unwrap(); @@ -541,11 +507,7 @@ mod test { let mut psbt = get_signed_proof(); let pkh = PubkeyHash::from_hash(hash160::Hash::hash(&[0, 1, 2, 3])); - let out_script_unspendable = Address { - payload: Payload::PubkeyHash(pkh), - network: Network::Testnet, - } - .script_pubkey(); + let out_script_unspendable = Script::new_p2pkh(&pkh); psbt.unsigned_tx.output[0].script_pubkey = out_script_unspendable; wallet.verify_proof(&psbt, message, None).unwrap(); diff --git a/tests/regtestenv.rs b/tests/regtestenv.rs index 80b4067..5bcb387 100644 --- a/tests/regtestenv.rs +++ b/tests/regtestenv.rs @@ -1,11 +1,11 @@ use bdk::blockchain::{electrum::ElectrumBlockchain, Blockchain}; use bdk::database::memory::MemoryDatabase; use bdk::electrum_client::Client; -use bdk::electrum_client::ElectrumApi; use bdk::wallet::{AddressIndex, SyncOptions, Wallet}; use bdk::SignOptions; use electrsd::bitcoind::bitcoincore_rpc::{bitcoin::Address, RpcApi}; use electrsd::bitcoind::BitcoinD; +use electrsd::electrum_client::ElectrumApi; use electrsd::ElectrsD; use std::str::FromStr; use std::time::Duration; @@ -50,7 +50,7 @@ impl RegTestEnv { let foreign_addr = Address::from_str(MY_FOREIGN_ADDR).unwrap(); // generate to the first receiving address of the test wallet - self.generate_to_address(10, &addr2); + self.generate_to_address(10, &addr2.address); // make the newly mined coins spendable self.generate_to_address(100, &foreign_addr);