Add CashAddr Address Format
Ported from Bitcoin Unlimited, Bitcoin ABC
This commit is contained in:
@@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
|
||||
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
|
||||
std::vector<unsigned char> result;
|
||||
CBitcoinSecret secret;
|
||||
CBitcoinAddress addr;
|
||||
CTxDestination destination;
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
|
||||
for (unsigned int idx = 0; idx < tests.size(); idx++) {
|
||||
@@ -155,18 +155,20 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
|
||||
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
|
||||
|
||||
// Private key must be invalid public key
|
||||
addr.SetString(exp_base58string);
|
||||
BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
|
||||
destination = DecodeLegacyAddr(exp_base58string, Params());
|
||||
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
|
||||
// "script" or "pubkey"
|
||||
std::string exp_addrType = find_value(metadata, "addrType").get_str();
|
||||
// Must be valid public key
|
||||
BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
|
||||
BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
|
||||
BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
|
||||
CTxDestination dest = addr.Get();
|
||||
BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
|
||||
destination = DecodeLegacyAddr(exp_base58string, Params());
|
||||
BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
|
||||
BOOST_CHECK_MESSAGE((boost::get<CScriptID>(&destination) != nullptr) == (exp_addrType == "script"),
|
||||
"isScript mismatch" + strTest);
|
||||
BOOST_CHECK_MESSAGE(
|
||||
boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), destination), "addrType mismatch" + strTest);
|
||||
|
||||
// Public key must be invalid private key
|
||||
secret.SetString(exp_base58string);
|
||||
@@ -229,17 +231,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
|
||||
BOOST_ERROR("Bad addrtype: " << strTest);
|
||||
continue;
|
||||
}
|
||||
CBitcoinAddress addrOut;
|
||||
BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
|
||||
BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
|
||||
std::string address = EncodeLegacyAddr(dest, Params());
|
||||
BOOST_CHECK_MESSAGE(address == exp_base58string, "mismatch: " + strTest);
|
||||
}
|
||||
}
|
||||
|
||||
// Visiting a CNoDestination must fail
|
||||
CBitcoinAddress dummyAddr;
|
||||
CTxDestination nodest = CNoDestination();
|
||||
BOOST_CHECK(!dummyAddr.Set(nodest));
|
||||
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
}
|
||||
|
||||
@@ -249,7 +245,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
|
||||
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
|
||||
std::vector<unsigned char> result;
|
||||
CBitcoinSecret secret;
|
||||
CBitcoinAddress addr;
|
||||
CTxDestination destination;
|
||||
|
||||
for (unsigned int idx = 0; idx < tests.size(); idx++) {
|
||||
UniValue test = tests[idx];
|
||||
@@ -262,8 +258,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
|
||||
std::string exp_base58string = test[0].get_str();
|
||||
|
||||
// must be invalid as public and as private key
|
||||
addr.SetString(exp_base58string);
|
||||
BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
|
||||
destination = DecodeLegacyAddr(exp_base58string, Params());
|
||||
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
|
||||
secret.SetString(exp_base58string);
|
||||
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
|
||||
}
|
||||
|
||||
115
src/test/cashaddr_tests.cpp
Normal file
115
src/test/cashaddr_tests.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2017 Pieter Wuille
|
||||
// Copyright (c) 2017 The Bitcoin developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "cashaddr.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
static std::pair<std::string, std::vector<uint8_t> > CashAddrDecode(const std::string &str)
|
||||
{
|
||||
return cashaddr::Decode(str, "");
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(cashaddr_tests, BasicTestingSetup)
|
||||
|
||||
bool CaseInsensitiveEqual(const std::string &s1, const std::string &s2)
|
||||
{
|
||||
if (s1.size() != s2.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < s1.size(); ++i)
|
||||
{
|
||||
char c1 = s1[i];
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
{
|
||||
c1 -= ('A' - 'a');
|
||||
}
|
||||
char c2 = s2[i];
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
{
|
||||
c2 -= ('A' - 'a');
|
||||
}
|
||||
if (c1 != c2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cashaddr_testvectors_valid)
|
||||
{
|
||||
static const std::string CASES[] = {
|
||||
"prefix:x64nx6hz", "PREFIX:X64NX6HZ", "p:gpf8m4h7", "blackcoin:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn",
|
||||
"bchtest:testnetaddress4d6njnut", "bchreg:555555555555555555555555555555555555555555555udxmlmrz",
|
||||
};
|
||||
|
||||
for (const std::string &str : CASES)
|
||||
{
|
||||
auto ret = CashAddrDecode(str);
|
||||
BOOST_CHECK_MESSAGE(!ret.first.empty(), str);
|
||||
std::string recode = cashaddr::Encode(ret.first, ret.second);
|
||||
BOOST_CHECK_MESSAGE(!recode.empty(), str);
|
||||
BOOST_CHECK_MESSAGE(CaseInsensitiveEqual(str, recode), str);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cashaddr_testvectors_invalid)
|
||||
{
|
||||
static const std::string CASES[] = {
|
||||
"prefix:x32nx6hz", "prEfix:x64nx6hz", "prefix:x64nx6Hz", "pref1x:6m8cxv73", "prefix:", ":u9wsx07j",
|
||||
"bchreg:555555555555555555x55555555555555555555555555udxmlmrz",
|
||||
"bchreg:555555555555555555555555555555551555555555555udxmlmrz", "pre:fix:x32nx6hz", "prefixx64nx6hz",
|
||||
};
|
||||
|
||||
for (const std::string &str : CASES)
|
||||
{
|
||||
auto ret = CashAddrDecode(str);
|
||||
BOOST_CHECK_MESSAGE(ret.first.empty(), str);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cashaddr_rawencode)
|
||||
{
|
||||
typedef std::pair<std::string, std::vector<uint8_t> > raw;
|
||||
|
||||
raw toEncode;
|
||||
toEncode.first = "helloworld";
|
||||
toEncode.second = {0x1f, 0x0d};
|
||||
|
||||
std::string encoded = cashaddr::Encode(toEncode.first, toEncode.second);
|
||||
raw decoded = CashAddrDecode(encoded);
|
||||
|
||||
BOOST_CHECK_EQUAL(toEncode.first, decoded.first);
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
begin(toEncode.second), end(toEncode.second), begin(decoded.second), end(decoded.second));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cashaddr_testvectors_noprefix)
|
||||
{
|
||||
static const std::pair<std::string, std::string> CASES[] = {
|
||||
{"blackcoin", "qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn"}, {"prefix", "x64nx6hz"}, {"PREFIX", "X64NX6HZ"},
|
||||
{"p", "gpf8m4h7"}, {"blackcoin", "qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn"},
|
||||
{"blktest", "testnetaddress4d6njnut"}, {"blkreg", "555555555555555555555555555555555555555555555udxmlmrz"},
|
||||
};
|
||||
|
||||
for (const std::pair<std::string, std::string> &c : CASES)
|
||||
{
|
||||
std::string prefix = c.first;
|
||||
std::string payload = c.second;
|
||||
std::string addr = prefix + ":" + payload;
|
||||
auto ret = cashaddr::Decode(payload, prefix);
|
||||
BOOST_CHECK_MESSAGE(CaseInsensitiveEqual(ret.first, prefix), addr);
|
||||
std::string recode = cashaddr::Encode(ret.first, ret.second);
|
||||
BOOST_CHECK_MESSAGE(!recode.empty(), addr);
|
||||
BOOST_CHECK_MESSAGE(CaseInsensitiveEqual(addr, recode), addr);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
311
src/test/cashaddrenc_tests.cpp
Normal file
311
src/test/cashaddrenc_tests.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// Copyright (c) 2017 The Bitcoin developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "cashaddr.h"
|
||||
#include "cashaddrenc.h"
|
||||
#include "chainparams.h"
|
||||
#include "random.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<std::string> GetNetworks()
|
||||
{
|
||||
return {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST};
|
||||
}
|
||||
|
||||
uint160 insecure_GetRandUInt160(FastRandomContext &rand)
|
||||
{
|
||||
uint160 n;
|
||||
for (uint8_t *c = n.begin(); c != n.end(); ++c)
|
||||
{
|
||||
*c = static_cast<uint8_t>(rand.rand32());
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> insecure_GetRandomByteArray(FastRandomContext &rand, size_t n)
|
||||
{
|
||||
std::vector<uint8_t> out;
|
||||
out.reserve(n);
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
out.push_back(uint8_t(rand.randbits(8)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
class DstTypeChecker : public boost::static_visitor<void>
|
||||
{
|
||||
public:
|
||||
void operator()(const CKeyID &id) { isKey = true; }
|
||||
void operator()(const CScriptID &id) { isScript = true; }
|
||||
void operator()(const CNoDestination &) {}
|
||||
static bool IsScriptDst(const CTxDestination &d)
|
||||
{
|
||||
DstTypeChecker checker;
|
||||
boost::apply_visitor(checker, d);
|
||||
return checker.isScript;
|
||||
}
|
||||
|
||||
static bool IsKeyDst(const CTxDestination &d)
|
||||
{
|
||||
DstTypeChecker checker;
|
||||
boost::apply_visitor(checker, d);
|
||||
return checker.isKey;
|
||||
}
|
||||
|
||||
private:
|
||||
DstTypeChecker() : isKey(false), isScript(false) {}
|
||||
bool isKey;
|
||||
bool isScript;
|
||||
};
|
||||
|
||||
// Map all possible size bits in the version to the expected size of the
|
||||
// hash in bytes.
|
||||
const std::array<std::pair<uint8_t, uint32_t>, 8> valid_sizes = {
|
||||
{{0, 20}, {1, 24}, {2, 28}, {3, 32}, {4, 40}, {5, 48}, {6, 56}, {7, 64}}};
|
||||
|
||||
} // anon ns
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(cashaddrenc_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(encode_decode_all_sizes)
|
||||
{
|
||||
FastRandomContext rand(true);
|
||||
const CChainParams ¶ms = Params(CBaseChainParams::MAIN);
|
||||
|
||||
for (auto ps : valid_sizes)
|
||||
{
|
||||
std::vector<uint8_t> data = insecure_GetRandomByteArray(rand, ps.second);
|
||||
CashAddrContent content = {PUBKEY_TYPE, data};
|
||||
std::vector<uint8_t> packed_data = PackCashAddrContent(content);
|
||||
|
||||
// Check that the packed size is correct
|
||||
BOOST_CHECK_EQUAL(packed_data[1] >> 2, ps.first);
|
||||
std::string address = cashaddr::Encode(params.CashAddrPrefix(), packed_data);
|
||||
|
||||
// Check that the address decodes properly
|
||||
CashAddrContent decoded = DecodeCashAddrContent(address, params);
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
std::begin(content.hash), std::end(content.hash), std::begin(decoded.hash), std::end(decoded.hash));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(check_packaddr_throws)
|
||||
{
|
||||
FastRandomContext rand(true);
|
||||
|
||||
for (auto ps : valid_sizes)
|
||||
{
|
||||
std::vector<uint8_t> data = insecure_GetRandomByteArray(rand, ps.second - 1);
|
||||
CashAddrContent content = {PUBKEY_TYPE, data};
|
||||
BOOST_CHECK_THROW(PackCashAddrContent(content), std::runtime_error);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(encode_decode)
|
||||
{
|
||||
std::vector<CTxDestination> toTest = {
|
||||
CNoDestination{}, CKeyID(uint160S("badf00d")), CScriptID(uint160S("f00dbad"))};
|
||||
|
||||
for (auto dst : toTest)
|
||||
{
|
||||
for (auto net : GetNetworks())
|
||||
{
|
||||
std::string encoded = EncodeCashAddr(dst, Params(net));
|
||||
CTxDestination decoded = DecodeCashAddr(encoded, Params(net));
|
||||
BOOST_CHECK(dst == decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that an encoded cash address is not valid on another network.
|
||||
BOOST_AUTO_TEST_CASE(invalid_on_wrong_network)
|
||||
{
|
||||
const CTxDestination dst = CKeyID(uint160S("c0ffee"));
|
||||
const CTxDestination invalidDst = CNoDestination{};
|
||||
|
||||
for (auto net : GetNetworks())
|
||||
{
|
||||
for (auto otherNet : GetNetworks())
|
||||
{
|
||||
if (net == otherNet)
|
||||
continue;
|
||||
|
||||
std::string encoded = EncodeCashAddr(dst, Params(net));
|
||||
CTxDestination decoded = DecodeCashAddr(encoded, Params(otherNet));
|
||||
BOOST_CHECK(decoded != dst);
|
||||
BOOST_CHECK(decoded == invalidDst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(random_dst)
|
||||
{
|
||||
FastRandomContext rand(true);
|
||||
|
||||
const size_t NUM_TESTS = 5000;
|
||||
const CChainParams ¶ms = Params(CBaseChainParams::MAIN);
|
||||
|
||||
for (size_t i = 0; i < NUM_TESTS; ++i)
|
||||
{
|
||||
uint160 hash = insecure_GetRandUInt160(rand);
|
||||
const CTxDestination dst_key = CKeyID(hash);
|
||||
const CTxDestination dst_scr = CScriptID(hash);
|
||||
|
||||
const std::string encoded_key = EncodeCashAddr(dst_key, params);
|
||||
const CTxDestination decoded_key = DecodeCashAddr(encoded_key, params);
|
||||
|
||||
const std::string encoded_scr = EncodeCashAddr(dst_scr, params);
|
||||
const CTxDestination decoded_scr = DecodeCashAddr(encoded_scr, params);
|
||||
|
||||
std::string err("cashaddr failed for hash: ");
|
||||
err += hash.ToString();
|
||||
|
||||
BOOST_CHECK_MESSAGE(dst_key == decoded_key, err);
|
||||
BOOST_CHECK_MESSAGE(dst_scr == decoded_scr, err);
|
||||
|
||||
BOOST_CHECK_MESSAGE(DstTypeChecker::IsKeyDst(decoded_key), err);
|
||||
BOOST_CHECK_MESSAGE(DstTypeChecker::IsScriptDst(decoded_scr), err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cashaddr payload made of 5-bit nibbles. The last one is padded. When
|
||||
* converting back to bytes, this extra padding is truncated. In order to ensure
|
||||
* cashaddr are cannonicals, we check that the data we truncate is zeroed.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(check_padding)
|
||||
{
|
||||
uint8_t version = 0;
|
||||
std::vector<uint8_t> data = {version};
|
||||
for (size_t i = 0; i < 33; ++i)
|
||||
{
|
||||
data.push_back(1);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(data.size(), 34UL);
|
||||
|
||||
const CTxDestination nodst = CNoDestination{};
|
||||
const CChainParams params = Params(CBaseChainParams::MAIN);
|
||||
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
{
|
||||
data[data.size() - 1] = i;
|
||||
std::string fake = cashaddr::Encode(params.CashAddrPrefix(), data);
|
||||
CTxDestination dst = DecodeCashAddr(fake, params);
|
||||
|
||||
// We have 168 bits of payload encoded as 170 bits in 5 bits nimbles. As
|
||||
// a result, we must have 2 zeros.
|
||||
if (i & 0x03)
|
||||
{
|
||||
BOOST_CHECK(dst == nodst);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(dst != nodst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We ensure type is extracted properly from the version.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(check_type)
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(34);
|
||||
|
||||
const CChainParams params = Params(CBaseChainParams::MAIN);
|
||||
|
||||
for (uint8_t v = 0; v < 16; v++)
|
||||
{
|
||||
std::fill(begin(data), end(data), 0);
|
||||
data[0] = v;
|
||||
auto content = DecodeCashAddrContent(cashaddr::Encode(params.CashAddrPrefix(), data), params);
|
||||
BOOST_CHECK_EQUAL(content.type, v);
|
||||
BOOST_CHECK_EQUAL(content.hash.size(), 20UL);
|
||||
|
||||
// Check that using the reserved bit result in a failure.
|
||||
data[0] |= 0x10;
|
||||
content = DecodeCashAddrContent(cashaddr::Encode(params.CashAddrPrefix(), data), params);
|
||||
BOOST_CHECK_EQUAL(content.type, 0);
|
||||
BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We ensure size is extracted and checked properly.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(check_size)
|
||||
{
|
||||
const CTxDestination nodst = CNoDestination{};
|
||||
const CChainParams params = Params(CBaseChainParams::MAIN);
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
for (auto ps : valid_sizes)
|
||||
{
|
||||
// Number of bytes required for a 5-bit packed version of a hash, with
|
||||
// version byte. Add half a byte(4) so integer math provides the next
|
||||
// multiple-of-5 that would fit all the data.
|
||||
size_t expectedSize = (8 * (1 + ps.second) + 4) / 5;
|
||||
data.resize(expectedSize);
|
||||
std::fill(begin(data), end(data), 0);
|
||||
// After conversion from 8 bit packing to 5 bit packing, the size will
|
||||
// be in the second 5-bit group, shifted left twice.
|
||||
data[1] = ps.first << 2;
|
||||
|
||||
auto content = DecodeCashAddrContent(cashaddr::Encode(params.CashAddrPrefix(), data), params);
|
||||
|
||||
BOOST_CHECK_EQUAL(content.type, 0);
|
||||
BOOST_CHECK_EQUAL(content.hash.size(), ps.second);
|
||||
|
||||
data.push_back(0);
|
||||
content = DecodeCashAddrContent(cashaddr::Encode(params.CashAddrPrefix(), data), params);
|
||||
|
||||
BOOST_CHECK_EQUAL(content.type, 0);
|
||||
BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
|
||||
|
||||
data.pop_back();
|
||||
data.pop_back();
|
||||
content = DecodeCashAddrContent(cashaddr::Encode(params.CashAddrPrefix(), data), params);
|
||||
|
||||
BOOST_CHECK_EQUAL(content.type, 0);
|
||||
BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_addresses)
|
||||
{
|
||||
const CChainParams params = Params(CBaseChainParams::MAIN);
|
||||
|
||||
std::vector<std::vector<uint8_t> > hash{
|
||||
{118, 160, 64, 83, 189, 160, 168, 139, 218, 81, 119, 184, 106, 21, 195, 178, 159, 85, 152, 115},
|
||||
{203, 72, 18, 50, 41, 156, 213, 116, 49, 81, 172, 75, 45, 99, 174, 25, 142, 123, 176, 169},
|
||||
{1, 31, 40, 228, 115, 201, 95, 64, 19, 215, 213, 62, 197, 251, 195, 180, 45, 248, 237, 16}};
|
||||
|
||||
std::vector<std::string> pubkey = {"blackcoin:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a",
|
||||
"blackcoin:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy",
|
||||
"blackcoin:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"};
|
||||
std::vector<std::string> script = {"blackcoin:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq",
|
||||
"blackcoin:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e",
|
||||
"blackcoin:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"};
|
||||
|
||||
for (size_t i = 0; i < hash.size(); ++i)
|
||||
{
|
||||
const CTxDestination dstKey = CKeyID(uint160(hash[i]));
|
||||
BOOST_CHECK_EQUAL(pubkey[i], EncodeCashAddr(dstKey, params));
|
||||
|
||||
const CTxDestination dstScript = CScriptID(uint160(hash[i]));
|
||||
BOOST_CHECK_EQUAL(script[i], EncodeCashAddr(dstScript, params));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
69
src/test/dstencode_tests.cpp
Normal file
69
src/test/dstencode_tests.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2017 The Bitcoin developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chainparams.h"
|
||||
#include "config.h"
|
||||
#include "dstencode.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
class DstCfgDummy : public DummyConfig {
|
||||
public:
|
||||
DstCfgDummy() : useCashAddr(false) {}
|
||||
void SetCashAddrEncoding(bool b) override { useCashAddr = b; }
|
||||
bool UseCashAddrEncoding() const override { return useCashAddr; }
|
||||
|
||||
private:
|
||||
bool useCashAddr;
|
||||
};
|
||||
|
||||
} // anon ns
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(dstencode_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_addresses) {
|
||||
std::vector<uint8_t> hash = {118, 160, 64, 83, 189, 160, 168,
|
||||
139, 218, 81, 119, 184, 106, 21,
|
||||
195, 178, 159, 85, 152, 115};
|
||||
|
||||
const CTxDestination dstKey = CKeyID(uint160(hash));
|
||||
const CTxDestination dstScript = CScriptID(uint160(hash));
|
||||
|
||||
std::string cashaddr_pubkey =
|
||||
"blackcoin:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a";
|
||||
std::string cashaddr_script =
|
||||
"blackcoin:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq";
|
||||
std::string base58_pubkey = "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu";
|
||||
std::string base58_script = "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC";
|
||||
|
||||
const CChainParams ¶ms = Params(CBaseChainParams::MAIN);
|
||||
DstCfgDummy cfg;
|
||||
|
||||
// Check encoding
|
||||
cfg.SetCashAddrEncoding(true);
|
||||
BOOST_CHECK_EQUAL(cashaddr_pubkey, EncodeDestination(dstKey, params, cfg));
|
||||
BOOST_CHECK_EQUAL(cashaddr_script,
|
||||
EncodeDestination(dstScript, params, cfg));
|
||||
cfg.SetCashAddrEncoding(false);
|
||||
BOOST_CHECK_EQUAL(base58_pubkey, EncodeDestination(dstKey, params, cfg));
|
||||
BOOST_CHECK_EQUAL(base58_script, EncodeDestination(dstScript, params, cfg));
|
||||
|
||||
// Check decoding
|
||||
BOOST_CHECK(dstKey == DecodeDestination(cashaddr_pubkey, params));
|
||||
BOOST_CHECK(dstScript == DecodeDestination(cashaddr_script, params));
|
||||
BOOST_CHECK(dstKey == DecodeDestination(base58_pubkey, params));
|
||||
BOOST_CHECK(dstScript == DecodeDestination(base58_script, params));
|
||||
|
||||
// Validation
|
||||
BOOST_CHECK(IsValidDestinationString(cashaddr_pubkey, params));
|
||||
BOOST_CHECK(IsValidDestinationString(cashaddr_script, params));
|
||||
BOOST_CHECK(IsValidDestinationString(base58_pubkey, params));
|
||||
BOOST_CHECK(IsValidDestinationString(base58_script, params));
|
||||
BOOST_CHECK(!IsValidDestinationString("notvalid", params));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "key.h"
|
||||
|
||||
#include "base58.h"
|
||||
#include "dstencode.h"
|
||||
#include "script/script.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
@@ -18,18 +19,16 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
|
||||
static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
|
||||
static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
|
||||
static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
|
||||
static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
|
||||
static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
|
||||
static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
|
||||
static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
|
||||
|
||||
|
||||
static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
|
||||
static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
|
||||
static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
|
||||
static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
|
||||
static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
|
||||
static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
|
||||
static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
|
||||
static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
|
||||
static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
|
||||
|
||||
static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
|
||||
|
||||
#ifdef KEY_TESTS_DUMPINFO
|
||||
void dumpKeyInfo(uint256 privkey)
|
||||
@@ -104,10 +103,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
||||
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
|
||||
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
|
||||
|
||||
BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
|
||||
BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
|
||||
BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
|
||||
BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
|
||||
BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
|
||||
BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
|
||||
BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
|
||||
BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
|
||||
|
||||
for (int n=0; n<16; n++)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "base58.h" // Freeze CBitcoinAddress
|
||||
#include "chain.h" // Freeze CBlockIndex
|
||||
#include "dstencode.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "policy/policy.h"
|
||||
@@ -306,5 +309,83 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef ENABLE_WALLET
|
||||
BOOST_AUTO_TEST_CASE(cltv_freeze)
|
||||
{
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 2; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
|
||||
// Create and unpack a CLTV script
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
vector<CTxDestination> addresses;
|
||||
int nRequiredReturn;
|
||||
txnouttype type = TX_CLTV;
|
||||
|
||||
// check cltv solve for block
|
||||
CPubKey newKey1 = ToByteVector(key[0].GetPubKey());
|
||||
CTxDestination newAddr1 = CTxDestination(newKey1.GetID());
|
||||
CScriptNum nFreezeLockTime(50000);
|
||||
CScript s1 = GetScriptForFreeze(nFreezeLockTime, newKey1);
|
||||
|
||||
BOOST_CHECK(Solver(s1, whichType, solutions));
|
||||
BOOST_CHECK(whichType == TX_CLTV);
|
||||
BOOST_CHECK(solutions.size() == 2);
|
||||
BOOST_CHECK(CScriptNum(solutions[0], false) == nFreezeLockTime);
|
||||
|
||||
nRequiredReturn = 0;
|
||||
ExtractDestinations(s1, type, addresses, nRequiredReturn);
|
||||
|
||||
for (const CTxDestination &addr : addresses)
|
||||
BOOST_CHECK(EncodeDestination(newAddr1) == EncodeDestination(addr));
|
||||
BOOST_CHECK(nRequiredReturn == 1);
|
||||
|
||||
|
||||
// check cltv solve for datetime
|
||||
CPubKey newKey2 = ToByteVector(key[0].GetPubKey());
|
||||
CTxDestination newAddr2 = CTxDestination(newKey2.GetID());
|
||||
nFreezeLockTime = CScriptNum(1482255731);
|
||||
CScript s2 = GetScriptForFreeze(nFreezeLockTime, newKey2);
|
||||
|
||||
BOOST_CHECK(Solver(s2, whichType, solutions));
|
||||
BOOST_CHECK(whichType == TX_CLTV);
|
||||
BOOST_CHECK(solutions.size() == 2);
|
||||
BOOST_CHECK(CScriptNum(solutions[0], false) == nFreezeLockTime);
|
||||
|
||||
nRequiredReturn = 0;
|
||||
ExtractDestinations(s2, type, addresses, nRequiredReturn);
|
||||
|
||||
for (const CTxDestination &addr : addresses)
|
||||
BOOST_CHECK(newAddr2 == addr);
|
||||
|
||||
BOOST_CHECK(nRequiredReturn == 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(opreturn_send)
|
||||
{
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 2; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
|
||||
CBasicKeyStore keystore;
|
||||
|
||||
// Create and unpack a CLTV script
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
vector<CTxDestination> addresses;
|
||||
|
||||
string inMsg = "hello world", outMsg = "";
|
||||
CScript s = GetScriptLabelPublic(inMsg);
|
||||
|
||||
outMsg = getLabelPublic(s);
|
||||
BOOST_CHECK(inMsg == outMsg);
|
||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
||||
BOOST_CHECK(whichType == TX_LABELPUBLIC);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -484,4 +484,59 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
|
||||
BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
|
||||
}
|
||||
|
||||
template <int F, int T>
|
||||
static void CheckConvertBits(const std::vector<uint8_t> &in, const std::vector<uint8_t> &expected)
|
||||
{
|
||||
std::vector<uint8_t> outpad;
|
||||
bool ret = ConvertBits<F, T, true>(outpad, in.begin(), in.end());
|
||||
BOOST_CHECK(ret);
|
||||
BOOST_CHECK(outpad == expected);
|
||||
|
||||
const bool dopad = (in.size() * F) % T;
|
||||
std::vector<uint8_t> outnopad;
|
||||
ret = ConvertBits<F, T, false>(outnopad, in.begin(), in.end());
|
||||
BOOST_CHECK(ret != dopad);
|
||||
|
||||
if (dopad)
|
||||
{
|
||||
// We should have skipped the last digit.
|
||||
outnopad.push_back(expected.back());
|
||||
}
|
||||
|
||||
BOOST_CHECK(outnopad == expected);
|
||||
|
||||
// Check the other way around.
|
||||
std::vector<uint8_t> orignopad;
|
||||
ret = ConvertBits<T, F, false>(orignopad, expected.begin(), expected.end());
|
||||
BOOST_CHECK(ret == !((expected.size() * T) % F));
|
||||
BOOST_CHECK(orignopad == in);
|
||||
|
||||
// Check with padding. We may get an extra 0 in that case.
|
||||
std::vector<uint8_t> origpad;
|
||||
ret = ConvertBits<T, F, true>(origpad, expected.begin(), expected.end());
|
||||
BOOST_CHECK(ret);
|
||||
|
||||
if (dopad)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(origpad.back(), 0);
|
||||
origpad.pop_back();
|
||||
}
|
||||
|
||||
BOOST_CHECK(origpad == in);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ConvertBits)
|
||||
{
|
||||
CheckConvertBits<8, 5>({}, {});
|
||||
CheckConvertBits<8, 5>({0xff}, {0x1f, 0x1c});
|
||||
CheckConvertBits<8, 5>({0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x10});
|
||||
CheckConvertBits<8, 5>({0xff, 0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x1f, 0x1e});
|
||||
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x18});
|
||||
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f});
|
||||
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f});
|
||||
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f});
|
||||
CheckConvertBits<8, 5>({0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
|
||||
{0x00, 0x04, 0x11, 0x14, 0x0a, 0x19, 0x1c, 0x09, 0x15, 0x0f, 0x06, 0x1e, 0x1e});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
Reference in New Issue
Block a user