Skip to content

Commit

Permalink
Auto merge of zcash#5252 - str4d:ua-encoding, r=str4d
Browse files Browse the repository at this point in the history
Unified Address encoding and decoding

Closes zcash#5133.
  • Loading branch information
zkbot committed Jul 30, 2021
2 parents 81da4f9 + 037bfa3 commit 82a50f6
Show file tree
Hide file tree
Showing 23 changed files with 1,037 additions and 62 deletions.
36 changes: 31 additions & 5 deletions Cargo.lock

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

10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ rand_core = "0.6"
tracing = "0.1"
tracing-core = "0.1"
tracing-appender = "0.1"
zcash_address = "0.0"
zcash_history = "0.2"
zcash_note_encryption = "0.0"
zcash_primitives = "0.5"
Expand Down Expand Up @@ -66,7 +67,8 @@ ed25519-zebra = { git = "https://github.com/ZcashFoundation/ed25519-zebra.git",
halo2 = { git = "https://github.com/zcash/halo2.git", rev = "d04b532368d05b505e622f8cac4c0693574fbd93" }
incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "8b59049f1746827ffa3763efa8af948f680491d0" }
orchard = { git = "https://github.com/zcash/orchard.git", rev = "74df35ce890726478983fb892ff38a5e44ceb08a" }
zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "3cab105c9c3bf4ba31f779095d939ad0c7057539" }
zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "3cab105c9c3bf4ba31f779095d939ad0c7057539" }
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "3cab105c9c3bf4ba31f779095d939ad0c7057539" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "3cab105c9c3bf4ba31f779095d939ad0c7057539" }
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" }
zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" }
zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" }
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" }
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ JSON_TEST_FILES = \
test/data/merkle_path_sapling.json \
test/data/merkle_commitments_sapling.json \
test/data/sapling_key_components.json \
test/data/unified_addrs.json \
test/data/zip0244.json

