zebra_rpc/methods/types/
validate_address.rs

1//! Response type for the `validateaddress` RPC.
2
3use derive_getters::Getters;
4use derive_new::new;
5use jsonrpsee::core::RpcResult;
6use zebra_chain::{parameters::Network, primitives};
7
8/// `validateaddress` response
9#[derive(
10    Clone, Default, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Getters, new,
11)]
12pub struct ValidateAddressResponse {
13    /// Whether the address is valid.
14    ///
15    /// If not, this is the only property returned.
16    #[serde(rename = "isvalid")]
17    pub(crate) is_valid: bool,
18
19    /// The zcash address that has been validated.
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub(crate) address: Option<String>,
22
23    /// If the key is a script.
24    #[serde(rename = "isscript")]
25    #[serde(skip_serializing_if = "Option::is_none")]
26    #[getter(copy)]
27    pub(crate) is_script: Option<bool>,
28}
29
30impl ValidateAddressResponse {
31    /// Creates an empty response with `isvalid` of false.
32    pub fn invalid() -> Self {
33        Self::default()
34    }
35}
36
37/// Checks if a zcash transparent address of type P2PKH, P2SH or TEX is valid.
38/// Returns information about the given address if valid.
39pub fn validate_address(
40    network: Network,
41    raw_address: String,
42) -> RpcResult<ValidateAddressResponse> {
43    let Ok(address) = raw_address.parse::<zcash_address::ZcashAddress>() else {
44        return Ok(ValidateAddressResponse::invalid());
45    };
46
47    let address = match address.convert::<primitives::Address>() {
48        Ok(address) => address,
49        Err(err) => {
50            tracing::debug!(?err, "conversion error");
51            return Ok(ValidateAddressResponse::invalid());
52        }
53    };
54
55    // We want to match zcashd's behaviour
56    if !address.is_transparent() {
57        return Ok(ValidateAddressResponse::invalid());
58    }
59
60    if address.network() == network.kind() {
61        Ok(ValidateAddressResponse {
62            address: Some(raw_address),
63            is_valid: true,
64            is_script: Some(address.is_script_hash()),
65        })
66    } else {
67        tracing::info!(
68            ?network,
69            address_network = ?address.network(),
70            "invalid address in validateaddress RPC: Zebra's configured network must match address network"
71        );
72
73        Ok(ValidateAddressResponse::invalid())
74    }
75}