From 792afb58050c576620d5517274ae9baed68de40e Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Fri, 20 Oct 2023 14:36:01 +0530 Subject: [PATCH 01/10] feat: add slot proof verification --- Cargo.toml | 2 ++ src/verifycommitment.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e37e762..a8108e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,8 @@ staking_credentials = { git = "https://github.com/civkit/staking-credentials.git reqwest = "0.11.20" base64 = "0.21.4" jsonrpc = "0.14.0" +rs_merkle = "1.4.1" + [build-dependencies] tonic-build = "0.9" diff --git a/src/verifycommitment.rs b/src/verifycommitment.rs index 10ee704..c9ba0f5 100644 --- a/src/verifycommitment.rs +++ b/src/verifycommitment.rs @@ -1,4 +1,7 @@ use bitcoin_hashes::{sha256, Hash}; +use crate::inclusionproof::{InclusionProof}; +use rs_merkle::{MerkleTree, MerkleProof}; +use rs_merkle::algorithms::Sha256; pub fn verify_commitments(event_commitments: Vec>, latest_commitment: Vec) -> bool { let mut concatenated_hash = Vec::new(); @@ -16,3 +19,27 @@ pub fn verify_commitments(event_commitments: Vec>, latest_commitment: Ve calculated_commitment == latest_commitment } + +pub fn verify_slot_proof(slot: usize, inclusion_proof: &mut InclusionProof) -> bool { + let merkle_root = inclusion_proof.merkle_root.lock().unwrap(); + let commitment = inclusion_proof.commitment.lock().unwrap(); + let ops = inclusion_proof.ops.lock().unwrap(); + let ops_commitments: Vec<&str> = ops.iter().map(|pth| pth.commitment.as_str()).collect(); + + let leaf_hashes: Vec<[u8; 32]> = ops_commitments + .iter() + .map(|x| sha256::Hash::hash(x.as_bytes()).into_inner()) + .collect(); + + let leaf_to_prove = leaf_hashes.get(slot).unwrap(); + + let merkle_tree = MerkleTree::::from_leaves(&leaf_hashes); + let merkle_proof = merkle_tree.proof(&[slot]); + let merkle_root = merkle_tree.root().unwrap(); + + let proof_bytes = merkle_proof.to_bytes(); + + let proof = MerkleProof::::try_from(proof_bytes).unwrap(); + + return proof.verify(merkle_root, &[slot], &[*leaf_to_prove], leaf_hashes.len()); +} From ff33e75c925a354958fb263b84dccecdca5f8977 Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Fri, 27 Oct 2023 13:45:51 +0530 Subject: [PATCH 02/10] feat: verify merkle root inclusion --- Cargo.toml | 3 ++ example-config.toml | 13 +++++ src/config.rs | 23 ++++---- src/inclusionproof.rs | 1 + src/server.rs | 1 + src/verifycommitment.rs | 114 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 145 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a8108e9..f375d6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,9 @@ reqwest = "0.11.20" base64 = "0.21.4" jsonrpc = "0.14.0" rs_merkle = "1.4.1" +bitcoincore-rpc = "0.17.0" +hex = "0.4.3" +bip32 = { version = "0.5.1", features = ["secp256k1"] } [build-dependencies] diff --git a/example-config.toml b/example-config.toml index 16c9084..3d31197 100644 --- a/example-config.toml +++ b/example-config.toml @@ -16,3 +16,16 @@ cli_port = 50031 [logging] level = "info" + +[mainstay] +url = "http://localhost:4000" +position = 1 +token = "14b2b754-5806-4157-883c-732baf88849c" +base_pubkey = "031dd94c5262454986a2f0a6c557d2cbe41ec5a8131c588b9367c9310125a8a7dc" +chain_code = "0a090f710e47968aee906804f211cf10cde9a11e14908ca0f78cc55dd190ceaa" + +[bicoind] +host = "http://127.0.0.1" +port = 18443 +rpc_user = "civkitd_client" +rpc_password = "hello_world" diff --git a/src/config.rs b/src/config.rs index 964b657..e659d44 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use std::fs; use toml; use serde_derive::Deserialize; +use crate::bitcoind_client::BitcoindClient; #[derive(Clone, PartialEq, Eq, Debug, Deserialize)] pub struct Config { @@ -44,9 +45,11 @@ pub struct Logging { #[derive(Clone, PartialEq, Eq, Debug, Deserialize)] pub struct Mainstay { - pub url: String, - pub position: i32, - pub token: String, + pub url: String, + pub position: u64, + pub token: String, + pub base_pubkey: String, + pub chain_code: String, } #[derive(Clone, PartialEq, Eq, Debug, Deserialize)] @@ -84,13 +87,15 @@ impl Default for Config { url: "https://mainstay.xyz/api/v1".to_string(), position: 1, token: "14b2b754-5806-4157-883c-732baf88849c".to_string(), + base_pubkey: "031dd94c5262454986a2f0a6c557d2cbe41ec5a8131c588b9367c9310125a8a7dc".to_string(), + chain_code: "0a090f710e47968aee906804f211cf10cde9a11e14908ca0f78cc55dd190ceaa".to_string(), }, - bitcoind_params: BitcoindParams { - host: "http://127.0.0.1".to_string(), - port: "18443".to_string(), // regtest - rpc_user: "civkitd_client".to_string(), - rpc_password: "hello_world".to_string(), - } + bitcoind_params: BitcoindParams { + host: "http://127.0.0.1".to_string(), + port: "18443".to_string(), // regtest + rpc_user: "civkitd_client".to_string(), + rpc_password: "hello_world".to_string(), + } } } } diff --git a/src/inclusionproof.rs b/src/inclusionproof.rs index 2dba292..f2b8f4e 100644 --- a/src/inclusionproof.rs +++ b/src/inclusionproof.rs @@ -16,6 +16,7 @@ use serde_json::Value; use crate::mainstay::{get_proof}; use crate::config::Config; use crate::nostr_db::{write_new_inclusion_proof_db}; +use crate::verifycommitment::{verify_merkle_root_inclusion}; pub struct InclusionProof { pub txid: Arc>, diff --git a/src/server.rs b/src/server.rs index dc5868a..483f434 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,6 +12,7 @@ mod servicemanager; mod config; mod util; +mod bitcoind_client; use crate::util::init_logger; use log; diff --git a/src/verifycommitment.rs b/src/verifycommitment.rs index c9ba0f5..33b09e5 100644 --- a/src/verifycommitment.rs +++ b/src/verifycommitment.rs @@ -1,7 +1,12 @@ -use bitcoin_hashes::{sha256, Hash}; +use bitcoin_hashes::{sha256, Hash, hash160}; use crate::inclusionproof::{InclusionProof}; use rs_merkle::{MerkleTree, MerkleProof}; use rs_merkle::algorithms::Sha256; +use bitcoincore_rpc::{Auth, Client, RpcApi}; +use bitcoincore_rpc::bitcoin::Txid; +use std::str::FromStr; +use hex::{encode, decode}; +use bip32::{ExtendedPublicKey, ExtendedKeyAttrs, PublicKey, DerivationPath, ChildNumber}; pub fn verify_commitments(event_commitments: Vec>, latest_commitment: Vec) -> bool { let mut concatenated_hash = Vec::new(); @@ -43,3 +48,110 @@ pub fn verify_slot_proof(slot: usize, inclusion_proof: &mut InclusionProof) -> b return proof.verify(merkle_root, &[slot], &[*leaf_to_prove], leaf_hashes.len()); } + +pub fn verify_merkle_root_inclusion(txid: String, inclusion_proof: &mut InclusionProof) -> bool { + let client = Client::new(format!("{}:{}/", inclusion_proof.config.bitcoind_params.host, inclusion_proof.config.bitcoind_params.port).as_str(), + Auth::UserPass(inclusion_proof.config.bitcoind_params.rpc_user.to_string(), + inclusion_proof.config.bitcoind_params.rpc_password.to_string())).unwrap(); + + match client.get_raw_transaction_info(&Txid::from_str(&txid).unwrap(), None) { + Ok(transaction) => { + let script_pubkey_from_tx = encode(&transaction.vout[0].script_pub_key.hex); + let merkle_root = inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec(); + let rev_merkle_root: Vec = merkle_root.iter().rev().cloned().collect(); + let rev_merkle_root_hex = encode(rev_merkle_root); + + let path = get_path_from_commitment(rev_merkle_root_hex).unwrap(); + + let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; + let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; + + let initial_public_key_bytes = decode(initial_public_key_hex).expect("Invalid public key hex string"); + let mut public_key_bytes = [0u8; 33]; + public_key_bytes.copy_from_slice(&initial_public_key_bytes); + + let initial_public_key = bip32::secp256k1::PublicKey::from_bytes(public_key_bytes).expect("Invalid public key"); + let mut initial_chain_code = decode(initial_chain_code_hex).expect("Invalid chain code hex string"); + let mut initial_chain_code_array = [0u8; 32]; + initial_chain_code_array.copy_from_slice(initial_chain_code.as_mut_slice()); + + let attrs = ExtendedKeyAttrs { + depth: 0, + parent_fingerprint: Default::default(), + child_number: Default::default(), + chain_code: initial_chain_code_array, + }; + + let initial_extended_pubkey = ExtendedPublicKey::new(initial_public_key, attrs); + let (child_pubkey, child_chain_code) = derive_child_key_and_chaincode(&initial_extended_pubkey, &path.to_string()); + + let script = create_1_of_1_multisig_script(child_pubkey); + + let address = bitcoin::Address::p2sh(&script, bitcoin::Network::Bitcoin).unwrap(); + let script_pubkey = encode(address.script_pubkey()); + + return script_pubkey == script_pubkey_from_tx; + } + Err(error) => { + println!("Error: {:?}", error); + } + } + return false; +} + +pub fn get_path_from_commitment(commitment: String) -> Option { + let path_size = 16; + let child_size = 4; + + if commitment.len() != path_size * child_size { + return None; + } + + let mut derivation_path = String::new(); + for it in 0..path_size { + let index = &commitment[it * child_size..it * child_size + child_size]; + let decoded_index = u64::from_str_radix(index, 16).unwrap(); + derivation_path.push_str(&decoded_index.to_string()); + if it < path_size - 1 { + derivation_path.push('/'); + } + } + + Some(derivation_path) +} + +fn derive_child_key_and_chaincode(mut parent: &ExtendedPublicKey, path: &str) -> (bip32::secp256k1::PublicKey, [u8; 32]) { + let mut extended_key = parent.clone(); + let mut chain_code = parent.attrs().chain_code.clone(); + let mut public_key = parent.public_key().clone(); + for step in path.split('/') { + match step { + "m" => continue, + number => { + if let Ok(index) = number.parse::() { + let new_extended_key = extended_key.derive_child(ChildNumber(index)).expect("Failed to derive child key"); + chain_code = new_extended_key.attrs().chain_code; + public_key = *new_extended_key.public_key(); + extended_key = new_extended_key.clone(); + } else { + panic!("Invalid derivation path step: {}", step); + } + } + } + } + (public_key, chain_code) +} + +fn create_1_of_1_multisig_script(pubkey: bip32::secp256k1::PublicKey) -> bitcoin::blockdata::script::Script { + let public_key = bitcoin::util::key::PublicKey { + inner: bitcoin::secp256k1::PublicKey::from_slice(&pubkey.to_bytes()).unwrap(), + compressed: true, + }; + let script = bitcoin::blockdata::script::Builder::new() + .push_opcode(bitcoin::blockdata::opcodes::all::OP_PUSHNUM_1) + .push_key(&public_key) + .push_opcode(bitcoin::blockdata::opcodes::all::OP_PUSHNUM_1) + .push_opcode(bitcoin::blockdata::opcodes::all::OP_CHECKMULTISIG) + .into_script(); + script +} \ No newline at end of file From 7d93cba2c335a3b0d9f85fb3a120455f76da5ed1 Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Wed, 8 Nov 2023 23:09:44 +0530 Subject: [PATCH 03/10] fix: remove unused imports --- src/config.rs | 1 - src/server.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index e659d44..8daa14d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,6 @@ use std::fs; use toml; use serde_derive::Deserialize; -use crate::bitcoind_client::BitcoindClient; #[derive(Clone, PartialEq, Eq, Debug, Deserialize)] pub struct Config { diff --git a/src/server.rs b/src/server.rs index 483f434..dc5868a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,7 +12,6 @@ mod servicemanager; mod config; mod util; -mod bitcoind_client; use crate::util::init_logger; use log; From 9c45daa404aea3345f077f73b70fbf0d29d106fe Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Mon, 13 Nov 2023 12:51:50 +0530 Subject: [PATCH 04/10] chore: add test for verify_merkle_root_inclusion --- src/lib.rs | 1 + src/verifycommitment.rs | 113 ++++++++++++++++++++++------------- src/verifycommitment_test.rs | 93 ++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 43 deletions(-) create mode 100644 src/verifycommitment_test.rs diff --git a/src/lib.rs b/src/lib.rs index 317e43f..bc990e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,3 +113,4 @@ pub mod mainstay; pub mod inclusionproof; pub mod verifycommitment; pub mod rpcclient; +pub mod verifycommitment_test; diff --git a/src/verifycommitment.rs b/src/verifycommitment.rs index 33b09e5..b2262c9 100644 --- a/src/verifycommitment.rs +++ b/src/verifycommitment.rs @@ -7,6 +7,7 @@ use bitcoincore_rpc::bitcoin::Txid; use std::str::FromStr; use hex::{encode, decode}; use bip32::{ExtendedPublicKey, ExtendedKeyAttrs, PublicKey, DerivationPath, ChildNumber}; +use crate::verifycommitment_test::{MockClient, test_merkle_root}; pub fn verify_commitments(event_commitments: Vec>, latest_commitment: Vec) -> bool { let mut concatenated_hash = Vec::new(); @@ -50,55 +51,81 @@ pub fn verify_slot_proof(slot: usize, inclusion_proof: &mut InclusionProof) -> b } pub fn verify_merkle_root_inclusion(txid: String, inclusion_proof: &mut InclusionProof) -> bool { - let client = Client::new(format!("{}:{}/", inclusion_proof.config.bitcoind_params.host, inclusion_proof.config.bitcoind_params.port).as_str(), - Auth::UserPass(inclusion_proof.config.bitcoind_params.rpc_user.to_string(), - inclusion_proof.config.bitcoind_params.rpc_password.to_string())).unwrap(); + if cfg!(test) { + let client = MockClient::new(); + + match client.get_raw_transaction_info(&Txid::from_str(&txid).unwrap(), None) { + Ok(transaction) => { + let script_pubkey_from_tx = encode(&transaction.vout[0].script_pub_key.hex); + let merkle_root = decode(test_merkle_root).expect("Invalid merkle root hex string"); + let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; + let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; - match client.get_raw_transaction_info(&Txid::from_str(&txid).unwrap(), None) { - Ok(transaction) => { - let script_pubkey_from_tx = encode(&transaction.vout[0].script_pub_key.hex); - let merkle_root = inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec(); - let rev_merkle_root: Vec = merkle_root.iter().rev().cloned().collect(); - let rev_merkle_root_hex = encode(rev_merkle_root); - - let path = get_path_from_commitment(rev_merkle_root_hex).unwrap(); - - let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; - let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; - - let initial_public_key_bytes = decode(initial_public_key_hex).expect("Invalid public key hex string"); - let mut public_key_bytes = [0u8; 33]; - public_key_bytes.copy_from_slice(&initial_public_key_bytes); - - let initial_public_key = bip32::secp256k1::PublicKey::from_bytes(public_key_bytes).expect("Invalid public key"); - let mut initial_chain_code = decode(initial_chain_code_hex).expect("Invalid chain code hex string"); - let mut initial_chain_code_array = [0u8; 32]; - initial_chain_code_array.copy_from_slice(initial_chain_code.as_mut_slice()); - - let attrs = ExtendedKeyAttrs { - depth: 0, - parent_fingerprint: Default::default(), - child_number: Default::default(), - chain_code: initial_chain_code_array, - }; - - let initial_extended_pubkey = ExtendedPublicKey::new(initial_public_key, attrs); - let (child_pubkey, child_chain_code) = derive_child_key_and_chaincode(&initial_extended_pubkey, &path.to_string()); - - let script = create_1_of_1_multisig_script(child_pubkey); - - let address = bitcoin::Address::p2sh(&script, bitcoin::Network::Bitcoin).unwrap(); - let script_pubkey = encode(address.script_pubkey()); - - return script_pubkey == script_pubkey_from_tx; + let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); + + return script_pubkey == script_pubkey_from_tx; + } + Err(error) => { + println!("Error: {:?}", error); + } } - Err(error) => { - println!("Error: {:?}", error); + } else { + let client = Client::new(format!("{}:{}/", inclusion_proof.config.bitcoind_params.host, inclusion_proof.config.bitcoind_params.port).as_str(), + Auth::UserPass(inclusion_proof.config.bitcoind_params.rpc_user.to_string(), + inclusion_proof.config.bitcoind_params.rpc_password.to_string())).unwrap(); + + match client.get_raw_transaction_info(&Txid::from_str(&txid).unwrap(), None) { + Ok(transaction) => { + let script_pubkey_from_tx = encode(&transaction.vout[0].script_pub_key.hex); + let merkle_root = inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec(); + let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; + let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; + + let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); + + return script_pubkey == script_pubkey_from_tx; + } + Err(error) => { + println!("Error: {:?}", error); + } } - } + }; + return false; } +pub fn derive_script_pubkey_from_merkle_root(merkle_root: Vec, initial_public_key_hex: String, initial_chain_code_hex: String) -> String { + let rev_merkle_root: Vec = merkle_root.iter().rev().cloned().collect(); + let rev_merkle_root_hex = encode(rev_merkle_root); + let path = get_path_from_commitment(rev_merkle_root_hex).unwrap(); + + let initial_public_key_bytes = decode(initial_public_key_hex).expect("Invalid public key hex string"); + let mut public_key_bytes = [0u8; 33]; + public_key_bytes.copy_from_slice(&initial_public_key_bytes); + + let initial_public_key = bip32::secp256k1::PublicKey::from_bytes(public_key_bytes).expect("Invalid public key"); + let mut initial_chain_code = decode(initial_chain_code_hex).expect("Invalid chain code hex string"); + let mut initial_chain_code_array = [0u8; 32]; + initial_chain_code_array.copy_from_slice(initial_chain_code.as_mut_slice()); + + let attrs = ExtendedKeyAttrs { + depth: 0, + parent_fingerprint: Default::default(), + child_number: Default::default(), + chain_code: initial_chain_code_array, + }; + + let initial_extended_pubkey = ExtendedPublicKey::new(initial_public_key, attrs); + let (child_pubkey, child_chain_code) = derive_child_key_and_chaincode(&initial_extended_pubkey, &path.to_string()); + + let script = create_1_of_1_multisig_script(child_pubkey); + + let address = bitcoin::Address::p2sh(&script, bitcoin::Network::Bitcoin).unwrap(); + let script_pubkey = encode(address.script_pubkey()); + + script_pubkey +} + pub fn get_path_from_commitment(commitment: String) -> Option { let path_size = 16; let child_size = 4; diff --git a/src/verifycommitment_test.rs b/src/verifycommitment_test.rs new file mode 100644 index 0000000..1c023f1 --- /dev/null +++ b/src/verifycommitment_test.rs @@ -0,0 +1,93 @@ +use crate::util; +use std::fs; +use crate::config::Config; +use crate::inclusionproof::InclusionProof; +use crate::verifycommitment::{verify_merkle_root_inclusion}; +use bitcoincore_rpc::bitcoin::Txid; +use bitcoin::BlockHash; +use bitcoincore_rpc::Client; +use bitcoincore_rpc::json::{GetRawTransactionResult}; +use serde_json::from_str; + +const tx_data: &str = r#" +{ + "txid": "b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2", + "hash": "b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2", + "version": 2, + "size": 194, + "vsize": 194, + "weight": 776, + "locktime": 0, + "vin": [ + { + "txid": "047352f01e5e3f8adc04a797311dde3917f274e55ceafb78edc39ff5d87d16c5", + "vout": 0, + "scriptSig": { + "asm": "0 30440220049d3138f841b63e96725cb9e86a53a92cd1d9e1b0740f5d4cd2ae0bcab684bf0220208d555c7e24e4c01cf67dfa9161091533e9efd6d1602bb53a49f7195c16b037[ALL] 5121036bd7943325ed9c9e1a44d98a8b5759c4bf4807df4312810ed5fc09dfb967811951ae", + "hex": "004730440220049d3138f841b63e96725cb9e86a53a92cd1d9e1b0740f5d4cd2ae0bcab684bf0220208d555c7e24e4c01cf67dfa9161091533e9efd6d1602bb53a49f7195c16b03701255121036bd7943325ed9c9e1a44d98a8b5759c4bf4807df4312810ed5fc09dfb967811951ae" + }, + "sequence": 4294967293 + } + ], + "vout": [ + { + "value": 0.01040868, + "n": 0, + "scriptPubKey": { + "asm": "OP_HASH160 29d13058087ddf2d48de404376fdcb5c4abff4bc OP_EQUAL", + "desc": "addr(35W8E71bdDhQw4ZC7uUZvXG3qhyWVYxfMB)#4rtfrxzg", + "hex": "a91429d13058087ddf2d48de404376fdcb5c4abff4bc87", + "address": "35W8E71bdDhQw4ZC7uUZvXG3qhyWVYxfMB", + "type": "scripthash" + } + } + ], + "hex": "0200000001c5167dd8f59fc3ed78fbea5ce574f21739de1d3197a704dc8a3f5e1ef0527304000000006f004730440220049d3138f841b63e96725cb9e86a53a92cd1d9e1b0740f5d4cd2ae0bcab684bf0220208d555c7e24e4c01cf67dfa9161091533e9efd6d1602bb53a49f7195c16b03701255121036bd7943325ed9c9e1a44d98a8b5759c4bf4807df4312810ed5fc09dfb967811951aefdffffff01e4e10f000000000017a91429d13058087ddf2d48de404376fdcb5c4abff4bc8700000000","blockhash":"000000000000000000036cb20420528cf0f00abb3a5716d80b5c87146b764d47", + "confirmations":15235, + "time":1690540748, + "blocktime":1690540748 +}"#; +pub const test_merkle_root: &str = "8d0ad2782d8f6e3f63c6f9611841c239630b55061d558abcc6bac53349edac70"; + +pub struct MockClient {} + +impl MockClient { + pub fn new() -> Self { + MockClient {} + } + pub fn get_raw_transaction_info(&self, txid: &Txid, blockhash: Option<&BlockHash>) -> Result> { + let tx_info: GetRawTransactionResult = from_str(tx_data)?; + Ok(tx_info) + } +} + +#[test] +fn test_verify_merkle_root_inclusion() { + + let data_dir = util::get_default_data_dir(); + + let config_path = data_dir.join("example-config.toml"); + + // Read the configuration file + let contents = fs::read_to_string(&config_path); + let config = match contents { + Ok(data) => { + toml::from_str(&data).expect("Could not deserialize the config file content") + }, + Err(_) => { + // If there's an error reading the file, use the default configuration + Config::default() + } + }; + + let mut inclusion_proof = InclusionProof::new( + "".to_string(), + "".to_string(), + "".to_string(), + Vec::new(), + config.clone() + ); + + let result = verify_merkle_root_inclusion("b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2".to_string(), &mut inclusion_proof); + assert_eq!(result, true); +} \ No newline at end of file From 9b112be9b31ea434ab309e506a457fa29d681eee Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Tue, 14 Nov 2023 23:47:03 +0530 Subject: [PATCH 05/10] feat: implement verifytxoutproof --- src/bitcoind_client.rs | 17 ++++++++++++++++- src/inclusionproof.rs | 1 - src/verifycommitment.rs | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/bitcoind_client.rs b/src/bitcoind_client.rs index 01cd474..a53922d 100644 --- a/src/bitcoind_client.rs +++ b/src/bitcoind_client.rs @@ -20,6 +20,10 @@ use tokio::sync::Mutex as TokioMutex; use tokio::time::{sleep, Duration}; +use crate::inclusionproof::InclusionProof; +use crate::verifycommitment::{verify_commitments, verify_slot_proof, verify_merkle_root_inclusion}; +use crate::nostr_db::get_hashes_of_all_events; + #[derive(Debug)] pub enum BitcoindRequest { CheckRpcCall, @@ -47,8 +51,19 @@ impl BitcoindClient { } - pub async fn verifytxoutproof() { + pub async fn verifytxoutproof(txid: String, slot: usize, mut inclusion_proof: InclusionProof) -> bool { + let event_commitments = get_hashes_of_all_events().await.unwrap(); + if !verify_commitments(event_commitments, &mut inclusion_proof) { + return false; + } + if !verify_slot_proof(slot, &mut inclusion_proof) { + return false; + } + if !verify_merkle_root_inclusion(txid, &mut inclusion_proof) { + return false; + } + true } //TODO: run and dispatch call to bitcoind diff --git a/src/inclusionproof.rs b/src/inclusionproof.rs index f2b8f4e..2dba292 100644 --- a/src/inclusionproof.rs +++ b/src/inclusionproof.rs @@ -16,7 +16,6 @@ use serde_json::Value; use crate::mainstay::{get_proof}; use crate::config::Config; use crate::nostr_db::{write_new_inclusion_proof_db}; -use crate::verifycommitment::{verify_merkle_root_inclusion}; pub struct InclusionProof { pub txid: Arc>, diff --git a/src/verifycommitment.rs b/src/verifycommitment.rs index b2262c9..67c676e 100644 --- a/src/verifycommitment.rs +++ b/src/verifycommitment.rs @@ -9,9 +9,9 @@ use hex::{encode, decode}; use bip32::{ExtendedPublicKey, ExtendedKeyAttrs, PublicKey, DerivationPath, ChildNumber}; use crate::verifycommitment_test::{MockClient, test_merkle_root}; -pub fn verify_commitments(event_commitments: Vec>, latest_commitment: Vec) -> bool { +pub fn verify_commitments(event_commitments: Vec>, inclusion_proof: &mut InclusionProof) -> bool { let mut concatenated_hash = Vec::new(); - + let mut latest_commitment = inclusion_proof.commitment.lock().unwrap().as_bytes().to_vec(); for event_commitment in &event_commitments { if concatenated_hash.is_empty() { concatenated_hash.extend_from_slice(&event_commitments[0]); From 11ebd352ab7fb571b8fdd6306086be62ac5c5196 Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Fri, 17 Nov 2023 22:26:11 +0530 Subject: [PATCH 06/10] fix: remove bitcoincore-rpc dependency --- src/config.rs | 16 +++++++------- src/kindprocessor.rs | 2 +- src/verifycommitment.rs | 41 ++++++++++++++++++------------------ src/verifycommitment_test.rs | 19 +++++++++++------ 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/config.rs b/src/config.rs index 83c9894..652f551 100644 --- a/src/config.rs +++ b/src/config.rs @@ -83,17 +83,17 @@ impl Default for Config { level: "info".to_string(), }, mainstay: Mainstay { - url: "https://mainstay.xyz/api/v1".to_string(), - position: 1, - token: "14b2b754-5806-4157-883c-732baf88849c".to_string(), - base_pubkey: "031dd94c5262454986a2f0a6c557d2cbe41ec5a8131c588b9367c9310125a8a7dc".to_string(), + url: "http://testnet.mainstay.xyz/api/v1".to_string(), + position: 4, + token: "dd7a917e-6cc6-4d95-9eed-cc9ebc20f9a9".to_string(), + base_pubkey: "021a89d4cdc8559f5aa34894049bcda4b2c648a28d8db29339595114ff3208ead9".to_string(), chain_code: "0a090f710e47968aee906804f211cf10cde9a11e14908ca0f78cc55dd190ceaa".to_string(), }, bitcoind_params: BitcoindParams { - host: "https://127.0.0.1".to_string(), - port: "18443".to_string(), // regtest - rpc_user: "civkitd_client".to_string(), - rpc_password: "hello_world".to_string(), + host: "http://209.250.231.82".to_string(), + port: "18332".to_string(), // regtest + rpc_user: "someuser".to_string(), + rpc_password: "somepass".to_string(), } } } diff --git a/src/kindprocessor.rs b/src/kindprocessor.rs index c4be9e6..22a022c 100644 --- a/src/kindprocessor.rs +++ b/src/kindprocessor.rs @@ -27,7 +27,7 @@ use crate::util::is_replaceable; use tokio::sync::mpsc; use tokio::sync::Mutex as TokioMutex; use tokio::time::{sleep, Duration}; -use base64::encode; +use hex::encode; pub struct NoteProcessor { note_counters: Mutex, diff --git a/src/verifycommitment.rs b/src/verifycommitment.rs index 67c676e..ffd3ae0 100644 --- a/src/verifycommitment.rs +++ b/src/verifycommitment.rs @@ -2,12 +2,12 @@ use bitcoin_hashes::{sha256, Hash, hash160}; use crate::inclusionproof::{InclusionProof}; use rs_merkle::{MerkleTree, MerkleProof}; use rs_merkle::algorithms::Sha256; -use bitcoincore_rpc::{Auth, Client, RpcApi}; -use bitcoincore_rpc::bitcoin::Txid; +use crate::rpcclient::{Client, Auth}; use std::str::FromStr; use hex::{encode, decode}; use bip32::{ExtendedPublicKey, ExtendedKeyAttrs, PublicKey, DerivationPath, ChildNumber}; -use crate::verifycommitment_test::{MockClient, test_merkle_root}; +use crate::verifycommitment_test::{MockClient, TEST_MERKLE_ROOT}; +use serde_json::{from_str, Value}; pub fn verify_commitments(event_commitments: Vec>, inclusion_proof: &mut InclusionProof) -> bool { let mut concatenated_hash = Vec::new(); @@ -53,16 +53,14 @@ pub fn verify_slot_proof(slot: usize, inclusion_proof: &mut InclusionProof) -> b pub fn verify_merkle_root_inclusion(txid: String, inclusion_proof: &mut InclusionProof) -> bool { if cfg!(test) { let client = MockClient::new(); - - match client.get_raw_transaction_info(&Txid::from_str(&txid).unwrap(), None) { - Ok(transaction) => { - let script_pubkey_from_tx = encode(&transaction.vout[0].script_pub_key.hex); - let merkle_root = decode(test_merkle_root).expect("Invalid merkle root hex string"); + match MockClient::call("getrawtransaction", &[Value::String(txid), Value::Bool(true)]) { + Ok(resp) => { + let script_pubkey_from_tx = resp["vout"][0]["scriptPubKey"]["hex"].as_str().unwrap().to_string(); + let merkle_root = decode(TEST_MERKLE_ROOT).unwrap(); let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; - let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); - + let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); return script_pubkey == script_pubkey_from_tx; } Err(error) => { @@ -74,16 +72,19 @@ pub fn verify_merkle_root_inclusion(txid: String, inclusion_proof: &mut Inclusio Auth::UserPass(inclusion_proof.config.bitcoind_params.rpc_user.to_string(), inclusion_proof.config.bitcoind_params.rpc_password.to_string())).unwrap(); - match client.get_raw_transaction_info(&Txid::from_str(&txid).unwrap(), None) { - Ok(transaction) => { - let script_pubkey_from_tx = encode(&transaction.vout[0].script_pub_key.hex); - let merkle_root = inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec(); - let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; - let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; - - let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); - - return script_pubkey == script_pubkey_from_tx; + match client.call("getrawtransaction", &[Value::String(txid), Value::Bool(true)]) { + Ok(resp) => { + if let Some(raw_value) = resp.result { + let json_value: Value = from_str(raw_value.get()).unwrap(); + let script_pubkey_from_tx = json_value["vout"][0]["scriptPubKey"]["hex"].as_str().unwrap().to_string(); + let merkle_root = inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec(); + let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; + let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; + + let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); + + return script_pubkey == script_pubkey_from_tx; + } } Err(error) => { println!("Error: {:?}", error); diff --git a/src/verifycommitment_test.rs b/src/verifycommitment_test.rs index 1c023f1..ad9b86d 100644 --- a/src/verifycommitment_test.rs +++ b/src/verifycommitment_test.rs @@ -8,8 +8,9 @@ use bitcoin::BlockHash; use bitcoincore_rpc::Client; use bitcoincore_rpc::json::{GetRawTransactionResult}; use serde_json::from_str; +use serde_json::Value; -const tx_data: &str = r#" +const TX_DATA_RES: &str = r#" { "txid": "b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2", "hash": "b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2", @@ -46,8 +47,12 @@ const tx_data: &str = r#" "confirmations":15235, "time":1690540748, "blocktime":1690540748 -}"#; -pub const test_merkle_root: &str = "8d0ad2782d8f6e3f63c6f9611841c239630b55061d558abcc6bac53349edac70"; +} +"#; + +pub const TEST_MERKLE_ROOT: &str = "8d0ad2782d8f6e3f63c6f9611841c239630b55061d558abcc6bac53349edac70"; + +pub const TXID: &str = "b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2"; pub struct MockClient {} @@ -55,9 +60,9 @@ impl MockClient { pub fn new() -> Self { MockClient {} } - pub fn get_raw_transaction_info(&self, txid: &Txid, blockhash: Option<&BlockHash>) -> Result> { - let tx_info: GetRawTransactionResult = from_str(tx_data)?; - Ok(tx_info) + pub fn call(command: &str, args: &[serde_json::Value]) -> Result { + let response: Value = from_str(TX_DATA_RES).unwrap(); + Ok(response) } } @@ -88,6 +93,6 @@ fn test_verify_merkle_root_inclusion() { config.clone() ); - let result = verify_merkle_root_inclusion("b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2".to_string(), &mut inclusion_proof); + let result = verify_merkle_root_inclusion(TXID.to_string(), &mut inclusion_proof); assert_eq!(result, true); } \ No newline at end of file From 0e6bc9e59b78130f097e37651527774e73eab56e Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Fri, 17 Nov 2023 22:29:34 +0530 Subject: [PATCH 07/10] fix: config and toml --- Cargo.toml | 9 ++++----- src/config.rs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8bef5f3..046b29f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,9 @@ path = "src/services/notaryd.rs" [dependencies] futures-channel = "0.3.28" futures-util = "0.3.28" -lightning = { git = "https://github.com/DhananjayPurohit/rust-lightning-wizards.git", branch = "civkit-branch" } -lightning-net-tokio = { git = "https://github.com/DhananjayPurohit/rust-lightning-wizards.git", branch = "civkit-branch" } -lightning-invoice = { git = "https://github.com/DhananjayPurohit/rust-lightning-wizards.git", branch = "civkit-branch" } +lightning = { git = "https://github.com/civkit/rust-lightning.git", branch = "civkit-branch" } +lightning-net-tokio = { git = "https://github.com/civkit/rust-lightning.git", branch = "civkit-branch" } +lightning-invoice = { git = "https://github.com/civkit/rust-lightning.git", branch = "civkit-branch" } tokio = { version = "1", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] } tokio-tungstenite = "0.19.0" bitcoin = "0.29.0" @@ -45,7 +45,7 @@ serde_json = { version = "1.0" } toml = "0.5.8" serde_derive = "1.0" serde = "1.0.130" -rusqlite = { version = "0.29.0", features = ["bundled"] } +rusqlite = "0.29.0" simplelog = "0.7.1" dirs = "3.0.1" log = "0.4.14" @@ -54,7 +54,6 @@ reqwest = "0.11.20" base64 = "0.21.4" jsonrpc = "0.14.0" rs_merkle = "1.4.1" -bitcoincore-rpc = "0.17.0" hex = "0.4.3" bip32 = { version = "0.5.1", features = ["secp256k1"] } diff --git a/src/config.rs b/src/config.rs index 652f551..83c9894 100644 --- a/src/config.rs +++ b/src/config.rs @@ -83,17 +83,17 @@ impl Default for Config { level: "info".to_string(), }, mainstay: Mainstay { - url: "http://testnet.mainstay.xyz/api/v1".to_string(), - position: 4, - token: "dd7a917e-6cc6-4d95-9eed-cc9ebc20f9a9".to_string(), - base_pubkey: "021a89d4cdc8559f5aa34894049bcda4b2c648a28d8db29339595114ff3208ead9".to_string(), + url: "https://mainstay.xyz/api/v1".to_string(), + position: 1, + token: "14b2b754-5806-4157-883c-732baf88849c".to_string(), + base_pubkey: "031dd94c5262454986a2f0a6c557d2cbe41ec5a8131c588b9367c9310125a8a7dc".to_string(), chain_code: "0a090f710e47968aee906804f211cf10cde9a11e14908ca0f78cc55dd190ceaa".to_string(), }, bitcoind_params: BitcoindParams { - host: "http://209.250.231.82".to_string(), - port: "18332".to_string(), // regtest - rpc_user: "someuser".to_string(), - rpc_password: "somepass".to_string(), + host: "https://127.0.0.1".to_string(), + port: "18443".to_string(), // regtest + rpc_user: "civkitd_client".to_string(), + rpc_password: "hello_world".to_string(), } } } From 742e33dc50944767cefe6dc81996cae1732a5958 Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Mon, 20 Nov 2023 11:31:54 +0530 Subject: [PATCH 08/10] fix: remove bitcoincore-rpc from verifycommitment test --- src/verifycommitment_test.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/verifycommitment_test.rs b/src/verifycommitment_test.rs index ad9b86d..6e32921 100644 --- a/src/verifycommitment_test.rs +++ b/src/verifycommitment_test.rs @@ -3,10 +3,8 @@ use std::fs; use crate::config::Config; use crate::inclusionproof::InclusionProof; use crate::verifycommitment::{verify_merkle_root_inclusion}; -use bitcoincore_rpc::bitcoin::Txid; use bitcoin::BlockHash; -use bitcoincore_rpc::Client; -use bitcoincore_rpc::json::{GetRawTransactionResult}; +use crate::rpcclient::Client; use serde_json::from_str; use serde_json::Value; From da6dd085d59c65f53dd68f3105480ba1a28305ac Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Wed, 22 Nov 2023 14:09:49 +0530 Subject: [PATCH 09/10] feat: store raw tx and txout proof in inclusion proof --- src/bitcoind_client.rs | 15 ++--------- src/inclusionproof.rs | 29 +++++++++++++++++++-- src/server.rs | 3 ++- src/verifycommitment.rs | 50 +++++------------------------------- src/verifycommitment_test.rs | 23 +++++------------ 5 files changed, 44 insertions(+), 76 deletions(-) diff --git a/src/bitcoind_client.rs b/src/bitcoind_client.rs index a53922d..ef0ed2c 100644 --- a/src/bitcoind_client.rs +++ b/src/bitcoind_client.rs @@ -51,19 +51,8 @@ impl BitcoindClient { } - pub async fn verifytxoutproof(txid: String, slot: usize, mut inclusion_proof: InclusionProof) -> bool { - let event_commitments = get_hashes_of_all_events().await.unwrap(); - if !verify_commitments(event_commitments, &mut inclusion_proof) { - return false; - } - if !verify_slot_proof(slot, &mut inclusion_proof) { - return false; - } - if !verify_merkle_root_inclusion(txid, &mut inclusion_proof) { - return false; - } - - true + pub async fn verifytxoutproof(mut inclusion_proof: InclusionProof) -> bool { + return verify_merkle_root_inclusion(&mut inclusion_proof).await; } //TODO: run and dispatch call to bitcoind diff --git a/src/inclusionproof.rs b/src/inclusionproof.rs index 2dba292..16f3478 100644 --- a/src/inclusionproof.rs +++ b/src/inclusionproof.rs @@ -11,17 +11,21 @@ use std::sync::Arc; use std::thread; use std::sync::Mutex; use tokio::time::{sleep, Duration}; -use serde_json::Value; +use serde_json::{Value, from_str, to_value}; +use crate::verifycommitment::verify_merkle_root_inclusion; use crate::mainstay::{get_proof}; use crate::config::Config; use crate::nostr_db::{write_new_inclusion_proof_db}; +use crate::rpcclient::{Client, Auth}; pub struct InclusionProof { pub txid: Arc>, pub commitment: Arc>, pub merkle_root: Arc>, pub ops: Arc>>, + pub txoutproof: Arc>, + pub raw_tx: Arc>, pub config: Config, } @@ -31,12 +35,14 @@ pub struct Ops { } impl InclusionProof { - pub fn new(txid: String, commitment: String, merkle_root: String, ops: Vec, our_config: Config) -> Self { + pub fn new(txid: String, commitment: String, merkle_root: String, ops: Vec, txout_proof: String, raw_tx: Value, our_config: Config) -> Self { InclusionProof { txid: Arc::new(Mutex::new(txid)), commitment: Arc::new(Mutex::new(commitment)), merkle_root: Arc::new(Mutex::new(merkle_root)), ops: Arc::new(Mutex::new(ops)), + txoutproof: Arc::new(Mutex::new(txout_proof)), + raw_tx: Arc::new(Mutex::new(raw_tx)), config: our_config, } } @@ -67,6 +73,25 @@ impl InclusionProof { Ops { append, commitment } }) .collect(); + + let client = Client::new(format!("{}:{}/", self.config.bitcoind_params.host, self.config.bitcoind_params.port).as_str(), + Auth::UserPass(self.config.bitcoind_params.rpc_user.to_string(), + self.config.bitcoind_params.rpc_password.to_string())).unwrap(); + let txid_json_value = to_value(txid).unwrap(); + let txid_json = Value::Array(vec![txid_json_value]); + if let Ok(response) = client.call("gettxoutproof", &[txid_json]) { + if let Some(raw_value) = response.result { + let mut txout_proof = raw_value.get().to_string(); + *self.txoutproof.lock().unwrap() = txout_proof; + } + } + + if let Ok(response) = client.call("getrawtransaction", &[Value::String(txid.to_string()), Value::Bool(true)]) { + if let Some(raw_value) = response.result { + let json_value: Value = from_str(raw_value.get()).unwrap(); + *self.raw_tx.lock().unwrap() = json_value; + } + } write_new_inclusion_proof_db(self).await; } }, diff --git a/src/server.rs b/src/server.rs index 00c2923..2e7259e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -61,6 +61,7 @@ use tokio::sync::{oneshot, mpsc}; use tokio_tungstenite::WebSocketStream; use tonic::{transport::Server, Request, Response, Status}; +use serde_json::Value; //TODO: rename boarctrl to something like relayctrl ? pub mod adminctrl { @@ -418,7 +419,7 @@ fn main() -> Result<(), Box> { let service_manager = ServiceManager::new(node_signer, anchor_manager, service_mngr_events_send, service_mngr_peer_send, manager_send_dbrequests, manager_send_bitcoind_request, config.clone()); // We initialize the inclusion proof with txid, commitment and merkle proof as empty strings. - let mut inclusion_proof = InclusionProof::new("".to_string(), "".to_string(), "".to_string(), Vec::new(), config.clone()); + let mut inclusion_proof = InclusionProof::new("".to_string(), "".to_string(), "".to_string(), Vec::new(), "".to_string(), Value::Null, config.clone()); let addr = format!("[::1]:{}", cli.cli_port).parse()?; diff --git a/src/verifycommitment.rs b/src/verifycommitment.rs index ffd3ae0..8c36e3f 100644 --- a/src/verifycommitment.rs +++ b/src/verifycommitment.rs @@ -6,7 +6,6 @@ use crate::rpcclient::{Client, Auth}; use std::str::FromStr; use hex::{encode, decode}; use bip32::{ExtendedPublicKey, ExtendedKeyAttrs, PublicKey, DerivationPath, ChildNumber}; -use crate::verifycommitment_test::{MockClient, TEST_MERKLE_ROOT}; use serde_json::{from_str, Value}; pub fn verify_commitments(event_commitments: Vec>, inclusion_proof: &mut InclusionProof) -> bool { @@ -50,49 +49,14 @@ pub fn verify_slot_proof(slot: usize, inclusion_proof: &mut InclusionProof) -> b return proof.verify(merkle_root, &[slot], &[*leaf_to_prove], leaf_hashes.len()); } -pub fn verify_merkle_root_inclusion(txid: String, inclusion_proof: &mut InclusionProof) -> bool { - if cfg!(test) { - let client = MockClient::new(); - match MockClient::call("getrawtransaction", &[Value::String(txid), Value::Bool(true)]) { - Ok(resp) => { - let script_pubkey_from_tx = resp["vout"][0]["scriptPubKey"]["hex"].as_str().unwrap().to_string(); - let merkle_root = decode(TEST_MERKLE_ROOT).unwrap(); - let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; - let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; +pub fn verify_merkle_root_inclusion(inclusion_proof: &mut InclusionProof) -> bool { + let script_pubkey_from_tx = &inclusion_proof.raw_tx.lock().unwrap()["vout"][0]["scriptPubKey"]["hex"].as_str().unwrap().to_string(); + let merkle_root = decode(inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec()).unwrap(); + let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; + let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; - let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); - return script_pubkey == script_pubkey_from_tx; - } - Err(error) => { - println!("Error: {:?}", error); - } - } - } else { - let client = Client::new(format!("{}:{}/", inclusion_proof.config.bitcoind_params.host, inclusion_proof.config.bitcoind_params.port).as_str(), - Auth::UserPass(inclusion_proof.config.bitcoind_params.rpc_user.to_string(), - inclusion_proof.config.bitcoind_params.rpc_password.to_string())).unwrap(); - - match client.call("getrawtransaction", &[Value::String(txid), Value::Bool(true)]) { - Ok(resp) => { - if let Some(raw_value) = resp.result { - let json_value: Value = from_str(raw_value.get()).unwrap(); - let script_pubkey_from_tx = json_value["vout"][0]["scriptPubKey"]["hex"].as_str().unwrap().to_string(); - let merkle_root = inclusion_proof.merkle_root.lock().unwrap().as_bytes().to_vec(); - let initial_public_key_hex = &inclusion_proof.config.mainstay.base_pubkey; - let initial_chain_code_hex = &inclusion_proof.config.mainstay.chain_code; - - let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); - - return script_pubkey == script_pubkey_from_tx; - } - } - Err(error) => { - println!("Error: {:?}", error); - } - } - }; - - return false; + let script_pubkey = derive_script_pubkey_from_merkle_root(merkle_root, initial_public_key_hex.to_string(), initial_chain_code_hex.to_string()); + return script_pubkey == *script_pubkey_from_tx; } pub fn derive_script_pubkey_from_merkle_root(merkle_root: Vec, initial_public_key_hex: String, initial_chain_code_hex: String) -> String { diff --git a/src/verifycommitment_test.rs b/src/verifycommitment_test.rs index 6e32921..9ba950c 100644 --- a/src/verifycommitment_test.rs +++ b/src/verifycommitment_test.rs @@ -50,20 +50,6 @@ const TX_DATA_RES: &str = r#" pub const TEST_MERKLE_ROOT: &str = "8d0ad2782d8f6e3f63c6f9611841c239630b55061d558abcc6bac53349edac70"; -pub const TXID: &str = "b891111d35ffc72709140b7bd2a82fde20deca53831f42a96704dede42c793d2"; - -pub struct MockClient {} - -impl MockClient { - pub fn new() -> Self { - MockClient {} - } - pub fn call(command: &str, args: &[serde_json::Value]) -> Result { - let response: Value = from_str(TX_DATA_RES).unwrap(); - Ok(response) - } -} - #[test] fn test_verify_merkle_root_inclusion() { @@ -83,14 +69,17 @@ fn test_verify_merkle_root_inclusion() { } }; + let json_value: Value = from_str(TX_DATA_RES).unwrap(); let mut inclusion_proof = InclusionProof::new( "".to_string(), "".to_string(), - "".to_string(), - Vec::new(), + TEST_MERKLE_ROOT.to_string(), + Vec::new(), + "".to_string(), + json_value, config.clone() ); - let result = verify_merkle_root_inclusion(TXID.to_string(), &mut inclusion_proof); + let result = verify_merkle_root_inclusion(&mut inclusion_proof); assert_eq!(result, true); } \ No newline at end of file From 32021fd7c2668fc714052acacf9b3c1883832b88 Mon Sep 17 00:00:00 2001 From: DhananjayPurohit Date: Wed, 22 Nov 2023 14:19:57 +0530 Subject: [PATCH 10/10] fix: remove unused imports --- src/bitcoind_client.rs | 5 ++--- src/inclusionproof.rs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bitcoind_client.rs b/src/bitcoind_client.rs index ef0ed2c..f387c2a 100644 --- a/src/bitcoind_client.rs +++ b/src/bitcoind_client.rs @@ -21,8 +21,7 @@ use tokio::sync::Mutex as TokioMutex; use tokio::time::{sleep, Duration}; use crate::inclusionproof::InclusionProof; -use crate::verifycommitment::{verify_commitments, verify_slot_proof, verify_merkle_root_inclusion}; -use crate::nostr_db::get_hashes_of_all_events; +use crate::verifycommitment::{verify_merkle_root_inclusion}; #[derive(Debug)] pub enum BitcoindRequest { @@ -52,7 +51,7 @@ impl BitcoindClient { } pub async fn verifytxoutproof(mut inclusion_proof: InclusionProof) -> bool { - return verify_merkle_root_inclusion(&mut inclusion_proof).await; + return verify_merkle_root_inclusion(&mut inclusion_proof); } //TODO: run and dispatch call to bitcoind diff --git a/src/inclusionproof.rs b/src/inclusionproof.rs index 16f3478..d80afa6 100644 --- a/src/inclusionproof.rs +++ b/src/inclusionproof.rs @@ -12,7 +12,6 @@ use std::thread; use std::sync::Mutex; use tokio::time::{sleep, Duration}; use serde_json::{Value, from_str, to_value}; -use crate::verifycommitment::verify_merkle_root_inclusion; use crate::mainstay::{get_proof}; use crate::config::Config;