Skip to content

Commit

Permalink
Updated the ticket purchase unit test.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Rusu committed Apr 9, 2020
1 parent 8221dc3 commit 6dd9900
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 122 deletions.
153 changes: 32 additions & 121 deletions src/wallet/test/wallet_tests.cpp
Expand Up @@ -857,105 +857,35 @@ BOOST_FIXTURE_TEST_CASE(ticket_purchase_split_transaction, TicketPurchaseTesting
BOOST_CHECK_LE(feeRate.GetFee(static_cast<size_t>(GetVirtualTransactionSize(*(splitTxFeeRate->tx)))), fee);
}


static void add_spendable_funds(const CAmount& nValue)
{
static int64_t blockTime{100};
SetMockTime(blockTime);

CPubKey pubKey;
CAmount nAbsurdFee;
CValidationState state;

// coinbase

CMutableTransaction ctx;
ctx.nLockTime = 0;
ctx.vin.resize(1);
ctx.vin[0].scriptSig = CScript() << OP_1;
ctx.vin[0].prevout.hash = uint256();
ctx.vin[0].prevout.n = 0;
ctx.vout.resize(1);
ctx.vout[0].nValue = nValue;
pwalletMain->GetKeyFromPool(pubKey, false);
ctx.vout[0].scriptPubKey = GetScriptForDestination(pubKey.GetID());

CWalletTx cwtx(pwalletMain, MakeTransactionRef(ctx));

CBlockIndex* block = nullptr;
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash1 = inserted.first->first;
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash1;
cwtx.SetMerkleBranch(block, 0);
cwtx.hashBlock = hash1;

pwalletMain->AddToWallet(cwtx);

blockTime++;

// non-coinbase

CMutableTransaction tx;
tx.nLockTime = 0;
tx.vin.resize(1);
tx.vin[0].scriptSig = CScript();
tx.vin[0].prevout.hash = ctx.GetHash();
tx.vin[0].prevout.n = 0;
tx.vout.resize(1);
tx.vout[0].nValue = nValue;
pwalletMain->GetKeyFromPool(pubKey, false);
tx.vout[0].scriptPubKey = GetScriptForDestination(pubKey.GetID());

CWalletTx wtx(pwalletMain, MakeTransactionRef(tx));

inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash2 = inserted.first->first;
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash2;
wtx.SetMerkleBranch(block, 0);
wtx.hashBlock = hash2;

TestMemPoolEntryHelper entry;
entry.nFee = 11;
entry.nHeight = 11;
const CAmount ZEROFEE = 0LL;
mempool.addUnchecked(cwtx.GetHash(), entry.Fee(ZEROFEE).FromTx(*wtx.tx));

pwalletMain->AddToWallet(wtx);

blockTime++;
}

static void empty_spendable_funds()
{
pwalletMain->mapWallet.clear();
}

