mirror of
https://github.com/AskDavis/Casinotest.git
synced 2026-01-06 05:09:46 -08:00
Initial commit.
This commit is contained in:
34
src/test/Checkpoints_tests.cpp
Normal file
34
src/test/Checkpoints_tests.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Unit tests for block-chain checkpoints
|
||||
//
|
||||
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "../checkpoints.h"
|
||||
#include "../util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Checkpoints_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sanity)
|
||||
{
|
||||
uint256 p1500 = uint256("0x841a2965955dd288cfa707a755d05a54e45f8bd476835ec9af4402a2b59a2967");
|
||||
uint256 p120000 = uint256("0xbd9d26924f05f6daa7f0155f32828ec89e8e29cee9e7121b026a7a3552ac6131");
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(1500, p1500));
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(120000, p120000));
|
||||
|
||||
|
||||
// Wrong hashes at checkpoints should fail:
|
||||
BOOST_CHECK(!Checkpoints::CheckBlock(1500, p120000));
|
||||
BOOST_CHECK(!Checkpoints::CheckBlock(120000, p1500));
|
||||
|
||||
// ... but any hash not at a checkpoint should succeed:
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(1500+1, p120000));
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(120000+1, p1500));
|
||||
|
||||
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 120000);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
314
src/test/DoS_tests.cpp
Normal file
314
src/test/DoS_tests.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
//
|
||||
// Unit tests for denial-of-service detection/prevention code
|
||||
//
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
#include "net.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Tests this internal-to-main.cpp method:
|
||||
extern bool AddOrphanTx(const CDataStream& vMsg);
|
||||
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
|
||||
extern std::map<uint256, CDataStream*> mapOrphanTransactions;
|
||||
extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
|
||||
|
||||
CService ip(uint32_t i)
|
||||
{
|
||||
struct in_addr s;
|
||||
s.s_addr = i;
|
||||
return CService(CNetAddr(s), GetDefaultPort());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(DoS_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||
{
|
||||
CNode::ClearBanned();
|
||||
CAddress addr1(ip(0xa0b0c001));
|
||||
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
|
||||
dummyNode1.Misbehaving(100); // Should get banned
|
||||
BOOST_CHECK(CNode::IsBanned(addr1));
|
||||
BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned
|
||||
|
||||
CAddress addr2(ip(0xa0b0c002));
|
||||
CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
|
||||
dummyNode2.Misbehaving(50);
|
||||
BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
|
||||
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
|
||||
dummyNode2.Misbehaving(50);
|
||||
BOOST_CHECK(CNode::IsBanned(addr2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
{
|
||||
CNode::ClearBanned();
|
||||
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
|
||||
CAddress addr1(ip(0xa0b0c001));
|
||||
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
|
||||
dummyNode1.Misbehaving(100);
|
||||
BOOST_CHECK(!CNode::IsBanned(addr1));
|
||||
dummyNode1.Misbehaving(10);
|
||||
BOOST_CHECK(!CNode::IsBanned(addr1));
|
||||
dummyNode1.Misbehaving(1);
|
||||
BOOST_CHECK(CNode::IsBanned(addr1));
|
||||
mapArgs.erase("-banscore");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
{
|
||||
CNode::ClearBanned();
|
||||
int64 nStartTime = GetTime();
|
||||
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||
|
||||
CAddress addr(ip(0xa0b0c001));
|
||||
CNode dummyNode(INVALID_SOCKET, addr, "", true);
|
||||
|
||||
dummyNode.Misbehaving(100);
|
||||
BOOST_CHECK(CNode::IsBanned(addr));
|
||||
|
||||
SetMockTime(nStartTime+60*60);
|
||||
BOOST_CHECK(CNode::IsBanned(addr));
|
||||
|
||||
SetMockTime(nStartTime+60*60*24+1);
|
||||
BOOST_CHECK(!CNode::IsBanned(addr));
|
||||
}
|
||||
|
||||
static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\
|
||||
{
|
||||
if (time1 > time2)
|
||||
return CheckNBits(nbits2, time2, nbits1, time1);
|
||||
int64 deltaTime = time2-time1;
|
||||
|
||||
CBigNum required;
|
||||
required.SetCompact(ComputeMinWork(nbits1, deltaTime));
|
||||
CBigNum have;
|
||||
have.SetCompact(nbits2);
|
||||
return (have <= required);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_checknbits)
|
||||
{
|
||||
using namespace boost::assign; // for 'map_list_of()'
|
||||
|
||||
// Timestamps,nBits from the bitcoin blockchain.
|
||||
// These are the block-chain checkpoint blocks
|
||||
typedef std::map<int64, unsigned int> BlockData;
|
||||
BlockData chainData =
|
||||
map_list_of(1239852051,486604799)(1262749024,486594666)
|
||||
(1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
|
||||
(1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
|
||||
(1313172719,436789733);
|
||||
|
||||
// Make sure CheckNBits considers every combination of block-chain-lock-in-points
|
||||
// "sane":
|
||||
BOOST_FOREACH(const BlockData::value_type& i, chainData)
|
||||
{
|
||||
BOOST_FOREACH(const BlockData::value_type& j, chainData)
|
||||
{
|
||||
BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
|
||||
}
|
||||
}
|
||||
|
||||
// Test a couple of insane combinations:
|
||||
BlockData::value_type firstcheck = *(chainData.begin());
|
||||
BlockData::value_type lastcheck = *(chainData.rbegin());
|
||||
|
||||
// First checkpoint difficulty at or a while after the last checkpoint time should fail when
|
||||
// compared to last checkpoint
|
||||
BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
|
||||
BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
|
||||
|
||||
// ... but OK if enough time passed for difficulty to adjust downward:
|
||||
BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
|
||||
|
||||
}
|
||||
|
||||
CTransaction RandomOrphan()
|
||||
{
|
||||
std::map<uint256, CDataStream*>::iterator it;
|
||||
it = mapOrphanTransactions.lower_bound(GetRandHash());
|
||||
if (it == mapOrphanTransactions.end())
|
||||
it = mapOrphanTransactions.begin();
|
||||
const CDataStream* pvMsg = it->second;
|
||||
CTransaction tx;
|
||||
CDataStream(*pvMsg) >> tx;
|
||||
return tx;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddKey(key);
|
||||
|
||||
// 50 orphan transactions:
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
CTransaction tx;
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].prevout.n = 0;
|
||||
tx.vin[0].prevout.hash = GetRandHash();
|
||||
tx.vin[0].scriptSig << OP_1;
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
AddOrphanTx(ds);
|
||||
}
|
||||
|
||||
// ... and 50 that depend on other orphans:
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
CTransaction txPrev = RandomOrphan();
|
||||
|
||||
CTransaction tx;
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].prevout.n = 0;
|
||||
tx.vin[0].prevout.hash = txPrev.GetHash();
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
SignSignature(keystore, txPrev, tx, 0);
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
AddOrphanTx(ds);
|
||||
}
|
||||
|
||||
// This really-big orphan should be ignored:
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
CTransaction txPrev = RandomOrphan();
|
||||
|
||||
CTransaction tx;
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
tx.vin.resize(500);
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
{
|
||||
tx.vin[j].prevout.n = j;
|
||||
tx.vin[j].prevout.hash = txPrev.GetHash();
|
||||
}
|
||||
SignSignature(keystore, txPrev, tx, 0);
|
||||
// Re-use same signature for other inputs
|
||||
// (they don't have to be valid for this test)
|
||||
for (unsigned int j = 1; j < tx.vin.size(); j++)
|
||||
tx.vin[j].scriptSig = tx.vin[0].scriptSig;
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
BOOST_CHECK(!AddOrphanTx(ds));
|
||||
}
|
||||
|
||||
// Test LimitOrphanTxSize() function:
|
||||
LimitOrphanTxSize(40);
|
||||
BOOST_CHECK(mapOrphanTransactions.size() <= 40);
|
||||
LimitOrphanTxSize(10);
|
||||
BOOST_CHECK(mapOrphanTransactions.size() <= 10);
|
||||
LimitOrphanTxSize(0);
|
||||
BOOST_CHECK(mapOrphanTransactions.empty());
|
||||
BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_checkSig)
|
||||
{
|
||||
// Test signature caching code (see key.cpp Verify() methods)
|
||||
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddKey(key);
|
||||
|
||||
// 100 orphan transactions:
|
||||
static const int NPREV=100;
|
||||
CTransaction orphans[NPREV];
|
||||
for (int i = 0; i < NPREV; i++)
|
||||
{
|
||||
CTransaction& tx = orphans[i];
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].prevout.n = 0;
|
||||
tx.vin[0].prevout.hash = GetRandHash();
|
||||
tx.vin[0].scriptSig << OP_1;
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
AddOrphanTx(ds);
|
||||
}
|
||||
|
||||
// Create a transaction that depends on orphans:
|
||||
CTransaction tx;
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
tx.vin.resize(NPREV);
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
{
|
||||
tx.vin[j].prevout.n = 0;
|
||||
tx.vin[j].prevout.hash = orphans[j].GetHash();
|
||||
}
|
||||
// Creating signatures primes the cache:
|
||||
boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
|
||||
boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
|
||||
boost::posix_time::time_duration msdiff = mst2 - mst1;
|
||||
long nOneValidate = msdiff.total_milliseconds();
|
||||
if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);
|
||||
|
||||
// ... now validating repeatedly should be quick:
|
||||
// 2.8GHz machine, -g build: Sign takes ~760ms,
|
||||
// uncached Verify takes ~250ms, cached Verify takes ~50ms
|
||||
// (for 100 single-signature inputs)
|
||||
mst1 = boost::posix_time::microsec_clock::local_time();
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
|
||||
mst2 = boost::posix_time::microsec_clock::local_time();
|
||||
msdiff = mst2 - mst1;
|
||||
long nManyValidate = msdiff.total_milliseconds();
|
||||
if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);
|
||||
|
||||
BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
|
||||
|
||||
// Empty a signature, validation should fail:
|
||||
CScript save = tx.vin[0].scriptSig;
|
||||
tx.vin[0].scriptSig = CScript();
|
||||
BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
|
||||
tx.vin[0].scriptSig = save;
|
||||
|
||||
// Swap signatures, validation should fail:
|
||||
std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
|
||||
BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
|
||||
BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));
|
||||
std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
|
||||
|
||||
// Exercise -maxsigcachesize code:
|
||||
mapArgs["-maxsigcachesize"] = "10";
|
||||
// Generate a new, different signature for vin[0] to trigger cache clear:
|
||||
CScript oldSig = tx.vin[0].scriptSig;
|
||||
BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
|
||||
BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
|
||||
mapArgs.erase("-maxsigcachesize");
|
||||
|
||||
LimitOrphanTxSize(0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
21
src/test/README
Normal file
21
src/test/README
Normal file
@@ -0,0 +1,21 @@
|
||||
The sources in this directory are unit test cases. Boost includes a
|
||||
unit testing framework, and since bitcoin already uses boost, it makes
|
||||
sense to simply use this framework rather than require developers to
|
||||
configure some other framework (we want as few impediments to creating
|
||||
unit tests as possible).
|
||||
|
||||
The build system is setup to compile an executable called "test_bitcoin"
|
||||
that runs all of the unit tests. The main source file is called
|
||||
test_bitcoin.cpp, which simply includes other files that contain the
|
||||
actual unit tests (outside of a couple required preprocessor
|
||||
directives). The pattern is to create one test file for each class or
|
||||
source file for which you want to create unit tests. The file naming
|
||||
convention is "<source_filename>_tests.cpp" and such files should wrap
|
||||
their tests in a test suite called "<source_filename>_tests". For an
|
||||
examples of this pattern, examine uint160_tests.cpp and
|
||||
uint256_tests.cpp.
|
||||
|
||||
For further reading, I found the following website to be helpful in
|
||||
explaining how the boost unit test framework works:
|
||||
|
||||
http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/
|
||||
20
src/test/base32_tests.cpp
Normal file
20
src/test/base32_tests.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(base32_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base32_testvectors)
|
||||
{
|
||||
static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"};
|
||||
static const std::string vstrOut[] = {"","my======","mzxq====","mzxw6===","mzxw6yq=","mzxw6ytb","mzxw6ytboi======"};
|
||||
for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
|
||||
{
|
||||
std::string strEnc = EncodeBase32(vstrIn[i]);
|
||||
BOOST_CHECK(strEnc == vstrOut[i]);
|
||||
std::string strDec = DecodeBase32(vstrOut[i]);
|
||||
BOOST_CHECK(strDec == vstrIn[i]);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
87
src/test/base58_tests.cpp
Normal file
87
src/test/base58_tests.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(base58_tests)
|
||||
|
||||
// TODO:
|
||||
// EncodeBase58Check
|
||||
// DecodeBase58Check
|
||||
// CBase58Data
|
||||
// bool SetString(const char* psz)
|
||||
// bool SetString(const std::string& str)
|
||||
// std::string ToString() const
|
||||
// int CompareTo(const CBase58Data& b58) const
|
||||
// bool operator==(const CBase58Data& b58) const
|
||||
// bool operator<=(const CBase58Data& b58) const
|
||||
// bool operator>=(const CBase58Data& b58) const
|
||||
// bool operator< (const CBase58Data& b58) const
|
||||
// bool operator> (const CBase58Data& b58) const
|
||||
|
||||
// CBitcoinAddress
|
||||
// bool SetHash160(const uint160& hash160)
|
||||
// bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
|
||||
// bool IsValid() const
|
||||
// CBitcoinAddress()
|
||||
// CBitcoinAddress(uint160 hash160In)
|
||||
// CBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
|
||||
// CBitcoinAddress(const std::string& strAddress)
|
||||
// CBitcoinAddress(const char* pszAddress)
|
||||
// uint160 GetHash160() const
|
||||
|
||||
#define U(x) (reinterpret_cast<const unsigned char*>(x))
|
||||
static struct {
|
||||
const unsigned char *data;
|
||||
int size;
|
||||
} vstrIn[] = {
|
||||
{U(""), 0},
|
||||
{U("\x61"), 1},
|
||||
{U("\x62\x62\x62"), 3},
|
||||
{U("\x63\x63\x63"), 3},
|
||||
{U("\x73\x69\x6d\x70\x6c\x79\x20\x61\x20\x6c\x6f\x6e\x67\x20\x73\x74\x72\x69\x6e\x67"), 20},
|
||||
{U("\x00\xeb\x15\x23\x1d\xfc\xeb\x60\x92\x58\x86\xb6\x7d\x06\x52\x99\x92\x59\x15\xae\xb1\x72\xc0\x66\x47"), 25},
|
||||
{U("\x51\x6b\x6f\xcd\x0f"), 5},
|
||||
{U("\xbf\x4f\x89\x00\x1e\x67\x02\x74\xdd"), 9},
|
||||
{U("\x57\x2e\x47\x94"), 4},
|
||||
{U("\xec\xac\x89\xca\xd9\x39\x23\xc0\x23\x21"), 10},
|
||||
{U("\x10\xc8\x51\x1e"), 4},
|
||||
{U("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), 10},
|
||||
};
|
||||
|
||||
const char *vstrOut[] = {
|
||||
"",
|
||||
"2g",
|
||||
"a3gV",
|
||||
"aPEr",
|
||||
"2cFupjhnEsSn59qHXstmK2ffpLv2",
|
||||
"1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L",
|
||||
"ABnLTmg",
|
||||
"3SEo3LWLoPntC",
|
||||
"3EFU7m",
|
||||
"EJDM8drfXA6uyA",
|
||||
"Rt5zm",
|
||||
"1111111111"
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
|
||||
{
|
||||
for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(EncodeBase58(vstrIn[i].data, vstrIn[i].data + vstrIn[i].size), vstrOut[i]);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
|
||||
{
|
||||
std::vector<unsigned char> result;
|
||||
for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
|
||||
{
|
||||
std::vector<unsigned char> expected(vstrIn[i].data, vstrIn[i].data + vstrIn[i].size);
|
||||
BOOST_CHECK(DecodeBase58(vstrOut[i], result));
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
|
||||
}
|
||||
BOOST_CHECK(!DecodeBase58("invalid", result));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
22
src/test/base64_tests.cpp
Normal file
22
src/test/base64_tests.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
#include "util.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(base64_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base64_testvectors)
|
||||
{
|
||||
static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"};
|
||||
static const std::string vstrOut[] = {"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"};
|
||||
for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
|
||||
{
|
||||
std::string strEnc = EncodeBase64(vstrIn[i]);
|
||||
BOOST_CHECK(strEnc == vstrOut[i]);
|
||||
std::string strDec = DecodeBase64(strEnc);
|
||||
BOOST_CHECK(strDec == vstrIn[i]);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
125
src/test/bignum_tests.cpp
Normal file
125
src/test/bignum_tests.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <limits>
|
||||
|
||||
#include "bignum.h"
|
||||
#include "util.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(bignum_tests)
|
||||
|
||||
// Unfortunately there's no standard way of preventing a function from being
|
||||
// inlined, so we define a macro for it.
|
||||
//
|
||||
// You should use it like this:
|
||||
// NOINLINE void function() {...}
|
||||
#if defined(__GNUC__)
|
||||
// This also works and will be defined for any compiler implementing gcc
|
||||
// extensions, such as clang and icc.
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define NOINLINE __declspec(noinline)
|
||||
#else
|
||||
// We give out a warning because it impacts the correctness of one bignum test.
|
||||
#warning You should define NOINLINE for your compiler.
|
||||
#define NOINLINE
|
||||
#endif
|
||||
|
||||
// For the following test case, it is useful to use additional tools.
|
||||
//
|
||||
// The simplest one to use is the compiler flag -ftrapv, which detects integer
|
||||
// overflows and similar errors. However, due to optimizations and compilers
|
||||
// taking advantage of undefined behavior sometimes it may not actually detect
|
||||
// anything.
|
||||
//
|
||||
// You can also use compiler-based stack protection to possibly detect possible
|
||||
// stack buffer overruns.
|
||||
//
|
||||
// For more accurate diagnostics, you can use an undefined arithmetic operation
|
||||
// detector such as the clang-based tool:
|
||||
//
|
||||
// "IOC: An Integer Overflow Checker for C/C++"
|
||||
//
|
||||
// Available at: http://embed.cs.utah.edu/ioc/
|
||||
//
|
||||
// It might also be useful to use Google's AddressSanitizer to detect
|
||||
// stack buffer overruns, which valgrind can't currently detect.
|
||||
|
||||
// Let's force this code not to be inlined, in order to actually
|
||||
// test a generic version of the function. This increases the chance
|
||||
// that -ftrapv will detect overflows.
|
||||
NOINLINE void mysetint64(CBigNum& num, int64 n)
|
||||
{
|
||||
num.setint64(n);
|
||||
}
|
||||
|
||||
// For each number, we do 2 tests: one with inline code, then we reset the
|
||||
// value to 0, then the second one with a non-inlined function.
|
||||
BOOST_AUTO_TEST_CASE(bignum_setint64)
|
||||
{
|
||||
int64 n;
|
||||
|
||||
{
|
||||
n = 0;
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
}
|
||||
{
|
||||
n = 1;
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "1");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "1");
|
||||
}
|
||||
{
|
||||
n = -1;
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "-1");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "-1");
|
||||
}
|
||||
{
|
||||
n = 5;
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "5");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "5");
|
||||
}
|
||||
{
|
||||
n = -5;
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "-5");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "-5");
|
||||
}
|
||||
{
|
||||
n = std::numeric_limits<int64>::min();
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "-9223372036854775808");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "-9223372036854775808");
|
||||
}
|
||||
{
|
||||
n = std::numeric_limits<int64>::max();
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "9223372036854775807");
|
||||
num.setulong(0);
|
||||
BOOST_CHECK(num.ToString() == "0");
|
||||
mysetint64(num, n);
|
||||
BOOST_CHECK(num.ToString() == "9223372036854775807");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
161
src/test/data/script_invalid.json
Normal file
161
src/test/data/script_invalid.json
Normal file
File diff suppressed because one or more lines are too long
204
src/test/data/script_valid.json
Normal file
204
src/test/data/script_valid.json
Normal file
File diff suppressed because one or more lines are too long
167
src/test/getarg_tests.cpp
Normal file
167
src/test/getarg_tests.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(getarg_tests)
|
||||
|
||||
static void
|
||||
ResetArgs(const std::string& strArg)
|
||||
{
|
||||
std::vector<std::string> vecArg;
|
||||
boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on);
|
||||
|
||||
// Insert dummy executable name:
|
||||
vecArg.insert(vecArg.begin(), "testbitcoin");
|
||||
|
||||
// Convert to char*:
|
||||
std::vector<const char*> vecChar;
|
||||
BOOST_FOREACH(std::string& s, vecArg)
|
||||
vecChar.push_back(s.c_str());
|
||||
|
||||
ParseParameters(vecChar.size(), &vecChar[0]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(boolarg)
|
||||
{
|
||||
ResetArgs("-foo");
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
BOOST_CHECK(GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(GetBoolArg("-foo", true));
|
||||
|
||||
BOOST_CHECK(!GetBoolArg("-fo"));
|
||||
BOOST_CHECK(!GetBoolArg("-fo", false));
|
||||
BOOST_CHECK(GetBoolArg("-fo", true));
|
||||
|
||||
BOOST_CHECK(!GetBoolArg("-fooo"));
|
||||
BOOST_CHECK(!GetBoolArg("-fooo", false));
|
||||
BOOST_CHECK(GetBoolArg("-fooo", true));
|
||||
|
||||
ResetArgs("-foo=0");
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
|
||||
ResetArgs("-foo=1");
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
BOOST_CHECK(GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(GetBoolArg("-foo", true));
|
||||
|
||||
// New 0.6 feature: auto-map -nosomething to !-something:
|
||||
ResetArgs("-nofoo");
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
|
||||
ResetArgs("-nofoo=1");
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
|
||||
ResetArgs("-foo -nofoo"); // -foo should win
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
BOOST_CHECK(GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(GetBoolArg("-foo", true));
|
||||
|
||||
ResetArgs("-foo=1 -nofoo=1"); // -foo should win
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
BOOST_CHECK(GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(GetBoolArg("-foo", true));
|
||||
|
||||
ResetArgs("-foo=0 -nofoo=0"); // -foo should win
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
|
||||
// New 0.6 feature: treat -- same as -:
|
||||
ResetArgs("--foo=1");
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
BOOST_CHECK(GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(GetBoolArg("-foo", true));
|
||||
|
||||
ResetArgs("--nofoo=1");
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stringarg)
|
||||
{
|
||||
ResetArgs("");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven");
|
||||
|
||||
ResetArgs("-foo -bar");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "");
|
||||
|
||||
ResetArgs("-foo=");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "");
|
||||
|
||||
ResetArgs("-foo=11");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "11");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "11");
|
||||
|
||||
ResetArgs("-foo=eleven");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "eleven");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven");
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(intarg)
|
||||
{
|
||||
ResetArgs("");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", 11), 11);
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", 0), 0);
|
||||
|
||||
ResetArgs("-foo -bar");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", 11), 0);
|
||||
BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0);
|
||||
|
||||
ResetArgs("-foo=11 -bar=12");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", 0), 11);
|
||||
BOOST_CHECK_EQUAL(GetArg("-bar", 11), 12);
|
||||
|
||||
ResetArgs("-foo=NaN -bar=NotANumber");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", 1), 0);
|
||||
BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(doubledash)
|
||||
{
|
||||
ResetArgs("--foo");
|
||||
BOOST_CHECK_EQUAL(GetBoolArg("-foo"), true);
|
||||
|
||||
ResetArgs("--foo=verbose --bar=1");
|
||||
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "verbose");
|
||||
BOOST_CHECK_EQUAL(GetArg("-bar", 0), 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(boolargno)
|
||||
{
|
||||
ResetArgs("-nofoo");
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
|
||||
ResetArgs("-nofoo=1");
|
||||
BOOST_CHECK(!GetBoolArg("-foo"));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", true));
|
||||
BOOST_CHECK(!GetBoolArg("-foo", false));
|
||||
|
||||
ResetArgs("-nofoo=0");
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
BOOST_CHECK(GetBoolArg("-foo", true));
|
||||
BOOST_CHECK(GetBoolArg("-foo", false));
|
||||
|
||||
ResetArgs("-foo --nofoo");
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
|
||||
ResetArgs("-nofoo -foo"); // foo always wins:
|
||||
BOOST_CHECK(GetBoolArg("-foo"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
147
src/test/key_tests.cpp
Normal file
147
src/test/key_tests.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "key.h"
|
||||
#include "base58.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const string strSecret1 ("6uu5bsZLA2Lm6yCxgwxDxHyZmhYeqBMLQT83Fyq738YhYucQPQf");
|
||||
static const string strSecret2 ("6vZDRwYgTNidWzmKs9x8QzQGeWCqbdUtNRpEKZMaP67ZSn8XMjb");
|
||||
static const string strSecret1C ("T6UsJv9hYpvDfM5noKYkB3vfeHxhyegkeWJ4y7qKeQJuyXMK11XX");
|
||||
static const string strSecret2C ("T9PBs5kq9QrkBPxeGNWKitMi4XuFVr25jaXTnuopLVZxCUAJbixA");
|
||||
static const CBitcoinAddress addr1 ("LWaFezDtucfCA4xcVEfs3R3xfgGWjSwcZr");
|
||||
static const CBitcoinAddress addr2 ("LXwHM6mRd432EzLJYwuKQMPhTzrgr7ur9K");
|
||||
static const CBitcoinAddress addr1C("LZWK8h7C166niP6GmpUmiGrvn4oxPqQgFV");
|
||||
static const CBitcoinAddress addr2C("Lgb6tdqmdW3n5E12johSuEAqRMt4kAr7yu");
|
||||
|
||||
|
||||
static const string strAddressBad("LRjyUS2uuieEPkhZNdQz8hE5YycxVEqSXA");
|
||||
|
||||
|
||||
#ifdef KEY_TESTS_DUMPINFO
|
||||
void dumpKeyInfo(uint256 privkey)
|
||||
{
|
||||
CSecret secret;
|
||||
secret.resize(32);
|
||||
memcpy(&secret[0], &privkey, 32);
|
||||
vector<unsigned char> sec;
|
||||
sec.resize(32);
|
||||
memcpy(&sec[0], &secret[0], 32);
|
||||
printf(" * secret (hex): %s\n", HexStr(sec).c_str());
|
||||
|
||||
for (int nCompressed=0; nCompressed<2; nCompressed++)
|
||||
{
|
||||
bool fCompressed = nCompressed == 1;
|
||||
printf(" * %s:\n", fCompressed ? "compressed" : "uncompressed");
|
||||
CBitcoinSecret bsecret;
|
||||
bsecret.SetSecret(secret, fCompressed);
|
||||
printf(" * secret (base58): %s\n", bsecret.ToString().c_str());
|
||||
CKey key;
|
||||
key.SetSecret(secret, fCompressed);
|
||||
vector<unsigned char> vchPubKey = key.GetPubKey();
|
||||
printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str());
|
||||
printf(" * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(key_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(key_test1)
|
||||
{
|
||||
CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1;
|
||||
BOOST_CHECK( bsecret1.SetString (strSecret1));
|
||||
BOOST_CHECK( bsecret2.SetString (strSecret2));
|
||||
BOOST_CHECK( bsecret1C.SetString(strSecret1C));
|
||||
BOOST_CHECK( bsecret2C.SetString(strSecret2C));
|
||||
BOOST_CHECK(!baddress1.SetString(strAddressBad));
|
||||
|
||||
bool fCompressed;
|
||||
CSecret secret1 = bsecret1.GetSecret (fCompressed);
|
||||
BOOST_CHECK(fCompressed == false);
|
||||
CSecret secret2 = bsecret2.GetSecret (fCompressed);
|
||||
BOOST_CHECK(fCompressed == false);
|
||||
CSecret secret1C = bsecret1C.GetSecret(fCompressed);
|
||||
BOOST_CHECK(fCompressed == true);
|
||||
CSecret secret2C = bsecret2C.GetSecret(fCompressed);
|
||||
BOOST_CHECK(fCompressed == true);
|
||||
|
||||
BOOST_CHECK(secret1 == secret1C);
|
||||
BOOST_CHECK(secret2 == secret2C);
|
||||
|
||||
CKey key1, key2, key1C, key2C;
|
||||
key1.SetSecret(secret1, false);
|
||||
key2.SetSecret(secret2, false);
|
||||
key1C.SetSecret(secret1, true);
|
||||
key2C.SetSecret(secret2, true);
|
||||
|
||||
BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID()));
|
||||
|
||||
for (int n=0; n<16; n++)
|
||||
{
|
||||
string strMsg = strprintf("Very secret message %i: 11", n);
|
||||
uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());
|
||||
|
||||
// normal signatures
|
||||
|
||||
vector<unsigned char> sign1, sign2, sign1C, sign2C;
|
||||
|
||||
BOOST_CHECK(key1.Sign (hashMsg, sign1));
|
||||
BOOST_CHECK(key2.Sign (hashMsg, sign2));
|
||||
BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
|
||||
BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK( key1.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK(!key1.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK( key1.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK(!key1.Verify(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK(!key2.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK( key2.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK(!key2.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK( key2.Verify(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK( key1C.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK(!key1C.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK( key1C.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK(!key1C.Verify(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK(!key2C.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK( key2C.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK(!key2C.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK( key2C.Verify(hashMsg, sign2C));
|
||||
|
||||
// compact signatures (with key recovery)
|
||||
|
||||
vector<unsigned char> csign1, csign2, csign1C, csign2C;
|
||||
|
||||
BOOST_CHECK(key1.SignCompact (hashMsg, csign1));
|
||||
BOOST_CHECK(key2.SignCompact (hashMsg, csign2));
|
||||
BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
|
||||
BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
|
||||
|
||||
CKey rkey1, rkey2, rkey1C, rkey2C;
|
||||
|
||||
BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1));
|
||||
BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2));
|
||||
BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C));
|
||||
BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C));
|
||||
|
||||
|
||||
BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey());
|
||||
BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey());
|
||||
BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey());
|
||||
BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
36
src/test/miner_tests.cpp
Normal file
36
src/test/miner_tests.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
||||
extern void SHA256Transform(void* pstate, void* pinput, const void* pinit);
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(miner_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sha256transform_equality)
|
||||
{
|
||||
unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
|
||||
|
||||
|
||||
// unsigned char pstate[32];
|
||||
unsigned char pinput[64];
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
pinput[i] = i;
|
||||
pinput[i+32] = 0;
|
||||
}
|
||||
|
||||
uint256 hash;
|
||||
|
||||
SHA256Transform(&hash, pinput, pSHA256InitState);
|
||||
|
||||
BOOST_TEST_MESSAGE(hash.GetHex());
|
||||
|
||||
uint256 hash_reference("0x2df5e1c65ef9f8cde240d23cae2ec036d31a15ec64bc68f64be242b1da6631f3");
|
||||
|
||||
BOOST_CHECK(hash == hash_reference);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
90
src/test/mruset_tests.cpp
Normal file
90
src/test/mruset_tests.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "mruset.h"
|
||||
#include "util.h"
|
||||
|
||||
#define NUM_TESTS 16
|
||||
#define MAX_SIZE 100
|
||||
|
||||
class mrutester
|
||||
{
|
||||
private:
|
||||
mruset<int> mru;
|
||||
std::set<int> set;
|
||||
|
||||
public:
|
||||
mrutester() { mru.max_size(MAX_SIZE); }
|
||||
int size() const { return set.size(); }
|
||||
|
||||
void insert(int n)
|
||||
{
|
||||
mru.insert(n);
|
||||
set.insert(n);
|
||||
BOOST_CHECK(mru == set);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(mruset_tests)
|
||||
|
||||
// Test that an mruset behaves like a set, as long as no more than MAX_SIZE elements are in it
|
||||
BOOST_AUTO_TEST_CASE(mruset_like_set)
|
||||
{
|
||||
|
||||
for (int nTest=0; nTest<NUM_TESTS; nTest++)
|
||||
{
|
||||
mrutester tester;
|
||||
while (tester.size() < MAX_SIZE)
|
||||
tester.insert(GetRandInt(2 * MAX_SIZE));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test that an mruset's size never exceeds its max_size
|
||||
BOOST_AUTO_TEST_CASE(mruset_limited_size)
|
||||
{
|
||||
for (int nTest=0; nTest<NUM_TESTS; nTest++)
|
||||
{
|
||||
mruset<int> mru(MAX_SIZE);
|
||||
for (int nAction=0; nAction<3*MAX_SIZE; nAction++)
|
||||
{
|
||||
int n = GetRandInt(2 * MAX_SIZE);
|
||||
mru.insert(n);
|
||||
BOOST_CHECK(mru.size() <= MAX_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit permutation function
|
||||
int static permute(int n)
|
||||
{
|
||||
// hexadecimals of pi; verified to be linearly independent
|
||||
static const int table[16] = {0x243F, 0x6A88, 0x85A3, 0x08D3, 0x1319, 0x8A2E, 0x0370, 0x7344,
|
||||
0xA409, 0x3822, 0x299F, 0x31D0, 0x082E, 0xFA98, 0xEC4E, 0x6C89};
|
||||
|
||||
int ret = 0;
|
||||
for (int bit=0; bit<16; bit++)
|
||||
if (n & (1<<bit))
|
||||
ret ^= table[bit];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Test that an mruset acts like a moving window, if no duplicate elements are added
|
||||
BOOST_AUTO_TEST_CASE(mruset_window)
|
||||
{
|
||||
mruset<int> mru(MAX_SIZE);
|
||||
for (int n=0; n<10*MAX_SIZE; n++)
|
||||
{
|
||||
mru.insert(permute(n));
|
||||
|
||||
set<int> tester;
|
||||
for (int m=max(0,n-MAX_SIZE+1); m<=n; m++)
|
||||
tester.insert(permute(m));
|
||||
|
||||
BOOST_CHECK(mru == tester);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
296
src/test/multisig_tests.cpp
Normal file
296
src/test/multisig_tests.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/assign/list_inserter.hpp>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
#include "script.h"
|
||||
#include "wallet.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::assign;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType);
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(multisig_tests)
|
||||
|
||||
CScript
|
||||
sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)
|
||||
{
|
||||
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);
|
||||
|
||||
CScript result;
|
||||
result << OP_0; // CHECKMULTISIG bug workaround
|
||||
BOOST_FOREACH(CKey key, keys)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
BOOST_CHECK(key.Sign(hash, vchSig));
|
||||
vchSig.push_back((unsigned char)SIGHASH_ALL);
|
||||
result << vchSig;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
{
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
|
||||
CScript a_and_b;
|
||||
a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
|
||||
CScript a_or_b;
|
||||
a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
|
||||
CScript escrow;
|
||||
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
|
||||
CTransaction txFrom; // Funding transaction
|
||||
txFrom.vout.resize(3);
|
||||
txFrom.vout[0].scriptPubKey = a_and_b;
|
||||
txFrom.vout[1].scriptPubKey = a_or_b;
|
||||
txFrom.vout[2].scriptPubKey = escrow;
|
||||
|
||||
CTransaction txTo[3]; // Spending transaction
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
txTo[i].vin.resize(1);
|
||||
txTo[i].vout.resize(1);
|
||||
txTo[i].vin[0].prevout.n = i;
|
||||
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
|
||||
txTo[i].vout[0].nValue = 1;
|
||||
}
|
||||
|
||||
vector<CKey> keys;
|
||||
CScript s;
|
||||
|
||||
// Test a AND b:
|
||||
keys.clear();
|
||||
keys += key[0],key[1]; // magic operator+= from boost.assign
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, 0));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.clear();
|
||||
keys += key[i];
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 1: %d", i));
|
||||
|
||||
keys.clear();
|
||||
keys += key[1],key[i];
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 2: %d", i));
|
||||
}
|
||||
|
||||
// Test a OR b:
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.clear();
|
||||
keys += key[i];
|
||||
s = sign_multisig(a_or_b, keys, txTo[1], 0);
|
||||
if (i == 0 || i == 1)
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i));
|
||||
else
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i));
|
||||
}
|
||||
s.clear();
|
||||
s << OP_0 << OP_0;
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0));
|
||||
s.clear();
|
||||
s << OP_0 << OP_1;
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0));
|
||||
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
keys.clear();
|
||||
keys += key[i],key[j];
|
||||
s = sign_multisig(escrow, keys, txTo[2], 0);
|
||||
if (i < j && i < 3 && j < 3)
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 1: %d %d", i, j));
|
||||
else
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 2: %d %d", i, j));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
||||
{
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
|
||||
CScript a_and_b;
|
||||
a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(::IsStandard(a_and_b));
|
||||
|
||||
CScript a_or_b;
|
||||
a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(::IsStandard(a_or_b));
|
||||
|
||||
CScript escrow;
|
||||
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(::IsStandard(escrow));
|
||||
|
||||
CScript one_of_four;
|
||||
one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(!::IsStandard(one_of_four));
|
||||
|
||||
CScript malformed[6];
|
||||
malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG;
|
||||
malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG;
|
||||
malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
BOOST_CHECK(!::IsStandard(malformed[i]));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multisig_Solver1)
|
||||
{
|
||||
// Tests Solver() that returns lists of keys that are
|
||||
// required to satisfy a ScriptPubKey
|
||||
//
|
||||
// Also tests IsMine() and ExtractAddress()
|
||||
//
|
||||
// Note: ExtractAddress for the multisignature transactions
|
||||
// always returns false for this release, even if you have
|
||||
// one key that would satisfy an (a|b) or 2-of-3 keys needed
|
||||
// to spend an escrow transaction.
|
||||
//
|
||||
CBasicKeyStore keystore, emptykeystore, partialkeystore;
|
||||
CKey key[3];
|
||||
CTxDestination keyaddr[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
keyaddr[i] = key[i].GetPubKey().GetID();
|
||||
}
|
||||
partialkeystore.AddKey(key[0]);
|
||||
|
||||
{
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
CScript s;
|
||||
s << key[0].GetPubKey() << OP_CHECKSIG;
|
||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
||||
BOOST_CHECK(solutions.size() == 1);
|
||||
CTxDestination addr;
|
||||
BOOST_CHECK(ExtractDestination(s, addr));
|
||||
BOOST_CHECK(addr == keyaddr[0]);
|
||||
BOOST_CHECK(IsMine(keystore, s));
|
||||
BOOST_CHECK(!IsMine(emptykeystore, s));
|
||||
}
|
||||
{
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
CScript s;
|
||||
s << OP_DUP << OP_HASH160 << key[0].GetPubKey().GetID() << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
||||
BOOST_CHECK(solutions.size() == 1);
|
||||
CTxDestination addr;
|
||||
BOOST_CHECK(ExtractDestination(s, addr));
|
||||
BOOST_CHECK(addr == keyaddr[0]);
|
||||
BOOST_CHECK(IsMine(keystore, s));
|
||||
BOOST_CHECK(!IsMine(emptykeystore, s));
|
||||
}
|
||||
{
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
CScript s;
|
||||
s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
||||
BOOST_CHECK_EQUAL(solutions.size(), 4);
|
||||
CTxDestination addr;
|
||||
BOOST_CHECK(!ExtractDestination(s, addr));
|
||||
BOOST_CHECK(IsMine(keystore, s));
|
||||
BOOST_CHECK(!IsMine(emptykeystore, s));
|
||||
BOOST_CHECK(!IsMine(partialkeystore, s));
|
||||
}
|
||||
{
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
CScript s;
|
||||
s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
||||
BOOST_CHECK_EQUAL(solutions.size(), 4);
|
||||
vector<CTxDestination> addrs;
|
||||
int nRequired;
|
||||
BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
|
||||
BOOST_CHECK(addrs[0] == keyaddr[0]);
|
||||
BOOST_CHECK(addrs[1] == keyaddr[1]);
|
||||
BOOST_CHECK(nRequired == 1);
|
||||
BOOST_CHECK(IsMine(keystore, s));
|
||||
BOOST_CHECK(!IsMine(emptykeystore, s));
|
||||
BOOST_CHECK(!IsMine(partialkeystore, s));
|
||||
}
|
||||
{
|
||||
vector<valtype> solutions;
|
||||
txnouttype whichType;
|
||||
CScript s;
|
||||
s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
||||
BOOST_CHECK(solutions.size() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multisig_Sign)
|
||||
{
|
||||
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
|
||||
CBasicKeyStore keystore;
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
}
|
||||
|
||||
CScript a_and_b;
|
||||
a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
|
||||
CScript a_or_b;
|
||||
a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
|
||||
CScript escrow;
|
||||
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
|
||||
CTransaction txFrom; // Funding transaction
|
||||
txFrom.vout.resize(3);
|
||||
txFrom.vout[0].scriptPubKey = a_and_b;
|
||||
txFrom.vout[1].scriptPubKey = a_or_b;
|
||||
txFrom.vout[2].scriptPubKey = escrow;
|
||||
|
||||
CTransaction txTo[3]; // Spending transaction
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
txTo[i].vin.resize(1);
|
||||
txTo[i].vout.resize(1);
|
||||
txTo[i].vin[0].prevout.n = i;
|
||||
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
|
||||
txTo[i].vout[0].nValue = 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
102
src/test/netbase_tests.cpp
Normal file
102
src/test/netbase_tests.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "netbase.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(netbase_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(netbase_networks)
|
||||
{
|
||||
BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
|
||||
BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE);
|
||||
BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4);
|
||||
BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6);
|
||||
BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(netbase_properties)
|
||||
{
|
||||
BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());
|
||||
BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4());
|
||||
BOOST_CHECK(CNetAddr("::1").IsIPv6());
|
||||
BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918());
|
||||
BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918());
|
||||
BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918());
|
||||
BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849());
|
||||
BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927());
|
||||
BOOST_CHECK(CNetAddr("2002::1").IsRFC3964());
|
||||
BOOST_CHECK(CNetAddr("FC00::").IsRFC4193());
|
||||
BOOST_CHECK(CNetAddr("2001::2").IsRFC4380());
|
||||
BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843());
|
||||
BOOST_CHECK(CNetAddr("FE80::").IsRFC4862());
|
||||
BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052());
|
||||
BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
|
||||
BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal());
|
||||
BOOST_CHECK(CNetAddr("::1").IsLocal());
|
||||
BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable());
|
||||
BOOST_CHECK(CNetAddr("2001::1").IsRoutable());
|
||||
BOOST_CHECK(CNetAddr("127.0.0.1").IsValid());
|
||||
}
|
||||
|
||||
bool static TestSplitHost(string test, string host, int port)
|
||||
{
|
||||
string hostOut;
|
||||
int portOut = -1;
|
||||
SplitHostPort(test, portOut, hostOut);
|
||||
return hostOut == host && port == portOut;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(netbase_splithost)
|
||||
{
|
||||
BOOST_CHECK(TestSplitHost("www.casinocoin.org", "www.casinocoin.org", -1));
|
||||
BOOST_CHECK(TestSplitHost("[www.casinocoin.org]", "www.casinocoin.org", -1));
|
||||
BOOST_CHECK(TestSplitHost("www.casinocoin.org:80", "www.casinocoin.org", 80));
|
||||
BOOST_CHECK(TestSplitHost("[www.casinocoin.org]:80", "www.casinocoin.org", 80));
|
||||
BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1));
|
||||
BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333));
|
||||
BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1));
|
||||
BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333));
|
||||
BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1));
|
||||
BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333));
|
||||
BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333));
|
||||
BOOST_CHECK(TestSplitHost("::8333", "::8333", -1));
|
||||
BOOST_CHECK(TestSplitHost(":8333", "", 8333));
|
||||
BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
|
||||
BOOST_CHECK(TestSplitHost("", "", -1));
|
||||
}
|
||||
|
||||
bool static TestParse(string src, string canon)
|
||||
{
|
||||
CService addr;
|
||||
if (!LookupNumeric(src.c_str(), addr, 65535))
|
||||
return canon == "";
|
||||
return canon == addr.ToString();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
|
||||
{
|
||||
BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535"));
|
||||
BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333"));
|
||||
BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535"));
|
||||
BOOST_CHECK(TestParse("::", "[::]:65535"));
|
||||
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
|
||||
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
|
||||
BOOST_CHECK(TestParse(":::", ""));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(onioncat_test)
|
||||
{
|
||||
// values from http://www.cypherpunk.at/onioncat/wiki/OnionCat
|
||||
CNetAddr addr1("5wyqrzbvrdsumnok.onion");
|
||||
CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca");
|
||||
BOOST_CHECK(addr1 == addr2);
|
||||
BOOST_CHECK(addr1.IsTor());
|
||||
BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion");
|
||||
BOOST_CHECK(addr1.IsRoutable());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
69
src/test/rpc_tests.cpp
Normal file
69
src/test/rpc_tests.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
#include "util.h"
|
||||
#include "bitcoinrpc.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(rpc_tests)
|
||||
|
||||
static Array
|
||||
createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
|
||||
{
|
||||
Array result;
|
||||
result.push_back(nRequired);
|
||||
Array addresses;
|
||||
if (address1) addresses.push_back(address1);
|
||||
if (address2) addresses.push_back(address1);
|
||||
result.push_back(addresses);
|
||||
return result;
|
||||
}
|
||||
|
||||
// This can be removed this when addmultisigaddress is enabled on main net:
|
||||
struct TestNetFixture
|
||||
{
|
||||
TestNetFixture() { fTestNet = true; }
|
||||
~TestNetFixture() { fTestNet = false; }
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
|
||||
{
|
||||
rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
|
||||
|
||||
// old, 65-byte-long:
|
||||
const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
|
||||
// new, compressed:
|
||||
const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
|
||||
|
||||
Value v;
|
||||
CBitcoinAddress address;
|
||||
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
|
||||
address.SetString(v.get_str());
|
||||
BOOST_CHECK(address.IsValid() && address.IsScript());
|
||||
|
||||
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
|
||||
address.SetString(v.get_str());
|
||||
BOOST_CHECK(address.IsValid() && address.IsScript());
|
||||
|
||||
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
|
||||
address.SetString(v.get_str());
|
||||
BOOST_CHECK(address.IsValid() && address.IsScript());
|
||||
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
|
||||
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
|
||||
|
||||
string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
|
||||
|
||||
string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing
|
||||
BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
330
src/test/script_P2SH_tests.cpp
Normal file
330
src/test/script_P2SH_tests.cpp
Normal file
@@ -0,0 +1,330 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/assign/list_inserter.hpp>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "../main.h"
|
||||
#include "../script.h"
|
||||
#include "../wallet.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Test routines internal to script.cpp:
|
||||
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType);
|
||||
|
||||
// Helpers:
|
||||
static std::vector<unsigned char>
|
||||
Serialize(const CScript& s)
|
||||
{
|
||||
std::vector<unsigned char> sSerialized(s);
|
||||
return sSerialized;
|
||||
}
|
||||
|
||||
static bool
|
||||
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
|
||||
{
|
||||
// Create dummy to/from transactions:
|
||||
CTransaction txFrom;
|
||||
txFrom.vout.resize(1);
|
||||
txFrom.vout[0].scriptPubKey = scriptPubKey;
|
||||
|
||||
CTransaction txTo;
|
||||
txTo.vin.resize(1);
|
||||
txTo.vout.resize(1);
|
||||
txTo.vin[0].prevout.n = 0;
|
||||
txTo.vin[0].prevout.hash = txFrom.GetHash();
|
||||
txTo.vin[0].scriptSig = scriptSig;
|
||||
txTo.vout[0].nValue = 1;
|
||||
|
||||
return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, 0);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(script_P2SH_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sign)
|
||||
{
|
||||
// Pay-to-script-hash looks like this:
|
||||
// scriptSig: <sig> <sig...> <serialized_script>
|
||||
// scriptPubKey: HASH160 <hash> EQUAL
|
||||
|
||||
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
|
||||
CBasicKeyStore keystore;
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
}
|
||||
|
||||
// 8 Scripts: checking all combinations of
|
||||
// different keys, straight/P2SH, pubkey/pubkeyhash
|
||||
CScript standardScripts[4];
|
||||
standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG;
|
||||
standardScripts[1].SetDestination(key[1].GetPubKey().GetID());
|
||||
standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG;
|
||||
standardScripts[3].SetDestination(key[2].GetPubKey().GetID());
|
||||
CScript evalScripts[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keystore.AddCScript(standardScripts[i]);
|
||||
evalScripts[i].SetDestination(standardScripts[i].GetID());
|
||||
}
|
||||
|
||||
CTransaction txFrom; // Funding transaction:
|
||||
txFrom.vout.resize(8);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
txFrom.vout[i].scriptPubKey = evalScripts[i];
|
||||
txFrom.vout[i+4].scriptPubKey = standardScripts[i];
|
||||
}
|
||||
BOOST_CHECK(txFrom.IsStandard());
|
||||
|
||||
CTransaction txTo[8]; // Spending transactions
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
txTo[i].vin.resize(1);
|
||||
txTo[i].vout.resize(1);
|
||||
txTo[i].vin[0].prevout.n = i;
|
||||
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
|
||||
txTo[i].vout[0].nValue = 1;
|
||||
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
|
||||
}
|
||||
// All of the above should be OK, and the txTos have valid signatures
|
||||
// Check to make sure signature verification fails if we use the wrong ScriptSig:
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
CScript sigSave = txTo[i].vin[0].scriptSig;
|
||||
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
|
||||
bool sigOK = VerifySignature(txFrom, txTo[i], 0, true, 0);
|
||||
if (i == j)
|
||||
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||
else
|
||||
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||
txTo[i].vin[0].scriptSig = sigSave;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(norecurse)
|
||||
{
|
||||
// Make sure only the outer pay-to-script-hash does the
|
||||
// extra-validation thing:
|
||||
CScript invalidAsScript;
|
||||
invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE;
|
||||
|
||||
CScript p2sh;
|
||||
p2sh.SetDestination(invalidAsScript.GetID());
|
||||
|
||||
CScript scriptSig;
|
||||
scriptSig << Serialize(invalidAsScript);
|
||||
|
||||
// Should not verify, because it will try to execute OP_INVALIDOPCODE
|
||||
BOOST_CHECK(!Verify(scriptSig, p2sh, true));
|
||||
|
||||
// Try to recurse, and verification should succeed because
|
||||
// the inner HASH160 <> EQUAL should only check the hash:
|
||||
CScript p2sh2;
|
||||
p2sh2.SetDestination(p2sh.GetID());
|
||||
CScript scriptSig2;
|
||||
scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh);
|
||||
|
||||
BOOST_CHECK(Verify(scriptSig2, p2sh2, true));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(set)
|
||||
{
|
||||
// Test the CScript::Set* methods
|
||||
CBasicKeyStore keystore;
|
||||
CKey key[4];
|
||||
std::vector<CKey> keys;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
keys.push_back(key[i]);
|
||||
}
|
||||
|
||||
CScript inner[4];
|
||||
inner[0].SetDestination(key[0].GetPubKey().GetID());
|
||||
inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2));
|
||||
inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2));
|
||||
inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3));
|
||||
|
||||
CScript outer[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
outer[i].SetDestination(inner[i].GetID());
|
||||
keystore.AddCScript(inner[i]);
|
||||
}
|
||||
|
||||
CTransaction txFrom; // Funding transaction:
|
||||
txFrom.vout.resize(4);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
txFrom.vout[i].scriptPubKey = outer[i];
|
||||
}
|
||||
BOOST_CHECK(txFrom.IsStandard());
|
||||
|
||||
CTransaction txTo[4]; // Spending transactions
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
txTo[i].vin.resize(1);
|
||||
txTo[i].vout.resize(1);
|
||||
txTo[i].vin[0].prevout.n = i;
|
||||
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
|
||||
txTo[i].vout[0].nValue = 1;
|
||||
txTo[i].vout[0].scriptPubKey = inner[i];
|
||||
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
|
||||
BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(is)
|
||||
{
|
||||
// Test CScript::IsPayToScriptHash()
|
||||
uint160 dummy;
|
||||
CScript p2sh;
|
||||
p2sh << OP_HASH160 << dummy << OP_EQUAL;
|
||||
BOOST_CHECK(p2sh.IsPayToScriptHash());
|
||||
|
||||
// Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes:
|
||||
static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
|
||||
BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash());
|
||||
static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
|
||||
BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash());
|
||||
static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
|
||||
BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash());
|
||||
static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
|
||||
BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash());
|
||||
|
||||
CScript not_p2sh;
|
||||
BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
|
||||
|
||||
not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << dummy << OP_EQUAL;
|
||||
BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
|
||||
|
||||
not_p2sh.clear(); not_p2sh << OP_NOP << dummy << OP_EQUAL;
|
||||
BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
|
||||
|
||||
not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << OP_CHECKSIG;
|
||||
BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(switchover)
|
||||
{
|
||||
// Test switchover code
|
||||
CScript notValid;
|
||||
notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
|
||||
CScript scriptSig;
|
||||
scriptSig << Serialize(notValid);
|
||||
|
||||
CScript fund;
|
||||
fund.SetDestination(notValid.GetID());
|
||||
|
||||
|
||||
// Validation should succeed under old rules (hash is correct):
|
||||
BOOST_CHECK(Verify(scriptSig, fund, false));
|
||||
// Fail under new:
|
||||
BOOST_CHECK(!Verify(scriptSig, fund, true));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||
{
|
||||
std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs;
|
||||
CBasicKeyStore keystore;
|
||||
CKey key[3];
|
||||
vector<CKey> keys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
keys.push_back(key[i]);
|
||||
}
|
||||
|
||||
CTransaction txFrom;
|
||||
txFrom.vout.resize(6);
|
||||
|
||||
// First three are standard:
|
||||
CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID());
|
||||
keystore.AddCScript(pay1);
|
||||
CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID());
|
||||
CScript pay1of3; pay1of3.SetMultisig(1, keys);
|
||||
|
||||
txFrom.vout[0].scriptPubKey = payScriptHash1;
|
||||
txFrom.vout[1].scriptPubKey = pay1;
|
||||
txFrom.vout[2].scriptPubKey = pay1of3;
|
||||
|
||||
// Last three non-standard:
|
||||
CScript empty;
|
||||
keystore.AddCScript(empty);
|
||||
txFrom.vout[3].scriptPubKey = empty;
|
||||
// Can't use SetPayToScriptHash, it checks for the empty Script. So:
|
||||
txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL;
|
||||
CScript oneOfEleven;
|
||||
oneOfEleven << OP_1;
|
||||
for (int i = 0; i < 11; i++)
|
||||
oneOfEleven << key[0].GetPubKey();
|
||||
oneOfEleven << OP_11 << OP_CHECKMULTISIG;
|
||||
txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID());
|
||||
|
||||
mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom);
|
||||
|
||||
CTransaction txTo;
|
||||
txTo.vout.resize(1);
|
||||
txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
|
||||
|
||||
txTo.vin.resize(3);
|
||||
txTo.vin[0].prevout.n = 0;
|
||||
txTo.vin[0].prevout.hash = txFrom.GetHash();
|
||||
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
|
||||
txTo.vin[1].prevout.n = 1;
|
||||
txTo.vin[1].prevout.hash = txFrom.GetHash();
|
||||
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
|
||||
txTo.vin[2].prevout.n = 2;
|
||||
txTo.vin[2].prevout.hash = txFrom.GetHash();
|
||||
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
|
||||
|
||||
BOOST_CHECK(txTo.AreInputsStandard(mapInputs));
|
||||
BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1);
|
||||
|
||||
// Make sure adding crap to the scriptSigs makes them non-standard:
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CScript t = txTo.vin[i].scriptSig;
|
||||
txTo.vin[i].scriptSig = (CScript() << 11) + t;
|
||||
BOOST_CHECK(!txTo.AreInputsStandard(mapInputs));
|
||||
txTo.vin[i].scriptSig = t;
|
||||
}
|
||||
|
||||
CTransaction txToNonStd;
|
||||
txToNonStd.vout.resize(1);
|
||||
txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
|
||||
txToNonStd.vin.resize(2);
|
||||
txToNonStd.vin[0].prevout.n = 4;
|
||||
txToNonStd.vin[0].prevout.hash = txFrom.GetHash();
|
||||
txToNonStd.vin[0].scriptSig << Serialize(empty);
|
||||
txToNonStd.vin[1].prevout.n = 5;
|
||||
txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
|
||||
txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
|
||||
|
||||
BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs));
|
||||
BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(mapInputs), 11);
|
||||
|
||||
txToNonStd.vin[0].scriptSig.clear();
|
||||
BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
445
src/test/script_tests.cpp
Normal file
445
src/test/script_tests.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "json/json_spirit_reader_template.h"
|
||||
#include "json/json_spirit_writer_template.h"
|
||||
#include "json/json_spirit_utils.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
using namespace boost::algorithm;
|
||||
|
||||
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType);
|
||||
|
||||
CScript
|
||||
ParseScript(string s)
|
||||
{
|
||||
CScript result;
|
||||
|
||||
static map<string, opcodetype> mapOpNames;
|
||||
|
||||
if (mapOpNames.size() == 0)
|
||||
{
|
||||
for (int op = OP_NOP; op <= OP_NOP10; op++)
|
||||
{
|
||||
const char* name = GetOpName((opcodetype)op);
|
||||
if (strcmp(name, "OP_UNKNOWN") == 0)
|
||||
continue;
|
||||
string strName(name);
|
||||
mapOpNames[strName] = (opcodetype)op;
|
||||
// Convenience: OP_ADD and just ADD are both recognized:
|
||||
replace_first(strName, "OP_", "");
|
||||
mapOpNames[strName] = (opcodetype)op;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> words;
|
||||
split(words, s, is_any_of(" \t\n"), token_compress_on);
|
||||
|
||||
BOOST_FOREACH(string w, words)
|
||||
{
|
||||
if (all(w, is_digit()) ||
|
||||
(starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit())))
|
||||
{
|
||||
// Number
|
||||
int64 n = atoi64(w);
|
||||
result << n;
|
||||
}
|
||||
else if (starts_with(w, "0x") && IsHex(string(w.begin()+2, w.end())))
|
||||
{
|
||||
// Raw hex data, inserted NOT pushed onto stack:
|
||||
std::vector<unsigned char> raw = ParseHex(string(w.begin()+2, w.end()));
|
||||
result.insert(result.end(), raw.begin(), raw.end());
|
||||
}
|
||||
else if (w.size() >= 2 && starts_with(w, "'") && ends_with(w, "'"))
|
||||
{
|
||||
// Single-quoted string, pushed as data. NOTE: this is poor-man's
|
||||
// parsing, spaces/tabs/newlines in single-quoted strings won't work.
|
||||
std::vector<unsigned char> value(w.begin()+1, w.end()-1);
|
||||
result << value;
|
||||
}
|
||||
else if (mapOpNames.count(w))
|
||||
{
|
||||
// opcode, e.g. OP_ADD or OP_1:
|
||||
result << mapOpNames[w];
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ERROR("Parse error: " << s);
|
||||
return CScript();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Array
|
||||
read_json(const std::string& filename)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
fs::path testFile = fs::current_path() / "test" / "data" / filename;
|
||||
|
||||
#ifdef TEST_DATA_DIR
|
||||
if (!fs::exists(testFile))
|
||||
{
|
||||
testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename;
|
||||
}
|
||||
#endif
|
||||
|
||||
ifstream ifs(testFile.string().c_str(), ifstream::in);
|
||||
Value v;
|
||||
if (!read_stream(ifs, v))
|
||||
{
|
||||
if (ifs.fail())
|
||||
BOOST_ERROR("Cound not find/open " << filename);
|
||||
else
|
||||
BOOST_ERROR("JSON syntax error in " << filename);
|
||||
return Array();
|
||||
}
|
||||
if (v.type() != array_type)
|
||||
{
|
||||
BOOST_ERROR(filename << " does not contain a json array");
|
||||
return Array();
|
||||
}
|
||||
|
||||
return v.get_array();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(script_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_valid)
|
||||
{
|
||||
// Read tests from test/data/script_valid.json
|
||||
// Format is an array of arrays
|
||||
// Inner arrays are [ "scriptSig", "scriptPubKey" ]
|
||||
// ... where scriptSig and scriptPubKey are stringified
|
||||
// scripts.
|
||||
Array tests = read_json("script_valid.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments)
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
string scriptSigString = test[0].get_str();
|
||||
CScript scriptSig = ParseScript(scriptSigString);
|
||||
string scriptPubKeyString = test[1].get_str();
|
||||
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
||||
|
||||
CTransaction tx;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_invalid)
|
||||
{
|
||||
// Scripts that should evaluate as invalid
|
||||
Array tests = read_json("script_invalid.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments)
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
string scriptSigString = test[0].get_str();
|
||||
CScript scriptSig = ParseScript(scriptSigString);
|
||||
string scriptPubKeyString = test[1].get_str();
|
||||
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
||||
|
||||
CTransaction tx;
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_PushData)
|
||||
{
|
||||
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
|
||||
// the stack as the 1-75 opcodes do.
|
||||
static const unsigned char direct[] = { 1, 0x5a };
|
||||
static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a };
|
||||
static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a };
|
||||
static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };
|
||||
|
||||
vector<vector<unsigned char> > directStack;
|
||||
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0));
|
||||
|
||||
vector<vector<unsigned char> > pushdata1Stack;
|
||||
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0));
|
||||
BOOST_CHECK(pushdata1Stack == directStack);
|
||||
|
||||
vector<vector<unsigned char> > pushdata2Stack;
|
||||
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0));
|
||||
BOOST_CHECK(pushdata2Stack == directStack);
|
||||
|
||||
vector<vector<unsigned char> > pushdata4Stack;
|
||||
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0));
|
||||
BOOST_CHECK(pushdata4Stack == directStack);
|
||||
}
|
||||
|
||||
CScript
|
||||
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
|
||||
{
|
||||
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL);
|
||||
|
||||
CScript result;
|
||||
//
|
||||
// NOTE: CHECKMULTISIG has an unfortunate bug; it requires
|
||||
// one extra item on the stack, before the signatures.
|
||||
// Putting OP_0 on the stack is the workaround;
|
||||
// fixing the bug would mean splitting the blockchain (old
|
||||
// clients would not accept new CHECKMULTISIG transactions,
|
||||
// and vice-versa)
|
||||
//
|
||||
result << OP_0;
|
||||
BOOST_FOREACH(CKey key, keys)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
BOOST_CHECK(key.Sign(hash, vchSig));
|
||||
vchSig.push_back((unsigned char)SIGHASH_ALL);
|
||||
result << vchSig;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
CScript
|
||||
sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction)
|
||||
{
|
||||
std::vector<CKey> keys;
|
||||
keys.push_back(key);
|
||||
return sign_multisig(scriptPubKey, keys, transaction);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
||||
{
|
||||
CKey key1, key2, key3;
|
||||
key1.MakeNewKey(true);
|
||||
key2.MakeNewKey(false);
|
||||
key3.MakeNewKey(true);
|
||||
|
||||
CScript scriptPubKey12;
|
||||
scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
|
||||
|
||||
CTransaction txFrom12;
|
||||
txFrom12.vout.resize(1);
|
||||
txFrom12.vout[0].scriptPubKey = scriptPubKey12;
|
||||
|
||||
CTransaction txTo12;
|
||||
txTo12.vin.resize(1);
|
||||
txTo12.vout.resize(1);
|
||||
txTo12.vin[0].prevout.n = 0;
|
||||
txTo12.vin[0].prevout.hash = txFrom12.GetHash();
|
||||
txTo12.vout[0].nValue = 1;
|
||||
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0));
|
||||
txTo12.vout[0].nValue = 2;
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0));
|
||||
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, 0));
|
||||
|
||||
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, 0));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||
{
|
||||
CKey key1, key2, key3, key4;
|
||||
key1.MakeNewKey(true);
|
||||
key2.MakeNewKey(false);
|
||||
key3.MakeNewKey(true);
|
||||
key4.MakeNewKey(false);
|
||||
|
||||
CScript scriptPubKey23;
|
||||
scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
|
||||
|
||||
CTransaction txFrom23;
|
||||
txFrom23.vout.resize(1);
|
||||
txFrom23.vout[0].scriptPubKey = scriptPubKey23;
|
||||
|
||||
CTransaction txTo23;
|
||||
txTo23.vin.resize(1);
|
||||
txTo23.vout.resize(1);
|
||||
txTo23.vin[0].prevout.n = 0;
|
||||
txTo23.vin[0].prevout.hash = txFrom23.GetHash();
|
||||
txTo23.vout[0].nValue = 1;
|
||||
|
||||
std::vector<CKey> keys;
|
||||
keys.push_back(key1); keys.push_back(key2);
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key3);
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key3);
|
||||
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
|
||||
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
|
||||
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
|
||||
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
|
||||
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
|
||||
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, 0));
|
||||
|
||||
keys.clear(); // Must have signatures
|
||||
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, 0));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
{
|
||||
// Test the CombineSignatures function
|
||||
CBasicKeyStore keystore;
|
||||
vector<CKey> keys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(i%2 == 1);
|
||||
keys.push_back(key);
|
||||
keystore.AddKey(key);
|
||||
}
|
||||
|
||||
CTransaction txFrom;
|
||||
txFrom.vout.resize(1);
|
||||
txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID());
|
||||
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
|
||||
CTransaction txTo;
|
||||
txTo.vin.resize(1);
|
||||
txTo.vout.resize(1);
|
||||
txTo.vin[0].prevout.n = 0;
|
||||
txTo.vin[0].prevout.hash = txFrom.GetHash();
|
||||
CScript& scriptSig = txTo.vin[0].scriptSig;
|
||||
txTo.vout[0].nValue = 1;
|
||||
|
||||
CScript empty;
|
||||
CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty);
|
||||
BOOST_CHECK(combined.empty());
|
||||
|
||||
// Single signature case:
|
||||
SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
CScript scriptSigCopy = scriptSig;
|
||||
// Signing again will give a different, valid signature:
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);
|
||||
|
||||
// P2SH, single-signature case:
|
||||
CScript pkSingle; pkSingle << keys[0].GetPubKey() << OP_CHECKSIG;
|
||||
keystore.AddCScript(pkSingle);
|
||||
scriptPubKey.SetDestination(pkSingle.GetID());
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
scriptSigCopy = scriptSig;
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);
|
||||
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
|
||||
scriptSigCopy = CScript() << OP_0 << static_cast<vector<unsigned char> >(pkSingle);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
|
||||
// Hardest case: Multisig 2-of-3
|
||||
scriptPubKey.SetMultisig(2, keys);
|
||||
keystore.AddCScript(scriptPubKey);
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
|
||||
// A couple of partially-signed versions:
|
||||
vector<unsigned char> sig1;
|
||||
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL);
|
||||
BOOST_CHECK(keys[0].Sign(hash1, sig1));
|
||||
sig1.push_back(SIGHASH_ALL);
|
||||
vector<unsigned char> sig2;
|
||||
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE);
|
||||
BOOST_CHECK(keys[1].Sign(hash2, sig2));
|
||||
sig2.push_back(SIGHASH_NONE);
|
||||
vector<unsigned char> sig3;
|
||||
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE);
|
||||
BOOST_CHECK(keys[2].Sign(hash3, sig3));
|
||||
sig3.push_back(SIGHASH_SINGLE);
|
||||
|
||||
// Not fussy about order (or even existence) of placeholders or signatures:
|
||||
CScript partial1a = CScript() << OP_0 << sig1 << OP_0;
|
||||
CScript partial1b = CScript() << OP_0 << OP_0 << sig1;
|
||||
CScript partial2a = CScript() << OP_0 << sig2;
|
||||
CScript partial2b = CScript() << sig2 << OP_0;
|
||||
CScript partial3a = CScript() << sig3;
|
||||
CScript partial3b = CScript() << OP_0 << OP_0 << sig3;
|
||||
CScript partial3c = CScript() << OP_0 << sig3 << OP_0;
|
||||
CScript complete12 = CScript() << OP_0 << sig1 << sig2;
|
||||
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
|
||||
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
|
||||
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b);
|
||||
BOOST_CHECK(combined == partial1a);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a);
|
||||
BOOST_CHECK(combined == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial1a);
|
||||
BOOST_CHECK(combined == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1b, partial2b);
|
||||
BOOST_CHECK(combined == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial1b);
|
||||
BOOST_CHECK(combined == complete13);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial3a);
|
||||
BOOST_CHECK(combined == complete23);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial2b);
|
||||
BOOST_CHECK(combined == complete23);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial3a);
|
||||
BOOST_CHECK(combined == partial3c);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
60
src/test/sigopcount_tests.cpp
Normal file
60
src/test/sigopcount_tests.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <vector>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "script.h"
|
||||
#include "key.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Helpers:
|
||||
static std::vector<unsigned char>
|
||||
Serialize(const CScript& s)
|
||||
{
|
||||
std::vector<unsigned char> sSerialized(s);
|
||||
return sSerialized;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(sigopcount_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(GetSigOpCount)
|
||||
{
|
||||
// Test CScript::GetSigOpCount()
|
||||
CScript s1;
|
||||
BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0);
|
||||
BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0);
|
||||
|
||||
uint160 dummy;
|
||||
s1 << OP_1 << dummy << dummy << OP_2 << OP_CHECKMULTISIG;
|
||||
BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2);
|
||||
s1 << OP_IF << OP_CHECKSIG << OP_ENDIF;
|
||||
BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3);
|
||||
BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21);
|
||||
|
||||
CScript p2sh;
|
||||
p2sh.SetDestination(s1.GetID());
|
||||
CScript scriptSig;
|
||||
scriptSig << OP_0 << Serialize(s1);
|
||||
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3);
|
||||
|
||||
std::vector<CKey> keys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CKey k;
|
||||
k.MakeNewKey(true);
|
||||
keys.push_back(k);
|
||||
}
|
||||
CScript s2;
|
||||
s2.SetMultisig(1, keys);
|
||||
BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3);
|
||||
BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20);
|
||||
|
||||
p2sh.SetDestination(s2.GetID());
|
||||
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0);
|
||||
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0);
|
||||
CScript scriptSig2;
|
||||
scriptSig2 << OP_1 << dummy << dummy << Serialize(s2);
|
||||
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
38
src/test/test_bitcoin.cpp
Normal file
38
src/test/test_bitcoin.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#define BOOST_TEST_MODULE Bitcoin Test Suite
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
|
||||
CWallet* pwalletMain;
|
||||
CClientUIInterface uiInterface;
|
||||
|
||||
extern bool fPrintToConsole;
|
||||
extern void noui_connect();
|
||||
|
||||
struct TestingSetup {
|
||||
TestingSetup() {
|
||||
fPrintToConsole = true; // don't want to write to debug.log file
|
||||
noui_connect();
|
||||
pwalletMain = new CWallet();
|
||||
RegisterWallet(pwalletMain);
|
||||
}
|
||||
~TestingSetup()
|
||||
{
|
||||
delete pwalletMain;
|
||||
pwalletMain = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_GLOBAL_FIXTURE(TestingSetup);
|
||||
|
||||
void Shutdown(void* parg)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void StartShutdown()
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
120
src/test/transaction_tests.cpp
Normal file
120
src/test/transaction_tests.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(transaction_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
||||
{
|
||||
// Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
|
||||
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
|
||||
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
||||
CTransaction tx;
|
||||
stream >> tx;
|
||||
BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized 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;
|
||||
inputsRet[dummyTransactions[0].GetHash()] = make_pair(CTxIndex(), dummyTransactions[0]);
|
||||
|
||||
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());
|
||||
inputsRet[dummyTransactions[1].GetHash()] = make_pair(CTxIndex(), dummyTransactions[1]);
|
||||
|
||||
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;
|
||||
|
||||
BOOST_CHECK_THROW(t1.AreInputsStandard(missingInputs), runtime_error);
|
||||
BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
18
src/test/uint160_tests.cpp
Normal file
18
src/test/uint160_tests.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "uint256.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(uint160_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(uint160_equality)
|
||||
{
|
||||
uint160 num1 = 10;
|
||||
uint160 num2 = 11;
|
||||
BOOST_CHECK(num1+1 == num2);
|
||||
|
||||
uint64 num3 = 10;
|
||||
BOOST_CHECK(num1 == num3);
|
||||
BOOST_CHECK(num1+num2 == num3+num2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
18
src/test/uint256_tests.cpp
Normal file
18
src/test/uint256_tests.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "uint256.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(uint256_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(uint256_equality)
|
||||
{
|
||||
uint256 num1 = 10;
|
||||
uint256 num2 = 11;
|
||||
BOOST_CHECK(num1+1 == num2);
|
||||
|
||||
uint64 num3 = 10;
|
||||
BOOST_CHECK(num1 == num3);
|
||||
BOOST_CHECK(num1+num2 == num3+num2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
262
src/test/util_tests.cpp
Normal file
262
src/test/util_tests.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
#include <vector>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(util_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_criticalsection)
|
||||
{
|
||||
CCriticalSection cs;
|
||||
|
||||
do {
|
||||
LOCK(cs);
|
||||
break;
|
||||
|
||||
BOOST_ERROR("break was swallowed!");
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
TRY_LOCK(cs, lockTest);
|
||||
if (lockTest)
|
||||
break;
|
||||
|
||||
BOOST_ERROR("break was swallowed!");
|
||||
} while(0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_MedianFilter)
|
||||
{
|
||||
CMedianFilter<int> filter(5, 15);
|
||||
|
||||
BOOST_CHECK_EQUAL(filter.median(), 15);
|
||||
|
||||
filter.input(20); // [15 20]
|
||||
BOOST_CHECK_EQUAL(filter.median(), 17);
|
||||
|
||||
filter.input(30); // [15 20 30]
|
||||
BOOST_CHECK_EQUAL(filter.median(), 20);
|
||||
|
||||
filter.input(3); // [3 15 20 30]
|
||||
BOOST_CHECK_EQUAL(filter.median(), 17);
|
||||
|
||||
filter.input(7); // [3 7 15 20 30]
|
||||
BOOST_CHECK_EQUAL(filter.median(), 15);
|
||||
|
||||
filter.input(18); // [3 7 18 20 30]
|
||||
BOOST_CHECK_EQUAL(filter.median(), 18);
|
||||
|
||||
filter.input(0); // [0 3 7 18 30]
|
||||
BOOST_CHECK_EQUAL(filter.median(), 7);
|
||||
}
|
||||
|
||||
static const unsigned char ParseHex_expected[65] = {
|
||||
0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,
|
||||
0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,
|
||||
0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12,
|
||||
0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
|
||||
0x5f
|
||||
};
|
||||
BOOST_AUTO_TEST_CASE(util_ParseHex)
|
||||
{
|
||||
std::vector<unsigned char> result;
|
||||
std::vector<unsigned char> expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected));
|
||||
// Basic test vector
|
||||
result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
|
||||
|
||||
// Spaces between bytes must be supported
|
||||
result = ParseHex("12 34 56 78");
|
||||
BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
|
||||
|
||||
// Stop parsing at invalid value
|
||||
result = ParseHex("1234 invalid 1234");
|
||||
BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_HexStr)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(
|
||||
HexStr(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)),
|
||||
"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
HexStr(ParseHex_expected, ParseHex_expected + 5, true),
|
||||
"04 67 8a fd b0");
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
HexStr(ParseHex_expected, ParseHex_expected, true),
|
||||
"");
|
||||
|
||||
std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
HexStr(ParseHex_vec, true),
|
||||
"04 67 8a fd b0");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00");
|
||||
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07");
|
||||
// Formats used within Bitcoin
|
||||
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17");
|
||||
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_ParseParameters)
|
||||
{
|
||||
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
|
||||
|
||||
ParseParameters(0, (char**)argv_test);
|
||||
BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
|
||||
|
||||
ParseParameters(1, (char**)argv_test);
|
||||
BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
|
||||
|
||||
ParseParameters(5, (char**)argv_test);
|
||||
// expectation: -ignored is ignored (program name argument),
|
||||
// -a, -b and -ccc end up in map, -d ignored because it is after
|
||||
// a non-option argument (non-GNU option parsing)
|
||||
BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3);
|
||||
BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc")
|
||||
&& !mapArgs.count("f") && !mapArgs.count("-d"));
|
||||
BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc")
|
||||
&& !mapMultiArgs.count("f") && !mapMultiArgs.count("-d"));
|
||||
|
||||
BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple");
|
||||
BOOST_CHECK(mapMultiArgs["-ccc"].size() == 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_GetArg)
|
||||
{
|
||||
mapArgs.clear();
|
||||
mapArgs["strtest1"] = "string...";
|
||||
// strtest2 undefined on purpose
|
||||
mapArgs["inttest1"] = "12345";
|
||||
mapArgs["inttest2"] = "81985529216486895";
|
||||
// inttest3 undefined on purpose
|
||||
mapArgs["booltest1"] = "";
|
||||
// booltest2 undefined on purpose
|
||||
mapArgs["booltest3"] = "0";
|
||||
mapArgs["booltest4"] = "1";
|
||||
|
||||
BOOST_CHECK_EQUAL(GetArg("strtest1", "default"), "string...");
|
||||
BOOST_CHECK_EQUAL(GetArg("strtest2", "default"), "default");
|
||||
BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345);
|
||||
BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL);
|
||||
BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1);
|
||||
BOOST_CHECK_EQUAL(GetBoolArg("booltest1"), true);
|
||||
BOOST_CHECK_EQUAL(GetBoolArg("booltest2"), false);
|
||||
BOOST_CHECK_EQUAL(GetBoolArg("booltest3"), false);
|
||||
BOOST_CHECK_EQUAL(GetBoolArg("booltest4"), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_WildcardMatch)
|
||||
{
|
||||
BOOST_CHECK(WildcardMatch("127.0.0.1", "*"));
|
||||
BOOST_CHECK(WildcardMatch("127.0.0.1", "127.*"));
|
||||
BOOST_CHECK(WildcardMatch("abcdef", "a?cde?"));
|
||||
BOOST_CHECK(!WildcardMatch("abcdef", "a?cde??"));
|
||||
BOOST_CHECK(WildcardMatch("abcdef", "a*f"));
|
||||
BOOST_CHECK(!WildcardMatch("abcdef", "a*x"));
|
||||
BOOST_CHECK(WildcardMatch("", "*"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_FormatMoney)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
|
||||
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_ParseMoney)
|
||||
{
|
||||
int64 ret = 0;
|
||||
BOOST_CHECK(ParseMoney("0.0", ret));
|
||||
BOOST_CHECK_EQUAL(ret, 0);
|
||||
|
||||
BOOST_CHECK(ParseMoney("12345.6789", ret));
|
||||
BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789);
|
||||
|
||||
BOOST_CHECK(ParseMoney("100000000.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*100000000);
|
||||
BOOST_CHECK(ParseMoney("10000000.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*10000000);
|
||||
BOOST_CHECK(ParseMoney("1000000.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*1000000);
|
||||
BOOST_CHECK(ParseMoney("100000.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*100000);
|
||||
BOOST_CHECK(ParseMoney("10000.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*10000);
|
||||
BOOST_CHECK(ParseMoney("1000.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*1000);
|
||||
BOOST_CHECK(ParseMoney("100.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*100);
|
||||
BOOST_CHECK(ParseMoney("10.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN*10);
|
||||
BOOST_CHECK(ParseMoney("1.00", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN);
|
||||
BOOST_CHECK(ParseMoney("0.1", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/10);
|
||||
BOOST_CHECK(ParseMoney("0.01", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/100);
|
||||
BOOST_CHECK(ParseMoney("0.001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/1000);
|
||||
BOOST_CHECK(ParseMoney("0.0001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/10000);
|
||||
BOOST_CHECK(ParseMoney("0.00001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/100000);
|
||||
BOOST_CHECK(ParseMoney("0.000001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/1000000);
|
||||
BOOST_CHECK(ParseMoney("0.0000001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/10000000);
|
||||
BOOST_CHECK(ParseMoney("0.00000001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/100000000);
|
||||
|
||||
// Attempted 63 bit overflow should fail
|
||||
BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_IsHex)
|
||||
{
|
||||
BOOST_CHECK(IsHex("00"));
|
||||
BOOST_CHECK(IsHex("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
|
||||
BOOST_CHECK(IsHex("ff"));
|
||||
BOOST_CHECK(IsHex("FF"));
|
||||
|
||||
BOOST_CHECK(!IsHex(""));
|
||||
BOOST_CHECK(!IsHex("0"));
|
||||
BOOST_CHECK(!IsHex("a"));
|
||||
BOOST_CHECK(!IsHex("eleven"));
|
||||
BOOST_CHECK(!IsHex("00xx00"));
|
||||
BOOST_CHECK(!IsHex("0x0000"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
295
src/test/wallet_tests.cpp
Normal file
295
src/test/wallet_tests.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
|
||||
// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles
|
||||
#define RUN_TESTS 100
|
||||
|
||||
// some tests fail 1% of the time due to bad luck.
|
||||
// we repeat those tests this many times and only complain if all iterations of the test fail
|
||||
#define RANDOM_REPEATS 5
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef set<pair<const CWalletTx*,unsigned int> > CoinSet;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(wallet_tests)
|
||||
|
||||
static CWallet wallet;
|
||||
static vector<COutput> vCoins;
|
||||
|
||||
static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
|
||||
{
|
||||
static int i;
|
||||
CTransaction* tx = new CTransaction;
|
||||
tx->nLockTime = i++; // so all transactions get different hashes
|
||||
tx->vout.resize(nInput+1);
|
||||
tx->vout[nInput].nValue = nValue;
|
||||
CWalletTx* wtx = new CWalletTx(&wallet, *tx);
|
||||
delete tx;
|
||||
if (fIsFromMe)
|
||||
{
|
||||
// IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
|
||||
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
|
||||
wtx->vin.resize(1);
|
||||
wtx->fDebitCached = true;
|
||||
wtx->nDebitCached = 1;
|
||||
}
|
||||
COutput output(wtx, nInput, nAge);
|
||||
vCoins.push_back(output);
|
||||
}
|
||||
|
||||
static void empty_wallet(void)
|
||||
{
|
||||
BOOST_FOREACH(COutput output, vCoins)
|
||||
delete output.tx;
|
||||
vCoins.clear();
|
||||
}
|
||||
|
||||
static bool equal_sets(CoinSet a, CoinSet b)
|
||||
{
|
||||
pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin());
|
||||
return ret.first == a.end() && ret.second == b.end();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
{
|
||||
static CoinSet setCoinsRet, setCoinsRet2;
|
||||
static int64 nValueRet;
|
||||
|
||||
// test multiple times to allow for differences in the shuffle order
|
||||
for (int i = 0; i < RUN_TESTS; i++)
|
||||
{
|
||||
empty_wallet();
|
||||
|
||||
// with an empty wallet we can't even pay one cent
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
add_coin(1*CENT, 4); // add a new 1 cent coin
|
||||
|
||||
// with a new 1 cent coin, we still can't find a mature 1 cent
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
// but we can find a new 1 cent
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
|
||||
|
||||
add_coin(2*CENT); // add a mature 2 cent coin
|
||||
|
||||
// we can't make 3 cents of mature coins
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
// we can make 3 cents of new coins
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
|
||||
|
||||
add_coin(5*CENT); // add a mature 5 cent coin,
|
||||
add_coin(10*CENT, 3, true); // a new 10 cent coin sent from one of our own addresses
|
||||
add_coin(20*CENT); // and a mature 20 cent coin
|
||||
|
||||
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
|
||||
|
||||
// we can't make 38 cents only if we disallow new coins:
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
// we can't even make 37 cents if we don't allow new coins even if they're from us
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet));
|
||||
// but we can make 37 cents if we accept new coins from ourself
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
|
||||
// and we can make 38 cents if we accept all new coins
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
|
||||
|
||||
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
|
||||
|
||||
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2);
|
||||
|
||||
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(nValueRet == 8 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3);
|
||||
|
||||
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
// now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin
|
||||
empty_wallet();
|
||||
|
||||
add_coin( 6*CENT);
|
||||
add_coin( 7*CENT);
|
||||
add_coin( 8*CENT);
|
||||
add_coin(20*CENT);
|
||||
add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total
|
||||
|
||||
// check that we have 71 and not 72
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
|
||||
|
||||
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3);
|
||||
|
||||
add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30
|
||||
|
||||
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); // because in the event of a tie, the biggest coin wins
|
||||
|
||||
// now try making 11 cents. we should get 5+6
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2);
|
||||
|
||||
// check that the smallest bigger coin is used
|
||||
add_coin( 1*COIN);
|
||||
add_coin( 2*COIN);
|
||||
add_coin( 3*COIN);
|
||||
add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 bitcoin in 1 coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 bitcoins in 1 coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
// empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance
|
||||
empty_wallet();
|
||||
add_coin(0.1*CENT);
|
||||
add_coin(0.2*CENT);
|
||||
add_coin(0.3*CENT);
|
||||
add_coin(0.4*CENT);
|
||||
add_coin(0.5*CENT);
|
||||
|
||||
// try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents
|
||||
// we'll get sub-cent change whatever happens, so can expect 1.0 exactly
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
|
||||
|
||||
// but if we add a bigger coin, making it possible to avoid sub-cent change, things change:
|
||||
add_coin(1111*CENT);
|
||||
|
||||
// try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
|
||||
|
||||
// if we add more sub-cent coins:
|
||||
add_coin(0.6*CENT);
|
||||
add_coin(0.7*CENT);
|
||||
|
||||
// and try again to make 1.0 cents, we can still make 1.0 cents
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
|
||||
|
||||
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
|
||||
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
|
||||
empty_wallet();
|
||||
for (int i = 0; i < 20; i++)
|
||||
add_coin(50000 * COIN);
|
||||
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10); // in ten coins
|
||||
|
||||
// if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0),
|
||||
// we need to try finding an exact subset anyway
|
||||
|
||||
// sometimes it will fail, and so we use the next biggest coin:
|
||||
empty_wallet();
|
||||
add_coin(0.5 * CENT);
|
||||
add_coin(0.6 * CENT);
|
||||
add_coin(0.7 * CENT);
|
||||
add_coin(1111 * CENT);
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)
|
||||
empty_wallet();
|
||||
add_coin(0.4 * CENT);
|
||||
add_coin(0.6 * CENT);
|
||||
add_coin(0.8 * CENT);
|
||||
add_coin(1111 * CENT);
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); // in two coins 0.4+0.6
|
||||
|
||||
// test avoiding sub-cent change
|
||||
empty_wallet();
|
||||
add_coin(0.0005 * COIN);
|
||||
add_coin(0.01 * COIN);
|
||||
add_coin(1 * COIN);
|
||||
|
||||
// trying to make 1.0001 from these three coins
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3);
|
||||
|
||||
// but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2);
|
||||
|
||||
// test randomness
|
||||
{
|
||||
empty_wallet();
|
||||
for (int i2 = 0; i2 < 100; i2++)
|
||||
add_coin(COIN);
|
||||
|
||||
// picking 50 from 100 coins doesn't depend on the shuffle,
|
||||
// but does depend on randomness in the stochastic approximation code
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
|
||||
|
||||
int fails = 0;
|
||||
for (int i = 0; i < RANDOM_REPEATS; i++)
|
||||
{
|
||||
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
|
||||
// run the test RANDOM_REPEATS times and only complain if all of them fail
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
if (equal_sets(setCoinsRet, setCoinsRet2))
|
||||
fails++;
|
||||
}
|
||||
BOOST_CHECK_NE(fails, RANDOM_REPEATS);
|
||||
|
||||
// add 75 cents in small change. not enough to make 90 cents,
|
||||
// then try making 90 cents. there are multiple competing "smallest bigger" coins,
|
||||
// one of which should be picked at random
|
||||
add_coin( 5*CENT); add_coin(10*CENT); add_coin(15*CENT); add_coin(20*CENT); add_coin(25*CENT);
|
||||
|
||||
fails = 0;
|
||||
for (int i = 0; i < RANDOM_REPEATS; i++)
|
||||
{
|
||||
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
|
||||
// run the test RANDOM_REPEATS times and only complain if all of them fail
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
if (equal_sets(setCoinsRet, setCoinsRet2))
|
||||
fails++;
|
||||
}
|
||||
BOOST_CHECK_NE(fails, RANDOM_REPEATS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Reference in New Issue
Block a user