diff --git a/doc/release-notes.md b/doc/release-notes.md
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -5,3 +5,10 @@
This release includes the following features and fixes:
+
+Deprecated features
+-------------------
+
+- `bitcoincash:`, `bchtest:` and `bchreg:` CashAddr prefixes have been
+ deprecated in favor of `ecash:`, `ectest:` and `ecregtest:` and will be
+ removed in a future version.
diff --git a/src/cashaddrenc.cpp b/src/cashaddrenc.cpp
--- a/src/cashaddrenc.cpp
+++ b/src/cashaddrenc.cpp
@@ -101,13 +101,16 @@
CTxDestination DecodeCashAddr(const std::string &addr,
const CChainParams ¶ms) {
- CashAddrContent content =
- DecodeCashAddrContent(addr, params.CashAddrPrefix());
- if (content.hash.size() == 0) {
- return CNoDestination{};
+ const std::array prefixes{
+ {params.CashAddrPrefix(), params.CashAddrLegacyPrefix()}};
+
+ for (const auto &prefix : prefixes) {
+ CashAddrContent content = DecodeCashAddrContent(addr, prefix);
+ if (content.hash.size() != 0) {
+ return DecodeCashAddrDestination(content);
+ }
}
-
- return DecodeCashAddrDestination(content);
+ return CNoDestination{};
}
CashAddrContent DecodeCashAddrContent(const std::string &addr,
diff --git a/src/chainparams.h b/src/chainparams.h
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -90,6 +90,9 @@
return base58Prefixes[type];
}
const std::string &CashAddrPrefix() const { return cashaddrPrefix; }
+ const std::string &CashAddrLegacyPrefix() const {
+ return cashaddrLegacyPrefix;
+ }
const std::vector &FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData &Checkpoints() const { return checkpointData; }
const ChainTxData &TxData() const { return chainTxData; }
@@ -107,6 +110,7 @@
std::vector vSeeds;
std::vector base58Prefixes[MAX_BASE58_TYPES];
std::string cashaddrPrefix;
+ std::string cashaddrLegacyPrefix;
std::string strNetworkID;
CBlock genesis;
std::vector vFixedSeeds;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -201,6 +201,7 @@
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
cashaddrPrefix = "ecash";
+ cashaddrLegacyPrefix = "bitcoincash";
vFixedSeeds = std::vector(
pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
@@ -345,6 +346,7 @@
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
cashaddrPrefix = "ectest";
+ cashaddrLegacyPrefix = "bchtest";
vFixedSeeds = std::vector(
pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
@@ -474,6 +476,7 @@
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
cashaddrPrefix = "ecregtest";
+ cashaddrLegacyPrefix = "bchreg";
}
};
diff --git a/src/qt/test/bitcoinaddressvalidatortests.cpp b/src/qt/test/bitcoinaddressvalidatortests.cpp
--- a/src/qt/test/bitcoinaddressvalidatortests.cpp
+++ b/src/qt/test/bitcoinaddressvalidatortests.cpp
@@ -25,26 +25,39 @@
// anyway.
in = "ICASH";
QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
+ // invalid base58 because of I
+ in = "BIIC";
+ QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
// invalid base58, invalid cashaddr, currently considered valid anyway.
in = "EOASH";
QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
+ in = "BITCOINCASHH";
+ QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
// invalid base58 because of I, but could be a cashaddr prefix
in = "ECASI";
QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
+ in = "BITC";
+ QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
// invalid base58, valid cashaddr
in = "ECASH:OP";
QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
+ in = "BITCOINCASH:QP";
+ QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
// invalid base58, valid cashaddr, lower case
in = "ecash:op";
QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
+ in = "bitcoincash:qp";
+ QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
// invalid base58, valid cashaddr, mixed case
in = "eCash:Op";
QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
+ in = "bItCoInCaSh:Qp";
+ QVERIFY(v.validate(in, unused) == QValidator::Acceptable);
// valid base58, invalid cash
in = "EEEEEEEEEEEEEE";
diff --git a/src/qt/test/guiutiltests.cpp b/src/qt/test/guiutiltests.cpp
--- a/src/qt/test/guiutiltests.cpp
+++ b/src/qt/test/guiutiltests.cpp
@@ -44,6 +44,8 @@
QString cashaddr_pubkey =
"ecash:qpm2qsznhks23z7629mms6s4cwef74vcwva87rkuu2";
+ QString backwards_compatible_cashaddr_pubkey =
+ "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a";
QString base58_pubkey = "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu";
@@ -51,4 +53,10 @@
cashaddr_pubkey);
QVERIFY(GUIUtil::convertToCashAddr(params, base58_pubkey) ==
cashaddr_pubkey);
+ QVERIFY(GUIUtil::convertToCashAddr(params,
+ backwards_compatible_cashaddr_pubkey) ==
+ cashaddr_pubkey);
+ QVERIFY(GUIUtil::convertToCashAddr(params,
+ backwards_compatible_cashaddr_pubkey) ==
+ GUIUtil::convertToCashAddr(params, base58_pubkey));
}
diff --git a/src/test/cashaddrenc_tests.cpp b/src/test/cashaddrenc_tests.cpp
--- a/src/test/cashaddrenc_tests.cpp
+++ b/src/test/cashaddrenc_tests.cpp
@@ -226,39 +226,43 @@
*/
BOOST_AUTO_TEST_CASE(check_size) {
const CTxDestination nodst = CNoDestination{};
- const std::string prefix = "ecash";
+ const auto prefixes = {"bitcoincash", "ecash"};
std::vector 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(prefix, data), prefix);
-
- BOOST_CHECK_EQUAL(content.type, 0);
- BOOST_CHECK_EQUAL(content.hash.size(), ps.second);
-
- data.push_back(0);
- content = DecodeCashAddrContent(cashaddr::Encode(prefix, data), prefix);
-
- BOOST_CHECK_EQUAL(content.type, 0);
- BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
-
- data.pop_back();
- data.pop_back();
- content = DecodeCashAddrContent(cashaddr::Encode(prefix, data), prefix);
-
- BOOST_CHECK_EQUAL(content.type, 0);
- BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
+ for (const auto &prefix : prefixes) {
+ 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(prefix, data), prefix);
+
+ BOOST_CHECK_EQUAL(content.type, 0);
+ BOOST_CHECK_EQUAL(content.hash.size(), ps.second);
+
+ data.push_back(0);
+ content =
+ DecodeCashAddrContent(cashaddr::Encode(prefix, data), prefix);
+
+ BOOST_CHECK_EQUAL(content.type, 0);
+ BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
+
+ data.pop_back();
+ data.pop_back();
+ content =
+ DecodeCashAddrContent(cashaddr::Encode(prefix, data), prefix);
+
+ BOOST_CHECK_EQUAL(content.type, 0);
+ BOOST_CHECK_EQUAL(content.hash.size(), 0UL);
+ }
}
}
@@ -295,6 +299,24 @@
CashAddrContent scriptContent{SCRIPT_TYPE, hash[i]};
BOOST_CHECK_EQUAL(script[i], EncodeCashAddr("ecash", scriptContent));
}
+
+ std::vector backward_compat_pubkey = {
+ "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a",
+ "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy",
+ "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"};
+ std::vector backward_compat_script = {
+ "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq",
+ "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e",
+ "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"};
+ for (size_t i = 0; i < hash.size(); ++i) {
+ CashAddrContent keyContent{PUBKEY_TYPE, hash[i]};
+ BOOST_CHECK_EQUAL(backward_compat_pubkey[i],
+ EncodeCashAddr("bitcoincash", keyContent));
+
+ CashAddrContent scriptContent{SCRIPT_TYPE, hash[i]};
+ BOOST_CHECK_EQUAL(backward_compat_script[i],
+ EncodeCashAddr("bitcoincash", scriptContent));
+ }
}
struct CashAddrTestVector {
diff --git a/test/functional/abc_feature_minerfund.py b/test/functional/abc_feature_minerfund.py
--- a/test/functional/abc_feature_minerfund.py
+++ b/test/functional/abc_feature_minerfund.py
@@ -20,6 +20,7 @@
MINER_FUND_RATIO = 8
+LEGACY_MINER_FUND_ADDR = 'bchreg:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdgd35g0pkl'
MINER_FUND_ADDR = 'ecregtest:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdgz0wv9ltl'
@@ -32,6 +33,24 @@
'-axionactivationtime={}'.format(AXION_ACTIVATION_TIME),
]]
+ def test_validate_address_backwards_compatibility(self):
+ self.log.info(
+ "Testing CashAddr old prefix backward compatibility using the miner fund destination")
+
+ assert(self.nodes[0].validateaddress(MINER_FUND_ADDR)['isvalid'])
+ self.log.info("Address {} is valid".format(MINER_FUND_ADDR))
+
+ assert(self.nodes[0].validateaddress(
+ LEGACY_MINER_FUND_ADDR)['isvalid'])
+ self.log.info("Address {} is valid".format(LEGACY_MINER_FUND_ADDR))
+
+ minerFundScriptPubKey = self.nodes[0].validateaddress(MINER_FUND_ADDR)[
+ 'scriptPubKey']
+ assert_equal(minerFundScriptPubKey, self.nodes[0].validateaddress(
+ LEGACY_MINER_FUND_ADDR)['scriptPubKey'])
+ self.log.info("Both addresses {} and {} share the {} scriptPubKey".format(
+ MINER_FUND_ADDR, LEGACY_MINER_FUND_ADDR, minerFundScriptPubKey))
+
def run_test(self):
node = self.nodes[0]
address = node.get_deterministic_priv_key().address
@@ -91,6 +110,8 @@
assert_equal(node.submitblock(ToHex(block)), 'bad-cb-minerfund')
+ self.test_validate_address_backwards_compatibility()
+
if __name__ == '__main__':
MinerFundTest().main()