// test the transaction for purchasing tickets
BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)
BOOST_FIXTURE_TEST_CASE(ticket_purchase_transaction, TicketPurchaseTestingSetup)
{
std::vector<std::string> txHashes;
CWalletError we;
const std::string ticketAddress{"PfgnJQeSrEtpAupGtfm5NT4uKQ6v6Yjft3"};
const std::string vspAddress{"PmR5pdoseES3fDgupW52edBPcEHaSSDGbg"};
const CTxDestination ticketAddr = DecodeDestination(ticketAddress);
const CTxDestination vspAddr = DecodeDestination(vspAddress);

CPubKey ticketPubKey;
BOOST_CHECK(wallet->GetKeyFromPool(ticketPubKey));
const CTxDestination ticketKeyId = ticketPubKey.GetID();
const std::string ticketAddress{EncodeDestination(ticketKeyId)};

CPubKey vspPubKey;
BOOST_CHECK(wallet->GetKeyFromPool(vspPubKey));
const CTxDestination vspKeyId = vspPubKey.GetID();
const std::string vspAddress{EncodeDestination(vspKeyId)};

const CAmount spendLimit{100 * COIN};
const CAmount feeRate{1 * COIN};
const double vspFeePercent{5.0};

LOCK2(cs_main, wallet->cs_wallet);

// validate a single ticket, with or without VSP fee
auto checkTicket = [&](uint256 txHash, bool useVsp) {
// Transaction

BOOST_CHECK(txHash != uint256());

const CWalletTx* wtx = pwalletMain->GetWalletTx(txHash);
const CWalletTx* wtx = wallet->GetWalletTx(txHash);
BOOST_CHECK(wtx != nullptr);

BOOST_CHECK(wtx->tx != nullptr);
Expand All @@ -975,13 +905,13 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)

// make sure that the stake address and value are correct
int64_t ticketPrice = CalculateNextRequiredStakeDifficulty(chainActive.Tip(), Params().GetConsensus());
BOOST_CHECK(tx.vout[1].scriptPubKey == GetScriptForDestination(ticketAddr));
BOOST_CHECK(tx.vout[1].scriptPubKey == GetScriptForDestination(ticketKeyId));
BOOST_CHECK_EQUAL(tx.vout[1].nValue, ticketPrice);

// precalculate the necessary values
size_t txSize = GetEstimatedSizeOfBuyTicketTx(useVsp);
CFeeRate txFeeRate{feeRate};
CAmount ticketFee{std::max(txFeeRate.GetFee(txSize), pwalletMain->minTxFee.GetFee(txSize))};
CAmount ticketFee{std::max(txFeeRate.GetFee(txSize), wallet->minTxFee.GetFee(txSize))};
CAmount neededPerTicket = ticketPrice + ticketFee;
CAmount vspFee = (useVsp ? StakePoolTicketFee(ticketPrice, ticketFee, chainActive.Height(), vspFeePercent) : 0);
CAmount forcedChange = std::max(neededPerTicket * 1 / 100, ticketFee); // 1% of needed per ticket, but no less than ticket fee
Expand All @@ -998,10 +928,10 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)
BOOST_CHECK_EQUAL(tcd.voteFees, TicketContribData::NoFees);
BOOST_CHECK_EQUAL(tcd.revokeFees, TicketContribData::NoFees);
BOOST_CHECK_EQUAL(tcd.whichAddr, 1);
BOOST_CHECK(tcd.rewardAddr == boost::get<CKeyID>(vspAddr));
BOOST_CHECK(tcd.rewardAddr == boost::get<CKeyID>(vspKeyId));
BOOST_CHECK_EQUAL(tx.vout[2].nValue, 0);

BOOST_CHECK(tx.vout[3].scriptPubKey == GetScriptForDestination(vspAddr));
BOOST_CHECK(tx.vout[3].scriptPubKey == GetScriptForDestination(vspKeyId));
BOOST_CHECK_EQUAL(tx.vout[3].nValue, forcedChange);
}

Expand All @@ -1015,33 +945,28 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)
BOOST_CHECK_EQUAL(tcd.voteFees, TicketContribData::NoFees);
BOOST_CHECK_EQUAL(tcd.revokeFees, TicketContribData::NoFees);
BOOST_CHECK_EQUAL(tcd.whichAddr, 1);
BOOST_CHECK(pwalletMain->IsMine(CTxOut(0, GetScriptForDestination(CKeyID(uint160(tcd.rewardAddr))))));
BOOST_CHECK(wallet->IsMine(CTxOut(0, GetScriptForDestination(CKeyID(uint160(tcd.rewardAddr))))));
BOOST_CHECK_EQUAL(tx.vout[userOutput].nValue, 0);

BOOST_CHECK(pwalletMain->IsMine(tx.vout[userOutput+1]));
BOOST_CHECK(wallet->IsMine(tx.vout[userOutput+1]));
BOOST_CHECK_EQUAL(tx.vout[userOutput+1].nValue, forcedChange);
};

// Single purchase, no VSP
// Coin availability
{
empty_spendable_funds();

txHashes.clear();

add_spendable_funds(1 * COIN);
std::tie(txHashes, we) = pwalletMain->PurchaseTicket("", spendLimit, 1, ticketAddress, 1, "", 0.0, 0, feeRate);
std::tie(txHashes, we) = wallet->PurchaseTicket("", 100000 * COIN, 1, ticketAddress, 10000, "", 0.0, 0, feeRate);
BOOST_CHECK_EQUAL(we.code, CWalletError::WALLET_INSUFFICIENT_FUNDS);
}

txHashes.clear();

