From 613bcdbed75f16cc791c5199f104fae596e742d5 Mon Sep 17 00:00:00 2001 From: davide3011 Date: Fri, 6 Feb 2026 15:23:23 +0100 Subject: [PATCH] encoding,test: backport BIP350 bech32m and align test vectors to Palladium - use Bech32 for witness v0 and Bech32m for witness v1+ in key_io - update C++ bech32 tests and python segwit_addr framework - realign key/address test vectors and fixtures to Palladium prefixes/params - adjust chain-parameter-sensitive tests (maturity, BIP66/regtest, message verify) - fix incorrect historical sha256 expected vector in unit tests --- src/bech32.cpp | 67 ++++++++++----- src/bech32.h | 15 +++- src/key_io.cpp | 22 +++-- src/test/bech32_tests.cpp | 62 +++++++++++-- src/test/crypto_tests.cpp | 2 +- src/test/data/key_io_invalid.json | 2 +- src/test/data/key_io_valid.json | 86 +++++++++---------- src/test/miner_tests.cpp | 19 ++++ src/test/transaction_tests.cpp | 13 ++- src/test/txvalidationcache_tests.cpp | 36 +++++--- src/test/util_tests.cpp | 48 +++++++---- src/test/validation_block_tests.cpp | 29 ++++++- src/wallet/test/wallet_tests.cpp | 4 +- test/functional/test_framework/segwit_addr.py | 51 +++++++---- 14 files changed, 324 insertions(+), 132 deletions(-) diff --git a/src/bech32.cpp b/src/bech32.cpp index 1e0471f..f316122 100644 --- a/src/bech32.cpp +++ b/src/bech32.cpp @@ -27,6 +27,10 @@ const int8_t CHARSET_REV[128] = { 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 }; +/** Constant to xor into the polymod after appending 6 zeroes. */ +constexpr uint32_t BECH32_CONST = 1; +constexpr uint32_t BECH32M_CONST = 0x2bc830a3; + /** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher * bits correspond to earlier values. */ @@ -110,22 +114,21 @@ data ExpandHRP(const std::string& hrp) return ret; } -/** Verify a checksum. */ -bool VerifyChecksum(const std::string& hrp, const data& values) +/** Verify a checksum and return the encoding type. */ +bech32::Encoding VerifyChecksum(const std::string& hrp, const data& values) { - // PolyMod computes what value to xor into the final values to make the checksum 0. However, - // if we required that the checksum was 0, it would be the case that appending a 0 to a valid - // list of values would result in a new valid list. For that reason, Bech32 requires the - // resulting checksum to be 1 instead. - return PolyMod(Cat(ExpandHRP(hrp), values)) == 1; + const uint32_t check = PolyMod(Cat(ExpandHRP(hrp), values)); + if (check == BECH32_CONST) return bech32::Encoding::BECH32; + if (check == BECH32M_CONST) return bech32::Encoding::BECH32M; + return bech32::Encoding::INVALID; } /** Create a checksum. */ -data CreateChecksum(const std::string& hrp, const data& values) +data CreateChecksum(bech32::Encoding encoding, const std::string& hrp, const data& values) { data enc = Cat(ExpandHRP(hrp), values); enc.resize(enc.size() + 6); // Append 6 zeroes - uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes. + uint32_t mod = PolyMod(enc) ^ (encoding == bech32::Encoding::BECH32 ? BECH32_CONST : BECH32M_CONST); data ret(6); for (size_t i = 0; i < 6; ++i) { // Convert the 5-bit groups in mod to checksum values. @@ -139,13 +142,14 @@ data CreateChecksum(const std::string& hrp, const data& values) namespace bech32 { -/** Encode a Bech32 string. */ -std::string Encode(const std::string& hrp, const data& values) { +/** Encode a Bech32 or Bech32m string. */ +std::string Encode(Encoding encoding, const std::string& hrp, const data& values) { + assert(encoding == Encoding::BECH32 || encoding == Encoding::BECH32M); // First ensure that the HRP is all lowercase. BIP-173 requires an encoder // to return a lowercase Bech32 string, but if given an uppercase HRP, the // result will always be invalid. for (const char& c : hrp) assert(c < 'A' || c > 'Z'); - data checksum = CreateChecksum(hrp, values); + data checksum = CreateChecksum(encoding, hrp, values); data combined = Cat(values, checksum); std::string ret = hrp + '1'; ret.reserve(ret.size() + combined.size()); @@ -155,19 +159,28 @@ std::string Encode(const std::string& hrp, const data& values) { return ret; } -/** Decode a Bech32 string. */ -std::pair Decode(const std::string& str) { +/** Encode a Bech32 string. */ +std::string Encode(const std::string& hrp, const data& values) +{ + return Encode(Encoding::BECH32, hrp, values); +} + +/** Decode a Bech32 or Bech32m string. */ +Encoding Decode(const std::string& str, std::string& out_hrp, std::vector& out_values) +{ + out_hrp.clear(); + out_values.clear(); bool lower = false, upper = false; for (size_t i = 0; i < str.size(); ++i) { unsigned char c = str[i]; if (c >= 'a' && c <= 'z') lower = true; else if (c >= 'A' && c <= 'Z') upper = true; - else if (c < 33 || c > 126) return {}; + else if (c < 33 || c > 126) return Encoding::INVALID; } - if (lower && upper) return {}; + if (lower && upper) return Encoding::INVALID; size_t pos = str.rfind('1'); if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) { - return {}; + return Encoding::INVALID; } data values(str.size() - 1 - pos); for (size_t i = 0; i < str.size() - 1 - pos; ++i) { @@ -175,7 +188,7 @@ std::pair Decode(const std::string& str) { int8_t rev = CHARSET_REV[c]; if (rev == -1) { - return {}; + return Encoding::INVALID; } values[i] = rev; } @@ -183,10 +196,24 @@ std::pair Decode(const std::string& str) { for (size_t i = 0; i < pos; ++i) { hrp += LowerCase(str[i]); } - if (!VerifyChecksum(hrp, values)) { + Encoding result = VerifyChecksum(hrp, values); + if (result == Encoding::INVALID) { + return result; + } + out_hrp = hrp; + out_values = data(values.begin(), values.end() - 6); + return result; +} + +/** Decode a Bech32 or Bech32m string. */ +std::pair Decode(const std::string& str) +{ + std::string hrp; + std::vector values; + if (Decode(str, hrp, values) == Encoding::INVALID) { return {}; } - return {hrp, data(values.begin(), values.end() - 6)}; + return {hrp, values}; } } // namespace bech32 diff --git a/src/bech32.h b/src/bech32.h index b6a2765..7dc90e4 100644 --- a/src/bech32.h +++ b/src/bech32.h @@ -19,12 +19,25 @@ namespace bech32 { -/** Encode a Bech32 string. If hrp contains uppercase characters, this will cause an assertion error. */ +/** The Bech32 and Bech32m checksum encodings. */ +enum class Encoding { + INVALID, + BECH32, + BECH32M, +}; + +/** Encode a Bech32 or Bech32m string. If hrp contains uppercase characters, this will cause an assertion error. */ +std::string Encode(Encoding encoding, const std::string& hrp, const std::vector& values); + +/** Legacy Bech32-only encoder for callers that don't pass an encoding type. */ std::string Encode(const std::string& hrp, const std::vector& values); /** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */ std::pair> Decode(const std::string& str); +/** Decode a Bech32 or Bech32m string, returning the checksum encoding used. */ +Encoding Decode(const std::string& str, std::string& out_hrp, std::vector& out_values); + } // namespace bech32 #endif // PALLADIUM_BECH32_H diff --git a/src/key_io.cpp b/src/key_io.cpp index 33c3ba0..cf6f65c 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -44,7 +44,7 @@ public: std::vector data = {0}; data.reserve(33); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end()); - return bech32::Encode(m_params.Bech32HRP(), data); + return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data); } std::string operator()(const WitnessV0ScriptHash& id) const @@ -52,7 +52,7 @@ public: std::vector data = {0}; data.reserve(53); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end()); - return bech32::Encode(m_params.Bech32HRP(), data); + return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data); } std::string operator()(const WitnessUnknown& id) const @@ -63,7 +63,7 @@ public: std::vector data = {(unsigned char)id.version}; data.reserve(1 + (id.length * 8 + 4) / 5); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.program, id.program + id.length); - return bech32::Encode(m_params.Bech32HRP(), data); + return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data); } std::string operator()(const CNoDestination& no) const { return {}; } @@ -91,13 +91,19 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par } } data.clear(); - auto bech = bech32::Decode(str); - if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) { + std::string bech_hrp; + std::vector bech_data; + const bech32::Encoding bech_encoding = bech32::Decode(str, bech_hrp, bech_data); + if (!bech_data.empty() && bech_hrp == params.Bech32HRP()) { // Bech32 decoding - int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16) + int version = bech_data[0]; // The first 5 bit symbol is the witness version (0-16) + if ((version == 0 && bech_encoding != bech32::Encoding::BECH32) || + (version > 0 && bech_encoding != bech32::Encoding::BECH32M)) { + return CNoDestination(); + } // The rest of the symbols are converted witness program bytes. - data.reserve(((bech.second.size() - 1) * 5) / 8); - if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin() + 1, bech.second.end())) { + data.reserve(((bech_data.size() - 1) * 5) / 8); + if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech_data.begin() + 1, bech_data.end())) { if (version == 0) { { WitnessV0KeyHash keyid; diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp index a2098f4..c3de0d0 100644 --- a/src/test/bech32_tests.cpp +++ b/src/test/bech32_tests.cpp @@ -22,9 +22,35 @@ BOOST_AUTO_TEST_CASE(bip173_testvectors_valid) "?1ezyfcl", }; for (const std::string& str : CASES) { - auto ret = bech32::Decode(str); - BOOST_CHECK(!ret.first.empty()); - std::string recode = bech32::Encode(ret.first, ret.second); + std::string hrp; + std::vector data; + bech32::Encoding encoding = bech32::Decode(str, hrp, data); + BOOST_CHECK(encoding == bech32::Encoding::BECH32); + BOOST_CHECK(!hrp.empty()); + std::string recode = bech32::Encode(encoding, hrp, data); + BOOST_CHECK(!recode.empty()); + BOOST_CHECK(CaseInsensitiveEqual(str, recode)); + } +} + +BOOST_AUTO_TEST_CASE(bip350_testvectors_valid) +{ + static const std::string CASES[] = { + "A1LQFN3A", + "a1lqfn3a", + "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", + "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", + "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", + "split1checkupstagehandshakeupstreamerranterredcaperredlc445v", + "?1v759aa", + }; + for (const std::string& str : CASES) { + std::string hrp; + std::vector data; + bech32::Encoding encoding = bech32::Decode(str, hrp, data); + BOOST_CHECK(encoding == bech32::Encoding::BECH32M); + BOOST_CHECK(!hrp.empty()); + std::string recode = bech32::Encode(encoding, hrp, data); BOOST_CHECK(!recode.empty()); BOOST_CHECK(CaseInsensitiveEqual(str, recode)); } @@ -47,11 +73,37 @@ BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid) "1qzzfhee", "a12UEL5L", "A12uEL5L", + " 1xj0phk", + "\x7f""1g6xzxy", + "\x80""1vctc34", + "an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", + "qyrz8wqd2c9m", + "1qyrz8wqd2c9m", + "y1b0jsk6g", + "lt1igcx5c0", + "in1muywd", + "mm1crxm3i", + "au1s5cgom", + "M1VUXWEZ", + "16plkw9", + "1p2gdwpf", }; for (const std::string& str : CASES) { - auto ret = bech32::Decode(str); - BOOST_CHECK(ret.first.empty()); + std::string hrp; + std::vector data; + bech32::Encoding encoding = bech32::Decode(str, hrp, data); + BOOST_CHECK(encoding == bech32::Encoding::INVALID); + BOOST_CHECK(hrp.empty()); + BOOST_CHECK(data.empty()); } } +BOOST_AUTO_TEST_CASE(checksum_type_detection) +{ + std::string hrp; + std::vector data; + BOOST_CHECK(bech32::Decode("a12uel5l", hrp, data) == bech32::Encoding::BECH32); + BOOST_CHECK(bech32::Decode("a1lqfn3a", hrp, data) == bech32::Encoding::BECH32M); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 4aa1b0a..703c3bf 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(sha256_testvectors) { TestSHA256("This is exactly 64 bytes long, not counting the terminating byte", "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8"); TestSHA256("As Palladium relies on 80 byte header hashes, we want to have an example for that.", - "7406e8de7d6e4fffc573daef05aefb8806e7790f55eab5576f31349743cca743"); + "74f5aabfc4547ee11fc7f4da9a75746b16c2829bf48d9f4806ab30d55b3cb7c4"); TestSHA256(std::string(1000000, 'a'), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); TestSHA256(test1, "a316d55510b49662420f49d145d42fb83f31ef8dc016aa4e32df049991a91e26"); diff --git a/src/test/data/key_io_invalid.json b/src/test/data/key_io_invalid.json index 9b52943..d7370fc 100644 --- a/src/test/data/key_io_invalid.json +++ b/src/test/data/key_io_invalid.json @@ -39,7 +39,7 @@ "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk" ], [ - "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs" + "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGt" ], [ "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo" diff --git a/src/test/data/key_io_valid.json b/src/test/data/key_io_valid.json index 8418a60..e5adbe4 100644 --- a/src/test/data/key_io_valid.json +++ b/src/test/data/key_io_valid.json @@ -1,6 +1,6 @@ [ [ - "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", + "PHrYiyUQTSekTWvVBNMEnSzV1DCB9TGR2P", "76a91465a16059864a2fdbc7c99a4723a8395bc6f188eb88ac", { "isPrivkey": false, @@ -16,7 +16,7 @@ } ], [ - "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "tEZSNGVUiXapct4zsnZcfz9CfqKhmUqguv", "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", { "isPrivkey": false, @@ -24,7 +24,7 @@ } ], [ - "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "tEZSNGVUiXapct4zsnZcfz9CfqKhmUqguv", "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", { "isPrivkey": false, @@ -32,7 +32,7 @@ } ], [ - "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", + "oRvMM9SjaZ8LpnNkN7R8MLj5ZtADdTxKan", "a9146349a418fc4578d10a372b54b45c280cc8c4382f87", { "isPrivkey": false, @@ -58,7 +58,7 @@ } ], [ - "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "9Z6xf1m6f6BryV7psTW7CQrdy9TEd3W5L3J68G33orABc1co6yT", "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", { "isCompressed": false, @@ -67,7 +67,7 @@ } ], [ - "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "9Z6xf1m6f6BryV7psTW7CQrdy9TEd3W5L3J68G33orABc1co6yT", "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", { "isCompressed": false, @@ -76,7 +76,7 @@ } ], [ - "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "eq6GD8VN8AqozEzwX5Y7LZjkEAt76XeSCCuM9Vm3pLTWVhumBKBp", "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3", { "isCompressed": true, @@ -85,7 +85,7 @@ } ], [ - "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "eq6GD8VN8AqozEzwX5Y7LZjkEAt76XeSCCuM9Vm3pLTWVhumBKBp", "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3", { "isCompressed": true, @@ -94,7 +94,7 @@ } ], [ - "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", + "PJYEqYHSAbeurs8VH1yGEBX9z7WLA3GVdM", "76a9146d23156cbbdcc82a5a47eee4c2c7c583c18b6bf488ac", { "isPrivkey": false, @@ -110,7 +110,7 @@ } ], [ - "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", + "tUyHPhkxH3xAt3EWTAWAN6btewJ4um5SJE", "76a914f1d470f9b02370fdec2e6b708b08ac431bf7a5f788ac", { "isPrivkey": false, @@ -118,7 +118,7 @@ } ], [ - "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", + "oasWYfcYrxaJKoaFcEcT3GWjymSjtrdZqs", "a914c579342c2c4c9220205e2cdc285617040c924a0a87", { "isPrivkey": false, @@ -144,7 +144,7 @@ } ], [ - "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", + "9aKQ9gS4aFBj6N6KjJbC7NysTpxkJ8NPJFUP2B4bxAh49UFthb8", "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", { "isCompressed": false, @@ -153,7 +153,7 @@ } ], [ - "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", + "epVaUU7fJ1AesUoJ1U44ENkPVh8mB2AxHRYVzfrUKTQpuTuovfiC", "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9", { "isCompressed": true, @@ -162,7 +162,7 @@ } ], [ - "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", + "PKfmbhQZHBxsRJGm545nn6kGjyYJ2g9DxL", "76a9147987ccaa53d02c8873487ef919677cd3db7a691288ac", { "isPrivkey": false, @@ -178,7 +178,7 @@ } ], [ - "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", + "tUkS4FySxH9hnqjFXY2ExZDki8ZnQUNcqN", "76a914ef66444b5b17f14e8fae6e7e19b045a78c54fd7988ac", { "isPrivkey": false, @@ -186,7 +186,7 @@ } ], [ - "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", + "oajAn6cQKAdV7aPtj94kxjLry86vNcYxpt", "a914c3e55fceceaa4391ed2a9677f4a4d34eacd021a087", { "isPrivkey": false, @@ -212,7 +212,7 @@ } ], [ - "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", + "9ZD7cBvzEPhB3MEqSmi1zFs27j1gn3omKn9aixdNsfHD6GgFQ68", "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", { "isCompressed": false, @@ -221,7 +221,7 @@ } ], [ - "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", + "eqtkLwC8WsKKfpaHqcZ2tQXf47GkUefi3q9HJ8CWhBKHxnmaBr1Q", "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69", { "isCompressed": true, @@ -230,7 +230,7 @@ } ], [ - "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", + "PQRvDSJxCJdCBSgCoVCzikymhmGzR4MF1N", "76a914adc1cc2081a27206fae25792f28bbc55b831549d88ac", { "isPrivkey": false, @@ -246,7 +246,7 @@ } ], [ - "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", + "t8z1Mviz3y2rchHxr7RLNVwuxjTBoBZsrQ", "76a9141694f5bc1a7295b600f40018a618a6ea48eeb49888ac", { "isPrivkey": false, @@ -254,7 +254,7 @@ } ], [ - "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", + "oNJY5isNx5y5ZTCjALpSL52d5SxJix375T", "a9143b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f387", { "isPrivkey": false, @@ -280,7 +280,7 @@ } ], [ - "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "9a4A4dpXBxBkiDMHpgLRNKZb6QzEg1MEbAEP5AjdGVSmAHgaNsV", "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", { "isCompressed": false, @@ -289,7 +289,7 @@ } ], [ - "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "9a4A4dpXBxBkiDMHpgLRNKZb6QzEg1MEbAEP5AjdGVSmAHgaNsV", "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", { "isCompressed": false, @@ -298,7 +298,7 @@ } ], [ - "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", + "erdBEUPwhUCWdQ6fePHZY5yCyzhctxGCczeECcSu2XN7Ea8XrAKq", "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef", { "isCompressed": true, @@ -307,7 +307,7 @@ } ], [ - "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", + "PSXXf9tBweL5rTGLmMuEjioZRVs8LFM2Qj", "76a914c4c1b72491ede1eedaca00618407ee0b772cad0d88ac", { "isPrivkey": false, @@ -323,7 +323,7 @@ } ], [ - "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", + "tAQBUeP8n6HFwedagC5Jbf1jtmGwJmFYjV", "76a914261f83568a098a8638844bd7aeca039d5f2352c088ac", { "isPrivkey": false, @@ -331,7 +331,7 @@ } ], [ - "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", + "oe8NEVNc2U2ba1uPXcCJXkKdMyLJzVtkb5", "a914e930e1834a4d234702773951d627cce82fbb5d2e87", { "isPrivkey": false, @@ -357,7 +357,7 @@ } ], [ - "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", + "9YiNKBoCcSfbiTyrfekeGoWiiu6mUJtNMHKbgbAZPrf7QuKF4Ad", "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", { "isCompressed": false, @@ -366,7 +366,7 @@ } ], [ - "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", + "en9up2mGUoJutYPKkMF8uW2cBRGoKAniuwcbkHzFPd7o7J2ce3Vf", "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de", { "isCompressed": true, @@ -375,7 +375,7 @@ } ], [ - "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", + "PHDnjvCAfV7bxskqrtr32bVN1wehX3qSQz", "76a9145eadaf9bb7121f0f192561a5a62f5e5f5421029288ac", { "isPrivkey": false, @@ -391,7 +391,7 @@ } ], [ - "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", + "tRDVNRKL1bKgwp2B9YxwMpSjhhkaeDuYKS", "76a914c8a3c2a09a298592c3e180f02487cd91ba3400b588ac", { "isPrivkey": false, @@ -399,7 +399,7 @@ } ], [ - "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", + "oWt4C7LaHqesy9LqBaAWg2jArVUZ6ZB9fQ", "a91499b31df7c9068d1481b596578ddbb4d3bd90baeb87", { "isPrivkey": false, @@ -425,7 +425,7 @@ } ], [ - "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", + "9aU2vvHRbF1d6fE7K2kywFqeRVFtBC15YWwEK34AF7f2VcrVEnq", "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", { "isCompressed": false, @@ -434,7 +434,7 @@ } ], [ - "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", + "ejEd4TD7W3BGjE2au6hCeG8MDMVKSuevd1CuvFQdyuJxuVmoodkQ", "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c", { "isCompressed": true, @@ -443,7 +443,7 @@ } ], [ - "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", + "PBQBshjnviLotpWNozd4RizS4Nhij9ekdv", "76a9141ed467017f043e91ed4c44b4e8dd674db211c4e688ac", { "isPrivkey": false, @@ -459,7 +459,7 @@ } ], [ - "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", + "plm1qw508d6qejxtdg4y5r3zarvary0c5xw7kxmmspk", "0014751e76e8199196d454941c45d1b3a323f1433bd6", { "isPrivkey": false, @@ -468,7 +468,7 @@ } ], [ - "bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080", + "rplm1qw508d6qejxtdg4y5r3zarvary0c5xw7k59erzz", "0014751e76e8199196d454941c45d1b3a323f1433bd6", { "isPrivkey": false, @@ -477,7 +477,7 @@ } ], [ - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", + "tplm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q57antz", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262", { "isPrivkey": false, @@ -486,7 +486,7 @@ } ], [ - "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", + "plm1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kwp46x6", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", { "isPrivkey": false, @@ -495,7 +495,7 @@ } ], [ - "bc1sw50qa3jx3s", + "plm1sw50qgf7s5k", "6002751e", { "isPrivkey": false, @@ -504,7 +504,7 @@ } ], [ - "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", + "plm1zw508d6qejxtdg4y5r3zarvaryvf9mh4q", "5210751e76e8199196d454941c45d1b3a323", { "isPrivkey": false, @@ -513,7 +513,7 @@ } ], [ - "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", + "tplm1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsescg4a2c", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", { "isPrivkey": false, @@ -522,7 +522,7 @@ } ], [ - "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7", + "rplm1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesz3f90s", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", { "isPrivkey": false, diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 8539812..dde0490 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -257,6 +257,25 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashPrevBlock = pblock->GetHash(); } + // Palladium uses a higher coinbase maturity than Bitcoin test vectors. + // Advance the active chain with dummy block indices so the imported coinbase + // outputs referenced later in this test are spendable. + { + LOCK(cs_main); + const int spend_height = baseheight + COINBASE_MATURITY + 3; + while (::ChainActive().Tip()->nHeight < spend_height) { + CBlockIndex* prev = ::ChainActive().Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(InsecureRand256()); + next->nTime = prev->nTime + 1; + ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + ::ChainActive().SetTip(next); + } + } + LOCK(cs_main); LOCK(m_node.mempool->cs); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 0774f0b..ba37cfc 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -717,13 +718,21 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); BOOST_CHECK_EQUAL(reason, "scriptpubkey"); + auto build_op_return_script = [](size_t target_size) { + for (size_t data_len = 0; data_len <= target_size; ++data_len) { + CScript script = CScript() << OP_RETURN << std::vector(data_len, 0x42); + if (script.size() == target_size) return script; + } + throw std::runtime_error("Unable to build OP_RETURN script of requested size"); + }; + // MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[0].scriptPubKey = build_op_return_script(MAX_OP_RETURN_RELAY); BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); // MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); + t.vout[0].scriptPubKey = build_op_return_script(MAX_OP_RETURN_RELAY + 1); BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); reason.clear(); BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 4bb34f2..9cd84b9 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -218,11 +218,21 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) ValidateCheckInputsForAllFlags(CTransaction(spend_tx), SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false); } - // And if we produce a block with this tx, it should be valid (DERSIG not - // enabled yet), even though there's no cache entry. + // And if we produce a block with this tx, it should be valid according to + // current consensus rules, even though there's no cache entry. + CMutableTransaction spend_tx_for_block = spend_tx; + { + spend_tx_for_block.vin[0].scriptSig = CScript(); + std::vector vchSig; + uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx_for_block, 0, SIGHASH_ALL, 0, SigVersion::BASE); + BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); + vchSig.push_back((unsigned char)SIGHASH_ALL); + spend_tx_for_block.vin[0].scriptSig << vchSig; + } + CBlock block; - block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); + block = CreateAndProcessBlock({spend_tx_for_block}, p2pk_scriptPubKey); LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(::ChainstateActive().CoinsTip().GetBestBlock() == block.GetHash()); @@ -233,7 +243,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) CMutableTransaction invalid_under_p2sh_tx; invalid_under_p2sh_tx.nVersion = 1; invalid_under_p2sh_tx.vin.resize(1); - invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx.GetHash(); + invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx_for_block.GetHash(); invalid_under_p2sh_tx.vin[0].prevout.n = 0; invalid_under_p2sh_tx.vout.resize(1); invalid_under_p2sh_tx.vout[0].nValue = 11*CENT; @@ -250,7 +260,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) invalid_with_cltv_tx.nVersion = 1; invalid_with_cltv_tx.nLockTime = 100; invalid_with_cltv_tx.vin.resize(1); - invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx.GetHash(); + invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx_for_block.GetHash(); invalid_with_cltv_tx.vin[0].prevout.n = 2; invalid_with_cltv_tx.vin[0].nSequence = 0; invalid_with_cltv_tx.vout.resize(1); @@ -259,7 +269,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(spend_tx_for_block.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; @@ -278,7 +288,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) CMutableTransaction invalid_with_csv_tx; invalid_with_csv_tx.nVersion = 2; invalid_with_csv_tx.vin.resize(1); - invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetHash(); + invalid_with_csv_tx.vin[0].prevout.hash = spend_tx_for_block.GetHash(); invalid_with_csv_tx.vin[0].prevout.n = 3; invalid_with_csv_tx.vin[0].nSequence = 100; invalid_with_csv_tx.vout.resize(1); @@ -287,7 +297,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(spend_tx_for_block.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; @@ -309,7 +319,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) CMutableTransaction valid_with_witness_tx; valid_with_witness_tx.nVersion = 1; valid_with_witness_tx.vin.resize(1); - valid_with_witness_tx.vin[0].prevout.hash = spend_tx.GetHash(); + valid_with_witness_tx.vin[0].prevout.hash = spend_tx_for_block.GetHash(); valid_with_witness_tx.vin[0].prevout.n = 1; valid_with_witness_tx.vout.resize(1); valid_with_witness_tx.vout[0].nValue = 11*CENT; @@ -317,7 +327,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign SignatureData sigdata; - BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(&valid_with_witness_tx, 0, 11*CENT, SIGHASH_ALL), spend_tx.vout[1].scriptPubKey, sigdata)); + BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(&valid_with_witness_tx, 0, 11*CENT, SIGHASH_ALL), spend_tx_for_block.vout[1].scriptPubKey, sigdata)); UpdateInput(valid_with_witness_tx.vin[0], sigdata); // This should be valid under all script flags. @@ -334,9 +344,9 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) tx.nVersion = 1; tx.vin.resize(2); - tx.vin[0].prevout.hash = spend_tx.GetHash(); + tx.vin[0].prevout.hash = spend_tx_for_block.GetHash(); tx.vin[0].prevout.n = 0; - tx.vin[1].prevout.hash = spend_tx.GetHash(); + tx.vin[1].prevout.hash = spend_tx_for_block.GetHash(); tx.vin[1].prevout.n = 1; tx.vout.resize(1); tx.vout[0].nValue = 22*CENT; @@ -345,7 +355,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign for (int i=0; i<2; ++i) { SignatureData sigdata; - BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(&tx, i, 11*CENT, SIGHASH_ALL), spend_tx.vout[i].scriptPubKey, sigdata)); + BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(&tx, i, 11*CENT, SIGHASH_ALL), spend_tx_for_block.vout[i].scriptPubKey, sigdata)); UpdateInput(tx.vin[i], sigdata); } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index d04a9d1..77780aa 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -7,7 +7,10 @@ #include #include // For Hash() #include // For CKey +#include #include +#include