Add Orchard components to unified address
Co-authored-by: Jack Grigg <jack@z.cash>
This commit is contained in:
parent
3e3ee1bf3b
commit
1a1522a4f1
|
@ -73,6 +73,12 @@ namespace libzcash {
|
|||
public:
|
||||
ReceiverToString() {}
|
||||
|
||||
std::string operator()(const OrchardRawAddress &zaddr) const {
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << zaddr;
|
||||
return tfm::format("Orchard(%s)", HexStr(ss.begin(), ss.end()));
|
||||
}
|
||||
|
||||
std::string operator()(const SaplingPaymentAddress &zaddr) const {
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << zaddr;
|
||||
|
@ -126,8 +132,11 @@ TEST(Keys, EncodeAndDecodeUnifiedAddresses)
|
|||
// These were added to the UA in preference order by the Python test vectors.
|
||||
if (!test[3].isNull()) {
|
||||
auto data = ParseHex(test[3].get_str());
|
||||
libzcash::UnknownReceiver r(0x03, data);
|
||||
ua.AddReceiver(r);
|
||||
CDataStream ss(
|
||||
data,
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
ua.AddReceiver(libzcash::OrchardRawAddress::Read(ss));
|
||||
}
|
||||
if (!test[2].isNull()) {
|
||||
auto data = ParseHex(test[2].get_str());
|
||||
|
|
|
@ -56,6 +56,7 @@ class DataLenForReceiver {
|
|||
public:
|
||||
DataLenForReceiver() {}
|
||||
|
||||
size_t operator()(const libzcash::OrchardRawAddress &zaddr) const { return 43; }
|
||||
size_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const { return 43; }
|
||||
size_t operator()(const CScriptID &p2sh) const { return 20; }
|
||||
size_t operator()(const CKeyID &p2pkh) const { return 20; }
|
||||
|
@ -76,6 +77,13 @@ class CopyDataForReceiver {
|
|||
public:
|
||||
CopyDataForReceiver(unsigned char* data, size_t length) : data(data), length(length) {}
|
||||
|
||||
void operator()(const libzcash::OrchardRawAddress &zaddr) const {
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << zaddr;
|
||||
assert(length == ss.size());
|
||||
memcpy(data, ss.data(), ss.size());
|
||||
}
|
||||
|
||||
void operator()(const libzcash::SaplingPaymentAddress &zaddr) const {
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << zaddr;
|
||||
|
@ -433,6 +441,12 @@ std::optional<T1> DecodeAny(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
static bool AddOrchardReceiver(void* ua, OrchardRawAddressPtr* ptr)
|
||||
{
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(
|
||||
libzcash::OrchardRawAddress::KeyIoOnlyFromReceiver(ptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* `raw` MUST be 43 bytes.
|
||||
*/
|
||||
|
@ -492,6 +506,7 @@ std::optional<libzcash::PaymentAddress> KeyIO::DecodePaymentAddress(const std::s
|
|||
str.c_str(),
|
||||
keyConstants.NetworkIDString().c_str(),
|
||||
&ua,
|
||||
AddOrchardReceiver,
|
||||
AddSaplingReceiver,
|
||||
AddP2SHReceiver,
|
||||
AddP2PKHReceiver,
|
||||
|
|
|
@ -403,6 +403,12 @@ std::optional<libzcash::UFVKId> CBasicKeyStore::GetUFVKIdForViewingKey(const lib
|
|||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
||||
FindUFVKId::operator()(const libzcash::OrchardRawAddress& orchardAddr) const {
|
||||
// TODO: Implement once we have Orchard in UFVKs
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
||||
FindUFVKId::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const {
|
||||
const auto saplingIvk = keystore.mapSaplingIncomingViewingKeys.find(saplingAddr);
|
||||
|
|
|
@ -398,6 +398,8 @@ private:
|
|||
public:
|
||||
FindUFVKId(const CBasicKeyStore& keystore): keystore(keystore) {}
|
||||
|
||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
||||
operator()(const libzcash::OrchardRawAddress& orchardAddr) const;
|
||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
||||
operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const;
|
||||
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
#ifndef ZCASH_RUST_INCLUDE_RUST_ADDRESS_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_ADDRESS_H
|
||||
|
||||
#include "rust/orchard/keys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef bool (*orchard_receiver_t)(void* ua, OrchardRawAddressPtr* addr);
|
||||
typedef bool (*raw_to_receiver_t)(void* ua, const unsigned char* raw);
|
||||
typedef bool (*unknown_receiver_t)(
|
||||
void* ua,
|
||||
|
@ -24,6 +27,7 @@ bool zcash_address_parse_unified(
|
|||
const char* str,
|
||||
const char* network,
|
||||
void* ua,
|
||||
orchard_receiver_t orchard_cb,
|
||||
raw_to_receiver_t sapling_cb,
|
||||
raw_to_receiver_t p2sh_cb,
|
||||
raw_to_receiver_t p2pkh_cb,
|
||||
|
|
|
@ -32,6 +32,34 @@ OrchardRawAddressPtr* orchard_address_clone(
|
|||
*/
|
||||
void orchard_address_free(OrchardRawAddressPtr* ptr);
|
||||
|
||||
/**
|
||||
* Parses Orchard raw address bytes from the given stream.
|
||||
*
|
||||
* - If the key does not parse correctly, the returned pointer will be null.
|
||||
*/
|
||||
OrchardRawAddressPtr* orchard_raw_address_parse(
|
||||
void* stream,
|
||||
read_callback_t read_cb);
|
||||
|
||||
|
||||
/**
|
||||
* Serializes Orchard raw address bytes to the given stream.
|
||||
*
|
||||
* This will return `false` and leave the stream unmodified if
|
||||
* `raw_address == nullptr`;
|
||||
*/
|
||||
bool orchard_raw_address_serialize(
|
||||
const OrchardRawAddressPtr* raw_address,
|
||||
void* stream,
|
||||
write_callback_t write_cb);
|
||||
|
||||
/**
|
||||
* Implements the "equal" operation for comparing two Orchard addresses.
|
||||
*/
|
||||
bool orchard_address_eq(
|
||||
const OrchardRawAddressPtr* k0,
|
||||
const OrchardRawAddressPtr* k1);
|
||||
|
||||
/**
|
||||
* Implements the "less than" operation `k0 < k1` for comparing two Orchard
|
||||
* addresses. This is a comparison of the raw bytes, only useful for cases
|
||||
|
|
|
@ -12,6 +12,8 @@ use zcash_address::{
|
|||
use zcash_primitives::sapling;
|
||||
|
||||
pub type UnifiedAddressObj = NonNull<c_void>;
|
||||
pub type AddOrchardReceiverCb =
|
||||
unsafe extern "C" fn(ua: Option<UnifiedAddressObj>, orchard: *const orchard::Address) -> bool;
|
||||
pub type AddReceiverCb =
|
||||
unsafe extern "C" fn(ua: Option<UnifiedAddressObj>, raw: *const u8) -> bool;
|
||||
pub type UnknownReceiverCb = unsafe extern "C" fn(
|
||||
|
@ -53,10 +55,12 @@ impl FromAddress for UnifiedAddressHelper {
|
|||
}
|
||||
|
||||
impl UnifiedAddressHelper {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn into_cpp(
|
||||
self,
|
||||
network: Network,
|
||||
ua_obj: Option<UnifiedAddressObj>,
|
||||
orchard_cb: Option<AddOrchardReceiverCb>,
|
||||
sapling_cb: Option<AddReceiverCb>,
|
||||
p2sh_cb: Option<AddReceiverCb>,
|
||||
p2pkh_cb: Option<AddReceiverCb>,
|
||||
|
@ -79,16 +83,13 @@ impl UnifiedAddressHelper {
|
|||
// ZIP 316: Consumers MUST reject Unified Addresses/Viewing Keys in
|
||||
// which any constituent Item does not meet the validation
|
||||
// requirements of its encoding.
|
||||
if orchard::Address::from_raw_address_bytes(&data)
|
||||
.is_none()
|
||||
.into()
|
||||
{
|
||||
let addr = orchard::Address::from_raw_address_bytes(&data);
|
||||
if addr.is_none().into() {
|
||||
tracing::error!("Unified Address contains invalid Orchard receiver");
|
||||
false
|
||||
} else {
|
||||
unsafe {
|
||||
// TODO: Replace with Orchard support.
|
||||
(unknown_cb.unwrap())(ua_obj, 0x03, data.as_ptr(), data.len())
|
||||
(orchard_cb.unwrap())(ua_obj, Box::into_raw(Box::new(addr.unwrap())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +123,7 @@ pub extern "C" fn zcash_address_parse_unified(
|
|||
encoded: *const c_char,
|
||||
network: *const c_char,
|
||||
ua_obj: Option<UnifiedAddressObj>,
|
||||
orchard_cb: Option<AddOrchardReceiverCb>,
|
||||
sapling_cb: Option<AddReceiverCb>,
|
||||
p2sh_cb: Option<AddReceiverCb>,
|
||||
p2pkh_cb: Option<AddReceiverCb>,
|
||||
|
@ -149,7 +151,9 @@ pub extern "C" fn zcash_address_parse_unified(
|
|||
}
|
||||
};
|
||||
|
||||
ua.into_cpp(network, ua_obj, sapling_cb, p2sh_cb, p2pkh_cb, unknown_cb)
|
||||
ua.into_cpp(
|
||||
network, ua_obj, orchard_cb, sapling_cb, p2sh_cb, p2pkh_cb, unknown_cb,
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -171,14 +175,9 @@ pub extern "C" fn zcash_address_serialize_unified(
|
|||
Ok(
|
||||
match unsafe { (typecode_cb.unwrap())(ua_obj, i) }.try_into()? {
|
||||
unified::Typecode::Orchard => {
|
||||
// TODO: Replace with Orchard support.
|
||||
let data_len = unsafe { (receiver_len_cb.unwrap())(ua_obj, i) };
|
||||
let mut data = vec![0; data_len];
|
||||
unsafe { (receiver_cb.unwrap())(ua_obj, i, data.as_mut_ptr(), data_len) };
|
||||
unified::Receiver::Unknown {
|
||||
typecode: 0x03,
|
||||
data,
|
||||
}
|
||||
let mut data = [0; 43];
|
||||
unsafe { (receiver_cb.unwrap())(ua_obj, i, data.as_mut_ptr(), data.len()) };
|
||||
unified::Receiver::Orchard(data)
|
||||
}
|
||||
unified::Typecode::Sapling => {
|
||||
let mut data = [0; 43];
|
||||
|
|
|
@ -28,6 +28,56 @@ pub extern "C" fn orchard_address_free(addr: *mut Address) {
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_raw_address_parse(
|
||||
stream: Option<StreamObj>,
|
||||
read_cb: Option<ReadCb>,
|
||||
) -> *mut Address {
|
||||
let mut reader = CppStreamReader::from_raw_parts(stream, read_cb.unwrap());
|
||||
|
||||
let mut buf = [0u8; 43];
|
||||
match reader.read_exact(&mut buf) {
|
||||
Err(e) => {
|
||||
error!("Stream failure reading bytes of Orchard raw address: {}", e);
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
Ok(()) => {
|
||||
let read = Address::from_raw_address_bytes(&buf);
|
||||
if read.is_some().into() {
|
||||
Box::into_raw(Box::new(read.unwrap()))
|
||||
} else {
|
||||
error!("Failed to parse Orchard raw address.");
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_raw_address_serialize(
|
||||
key: *const Address,
|
||||
stream: Option<StreamObj>,
|
||||
write_cb: Option<WriteCb>,
|
||||
) -> bool {
|
||||
let key = unsafe { key.as_ref() }.expect("Orchard raw address pointer may not be null.");
|
||||
|
||||
let mut writer = CppStreamWriter::from_raw_parts(stream, write_cb.unwrap());
|
||||
match writer.write_all(&key.to_raw_address_bytes()) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
error!("Stream failure writing Orchard raw address: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_address_eq(a0: *const Address, a1: *const Address) -> bool {
|
||||
let a0 = unsafe { a0.as_ref() };
|
||||
let a1 = unsafe { a1.as_ref() };
|
||||
a0 == a1
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_address_lt(a0: *const Address, a1: *const Address) -> bool {
|
||||
let a0 = unsafe { a0.as_ref() };
|
||||
|
|
|
@ -340,6 +340,9 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
|||
case ReceiverType::Sapling:
|
||||
allowedChangeTypes_.insert(libzcash::ChangeType::Sapling);
|
||||
break;
|
||||
case ReceiverType::Orchard:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6555,6 +6555,10 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedS
|
|||
|
||||
// UFVKForReceiver :: (CWallet&, Receiver) -> std::optional<ZcashdUnifiedFullViewingKey>
|
||||
|
||||
std::optional<libzcash::ZcashdUnifiedFullViewingKey> UFVKForReceiver::operator()(const libzcash::OrchardRawAddress& orchardAddr) const {
|
||||
// TODO: Implement once we have Orchard in UFVKs
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<libzcash::ZcashdUnifiedFullViewingKey> UFVKForReceiver::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const {
|
||||
auto ufvkPair = wallet.GetUFVKMetadataForReceiver(saplingAddr);
|
||||
if (ufvkPair.has_value()) {
|
||||
|
@ -6594,6 +6598,12 @@ std::optional<libzcash::ZcashdUnifiedFullViewingKey> UFVKForReceiver::operator()
|
|||
|
||||
// UnifiedAddressForReceiver :: (CWallet&, Receiver) -> std::optional<UnifiedAddress>
|
||||
|
||||
std::optional<libzcash::UnifiedAddress> UnifiedAddressForReceiver::operator()(
|
||||
const libzcash::OrchardRawAddress& orchardAddr) const {
|
||||
// TODO: Implement once we have Orchard in UFVKs
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::UnifiedAddress> UnifiedAddressForReceiver::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const {
|
||||
auto ufvkPair = wallet.GetUFVKMetadataForReceiver(saplingAddr);
|
||||
if (ufvkPair.has_value()) {
|
||||
|
|
|
@ -1931,6 +1931,7 @@ private:
|
|||
public:
|
||||
UFVKForReceiver(const CWallet& wallet): wallet(wallet) {}
|
||||
|
||||
std::optional<libzcash::ZcashdUnifiedFullViewingKey> operator()(const libzcash::OrchardRawAddress& orchardAddr) const;
|
||||
std::optional<libzcash::ZcashdUnifiedFullViewingKey> operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const;
|
||||
std::optional<libzcash::ZcashdUnifiedFullViewingKey> operator()(const CScriptID& scriptId) const;
|
||||
std::optional<libzcash::ZcashdUnifiedFullViewingKey> operator()(const CKeyID& keyId) const;
|
||||
|
@ -1945,6 +1946,7 @@ private:
|
|||
public:
|
||||
UnifiedAddressForReceiver(const CWallet& wallet): wallet(wallet) {}
|
||||
|
||||
std::optional<libzcash::UnifiedAddress> operator()(const libzcash::OrchardRawAddress& orchardAddr) const;
|
||||
std::optional<libzcash::UnifiedAddress> operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const;
|
||||
std::optional<libzcash::UnifiedAddress> operator()(const CScriptID& scriptId) const;
|
||||
std::optional<libzcash::UnifiedAddress> operator()(const CKeyID& keyId) const;
|
||||
|
|
|
@ -73,12 +73,23 @@ std::optional<SaplingPaymentAddress> UnifiedAddress::GetSaplingReceiver() const
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<OrchardRawAddress> UnifiedAddress::GetOrchardReceiver() const {
|
||||
for (const auto& r : receivers) {
|
||||
if (std::holds_alternative<OrchardRawAddress>(r)) {
|
||||
return std::get<OrchardRawAddress>(r);
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<RecipientAddress> UnifiedAddress::GetPreferredRecipientAddress() const {
|
||||
// Return the first receiver type we recognize; receivers are sorted in
|
||||
// order from most-preferred to least.
|
||||
std::optional<RecipientAddress> result;
|
||||
for (const auto& receiver : *this) {
|
||||
std::visit(match {
|
||||
[&](const OrchardRawAddress& addr) { /* TODO: Return once we enable Orchard as recipient */ },
|
||||
[&](const SaplingPaymentAddress& addr) { result = addr; },
|
||||
[&](const CScriptID& addr) { result = addr; },
|
||||
[&](const CKeyID& addr) { result = addr; },
|
||||
|
@ -94,6 +105,7 @@ std::optional<RecipientAddress> UnifiedAddress::GetPreferredRecipientAddress() c
|
|||
|
||||
bool HasKnownReceiverType(const Receiver& receiver) {
|
||||
return std::visit(match {
|
||||
[](const OrchardRawAddress& addr) { return true; },
|
||||
[](const SaplingPaymentAddress& addr) { return true; },
|
||||
[](const CScriptID& addr) { return true; },
|
||||
[](const CKeyID& addr) { return true; },
|
||||
|
@ -125,6 +137,12 @@ std::pair<std::string, PaymentAddress> AddressInfoFromViewingKey::operator()(con
|
|||
|
||||
} // namespace libzcash
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::OrchardRawAddress &zaddr) const
|
||||
{
|
||||
return static_cast<uint32_t>(libzcash::ReceiverType::Orchard);
|
||||
}
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::SaplingPaymentAddress &zaddr) const
|
||||
{
|
||||
|
|
|
@ -84,6 +84,9 @@ public:
|
|||
std::set<ReceiverType> result;
|
||||
for (const auto& receiver : receivers) {
|
||||
std::visit(match {
|
||||
[&](const libzcash::OrchardRawAddress &zaddr) {
|
||||
result.insert(ReceiverType::Orchard);
|
||||
},
|
||||
[&](const libzcash::SaplingPaymentAddress &zaddr) {
|
||||
result.insert(ReceiverType::Sapling);
|
||||
},
|
||||
|
@ -116,6 +119,8 @@ public:
|
|||
|
||||
std::optional<SaplingPaymentAddress> GetSaplingReceiver() const;
|
||||
|
||||
std::optional<OrchardRawAddress> GetOrchardReceiver() const;
|
||||
|
||||
/**
|
||||
* Return the most-preferred receiver from among the receiver types
|
||||
* that we recognize.
|
||||
|
@ -283,6 +288,7 @@ class TypecodeForReceiver {
|
|||
public:
|
||||
TypecodeForReceiver() {}
|
||||
|
||||
uint32_t operator()(const libzcash::OrchardRawAddress &zaddr) const;
|
||||
uint32_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
uint32_t operator()(const CScriptID &p2sh) const;
|
||||
uint32_t operator()(const CKeyID &p2pkh) const;
|
||||
|
|
|
@ -31,6 +31,10 @@ private:
|
|||
friend class ::OrchardWallet;
|
||||
friend class ::orchard::Builder;
|
||||
public:
|
||||
static OrchardRawAddress KeyIoOnlyFromReceiver(OrchardRawAddressPtr* ptr) {
|
||||
return OrchardRawAddress(ptr);
|
||||
}
|
||||
|
||||
OrchardRawAddress(OrchardRawAddress&& key) : inner(std::move(key.inner)) {}
|
||||
|
||||
OrchardRawAddress(const OrchardRawAddress& key) :
|
||||
|
@ -52,9 +56,38 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator==(const OrchardRawAddress& c1, const OrchardRawAddress& c2) {
|
||||
return orchard_address_eq(c1.inner.get(), c2.inner.get());
|
||||
}
|
||||
|
||||
friend bool operator<(const OrchardRawAddress& c1, const OrchardRawAddress& c2) {
|
||||
return orchard_address_lt(c1.inner.get(), c2.inner.get());
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
RustStream rs(s);
|
||||
if (!orchard_raw_address_serialize(inner.get(), &rs, RustStream<Stream>::write_callback)) {
|
||||
throw std::ios_base::failure("Failed to serialize Orchard raw address to bytes");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s) {
|
||||
RustStream rs(s);
|
||||
OrchardRawAddressPtr* addr = orchard_raw_address_parse(&rs, RustStream<Stream>::read_callback);
|
||||
if (addr == nullptr) {
|
||||
throw std::ios_base::failure("Failed to parse Orchard raw address bytes");
|
||||
}
|
||||
inner.reset(addr);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
static OrchardRawAddress Read(Stream& stream) {
|
||||
OrchardRawAddress key;
|
||||
stream >> key;
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
class OrchardIncomingViewingKey
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "transparent.h"
|
||||
#include "key_constants.h"
|
||||
#include "script/script.h"
|
||||
#include "zcash/address/orchard.hpp"
|
||||
#include "zip32.h"
|
||||
|
||||
#include <variant>
|
||||
|
@ -23,7 +24,7 @@ enum class ReceiverType: uint32_t {
|
|||
P2PKH = 0x00,
|
||||
P2SH = 0x01,
|
||||
Sapling = 0x02,
|
||||
//Orchard = 0x03
|
||||
Orchard = 0x03
|
||||
};
|
||||
|
||||
enum class UnifiedAddressGenerationError {
|
||||
|
@ -113,6 +114,7 @@ public:
|
|||
* variants by `operator<` is equivalent to sorting by preference.
|
||||
*/
|
||||
typedef std::variant<
|
||||
OrchardRawAddress,
|
||||
SaplingPaymentAddress,
|
||||
CScriptID,
|
||||
CKeyID,
|
||||
|
|
Loading…
Reference in New Issue