Implementation of Overwinter transaction format ZIP 202.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "base58.h"
|
||||
#include "netbase.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
@@ -295,4 +296,44 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
|
||||
BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(rpc_raw_create_overwinter_v3)
|
||||
{
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
|
||||
|
||||
// Sample regtest address:
|
||||
// public: tmHU5HLMu3yS8eoNvbrU1NWeJaGf6jxehru
|
||||
// private: cW1G4SxEm5rui2RQtBcSUZrERTVYPtyZXKbSi5MCwBqzbn5kqwbN
|
||||
|
||||
UniValue r;
|
||||
std::string prevout =
|
||||
"[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
|
||||
"\"vout\":1}]";
|
||||
r = CallRPC(string("createrawtransaction ") + prevout + " " +
|
||||
"{\"tmHU5HLMu3yS8eoNvbrU1NWeJaGf6jxehru\":11}");
|
||||
std::string rawhex = r.get_str();
|
||||
BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ") + rawhex));
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "overwintered").get_bool(), true);
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 3);
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "expiryheight").get_int(), 0);
|
||||
BOOST_CHECK_EQUAL(
|
||||
ParseHexToUInt32(find_value(r.get_obj(), "versiongroupid").get_str()),
|
||||
OVERWINTER_VERSION_GROUP_ID);
|
||||
|
||||
// Sanity check we can deserialize the raw hex
|
||||
// 030000807082c40301f393847c97508f24b772281deea475cd3e0f719f321794e5da7cf8587e28ccb40100000000ffffffff0100ab9041000000001976a914550dc92d3ff8d1f0cb6499fddf2fe43b745330cd88ac000000000000000000
|
||||
CDataStream ss(ParseHex(rawhex), SER_DISK, PROTOCOL_VERSION);
|
||||
CTransaction tx;
|
||||
ss >> tx;
|
||||
CDataStream ss2(ParseHex(rawhex), SER_DISK, PROTOCOL_VERSION);
|
||||
CMutableTransaction mtx;
|
||||
ss2 >> mtx;
|
||||
BOOST_CHECK_EQUAL(tx.GetHash().GetHex(), CTransaction(mtx).GetHash().GetHex());
|
||||
|
||||
// Revert to default
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -908,28 +908,36 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ")
|
||||
+ "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error);
|
||||
|
||||
// Mutable tx containing contextual information we need to build tx
|
||||
UniValue retValue = CallRPC("getblockcount");
|
||||
int nHeight = retValue.get_int();
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
|
||||
if (mtx.nVersion == 1) {
|
||||
mtx.nVersion = 2;
|
||||
}
|
||||
|
||||
// Test constructor of AsyncRPCOperation_sendmany
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany("",{}, {}, -1));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(mtx, "",{}, {}, -1));
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Minconf cannot be negative"));
|
||||
}
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany("",{}, {}, 1));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(mtx, "",{}, {}, 1));
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "From address parameter missing"));
|
||||
}
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ", {}, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ", {}, {}, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "No recipients"));
|
||||
}
|
||||
|
||||
try {
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("INVALID", recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "INVALID", recipients, {}, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "payment address is invalid"));
|
||||
}
|
||||
@@ -937,7 +945,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
|
||||
try {
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U", recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U", recipients, {}, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "payment address is for wrong network type"));
|
||||
}
|
||||
@@ -946,7 +954,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
// invokes a method on pwalletMain, which is undefined in the google test environment.
|
||||
try {
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP", recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP", recipients, {}, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "no spending key found for zaddr"));
|
||||
}
|
||||
@@ -962,6 +970,14 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
|
||||
UniValue retValue;
|
||||
|
||||
// Mutable tx containing contextual information we need to build tx
|
||||
retValue = CallRPC("getblockcount");
|
||||
int nHeight = retValue.get_int();
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
|
||||
if (mtx.nVersion == 1) {
|
||||
mtx.nVersion = 2;
|
||||
}
|
||||
|
||||
// add keys manually
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
||||
std::string taddr1 = retValue.get_str();
|
||||
@@ -971,7 +987,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// there are no utxos to spend
|
||||
{
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1,100.0, "DEADBEEF") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(taddr1, {}, recipients, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, taddr1, {}, recipients, 1) );
|
||||
operation->main();
|
||||
BOOST_CHECK(operation->isFailed());
|
||||
std::string msg = operation->getErrorMessage();
|
||||
@@ -982,7 +998,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
{
|
||||
try {
|
||||
std::vector<SendManyRecipient> recipients = {SendManyRecipient(taddr1, 100.0, "DEADBEEF")};
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(zaddr1, recipients, {}, 0));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 0));
|
||||
BOOST_CHECK(false); // Fail test if an exception is not thrown
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK(find_error(objError, "Minconf cannot be zero when sending from zaddr"));
|
||||
@@ -993,7 +1009,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// there are no unspent notes to spend
|
||||
{
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(taddr1,100.0, "DEADBEEF") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
|
||||
operation->main();
|
||||
BOOST_CHECK(operation->isFailed());
|
||||
std::string msg = operation->getErrorMessage();
|
||||
@@ -1003,7 +1019,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// get_memo_from_hex_string())
|
||||
{
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1,100.0, "DEADBEEF") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
|
||||
|
||||
@@ -1054,7 +1070,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// add_taddr_change_output_to_tx() will append a vout to a raw transaction
|
||||
{
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1,100.0, "DEADBEEF") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
|
||||
|
||||
@@ -1083,7 +1099,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
SendManyRecipient("tmUSbHz3vxnwLvRyNDXbwkZxjVyDodMJEhh",CAmount(4.56), ""),
|
||||
SendManyRecipient("tmYZAXYPCP56Xa5JQWWPZuK7o7bfUQW6kkd",CAmount(7.89), ""),
|
||||
};
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
|
||||
|
||||
@@ -1106,7 +1122,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// we have the spending key for the dummy recipient zaddr1
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 0.0005, "ABCD") };
|
||||
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, {}, recipients, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, {}, recipients, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
|
||||
|
||||
@@ -1131,7 +1147,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// Dummy input so the operation object can be instantiated.
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 0.0005, "ABCD") };
|
||||
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, {}, recipients, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, {}, recipients, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
|
||||
|
||||
@@ -1286,18 +1302,26 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
|
||||
"100 -1"
|
||||
), runtime_error);
|
||||
|
||||
// Mutable tx containing contextual information we need to build tx
|
||||
UniValue retValue = CallRPC("getblockcount");
|
||||
int nHeight = retValue.get_int();
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
|
||||
if (mtx.nVersion == 1) {
|
||||
mtx.nVersion = 2;
|
||||
}
|
||||
|
||||
// Test constructor of AsyncRPCOperation_sendmany
|
||||
std::string testnetzaddr = "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP";
|
||||
std::string mainnetzaddr = "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U";
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase({}, testnetzaddr, -1 ));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(mtx, {}, testnetzaddr, -1 ));
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Fee is out of range"));
|
||||
}
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase({}, testnetzaddr, 1));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(mtx, {}, testnetzaddr, 1));
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "Empty inputs"));
|
||||
}
|
||||
@@ -1305,7 +1329,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
|
||||
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
|
||||
try {
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(inputs, mainnetzaddr, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, mainnetzaddr, 1) );
|
||||
} catch (const UniValue& objError) {
|
||||
BOOST_CHECK( find_error(objError, "payment address is for wrong network type"));
|
||||
}
|
||||
@@ -1320,8 +1344,14 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
||||
|
||||
LOCK(pwalletMain->cs_wallet);
|
||||
|
||||
UniValue retValue;
|
||||
|
||||
// Mutable tx containing contextual information we need to build tx
|
||||
UniValue retValue = CallRPC("getblockcount");
|
||||
int nHeight = retValue.get_int();
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
|
||||
if (mtx.nVersion == 1) {
|
||||
mtx.nVersion = 2;
|
||||
}
|
||||
|
||||
// Test that option -mempooltxinputlimit is respected.
|
||||
mapArgs["-mempooltxinputlimit"] = "1";
|
||||
|
||||
@@ -1332,7 +1362,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
||||
// Supply 2 inputs when mempool limit is 1
|
||||
{
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0}, ShieldCoinbaseUTXO{uint256(),0,0} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(inputs, zaddr) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, zaddr) );
|
||||
operation->main();
|
||||
BOOST_CHECK(operation->isFailed());
|
||||
std::string msg = operation->getErrorMessage();
|
||||
@@ -1342,7 +1372,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
||||
// Insufficient funds
|
||||
{
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(inputs, zaddr) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, zaddr) );
|
||||
operation->main();
|
||||
BOOST_CHECK(operation->isFailed());
|
||||
std::string msg = operation->getErrorMessage();
|
||||
@@ -1353,7 +1383,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
||||
{
|
||||
// Dummy input so the operation object can be instantiated.
|
||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,100000} };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(inputs, zaddr) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, zaddr) );
|
||||
std::shared_ptr<AsyncRPCOperation_shieldcoinbase> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_shieldcoinbase> (operation);
|
||||
TEST_FRIEND_AsyncRPCOperation_shieldcoinbase proxy(ptr);
|
||||
static_cast<AsyncRPCOperation_shieldcoinbase *>(operation.get())->testmode = true;
|
||||
|
||||
@@ -234,7 +234,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
||||
stream >> tx;
|
||||
|
||||
CValidationState state;
|
||||
if (tx.nVersion < MIN_TX_VERSION) {
|
||||
if (tx.nVersion < SPROUT_MIN_TX_VERSION) {
|
||||
// Transaction must be invalid
|
||||
BOOST_CHECK_MESSAGE(!CheckTransactionWithoutProofVerification(tx, state), strTest);
|
||||
BOOST_CHECK(!state.IsValid());
|
||||
|
||||
Reference in New Issue
Block a user