Adds `NetworkKind` and uses it instead of `Network` in `HistoryTreeParts` and `transparent::Address`

This commit is contained in:
Arya 2024-03-21 21:16:46 -04:00
parent 7533e2fbc0
commit 06cf9474ce
11 changed files with 220 additions and 144 deletions

View File

@ -23,7 +23,7 @@ pub mod arbitrary;
pub use error::*;
pub use genesis::*;
pub use network::Network;
pub use network::{Network, NetworkKind};
pub use network_upgrade::*;
pub use transaction::*;

View File

@ -66,6 +66,17 @@ impl NetworkParameters {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
/// An enum describing the kind of network, whether it's the production mainnet or a testnet.
pub enum NetworkKind {
/// The production mainnet.
Mainnet,
/// A test network.
Testnet,
}
/// An enum describing the possible network choices.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
@ -106,41 +117,50 @@ impl<'de> Deserialize<'de> for Network {
}
}
impl Network {
impl NetworkKind {
/// Returns the human-readable prefix for Base58Check-encoded transparent
/// pay-to-public-key-hash payment addresses for the network.
pub fn b58_pubkey_address_prefix(&self) -> [u8; 2] {
<ZcashPrimitivesNetwork>::try_from(self)
// This prefix is the same for Testnet and Regtest in zcashd.
// TODO: Use the constants directly when implementing `Parameters` for `Network` (#8365)
.unwrap_or(ZcashPrimitivesNetwork::TestNetwork)
.b58_pubkey_address_prefix()
pub fn b58_pubkey_address_prefix(self) -> [u8; 2] {
<ZcashPrimitivesNetwork>::from(self).b58_pubkey_address_prefix()
}
/// Returns the human-readable prefix for Base58Check-encoded transparent pay-to-script-hash
/// payment addresses for the network.
pub fn b58_script_address_prefix(&self) -> [u8; 2] {
<ZcashPrimitivesNetwork>::try_from(self)
// This prefix is the same for Testnet and Regtest in zcashd.
// TODO: Use the constants directly when implementing `Parameters` for `Network` (#8365)
.unwrap_or(ZcashPrimitivesNetwork::TestNetwork)
.b58_script_address_prefix()
pub fn b58_script_address_prefix(self) -> [u8; 2] {
<ZcashPrimitivesNetwork>::from(self).b58_script_address_prefix()
}
/// Returns true if the maximum block time rule is active for `network` and `height`.
///
/// Always returns true if `network` is the Mainnet.
/// If `network` is the Testnet, the `height` should be at least
/// TESTNET_MAX_TIME_START_HEIGHT to return true.
/// Returns false otherwise.
///
/// Part of the consensus rules at <https://zips.z.cash/protocol/protocol.pdf#blockheader>
pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool {
/// Return the network name as defined in
/// [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest)
pub fn bip70_network_name(&self) -> String {
match self {
Network::Mainnet => true,
// TODO: Move `TESTNET_MAX_TIME_START_HEIGHT` to a field on NetworkParameters (#8364)
Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
Self::Mainnet => "main".to_string(),
Self::Testnet => "test".to_string(),
}
}
/// Converts a [`zcash_address::Network`] to a [`NetworkKind`].
pub fn from_zcash_address(network: zcash_address::Network) -> Self {
match network {
zcash_address::Network::Main => NetworkKind::Mainnet,
zcash_address::Network::Test | zcash_address::Network::Regtest => NetworkKind::Testnet,
}
}
}
impl From<NetworkKind> for &'static str {
fn from(network: NetworkKind) -> &'static str {
match network {
NetworkKind::Mainnet => "MainnetKind",
NetworkKind::Testnet => "TestnetKind",
}
}
}
impl fmt::Display for NetworkKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str((*self).into())
}
}
impl From<&Network> for &'static str {
@ -178,17 +198,41 @@ impl Network {
}
}
/// Returns the [`NetworkKind`] for this network.
pub fn kind(&self) -> NetworkKind {
match self {
Network::Mainnet => NetworkKind::Mainnet,
Network::Testnet(_) => NetworkKind::Testnet,
}
}
/// Returns an iterator over [`Network`] variants.
pub fn iter() -> impl Iterator<Item = Self> {
// TODO: Use default values of `Testnet` variant when adding fields for #7845.
[Self::Mainnet, Self::new_default_testnet()].into_iter()
}
/// Returns true if the maximum block time rule is active for `network` and `height`.
///
/// Always returns true if `network` is the Mainnet.
/// If `network` is the Testnet, the `height` should be at least
/// TESTNET_MAX_TIME_START_HEIGHT to return true.
/// Returns false otherwise.
///
/// Part of the consensus rules at <https://zips.z.cash/protocol/protocol.pdf#blockheader>
pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool {
match self {
Network::Mainnet => true,
// TODO: Move `TESTNET_MAX_TIME_START_HEIGHT` to a field on NetworkParameters (#8364)
Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
}
}
/// Get the default port associated to this network.
pub fn default_port(&self) -> u16 {
match self {
Network::Mainnet => 8233,
// TODO: Add a `default_port` field to `NetworkParameters` to return here.
// TODO: Add a `default_port` field to `NetworkParameters` to return here. (zcashd uses 18344 for Regtest)
Network::Testnet(_params) => 18233,
}
}
@ -214,10 +258,7 @@ impl Network {
/// Return the network name as defined in
/// [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest)
pub fn bip70_network_name(&self) -> String {
match self {
Network::Mainnet => "main".to_string(),
Network::Testnet(_params) => "test".to_string(),
}
self.kind().bip70_network_name()
}
/// Return the lowercase network name.

View File

@ -6,7 +6,7 @@ use zcash_address::unified::{self, Container};
use zcash_primitives::sapling;
use crate::{
parameters::{Network, UnsupportedNetwork},
parameters::{Network, NetworkKind, UnsupportedNetwork},
transparent, BoxError,
};
@ -17,8 +17,8 @@ pub enum Address {
/// Sapling address
Sapling {
/// Address' network
network: Network,
/// Address' network kind
network: NetworkKind,
/// Sapling address
address: sapling::PaymentAddress,
@ -26,8 +26,8 @@ pub enum Address {
/// Unified address
Unified {
/// Address' network
network: Network,
/// Address' network kind
network: NetworkKind,
/// Unified address
unified_address: zcash_address::unified::Address,
@ -73,6 +73,15 @@ impl TryFrom<&Network> for zcash_address::Network {
}
}
impl From<NetworkKind> for zcash_address::Network {
fn from(network: NetworkKind) -> Self {
match network {
NetworkKind::Mainnet => zcash_address::Network::Main,
NetworkKind::Testnet => zcash_address::Network::Test,
}
}
}
impl zcash_address::TryFromAddress for Address {
// TODO: crate::serialization::SerializationError
type Error = BoxError;
@ -82,7 +91,7 @@ impl zcash_address::TryFromAddress for Address {
data: [u8; 20],
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
Ok(Self::Transparent(transparent::Address::from_pub_key_hash(
&network.try_into()?,
NetworkKind::from_zcash_address(network),
data,
)))
}
@ -92,7 +101,7 @@ impl zcash_address::TryFromAddress for Address {
data: [u8; 20],
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
Ok(Self::Transparent(transparent::Address::from_script_hash(
&network.try_into()?,
NetworkKind::from_zcash_address(network),
data,
)))
}
@ -101,7 +110,7 @@ impl zcash_address::TryFromAddress for Address {
network: zcash_address::Network,
data: [u8; 43],
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
let network = network.try_into()?;
let network = NetworkKind::from_zcash_address(network);
sapling::PaymentAddress::from_bytes(&data)
.map(|address| Self::Sapling { address, network })
.ok_or_else(|| BoxError::from("not a valid sapling address").into())
@ -111,7 +120,7 @@ impl zcash_address::TryFromAddress for Address {
network: zcash_address::Network,
unified_address: zcash_address::unified::Address,
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
let network = &network.try_into()?;
let network = NetworkKind::from_zcash_address(network);
let mut orchard = None;
let mut sapling = None;
let mut transparent = None;
@ -155,7 +164,7 @@ impl zcash_address::TryFromAddress for Address {
}
Ok(Self::Unified {
network: network.clone(),
network,
unified_address,
orchard,
sapling,
@ -166,10 +175,10 @@ impl zcash_address::TryFromAddress for Address {
impl Address {
/// Returns the network for the address.
pub fn network(&self) -> Network {
pub fn network(&self) -> NetworkKind {
match &self {
Self::Transparent(address) => address.network(),
Self::Sapling { network, .. } | Self::Unified { network, .. } => network.clone(),
Self::Sapling { network, .. } | Self::Unified { network, .. } => *network,
}
}
@ -196,14 +205,7 @@ impl Address {
Self::Transparent(address) => Some(address.to_string()),
Self::Sapling { address, network } => {
let data = address.to_bytes();
let network = network
.try_into()
.map_err(|err| {
warn!(?err, "could not convert address network to zcash network")
})
.ok()?;
let address = ZcashAddress::from_sapling(network, data);
let address = ZcashAddress::from_sapling((*network).into(), data);
Some(address.encode())
}
Self::Unified { .. } => None,

View File

@ -7,7 +7,7 @@ use zcash_primitives::transaction as zp_tx;
use crate::{
amount::{Amount, NonNegative},
parameters::{Network, NetworkUpgrade, UnsupportedNetwork},
parameters::{Network, NetworkKind, NetworkUpgrade, UnsupportedNetwork},
serialization::ZcashSerialize,
transaction::{AuthDigest, HashType, SigHash, Transaction},
transparent::{self, Script},
@ -328,11 +328,11 @@ pub(crate) fn transparent_output_address(
match alt_addr {
Some(zcash_primitives::legacy::TransparentAddress::PublicKey(pub_key_hash)) => Some(
transparent::Address::from_pub_key_hash(network, pub_key_hash),
transparent::Address::from_pub_key_hash(network.kind(), pub_key_hash),
),
Some(zcash_primitives::legacy::TransparentAddress::Script(script_hash)) => Some(
transparent::Address::from_script_hash(network.kind(), script_hash),
),
Some(zcash_primitives::legacy::TransparentAddress::Script(script_hash)) => {
Some(transparent::Address::from_script_hash(network, script_hash))
}
None => None,
}
}
@ -356,6 +356,15 @@ impl TryFrom<&Network> for zcash_primitives::consensus::Network {
}
}
impl From<NetworkKind> for zcash_primitives::consensus::Network {
fn from(network: NetworkKind) -> Self {
match network {
NetworkKind::Mainnet => zcash_primitives::consensus::Network::MainNetwork,
NetworkKind::Testnet => zcash_primitives::consensus::Network::TestNetwork,
}
}
}
impl From<zcash_primitives::consensus::Network> for Network {
fn from(network: zcash_primitives::consensus::Network) -> Self {
match network {

View File

@ -7,7 +7,7 @@ use secp256k1::PublicKey;
use sha2::Sha256;
use crate::{
parameters::Network,
parameters::NetworkKind,
serialization::{SerializationError, ZcashDeserialize, ZcashSerialize},
transparent::{opcodes::OpCode, Script},
};
@ -37,7 +37,7 @@ pub enum Address {
/// P2SH (Pay to Script Hash) addresses
PayToScriptHash {
/// Production, test, or other network
network: Network,
network: NetworkKind,
/// 20 bytes specifying a script hash.
script_hash: [u8; 20],
},
@ -45,7 +45,7 @@ pub enum Address {
/// P2PKH (Pay to Public Key Hash) addresses
PayToPublicKeyHash {
/// Production, test, or other network
network: Network,
network: NetworkKind,
/// 20 bytes specifying a public key hash, which is a RIPEMD-160
/// hash of a SHA-256 hash of a compressed ECDSA key encoding.
pub_key_hash: [u8; 20],
@ -131,27 +131,25 @@ impl ZcashDeserialize for Address {
match version_bytes {
zcash_primitives::constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX => {
Ok(Address::PayToScriptHash {
network: Network::Mainnet,
network: NetworkKind::Mainnet,
script_hash: hash_bytes,
})
}
zcash_primitives::constants::testnet::B58_SCRIPT_ADDRESS_PREFIX => {
Ok(Address::PayToScriptHash {
// TODO: Replace `network` field on `Address` with the prefix and a method for checking if it's the mainnet prefix.
network: Network::new_default_testnet(),
network: NetworkKind::Testnet,
script_hash: hash_bytes,
})
}
zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX => {
Ok(Address::PayToPublicKeyHash {
network: Network::Mainnet,
network: NetworkKind::Mainnet,
pub_key_hash: hash_bytes,
})
}
zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX => {
Ok(Address::PayToPublicKeyHash {
// TODO: Replace `network` field on `Address` with the prefix and a method for checking if it's the mainnet prefix.
network: Network::new_default_testnet(),
network: NetworkKind::Testnet,
pub_key_hash: hash_bytes,
})
}
@ -162,11 +160,11 @@ impl ZcashDeserialize for Address {
trait ToAddressWithNetwork {
/// Convert `self` to an `Address`, given the current `network`.
fn to_address(&self, network: Network) -> Address;
fn to_address(&self, network: NetworkKind) -> Address;
}
impl ToAddressWithNetwork for Script {
fn to_address(&self, network: Network) -> Address {
fn to_address(&self, network: NetworkKind) -> Address {
Address::PayToScriptHash {
network,
script_hash: Address::hash_payload(self.as_raw_bytes()),
@ -175,7 +173,7 @@ impl ToAddressWithNetwork for Script {
}
impl ToAddressWithNetwork for PublicKey {
fn to_address(&self, network: Network) -> Address {
fn to_address(&self, network: NetworkKind) -> Address {
Address::PayToPublicKeyHash {
network,
pub_key_hash: Address::hash_payload(&self.serialize()[..]),
@ -185,26 +183,26 @@ impl ToAddressWithNetwork for PublicKey {
impl Address {
/// Create an address for the given public key hash and network.
pub fn from_pub_key_hash(network: &Network, pub_key_hash: [u8; 20]) -> Self {
pub fn from_pub_key_hash(network: NetworkKind, pub_key_hash: [u8; 20]) -> Self {
Self::PayToPublicKeyHash {
network: network.clone(),
network,
pub_key_hash,
}
}
/// Create an address for the given script hash and network.
pub fn from_script_hash(network: &Network, script_hash: [u8; 20]) -> Self {
pub fn from_script_hash(network: NetworkKind, script_hash: [u8; 20]) -> Self {
Self::PayToScriptHash {
network: network.clone(),
network,
script_hash,
}
}
/// Returns the network for this address.
pub fn network(&self) -> Network {
/// Returns the network kind for this address.
pub fn network(&self) -> NetworkKind {
match self {
Address::PayToScriptHash { network, .. } => network.clone(),
Address::PayToPublicKeyHash { network, .. } => network.clone(),
Address::PayToScriptHash { network, .. } => *network,
Address::PayToPublicKeyHash { network, .. } => *network,
}
}
@ -285,7 +283,7 @@ mod tests {
])
.expect("A PublicKey from slice");
let t_addr = pub_key.to_address(Network::Mainnet);
let t_addr = pub_key.to_address(NetworkKind::Mainnet);
assert_eq!(format!("{t_addr}"), "t1bmMa1wJDFdbc2TiURQP5BbBz6jHjUBuHq");
}
@ -300,7 +298,7 @@ mod tests {
])
.expect("A PublicKey from slice");
let t_addr = pub_key.to_address(Network::new_default_testnet());
let t_addr = pub_key.to_address(NetworkKind::Testnet);
assert_eq!(format!("{t_addr}"), "tmTc6trRhbv96kGfA99i7vrFwb5p7BVFwc3");
}
@ -311,7 +309,7 @@ mod tests {
let script = Script::new(&[0u8; 20]);
let t_addr = script.to_address(Network::Mainnet);
let t_addr = script.to_address(NetworkKind::Mainnet);
assert_eq!(format!("{t_addr}"), "t3Y5pHwfgHbS6pDjj1HLuMFxhFFip1fcJ6g");
}
@ -322,7 +320,7 @@ mod tests {
let script = Script::new(&[0; 20]);
let t_addr = script.to_address(Network::new_default_testnet());
let t_addr = script.to_address(NetworkKind::Testnet);
assert_eq!(format!("{t_addr}"), "t2L51LcmpA43UMvKTw2Lwtt9LMjwyqU2V1P");
}

View File

@ -451,7 +451,7 @@ where
if let Some(miner_address) = mining_config.miner_address.clone() {
assert_eq!(
miner_address.network(),
network.clone(),
network.kind(),
"incorrect miner address config: {miner_address} \
network.network {network} and miner address network {} must match",
miner_address.network(),
@ -1084,7 +1084,7 @@ where
return Ok(validate_address::Response::invalid());
}
if address.network() == network {
if address.network() == network.kind() {
Ok(validate_address::Response {
address: Some(raw_address),
is_valid: true,
@ -1124,7 +1124,7 @@ where
}
};
if address.network() == network {
if address.network() == network.kind() {
Ok(z_validate_address::Response {
is_valid: true,
address: Some(raw_address),

View File

@ -94,7 +94,10 @@ pub async fn test_responses<State, ReadState>(
#[allow(clippy::unnecessary_struct_initialization)]
let mining_config = crate::config::mining::Config {
miner_address: Some(transparent::Address::from_script_hash(network, [0xad; 20])),
miner_address: Some(transparent::Address::from_script_hash(
network.kind(),
[0xad; 20],
)),
extra_coinbase_data: None,
debug_like_zcashd: true,
// TODO: Use default field values when optional features are enabled in tests #8183

View File

@ -1193,6 +1193,7 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) {
amount::NonNegative,
block::{Hash, MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION},
chain_sync_status::MockSyncStatus,
parameters::NetworkKind,
serialization::DateTime32,
transaction::{zip317, VerifiedUnminedTx},
work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256},
@ -1223,11 +1224,10 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) {
let mut mock_sync_status = MockSyncStatus::default();
mock_sync_status.set_is_close_to_tip(true);
let network = NetworkKind::Mainnet;
let miner_address = match use_p2pkh {
false => Some(transparent::Address::from_script_hash(&Mainnet, [0x7e; 20])),
true => Some(transparent::Address::from_pub_key_hash(
&Mainnet, [0x7e; 20],
)),
false => Some(transparent::Address::from_script_hash(network, [0x7e; 20])),
true => Some(transparent::Address::from_pub_key_hash(network, [0x7e; 20])),
};
#[allow(clippy::unnecessary_struct_initialization)]

View File

@ -10,8 +10,12 @@ use std::collections::BTreeMap;
use bincode::Options;
use zebra_chain::{
amount::NonNegative, block::Height, history_tree::NonEmptyHistoryTree, parameters::Network,
primitives::zcash_history, value_balance::ValueBalance,
amount::NonNegative,
block::Height,
history_tree::{HistoryTreeError, NonEmptyHistoryTree},
parameters::{Network, NetworkKind},
primitives::zcash_history,
value_balance::ValueBalance,
};
use crate::service::finalized_state::disk_format::{FromDisk, IntoDisk};
@ -39,42 +43,54 @@ impl FromDisk for ValueBalance<NonNegative> {
// https://docs.rs/bincode/1.3.3/bincode/config/index.html#options-struct-vs-bincode-functions
#[derive(serde::Serialize, serde::Deserialize)]
struct HistoryTreeParts {
network: Network,
pub struct HistoryTreeParts {
network: NetworkKind,
size: u32,
peaks: BTreeMap<u32, zcash_history::Entry>,
current_height: Height,
}
impl IntoDisk for NonEmptyHistoryTree {
impl HistoryTreeParts {
/// Converts [`HistoryTreeParts`] to a [`NonEmptyHistoryTree`].
pub(crate) fn with_network(
self,
network: &Network,
) -> Result<NonEmptyHistoryTree, HistoryTreeError> {
assert_eq!(
self.network,
network.kind(),
"history tree network kind should match current network"
);
NonEmptyHistoryTree::from_cache(network, self.size, self.peaks, self.current_height)
}
}
impl From<&NonEmptyHistoryTree> for HistoryTreeParts {
fn from(history_tree: &NonEmptyHistoryTree) -> Self {
HistoryTreeParts {
network: history_tree.network().kind(),
size: history_tree.size(),
peaks: history_tree.peaks().clone(),
current_height: history_tree.current_height(),
}
}
}
impl IntoDisk for HistoryTreeParts {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
let data = HistoryTreeParts {
network: self.network(),
size: self.size(),
peaks: self.peaks().clone(),
current_height: self.current_height(),
};
bincode::DefaultOptions::new()
.serialize(&data)
.serialize(self)
.expect("serialization to vec doesn't fail")
}
}
impl FromDisk for NonEmptyHistoryTree {
impl FromDisk for HistoryTreeParts {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let parts: HistoryTreeParts = bincode::DefaultOptions::new()
bincode::DefaultOptions::new()
.deserialize(bytes.as_ref())
.expect(
"deserialization format should match the serialization format used by IntoDisk",
);
NonEmptyHistoryTree::from_cache(
&parts.network,
parts.size,
parts.peaks,
parts.current_height,
)
.expect("deserialization format should match the serialization format used by IntoDisk")
.expect("deserialization format should match the serialization format used by IntoDisk")
}
}

View File

@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
use zebra_chain::{
amount::{self, Amount, NonNegative},
block::Height,
parameters::Network::{self, *},
parameters::NetworkKind,
serialization::{ZcashDeserializeInto, ZcashSerialize},
transparent::{self, Address::*},
};
@ -502,13 +502,10 @@ fn address_variant(address: &transparent::Address) -> u8 {
//
// (This probably doesn't matter, but it might help slightly with data compression.)
match (address.network(), address) {
(Mainnet, PayToPublicKeyHash { .. }) => 0,
(Mainnet, PayToScriptHash { .. }) => 1,
(Testnet(params), PayToPublicKeyHash { .. }) if params.is_default_testnet() => 2,
(Testnet(params), PayToScriptHash { .. }) if params.is_default_testnet() => 3,
// TODO: Use 4 and 5 for `Regtest` (#7839)
(Testnet(_params), PayToPublicKeyHash { .. }) => 6,
(Testnet(_params), PayToScriptHash { .. }) => 7,
(NetworkKind::Mainnet, PayToPublicKeyHash { .. }) => 0,
(NetworkKind::Mainnet, PayToScriptHash { .. }) => 1,
(NetworkKind::Testnet, PayToPublicKeyHash { .. }) => 2,
(NetworkKind::Testnet, PayToScriptHash { .. }) => 3,
}
}
@ -532,16 +529,16 @@ impl FromDisk for transparent::Address {
let hash_bytes = hash_bytes.try_into().unwrap();
let network = if address_variant < 2 {
Mainnet
NetworkKind::Mainnet
} else {
// TODO: Replace `network` field on `Address` with the prefix and a method for checking if it's the mainnet prefix.
Network::new_default_testnet()
NetworkKind::Testnet
};
if address_variant % 2 == 0 {
transparent::Address::from_pub_key_hash(&network, hash_bytes)
transparent::Address::from_pub_key_hash(network, hash_bytes)
} else {
transparent::Address::from_script_hash(&network, hash_bytes)
transparent::Address::from_script_hash(network, hash_bytes)
}
}
}

View File

@ -18,17 +18,17 @@ use std::{
};
use zebra_chain::{
amount::NonNegative,
block::Height,
history_tree::{HistoryTree, NonEmptyHistoryTree},
transparent,
amount::NonNegative, block::Height, history_tree::HistoryTree, transparent,
value_balance::ValueBalance,
};
use crate::{
request::FinalizedBlock,
service::finalized_state::{
disk_db::DiskWriteBatch, disk_format::RawBytes, zebra_db::ZebraDb, TypedColumnFamily,
disk_db::DiskWriteBatch,
disk_format::{chain::HistoryTreeParts, RawBytes},
zebra_db::ZebraDb,
TypedColumnFamily,
},
BoxError,
};
@ -42,15 +42,15 @@ pub const HISTORY_TREE: &str = "history_tree";
///
/// This constant should be used so the compiler can detect incorrectly typed accesses to the
/// column family.
pub type HistoryTreeCf<'cf> = TypedColumnFamily<'cf, (), NonEmptyHistoryTree>;
pub type HistoryTreePartsCf<'cf> = TypedColumnFamily<'cf, (), HistoryTreeParts>;
/// The legacy (1.3.0 and earlier) type for reading history trees from the database.
/// This type should not be used in new code.
pub type LegacyHistoryTreeCf<'cf> = TypedColumnFamily<'cf, Height, NonEmptyHistoryTree>;
pub type LegacyHistoryTreePartsCf<'cf> = TypedColumnFamily<'cf, Height, HistoryTreeParts>;
/// A generic raw key type for reading history trees from the database, regardless of the database version.
/// This type should not be used in new code.
pub type RawHistoryTreeCf<'cf> = TypedColumnFamily<'cf, RawBytes, NonEmptyHistoryTree>;
pub type RawHistoryTreePartsCf<'cf> = TypedColumnFamily<'cf, RawBytes, HistoryTreeParts>;
/// The name of the chain value pools column family.
///
@ -67,22 +67,22 @@ impl ZebraDb {
// Column family convenience methods
/// Returns a typed handle to the `history_tree` column family.
pub(crate) fn history_tree_cf(&self) -> HistoryTreeCf {
HistoryTreeCf::new(&self.db, HISTORY_TREE)
pub(crate) fn history_tree_cf(&self) -> HistoryTreePartsCf {
HistoryTreePartsCf::new(&self.db, HISTORY_TREE)
.expect("column family was created when database was created")
}
/// Returns a legacy typed handle to the `history_tree` column family.
/// This should not be used in new code.
pub(crate) fn legacy_history_tree_cf(&self) -> LegacyHistoryTreeCf {
LegacyHistoryTreeCf::new(&self.db, HISTORY_TREE)
pub(crate) fn legacy_history_tree_cf(&self) -> LegacyHistoryTreePartsCf {
LegacyHistoryTreePartsCf::new(&self.db, HISTORY_TREE)
.expect("column family was created when database was created")
}
/// Returns a generic raw key typed handle to the `history_tree` column family.
/// This should not be used in new code.
pub(crate) fn raw_history_tree_cf(&self) -> RawHistoryTreeCf {
RawHistoryTreeCf::new(&self.db, HISTORY_TREE)
pub(crate) fn raw_history_tree_cf(&self) -> RawHistoryTreePartsCf {
RawHistoryTreePartsCf::new(&self.db, HISTORY_TREE)
.expect("column family was created when database was created")
}
@ -115,19 +115,24 @@ impl ZebraDb {
//
// So we use the empty key `()`. Since the key has a constant value, we will always read
// the latest tree.
let mut history_tree = history_tree_cf.zs_get(&());
let mut history_tree_parts = history_tree_cf.zs_get(&());
if history_tree.is_none() {
if history_tree_parts.is_none() {
let legacy_history_tree_cf = self.legacy_history_tree_cf();
// In Zebra 1.4.0 and later, we only update the history tip tree when it has changed (for every block after heartwood).
// But we write with a `()` key, not a height key.
// So we need to look for the most recent update height if the `()` key has never been written.
history_tree = legacy_history_tree_cf
history_tree_parts = legacy_history_tree_cf
.zs_last_key_value()
.map(|(_height_key, tree_value)| tree_value);
}
let history_tree = history_tree_parts.map(|parts| {
parts.with_network(&self.db.network()).expect(
"deserialization format should match the serialization format used by IntoDisk",
)
});
Arc::new(HistoryTree::from(history_tree))
}
@ -139,7 +144,12 @@ impl ZebraDb {
raw_history_tree_cf
.zs_forward_range_iter(..)
.map(|(raw_key, history_tree)| (raw_key, Arc::new(HistoryTree::from(history_tree))))
.map(|(raw_key, history_tree_parts)| {
let history_tree = history_tree_parts.with_network(&self.db.network()).expect(
"deserialization format should match the serialization format used by IntoDisk",
);
(raw_key, Arc::new(HistoryTree::from(history_tree)))
})
.collect()
}
@ -164,9 +174,9 @@ impl DiskWriteBatch {
pub fn update_history_tree(&mut self, db: &ZebraDb, tree: &HistoryTree) {
let history_tree_cf = db.history_tree_cf().with_batch_for_writing(self);
if let Some(tree) = tree.as_ref().as_ref() {
if let Some(tree) = tree.as_ref() {
// The batch is modified by this method and written by the caller.
let _ = history_tree_cf.zs_insert(&(), tree);
let _ = history_tree_cf.zs_insert(&(), &HistoryTreeParts::from(tree));
}
}