RAW_TEST_FILES = test/data/alertTests.raw
Expand Down
6 changes: 3 additions & 3 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const arith_uint256 maxUint = UintToArith256(uint256S("fffffffffffffffffffffffff
class CMainParams : public CChainParams {
public:
CMainParams() {
strNetworkID = "main";
keyConstants.strNetworkID = "main";
strCurrencyUnits = "ZEC";
bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
consensus.fCoinbaseMustBeShielded = true;
Expand Down Expand Up @@ -368,7 +368,7 @@ static CMainParams mainParams;
class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
keyConstants.strNetworkID = "test";
strCurrencyUnits = "TAZ";
bip44CoinType = 1;
consensus.fCoinbaseMustBeShielded = true;
Expand Down Expand Up @@ -620,7 +620,7 @@ static CTestNetParams testNetParams;
class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
keyConstants.strNetworkID = "regtest";
strCurrencyUnits = "REG";
bip44CoinType = 1;
consensus.fCoinbaseMustBeShielded = false;
Expand Down
5 changes: 3 additions & 2 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ struct CCheckpointData {

class CBaseKeyConstants : public KeyConstants {
public:
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; }

std::string strNetworkID;
std::vector<unsigned char> base58Prefixes[KeyConstants::MAX_BASE58_TYPES];
std::string bech32HRPs[KeyConstants::MAX_BECH32_TYPES];
};
Expand Down Expand Up @@ -76,7 +78,7 @@ class CChainParams: public KeyConstants
/** In the future use NetworkIDString() for RPC fields */
bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
/** Return the BIP70 network string (main, test or regtest) */
std::string NetworkIDString() const { return strNetworkID; }
std::string NetworkIDString() const { return keyConstants.NetworkIDString(); }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const {
return keyConstants.Base58Prefix(type);
Expand All @@ -103,7 +105,6 @@ class CChainParams: public KeyConstants
uint64_t nPruneAfterHeight = 0;
std::vector<CDNSSeedData> vSeeds;
CBaseKeyConstants keyConstants;
std::string strNetworkID;
std::string strCurrencyUnits;
uint32_t bip44CoinType;
CBlock genesis;
Expand Down
103 changes: 103 additions & 0 deletions src/gtest/test_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include <gtest/gtest.h>

#include "json_test_vectors.h"
#include "test/data/unified_addrs.json.h"

TEST(Keys, EncodeAndDecodeSapling)
{
SelectParams(CBaseChainParams::MAIN);
Expand Down Expand Up @@ -61,3 +64,103 @@ TEST(Keys, EncodeAndDecodeSapling)
}
}
}

#define MAKE_STRING(x) std::string((x), (x) + sizeof(x))

namespace libzcash {
class ReceiverToString {
public:
ReceiverToString() {}

std::string operator()(const SaplingPaymentAddress &zaddr) const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zaddr;
return tfm::format("Sapling(%s)", HexStr(ss.begin(), ss.end()));
}

std::string operator()(const P2SHAddress &p2sh) const {
return tfm::format("P2SH(%s)", p2sh.GetHex());
}

std::string operator()(const P2PKHAddress &p2pkh) const {
return tfm::format("P2PKH(%s)", p2pkh.GetHex());
}

std::string operator()(const UnknownReceiver &unknown) const {
return tfm::format(
"Unknown(%x, %s)",
unknown.typecode,
HexStr(unknown.data.begin(), unknown.data.end()));
}
};

void PrintTo(const Receiver& receiver, std::ostream* os) {
*os << std::visit(ReceiverToString(), receiver);
}
void PrintTo(const UnifiedAddress& ua, std::ostream* os) {
*os << "UnifiedAddress(" << testing::PrintToString(ua.GetReceiversAsParsed()) << ")";
}
}

TEST(Keys, EncodeAndDecodeUnified)
{
SelectParams(CBaseChainParams::MAIN);
KeyIO keyIO(Params());

UniValue ua_tests = read_json(MAKE_STRING(json_tests::unified_addrs));

for (size_t idx = 0; idx < ua_tests.size(); idx++) {
UniValue test = ua_tests[idx];
std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
FAIL() << "Bad test: " << strTest;
continue;
}
if (test.size() == 1) continue; // comment

try {
libzcash::UnifiedAddress ua;
// ["p2pkh_bytes, p2sh_bytes, sapling_raw_addr, orchard_raw_addr, unified_addr"]
// 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);
}
if (!test[2].isNull()) {
auto data = ParseHex(test[2].get_str());
CDataStream ss(
reinterpret_cast<const char*>(data.data()),
reinterpret_cast<const char*>(data.data() + data.size()),
SER_NETWORK,
PROTOCOL_VERSION);
libzcash::SaplingPaymentAddress r;
ss >> r;
ua.AddReceiver(r);
}
if (!test[1].isNull()) {
libzcash::P2SHAddress r(ParseHex(test[1].get_str()));
ua.AddReceiver(r);
}
if (!test[0].isNull()) {
libzcash::P2PKHAddress r(ParseHex(test[0].get_str()));
ua.AddReceiver(r);
}

auto expectedBytes = ParseHex(test[4].get_str());
std::string expected(expectedBytes.begin(), expectedBytes.end());

auto decoded = keyIO.DecodePaymentAddress(expected);
ASSERT_TRUE(std::holds_alternative<libzcash::UnifiedAddress>(decoded));
EXPECT_EQ(std::get<libzcash::UnifiedAddress>(decoded), ua);

auto encoded = keyIO.EncodePaymentAddress(ua);
EXPECT_EQ(encoded, expected);
} catch (const std::exception& ex) {
FAIL() << "Bad test, couldn't deserialize data: " << strTest << ": " << ex.what();
} catch (...) {
FAIL() << "Bad test, couldn't deserialize data: " << strTest;
}
}
}
5 changes: 2 additions & 3 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,10 +1093,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-mineraddress")) {
CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]);
if (!IsValidDestination(addr)) {
// Try a Sapling address
// Try a payment address
auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
if (!IsValidPaymentAddress(zaddr) ||
std::get_if<libzcash::SaplingPaymentAddress>(&zaddr) == nullptr)
if (!std::visit(IsValidMinerAddress(), std::visit(ExtractMinerAddress(), zaddr)))
{
return InitError(strprintf(
_("Invalid address for -mineraddress=<addr>: '%s' (must be a Sapling or transparent address)"),
Expand Down
1 change: 1 addition & 0 deletions src/key_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class KeyConstants
MAX_BECH32_TYPES
};

virtual std::string NetworkIDString() const =0;
virtual const std::vector<unsigned char>& Base58Prefix(Base58Type type) const =0;
virtual const std::string& Bech32HRP(Bech32Type type) const =0;
};
Expand Down
Loading

0 comments on commit 82a50f6

Please sign in to comment.