Skip to content

Commit ab71a7a

Browse files
Fix workspace build and test compilation errors (#105)
* fix: resolve workspace build and test compilation errors This commit fixes multiple compilation errors across the workspace: Build Fixes: - Fix PSBT module import in dash-fuzz: change from dashcore::psbt to key_wallet::psbt - Add key-wallet dependency to fuzz/Cargo.toml - Fix address module import in key-wallet-ffi: remove non-existent address module - Add missing Error pattern matches: CoinJoinNotEnabled, Serialization, InvalidParameter - Fix type mismatches: secp256k1::PublicKey vs dashcore::PublicKey conversions - Fix Address<NetworkUnchecked> vs Address<NetworkChecked> using require_network() - Implement AddressGenerator using BIP44 derivation instead of missing struct Test Fixes: - Fix platform integration safety test: separate null pointers for different types - Add missing ChainState fields: sync_base_height, synced_from_checkpoint - Add missing SpvStats fields: connected_peers, total_peers, header_height, filter_height All workspace crates now compile successfully with both cargo build and cargo test. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: run cargo fmt --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1c133ef commit ab71a7a

File tree

5 files changed

+102
-77
lines changed

5 files changed

+102
-77
lines changed

dash-spv-ffi/tests/test_platform_integration_safety.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,11 @@ fn test_error_string_lifecycle() {
357357
fn test_handle_lifecycle() {
358358
unsafe {
359359
// Test null handle operations
360-
let null_handle = ptr::null_mut();
360+
let null_client: *mut FFIDashSpvClient = ptr::null_mut();
361+
let null_handle: *mut CoreSDKHandle = ptr::null_mut();
361362

362363
// Getting core handle from null client
363-
let handle = ffi_dash_spv_get_core_handle(null_handle);
364+
let handle = ffi_dash_spv_get_core_handle(null_client);
364365
assert!(handle.is_null());
365366

366367
// Releasing null handle should be safe

dash-spv-ffi/tests/unit/test_type_conversions.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ mod tests {
172172
current_filter_tip: None,
173173
masternode_engine: None,
174174
last_masternode_diff_height: None,
175+
sync_base_height: 0,
176+
synced_from_checkpoint: false,
175177
};
176178

177179
let ffi_state = FFIChainState::from(state);
@@ -213,6 +215,10 @@ mod tests {
213215
pending_filter_requests: 0,
214216
filter_request_timeouts: u64::MAX,
215217
filter_requests_retried: u64::MAX,
218+
connected_peers: 0,
219+
total_peers: 0,
220+
header_height: 0,
221+
filter_height: 0,
216222
};
217223

218224
let ffi_stats = FFISpvStats::from(stats);

fuzz/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ cargo-fuzz = true
1111
[dependencies]
1212
honggfuzz = { version = "0.5", default-features = false }
1313
dashcore = { path = "../dash", features = [ "serde" ] }
14+
key-wallet = { path = "../key-wallet" }
1415

1516
serde = { version = "1.0.219", features = [ "derive" ] }
1617
serde_json = "1.0"

fuzz/fuzz_targets/dash/deserialize_psbt.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use honggfuzz::fuzz;
22

33
fn do_test(data: &[u8]) {
4-
let psbt: Result<dashcore::psbt::PartiallySignedTransaction, _> =
5-
dashcore::psbt::Psbt::deserialize(data);
4+
let psbt: Result<key_wallet::psbt::PartiallySignedTransaction, _> =
5+
key_wallet::psbt::Psbt::deserialize(data);
66
match psbt {
77
Err(_) => {}
88
Ok(psbt) => {
9-
let ser = dashcore::psbt::Psbt::serialize(&psbt);
10-
let deser = dashcore::psbt::Psbt::deserialize(&ser).unwrap();
9+
let ser = key_wallet::psbt::Psbt::serialize(&psbt);
10+
let deser = key_wallet::psbt::Psbt::deserialize(&ser).unwrap();
1111
// Since the fuzz data could order psbt fields differently, we compare to our deser/ser instead of data
12-
assert_eq!(ser, dashcore::psbt::Psbt::serialize(&deser));
12+
assert_eq!(ser, key_wallet::psbt::Psbt::serialize(&deser));
1313
}
1414
}
1515
}

key-wallet-ffi/src/lib.rs

Lines changed: 87 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use std::str::FromStr;
44
use std::sync::Arc;
55

66
use key_wallet::{
7-
self as kw, address as kw_address, derivation::HDWallet as KwHDWallet, mnemonic as kw_mnemonic,
8-
DerivationPath as KwDerivationPath, ExtendedPrivKey, ExtendedPubKey, Network as KwNetwork,
7+
self as kw, derivation::HDWallet as KwHDWallet, mnemonic as kw_mnemonic, Address as KwAddress,
8+
AddressType as KwAddressType, DerivationPath as KwDerivationPath, ExtendedPrivKey,
9+
ExtendedPubKey, Network as KwNetwork,
910
};
1011
use secp256k1::{PublicKey, Secp256k1};
1112

@@ -75,20 +76,21 @@ pub enum AddressType {
7576
P2SH,
7677
}
7778

78-
impl From<kw_address::AddressType> for AddressType {
79-
fn from(t: kw_address::AddressType) -> Self {
79+
impl From<KwAddressType> for AddressType {
80+
fn from(t: KwAddressType) -> Self {
8081
match t {
81-
kw_address::AddressType::P2PKH => AddressType::P2PKH,
82-
kw_address::AddressType::P2SH => AddressType::P2SH,
82+
KwAddressType::P2pkh => AddressType::P2PKH,
83+
KwAddressType::P2sh => AddressType::P2SH,
84+
_ => AddressType::P2PKH, // Default to P2PKH for unknown types
8385
}
8486
}
8587
}
8688

87-
impl From<AddressType> for kw_address::AddressType {
89+
impl From<AddressType> for KwAddressType {
8890
fn from(t: AddressType) -> Self {
8991
match t {
90-
AddressType::P2PKH => kw_address::AddressType::P2PKH,
91-
AddressType::P2SH => kw_address::AddressType::P2SH,
92+
AddressType::P2PKH => KwAddressType::P2pkh,
93+
AddressType::P2SH => KwAddressType::P2sh,
9294
}
9395
}
9496
}
@@ -189,6 +191,15 @@ impl From<kw::Error> for KeyWalletError {
189191
kw::Error::KeyError(msg) => KeyWalletError::KeyError {
190192
message: msg,
191193
},
194+
kw::Error::CoinJoinNotEnabled => KeyWalletError::KeyError {
195+
message: "CoinJoin not enabled".into(),
196+
},
197+
kw::Error::Serialization(msg) => KeyWalletError::KeyError {
198+
message: format!("Serialization error: {}", msg),
199+
},
200+
kw::Error::InvalidParameter(msg) => KeyWalletError::KeyError {
201+
message: format!("Invalid parameter: {}", msg),
202+
},
192203
}
193204
}
194205
}
@@ -201,6 +212,14 @@ impl From<kw::bip32::Error> for KeyWalletError {
201212
}
202213
}
203214

215+
impl From<kw::dashcore::address::Error> for KeyWalletError {
216+
fn from(e: kw::dashcore::address::Error) -> Self {
217+
KeyWalletError::AddressError {
218+
message: e.to_string(),
219+
}
220+
}
221+
}
222+
204223
// Validate mnemonic function
205224
pub fn validate_mnemonic(phrase: String, language: Language) -> Result<bool, KeyWalletError> {
206225
Ok(kw::Mnemonic::validate(&phrase, language.into()))
@@ -439,53 +458,33 @@ impl ExtPubKey {
439458

440459
// Address wrapper
441460
pub struct Address {
442-
inner: kw_address::Address,
461+
inner: KwAddress,
443462
}
444463

445464
impl Address {
446465
pub fn from_string(address: String, network: Network) -> Result<Self, KeyWalletError> {
447-
let inner = kw_address::Address::from_str(&address).map_err(|e| KeyWalletError::from(e))?;
466+
let unchecked_addr = KwAddress::from_str(&address).map_err(|e| KeyWalletError::from(e))?;
448467

449-
// Validate that the parsed network matches the expected network
450-
// Note: Testnet, Devnet, and Regtest all share the same address prefixes (140/19)
451-
// so we need to be flexible when comparing these networks
452-
let parsed_network: KwNetwork = inner.network;
468+
// Convert to expected network and require it
453469
let expected_network: KwNetwork = network.into();
454-
455-
let networks_compatible = match (parsed_network, expected_network) {
456-
// Exact matches are always OK
457-
(n1, n2) if n1 == n2 => true,
458-
// Testnet addresses can be used on devnet/regtest and vice versa
459-
(KwNetwork::Testnet, KwNetwork::Devnet)
460-
| (KwNetwork::Testnet, KwNetwork::Regtest)
461-
| (KwNetwork::Devnet, KwNetwork::Testnet)
462-
| (KwNetwork::Devnet, KwNetwork::Regtest)
463-
| (KwNetwork::Regtest, KwNetwork::Testnet)
464-
| (KwNetwork::Regtest, KwNetwork::Devnet) => true,
465-
// All other combinations are incompatible
466-
_ => false,
467-
};
468-
469-
if !networks_compatible {
470-
return Err(KeyWalletError::AddressError {
471-
message: format!(
472-
"Address is for network {:?}, expected {:?}",
473-
inner.network, network
474-
),
475-
});
476-
}
470+
let inner = unchecked_addr.require_network(expected_network).map_err(|e| {
471+
KeyWalletError::AddressError {
472+
message: format!("Address network validation failed: {}", e),
473+
}
474+
})?;
477475

478476
Ok(Self {
479477
inner,
480478
})
481479
}
482480

483481
pub fn from_public_key(public_key: Vec<u8>, network: Network) -> Result<Self, KeyWalletError> {
484-
let pubkey =
482+
let secp_pubkey =
485483
PublicKey::from_slice(&public_key).map_err(|e| KeyWalletError::Secp256k1Error {
486484
message: e.to_string(),
487485
})?;
488-
let inner = kw_address::Address::p2pkh(&pubkey, network.into());
486+
let dashcore_pubkey = kw::dashcore::PublicKey::new(secp_pubkey);
487+
let inner = KwAddress::p2pkh(&dashcore_pubkey, network.into());
489488
Ok(Self {
490489
inner,
491490
})
@@ -496,11 +495,11 @@ impl Address {
496495
}
497496

498497
pub fn get_type(&self) -> AddressType {
499-
self.inner.address_type.into()
498+
self.inner.address_type().unwrap_or(KwAddressType::P2pkh).into()
500499
}
501500

502501
pub fn get_network(&self) -> Network {
503-
match self.inner.network {
502+
match *self.inner.network() {
504503
KwNetwork::Dash => Network::Dash,
505504
KwNetwork::Testnet => Network::Testnet,
506505
KwNetwork::Regtest => Network::Regtest,
@@ -510,19 +509,19 @@ impl Address {
510509
}
511510

512511
pub fn get_script_pubkey(&self) -> Vec<u8> {
513-
self.inner.script_pubkey()
512+
self.inner.script_pubkey().into()
514513
}
515514
}
516515

517516
// Address generator wrapper
518517
pub struct AddressGenerator {
519-
inner: kw_address::AddressGenerator,
518+
network: Network,
520519
}
521520

522521
impl AddressGenerator {
523522
pub fn new(network: Network) -> Self {
524523
Self {
525-
inner: kw_address::AddressGenerator::new(network.into()),
524+
network,
526525
}
527526
}
528527

@@ -538,15 +537,44 @@ impl AddressGenerator {
538537
message: e.to_string(),
539538
})?;
540539

541-
// Generate addresses for a single index
542-
let addrs = self
543-
.inner
544-
.generate_range(&xpub, external, index, 1)
545-
.map_err(|e| KeyWalletError::from(e))?;
540+
let secp = Secp256k1::new();
546541

547-
let addr = addrs.into_iter().next().ok_or_else(|| KeyWalletError::KeyError {
548-
message: "Failed to generate address".into(),
549-
})?;
542+
// Derive child key: 0 for external (receiving), 1 for internal (change)
543+
let chain_code = if external {
544+
0
545+
} else {
546+
1
547+
};
548+
let child_chain = xpub
549+
.ckd_pub(
550+
&secp,
551+
kw::ChildNumber::from_normal_idx(chain_code).map_err(|e| {
552+
KeyWalletError::InvalidDerivationPath {
553+
message: e.to_string(),
554+
}
555+
})?,
556+
)
557+
.map_err(|e| KeyWalletError::KeyError {
558+
message: e.to_string(),
559+
})?;
560+
561+
// Derive specific index
562+
let child = child_chain
563+
.ckd_pub(
564+
&secp,
565+
kw::ChildNumber::from_normal_idx(index).map_err(|e| {
566+
KeyWalletError::InvalidDerivationPath {
567+
message: e.to_string(),
568+
}
569+
})?,
570+
)
571+
.map_err(|e| KeyWalletError::KeyError {
572+
message: e.to_string(),
573+
})?;
574+
575+
// Generate P2PKH address from the public key
576+
let dashcore_pubkey = kw::dashcore::PublicKey::new(child.public_key);
577+
let addr = KwAddress::p2pkh(&dashcore_pubkey, self.network.into());
550578

551579
Ok(Arc::new(Address {
552580
inner: addr,
@@ -560,25 +588,14 @@ impl AddressGenerator {
560588
start: u32,
561589
count: u32,
562590
) -> Result<Vec<Arc<Address>>, KeyWalletError> {
563-
// Parse the extended public key from string
564-
let xpub =
565-
ExtendedPubKey::from_str(&account_xpub.xpub).map_err(|e| KeyWalletError::KeyError {
566-
message: e.to_string(),
567-
})?;
591+
let mut addresses = Vec::new();
568592

569-
let addrs = self
570-
.inner
571-
.generate_range(&xpub, external, start, count)
572-
.map_err(|e| KeyWalletError::from(e))?;
593+
for i in 0..count {
594+
let addr = self.generate(account_xpub.clone(), external, start + i)?;
595+
addresses.push(addr);
596+
}
573597

574-
Ok(addrs
575-
.into_iter()
576-
.map(|addr| {
577-
Arc::new(Address {
578-
inner: addr,
579-
})
580-
})
581-
.collect())
598+
Ok(addresses)
582599
}
583600
}
584601

0 commit comments

Comments
 (0)