Implementation of Overwinter transaction format ZIP 202.

This commit is contained in:
Simon
2018-02-15 22:19:36 -08:00
parent d527116d46
commit 072099d788
25 changed files with 1125 additions and 66 deletions

View File

@@ -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()

View File

@@ -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;

View File

@@ -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());