add_spendable_funds(1 * COIN);
std::tie(txHashes, we) = pwalletMain->PurchaseTicket("", spendLimit, 1, ticketAddress, 1, "", 0.0, 0, feeRate);
BOOST_CHECK_EQUAL(we.code, CWalletError::WALLET_INSUFFICIENT_FUNDS);
ExtendChain(Params().GetConsensus().nStakeValidationHeight + 1 - Params().GetConsensus().nTicketMaturity - chainActive.Height());

// Single purchase, no VSP
{
txHashes.clear();

add_spendable_funds(1000000 * COIN);
std::tie(txHashes, we) = pwalletMain->PurchaseTicket("", spendLimit, 1, ticketAddress, 1, "", 0.0, 0, feeRate);
std::tie(txHashes, we) = wallet->PurchaseTicket("", spendLimit, 1, ticketAddress, 1, "", 0.0, 0, feeRate);
BOOST_CHECK_EQUAL(we.code, CWalletError::SUCCESSFUL);

BOOST_CHECK_EQUAL(txHashes.size(), static_cast<size_t>(1));
Expand All @@ -1053,13 +978,9 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)

// Single purchase, with VSP
{
empty_spendable_funds();

txHashes.clear();

add_spendable_funds(1000000 * COIN);
//txHashes.clear();

std::tie(txHashes, we) = pwalletMain->PurchaseTicket("", spendLimit, 1, ticketAddress, 1, vspAddress, vspFeePercent, 0, feeRate);
std::tie(txHashes, we) = wallet->PurchaseTicket("", spendLimit, 1, ticketAddress, 1, vspAddress, vspFeePercent, 0, feeRate);
BOOST_CHECK_EQUAL(we.code, CWalletError::SUCCESSFUL);

BOOST_CHECK_EQUAL(txHashes.size(), static_cast<size_t>(1));
Expand All @@ -1071,15 +992,11 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)

// Multiple purchase, no VSP
{
empty_spendable_funds();

txHashes.clear();

add_spendable_funds(1000000 * COIN);

unsigned int numTickets{10};

std::tie(txHashes, we) = pwalletMain->PurchaseTicket("", spendLimit, 1, ticketAddress, numTickets, "", 0.0, 0, feeRate);
std::tie(txHashes, we) = wallet->PurchaseTicket("", spendLimit, 1, ticketAddress, numTickets, "", 0.0, 0, feeRate);
BOOST_CHECK_EQUAL(we.code, CWalletError::SUCCESSFUL);

BOOST_CHECK_EQUAL(txHashes.size(), static_cast<size_t>(numTickets));
Expand All @@ -1092,15 +1009,11 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)

// Multiple purchase, with VSP
{
empty_spendable_funds();

txHashes.clear();

add_spendable_funds(1000000 * COIN);

unsigned int numTickets{10};

std::tie(txHashes, we) = pwalletMain->PurchaseTicket("", spendLimit, 1, ticketAddress, numTickets, vspAddress, vspFeePercent, 0, feeRate);
std::tie(txHashes, we) = wallet->PurchaseTicket("", spendLimit, 1, ticketAddress, numTickets, vspAddress, vspFeePercent, 0, feeRate);
BOOST_CHECK_EQUAL(we.code, CWalletError::SUCCESSFUL);

BOOST_CHECK_EQUAL(txHashes.size(), static_cast<size_t>(numTickets));
Expand All @@ -1110,8 +1023,6 @@ BOOST_AUTO_TEST_CASE(ticket_purchase_transaction)
checkTicket(txHash, true);
}
}

empty_spendable_funds();
}

BOOST_AUTO_TEST_SUITE_END()
2 changes: 1 addition & 1 deletion src/wallet/wallet.cpp
Expand Up @@ -1832,7 +1832,7 @@ std::pair<std::vector<std::string>, CWalletError> CWallet::PurchaseTicket(std::s
// inputs

if (useVsp) {
mTicketTx.vin.push_back(CTxIn(splitTx->GetHash(), 2*i)); // VSP
mTicketTx.vin.push_back(CTxIn(splitTx->GetHash(), 2*i)); // VSP
mTicketTx.vin.push_back(CTxIn(splitTx->GetHash(), 2*i+1)); // ticket
} else
mTicketTx.vin.push_back(CTxIn(splitTx->GetHash(), i));
Expand Down

0 comments on commit 6dd9900

Please sign in to comment.