Changeset View
Changeset View
Standalone View
Standalone View
src/test/cashaddrenc_tests.cpp
Show All 20 Lines | |||||
uint160 insecure_GetRandUInt160(FastRandomContext &rand) { | uint160 insecure_GetRandUInt160(FastRandomContext &rand) { | ||||
uint160 n; | uint160 n; | ||||
for (uint8_t *c = n.begin(); c != n.end(); ++c) { | for (uint8_t *c = n.begin(); c != n.end(); ++c) { | ||||
*c = static_cast<uint8_t>(rand.rand32()); | *c = static_cast<uint8_t>(rand.rand32()); | ||||
} | } | ||||
return n; | 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> { | class DstTypeChecker : public boost::static_visitor<void> { | ||||
public: | public: | ||||
void operator()(const CKeyID &id) { isKey = true; } | void operator()(const CKeyID &id) { isKey = true; } | ||||
void operator()(const CScriptID &id) { isScript = true; } | void operator()(const CScriptID &id) { isScript = true; } | ||||
void operator()(const CNoDestination &) {} | void operator()(const CNoDestination &) {} | ||||
static bool IsScriptDst(const CTxDestination &d) { | static bool IsScriptDst(const CTxDestination &d) { | ||||
DstTypeChecker checker; | DstTypeChecker checker; | ||||
boost::apply_visitor(checker, d); | boost::apply_visitor(checker, d); | ||||
return checker.isScript; | return checker.isScript; | ||||
} | } | ||||
static bool IsKeyDst(const CTxDestination &d) { | static bool IsKeyDst(const CTxDestination &d) { | ||||
DstTypeChecker checker; | DstTypeChecker checker; | ||||
boost::apply_visitor(checker, d); | boost::apply_visitor(checker, d); | ||||
return checker.isKey; | return checker.isKey; | ||||
} | } | ||||
private: | private: | ||||
DstTypeChecker() : isKey(false), isScript(false) {} | DstTypeChecker() : isKey(false), isScript(false) {} | ||||
bool isKey; | bool isKey; | ||||
bool isScript; | 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 | } // anon ns | ||||
BOOST_FIXTURE_TEST_SUITE(cashaddrenc_tests, BasicTestingSetup) | 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) { | BOOST_AUTO_TEST_CASE(encode_decode) { | ||||
std::vector<CTxDestination> toTest = {CNoDestination{}, | std::vector<CTxDestination> toTest = {CNoDestination{}, | ||||
CKeyID(uint160S("badf00d")), | CKeyID(uint160S("badf00d")), | ||||
CScriptID(uint160S("f00dbad"))}; | CScriptID(uint160S("f00dbad"))}; | ||||
for (auto dst : toTest) { | for (auto dst : toTest) { | ||||
for (auto net : GetNetworks()) { | for (auto net : GetNetworks()) { | ||||
std::string encoded = EncodeCashAddr(dst, Params(net)); | std::string encoded = EncodeCashAddr(dst, Params(net)); | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
BOOST_AUTO_TEST_CASE(check_padding) { | BOOST_AUTO_TEST_CASE(check_padding) { | ||||
uint8_t version = 0; | uint8_t version = 0; | ||||
std::vector<uint8_t> data = {version}; | std::vector<uint8_t> data = {version}; | ||||
for (size_t i = 0; i < 33; ++i) { | for (size_t i = 0; i < 33; ++i) { | ||||
data.push_back(1); | data.push_back(1); | ||||
} | } | ||||
BOOST_CHECK_EQUAL(data.size(), 34); | BOOST_CHECK_EQUAL(data.size(), 34UL); | ||||
const CTxDestination nodst = CNoDestination{}; | const CTxDestination nodst = CNoDestination{}; | ||||
const CChainParams params = Params(CBaseChainParams::MAIN); | const CChainParams params = Params(CBaseChainParams::MAIN); | ||||
for (uint8_t i = 0; i < 32; i++) { | for (uint8_t i = 0; i < 32; i++) { | ||||
data[data.size() - 1] = i; | data[data.size() - 1] = i; | ||||
std::string fake = cashaddr::Encode(params.CashAddrPrefix(), data); | std::string fake = cashaddr::Encode(params.CashAddrPrefix(), data); | ||||
CTxDestination dst = DecodeCashAddr(fake, params); | CTxDestination dst = DecodeCashAddr(fake, params); | ||||
Show All 18 Lines | BOOST_AUTO_TEST_CASE(check_type) { | ||||
const CChainParams params = Params(CBaseChainParams::MAIN); | const CChainParams params = Params(CBaseChainParams::MAIN); | ||||
for (uint8_t v = 0; v < 16; v++) { | for (uint8_t v = 0; v < 16; v++) { | ||||
std::fill(begin(data), end(data), 0); | std::fill(begin(data), end(data), 0); | ||||
data[0] = v; | data[0] = v; | ||||
auto content = DecodeCashAddrContent( | auto content = DecodeCashAddrContent( | ||||
cashaddr::Encode(params.CashAddrPrefix(), data), params); | cashaddr::Encode(params.CashAddrPrefix(), data), params); | ||||
BOOST_CHECK_EQUAL(content.type, v); | BOOST_CHECK_EQUAL(content.type, v); | ||||
BOOST_CHECK_EQUAL(content.hash.size(), 20); | BOOST_CHECK_EQUAL(content.hash.size(), 20UL); | ||||
// Check that using the reserved bit result in a failure. | // Check that using the reserved bit result in a failure. | ||||
data[0] |= 0x10; | data[0] |= 0x10; | ||||
content = DecodeCashAddrContent( | content = DecodeCashAddrContent( | ||||
cashaddr::Encode(params.CashAddrPrefix(), data), params); | cashaddr::Encode(params.CashAddrPrefix(), data), params); | ||||
BOOST_CHECK_EQUAL(content.type, 0); | BOOST_CHECK_EQUAL(content.type, 0); | ||||
BOOST_CHECK_EQUAL(content.hash.size(), 0); | BOOST_CHECK_EQUAL(content.hash.size(), 0UL); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* We ensure size is extracted and checked properly. | * We ensure size is extracted and checked properly. | ||||
*/ | */ | ||||
BOOST_AUTO_TEST_CASE(check_size) { | BOOST_AUTO_TEST_CASE(check_size) { | ||||
const CTxDestination nodst = CNoDestination{}; | const CTxDestination nodst = CNoDestination{}; | ||||
const CChainParams params = Params(CBaseChainParams::MAIN); | const CChainParams params = Params(CBaseChainParams::MAIN); | ||||
// Mapp all possible size bits in the version to the expected size of the | |||||
// hash in bytes. | |||||
std::vector<std::pair<uint8_t, uint32_t>> sizes = { | |||||
{0, 20}, {1, 24}, {2, 28}, {3, 32}, {4, 40}, {5, 48}, {6, 56}, {7, 64}, | |||||
}; | |||||
std::vector<uint8_t> data; | std::vector<uint8_t> data; | ||||
for (auto ps : sizes) { | for (auto ps : valid_sizes) { | ||||
// Number of bytes required for a 5-bit packed version of a hash, with | // 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 | // version byte. Add half a byte(4) so integer math provides the next | ||||
// multiple-of-5 that would fit all the data. | // multiple-of-5 that would fit all the data. | ||||
size_t expectedSize = (8 * (1 + ps.second) + 4) / 5; | size_t expectedSize = (8 * (1 + ps.second) + 4) / 5; | ||||
data.resize(expectedSize); | data.resize(expectedSize); | ||||
std::fill(begin(data), end(data), 0); | std::fill(begin(data), end(data), 0); | ||||
// After conversion from 8 bit packing to 5 bit packing, the size will | // After conversion from 8 bit packing to 5 bit packing, the size will | ||||
// be in the second 5-bit group, shifted left twice. | // be in the second 5-bit group, shifted left twice. | ||||
data[1] = ps.first << 2; | data[1] = ps.first << 2; | ||||
auto content = DecodeCashAddrContent( | auto content = DecodeCashAddrContent( | ||||
cashaddr::Encode(params.CashAddrPrefix(), data), params); | cashaddr::Encode(params.CashAddrPrefix(), data), params); | ||||
BOOST_CHECK_EQUAL(content.type, 0); | BOOST_CHECK_EQUAL(content.type, 0); | ||||
BOOST_CHECK_EQUAL(content.hash.size(), ps.second); | BOOST_CHECK_EQUAL(content.hash.size(), ps.second); | ||||
data.push_back(0); | data.push_back(0); | ||||
content = DecodeCashAddrContent( | content = DecodeCashAddrContent( | ||||
cashaddr::Encode(params.CashAddrPrefix(), data), params); | cashaddr::Encode(params.CashAddrPrefix(), data), params); | ||||
BOOST_CHECK_EQUAL(content.type, 0); | BOOST_CHECK_EQUAL(content.type, 0); | ||||
BOOST_CHECK_EQUAL(content.hash.size(), 0); | BOOST_CHECK_EQUAL(content.hash.size(), 0UL); | ||||
data.pop_back(); | data.pop_back(); | ||||
data.pop_back(); | data.pop_back(); | ||||
content = DecodeCashAddrContent( | content = DecodeCashAddrContent( | ||||
cashaddr::Encode(params.CashAddrPrefix(), data), params); | cashaddr::Encode(params.CashAddrPrefix(), data), params); | ||||
BOOST_CHECK_EQUAL(content.type, 0); | BOOST_CHECK_EQUAL(content.type, 0); | ||||
BOOST_CHECK_EQUAL(content.hash.size(), 0); | BOOST_CHECK_EQUAL(content.hash.size(), 0UL); | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(test_addresses) { | BOOST_AUTO_TEST_CASE(test_addresses) { | ||||
const CChainParams params = Params(CBaseChainParams::MAIN); | const CChainParams params = Params(CBaseChainParams::MAIN); | ||||
std::vector<std::vector<uint8_t>> hash{ | std::vector<std::vector<uint8_t>> hash{ | ||||
{118, 160, 64, 83, 189, 160, 168, 139, 218, 81, | {118, 160, 64, 83, 189, 160, 168, 139, 218, 81, | ||||
Show All 25 Lines |