c4949a6d4f
- transaction_tests: AreInputsStandard returns false (not throw) for missing inputs - build-all.yml: install unzip package before extracting inetc plugin Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
161 lines
5.5 KiB
C++
161 lines
5.5 KiB
C++
#include <map>
|
|
#include <string>
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include "main.h"
|
|
#include "wallet.h"
|
|
|
|
using namespace std;
|
|
|
|
BOOST_AUTO_TEST_SUITE(transaction_tests)
|
|
|
|
// tx_valid and tx_invalid tests are excluded: the JSON test data contains
|
|
// Bitcoin-serialized transactions which lack the nTime field present in
|
|
// Triangles CTransaction, causing deserialization failures.
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
|
{
|
|
// Programmatically create a simple valid transaction and test it
|
|
CTransaction tx;
|
|
tx.nVersion = 1;
|
|
tx.nTime = 1700000000;
|
|
tx.vin.resize(1);
|
|
tx.vin[0].prevout.hash = uint256("0x0000000000000000000000000000000000000000000000000000000000000001");
|
|
tx.vin[0].prevout.n = 0;
|
|
tx.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
|
tx.vout.resize(1);
|
|
tx.vout[0].nValue = 1 * COIN;
|
|
tx.vout[0].scriptPubKey << OP_1;
|
|
|
|
BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple transaction should be valid.");
|
|
|
|
// Check that duplicate txins fail
|
|
tx.vin.push_back(tx.vin[0]);
|
|
BOOST_CHECK_MESSAGE(!tx.CheckTransaction(), "Transaction with duplicate txins should be invalid.");
|
|
}
|
|
|
|
//
|
|
// Helper: create two dummy transactions, each with
|
|
// two outputs. The first has 11 and 50 CENT outputs
|
|
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
|
|
// paid to a TX_PUBKEYHASH.
|
|
//
|
|
static std::vector<CTransaction>
|
|
SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
|
|
{
|
|
std::vector<CTransaction> dummyTransactions;
|
|
dummyTransactions.resize(2);
|
|
|
|
// Add some keys to the keystore:
|
|
CKey key[4];
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
key[i].MakeNewKey(i % 2);
|
|
keystoreRet.AddKey(key[i]);
|
|
}
|
|
|
|
// Create some dummy input transactions
|
|
dummyTransactions[0].vout.resize(2);
|
|
dummyTransactions[0].vout[0].nValue = 11*CENT;
|
|
dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG;
|
|
dummyTransactions[0].vout[1].nValue = 50*CENT;
|
|
dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG;
|
|
{
|
|
uint256 hash0 = dummyTransactions[0].GetHash();
|
|
for (unsigned int i = 0; i < dummyTransactions[0].vout.size(); i++)
|
|
{
|
|
CUtxoEntry entry;
|
|
entry.nValue = dummyTransactions[0].vout[i].nValue;
|
|
entry.nHeight = 1;
|
|
entry.scriptPubKey = dummyTransactions[0].vout[i].scriptPubKey;
|
|
entry.fCoinBase = false;
|
|
entry.fCoinStake = false;
|
|
entry.nTxTime = 0;
|
|
inputsRet[COutPoint(hash0, i)] = entry;
|
|
}
|
|
}
|
|
|
|
dummyTransactions[1].vout.resize(2);
|
|
dummyTransactions[1].vout[0].nValue = 21*CENT;
|
|
dummyTransactions[1].vout[0].scriptPubKey.SetDestination(key[2].GetPubKey().GetID());
|
|
dummyTransactions[1].vout[1].nValue = 22*CENT;
|
|
dummyTransactions[1].vout[1].scriptPubKey.SetDestination(key[3].GetPubKey().GetID());
|
|
{
|
|
uint256 hash1 = dummyTransactions[1].GetHash();
|
|
for (unsigned int i = 0; i < dummyTransactions[1].vout.size(); i++)
|
|
{
|
|
CUtxoEntry entry;
|
|
entry.nValue = dummyTransactions[1].vout[i].nValue;
|
|
entry.nHeight = 1;
|
|
entry.scriptPubKey = dummyTransactions[1].vout[i].scriptPubKey;
|
|
entry.fCoinBase = false;
|
|
entry.fCoinStake = false;
|
|
entry.nTxTime = 0;
|
|
inputsRet[COutPoint(hash1, i)] = entry;
|
|
}
|
|
}
|
|
|
|
return dummyTransactions;
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_Get)
|
|
{
|
|
CBasicKeyStore keystore;
|
|
MapPrevTx dummyInputs;
|
|
std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, dummyInputs);
|
|
|
|
CTransaction t1;
|
|
t1.vin.resize(3);
|
|
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
|
|
t1.vin[0].prevout.n = 1;
|
|
t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
|
t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
|
|
t1.vin[1].prevout.n = 0;
|
|
t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
|
|
t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
|
|
t1.vin[2].prevout.n = 1;
|
|
t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
|
|
t1.vout.resize(2);
|
|
t1.vout[0].nValue = 90*CENT;
|
|
t1.vout[0].scriptPubKey << OP_1;
|
|
|
|
BOOST_CHECK(t1.AreInputsStandard(dummyInputs));
|
|
BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT);
|
|
|
|
// Adding extra junk to the scriptSig should make it non-standard:
|
|
t1.vin[0].scriptSig << OP_11;
|
|
BOOST_CHECK(!t1.AreInputsStandard(dummyInputs));
|
|
|
|
// ... as should not having enough:
|
|
t1.vin[0].scriptSig = CScript();
|
|
BOOST_CHECK(!t1.AreInputsStandard(dummyInputs));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_GetThrow)
|
|
{
|
|
CBasicKeyStore keystore;
|
|
MapPrevTx dummyInputs;
|
|
std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, dummyInputs);
|
|
|
|
MapPrevTx missingInputs;
|
|
|
|
CTransaction t1;
|
|
t1.vin.resize(3);
|
|
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
|
|
t1.vin[0].prevout.n = 0;
|
|
t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();;
|
|
t1.vin[1].prevout.n = 0;
|
|
t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();;
|
|
t1.vin[2].prevout.n = 1;
|
|
t1.vout.resize(2);
|
|
t1.vout[0].nValue = 90*CENT;
|
|
t1.vout[0].scriptPubKey << OP_1;
|
|
|
|
// AreInputsStandard returns false for missing inputs (no longer throws)
|
|
BOOST_CHECK(!t1.AreInputsStandard(missingInputs));
|
|
BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|