Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ members = [
[workspace.dependencies]
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "0093278609a22fc53086bfef569b74bf10544982" }
dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "0093278609a22fc53086bfef569b74bf10544982" }
dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "0093278609a22fc53086bfef569b74bf10544982" }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "0093278609a22fc53086bfef569b74bf10544982" }
dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "0093278609a22fc53086bfef569b74bf10544982" }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "0093278609a22fc53086bfef569b74bf10544982" }
Expand Down
58 changes: 2 additions & 56 deletions packages/rs-sdk-ffi/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,62 +380,8 @@ pub unsafe extern "C" fn dash_sdk_create_trusted(config: *const DashSDKConfig) -
info!("dash_sdk_create_trusted: no DAPI addresses provided, using defaults for network");
// Use default addresses for the network
match network {
Network::Testnet => {
// Use testnet addresses from WASM SDK
let default_addresses = [
"https://52.12.176.90:1443",
"https://35.82.197.197:1443",
"https://44.240.98.102:1443",
"https://52.34.144.50:1443",
"https://44.239.39.153:1443",
"https://35.164.23.245:1443",
"https://54.149.33.167:1443",
]
.join(",");

info!(
addresses = default_addresses.as_str(),
"dash_sdk_create_trusted: using default testnet addresses"
);
let address_list = match AddressList::from_str(&default_addresses) {
Ok(list) => list,
Err(e) => {
error!(error = %e, "dash_sdk_create_trusted: failed to parse default addresses");
return DashSDKResult::error(DashSDKError::new(
DashSDKErrorCode::InternalError,
format!("Failed to parse default addresses: {}", e),
));
}
};
SdkBuilder::new(address_list).with_network(network)
}
Network::Mainnet => {
// Use mainnet addresses from WASM SDK
let default_addresses = [
"https://149.28.241.190:443",
"https://198.7.115.48:443",
"https://134.255.182.186:443",
"https://93.115.172.39:443",
"https://5.189.164.253:443",
"https://178.215.237.134:443",
"https://157.66.81.162:443",
"https://173.212.232.90:443",
]
.join(",");

info!("dash_sdk_create_trusted: using default mainnet addresses");
let address_list = match AddressList::from_str(&default_addresses) {
Ok(list) => list,
Err(e) => {
error!(error = %e, "dash_sdk_create_trusted: failed to parse default addresses");
return DashSDKResult::error(DashSDKError::new(
DashSDKErrorCode::InternalError,
format!("Failed to parse default addresses: {}", e),
));
}
};
SdkBuilder::new(address_list).with_network(network)
}
Network::Testnet => SdkBuilder::new_testnet(),
Network::Mainnet => SdkBuilder::new_mainnet(),
_ => {
error!(
?network,
Expand Down
1 change: 1 addition & 0 deletions packages/rs-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [
] }
dapi-grpc = { path = "../dapi-grpc", default-features = false }
rs-dapi-client = { path = "../rs-dapi-client", default-features = false }
dash-network-seeds = { workspace = true }
drive = { path = "../rs-drive", default-features = false, features = [
"verify",
] }
Expand Down
126 changes: 118 additions & 8 deletions packages/rs-sdk/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use drive_proof_verifier::FromProof;
pub use http::Uri;
#[cfg(feature = "mocks")]
use rs_dapi_client::mock::MockDapiClient;
use rs_dapi_client::Address;
pub use rs_dapi_client::AddressList;
pub use rs_dapi_client::RequestSettings;
use rs_dapi_client::{
Expand Down Expand Up @@ -63,6 +64,41 @@ const DEFAULT_REQUEST_SETTINGS: RequestSettings = RequestSettings {
max_decoding_message_size: None,
};

/// Build the default DAPI bootstrap address list for `network` from
/// [`dash_network_seeds`].
///
/// The seed lists are single-source-of-truth, weekly-refreshed upstream in
/// `rust-dashcore`. We filter to Evo (HPMN) masternodes — the only ones that
/// run Dash Platform — and build `https://<ip>:<platform_http_port>` URIs.
/// The Core port on `seed.address` is intentionally discarded: DAPI clients
/// need the platform HTTP port, not the Core P2P port.
///
/// Malformed upstream entries are silently skipped rather than panicking;
/// the DAPI client handles retry/rotation across the remaining addresses.
///
/// ## Panics
///
/// Panics on networks other than `Mainnet` and `Testnet` — no upstream
/// seed list exists for devnet/regtest.
fn default_address_list_for_network(network: Network) -> AddressList {
if !matches!(network, Network::Mainnet | Network::Testnet) {
panic!("default address list is only available for mainnet and testnet");
}
let mut list = AddressList::new();
for seed in dash_network_seeds::evo_seeds(network) {
let Some(port) = seed.platform_http_port else {
continue;
};
let url = format!("https://{}:{}", seed.address.ip(), port);
Comment thread
lklimek marked this conversation as resolved.
if let Ok(uri) = url.parse::<Uri>() {
if let Ok(address) = Address::try_from(uri) {
list.add(address);
}
Comment thread
lklimek marked this conversation as resolved.
}
}
list
}

/// Dash Platform SDK
///
/// This is the main entry point for interacting with Dash Platform.
Expand Down Expand Up @@ -747,18 +783,18 @@ impl SdkBuilder {
Self::default()
}

/// Create a new SdkBuilder instance preconfigured for testnet. NOT IMPLEMENTED YET.
/// Create a new SdkBuilder instance preconfigured for testnet.
///
/// This is a helper method that preconfigures [SdkBuilder] for testnet use.
/// Use this method if you want to connect to Dash Platform testnet during development and testing
/// of your solution.
pub fn new_testnet() -> Self {
unimplemented!(
"Testnet address list not implemented yet. Use new() and provide address list."
)
let address_list = default_address_list_for_network(Network::Testnet);

Self::new(address_list).with_network(Network::Testnet)
}

/// Create a new SdkBuilder instance preconfigured for mainnet (production network). NOT IMPLEMENTED YET.
/// Create a new SdkBuilder instance preconfigured for mainnet (production network).
///
/// This is a helper method that preconfigures [SdkBuilder] for production use.
/// Use this method if you want to connect to Dash Platform mainnet with production-ready product.
Expand All @@ -771,9 +807,9 @@ impl SdkBuilder {
///
/// This method is unstable and can be changed in the future.
pub fn new_mainnet() -> Self {
unimplemented!(
"Mainnet address list not implemented yet. Use new() and provide address list."
)
let address_list = default_address_list_for_network(Network::Mainnet);

Self::new(address_list).with_network(Network::Mainnet)
Comment thread
lklimek marked this conversation as resolved.
}

/// Configure network type.
Expand Down Expand Up @@ -1102,6 +1138,80 @@ mod test {

use crate::SdkBuilder;

use super::Network;

/// Mainnet Evo masternodes expose the Platform HTTP endpoint on 443.
const MAINNET_PLATFORM_HTTP_PORT: u16 = 443;
/// Testnet Evo masternodes expose the Platform HTTP endpoint on 1443.
const TESTNET_PLATFORM_HTTP_PORT: u16 = 1443;

#[test]
fn new_testnet_sources_bootstrap_from_seeds() {
let builder = SdkBuilder::new_testnet();
let address_list = builder
.addresses
.as_ref()
.expect("testnet builder should configure default addresses");

assert_eq!(builder.network, Network::Testnet);
assert!(
!address_list.is_empty(),
"testnet must have at least one bootstrap address"
);
for address in address_list.get_live_addresses() {
assert_eq!(
address.uri().port_u16(),
Some(TESTNET_PLATFORM_HTTP_PORT),
"testnet bootstrap address must use the platform HTTP port",
);
}
}

#[test]
fn new_mainnet_sources_bootstrap_from_seeds() {
let builder = SdkBuilder::new_mainnet();
let address_list = builder
.addresses
.as_ref()
.expect("mainnet builder should configure default addresses");

assert_eq!(builder.network, Network::Mainnet);
assert!(
!address_list.is_empty(),
"mainnet must have at least one bootstrap address"
);
for address in address_list.get_live_addresses() {
assert_eq!(
address.uri().port_u16(),
Some(MAINNET_PLATFORM_HTTP_PORT),
"mainnet bootstrap address must use the platform HTTP port",
);
}
}

/// Smoke signal: the upstream seed lists are far larger than 10 entries on
/// both networks. If parsing drops most of them we want a loud test
/// failure rather than silently shipping a near-empty bootstrap list.
#[test]
fn bootstrap_counts_reasonable() {
let mainnet = SdkBuilder::new_mainnet()
.addresses
.expect("mainnet builder should configure default addresses");
let testnet = SdkBuilder::new_testnet()
.addresses
.expect("testnet builder should configure default addresses");
assert!(
mainnet.len() >= 10,
"expected >=10 mainnet bootstrap addresses, got {}",
mainnet.len()
);
assert!(
testnet.len() >= 10,
"expected >=10 testnet bootstrap addresses, got {}",
testnet.len()
);
}

#[test_matrix(97..102, 100, 2, false; "valid height")]
#[test_case(103, 100, 2, true; "invalid height")]
fn test_verify_metadata_height(
Expand Down
34 changes: 3 additions & 31 deletions packages/wasm-sdk/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,7 @@ fn parse_addresses(addresses: &'static [&str]) -> Vec<Address> {
})
.collect()
}
// Mainnet addresses from mnowatch.org
fn default_mainnet_addresses() -> Vec<Address> {
parse_addresses(&[
"https://149.28.241.190:443",
"https://198.7.115.48:443",
"https://134.255.182.186:443",
"https://93.115.172.39:443",
"https://5.189.164.253:443",
])
}
// Testnet addresses from https://quorums.testnet.networks.dash.org/masternodes
fn default_testnet_addresses() -> Vec<Address> {
parse_addresses(&[
"https://52.12.176.90:1443",
"https://35.82.197.197:1443",
"https://44.240.98.102:1443",
"https://52.34.144.50:1443",
"https://44.239.39.153:1443",
"https://34.214.48.68:1443",
"https://54.149.33.167:1443",
"https://52.24.124.162:1443",
])
}

fn default_local_addresses() -> Vec<Address> {
parse_addresses(&["https://127.0.0.1:2443"])
}
Expand Down Expand Up @@ -249,10 +227,7 @@ impl WasmSdkBuilder {

#[wasm_bindgen(js_name = "mainnet")]
pub fn new_mainnet() -> Self {
let address_list = dash_sdk::sdk::AddressList::from_iter(default_mainnet_addresses());
let sdk_builder = SdkBuilder::new(address_list)
.with_network(dash_sdk::dpp::dashcore::Network::Mainnet)
.with_context_provider(WasmContext {});
let sdk_builder = SdkBuilder::new_mainnet().with_context_provider(WasmContext {});

Self {
inner: sdk_builder,
Expand All @@ -262,10 +237,7 @@ impl WasmSdkBuilder {

#[wasm_bindgen(js_name = "testnet")]
pub fn new_testnet() -> Self {
let address_list = dash_sdk::sdk::AddressList::from_iter(default_testnet_addresses());
let sdk_builder = SdkBuilder::new(address_list)
.with_network(dash_sdk::dpp::dashcore::Network::Testnet)
.with_context_provider(WasmContext {});
let sdk_builder = SdkBuilder::new_testnet().with_context_provider(WasmContext {});

Self {
inner: sdk_builder,
Expand Down
Loading