aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/Checkpoints_tests.cpp34
-rw-r--r--src/test/DoS_tests.cpp318
-rw-r--r--src/test/Makefile.am74
-rw-r--r--src/test/README21
-rw-r--r--src/test/accounting_tests.cpp127
-rw-r--r--src/test/alert_tests.cpp179
-rw-r--r--src/test/allocator_tests.cpp115
-rw-r--r--src/test/base32_tests.cpp22
-rw-r--r--src/test/base58_tests.cpp268
-rw-r--r--src/test/base64_tests.cpp22
-rw-r--r--src/test/bignum_tests.cpp187
-rw-r--r--src/test/bip32_tests.cpp116
-rw-r--r--src/test/bloom_tests.cpp450
-rw-r--r--src/test/canonical_tests.cpp92
-rw-r--r--src/test/checkblock_tests.cpp64
-rw-r--r--src/test/compress_tests.cpp62
-rw-r--r--src/test/data/alertTests.rawbin0 -> 1279 bytes
-rw-r--r--src/test/data/base58_encode_decode.json14
-rw-r--r--src/test/data/base58_keys_invalid.json152
-rw-r--r--src/test/data/base58_keys_valid.json452
-rw-r--r--src/test/data/script_invalid.json329
-rw-r--r--src/test/data/script_valid.json415
-rw-r--r--src/test/data/sig_canonical.json7
-rw-r--r--src/test/data/sig_noncanonical.json22
-rw-r--r--src/test/data/tx_invalid.json74
-rw-r--r--src/test/data/tx_valid.json96
-rw-r--r--src/test/getarg_tests.cpp158
-rw-r--r--src/test/hash_tests.cpp47
-rw-r--r--src/test/hmac_tests.cpp127
-rw-r--r--src/test/key_tests.cpp143
-rw-r--r--src/test/miner_tests.cpp237
-rw-r--r--src/test/mruset_tests.cpp93
-rw-r--r--src/test/multisig_tests.cpp294
-rw-r--r--src/test/netbase_tests.cpp101
-rw-r--r--src/test/pmt_tests.cpp103
-rw-r--r--src/test/rpc_tests.cpp137
-rw-r--r--src/test/rpc_wallet_tests.cpp82
-rw-r--r--src/test/script_P2SH_tests.cpp341
-rw-r--r--src/test/script_tests.cpp441
-rw-r--r--src/test/serialize_tests.cpp159
-rw-r--r--src/test/sighash_tests.cpp120
-rw-r--r--src/test/sigopcount_tests.cpp64
-rw-r--r--src/test/test_bitcoin.cpp82
-rw-r--r--src/test/transaction_tests.cpp311
-rw-r--r--src/test/uint256_tests.cpp633
-rw-r--r--src/test/util_tests.cpp341
-rw-r--r--src/test/wallet_tests.cpp300
47 files changed, 8026 insertions, 0 deletions
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
new file mode 100644
index 000000000..78b0236b7
--- /dev/null
+++ b/src/test/Checkpoints_tests.cpp
@@ -0,0 +1,34 @@
+//
+// Unit tests for block-chain checkpoints
+//
+
+#include "checkpoints.h"
+
+#include "uint256.h"
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(Checkpoints_tests)
+
+BOOST_AUTO_TEST_CASE(sanity)
+{
+ uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
+ uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
+ BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111));
+ BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444));
+
+
+ // Wrong hashes at checkpoints should fail:
+ BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444));
+ BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111));
+
+ // ... but any hash not at a checkpoint should succeed:
+ BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444));
+ BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111));
+
+ BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
new file mode 100644
index 000000000..fbca09b4d
--- /dev/null
+++ b/src/test/DoS_tests.cpp
@@ -0,0 +1,318 @@
+//
+// Unit tests for denial-of-service detection/prevention code
+//
+
+
+
+#include "bignum.h"
+#include "keystore.h"
+#include "main.h"
+#include "net.h"
+#include "script.h"
+#include "serialize.h"
+
+#include <stdint.h>
+
+#include <boost/assign/list_of.hpp> // for 'map_list_of()'
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+// Tests this internal-to-main.cpp method:
+extern bool AddOrphanTx(const CTransaction& tx);
+extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
+extern void Misbehaving(NodeId nodeid, int howmuch);
+extern std::map<uint256, CTransaction> mapOrphanTransactions;
+extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
+
+CService ip(uint32_t i)
+{
+ struct in_addr s;
+ s.s_addr = i;
+ return CService(CNetAddr(s), Params().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.nVersion = 1;
+ Misbehaving(dummyNode1.GetId(), 100); // Should get banned
+ SendMessages(&dummyNode1, false);
+ 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.nVersion = 1;
+ Misbehaving(dummyNode2.GetId(), 50);
+ SendMessages(&dummyNode2, false);
+ BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
+ BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
+ Misbehaving(dummyNode2.GetId(), 50);
+ SendMessages(&dummyNode2, false);
+ 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.nVersion = 1;
+ Misbehaving(dummyNode1.GetId(), 100);
+ SendMessages(&dummyNode1, false);
+ BOOST_CHECK(!CNode::IsBanned(addr1));
+ Misbehaving(dummyNode1.GetId(), 10);
+ SendMessages(&dummyNode1, false);
+ BOOST_CHECK(!CNode::IsBanned(addr1));
+ Misbehaving(dummyNode1.GetId(), 1);
+ SendMessages(&dummyNode1, false);
+ BOOST_CHECK(CNode::IsBanned(addr1));
+ mapArgs.erase("-banscore");
+}
+
+BOOST_AUTO_TEST_CASE(DoS_bantime)
+{
+ CNode::ClearBanned();
+ int64_t nStartTime = GetTime();
+ SetMockTime(nStartTime); // Overrides future calls to GetTime()
+
+ CAddress addr(ip(0xa0b0c001));
+ CNode dummyNode(INVALID_SOCKET, addr, "", true);
+ dummyNode.nVersion = 1;
+
+ Misbehaving(dummyNode.GetId(), 100);
+ SendMessages(&dummyNode, false);
+ 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_t time1, unsigned int nbits2, int64_t time2)\
+{
+ if (time1 > time2)
+ return CheckNBits(nbits2, time2, nbits1, time1);
+ int64_t 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 block chain.
+ // These are the block-chain checkpoint blocks
+ typedef std::map<int64_t, 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, CTransaction>::iterator it;
+ it = mapOrphanTransactions.lower_bound(GetRandHash());
+ if (it == mapOrphanTransactions.end())
+ it = mapOrphanTransactions.begin();
+ return it->second;
+}
+
+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());
+
+ AddOrphanTx(tx);
+ }
+
+ // ... 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);
+
+ AddOrphanTx(tx);
+ }
+
+ // 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;
+
+ BOOST_CHECK(!AddOrphanTx(tx));
+ }
+
+ // 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);
+ unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
+
+ // 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());
+
+ AddOrphanTx(tx);
+ }
+
+ // 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(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, 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(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, 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(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
+ BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, 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(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
+ mapArgs.erase("-maxsigcachesize");
+
+ LimitOrphanTxSize(0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
new file mode 100644
index 000000000..667e53c6b
--- /dev/null
+++ b/src/test/Makefile.am
@@ -0,0 +1,74 @@
+include $(top_srcdir)/src/Makefile.include
+
+AM_CPPFLAGS += -I$(top_srcdir)/src
+
+bin_PROGRAMS = test_bitcoin
+
+TESTS = test_bitcoin
+
+JSON_TEST_FILES = \
+ data/script_valid.json \
+ data/base58_keys_valid.json \
+ data/sig_canonical.json \
+ data/sig_noncanonical.json \
+ data/base58_encode_decode.json \
+ data/base58_keys_invalid.json \
+ data/script_invalid.json \
+ data/tx_invalid.json \
+ data/tx_valid.json
+
+RAW_TEST_FILES = data/alertTests.raw
+
+BUILT_SOURCES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
+
+# test_bitcoin binary #
+test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS)
+test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
+ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
+if ENABLE_WALLET
+test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
+endif
+test_bitcoin_LDADD += $(BDB_LIBS)
+
+test_bitcoin_SOURCES = \
+ alert_tests.cpp \
+ allocator_tests.cpp \
+ base32_tests.cpp \
+ base58_tests.cpp \
+ base64_tests.cpp \
+ bignum_tests.cpp \
+ bloom_tests.cpp \
+ canonical_tests.cpp \
+ checkblock_tests.cpp \
+ Checkpoints_tests.cpp \
+ compress_tests.cpp \
+ DoS_tests.cpp \
+ getarg_tests.cpp \
+ key_tests.cpp \
+ miner_tests.cpp \
+ mruset_tests.cpp \
+ multisig_tests.cpp \
+ netbase_tests.cpp \
+ pmt_tests.cpp \
+ rpc_tests.cpp \
+ script_P2SH_tests.cpp \
+ script_tests.cpp \
+ serialize_tests.cpp \
+ sigopcount_tests.cpp \
+ test_bitcoin.cpp \
+ transaction_tests.cpp \
+ uint256_tests.cpp \
+ util_tests.cpp \
+ sighash_tests.cpp \
+ $(JSON_TEST_FILES) $(RAW_TEST_FILES)
+
+if ENABLE_WALLET
+test_bitcoin_SOURCES += \
+ accounting_tests.cpp \
+ wallet_tests.cpp \
+ rpc_wallet_tests.cpp
+endif
+
+nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES)
+
+CLEANFILES = *.gcda *.gcno $(BUILT_SOURCES)
diff --git a/src/test/README b/src/test/README
new file mode 100644
index 000000000..77f7faa81
--- /dev/null
+++ b/src/test/README
@@ -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/
diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp
new file mode 100644
index 000000000..5f79436e4
--- /dev/null
+++ b/src/test/accounting_tests.cpp
@@ -0,0 +1,127 @@
+
+
+#include "wallet.h"
+#include "walletdb.h"
+
+#include <stdint.h>
+
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+extern CWallet* pwalletMain;
+
+BOOST_AUTO_TEST_SUITE(accounting_tests)
+
+static void
+GetResults(CWalletDB& walletdb, std::map<int64_t, CAccountingEntry>& results)
+{
+ std::list<CAccountingEntry> aes;
+
+ results.clear();
+ BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK);
+ walletdb.ListAccountCreditDebit("", aes);
+ BOOST_FOREACH(CAccountingEntry& ae, aes)
+ {
+ results[ae.nOrderPos] = ae;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(acc_orderupgrade)
+{
+ CWalletDB walletdb(pwalletMain->strWalletFile);
+ std::vector<CWalletTx*> vpwtx;
+ CWalletTx wtx;
+ CAccountingEntry ae;
+ std::map<int64_t, CAccountingEntry> results;
+
+ ae.strAccount = "";
+ ae.nCreditDebit = 1;
+ ae.nTime = 1333333333;
+ ae.strOtherAccount = "b";
+ ae.strComment = "";
+ walletdb.WriteAccountingEntry(ae);
+
+ wtx.mapValue["comment"] = "z";
+ pwalletMain->AddToWallet(wtx);
+ vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
+ vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
+ vpwtx[0]->nOrderPos = -1;
+
+ ae.nTime = 1333333336;
+ ae.strOtherAccount = "c";
+ walletdb.WriteAccountingEntry(ae);
+
+ GetResults(walletdb, results);
+
+ BOOST_CHECK(pwalletMain->nOrderPosNext == 3);
+ BOOST_CHECK(2 == results.size());
+ BOOST_CHECK(results[0].nTime == 1333333333);
+ BOOST_CHECK(results[0].strComment.empty());
+ BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
+ BOOST_CHECK(results[2].nTime == 1333333336);
+ BOOST_CHECK(results[2].strOtherAccount == "c");
+
+
+ ae.nTime = 1333333330;
+ ae.strOtherAccount = "d";
+ ae.nOrderPos = pwalletMain->IncOrderPosNext();
+ walletdb.WriteAccountingEntry(ae);
+
+ GetResults(walletdb, results);
+
+ BOOST_CHECK(results.size() == 3);
+ BOOST_CHECK(pwalletMain->nOrderPosNext == 4);
+ BOOST_CHECK(results[0].nTime == 1333333333);
+ BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
+ BOOST_CHECK(results[2].nTime == 1333333336);
+ BOOST_CHECK(results[3].nTime == 1333333330);
+ BOOST_CHECK(results[3].strComment.empty());
+
+
+ wtx.mapValue["comment"] = "y";
+ --wtx.nLockTime; // Just to change the hash :)
+ pwalletMain->AddToWallet(wtx);
+ vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
+ vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
+
+ wtx.mapValue["comment"] = "x";
+ --wtx.nLockTime; // Just to change the hash :)
+ pwalletMain->AddToWallet(wtx);
+ vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
+ vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
+ vpwtx[2]->nOrderPos = -1;
+
+ GetResults(walletdb, results);
+
+ BOOST_CHECK(results.size() == 3);
+ BOOST_CHECK(pwalletMain->nOrderPosNext == 6);
+ BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
+ BOOST_CHECK(results[1].nTime == 1333333333);
+ BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
+ BOOST_CHECK(results[3].nTime == 1333333336);
+ BOOST_CHECK(results[4].nTime == 1333333330);
+ BOOST_CHECK(results[4].strComment.empty());
+ BOOST_CHECK(5 == vpwtx[1]->nOrderPos);
+
+
+ ae.nTime = 1333333334;
+ ae.strOtherAccount = "e";
+ ae.nOrderPos = -1;
+ walletdb.WriteAccountingEntry(ae);
+
+ GetResults(walletdb, results);
+
+ BOOST_CHECK(results.size() == 4);
+ BOOST_CHECK(pwalletMain->nOrderPosNext == 7);
+ BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
+ BOOST_CHECK(results[1].nTime == 1333333333);
+ BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
+ BOOST_CHECK(results[3].nTime == 1333333336);
+ BOOST_CHECK(results[3].strComment.empty());
+ BOOST_CHECK(results[4].nTime == 1333333330);
+ BOOST_CHECK(results[4].strComment.empty());
+ BOOST_CHECK(results[5].nTime == 1333333334);
+ BOOST_CHECK(6 == vpwtx[1]->nOrderPos);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
new file mode 100644
index 000000000..a7e668222
--- /dev/null
+++ b/src/test/alert_tests.cpp
@@ -0,0 +1,179 @@
+//
+// Unit tests for alert system
+//
+
+#include "alert.h"
+#include "data/alertTests.raw.h"
+
+#include "serialize.h"
+#include "util.h"
+#include "version.h"
+
+#include <fstream>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+#if 0
+//
+// alertTests contains 7 alerts, generated with this code:
+// (SignAndSave code not shown, alert signing key is secret)
+//
+{
+ CAlert alert;
+ alert.nRelayUntil = 60;
+ alert.nExpiration = 24 * 60 * 60;
+ alert.nID = 1;
+ alert.nCancel = 0; // cancels previous messages up to this ID number
+ alert.nMinVer = 0; // These versions are protocol versions
+ alert.nMaxVer = 999001;
+ alert.nPriority = 1;
+ alert.strComment = "Alert comment";
+ alert.strStatusBar = "Alert 1";
+
+ SignAndSave(alert, "test/alertTests");
+
+ alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
+ alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
+ SignAndSave(alert, "test/alertTests");
+
+ alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
+ alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
+ SignAndSave(alert, "test/alertTests");
+
+ alert.setSubVer.clear();
+ ++alert.nID;
+ alert.nCancel = 1;
+ alert.nPriority = 100;
+ alert.strStatusBar = "Alert 2, cancels 1";
+ SignAndSave(alert, "test/alertTests");
+
+ alert.nExpiration += 60;
+ ++alert.nID;
+ SignAndSave(alert, "test/alertTests");
+
+ ++alert.nID;
+ alert.nMinVer = 11;
+ alert.nMaxVer = 22;
+ SignAndSave(alert, "test/alertTests");
+
+ ++alert.nID;
+ alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
+ alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
+ SignAndSave(alert, "test/alertTests");
+
+ ++alert.nID;
+ alert.nMinVer = 0;
+ alert.nMaxVer = 999999;
+ alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
+ alert.setSubVer.clear();
+ SignAndSave(alert, "test/alertTests");
+}
+#endif
+
+struct ReadAlerts
+{
+ ReadAlerts()
+ {
+ std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
+ CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
+ try {
+ while (stream.good())
+ {
+ CAlert alert;
+ stream >> alert;
+ alerts.push_back(alert);
+ }
+ }
+ catch (std::exception) { }
+ }
+ ~ReadAlerts() { }
+
+ static std::vector<std::string> read_lines(boost::filesystem::path filepath)
+ {
+ std::vector<std::string> result;
+
+ std::ifstream f(filepath.string().c_str());
+ std::string line;
+ while (std::getline(f,line))
+ result.push_back(line);
+
+ return result;
+ }
+
+ std::vector<CAlert> alerts;
+};
+
+BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
+
+
+BOOST_AUTO_TEST_CASE(AlertApplies)
+{
+ SetMockTime(11);
+
+ BOOST_FOREACH(const CAlert& alert, alerts)
+ {
+ BOOST_CHECK(alert.CheckSignature());
+ }
+
+ BOOST_CHECK(alerts.size() >= 3);
+
+ // Matches:
+ BOOST_CHECK(alerts[0].AppliesTo(1, ""));
+ BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
+ BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));
+
+ BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
+ BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));
+
+ BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
+ BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));
+
+ // Don't match:
+ BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
+ BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));
+
+ BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
+ BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
+ BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
+ BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
+ BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
+ BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
+ BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));
+
+ BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));
+
+ SetMockTime(0);
+}
+
+
+// This uses sh 'echo' to test the -alertnotify function, writing to a
+// /tmp file. So skip it on Windows:
+#ifndef WIN32
+BOOST_AUTO_TEST_CASE(AlertNotify)
+{
+ SetMockTime(11);
+
+ boost::filesystem::path temp = GetTempPath() / "alertnotify.txt";
+ boost::filesystem::remove(temp);
+
+ mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
+
+ BOOST_FOREACH(CAlert alert, alerts)
+ alert.ProcessAlert(false);
+
+ std::vector<std::string> r = read_lines(temp);
+ BOOST_CHECK_EQUAL(r.size(), 4u);
+ BOOST_CHECK_EQUAL(r[0], "Alert 1");
+ BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1");
+ BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1");
+ BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
+
+ boost::filesystem::remove(temp);
+
+ SetMockTime(0);
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
new file mode 100644
index 000000000..490dff87e
--- /dev/null
+++ b/src/test/allocator_tests.cpp
@@ -0,0 +1,115 @@
+
+
+#include "util.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(allocator_tests)
+
+// Dummy memory page locker for platform independent tests
+static const void *last_lock_addr, *last_unlock_addr;
+static size_t last_lock_len, last_unlock_len;
+class TestLocker
+{
+public:
+ bool Lock(const void *addr, size_t len)
+ {
+ last_lock_addr = addr;
+ last_lock_len = len;
+ return true;
+ }
+ bool Unlock(const void *addr, size_t len)
+ {
+ last_unlock_addr = addr;
+ last_unlock_len = len;
+ return true;
+ }
+};
+
+BOOST_AUTO_TEST_CASE(test_LockedPageManagerBase)
+{
+ const size_t test_page_size = 4096;
+ LockedPageManagerBase<TestLocker> lpm(test_page_size);
+ size_t addr;
+ last_lock_addr = last_unlock_addr = 0;
+ last_lock_len = last_unlock_len = 0;
+
+ /* Try large number of small objects */
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), 33);
+ addr += 33;
+ }
+ /* Try small number of page-sized objects, straddling two pages */
+ addr = test_page_size*100 + 53;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ /* Try small number of page-sized objects aligned to exactly one page */
+ addr = test_page_size*300;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ /* one very large object, straddling pages */
+ lpm.LockRange(reinterpret_cast<void*>(test_page_size*600+1), test_page_size*500);
+ BOOST_CHECK(last_lock_addr == reinterpret_cast<void*>(test_page_size*(600+500)));
+ /* one very large object, page aligned */
+ lpm.LockRange(reinterpret_cast<void*>(test_page_size*1200), test_page_size*500-1);
+ BOOST_CHECK(last_lock_addr == reinterpret_cast<void*>(test_page_size*(1200+500-1)));
+
+ BOOST_CHECK(lpm.GetLockedPageCount() == (
+ (1000*33+test_page_size-1)/test_page_size + // small objects
+ 101 + 100 + // page-sized objects
+ 501 + 500)); // large objects
+ BOOST_CHECK((last_lock_len & (test_page_size-1)) == 0); // always lock entire pages
+ BOOST_CHECK(last_unlock_len == 0); // nothing unlocked yet
+
+ /* And unlock again */
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), 33);
+ addr += 33;
+ }
+ addr = test_page_size*100 + 53;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ addr = test_page_size*300;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ lpm.UnlockRange(reinterpret_cast<void*>(test_page_size*600+1), test_page_size*500);
+ lpm.UnlockRange(reinterpret_cast<void*>(test_page_size*1200), test_page_size*500-1);
+
+ /* Check that everything is released */
+ BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+
+ /* A few and unlocks of size zero (should have no effect) */
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), 0);
+ addr += 1;
+ }
+ BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), 0);
+ addr += 1;
+ }
+ BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+ BOOST_CHECK((last_unlock_len & (test_page_size-1)) == 0); // always unlock entire pages
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
new file mode 100644
index 000000000..580e87f65
--- /dev/null
+++ b/src/test/base32_tests.cpp
@@ -0,0 +1,22 @@
+
+
+#include "util.h"
+
+#include <boost/test/unit_test.hpp>
+
+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()
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
new file mode 100644
index 000000000..84db99d81
--- /dev/null
+++ b/src/test/base58_tests.cpp
@@ -0,0 +1,268 @@
+#include "base58.h"
+
+#include "data/base58_encode_decode.json.h"
+#include "data/base58_keys_invalid.json.h"
+#include "data/base58_keys_valid.json.h"
+
+#include "key.h"
+#include "script.h"
+#include "uint256.h"
+#include "util.h"
+
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_utils.h"
+#include "json/json_spirit_writer_template.h"
+
+using namespace json_spirit;
+extern Array read_json(const std::string& jsondata);
+
+BOOST_AUTO_TEST_SUITE(base58_tests)
+
+// Goal: test low-level base58 encoding functionality
+BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
+{
+ Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ std::string strTest = write_string(tv, false);
+ if (test.size() < 2) // Allow for extra stuff (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
+ std::string base58string = test[1].get_str();
+ BOOST_CHECK_MESSAGE(
+ EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,
+ strTest);
+ }
+}
+
+// Goal: test low-level base58 decoding functionality
+BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
+{
+ Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ std::vector<unsigned char> result;
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ std::string strTest = write_string(tv, false);
+ if (test.size() < 2) // Allow for extra stuff (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ std::vector<unsigned char> expected = ParseHex(test[0].get_str());
+ std::string base58string = test[1].get_str();
+ BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest);
+ BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);
+ }
+
+ BOOST_CHECK(!DecodeBase58("invalid", result));
+}
+
+// Visitor to check address type
+class TestAddrTypeVisitor : public boost::static_visitor<bool>
+{
+private:
+ std::string exp_addrType;
+public:
+ TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { }
+ bool operator()(const CKeyID &id) const
+ {
+ return (exp_addrType == "pubkey");
+ }
+ bool operator()(const CScriptID &id) const
+ {
+ return (exp_addrType == "script");
+ }
+ bool operator()(const CNoDestination &no) const
+ {
+ return (exp_addrType == "none");
+ }
+};
+
+// Visitor to check address payload
+class TestPayloadVisitor : public boost::static_visitor<bool>
+{
+private:
+ std::vector<unsigned char> exp_payload;
+public:
+ TestPayloadVisitor(std::vector<unsigned char> &exp_payload) : exp_payload(exp_payload) { }
+ bool operator()(const CKeyID &id) const
+ {
+ uint160 exp_key(exp_payload);
+ return exp_key == id;
+ }
+ bool operator()(const CScriptID &id) const
+ {
+ uint160 exp_key(exp_payload);
+ return exp_key == id;
+ }
+ bool operator()(const CNoDestination &no) const
+ {
+ return exp_payload.size() == 0;
+ }
+};
+
+// Goal: check that parsed keys match test payload
+BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
+{
+ Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ std::vector<unsigned char> result;
+ CBitcoinSecret secret;
+ CBitcoinAddress addr;
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ std::string strTest = write_string(tv, false);
+ if (test.size() < 3) // Allow for extra stuff (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ std::string exp_base58string = test[0].get_str();
+ std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
+ const Object &metadata = test[2].get_obj();
+ bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
+ bool isTestnet = find_value(metadata, "isTestnet").get_bool();
+ if (isTestnet)
+ SelectParams(CChainParams::TESTNET);
+ else
+ SelectParams(CChainParams::MAIN);
+ if(isPrivkey)
+ {
+ bool isCompressed = find_value(metadata, "isCompressed").get_bool();
+ // Must be valid private key
+ // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
+ BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
+ BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
+ CKey privkey = secret.GetKey();
+ BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
+ BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
+
+ // Private key must be invalid public key
+ addr.SetString(exp_base58string);
+ BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
+ }
+ else
+ {
+ std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
+ // Must be valid public key
+ BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
+ BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
+ BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
+ CTxDestination dest = addr.Get();
+ BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
+
+ // Public key must be invalid private key
+ secret.SetString(exp_base58string);
+ BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
+ }
+ }
+ SelectParams(CChainParams::MAIN);
+}
+
+// Goal: check that generated keys match test vectors
+BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
+{
+ Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ std::vector<unsigned char> result;
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ std::string strTest = write_string(tv, false);
+ if (test.size() < 3) // Allow for extra stuff (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ std::string exp_base58string = test[0].get_str();
+ std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
+ const Object &metadata = test[2].get_obj();
+ bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
+ bool isTestnet = find_value(metadata, "isTestnet").get_bool();
+ if (isTestnet)
+ SelectParams(CChainParams::TESTNET);
+ else
+ SelectParams(CChainParams::MAIN);
+ if(isPrivkey)
+ {
+ bool isCompressed = find_value(metadata, "isCompressed").get_bool();
+ CKey key;
+ key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
+ assert(key.IsValid());
+ CBitcoinSecret secret;
+ secret.SetKey(key);
+ BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
+ }
+ else
+ {
+ std::string exp_addrType = find_value(metadata, "addrType").get_str();
+ CTxDestination dest;
+ if(exp_addrType == "pubkey")
+ {
+ dest = CKeyID(uint160(exp_payload));
+ }
+ else if(exp_addrType == "script")
+ {
+ dest = CScriptID(uint160(exp_payload));
+ }
+ else if(exp_addrType == "none")
+ {
+ dest = CNoDestination();
+ }
+ else
+ {
+ BOOST_ERROR("Bad addrtype: " << strTest);
+ continue;
+ }
+ CBitcoinAddress addrOut;
+ BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest);
+ BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
+ }
+ }
+
+ // Visiting a CNoDestination must fail
+ CBitcoinAddress dummyAddr;
+ CTxDestination nodest = CNoDestination();
+ BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest));
+
+ SelectParams(CChainParams::MAIN);
+}
+
+// Goal: check that base58 parsing code is robust against a variety of corrupted data
+BOOST_AUTO_TEST_CASE(base58_keys_invalid)
+{
+ Array tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
+ std::vector<unsigned char> result;
+ CBitcoinSecret secret;
+ CBitcoinAddress addr;
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ std::string strTest = write_string(tv, false);
+ if (test.size() < 1) // Allow for extra stuff (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ std::string exp_base58string = test[0].get_str();
+
+ // must be invalid as public and as private key
+ addr.SetString(exp_base58string);
+ BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
+ secret.SetString(exp_base58string);
+ BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
new file mode 100644
index 000000000..c59c29066
--- /dev/null
+++ b/src/test/base64_tests.cpp
@@ -0,0 +1,22 @@
+
+
+#include "util.h"
+
+#include <boost/test/unit_test.hpp>
+
+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()
diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp
new file mode 100644
index 000000000..9d67324c7
--- /dev/null
+++ b/src/test/bignum_tests.cpp
@@ -0,0 +1,187 @@
+#include "bignum.h"
+
+#include <limits>
+#include <stdint.h>
+
+#include <boost/test/unit_test.hpp>
+
+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_t 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_t 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_t>::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_t>::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_CASE(bignum_SetCompact)
+{
+ CBigNum num;
+ num.SetCompact(0);
+ BOOST_CHECK_EQUAL(num.GetHex(), "0");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0U);
+
+ num.SetCompact(0x00123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "0");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0U);
+
+ num.SetCompact(0x01123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "12");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U);
+
+ // Make sure that we don't generate compacts with the 0x00800000 bit set
+ num = 0x80;
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U);
+
+ num.SetCompact(0x01fedcba);
+ BOOST_CHECK_EQUAL(num.GetHex(), "-7e");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000U);
+
+ num.SetCompact(0x02123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "1234");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U);
+
+ num.SetCompact(0x03123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "123456");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U);
+
+ num.SetCompact(0x04123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "12345600");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U);
+
+ num.SetCompact(0x04923456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "-12345600");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456U);
+
+ num.SetCompact(0x05009234);
+ BOOST_CHECK_EQUAL(num.GetHex(), "92340000");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U);
+
+ num.SetCompact(0x20123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U);
+
+ num.SetCompact(0xff123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456U);
+}
+
+BOOST_AUTO_TEST_CASE(bignum_SetHex)
+{
+ std::string hexStr = "deecf97fd890808b9cc0f1b6a3e7a60b400f52710e6ad075b1340755bfa58cc9";
+ CBigNum num;
+ num.SetHex(hexStr);
+ BOOST_CHECK_EQUAL(num.GetHex(), hexStr);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
new file mode 100644
index 000000000..2bcca2433
--- /dev/null
+++ b/src/test/bip32_tests.cpp
@@ -0,0 +1,116 @@
+#include <boost/test/unit_test.hpp>
+
+#include "base58.h"
+#include "key.h"
+#include "uint256.h"
+#include "util.h"
+
+#include <string>
+#include <vector>
+
+struct TestDerivation {
+ std::string pub;
+ std::string prv;
+ unsigned int nChild;
+};
+
+struct TestVector {
+ std::string strHexMaster;
+ std::vector<TestDerivation> vDerive;
+
+ TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
+
+ TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {
+ vDerive.push_back(TestDerivation());
+ TestDerivation &der = vDerive.back();
+ der.pub = pub;
+ der.prv = prv;
+ der.nChild = nChild;
+ return *this;
+ }
+};
+
+TestVector test1 =
+ TestVector("000102030405060708090a0b0c0d0e0f")
+ ("xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
+ "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
+ 0x80000000)
+ ("xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
+ "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
+ 1)
+ ("xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
+ "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
+ 0x80000002)
+ ("xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
+ "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
+ 2)
+ ("xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
+ "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
+ 1000000000)
+ ("xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
+ "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
+ 0);
+
+TestVector test2 =
+ TestVector("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542")
+ ("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
+ "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
+ 0)
+ ("xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
+ "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
+ 0xFFFFFFFF)
+ ("xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
+ "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
+ 1)
+ ("xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
+ "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
+ 0xFFFFFFFE)
+ ("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
+ "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
+ 2)
+ ("xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
+ "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
+ 0);
+
+void RunTest(const TestVector &test) {
+ std::vector<unsigned char> seed = ParseHex(test.strHexMaster);
+ CExtKey key;
+ CExtPubKey pubkey;
+ key.SetMaster(&seed[0], seed.size());
+ pubkey = key.Neuter();
+ BOOST_FOREACH(const TestDerivation &derive, test.vDerive) {
+ unsigned char data[74];
+ key.Encode(data);
+ pubkey.Encode(data);
+ // Test private key
+ CBitcoinExtKey b58key; b58key.SetKey(key);
+ BOOST_CHECK(b58key.ToString() == derive.prv);
+ // Test public key
+ CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);
+ BOOST_CHECK(b58pubkey.ToString() == derive.pub);
+ // Derive new keys
+ CExtKey keyNew;
+ BOOST_CHECK(key.Derive(keyNew, derive.nChild));
+ CExtPubKey pubkeyNew = keyNew.Neuter();
+ if (!(derive.nChild & 0x80000000)) {
+ // Compare with public derivation
+ CExtPubKey pubkeyNew2;
+ BOOST_CHECK(pubkey.Derive(pubkeyNew2, derive.nChild));
+ BOOST_CHECK(pubkeyNew == pubkeyNew2);
+ }
+ key = keyNew;
+ pubkey = pubkeyNew;
+ }
+}
+
+BOOST_AUTO_TEST_SUITE(bip32_tests)
+
+BOOST_AUTO_TEST_CASE(bip32_test1) {
+ RunTest(test1);
+}
+
+BOOST_AUTO_TEST_CASE(bip32_test2) {
+ RunTest(test2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
new file mode 100644
index 000000000..c4e4403b7
--- /dev/null
+++ b/src/test/bloom_tests.cpp
@@ -0,0 +1,450 @@
+#include "bloom.h"
+
+#include "base58.h"
+#include "key.h"
+#include "main.h"
+#include "serialize.h"
+#include "uint256.h"
+#include "util.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost::tuples;
+
+BOOST_AUTO_TEST_SUITE(bloom_tests)
+
+BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)
+{
+ CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL);
+
+ filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8"));
+ BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
+ // One bit different in first byte
+ BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter contains something it shouldn't!");
+
+ filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"));
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "BloomFilter doesn't contain just-inserted object (2)!");
+
+ filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5"));
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "BloomFilter doesn't contain just-inserted object (3)!");
+
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION);
+
+ vector<unsigned char> vch = ParseHex("03614e9b050000000000000001");
+ vector<char> expected(vch.size());
+
+ for (unsigned int i = 0; i < vch.size(); i++)
+ expected[i] = (char)vch[i];
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end());
+}
+
+BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
+{
+ // Same test as bloom_create_insert_serialize, but we add a nTweak of 100
+ CBloomFilter filter(3, 0.01, 2147483649, BLOOM_UPDATE_ALL);
+
+ filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8"));
+ BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
+ // One bit different in first byte
+ BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter contains something it shouldn't!");
+
+ filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"));
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "BloomFilter doesn't contain just-inserted object (2)!");
+
+ filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5"));
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "BloomFilter doesn't contain just-inserted object (3)!");
+
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION);
+
+ vector<unsigned char> vch = ParseHex("03ce4299050000000100008001");
+ vector<char> expected(vch.size());
+
+ for (unsigned int i = 0; i < vch.size(); i++)
+ expected[i] = (char)vch[i];
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end());
+}
+
+BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
+{
+ string strSecret = string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
+ CBitcoinSecret vchSecret;
+ BOOST_CHECK(vchSecret.SetString(strSecret));
+
+ CKey key = vchSecret.GetKey();
+ CPubKey pubkey = key.GetPubKey();
+ vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
+
+ CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(vchPubKey);
+ uint160 hash = pubkey.GetID();
+ filter.insert(vector<unsigned char>(hash.begin(), hash.end()));
+
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION);
+
+ vector<unsigned char> vch = ParseHex("038fc16b080000000000000001");
+ vector<char> expected(vch.size());
+
+ for (unsigned int i = 0; i < vch.size(); i++)
+ expected[i] = (char)vch[i];
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end());
+}
+
+BOOST_AUTO_TEST_CASE(bloom_match)
+{
+ // Random real transaction (b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b)
+ CTransaction tx;
+ CDataStream stream(ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"), SER_DISK, CLIENT_VERSION);
+ stream >> tx;
+
+ // and one which spends it (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 spendStream(vch, SER_DISK, CLIENT_VERSION);
+ CTransaction spendingTx;
+ spendStream >> spendingTx;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match tx hash");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ // byte-reversed tx hash
+ filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4"));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized tx hash");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01"));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input signature");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339"));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input pub key");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19"));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx, spendingTx.GetHash()), "Simple Bloom filter didn't add output");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431"));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match COutPoint");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
+ {
+ vector<unsigned char> data(32 + sizeof(unsigned int));
+ memcpy(&data[0], prevOutPoint.hash.begin(), 32);
+ memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
+ filter.insert(data);
+ }
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized COutPoint");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"));
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random tx hash");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431"));
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random address");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about");
+
+ filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about");
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_1)
+{
+ // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
+ // With 9 txes
+ CBlock block;
+ CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ // Match the last transaction
+ filter.insert(uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+ pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8);
+
+ vector<uint256> vMatched;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+
+ // Also match the 8th transaction
+ filter.insert(uint256("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
+ merkleBlock = CMerkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7);
+
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_2)
+{
+ // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6)
+ // With 4 txes
+ CBlock block;
+ CDataStream stream(ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ // Match the first transaction
+ filter.insert(uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+ pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
+
+ vector<uint256> vMatched;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+
+ // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5)
+ // This should match the third transaction because it spends the output matched
+ // It also matches the fourth transaction, which spends to the pubkey again
+ filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af"));
+
+ merkleBlock = CMerkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 4);
+
+ BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 2);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3);
+
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
+{
+ // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6)
+ // With 4 txes
+ CBlock block;
+ CDataStream stream(ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE);
+ // Match the first transaction
+ filter.insert(uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+ pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
+
+ vector<uint256> vMatched;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+
+ // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5)
+ // This should not match the third transaction though it spends the output matched
+ // It will match the fourth transaction, which has another pay-to-pubkey output to the same address
+ filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af"));
+
+ merkleBlock = CMerkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 3);
+
+ BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3);
+
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
+{
+ // Random real block (000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45)
+ // With one tx
+ CBlock block;
+ CDataStream stream(ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ // Match the only transaction
+ filter.insert(uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
+
+ vector<uint256> vMatched;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+
+ CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION);
+ merkleStream << merkleBlock;
+
+ vector<unsigned char> vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101");
+ vector<char> expected(vch.size());
+
+ for (unsigned int i = 0; i < vch.size(); i++)
+ expected[i] = (char)vch[i];
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), merkleStream.begin(), merkleStream.end());
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_4)
+{
+ // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4)
+ // With 7 txes
+ CBlock block;
+ CDataStream stream(ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
+ // Match the last transaction
+ filter.insert(uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+ pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6);
+
+ vector<uint256> vMatched;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+
+ // Also match the 4th transaction
+ filter.insert(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"));
+ merkleBlock = CMerkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"));
+ BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 3);
+
+ BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
+
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
+ for (unsigned int i = 0; i < vMatched.size(); i++)
+ BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only)
+{
+ // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4)
+ // With 7 txes
+ CBlock block;
+ CDataStream stream(ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_P2PUBKEY_ONLY);
+ // Match the generation pubkey
+ filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91"));
+ // ...and the output address of the 4th transaction
+ filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ // We should match the generation outpoint
+ BOOST_CHECK(filter.contains(COutPoint(uint256("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
+ // ... but not the 4th transaction's output (its not pay-2-pubkey)
+ BOOST_CHECK(!filter.contains(COutPoint(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
+}
+
+BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none)
+{
+ // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4)
+ // With 7 txes
+ CBlock block;
+ CDataStream stream(ParseHex("0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+
+ CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE);
+ // Match the generation pubkey
+ filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91"));
+ // ...and the output address of the 4th transaction
+ filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21"));
+
+ CMerkleBlock merkleBlock(block, filter);
+ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+
+ // We shouldn't match any outpoints (UPDATE_NONE)
+ BOOST_CHECK(!filter.contains(COutPoint(uint256("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
+ BOOST_CHECK(!filter.contains(COutPoint(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp
new file mode 100644
index 000000000..c521f2cf9
--- /dev/null
+++ b/src/test/canonical_tests.cpp
@@ -0,0 +1,92 @@
+//
+// Unit tests for canonical signatures
+//
+
+
+
+#include "script.h"
+#include "util.h"
+#include "data/sig_noncanonical.json.h"
+#include "data/sig_canonical.json.h"
+
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+#include "json/json_spirit_writer_template.h"
+#include <openssl/ecdsa.h>
+
+using namespace std;
+using namespace json_spirit;
+
+
+// In script_tests.cpp
+extern Array read_json(const std::string& jsondata);
+
+BOOST_AUTO_TEST_SUITE(canonical_tests)
+
+// OpenSSL-based test for canonical signature (without test for hashtype byte)
+bool static IsCanonicalSignature_OpenSSL_inner(const std::vector<unsigned char>& vchSig)
+{
+ if (vchSig.size() == 0)
+ return false;
+ const unsigned char *input = &vchSig[0];
+ ECDSA_SIG *psig = NULL;
+ d2i_ECDSA_SIG(&psig, &input, vchSig.size());
+ if (psig == NULL)
+ return false;
+ unsigned char buf[256];
+ unsigned char *pbuf = buf;
+ unsigned int nLen = i2d_ECDSA_SIG(psig, NULL);
+ if (nLen != vchSig.size()) {
+ ECDSA_SIG_free(psig);
+ return false;
+ }
+ nLen = i2d_ECDSA_SIG(psig, &pbuf);
+ ECDSA_SIG_free(psig);
+ return (memcmp(&vchSig[0], &buf[0], nLen) == 0);
+}
+
+// OpenSSL-based test for canonical signature
+bool static IsCanonicalSignature_OpenSSL(const std::vector<unsigned char> &vchSignature) {
+ if (vchSignature.size() < 1)
+ return false;
+ if (vchSignature.size() > 127)
+ return false;
+ if (vchSignature[vchSignature.size() - 1] & 0x7C)
+ return false;
+
+ std::vector<unsigned char> vchSig(vchSignature);
+ vchSig.pop_back();
+ if (!IsCanonicalSignature_OpenSSL_inner(vchSig))
+ return false;
+ return true;
+}
+
+BOOST_AUTO_TEST_CASE(script_canon)
+{
+ Array tests = read_json(std::string(json_tests::sig_canonical, json_tests::sig_canonical + sizeof(json_tests::sig_canonical)));
+
+ BOOST_FOREACH(Value &tv, tests) {
+ string test = tv.get_str();
+ if (IsHex(test)) {
+ std::vector<unsigned char> sig = ParseHex(test);
+ BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
+ BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(script_noncanon)
+{
+ Array tests = read_json(std::string(json_tests::sig_noncanonical, json_tests::sig_noncanonical + sizeof(json_tests::sig_noncanonical)));
+
+ BOOST_FOREACH(Value &tv, tests) {
+ string test = tv.get_str();
+ if (IsHex(test)) {
+ std::vector<unsigned char> sig = ParseHex(test);
+ BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
+ BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
new file mode 100644
index 000000000..d47a33fd4
--- /dev/null
+++ b/src/test/checkblock_tests.cpp
@@ -0,0 +1,64 @@
+//
+// Unit tests for block.CheckBlock()
+//
+
+
+
+#include "main.h"
+
+#include <cstdio>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_AUTO_TEST_SUITE(CheckBlock_tests)
+
+bool
+read_block(const std::string& filename, CBlock& block)
+{
+ namespace fs = boost::filesystem;
+ fs::path testFile = fs::current_path() / "data" / filename;
+#ifdef TEST_DATA_DIR
+ if (!fs::exists(testFile))
+ {
+ testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename;
+ }
+#endif
+ FILE* fp = fopen(testFile.string().c_str(), "rb");
+ if (!fp) return false;
+
+ fseek(fp, 8, SEEK_SET); // skip msgheader/size
+
+ CAutoFile filein = CAutoFile(fp, SER_DISK, CLIENT_VERSION);
+ if (!filein) return false;
+
+ filein >> block;
+
+ return true;
+}
+
+BOOST_AUTO_TEST_CASE(May15)
+{
+ // Putting a 1MB binary file in the git repository is not a great
+ // idea, so this test is only run if you manually download
+ // test/data/Mar12Fork.dat from
+ // http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/Mar12Fork.dat/download
+ unsigned int tMay15 = 1368576000;
+ SetMockTime(tMay15); // Test as if it was right at May 15
+
+ CBlock forkingBlock;
+ if (read_block("Mar12Fork.dat", forkingBlock))
+ {
+ CValidationState state;
+
+ // After May 15'th, big blocks are OK:
+ forkingBlock.nTime = tMay15; // Invalidates PoW
+ BOOST_CHECK(CheckBlock(forkingBlock, state, false, false));
+ }
+
+ SetMockTime(0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
new file mode 100644
index 000000000..4d1691477
--- /dev/null
+++ b/src/test/compress_tests.cpp
@@ -0,0 +1,62 @@
+
+
+#include "main.h"
+#include "util.h"
+
+#include <stdint.h>
+
+#include <boost/test/unit_test.hpp>
+
+// amounts 0.00000001 .. 0.00100000
+#define NUM_MULTIPLES_UNIT 100000
+
+// amounts 0.01 .. 100.00
+#define NUM_MULTIPLES_CENT 10000
+
+// amounts 1 .. 10000
+#define NUM_MULTIPLES_1BTC 10000
+
+// amounts 50 .. 21000000
+#define NUM_MULTIPLES_50BTC 420000
+
+BOOST_AUTO_TEST_SUITE(compress_tests)
+
+bool static TestEncode(uint64_t in) {
+ return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in));
+}
+
+bool static TestDecode(uint64_t in) {
+ return in == CTxOutCompressor::CompressAmount(CTxOutCompressor::DecompressAmount(in));
+}
+
+bool static TestPair(uint64_t dec, uint64_t enc) {
+ return CTxOutCompressor::CompressAmount(dec) == enc &&
+ CTxOutCompressor::DecompressAmount(enc) == dec;
+}
+
+BOOST_AUTO_TEST_CASE(compress_amounts)
+{
+ BOOST_CHECK(TestPair( 0, 0x0));
+ BOOST_CHECK(TestPair( 1, 0x1));
+ BOOST_CHECK(TestPair( CENT, 0x7));
+ BOOST_CHECK(TestPair( COIN, 0x9));
+ BOOST_CHECK(TestPair( 50*COIN, 0x32));
+ BOOST_CHECK(TestPair(21000000*COIN, 0x1406f40));
+
+ for (uint64_t i = 1; i <= NUM_MULTIPLES_UNIT; i++)
+ BOOST_CHECK(TestEncode(i));
+
+ for (uint64_t i = 1; i <= NUM_MULTIPLES_CENT; i++)
+ BOOST_CHECK(TestEncode(i * CENT));
+
+ for (uint64_t i = 1; i <= NUM_MULTIPLES_1BTC; i++)
+ BOOST_CHECK(TestEncode(i * COIN));
+
+ for (uint64_t i = 1; i <= NUM_MULTIPLES_50BTC; i++)
+ BOOST_CHECK(TestEncode(i * 50 * COIN));
+
+ for (uint64_t i = 0; i < 100000; i++)
+ BOOST_CHECK(TestDecode(i));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw
new file mode 100644
index 000000000..01f50680b
--- /dev/null
+++ b/src/test/data/alertTests.raw
Binary files differ
diff --git a/src/test/data/base58_encode_decode.json b/src/test/data/base58_encode_decode.json
new file mode 100644
index 000000000..9448f256d
--- /dev/null
+++ b/src/test/data/base58_encode_decode.json
@@ -0,0 +1,14 @@
+[
+["", ""],
+["61", "2g"],
+["626262", "a3gV"],
+["636363", "aPEr"],
+["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"],
+["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"],
+["516b6fcd0f", "ABnLTmg"],
+["bf4f89001e670274dd", "3SEo3LWLoPntC"],
+["572e4794", "3EFU7m"],
+["ecac89cad93923c02321", "EJDM8drfXA6uyA"],
+["10c8511e", "Rt5zm"],
+["00000000000000000000", "1111111111"]
+]
diff --git a/src/test/data/base58_keys_invalid.json b/src/test/data/base58_keys_invalid.json
new file mode 100644
index 000000000..a088620f1
--- /dev/null
+++ b/src/test/data/base58_keys_invalid.json
@@ -0,0 +1,152 @@
+[
+ [
+ ""
+ ],
+ [
+ "x"
+ ],
+ [
+ "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y"
+ ],
+ [
+ "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv"
+ ],
+ [
+ "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S"
+ ],
+ [
+ "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf"
+ ],
+ [
+ "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq"
+ ],
+ [
+ "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb"
+ ],
+ [
+ "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs"
+ ],
+ [
+ "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3"
+ ],
+ [
+ "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th"
+ ],
+ [
+ "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va"
+ ],
+ [
+ "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk"
+ ],
+ [
+ "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs"
+ ],
+ [
+ "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo"
+ ],
+ [
+ "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso"
+ ],
+ [
+ "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq"
+ ],
+ [
+ "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN"
+ ],
+ [
+ "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i"
+ ],
+ [
+ "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos"
+ ],
+ [
+ "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu"
+ ],
+ [
+ "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb"
+ ],
+ [
+ "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ"
+ ],
+ [
+ "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ"
+ ],
+ [
+ "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu"
+ ],
+ [
+ "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU"
+ ],
+ [
+ "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs"
+ ],
+ [
+ "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn"
+ ],
+ [
+ "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj"
+ ],
+ [
+ "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny"
+ ],
+ [
+ "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc"
+ ],
+ [
+ "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ"
+ ],
+ [
+ "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP"
+ ],
+ [
+ "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw"
+ ],
+ [
+ "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX"
+ ],
+ [
+ "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB"
+ ],
+ [
+ "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ"
+ ],
+ [
+ "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs"
+ ],
+ [
+ "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ"
+ ],
+ [
+ "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4"
+ ],
+ [
+ "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK"
+ ],
+ [
+ "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig"
+ ],
+ [
+ "EsYbG4tWWWY45G31nox838qNdzksbPySWc"
+ ],
+ [
+ "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT"
+ ],
+ [
+ "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx"
+ ],
+ [
+ "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde"
+ ],
+ [
+ "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU"
+ ],
+ [
+ "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf"
+ ],
+ [
+ "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd"
+ ],
+ [
+ "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED"
+ ]
+]
diff --git a/src/test/data/base58_keys_valid.json b/src/test/data/base58_keys_valid.json
new file mode 100644
index 000000000..e1e252e22
--- /dev/null
+++ b/src/test/data/base58_keys_valid.json
@@ -0,0 +1,452 @@
+[
+ [
+ "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
+ "65a16059864a2fdbc7c99a4723a8395bc6f188eb",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
+ "74f209f6ea907e2ea48f74fae05782ae8a665257",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
+ "53c0307d6851aa0ce7825ba883c6bd9ad242b486",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
+ "6349a418fc4578d10a372b54b45c280cc8c4382f",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
+ "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
+ "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
+ "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
+ "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
+ "6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
+ "fcc5460dd6e2487c7d75b1963625da0e8f4c5975",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
+ "f1d470f9b02370fdec2e6b708b08ac431bf7a5f7",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
+ "c579342c2c4c9220205e2cdc285617040c924a0a",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
+ "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
+ "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
+ "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
+ "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
+ "7987ccaa53d02c8873487ef919677cd3db7a6912",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
+ "63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
+ "ef66444b5b17f14e8fae6e7e19b045a78c54fd79",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
+ "c3e55fceceaa4391ed2a9677f4a4d34eacd021a0",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
+ "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
+ "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
+ "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
+ "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
+ "adc1cc2081a27206fae25792f28bbc55b831549d",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
+ "188f91a931947eddd7432d6e614387e32b244709",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
+ "1694f5bc1a7295b600f40018a618a6ea48eeb498",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
+ "3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
+ "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
+ "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
+ "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
+ "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
+ "c4c1b72491ede1eedaca00618407ee0b772cad0d",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
+ "f6fe69bcb548a829cce4c57bf6fff8af3a5981f9",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
+ "261f83568a098a8638844bd7aeca039d5f2352c0",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
+ "e930e1834a4d234702773951d627cce82fbb5d2e",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
+ "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
+ "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
+ "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
+ "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
+ "5eadaf9bb7121f0f192561a5a62f5e5f54210292",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
+ "3f210e7277c899c3a155cc1c90f4106cbddeec6e",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
+ "c8a3c2a09a298592c3e180f02487cd91ba3400b5",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
+ "99b31df7c9068d1481b596578ddbb4d3bd90baeb",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": true
+ }
+ ],
+ [
+ "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
+ "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
+ "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": false
+ }
+ ],
+ [
+ "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
+ "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
+ "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "isTestnet": true
+ }
+ ],
+ [
+ "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
+ "1ed467017f043e91ed4c44b4e8dd674db211c4e6",
+ {
+ "addrType": "pubkey",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ],
+ [
+ "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
+ "5ece0cadddc415b1980f001785947120acdb36fc",
+ {
+ "addrType": "script",
+ "isPrivkey": false,
+ "isTestnet": false
+ }
+ ]
+]
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
new file mode 100644
index 000000000..761cc4a00
--- /dev/null
+++ b/src/test/data/script_invalid.json
@@ -0,0 +1,329 @@
+[
+["", ""],
+["", "NOP"],
+["NOP", ""],
+["NOP","NOP"],
+
+["0x4c01","0x01 NOP", "PUSHDATA1 with not enough bytes"],
+["0x4d0200ff","0x01 NOP", "PUSHDATA2 with not enough bytes"],
+["0x4e03000000ffff","0x01 NOP", "PUSHDATA4 with not enough bytes"],
+
+["1", "IF 0x50 ENDIF 1", "0x50 is reserved"],
+["0x52", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"],
+["0","NOP"],
+["1", "IF VER ELSE 1 ENDIF", "VER non-functional"],
+["0", "IF VERIF ELSE 1 ENDIF", "VERIF illegal everywhere"],
+["0", "IF ELSE 1 ELSE VERIF ENDIF", "VERIF illegal everywhere"],
+["0", "IF VERNOTIF ELSE 1 ENDIF", "VERNOTIF illegal everywhere"],
+["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "VERNOTIF illegal everywhere"],
+
+["1 IF", "1 ENDIF", "IF/ENDIF can't span scriptSig/scriptPubKey"],
+["1 IF 0 ENDIF", "1 ENDIF"],
+["1 ELSE 0 ENDIF", "1"],
+["0 NOTIF", "123"],
+
+["0", "DUP IF ENDIF"],
+["0", "IF 1 ENDIF"],
+["0", "DUP IF ELSE ENDIF"],
+["0", "IF 1 ELSE ENDIF"],
+["0", "NOTIF ELSE 1 ENDIF"],
+
+["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF"],
+["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF"],
+["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+
+["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],
+["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],
+["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+
+["1", "IF RETURN ELSE ELSE 1 ENDIF", "Multiple ELSEs"],
+["1", "IF 1 ELSE ELSE RETURN ENDIF"],
+
+["1", "ENDIF", "Malformed IF/ELSE/ENDIF sequence"],
+["1", "ELSE ENDIF"],
+["1", "ENDIF ELSE"],
+["1", "ENDIF ELSE IF"],
+["1", "IF ELSE ENDIF ELSE"],
+["1", "IF ELSE ENDIF ELSE ENDIF"],
+["1", "IF ENDIF ENDIF"],
+["1", "IF ELSE ELSE ENDIF ENDIF"],
+
+["1", "RETURN"],
+["1", "DUP IF RETURN ENDIF"],
+
+["1", "RETURN 'data'", "canonical prunable txout format"],
+["0 IF", "RETURN ENDIF 1", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"],
+
+["0", "VERIFY 1"],
+["1", "VERIFY"],
+["1", "VERIFY 0"],
+
+["1 TOALTSTACK", "FROMALTSTACK 1", "alt stack not shared between sig/pubkey"],
+
+["IFDUP", "DEPTH 0 EQUAL"],
+["DROP", "DEPTH 0 EQUAL"],
+["DUP", "DEPTH 0 EQUAL"],
+["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL"],
+["NOP", "NIP"],
+["NOP", "1 NIP"],
+["NOP", "1 0 NIP"],
+["NOP", "OVER 1"],
+["1", "OVER"],
+["0 1", "OVER DEPTH 3 EQUALVERIFY"],
+["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL"],
+["NOP", "0 PICK"],
+["1", "-1 PICK"],
+["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL"],
+["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL"],
+["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL"],
+["NOP", "0 ROLL"],
+["1", "-1 ROLL"],
+["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL"],
+["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"],
+["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"],
+["NOP", "ROT 1"],
+["NOP", "1 ROT 1"],
+["NOP", "1 2 ROT 1"],
+["NOP", "0 1 2 ROT"],
+["NOP", "SWAP 1"],
+["1", "SWAP 1"],
+["0 1", "SWAP 1 EQUALVERIFY"],
+["NOP", "TUCK 1"],
+["1", "TUCK 1"],
+["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"],
+["NOP", "2DUP 1"],
+["1", "2DUP 1"],
+["NOP", "3DUP 1"],
+["1", "3DUP 1"],
+["1 2", "3DUP 1"],
+["NOP", "2OVER 1"],
+["1", "2 3 2OVER 1"],
+["NOP", "2SWAP 1"],
+["1", "2 3 2SWAP 1"],
+
+["'a' 'b'", "CAT", "CAT disabled"],
+["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "CAT disabled"],
+["'abc' 1 1", "SUBSTR", "SUBSTR disabled"],
+["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "SUBSTR disabled"],
+["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "LEFT disabled"],
+["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "RIGHT disabled"],
+
+["NOP", "SIZE 1"],
+
+["'abc'", "IF INVERT ELSE 1 ENDIF", "INVERT disabled"],
+["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "AND disabled"],
+["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "OR disabled"],
+["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "XOR disabled"],
+["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "2MUL disabled"],
+["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "2DIV disabled"],
+["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "MUL disabled"],
+["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "DIV disabled"],
+["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "MOD disabled"],
+["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "LSHIFT disabled"],
+["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "RSHIFT disabled"],
+
+["0 1","EQUAL"],
+["1 1 ADD", "0 EQUAL"],
+["11 1 ADD 12 SUB", "11 EQUAL"],
+
+["2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "],
+["-2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "],
+["2147483647 DUP ADD", "4294967294 NUMEQUAL", "NUMEQUAL must be in numeric range"],
+["'abcdef' NOT", "0 EQUAL", "NOT is an arithmetic operand"],
+
+["2 DUP MUL", "4 EQUAL", "disabled"],
+["2 DUP DIV", "1 EQUAL", "disabled"],
+["2 2MUL", "4 EQUAL", "disabled"],
+["2 2DIV", "1 EQUAL", "disabled"],
+["7 3 MOD", "1 EQUAL", "disabled"],
+["2 2 LSHIFT", "8 EQUAL", "disabled"],
+["2 1 RSHIFT", "1 EQUAL", "disabled"],
+
+["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL"],
+["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL"],
+
+["0x50","1", "opcode 0x50 is reserved"],
+["1", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"],
+["1", "IF 0xbb ELSE 1 ENDIF"],
+["1", "IF 0xbc ELSE 1 ENDIF"],
+["1", "IF 0xbd ELSE 1 ENDIF"],
+["1", "IF 0xbe ELSE 1 ENDIF"],
+["1", "IF 0xbf ELSE 1 ENDIF"],
+["1", "IF 0xc0 ELSE 1 ENDIF"],
+["1", "IF 0xc1 ELSE 1 ENDIF"],
+["1", "IF 0xc2 ELSE 1 ENDIF"],
+["1", "IF 0xc3 ELSE 1 ENDIF"],
+["1", "IF 0xc4 ELSE 1 ENDIF"],
+["1", "IF 0xc5 ELSE 1 ENDIF"],
+["1", "IF 0xc6 ELSE 1 ENDIF"],
+["1", "IF 0xc7 ELSE 1 ENDIF"],
+["1", "IF 0xc8 ELSE 1 ENDIF"],
+["1", "IF 0xc9 ELSE 1 ENDIF"],
+["1", "IF 0xca ELSE 1 ENDIF"],
+["1", "IF 0xcb ELSE 1 ENDIF"],
+["1", "IF 0xcc ELSE 1 ENDIF"],
+["1", "IF 0xcd ELSE 1 ENDIF"],
+["1", "IF 0xce ELSE 1 ENDIF"],
+["1", "IF 0xcf ELSE 1 ENDIF"],
+["1", "IF 0xd0 ELSE 1 ENDIF"],
+["1", "IF 0xd1 ELSE 1 ENDIF"],
+["1", "IF 0xd2 ELSE 1 ENDIF"],
+["1", "IF 0xd3 ELSE 1 ENDIF"],
+["1", "IF 0xd4 ELSE 1 ENDIF"],
+["1", "IF 0xd5 ELSE 1 ENDIF"],
+["1", "IF 0xd6 ELSE 1 ENDIF"],
+["1", "IF 0xd7 ELSE 1 ENDIF"],
+["1", "IF 0xd8 ELSE 1 ENDIF"],
+["1", "IF 0xd9 ELSE 1 ENDIF"],
+["1", "IF 0xda ELSE 1 ENDIF"],
+["1", "IF 0xdb ELSE 1 ENDIF"],
+["1", "IF 0xdc ELSE 1 ENDIF"],
+["1", "IF 0xdd ELSE 1 ENDIF"],
+["1", "IF 0xde ELSE 1 ENDIF"],
+["1", "IF 0xdf ELSE 1 ENDIF"],
+["1", "IF 0xe0 ELSE 1 ENDIF"],
+["1", "IF 0xe1 ELSE 1 ENDIF"],
+["1", "IF 0xe2 ELSE 1 ENDIF"],
+["1", "IF 0xe3 ELSE 1 ENDIF"],
+["1", "IF 0xe4 ELSE 1 ENDIF"],
+["1", "IF 0xe5 ELSE 1 ENDIF"],
+["1", "IF 0xe6 ELSE 1 ENDIF"],
+["1", "IF 0xe7 ELSE 1 ENDIF"],
+["1", "IF 0xe8 ELSE 1 ENDIF"],
+["1", "IF 0xe9 ELSE 1 ENDIF"],
+["1", "IF 0xea ELSE 1 ENDIF"],
+["1", "IF 0xeb ELSE 1 ENDIF"],
+["1", "IF 0xec ELSE 1 ENDIF"],
+["1", "IF 0xed ELSE 1 ENDIF"],
+["1", "IF 0xee ELSE 1 ENDIF"],
+["1", "IF 0xef ELSE 1 ENDIF"],
+["1", "IF 0xf0 ELSE 1 ENDIF"],
+["1", "IF 0xf1 ELSE 1 ENDIF"],
+["1", "IF 0xf2 ELSE 1 ENDIF"],
+["1", "IF 0xf3 ELSE 1 ENDIF"],
+["1", "IF 0xf4 ELSE 1 ENDIF"],
+["1", "IF 0xf5 ELSE 1 ENDIF"],
+["1", "IF 0xf6 ELSE 1 ENDIF"],
+["1", "IF 0xf7 ELSE 1 ENDIF"],
+["1", "IF 0xf8 ELSE 1 ENDIF"],
+["1", "IF 0xf9 ELSE 1 ENDIF"],
+["1", "IF 0xfa ELSE 1 ENDIF"],
+["1", "IF 0xfb ELSE 1 ENDIF"],
+["1", "IF 0xfc ELSE 1 ENDIF"],
+["1", "IF 0xfd ELSE 1 ENDIF"],
+["1", "IF 0xfe ELSE 1 ENDIF"],
+["1", "IF 0xff ELSE 1 ENDIF"],
+
+["1 IF 1 ELSE", "0xff ENDIF", "invalid because scriptSig and scriptPubKey are processed separately"],
+
+["NOP", "RIPEMD160"],
+["NOP", "SHA1"],
+["NOP", "SHA256"],
+["NOP", "HASH160"],
+["NOP", "HASH256"],
+
+["NOP",
+"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",
+">520 byte push"],
+["0",
+"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1",
+">520 byte push in non-executed IF branch"],
+["1",
+"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
+">201 opcodes executed. 0x61 is NOP"],
+["0",
+"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1",
+">201 opcodes including non-executed IF branch. 0x61 is NOP"],
+["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+">1,000 stack size (0x6f is 3DUP)"],
+["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+">1,000 stack+altstack size"],
+["NOP",
+"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
+"10,001-byte scriptPubKey"],
+
+["NOP1","NOP10"],
+
+["1","VER", "OP_VER is reserved"],
+["1","VERIF", "OP_VERIF is reserved"],
+["1","VERNOTIF", "OP_VERNOTIF is reserved"],
+["1","RESERVED", "OP_RESERVED is reserved"],
+["1","RESERVED1", "OP_RESERVED1 is reserved"],
+["1","RESERVED2", "OP_RESERVED2 is reserved"],
+["1","0xba", "0xba == OP_NOP10 + 1"],
+
+["2147483648", "1ADD 1", "We cannot do math on 5-byte integers"],
+["-2147483648", "1ADD 1", "Because we use a sign bit, -2147483648 is also 5 bytes"],
+
+["1", "1 ENDIF", "ENDIF without IF"],
+["1", "IF 1", "IF without ENDIF"],
+["1 IF 1", "ENDIF", "IFs don't carry over"],
+
+["NOP", "IF 1 ENDIF", "The following tests check the if(stack.size() < N) tests in each opcode"],
+["NOP", "NOTIF 1 ENDIF", "They are here to catch copy-and-paste errors"],
+["NOP", "VERIFY 1", "Most of them are duplicated elsewhere,"],
+
+["NOP", "TOALTSTACK 1", "but, hey, more is always better, right?"],
+["1", "FROMALTSTACK"],
+["1", "2DROP 1"],
+["1", "2DUP"],
+["1 1", "3DUP"],
+["1 1 1", "2OVER"],
+["1 1 1 1 1", "2ROT"],
+["1 1 1", "2SWAP"],
+["NOP", "IFDUP 1"],
+["NOP", "DROP 1"],
+["NOP", "DUP 1"],
+["1", "NIP"],
+["1", "OVER"],
+["1 1 1 3", "PICK"],
+["0", "PICK 1"],
+["1 1 1 3", "ROLL"],
+["0", "ROLL 1"],
+["1 1", "ROT"],
+["1", "SWAP"],
+["1", "TUCK"],
+
+["NOP", "SIZE 1"],
+
+["1", "EQUAL 1"],
+["1", "EQUALVERIFY 1"],
+
+["NOP", "1ADD 1"],
+["NOP", "1SUB 1"],
+["NOP", "NEGATE 1"],
+["NOP", "ABS 1"],
+["NOP", "NOT 1"],
+["NOP", "0NOTEQUAL 1"],
+
+["1", "ADD"],
+["1", "SUB"],
+["1", "BOOLAND"],
+["1", "BOOLOR"],
+["1", "NUMEQUAL"],
+["1", "NUMEQUALVERIFY 1"],
+["1", "NUMNOTEQUAL"],
+["1", "LESSTHAN"],
+["1", "GREATERTHAN"],
+["1", "LESSTHANOREQUAL"],
+["1", "GREATERTHANOREQUAL"],
+["1", "MIN"],
+["1", "MAX"],
+["1 1", "WITHIN"],
+
+["NOP", "RIPEMD160 1"],
+["NOP", "SHA1 1"],
+["NOP", "SHA256 1"],
+["NOP", "HASH160 1"],
+["NOP", "HASH256 1"],
+
+["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Tests for Script.IsPushOnly()"],
+["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"],
+
+["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "OP_RESERVED in P2SH should fail"],
+["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "OP_VER in P2SH should fail"]
+]
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
new file mode 100644
index 000000000..e4c181cae
--- /dev/null
+++ b/src/test/data/script_valid.json
@@ -0,0 +1,415 @@
+[
+["0x01 0x0b", "11 EQUAL", "push 1 byte"],
+["0x02 0x417a", "'Az' EQUAL"],
+["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a",
+ "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "push 75 bytes"],
+
+["0x4c 0x01 0x07","7 EQUAL", "0x4c is OP_PUSHDATA1"],
+["0x4d 0x0100 0x08","8 EQUAL", "0x4d is OP_PUSHDATA2"],
+["0x4e 0x01000000 0x09","9 EQUAL", "0x4e is OP_PUSHDATA4"],
+
+["0x4c 0x00","0 EQUAL"],
+["0x4d 0x0000","0 EQUAL"],
+["0x4e 0x00000000","0 EQUAL"],
+["0x4f 1000 ADD","999 EQUAL"],
+["0", "IF 0x50 ENDIF 1", "0x50 is reserved (ok if not executed)"],
+["0x51", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"],
+["1","NOP"],
+["0", "IF VER ELSE 1 ENDIF", "VER non-functional (ok if not executed)"],
+["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "RESERVED ok in un-executed IF"],
+
+["1", "DUP IF ENDIF"],
+["1", "IF 1 ENDIF"],
+["1", "DUP IF ELSE ENDIF"],
+["1", "IF 1 ELSE ENDIF"],
+["0", "IF ELSE 1 ENDIF"],
+
+["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF"],
+["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF"],
+["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+
+["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],
+["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],
+["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],
+
+["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"],
+["1", "IF 1 ELSE 0 ELSE ENDIF"],
+["1", "IF ELSE 0 ELSE 1 ENDIF"],
+["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL"],
+["'' 1", "IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL"],
+
+["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"],
+["0", "NOTIF 1 ELSE 0 ELSE ENDIF"],
+["0", "NOTIF ELSE 0 ELSE 1 ENDIF"],
+["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL"],
+["'' 0", "NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL"],
+
+["0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "Nested ELSE ELSE"],
+["1", "NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL"],
+
+["0", "IF RETURN ENDIF 1", "RETURN only works if executed"],
+
+["1 1", "VERIFY"],
+
+["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL"],
+["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL"],
+
+["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL"],
+["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL"],
+["0 DROP", "DEPTH 0 EQUAL"],
+["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL"],
+["0 1", "NIP"],
+["1 0", "OVER DEPTH 3 EQUALVERIFY"],
+["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL"],
+["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL"],
+["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL"],
+["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL"],
+["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"],
+["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"],
+["22 21 20", "ROT 22 EQUAL"],
+["22 21 20", "ROT DROP 20 EQUAL"],
+["22 21 20", "ROT DROP DROP 21 EQUAL"],
+["22 21 20", "ROT ROT 21 EQUAL"],
+["22 21 20", "ROT ROT ROT 20 EQUAL"],
+["25 24 23 22 21 20", "2ROT 24 EQUAL"],
+["25 24 23 22 21 20", "2ROT DROP 25 EQUAL"],
+["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL"],
+["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL"],
+["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL"],
+["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL"],
+["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL"],
+["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL"],
+["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL"],
+["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"],
+["13 14", "2DUP ROT EQUALVERIFY EQUAL"],
+["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY"],
+["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL"],
+["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL"],
+["0", "SIZE 0 EQUAL"],
+["1", "SIZE 1 EQUAL"],
+["127", "SIZE 1 EQUAL"],
+["128", "SIZE 2 EQUAL"],
+["32767", "SIZE 2 EQUAL"],
+["32768", "SIZE 3 EQUAL"],
+["8388607", "SIZE 3 EQUAL"],
+["8388608", "SIZE 4 EQUAL"],
+["2147483647", "SIZE 4 EQUAL"],
+["2147483648", "SIZE 5 EQUAL"],
+["-1", "SIZE 1 EQUAL"],
+["-127", "SIZE 1 EQUAL"],
+["-128", "SIZE 2 EQUAL"],
+["-32767", "SIZE 2 EQUAL"],
+["-32768", "SIZE 3 EQUAL"],
+["-8388607", "SIZE 3 EQUAL"],
+["-8388608", "SIZE 4 EQUAL"],
+["-2147483647", "SIZE 4 EQUAL"],
+["-2147483648", "SIZE 5 EQUAL"],
+["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL"],
+
+
+["2 -2 ADD", "0 EQUAL"],
+["2147483647 -2147483647 ADD", "0 EQUAL"],
+["-1 -1 ADD", "-2 EQUAL"],
+
+["0 0","EQUAL"],
+["1 1 ADD", "2 EQUAL"],
+["1 1ADD", "2 EQUAL"],
+["111 1SUB", "110 EQUAL"],
+["111 1 ADD 12 SUB", "100 EQUAL"],
+["0 ABS", "0 EQUAL"],
+["16 ABS", "16 EQUAL"],
+["-16 ABS", "-16 NEGATE EQUAL"],
+["0 NOT", "NOP"],
+["1 NOT", "0 EQUAL"],
+["11 NOT", "0 EQUAL"],
+["0 0NOTEQUAL", "0 EQUAL"],
+["1 0NOTEQUAL", "1 EQUAL"],
+["111 0NOTEQUAL", "1 EQUAL"],
+["-111 0NOTEQUAL", "1 EQUAL"],
+["1 1 BOOLAND", "NOP"],
+["1 0 BOOLAND", "NOT"],
+["0 1 BOOLAND", "NOT"],
+["0 0 BOOLAND", "NOT"],
+["16 17 BOOLAND", "NOP"],
+["1 1 BOOLOR", "NOP"],
+["1 0 BOOLOR", "NOP"],
+["0 1 BOOLOR", "NOP"],
+["0 0 BOOLOR", "NOT"],
+["16 17 BOOLOR", "NOP"],
+["11 10 1 ADD", "NUMEQUAL"],
+["11 10 1 ADD", "NUMEQUALVERIFY 1"],
+["11 10 1 ADD", "NUMNOTEQUAL NOT"],
+["111 10 1 ADD", "NUMNOTEQUAL"],
+["11 10", "LESSTHAN NOT"],
+["4 4", "LESSTHAN NOT"],
+["10 11", "LESSTHAN"],
+["-11 11", "LESSTHAN"],
+["-11 -10", "LESSTHAN"],
+["11 10", "GREATERTHAN"],
+["4 4", "GREATERTHAN NOT"],
+["10 11", "GREATERTHAN NOT"],
+["-11 11", "GREATERTHAN NOT"],
+["-11 -10", "GREATERTHAN NOT"],
+["11 10", "LESSTHANOREQUAL NOT"],
+["4 4", "LESSTHANOREQUAL"],
+["10 11", "LESSTHANOREQUAL"],
+["-11 11", "LESSTHANOREQUAL"],
+["-11 -10", "LESSTHANOREQUAL"],
+["11 10", "GREATERTHANOREQUAL"],
+["4 4", "GREATERTHANOREQUAL"],
+["10 11", "GREATERTHANOREQUAL NOT"],
+["-11 11", "GREATERTHANOREQUAL NOT"],
+["-11 -10", "GREATERTHANOREQUAL NOT"],
+["1 0 MIN", "0 NUMEQUAL"],
+["0 1 MIN", "0 NUMEQUAL"],
+["-1 0 MIN", "-1 NUMEQUAL"],
+["0 -2147483647 MIN", "-2147483647 NUMEQUAL"],
+["2147483647 0 MAX", "2147483647 NUMEQUAL"],
+["0 100 MAX", "100 NUMEQUAL"],
+["-100 0 MAX", "0 NUMEQUAL"],
+["0 -2147483647 MAX", "0 NUMEQUAL"],
+["0 0 1", "WITHIN"],
+["1 0 1", "WITHIN NOT"],
+["0 -2147483647 2147483647", "WITHIN"],
+["-1 -100 100", "WITHIN"],
+["11 -100 100", "WITHIN"],
+["-2147483647 -100 100", "WITHIN NOT"],
+["2147483647 -100 100", "WITHIN NOT"],
+
+["2147483647 2147483647 SUB", "0 EQUAL"],
+["2147483647 DUP ADD", "4294967294 EQUAL", ">32 bit EQUAL is valid"],
+["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL"],
+
+["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL"],
+["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL"],
+["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL"],
+["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL"],
+["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL"],
+["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL"],
+["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL"],
+["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL"],
+["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL"],
+["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL"],
+["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL"],
+["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL"],
+["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL"],
+["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL"],
+["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL"],
+["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL"],
+["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL"],
+
+
+["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL"],
+["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL"],
+
+["0", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"],
+["0", "IF 0xbb ELSE 1 ENDIF"],
+["0", "IF 0xbc ELSE 1 ENDIF"],
+["0", "IF 0xbd ELSE 1 ENDIF"],
+["0", "IF 0xbe ELSE 1 ENDIF"],
+["0", "IF 0xbf ELSE 1 ENDIF"],
+["0", "IF 0xc0 ELSE 1 ENDIF"],
+["0", "IF 0xc1 ELSE 1 ENDIF"],
+["0", "IF 0xc2 ELSE 1 ENDIF"],
+["0", "IF 0xc3 ELSE 1 ENDIF"],
+["0", "IF 0xc4 ELSE 1 ENDIF"],
+["0", "IF 0xc5 ELSE 1 ENDIF"],
+["0", "IF 0xc6 ELSE 1 ENDIF"],
+["0", "IF 0xc7 ELSE 1 ENDIF"],
+["0", "IF 0xc8 ELSE 1 ENDIF"],
+["0", "IF 0xc9 ELSE 1 ENDIF"],
+["0", "IF 0xca ELSE 1 ENDIF"],
+["0", "IF 0xcb ELSE 1 ENDIF"],
+["0", "IF 0xcc ELSE 1 ENDIF"],
+["0", "IF 0xcd ELSE 1 ENDIF"],
+["0", "IF 0xce ELSE 1 ENDIF"],
+["0", "IF 0xcf ELSE 1 ENDIF"],
+["0", "IF 0xd0 ELSE 1 ENDIF"],
+["0", "IF 0xd1 ELSE 1 ENDIF"],
+["0", "IF 0xd2 ELSE 1 ENDIF"],
+["0", "IF 0xd3 ELSE 1 ENDIF"],
+["0", "IF 0xd4 ELSE 1 ENDIF"],
+["0", "IF 0xd5 ELSE 1 ENDIF"],
+["0", "IF 0xd6 ELSE 1 ENDIF"],
+["0", "IF 0xd7 ELSE 1 ENDIF"],
+["0", "IF 0xd8 ELSE 1 ENDIF"],
+["0", "IF 0xd9 ELSE 1 ENDIF"],
+["0", "IF 0xda ELSE 1 ENDIF"],
+["0", "IF 0xdb ELSE 1 ENDIF"],
+["0", "IF 0xdc ELSE 1 ENDIF"],
+["0", "IF 0xdd ELSE 1 ENDIF"],
+["0", "IF 0xde ELSE 1 ENDIF"],
+["0", "IF 0xdf ELSE 1 ENDIF"],
+["0", "IF 0xe0 ELSE 1 ENDIF"],
+["0", "IF 0xe1 ELSE 1 ENDIF"],
+["0", "IF 0xe2 ELSE 1 ENDIF"],
+["0", "IF 0xe3 ELSE 1 ENDIF"],
+["0", "IF 0xe4 ELSE 1 ENDIF"],
+["0", "IF 0xe5 ELSE 1 ENDIF"],
+["0", "IF 0xe6 ELSE 1 ENDIF"],
+["0", "IF 0xe7 ELSE 1 ENDIF"],
+["0", "IF 0xe8 ELSE 1 ENDIF"],
+["0", "IF 0xe9 ELSE 1 ENDIF"],
+["0", "IF 0xea ELSE 1 ENDIF"],
+["0", "IF 0xeb ELSE 1 ENDIF"],
+["0", "IF 0xec ELSE 1 ENDIF"],
+["0", "IF 0xed ELSE 1 ENDIF"],
+["0", "IF 0xee ELSE 1 ENDIF"],
+["0", "IF 0xef ELSE 1 ENDIF"],
+["0", "IF 0xf0 ELSE 1 ENDIF"],
+["0", "IF 0xf1 ELSE 1 ENDIF"],
+["0", "IF 0xf2 ELSE 1 ENDIF"],
+["0", "IF 0xf3 ELSE 1 ENDIF"],
+["0", "IF 0xf4 ELSE 1 ENDIF"],
+["0", "IF 0xf5 ELSE 1 ENDIF"],
+["0", "IF 0xf6 ELSE 1 ENDIF"],
+["0", "IF 0xf7 ELSE 1 ENDIF"],
+["0", "IF 0xf8 ELSE 1 ENDIF"],
+["0", "IF 0xf9 ELSE 1 ENDIF"],
+["0", "IF 0xfa ELSE 1 ENDIF"],
+["0", "IF 0xfb ELSE 1 ENDIF"],
+["0", "IF 0xfc ELSE 1 ENDIF"],
+["0", "IF 0xfd ELSE 1 ENDIF"],
+["0", "IF 0xfe ELSE 1 ENDIF"],
+["0", "IF 0xff ELSE 1 ENDIF"],
+
+["NOP",
+"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",
+"520 byte push"],
+["1",
+"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
+"201 opcodes executed. 0x61 is NOP"],
+["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"1,000 stack size (0x6f is 3DUP)"],
+["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"],
+["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
+"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
+"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"],
+
+["0",
+"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1",
+">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."],
+
+["NOP","1"],
+
+["1", "0x01 0x01 EQUAL", "The following is useful for checking implementations of BN_bn2mpi"],
+["127", "0x01 0x7F EQUAL"],
+["128", "0x02 0x8000 EQUAL", "Leave room for the sign bit"],
+["32767", "0x02 0xFF7F EQUAL"],
+["32768", "0x03 0x008000 EQUAL"],
+["8388607", "0x03 0xFFFF7F EQUAL"],
+["8388608", "0x04 0x00008000 EQUAL"],
+["2147483647", "0x04 0xFFFFFF7F EQUAL"],
+["2147483648", "0x05 0x0000008000 EQUAL"],
+["-1", "0x01 0x81 EQUAL", "Numbers are little-endian with the MSB being a sign bit"],
+["-127", "0x01 0xFF EQUAL"],
+["-128", "0x02 0x8080 EQUAL"],
+["-32767", "0x02 0xFFFF EQUAL"],
+["-32768", "0x03 0x008080 EQUAL"],
+["-8388607", "0x03 0xFFFFFF EQUAL"],
+["-8388608", "0x04 0x00008080 EQUAL"],
+["-2147483647", "0x04 0xFFFFFFFF EQUAL"],
+["-2147483648", "0x05 0x0000008080 EQUAL"],
+
+["2147483647", "1ADD 2147483648 EQUAL", "We can do math on 4-byte integers, and compare 5-byte ones"],
+["2147483647", "1ADD 1"],
+["-2147483647", "1ADD 1"],
+
+["1", "0x02 0x0100 EQUAL NOT", "Not the same byte array..."],
+["1", "0x02 0x0100 NUMEQUAL", "... but they are numerically equal"],
+["11", "0x4c 0x03 0x0b0000 NUMEQUAL"],
+["0", "0x01 0x80 EQUAL NOT"],
+["0", "0x01 0x80 NUMEQUAL", "Zero numerically equals negative zero"],
+["0", "0x02 0x0080 NUMEQUAL"],
+["0x03 0x000080", "0x04 0x00000080 NUMEQUAL"],
+["0x03 0x100080", "0x04 0x10000080 NUMEQUAL"],
+["0x03 0x100000", "0x04 0x10000000 NUMEQUAL"],
+
+["NOP", "NOP 1", "The following tests check the if(stack.size() < N) tests in each opcode"],
+["1", "IF 1 ENDIF", "They are here to catch copy-and-paste errors"],
+["0", "NOTIF 1 ENDIF", "Most of them are duplicated elsewhere,"],
+["1", "VERIFY 1", "but, hey, more is always better, right?"],
+
+["0", "TOALTSTACK 1"],
+["1", "TOALTSTACK FROMALTSTACK"],
+["0 0", "2DROP 1"],
+["0 1", "2DUP"],
+["0 0 1", "3DUP"],
+["0 1 0 0", "2OVER"],
+["0 1 0 0 0 0", "2ROT"],
+["0 1 0 0", "2SWAP"],
+["1", "IFDUP"],
+["NOP", "DEPTH 1"],
+["0", "DROP 1"],
+["1", "DUP"],
+["0 1", "NIP"],
+["1 0", "OVER"],
+["1 0 0 0 3", "PICK"],
+["1 0", "PICK"],
+["1 0 0 0 3", "ROLL"],
+["1 0", "ROLL"],
+["1 0 0", "ROT"],
+["1 0", "SWAP"],
+["0 1", "TUCK"],
+
+["1", "SIZE"],
+
+["0 0", "EQUAL"],
+["0 0", "EQUALVERIFY 1"],
+
+["0", "1ADD"],
+["2", "1SUB"],
+["-1", "NEGATE"],
+["-1", "ABS"],
+["0", "NOT"],
+["-1", "0NOTEQUAL"],
+
+["1 0", "ADD"],
+["1 0", "SUB"],
+["-1 -1", "BOOLAND"],
+["-1 0", "BOOLOR"],
+["0 0", "NUMEQUAL"],
+["0 0", "NUMEQUALVERIFY 1"],
+["-1 0", "NUMNOTEQUAL"],
+["-1 0", "LESSTHAN"],
+["1 0", "GREATERTHAN"],
+["0 0", "LESSTHANOREQUAL"],
+["0 0", "GREATERTHANOREQUAL"],
+["-1 0", "MIN"],
+["1 0", "MAX"],
+["-1 -1 0", "WITHIN"],
+
+["0", "RIPEMD160"],
+["0", "SHA1"],
+["0", "SHA256"],
+["0", "HASH160"],
+["0", "HASH256"],
+["NOP", "CODESEPARATOR 1"],
+
+["NOP", "NOP1 1"],
+["NOP", "NOP2 1"],
+["NOP", "NOP3 1"],
+["NOP", "NOP4 1"],
+["NOP", "NOP5 1"],
+["NOP", "NOP6 1"],
+["NOP", "NOP7 1"],
+["NOP", "NOP8 1"],
+["NOP", "NOP9 1"],
+["NOP", "NOP10 1"],
+
+["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Very basic P2SH"],
+["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"],
+
+["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242",
+"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL",
+"Basic PUSH signedness check"],
+
+["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242",
+"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL",
+"Basic PUSHDATA1 signedness check"]
+]
diff --git a/src/test/data/sig_canonical.json b/src/test/data/sig_canonical.json
new file mode 100644
index 000000000..e43a08629
--- /dev/null
+++ b/src/test/data/sig_canonical.json
@@ -0,0 +1,7 @@
+[
+ "300602010002010001",
+ "3008020200ff020200ff01",
+ "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001",
+ "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01",
+ "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"
+]
diff --git a/src/test/data/sig_noncanonical.json b/src/test/data/sig_noncanonical.json
new file mode 100644
index 000000000..d9a6c1cdd
--- /dev/null
+++ b/src/test/data/sig_noncanonical.json
@@ -0,0 +1,22 @@
+[
+ "non-hex strings are ignored",
+
+ "too short:", "30050201FF020001",
+ "too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11",
+ "type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101",
+ "R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001",
+
+ "R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+
+
+ "S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001",
+ "S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
+ "S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"
+]
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
new file mode 100644
index 000000000..e386f81fe
--- /dev/null
+++ b/src/test/data/tx_invalid.json
@@ -0,0 +1,74 @@
+[
+["The following are deserialized transactions which are invalid."],
+["They are in the form"],
+["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
+["serializedTransaction, enforceP2SH]"],
+["Objects that are only a single string (like this one) are ignored"],
+
+["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"],
+[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]],
+"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", true],
+
+["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"],
+["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"],
+["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true],
+
+["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true],
+
+["An invalid P2SH Transaction"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true],
+
+["Tests for CheckTransaction()"],
+["No inputs"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
+"0100000000010000000000000000015100000000", true],
+
+["No outputs"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", true],
+
+["Negative output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", true],
+
+["MAX_MONEY + 1 output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", true],
+
+["MAX_MONEY output + 1 output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", true],
+
+["Duplicate inputs"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]],
+"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", true],
+
+["Coinbase of size 1"],
+["Note the input is just required to make the tester happy"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", true],
+
+["Coinbase of size 101"],
+["Note the input is just required to make the tester happy"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true],
+
+["Null txin"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true],
+
+["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
+ ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
+ "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true],
+
+["Incorrect signature order"],
+["Note the input is just required to make the tester happy"],
+[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
+"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true]
+]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
new file mode 100644
index 000000000..c33a7a035
--- /dev/null
+++ b/src/test/data/tx_valid.json
@@ -0,0 +1,96 @@
+[
+["The following are deserialized transactions which are valid."],
+["They are in the form"],
+["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
+["serializedTransaction, enforceP2SH]"],
+["Objects that are only a single string (like this one) are ignored"],
+
+["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
+["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"],
+["See http://r6.ca/blog/20111119T211504Z.html"],
+["It is also the first OP_CHECKMULTISIG transaction in standard form"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true],
+
+["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
+["It has an arbitrary extra byte stuffed into the signature at pos length - 2"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true],
+
+["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"],
+["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"],
+[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]],
+"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", true],
+
+["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true],
+
+["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true],
+
+["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
+["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
+[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
+["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
+"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", true],
+
+["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
+["It results in signing the constant 1, instead of something generated based on the transaction,"],
+["when the input doing the signing has an index greater than the maximum output index"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
+"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", true],
+
+["An invalid P2SH Transaction"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", false],
+
+["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true],
+
+["Tests for CheckTransaction()"],
+["MAX_MONEY output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true],
+
+["MAX_MONEY output + 0 output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", true],
+
+["Coinbase of size 2"],
+["Note the input is just required to make the tester happy"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", true],
+
+["Coinbase of size 100"],
+["Note the input is just required to make the tester happy"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true],
+
+["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
+ ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
+ "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true],
+
+["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
+ ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
+ "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true],
+
+["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"],
+[[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
+ ["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
+ ["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]],
+ "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", true],
+
+ ["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"],
+ [[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]],
+ "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", true],
+
+["Correct signature order"],
+["Note the input is just required to make the tester happy"],
+[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
+"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true]
+]
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
new file mode 100644
index 000000000..d76124885
--- /dev/null
+++ b/src/test/getarg_tests.cpp
@@ -0,0 +1,158 @@
+
+
+#include "util.h"
+
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+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", false));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+
+ BOOST_CHECK(!GetBoolArg("-fo", false));
+ BOOST_CHECK(GetBoolArg("-fo", true));
+
+ BOOST_CHECK(!GetBoolArg("-fooo", false));
+ BOOST_CHECK(GetBoolArg("-fooo", true));
+
+ ResetArgs("-foo=0");
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+
+ ResetArgs("-foo=1");
+ 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", false));
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+
+ ResetArgs("-nofoo=1");
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+
+ ResetArgs("-foo -nofoo"); // -foo should win
+ BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+
+ ResetArgs("-foo=1 -nofoo=1"); // -foo should win
+ BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+
+ ResetArgs("-foo=0 -nofoo=0"); // -foo should win
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+
+ // New 0.6 feature: treat -- same as -:
+ ResetArgs("--foo=1");
+ BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+
+ ResetArgs("--nofoo=1");
+ 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", false), 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", true));
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+
+ ResetArgs("-nofoo=1");
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+
+ ResetArgs("-nofoo=0");
+ BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(GetBoolArg("-foo", false));
+
+ ResetArgs("-foo --nofoo");
+ BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(GetBoolArg("-foo", false));
+
+ ResetArgs("-nofoo -foo"); // foo always wins:
+ BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(GetBoolArg("-foo", false));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
new file mode 100644
index 000000000..28410f0fe
--- /dev/null
+++ b/src/test/hash_tests.cpp
@@ -0,0 +1,47 @@
+
+
+#include "hash.h"
+#include "util.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(hash_tests)
+
+BOOST_AUTO_TEST_CASE(murmurhash3)
+{
+
+#define T(expected, seed, data) BOOST_CHECK_EQUAL(MurmurHash3(seed, ParseHex(data)), expected)
+
+ // Test MurmurHash3 with various inputs. Of course this is retested in the
+ // bloom filter tests - they would fail if MurmurHash3() had any problems -
+ // but is useful for those trying to implement Bitcoin libraries as a
+ // source of test data for their MurmurHash3() primitive during
+ // development.
+ //
+ // The magic number 0xFBA4C795 comes from CBloomFilter::Hash()
+
+ T(0x00000000, 0x00000000, "");
+ T(0x6a396f08, 0xFBA4C795, "");
+ T(0x81f16f39, 0xffffffff, "");
+
+ T(0x514e28b7, 0x00000000, "00");
+ T(0xea3f0b17, 0xFBA4C795, "00");
+ T(0xfd6cf10d, 0x00000000, "ff");
+
+ T(0x16c6b7ab, 0x00000000, "0011");
+ T(0x8eb51c3d, 0x00000000, "001122");
+ T(0xb4471bf8, 0x00000000, "00112233");
+ T(0xe2301fa8, 0x00000000, "0011223344");
+ T(0xfc2e4a15, 0x00000000, "001122334455");
+ T(0xb074502c, 0x00000000, "00112233445566");
+ T(0x8034d2a0, 0x00000000, "0011223344556677");
+ T(0xb4698def, 0x00000000, "001122334455667788");
+
+#undef T
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/hmac_tests.cpp b/src/test/hmac_tests.cpp
new file mode 100644
index 000000000..68868866a
--- /dev/null
+++ b/src/test/hmac_tests.cpp
@@ -0,0 +1,127 @@
+
+
+#include "hash.h"
+#include "util.h"
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(hmac_tests)
+
+typedef struct {
+ const char *pszKey;
+ const char *pszData;
+ const char *pszMAC;
+} testvec_t;
+
+// test cases 1, 2, 3, 4, 6 and 7 of RFC 4231
+static const testvec_t vtest[] = {
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
+ "0b0b0b0b",
+ "4869205468657265",
+ "87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"
+ },
+ {
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"
+ },
+ {
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58"
+ }
+};
+
+BOOST_AUTO_TEST_CASE(hmacsha512_testvectors)
+{
+ for (unsigned int n=0; n<sizeof(vtest)/sizeof(vtest[0]); n++)
+ {
+ vector<unsigned char> vchKey = ParseHex(vtest[n].pszKey);
+ vector<unsigned char> vchData = ParseHex(vtest[n].pszData);
+ vector<unsigned char> vchMAC = ParseHex(vtest[n].pszMAC);
+ unsigned char vchTemp[64];
+
+ HMAC_SHA512_CTX ctx;
+ HMAC_SHA512_Init(&ctx, &vchKey[0], vchKey.size());
+ HMAC_SHA512_Update(&ctx, &vchData[0], vchData.size());
+ HMAC_SHA512_Final(&vchTemp[0], &ctx);
+
+ BOOST_CHECK(memcmp(&vchTemp[0], &vchMAC[0], 64) == 0);
+
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
new file mode 100644
index 000000000..421ffeac4
--- /dev/null
+++ b/src/test/key_tests.cpp
@@ -0,0 +1,143 @@
+#include "key.h"
+
+#include "base58.h"
+#include "script.h"
+#include "uint256.h"
+#include "util.h"
+
+#include <string>
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
+static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
+static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
+static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
+static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
+static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
+static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
+static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
+
+
+static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
+
+
+#ifdef KEY_TESTS_DUMPINFO
+void dumpKeyInfo(uint256 privkey)
+{
+ CKey key;
+ key.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));
+
+ CKey key1 = bsecret1.GetKey();
+ BOOST_CHECK(key1.IsCompressed() == false);
+ CKey key2 = bsecret2.GetKey();
+ BOOST_CHECK(key2.IsCompressed() == false);
+ CKey key1C = bsecret1C.GetKey();
+ BOOST_CHECK(key1C.IsCompressed() == true);
+ CKey key2C = bsecret2C.GetKey();
+ BOOST_CHECK(key1C.IsCompressed() == true);
+
+ CPubKey pubkey1 = key1. GetPubKey();
+ CPubKey pubkey2 = key2. GetPubKey();
+ CPubKey pubkey1C = key1C.GetPubKey();
+ CPubKey pubkey2C = key2C.GetPubKey();
+
+ BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
+ BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
+ BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
+ BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.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( pubkey1.Verify(hashMsg, sign1));
+ BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
+ BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
+ BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
+
+ BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
+ BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
+ BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
+ BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
+
+ BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
+ BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
+ BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
+ BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
+
+ BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
+ BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
+ BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
+ BOOST_CHECK( pubkey2C.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));
+
+ CPubKey rkey1, rkey2, rkey1C, rkey2C;
+
+ BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
+ BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
+ BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
+ BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
+
+ BOOST_CHECK(rkey1 == pubkey1);
+ BOOST_CHECK(rkey2 == pubkey2);
+ BOOST_CHECK(rkey1C == pubkey1C);
+ BOOST_CHECK(rkey2C == pubkey2C);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
new file mode 100644
index 000000000..8e3091d55
--- /dev/null
+++ b/src/test/miner_tests.cpp
@@ -0,0 +1,237 @@
+
+
+#include "main.h"
+#include "miner.h"
+#include "uint256.h"
+#include "util.h"
+
+#include <boost/test/unit_test.hpp>
+
+extern void SHA256Transform(void* pstate, void* pinput, const void* pinit);
+
+BOOST_AUTO_TEST_SUITE(miner_tests)
+
+static
+struct {
+ unsigned char extranonce;
+ unsigned int nonce;
+} blockinfo[] = {
+ {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5},
+ {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84},
+ {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4},
+ {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa},
+ {1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb},
+ {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406},
+ {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38},
+ {2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9},
+ {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7},
+ {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34},
+ {1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c},
+ {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f},
+ {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81},
+ {1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78},
+ {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c},
+ {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049},
+ {2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169},
+ {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10},
+ {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d},
+ {2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323},
+ {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6},
+ {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408},
+ {1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602},
+ {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459},
+ {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668},
+ {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce},
+ {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e},
+ {2, 0xbbbeb305}, {2, 0xfe1c810a},
+};
+
+// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
+BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
+{
+ CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
+ CBlockTemplate *pblocktemplate;
+ CTransaction tx;
+ CScript script;
+ uint256 hash;
+
+ LOCK(cs_main);
+
+ // Simple block creation, nothing special yet:
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+
+ // We can't make transactions until we have inputs
+ // Therefore, load 100 blocks :)
+ std::vector<CTransaction*>txFirst;
+ for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
+ {
+ CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ pblock->nVersion = 1;
+ pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
+ pblock->vtx[0].vin[0].scriptSig = CScript();
+ pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce);
+ pblock->vtx[0].vin[0].scriptSig.push_back(chainActive.Height());
+ pblock->vtx[0].vout[0].scriptPubKey = CScript();
+ if (txFirst.size() < 2)
+ txFirst.push_back(new CTransaction(pblock->vtx[0]));
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+ pblock->nNonce = blockinfo[i].nonce;
+ CValidationState state;
+ BOOST_CHECK(ProcessBlock(state, NULL, pblock));
+ BOOST_CHECK(state.IsValid());
+ pblock->hashPrevBlock = pblock->GetHash();
+ }
+ delete pblocktemplate;
+
+ // Just to make sure we can still make simple blocks
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+
+ // block sigops > limit: 1000 CHECKMULTISIG + 1
+ tx.vin.resize(1);
+ // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
+ tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 5000000000LL;
+ for (unsigned int i = 0; i < 1001; ++i)
+ {
+ tx.vout[0].nValue -= 1000000;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ tx.vin[0].prevout.hash = hash;
+ }
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // block size > limit
+ tx.vin[0].scriptSig = CScript();
+ // 18 * (520char + DROP) + OP_1 = 9433 bytes
+ std::vector<unsigned char> vchData(520);
+ for (unsigned int i = 0; i < 18; ++i)
+ tx.vin[0].scriptSig << vchData << OP_DROP;
+ tx.vin[0].scriptSig << OP_1;
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vout[0].nValue = 5000000000LL;
+ for (unsigned int i = 0; i < 128; ++i)
+ {
+ tx.vout[0].nValue -= 10000000;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ tx.vin[0].prevout.hash = hash;
+ }
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // orphan in mempool
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // child with higher priority than parent
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vin[0].prevout.hash = txFirst[1]->GetHash();
+ tx.vout[0].nValue = 4900000000LL;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin.resize(2);
+ tx.vin[1].scriptSig = CScript() << OP_1;
+ tx.vin[1].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[1].prevout.n = 0;
+ tx.vout[0].nValue = 5900000000LL;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // coinbase in mempool
+ tx.vin.resize(1);
+ tx.vin[0].prevout.SetNull();
+ tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
+ tx.vout[0].nValue = 0;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // invalid (pre-p2sh) txn in mempool
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = 4900000000LL;
+ script = CScript() << OP_0;
+ tx.vout[0].scriptPubKey.SetDestination(script.GetID());
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
+ tx.vout[0].nValue -= 1000000;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // double spend txn pair in mempool
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = 4900000000LL;
+ tx.vout[0].scriptPubKey = CScript() << OP_1;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ tx.vout[0].scriptPubKey = CScript() << OP_2;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ mempool.clear();
+
+ // subsidy changing
+ int nHeight = chainActive.Height();
+ chainActive.Tip()->nHeight = 209999;
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ chainActive.Tip()->nHeight = 210000;
+ BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
+ delete pblocktemplate;
+ chainActive.Tip()->nHeight = nHeight;
+
+ BOOST_FOREACH(CTransaction *tx, txFirst)
+ delete tx;
+}
+
+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()
diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp
new file mode 100644
index 000000000..638c88fab
--- /dev/null
+++ b/src/test/mruset_tests.cpp
@@ -0,0 +1,93 @@
+#include "mruset.h"
+
+#include "util.h"
+
+#include <set>
+
+#include <boost/test/unit_test.hpp>
+
+#define NUM_TESTS 16
+#define MAX_SIZE 100
+
+using namespace std;
+
+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()
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
new file mode 100644
index 000000000..772217b88
--- /dev/null
+++ b/src/test/multisig_tests.cpp
@@ -0,0 +1,294 @@
+
+
+#include "key.h"
+#include "keystore.h"
+#include "main.h"
+#include "script.h"
+#include "uint256.h"
+
+#include <boost/assign/std/vector.hpp>
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost::assign;
+
+typedef vector<unsigned char> valtype;
+
+extern uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, 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(const 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)
+{
+ unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
+
+ 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, flags, 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, flags, 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, flags, 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, flags, 0), strprintf("a|b: %d", i));
+ else
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i));
+ }
+ s.clear();
+ s << OP_0 << OP_0;
+ BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0));
+ s.clear();
+ s << OP_0 << OP_1;
+ BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 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, flags, 0), strprintf("escrow 1: %d %d", i, j));
+ else
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags, 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);
+
+ txnouttype whichType;
+
+ 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, whichType));
+
+ 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, whichType));
+
+ CScript escrow;
+ escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+ BOOST_CHECK(::IsStandard(escrow, whichType));
+
+ 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, whichType));
+
+ 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], whichType));
+}
+
+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(), 4U);
+ 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(), 4U);
+ 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()
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
new file mode 100644
index 000000000..412ba0491
--- /dev/null
+++ b/src/test/netbase_tests.cpp
@@ -0,0 +1,101 @@
+#include "netbase.h"
+
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+
+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.bitcoin.org", "www.bitcoin.org", -1));
+ BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1));
+ BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80));
+ BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.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()
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
new file mode 100644
index 000000000..dea5e1b82
--- /dev/null
+++ b/src/test/pmt_tests.cpp
@@ -0,0 +1,103 @@
+
+
+#include "main.h"
+#include "serialize.h"
+#include "uint256.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+class CPartialMerkleTreeTester : public CPartialMerkleTree
+{
+public:
+ // flip one bit in one of the hashes - this should break the authentication
+ void Damage() {
+ unsigned int n = rand() % vHash.size();
+ int bit = rand() % 256;
+ uint256 &hash = vHash[n];
+ hash ^= ((uint256)1 << bit);
+ }
+};
+
+BOOST_AUTO_TEST_SUITE(pmt_tests)
+
+BOOST_AUTO_TEST_CASE(pmt_test1)
+{
+ static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095};
+
+ for (int n = 0; n < 12; n++) {
+ unsigned int nTx = nTxCounts[n];
+
+ // build a block with some dummy transactions
+ CBlock block;
+ for (unsigned int j=0; j<nTx; j++) {
+ CTransaction tx;
+ tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique
+ block.vtx.push_back(tx);
+ }
+
+ // calculate actual merkle root and height
+ uint256 merkleRoot1 = block.BuildMerkleTree();
+ std::vector<uint256> vTxid(nTx, 0);
+ for (unsigned int j=0; j<nTx; j++)
+ vTxid[j] = block.vtx[j].GetHash();
+ int nHeight = 1, nTx_ = nTx;
+ while (nTx_ > 1) {
+ nTx_ = (nTx_+1)/2;
+ nHeight++;
+ }
+
+ // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128
+ for (int att = 1; att < 15; att++) {
+ // build random subset of txid's
+ std::vector<bool> vMatch(nTx, false);
+ std::vector<uint256> vMatchTxid1;
+ for (unsigned int j=0; j<nTx; j++) {
+ bool fInclude = (rand() & ((1 << (att/2)) - 1)) == 0;
+ vMatch[j] = fInclude;
+ if (fInclude)
+ vMatchTxid1.push_back(vTxid[j]);
+ }
+
+ // build the partial merkle tree
+ CPartialMerkleTree pmt1(vTxid, vMatch);
+
+ // serialize
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss << pmt1;
+
+ // verify CPartialMerkleTree's size guarantees
+ unsigned int n = std::min<unsigned int>(nTx, 1 + vMatchTxid1.size()*nHeight);
+ BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8);
+
+ // deserialize into a tester copy
+ CPartialMerkleTreeTester pmt2;
+ ss >> pmt2;
+
+ // extract merkle root and matched txids from copy
+ std::vector<uint256> vMatchTxid2;
+ uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2);
+
+ // check that it has the same merkle root as the original, and a valid one
+ BOOST_CHECK(merkleRoot1 == merkleRoot2);
+ BOOST_CHECK(merkleRoot2 != 0);
+
+ // check that it contains the matched transactions (in the same order!)
+ BOOST_CHECK(vMatchTxid1 == vMatchTxid2);
+
+ // check that random bit flips break the authentication
+ for (int j=0; j<4; j++) {
+ CPartialMerkleTreeTester pmt3(pmt2);
+ pmt3.Damage();
+ std::vector<uint256> vMatchTxid3;
+ uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3);
+ BOOST_CHECK(merkleRoot3 != merkleRoot1);
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
new file mode 100644
index 000000000..29195545d
--- /dev/null
+++ b/src/test/rpc_tests.cpp
@@ -0,0 +1,137 @@
+#include "rpcserver.h"
+#include "rpcclient.h"
+
+#include "base58.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace json_spirit;
+
+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(address2);
+ result.push_back(addresses);
+ return result;
+}
+
+Value CallRPC(string args)
+{
+ vector<string> vArgs;
+ boost::split(vArgs, args, boost::is_any_of(" \t"));
+ string strMethod = vArgs[0];
+ vArgs.erase(vArgs.begin());
+ Array params = RPCConvertValues(strMethod, vArgs);
+
+ rpcfn_type method = tableRPC[strMethod]->actor;
+ try {
+ Value result = (*method)(params, false);
+ return result;
+ }
+ catch (Object& objError)
+ {
+ throw runtime_error(find_value(objError, "message").get_str());
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE(rpc_tests)
+
+BOOST_AUTO_TEST_CASE(rpc_rawparams)
+{
+ // Test raw transaction API argument handling
+ Value r;
+
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}"));
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
+ string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
+ BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx));
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
+ BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error);
+
+ // Only check failure cases for sendrawtransaction, there's no network to send to...
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_rawsign)
+{
+ Value r;
+ // input is a 1-of-2 multisig (so is output):
+ string prevout =
+ "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
+ "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\","
+ "\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]";
+ r = CallRPC(string("createrawtransaction ")+prevout+" "+
+ "{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}");
+ string notsigned = r.get_str();
+ string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
+ string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
+ r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]");
+ BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
+ r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]");
+ BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
+{
+ BOOST_CHECK(write_string(ValueFromAmount(0LL), false) == "0.00000000");
+ BOOST_CHECK(write_string(ValueFromAmount(1LL), false) == "0.00000001");
+ BOOST_CHECK(write_string(ValueFromAmount(17622195LL), false) == "0.17622195");
+ BOOST_CHECK(write_string(ValueFromAmount(50000000LL), false) == "0.50000000");
+ BOOST_CHECK(write_string(ValueFromAmount(89898989LL), false) == "0.89898989");
+ BOOST_CHECK(write_string(ValueFromAmount(100000000LL), false) == "1.00000000");
+ BOOST_CHECK(write_string(ValueFromAmount(2099999999999990LL), false) == "20999999.99999990");
+ BOOST_CHECK(write_string(ValueFromAmount(2099999999999999LL), false) == "20999999.99999999");
+}
+
+static Value ValueFromString(const std::string &str)
+{
+ Value value;
+ BOOST_CHECK(read_string(str, value));
+ return value;
+}
+
+BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
+{
+ BOOST_CHECK(AmountFromValue(ValueFromString("0.00000001")) == 1LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("0.17622195")) == 17622195LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("0.5")) == 50000000LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("0.50000000")) == 50000000LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("0.89898989")) == 89898989LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("1.00000000")) == 100000000LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("20999999.9999999")) == 2099999999999990LL);
+ BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
new file mode 100644
index 000000000..2cf0fb350
--- /dev/null
+++ b/src/test/rpc_wallet_tests.cpp
@@ -0,0 +1,82 @@
+#include "rpcserver.h"
+#include "rpcclient.h"
+
+#include "base58.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace json_spirit;
+
+extern Array createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL);
+extern Value CallRPC(string args);
+
+BOOST_AUTO_TEST_SUITE(rpc_wallet_tests)
+
+BOOST_AUTO_TEST_CASE(rpc_addmultisig)
+{
+ 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_CASE(rpc_wallet)
+{
+ // Test RPC calls for various wallet statistics
+ Value r;
+
+ BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
+ BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
+ BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
+ BOOST_CHECK(r.get_array().empty());
+
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
new file mode 100644
index 000000000..e57dc9bbb
--- /dev/null
+++ b/src/test/script_P2SH_tests.cpp
@@ -0,0 +1,341 @@
+#include "script.h"
+
+#include "key.h"
+#include "keystore.h"
+#include "main.h"
+#include "script.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+// Test routines internal to script.cpp:
+extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, 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 ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 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:
+ string reason;
+ txFrom.vout.resize(8);
+ for (int i = 0; i < 4; i++)
+ {
+ txFrom.vout[i].scriptPubKey = evalScripts[i];
+ txFrom.vout[i].nValue = COIN;
+ txFrom.vout[i+4].scriptPubKey = standardScripts[i];
+ txFrom.vout[i+4].nValue = COIN;
+ }
+ BOOST_CHECK(IsStandardTx(txFrom, reason));
+
+ 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(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 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 recur, 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<CPubKey> keys;
+ for (int i = 0; i < 4; i++)
+ {
+ key[i].MakeNewKey(true);
+ keystore.AddKey(key[i]);
+ keys.push_back(key[i].GetPubKey());
+ }
+
+ CScript inner[4];
+ inner[0].SetDestination(key[0].GetPubKey().GetID());
+ inner[1].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
+ inner[2].SetMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
+ inner[3].SetMultisig(2, std::vector<CPubKey>(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:
+ string reason;
+ txFrom.vout.resize(4);
+ for (int i = 0; i < 4; i++)
+ {
+ txFrom.vout[i].scriptPubKey = outer[i];
+ txFrom.vout[i].nValue = CENT;
+ }
+ BOOST_CHECK(IsStandardTx(txFrom, reason));
+
+ 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*CENT;
+ 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(IsStandardTx(txTo[i], reason), 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 switch over 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)
+{
+ CCoinsView coinsDummy;
+ CCoinsViewCache coins(coinsDummy);
+ CBasicKeyStore keystore;
+ CKey key[3];
+ vector<CPubKey> keys;
+ for (int i = 0; i < 3; i++)
+ {
+ key[i].MakeNewKey(true);
+ keystore.AddKey(key[i]);
+ keys.push_back(key[i].GetPubKey());
+ }
+
+ 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[0].nValue = 1000;
+ txFrom.vout[1].scriptPubKey = pay1;
+ txFrom.vout[1].nValue = 2000;
+ txFrom.vout[2].scriptPubKey = pay1of3;
+ txFrom.vout[2].nValue = 3000;
+
+ // Last three non-standard:
+ CScript empty;
+ keystore.AddCScript(empty);
+ txFrom.vout[3].scriptPubKey = empty;
+ txFrom.vout[3].nValue = 4000;
+ // Can't use SetPayToScriptHash, it checks for the empty Script. So:
+ txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL;
+ txFrom.vout[4].nValue = 5000;
+ 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());
+ txFrom.vout[5].nValue = 6000;
+
+ coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
+
+ 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(::AreInputsStandard(txTo, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 1U);
+
+ // 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(!::AreInputsStandard(txTo, coins));
+ txTo.vin[i].scriptSig = t;
+ }
+
+ CTransaction txToNonStd;
+ txToNonStd.vout.resize(1);
+ txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
+ txToNonStd.vout[0].nValue = 1000;
+ 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(!::AreInputsStandard(txToNonStd, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd, coins), 11U);
+
+ txToNonStd.vin[0].scriptSig.clear();
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
new file mode 100644
index 000000000..dee0f110a
--- /dev/null
+++ b/src/test/script_tests.cpp
@@ -0,0 +1,441 @@
+#include "script.h"
+
+#include "data/script_invalid.json.h"
+#include "data/script_valid.json.h"
+
+#include "key.h"
+#include "keystore.h"
+#include "main.h"
+
+#include <fstream>
+#include <stdint.h>
+#include <string>
+#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/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_utils.h"
+#include "json/json_spirit_writer_template.h"
+
+using namespace std;
+using namespace json_spirit;
+using namespace boost::algorithm;
+
+extern uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+
+static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
+
+CScript
+ParseScript(string s)
+{
+ CScript result;
+
+ static map<string, opcodetype> mapOpNames;
+
+ if (mapOpNames.size() == 0)
+ {
+ for (int op = 0; op <= OP_NOP10; op++)
+ {
+ // Allow OP_RESERVED to get into mapOpNames
+ if (op < OP_NOP && op != OP_RESERVED)
+ continue;
+
+ 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_t 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 ADD:
+ result << mapOpNames[w];
+ }
+ else
+ {
+ BOOST_ERROR("Parse error: " << s);
+ return CScript();
+ }
+ }
+
+ return result;
+}
+
+Array
+read_json(const std::string& jsondata)
+{
+ Value v;
+
+ if (!read_string(jsondata, v) || v.type() != array_type)
+ {
+ BOOST_ERROR("Parse error.");
+ 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(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+
+ 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, flags, SIGHASH_NONE), strTest);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(script_invalid)
+{
+ // Scripts that should evaluate as invalid
+ Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+
+ 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, flags, 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, true, 0));
+
+ vector<vector<unsigned char> > pushdata1Stack;
+ BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, true, 0));
+ BOOST_CHECK(pushdata1Stack == directStack);
+
+ vector<vector<unsigned char> > pushdata2Stack;
+ BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, true, 0));
+ BOOST_CHECK(pushdata2Stack == directStack);
+
+ vector<vector<unsigned char> > pushdata4Stack;
+ BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, true, 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 block chain (old
+ // clients would not accept new CHECKMULTISIG transactions,
+ // and vice-versa)
+ //
+ result << OP_0;
+ BOOST_FOREACH(const 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, const 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, flags, 0));
+ txTo12.vout[0].nValue = 2;
+ BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0));
+
+ CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, flags, 0));
+
+ CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, flags, 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, flags, 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, flags, 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, flags, 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, flags, 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, flags, 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, flags, 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, flags, 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, flags, 0));
+
+ keys.clear(); // Must have signatures
+ CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
+ BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, flags, 0));
+}
+
+BOOST_AUTO_TEST_CASE(script_combineSigs)
+{
+ // Test the CombineSignatures function
+ CBasicKeyStore keystore;
+ vector<CKey> keys;
+ vector<CPubKey> pubkeys;
+ for (int i = 0; i < 3; i++)
+ {
+ CKey key;
+ key.MakeNewKey(i%2 == 1);
+ keys.push_back(key);
+ pubkeys.push_back(key.GetPubKey());
+ 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, pubkeys);
+ 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()
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
new file mode 100644
index 000000000..415f95781
--- /dev/null
+++ b/src/test/serialize_tests.cpp
@@ -0,0 +1,159 @@
+#include "serialize.h"
+
+#include <stdint.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(serialize_tests)
+
+BOOST_AUTO_TEST_CASE(varints)
+{
+ // encode
+
+ CDataStream ss(SER_DISK, 0);
+ CDataStream::size_type size = 0;
+ for (int i = 0; i < 100000; i++) {
+ ss << VARINT(i);
+ size += ::GetSerializeSize(VARINT(i), 0, 0);
+ BOOST_CHECK(size == ss.size());
+ }
+
+ for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
+ ss << VARINT(i);
+ size += ::GetSerializeSize(VARINT(i), 0, 0);
+ BOOST_CHECK(size == ss.size());
+ }
+
+ // decode
+ for (int i = 0; i < 100000; i++) {
+ int j = -1;
+ ss >> VARINT(j);
+ BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
+ }
+
+ for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
+ uint64_t j = -1;
+ ss >> VARINT(j);
+ BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(compactsize)
+{
+ CDataStream ss(SER_DISK, 0);
+ vector<char>::size_type i, j;
+
+ for (i = 1; i <= MAX_SIZE; i *= 2)
+ {
+ WriteCompactSize(ss, i-1);
+ WriteCompactSize(ss, i);
+ }
+ for (i = 1; i <= MAX_SIZE; i *= 2)
+ {
+ j = ReadCompactSize(ss);
+ BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
+ j = ReadCompactSize(ss);
+ BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
+ }
+}
+
+static bool isCanonicalException(const std::ios_base::failure& ex)
+{
+ std::ios_base::failure expectedException("non-canonical ReadCompactSize()");
+
+ // The string returned by what() can be different for different platforms.
+ // Instead of directly comparing the ex.what() with an expected string,
+ // create an instance of exception to see if ex.what() matches
+ // the expected explanatory string returned by the exception instance.
+ return strcmp(expectedException.what(), ex.what()) == 0;
+}
+
+
+BOOST_AUTO_TEST_CASE(noncanonical)
+{
+ // Write some non-canonical CompactSize encodings, and
+ // make sure an exception is thrown when read back.
+ CDataStream ss(SER_DISK, 0);
+ vector<char>::size_type n;
+
+ // zero encoded with three bytes:
+ ss.write("\xfd\x00\x00", 3);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0xfc encoded with three bytes:
+ ss.write("\xfd\xfc\x00", 3);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0xfd encoded with three bytes is OK:
+ ss.write("\xfd\xfd\x00", 3);
+ n = ReadCompactSize(ss);
+ BOOST_CHECK(n == 0xfd);
+
+ // zero encoded with five bytes:
+ ss.write("\xfe\x00\x00\x00\x00", 5);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0xffff encoded with five bytes:
+ ss.write("\xfe\xff\xff\x00\x00", 5);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // zero encoded with nine bytes:
+ ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0x01ffffff encoded with nine bytes:
+ ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+}
+
+BOOST_AUTO_TEST_CASE(insert_delete)
+{
+ // Test inserting/deleting bytes.
+ CDataStream ss(SER_DISK, 0);
+ BOOST_CHECK_EQUAL(ss.size(), 0);
+
+ ss.write("\x00\x01\x02\xff", 4);
+ BOOST_CHECK_EQUAL(ss.size(), 4);
+
+ char c = (char)11;
+
+ // Inserting at beginning/end/middle:
+ ss.insert(ss.begin(), c);
+ BOOST_CHECK_EQUAL(ss.size(), 5);
+ BOOST_CHECK_EQUAL(ss[0], c);
+ BOOST_CHECK_EQUAL(ss[1], 0);
+
+ ss.insert(ss.end(), c);
+ BOOST_CHECK_EQUAL(ss.size(), 6);
+ BOOST_CHECK_EQUAL(ss[4], (char)0xff);
+ BOOST_CHECK_EQUAL(ss[5], c);
+
+ ss.insert(ss.begin()+2, c);
+ BOOST_CHECK_EQUAL(ss.size(), 7);
+ BOOST_CHECK_EQUAL(ss[2], c);
+
+ // Delete at beginning/end/middle
+ ss.erase(ss.begin());
+ BOOST_CHECK_EQUAL(ss.size(), 6);
+ BOOST_CHECK_EQUAL(ss[0], 0);
+
+ ss.erase(ss.begin()+ss.size()-1);
+ BOOST_CHECK_EQUAL(ss.size(), 5);
+ BOOST_CHECK_EQUAL(ss[4], (char)0xff);
+
+ ss.erase(ss.begin()+1);
+ BOOST_CHECK_EQUAL(ss.size(), 4);
+ BOOST_CHECK_EQUAL(ss[0], 0);
+ BOOST_CHECK_EQUAL(ss[1], 1);
+ BOOST_CHECK_EQUAL(ss[2], 2);
+ BOOST_CHECK_EQUAL(ss[3], (char)0xff);
+
+ // Make sure GetAndClear does the right thing:
+ CSerializeData d;
+ ss.GetAndClear(d);
+ BOOST_CHECK_EQUAL(ss.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
new file mode 100644
index 000000000..f098d4618
--- /dev/null
+++ b/src/test/sighash_tests.cpp
@@ -0,0 +1,120 @@
+#include <boost/test/unit_test.hpp>
+
+#include "main.h"
+#include "util.h"
+
+extern uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+
+// Old script.cpp SignatureHash function
+uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ if (nIn >= txTo.vin.size())
+ {
+ printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
+ return 1;
+ }
+ CTransaction txTmp(txTo);
+
+ // In case concatenating two scripts ends up with two codeseparators,
+ // or an extra one at the end, this prevents all those possible incompatibilities.
+ scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
+
+ // Blank out other inputs' signatures
+ for (unsigned int i = 0; i < txTmp.vin.size(); i++)
+ txTmp.vin[i].scriptSig = CScript();
+ txTmp.vin[nIn].scriptSig = scriptCode;
+
+ // Blank out some of the outputs
+ if ((nHashType & 0x1f) == SIGHASH_NONE)
+ {
+ // Wildcard payee
+ txTmp.vout.clear();
+
+ // Let the others update at will
+ for (unsigned int i = 0; i < txTmp.vin.size(); i++)
+ if (i != nIn)
+ txTmp.vin[i].nSequence = 0;
+ }
+ else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
+ {
+ // Only lock-in the txout payee at same index as txin
+ unsigned int nOut = nIn;
+ if (nOut >= txTmp.vout.size())
+ {
+ printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
+ return 1;
+ }
+ txTmp.vout.resize(nOut+1);
+ for (unsigned int i = 0; i < nOut; i++)
+ txTmp.vout[i].SetNull();
+
+ // Let the others update at will
+ for (unsigned int i = 0; i < txTmp.vin.size(); i++)
+ if (i != nIn)
+ txTmp.vin[i].nSequence = 0;
+ }
+
+ // Blank out other inputs completely, not recommended for open transactions
+ if (nHashType & SIGHASH_ANYONECANPAY)
+ {
+ txTmp.vin[0] = txTmp.vin[nIn];
+ txTmp.vin.resize(1);
+ }
+
+ // Serialize and hash
+ CHashWriter ss(SER_GETHASH, 0);
+ ss << txTmp << nHashType;
+ return ss.GetHash();
+}
+
+void static RandomScript(CScript &script) {
+ static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};
+ script = CScript();
+ int ops = (insecure_rand() % 10);
+ for (int i=0; i<ops; i++)
+ script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
+}
+
+void static RandomTransaction(CTransaction &tx, bool fSingle) {
+ tx.nVersion = insecure_rand();
+ tx.vin.clear();
+ tx.vout.clear();
+ tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0;
+ int ins = (insecure_rand() % 4) + 1;
+ int outs = fSingle ? ins : (insecure_rand() % 4) + 1;
+ for (int in = 0; in < ins; in++) {
+ tx.vin.push_back(CTxIn());
+ CTxIn &txin = tx.vin.back();
+ txin.prevout.hash = GetRandHash();
+ txin.prevout.n = insecure_rand() % 4;
+ RandomScript(txin.scriptSig);
+ txin.nSequence = (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1;
+ }
+ for (int out = 0; out < outs; out++) {
+ tx.vout.push_back(CTxOut());
+ CTxOut &txout = tx.vout.back();
+ txout.nValue = insecure_rand() % 100000000;
+ RandomScript(txout.scriptPubKey);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE(sighash_tests)
+
+BOOST_AUTO_TEST_CASE(sighash_test)
+{
+ seed_insecure_rand(false);
+
+ for (int i=0; i<50000; i++) {
+ int nHashType = insecure_rand();
+ CTransaction txTo;
+ RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
+ CScript scriptCode;
+ RandomScript(scriptCode);
+ int nIn = insecure_rand() % txTo.vin.size();
+ BOOST_CHECK(SignatureHash(scriptCode, txTo, nIn, nHashType) ==
+ SignatureHashOld(scriptCode, txTo, nIn, nHashType));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
new file mode 100644
index 000000000..96f663cce
--- /dev/null
+++ b/src/test/sigopcount_tests.cpp
@@ -0,0 +1,64 @@
+
+
+#include "key.h"
+#include "script.h"
+#include "uint256.h"
+
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+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), 0U);
+ BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U);
+
+ uint160 dummy;
+ s1 << OP_1 << dummy << dummy << OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U);
+ s1 << OP_IF << OP_CHECKSIG << OP_ENDIF;
+ BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U);
+ BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U);
+
+ CScript p2sh;
+ p2sh.SetDestination(s1.GetID());
+ CScript scriptSig;
+ scriptSig << OP_0 << Serialize(s1);
+ BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);
+
+ std::vector<CPubKey> keys;
+ for (int i = 0; i < 3; i++)
+ {
+ CKey k;
+ k.MakeNewKey(true);
+ keys.push_back(k.GetPubKey());
+ }
+ CScript s2;
+ s2.SetMultisig(1, keys);
+ BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U);
+ BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U);
+
+ p2sh.SetDestination(s2.GetID());
+ BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U);
+ BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U);
+ CScript scriptSig2;
+ scriptSig2 << OP_1 << dummy << dummy << Serialize(s2);
+ BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
new file mode 100644
index 000000000..96d071240
--- /dev/null
+++ b/src/test/test_bitcoin.cpp
@@ -0,0 +1,82 @@
+#define BOOST_TEST_MODULE Bitcoin Test Suite
+
+
+
+#include "main.h"
+#include "txdb.h"
+#include "ui_interface.h"
+#include "util.h"
+#ifdef ENABLE_WALLET
+#include "db.h"
+#include "wallet.h"
+#endif
+
+#include <boost/filesystem.hpp>
+#include <boost/test/unit_test.hpp>
+
+
+CWallet* pwalletMain;
+
+extern bool fPrintToConsole;
+extern void noui_connect();
+
+struct TestingSetup {
+ CCoinsViewDB *pcoinsdbview;
+ boost::filesystem::path pathTemp;
+ boost::thread_group threadGroup;
+
+ TestingSetup() {
+ fPrintToDebugLog = false; // don't want to write to debug.log file
+ noui_connect();
+#ifdef ENABLE_WALLET
+ bitdb.MakeMock();
+#endif
+ pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
+ boost::filesystem::create_directories(pathTemp);
+ mapArgs["-datadir"] = pathTemp.string();
+ pblocktree = new CBlockTreeDB(1 << 20, true);
+ pcoinsdbview = new CCoinsViewDB(1 << 23, true);
+ pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+ InitBlockIndex();
+#ifdef ENABLE_WALLET
+ bool fFirstRun;
+ pwalletMain = new CWallet("wallet.dat");
+ pwalletMain->LoadWallet(fFirstRun);
+ RegisterWallet(pwalletMain);
+#endif
+ nScriptCheckThreads = 3;
+ for (int i=0; i < nScriptCheckThreads-1; i++)
+ threadGroup.create_thread(&ThreadScriptCheck);
+ RegisterNodeSignals(GetNodeSignals());
+ }
+ ~TestingSetup()
+ {
+ threadGroup.interrupt_all();
+ threadGroup.join_all();
+ UnregisterNodeSignals(GetNodeSignals());
+#ifdef ENABLE_WALLET
+ delete pwalletMain;
+ pwalletMain = NULL;
+#endif
+ delete pcoinsTip;
+ delete pcoinsdbview;
+ delete pblocktree;
+#ifdef ENABLE_WALLET
+ bitdb.Flush(true);
+#endif
+ boost::filesystem::remove_all(pathTemp);
+ }
+};
+
+BOOST_GLOBAL_FIXTURE(TestingSetup);
+
+void Shutdown(void* parg)
+{
+ exit(0);
+}
+
+void StartShutdown()
+{
+ exit(0);
+}
+
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
new file mode 100644
index 000000000..ad33184bc
--- /dev/null
+++ b/src/test/transaction_tests.cpp
@@ -0,0 +1,311 @@
+
+
+#include "data/tx_invalid.json.h"
+#include "data/tx_valid.json.h"
+
+#include "key.h"
+#include "keystore.h"
+#include "main.h"
+#include "script.h"
+
+#include <map>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+#include "json/json_spirit_writer_template.h"
+
+using namespace std;
+using namespace json_spirit;
+
+// In script_tests.cpp
+extern Array read_json(const std::string& jsondata);
+extern CScript ParseScript(string s);
+
+BOOST_AUTO_TEST_SUITE(transaction_tests)
+
+BOOST_AUTO_TEST_CASE(tx_valid)
+{
+ // Read tests from test/data/tx_valid.json
+ // Format is an array of arrays
+ // Inner arrays are either [ "comment" ]
+ // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH
+ // ... where all scripts are stringified scripts.
+ Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ string strTest = write_string(tv, false);
+ if (test[0].type() == array_type)
+ {
+ if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+
+ map<COutPoint, CScript> mapprevOutScriptPubKeys;
+ Array inputs = test[0].get_array();
+ bool fValid = true;
+ BOOST_FOREACH(Value& input, inputs)
+ {
+ if (input.type() != array_type)
+ {
+ fValid = false;
+ break;
+ }
+ Array vinput = input.get_array();
+ if (vinput.size() != 3)
+ {
+ fValid = false;
+ break;
+ }
+
+ mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
+ }
+ if (!fValid)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+
+ string transaction = test[1].get_str();
+ CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
+ CTransaction tx;
+ stream >> tx;
+
+ CValidationState state;
+ BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
+ BOOST_CHECK(state.IsValid());
+
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ break;
+ }
+
+ BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0), strTest);
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(tx_invalid)
+{
+ // Read tests from test/data/tx_invalid.json
+ // Format is an array of arrays
+ // Inner arrays are either [ "comment" ]
+ // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH
+ // ... where all scripts are stringified scripts.
+ Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ string strTest = write_string(tv, false);
+ if (test[0].type() == array_type)
+ {
+ if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+
+ map<COutPoint, CScript> mapprevOutScriptPubKeys;
+ Array inputs = test[0].get_array();
+ bool fValid = true;
+ BOOST_FOREACH(Value& input, inputs)
+ {
+ if (input.type() != array_type)
+ {
+ fValid = false;
+ break;
+ }
+ Array vinput = input.get_array();
+ if (vinput.size() != 3)
+ {
+ fValid = false;
+ break;
+ }
+
+ mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
+ }
+ if (!fValid)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+
+ string transaction = test[1].get_str();
+ CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
+ CTransaction tx;
+ stream >> tx;
+
+ CValidationState state;
+ fValid = CheckTransaction(tx, state) && state.IsValid();
+
+ for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
+ {
+ if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ break;
+ }
+
+ fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0);
+ }
+
+ BOOST_CHECK_MESSAGE(!fValid, strTest);
+ }
+ }
+}
+
+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;
+ CValidationState state;
+ BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
+
+ // Check that duplicate txins fail
+ tx.vin.push_back(tx.vin[0]);
+ BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "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, CCoinsView & coinsRet)
+{
+ 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;
+ coinsRet.SetCoins(dummyTransactions[0].GetHash(), CCoins(dummyTransactions[0], 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());
+ coinsRet.SetCoins(dummyTransactions[1].GetHash(), CCoins(dummyTransactions[1], 0));
+
+ return dummyTransactions;
+}
+
+BOOST_AUTO_TEST_CASE(test_Get)
+{
+ CBasicKeyStore keystore;
+ CCoinsView coinsDummy;
+ CCoinsViewCache coins(coinsDummy);
+ std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+
+ 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(AreInputsStandard(t1, coins));
+ BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
+
+ // Adding extra junk to the scriptSig should make it non-standard:
+ t1.vin[0].scriptSig << OP_11;
+ BOOST_CHECK(!AreInputsStandard(t1, coins));
+
+ // ... as should not having enough:
+ t1.vin[0].scriptSig = CScript();
+ BOOST_CHECK(!AreInputsStandard(t1, coins));
+}
+
+BOOST_AUTO_TEST_CASE(test_IsStandard)
+{
+ CBasicKeyStore keystore;
+ CCoinsView coinsDummy;
+ CCoinsViewCache coins(coinsDummy);
+ std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+
+ CTransaction t;
+ t.vin.resize(1);
+ t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
+ t.vin[0].prevout.n = 1;
+ t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
+ t.vout.resize(1);
+ t.vout[0].nValue = 90*CENT;
+ CKey key;
+ key.MakeNewKey(true);
+ t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
+
+ string reason;
+ BOOST_CHECK(IsStandardTx(t, reason));
+
+ t.vout[0].nValue = 5011; // dust
+ BOOST_CHECK(!IsStandardTx(t, reason));
+
+ t.vout[0].nValue = 6011; // not dust
+ BOOST_CHECK(IsStandardTx(t, reason));
+
+ t.vout[0].scriptPubKey = CScript() << OP_1;
+ BOOST_CHECK(!IsStandardTx(t, reason));
+
+ // 80-byte TX_NULL_DATA (standard)
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ BOOST_CHECK(IsStandardTx(t, reason));
+
+ // 81-byte TX_NULL_DATA (non-standard)
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
+ BOOST_CHECK(!IsStandardTx(t, reason));
+
+ // TX_NULL_DATA w/o PUSHDATA
+ t.vout.resize(1);
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN;
+ BOOST_CHECK(IsStandardTx(t, reason));
+
+ // Only one TX_NULL_DATA permitted in all cases
+ t.vout.resize(2);
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ BOOST_CHECK(!IsStandardTx(t, reason));
+
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ t.vout[1].scriptPubKey = CScript() << OP_RETURN;
+ BOOST_CHECK(!IsStandardTx(t, reason));
+
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN;
+ t.vout[1].scriptPubKey = CScript() << OP_RETURN;
+ BOOST_CHECK(!IsStandardTx(t, reason));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
new file mode 100644
index 000000000..368484fdf
--- /dev/null
+++ b/src/test/uint256_tests.cpp
@@ -0,0 +1,633 @@
+#include <boost/test/unit_test.hpp>
+#include <stdint.h>
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <cmath>
+#include "uint256.h"
+#include <string>
+#include "version.h"
+
+BOOST_AUTO_TEST_SUITE(uint256_tests)
+
+const unsigned char R1Array[] =
+ "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2"
+ "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d";
+const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c";
+const double R1Ldouble = 0.4887374590559308955; // R1L equals roughly R1Ldouble * 2^256
+const double R1Sdouble = 0.7096329412477836074;
+const uint256 R1L = uint256(std::vector<unsigned char>(R1Array,R1Array+32));
+const uint160 R1S = uint160(std::vector<unsigned char>(R1Array,R1Array+20));
+const uint64_t R1LLow64 = 0x121156cfdb4a529cULL;
+
+const unsigned char R2Array[] =
+ "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf"
+ "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7";
+const uint256 R2L = uint256(std::vector<unsigned char>(R2Array,R2Array+32));
+const uint160 R2S = uint160(std::vector<unsigned char>(R2Array,R2Array+20));
+
+const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C";
+
+const unsigned char ZeroArray[] =
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+const uint256 ZeroL = uint256(std::vector<unsigned char>(ZeroArray,ZeroArray+32));
+const uint160 ZeroS = uint160(std::vector<unsigned char>(ZeroArray,ZeroArray+20));
+
+const unsigned char OneArray[] =
+ "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+const uint256 OneL = uint256(std::vector<unsigned char>(OneArray,OneArray+32));
+const uint160 OneS = uint160(std::vector<unsigned char>(OneArray,OneArray+20));
+
+const unsigned char MaxArray[] =
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+const uint256 MaxL = uint256(std::vector<unsigned char>(MaxArray,MaxArray+32));
+const uint160 MaxS = uint160(std::vector<unsigned char>(MaxArray,MaxArray+20));
+
+const uint256 HalfL = (OneL << 255);
+const uint160 HalfS = (OneS << 159);
+std::string ArrayToString(const unsigned char A[], unsigned int width)
+{
+ std::stringstream Stream;
+ Stream << std::hex;
+ for (unsigned int i = 0; i < width; ++i)
+ {
+ Stream<<std::setw(2)<<std::setfill('0')<<(unsigned int)A[width-i-1];
+ }
+ return Stream.str();
+}
+
+BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality
+{
+ BOOST_CHECK(1 == 0+1);
+ // constructor uint256(vector<char>):
+ BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32));
+ BOOST_CHECK(R1S.ToString() == ArrayToString(R1Array,20));
+ BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32));
+ BOOST_CHECK(R2S.ToString() == ArrayToString(R2Array,20));
+ BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray,32));
+ BOOST_CHECK(ZeroS.ToString() == ArrayToString(ZeroArray,20));
+ BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray,32));
+ BOOST_CHECK(OneS.ToString() == ArrayToString(OneArray,20));
+ BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray,32));
+ BOOST_CHECK(MaxS.ToString() == ArrayToString(MaxArray,20));
+ BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray,32));
+ BOOST_CHECK(OneS.ToString() != ArrayToString(ZeroArray,20));
+
+ // == and !=
+ BOOST_CHECK(R1L != R2L && R1S != R2S);
+ BOOST_CHECK(ZeroL != OneL && ZeroS != OneS);
+ BOOST_CHECK(OneL != ZeroL && OneS != ZeroS);
+ BOOST_CHECK(MaxL != ZeroL && MaxS != ZeroS);
+ BOOST_CHECK(~MaxL == ZeroL && ~MaxS == ZeroS);
+ BOOST_CHECK( ((R1L ^ R2L) ^ R1L) == R2L);
+ BOOST_CHECK( ((R1S ^ R2S) ^ R1S) == R2S);
+
+ uint64_t Tmp64 = 0xc4dab720d9c7acaaULL;
+ for (unsigned int i = 0; i < 256; ++i)
+ {
+ BOOST_CHECK(ZeroL != (OneL << i));
+ BOOST_CHECK((OneL << i) != ZeroL);
+ BOOST_CHECK(R1L != (R1L ^ (OneL << i)));
+ BOOST_CHECK(((uint256(Tmp64) ^ (OneL << i) ) != Tmp64 ));
+ }
+ BOOST_CHECK(ZeroL == (OneL << 256));
+
+ for (unsigned int i = 0; i < 160; ++i)
+ {
+ BOOST_CHECK(ZeroS != (OneS << i));
+ BOOST_CHECK((OneS << i) != ZeroS);
+ BOOST_CHECK(R1S != (R1S ^ (OneS << i)));
+ BOOST_CHECK(((uint160(Tmp64) ^ (OneS << i) ) != Tmp64 ));
+ }
+ BOOST_CHECK(ZeroS == (OneS << 256));
+
+ // String Constructor and Copy Constructor
+ BOOST_CHECK(uint256("0x"+R1L.ToString()) == R1L);
+ BOOST_CHECK(uint256("0x"+R2L.ToString()) == R2L);
+ BOOST_CHECK(uint256("0x"+ZeroL.ToString()) == ZeroL);
+ BOOST_CHECK(uint256("0x"+OneL.ToString()) == OneL);
+ BOOST_CHECK(uint256("0x"+MaxL.ToString()) == MaxL);
+ BOOST_CHECK(uint256(R1L.ToString()) == R1L);
+ BOOST_CHECK(uint256(" 0x"+R1L.ToString()+" ") == R1L);
+ BOOST_CHECK(uint256("") == ZeroL);
+ BOOST_CHECK(R1L == uint256(R1ArrayHex));
+ BOOST_CHECK(uint256(R1L) == R1L);
+ BOOST_CHECK((uint256(R1L^R2L)^R2L) == R1L);
+ BOOST_CHECK(uint256(ZeroL) == ZeroL);
+ BOOST_CHECK(uint256(OneL) == OneL);
+
+ BOOST_CHECK(uint160("0x"+R1S.ToString()) == R1S);
+ BOOST_CHECK(uint160("0x"+R2S.ToString()) == R2S);
+ BOOST_CHECK(uint160("0x"+ZeroS.ToString()) == ZeroS);
+ BOOST_CHECK(uint160("0x"+OneS.ToString()) == OneS);
+ BOOST_CHECK(uint160("0x"+MaxS.ToString()) == MaxS);
+ BOOST_CHECK(uint160(R1S.ToString()) == R1S);
+ BOOST_CHECK(uint160(" 0x"+R1S.ToString()+" ") == R1S);
+ BOOST_CHECK(uint160("") == ZeroS);
+ BOOST_CHECK(R1S == uint160(R1ArrayHex));
+
+ BOOST_CHECK(uint160(R1S) == R1S);
+ BOOST_CHECK((uint160(R1S^R2S)^R2S) == R1S);
+ BOOST_CHECK(uint160(ZeroS) == ZeroS);
+ BOOST_CHECK(uint160(OneS) == OneS);
+
+ // uint64_t constructor
+ BOOST_CHECK( (R1L & uint256("0xffffffffffffffff")) == uint256(R1LLow64));
+ BOOST_CHECK(ZeroL == uint256(0));
+ BOOST_CHECK(OneL == uint256(1));
+ BOOST_CHECK(uint256("0xffffffffffffffff") = uint256(0xffffffffffffffffULL));
+ BOOST_CHECK( (R1S & uint160("0xffffffffffffffff")) == uint160(R1LLow64));
+ BOOST_CHECK(ZeroS == uint160(0));
+ BOOST_CHECK(OneS == uint160(1));
+ BOOST_CHECK(uint160("0xffffffffffffffff") = uint160(0xffffffffffffffffULL));
+
+ // Assignment (from base_uint)
+ uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL);
+ tmpL = ~OneL; BOOST_CHECK(tmpL == ~OneL);
+ tmpL = ~R1L; BOOST_CHECK(tmpL == ~R1L);
+ tmpL = ~R2L; BOOST_CHECK(tmpL == ~R2L);
+ tmpL = ~MaxL; BOOST_CHECK(tmpL == ~MaxL);
+ uint160 tmpS = ~ZeroS; BOOST_CHECK(tmpS == ~ZeroS);
+ tmpS = ~OneS; BOOST_CHECK(tmpS == ~OneS);
+ tmpS = ~R1S; BOOST_CHECK(tmpS == ~R1S);
+ tmpS = ~R2S; BOOST_CHECK(tmpS == ~R2S);
+ tmpS = ~MaxS; BOOST_CHECK(tmpS == ~MaxS);
+
+ // Wrong length must give 0
+ BOOST_CHECK(uint256(std::vector<unsigned char>(OneArray,OneArray+31)) == 0);
+ BOOST_CHECK(uint256(std::vector<unsigned char>(OneArray,OneArray+20)) == 0);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(OneArray,OneArray+32)) == 0);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(OneArray,OneArray+19)) == 0);
+}
+
+void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift)
+{
+ for (unsigned int T=0; T < arrayLength; ++T)
+ {
+ unsigned int F = (T+bitsToShift/8);
+ if (F < arrayLength)
+ to[T] = from[F] >> (bitsToShift%8);
+ else
+ to[T] = 0;
+ if (F + 1 < arrayLength)
+ to[T] |= from[(F+1)] << (8-bitsToShift%8);
+ }
+}
+
+void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift)
+{
+ for (unsigned int T=0; T < arrayLength; ++T)
+ {
+ if (T >= bitsToShift/8)
+ {
+ unsigned int F = T-bitsToShift/8;
+ to[T] = from[F] << (bitsToShift%8);
+ if (T >= bitsToShift/8+1)
+ to[T] |= from[F-1] >> (8-bitsToShift%8);
+ }
+ else {
+ to[T] = 0;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>="
+ unsigned char TmpArray[32];
+ uint256 TmpL;
+ for (unsigned int i = 0; i < 256; ++i)
+ {
+ shiftArrayLeft(TmpArray, OneArray, 32, i);
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (OneL << i));
+ TmpL = OneL; TmpL <<= i;
+ BOOST_CHECK(TmpL == (OneL << i));
+ BOOST_CHECK((HalfL >> (255-i)) == (OneL << i));
+ TmpL = HalfL; TmpL >>= (255-i);
+ BOOST_CHECK(TmpL == (OneL << i));
+
+ shiftArrayLeft(TmpArray, R1Array, 32, i);
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (R1L << i));
+ TmpL = R1L; TmpL <<= i;
+ BOOST_CHECK(TmpL == (R1L << i));
+
+ shiftArrayRight(TmpArray, R1Array, 32, i);
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (R1L >> i));
+ TmpL = R1L; TmpL >>= i;
+ BOOST_CHECK(TmpL == (R1L >> i));
+
+ shiftArrayLeft(TmpArray, MaxArray, 32, i);
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (MaxL << i));
+ TmpL = MaxL; TmpL <<= i;
+ BOOST_CHECK(TmpL == (MaxL << i));
+
+ shiftArrayRight(TmpArray, MaxArray, 32, i);
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (MaxL >> i));
+ TmpL = MaxL; TmpL >>= i;
+ BOOST_CHECK(TmpL == (MaxL >> i));
+ }
+ uint256 c1L = uint256(0x0123456789abcdefULL);
+ uint256 c2L = c1L << 128;
+ for (unsigned int i = 0; i < 128; ++i) {
+ BOOST_CHECK((c1L << i) == (c2L >> (128-i)));
+ }
+ for (unsigned int i = 128; i < 256; ++i) {
+ BOOST_CHECK((c1L << i) == (c2L << (i-128)));
+ }
+
+ uint160 TmpS;
+ for (unsigned int i = 0; i < 160; ++i)
+ {
+ shiftArrayLeft(TmpArray, OneArray, 20, i);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (OneS << i));
+ TmpS = OneS; TmpS <<= i;
+ BOOST_CHECK(TmpS == (OneS << i));
+ BOOST_CHECK((HalfS >> (159-i)) == (OneS << i));
+ TmpS = HalfS; TmpS >>= (159-i);
+ BOOST_CHECK(TmpS == (OneS << i));
+
+ shiftArrayLeft(TmpArray, R1Array, 20, i);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (R1S << i));
+ TmpS = R1S; TmpS <<= i;
+ BOOST_CHECK(TmpS == (R1S << i));
+
+ shiftArrayRight(TmpArray, R1Array, 20, i);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (R1S >> i));
+ TmpS = R1S; TmpS >>= i;
+ BOOST_CHECK(TmpS == (R1S >> i));
+
+ shiftArrayLeft(TmpArray, MaxArray, 20, i);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (MaxS << i));
+ TmpS = MaxS; TmpS <<= i;
+ BOOST_CHECK(TmpS == (MaxS << i));
+
+ shiftArrayRight(TmpArray, MaxArray, 20, i);
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (MaxS >> i));
+ TmpS = MaxS; TmpS >>= i;
+ BOOST_CHECK(TmpS == (MaxS >> i));
+ }
+ uint160 c1S = uint160(0x0123456789abcdefULL);
+ uint160 c2S = c1S << 80;
+ for (unsigned int i = 0; i < 80; ++i) {
+ BOOST_CHECK((c1S << i) == (c2S >> (80-i)));
+ }
+ for (unsigned int i = 80; i < 160; ++i) {
+ BOOST_CHECK((c1S << i) == (c2S << (i-80)));
+ }
+}
+
+BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ -
+{
+ BOOST_CHECK(!ZeroL); BOOST_CHECK(!ZeroS);
+ BOOST_CHECK(!(!OneL));BOOST_CHECK(!(!OneS));
+ for (unsigned int i = 0; i < 256; ++i)
+ BOOST_CHECK(!(!(OneL<<i)));
+ for (unsigned int i = 0; i < 160; ++i)
+ BOOST_CHECK(!(!(OneS<<i)));
+ BOOST_CHECK(!(!R1L));BOOST_CHECK(!(!R1S));
+ BOOST_CHECK(!(!R2S));BOOST_CHECK(!(!R2S));
+ BOOST_CHECK(!(!MaxL));BOOST_CHECK(!(!MaxS));
+
+ BOOST_CHECK(~ZeroL == MaxL); BOOST_CHECK(~ZeroS == MaxS);
+
+ unsigned char TmpArray[32];
+ for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = ~R1Array[i]; }
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (~R1L));
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (~R1S));
+
+ BOOST_CHECK(-ZeroL == ZeroL); BOOST_CHECK(-ZeroS == ZeroS);
+ BOOST_CHECK(-R1L == (~R1L)+1);
+ BOOST_CHECK(-R1S == (~R1S)+1);
+ for (unsigned int i = 0; i < 256; ++i)
+ BOOST_CHECK(-(OneL<<i) == (MaxL << i));
+ for (unsigned int i = 0; i < 160; ++i)
+ BOOST_CHECK(-(OneS<<i) == (MaxS << i));
+}
+
+
+// Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each
+// element of Aarray and Barray, and then converting the result into a uint256.
+#define CHECKBITWISEOPERATOR(_A_,_B_,_OP_) \
+ for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; } \
+ BOOST_CHECK(uint256(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (_A_##L _OP_ _B_##L)); \
+ for (unsigned int i = 0; i < 20; ++i) { TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; } \
+ BOOST_CHECK(uint160(std::vector<unsigned char>(TmpArray,TmpArray+20)) == (_A_##S _OP_ _B_##S));
+
+#define CHECKASSIGNMENTOPERATOR(_A_,_B_,_OP_) \
+ TmpL = _A_##L; TmpL _OP_##= _B_##L; BOOST_CHECK(TmpL == (_A_##L _OP_ _B_##L)); \
+ TmpS = _A_##S; TmpS _OP_##= _B_##S; BOOST_CHECK(TmpS == (_A_##S _OP_ _B_##S));
+
+BOOST_AUTO_TEST_CASE( bitwiseOperators )
+{
+ unsigned char TmpArray[32];
+
+ CHECKBITWISEOPERATOR(R1,R2,|)
+ CHECKBITWISEOPERATOR(R1,R2,^)
+ CHECKBITWISEOPERATOR(R1,R2,&)
+ CHECKBITWISEOPERATOR(R1,Zero,|)
+ CHECKBITWISEOPERATOR(R1,Zero,^)
+ CHECKBITWISEOPERATOR(R1,Zero,&)
+ CHECKBITWISEOPERATOR(R1,Max,|)
+ CHECKBITWISEOPERATOR(R1,Max,^)
+ CHECKBITWISEOPERATOR(R1,Max,&)
+ CHECKBITWISEOPERATOR(Zero,R1,|)
+ CHECKBITWISEOPERATOR(Zero,R1,^)
+ CHECKBITWISEOPERATOR(Zero,R1,&)
+ CHECKBITWISEOPERATOR(Max,R1,|)
+ CHECKBITWISEOPERATOR(Max,R1,^)
+ CHECKBITWISEOPERATOR(Max,R1,&)
+
+ uint256 TmpL;
+ uint160 TmpS;
+ CHECKASSIGNMENTOPERATOR(R1,R2,|)
+ CHECKASSIGNMENTOPERATOR(R1,R2,^)
+ CHECKASSIGNMENTOPERATOR(R1,R2,&)
+ CHECKASSIGNMENTOPERATOR(R1,Zero,|)
+ CHECKASSIGNMENTOPERATOR(R1,Zero,^)
+ CHECKASSIGNMENTOPERATOR(R1,Zero,&)
+ CHECKASSIGNMENTOPERATOR(R1,Max,|)
+ CHECKASSIGNMENTOPERATOR(R1,Max,^)
+ CHECKASSIGNMENTOPERATOR(R1,Max,&)
+ CHECKASSIGNMENTOPERATOR(Zero,R1,|)
+ CHECKASSIGNMENTOPERATOR(Zero,R1,^)
+ CHECKASSIGNMENTOPERATOR(Zero,R1,&)
+ CHECKASSIGNMENTOPERATOR(Max,R1,|)
+ CHECKASSIGNMENTOPERATOR(Max,R1,^)
+ CHECKASSIGNMENTOPERATOR(Max,R1,&)
+
+ uint64_t Tmp64 = 0xe1db685c9a0b47a2ULL;
+ TmpL = R1L; TmpL |= Tmp64; BOOST_CHECK(TmpL == (R1L | uint256(Tmp64)));
+ TmpS = R1S; TmpS |= Tmp64; BOOST_CHECK(TmpS == (R1S | uint160(Tmp64)));
+ TmpL = R1L; TmpL |= 0; BOOST_CHECK(TmpL == R1L);
+ TmpS = R1S; TmpS |= 0; BOOST_CHECK(TmpS == R1S);
+ TmpL ^= 0; BOOST_CHECK(TmpL == R1L);
+ TmpS ^= 0; BOOST_CHECK(TmpS == R1S);
+ TmpL ^= Tmp64; BOOST_CHECK(TmpL == (R1L ^ uint256(Tmp64)));
+ TmpS ^= Tmp64; BOOST_CHECK(TmpS == (R1S ^ uint160(Tmp64)));
+}
+
+BOOST_AUTO_TEST_CASE( comparison ) // <= >= < >
+{
+ uint256 TmpL;
+ for (unsigned int i = 0; i < 256; ++i) {
+ TmpL= OneL<< i;
+ BOOST_CHECK( TmpL >= ZeroL && TmpL > ZeroL && ZeroL < TmpL && ZeroL <= TmpL);
+ BOOST_CHECK( TmpL >= 0 && TmpL > 0 && 0 < TmpL && 0 <= TmpL);
+ TmpL |= R1L;
+ BOOST_CHECK( TmpL >= R1L ); BOOST_CHECK( (TmpL == R1L) != (TmpL > R1L)); BOOST_CHECK( (TmpL == R1L) || !( TmpL <= R1L));
+ BOOST_CHECK( R1L <= TmpL ); BOOST_CHECK( (R1L == TmpL) != (R1L < TmpL)); BOOST_CHECK( (TmpL == R1L) || !( R1L >= TmpL));
+ BOOST_CHECK(! (TmpL < R1L)); BOOST_CHECK(! (R1L > TmpL));
+ }
+ uint160 TmpS;
+ for (unsigned int i = 0; i < 160; ++i) {
+ TmpS= OneS<< i;
+ BOOST_CHECK( TmpS >= ZeroS && TmpS > ZeroS && ZeroS < TmpS && ZeroS <= TmpS);
+ BOOST_CHECK( TmpS >= 0 && TmpS > 0 && 0 < TmpS && 0 <= TmpS);
+ TmpS |= R1S;
+ BOOST_CHECK( TmpS >= R1S ); BOOST_CHECK( (TmpS == R1S) != (TmpS > R1S)); BOOST_CHECK( (TmpS == R1S) || !( TmpS <= R1S));
+ BOOST_CHECK( R1S <= TmpS ); BOOST_CHECK( (R1S == TmpS) != (R1S < TmpS)); BOOST_CHECK( (TmpS == R1S) || !( R1S >= TmpS));
+ BOOST_CHECK(! (TmpS < R1S)); BOOST_CHECK(! (R1S > TmpS));
+ }
+}
+
+BOOST_AUTO_TEST_CASE( plusMinus )
+{
+ uint256 TmpL = 0;
+ BOOST_CHECK(R1L+R2L == uint256(R1LplusR2L));
+ TmpL += R1L;
+ BOOST_CHECK(TmpL == R1L);
+ TmpL += R2L;
+ BOOST_CHECK(TmpL == R1L + R2L);
+ BOOST_CHECK(OneL+MaxL == ZeroL);
+ BOOST_CHECK(MaxL+OneL == ZeroL);
+ for (unsigned int i = 1; i < 256; ++i) {
+ BOOST_CHECK( (MaxL >> i) + OneL == (HalfL >> (i-1)) );
+ BOOST_CHECK( OneL + (MaxL >> i) == (HalfL >> (i-1)) );
+ TmpL = (MaxL>>i); TmpL += OneL;
+ BOOST_CHECK( TmpL == (HalfL >> (i-1)) );
+ TmpL = (MaxL>>i); TmpL += 1;
+ BOOST_CHECK( TmpL == (HalfL >> (i-1)) );
+ TmpL = (MaxL>>i);
+ BOOST_CHECK( TmpL++ == (MaxL>>i) );
+ BOOST_CHECK( TmpL == (HalfL >> (i-1)));
+ }
+ BOOST_CHECK(uint256(0xbedc77e27940a7ULL) + 0xee8d836fce66fbULL == uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL));
+ TmpL = uint256(0xbedc77e27940a7ULL); TmpL += 0xee8d836fce66fbULL;
+ BOOST_CHECK(TmpL == uint256(0xbedc77e27940a7ULL+0xee8d836fce66fbULL));
+ TmpL -= 0xee8d836fce66fbULL; BOOST_CHECK(TmpL == 0xbedc77e27940a7ULL);
+ TmpL = R1L;
+ BOOST_CHECK(++TmpL == R1L+1);
+
+ BOOST_CHECK(R1L -(-R2L) == R1L+R2L);
+ BOOST_CHECK(R1L -(-OneL) == R1L+OneL);
+ BOOST_CHECK(R1L - OneL == R1L+(-OneL));
+ for (unsigned int i = 1; i < 256; ++i) {
+ BOOST_CHECK((MaxL>>i) - (-OneL) == (HalfL >> (i-1)));
+ BOOST_CHECK((HalfL >> (i-1)) - OneL == (MaxL>>i));
+ TmpL = (HalfL >> (i-1));
+ BOOST_CHECK(TmpL-- == (HalfL >> (i-1)));
+ BOOST_CHECK(TmpL == (MaxL >> i));
+ TmpL = (HalfL >> (i-1));
+ BOOST_CHECK(--TmpL == (MaxL >> i));
+ }
+ TmpL = R1L;
+ BOOST_CHECK(--TmpL == R1L-1);
+
+ // 160-bit; copy-pasted
+ uint160 TmpS = 0;
+ BOOST_CHECK(R1S+R2S == uint160(R1LplusR2L));
+ TmpS += R1S;
+ BOOST_CHECK(TmpS == R1S);
+ TmpS += R2S;
+ BOOST_CHECK(TmpS == R1S + R2S);
+ BOOST_CHECK(OneS+MaxS == ZeroS);
+ BOOST_CHECK(MaxS+OneS == ZeroS);
+ for (unsigned int i = 1; i < 160; ++i) {
+ BOOST_CHECK( (MaxS >> i) + OneS == (HalfS >> (i-1)) );
+ BOOST_CHECK( OneS + (MaxS >> i) == (HalfS >> (i-1)) );
+ TmpS = (MaxS>>i); TmpS += OneS;
+ BOOST_CHECK( TmpS == (HalfS >> (i-1)) );
+ TmpS = (MaxS>>i); TmpS += 1;
+ BOOST_CHECK( TmpS == (HalfS >> (i-1)) );
+ TmpS = (MaxS>>i);
+ BOOST_CHECK( TmpS++ == (MaxS>>i) );
+ BOOST_CHECK( TmpS == (HalfS >> (i-1)));
+ }
+ BOOST_CHECK(uint160(0xbedc77e27940a7ULL) + 0xee8d836fce66fbULL == uint160(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL));
+ TmpS = uint160(0xbedc77e27940a7ULL); TmpS += 0xee8d836fce66fbULL;
+ BOOST_CHECK(TmpS == uint160(0xbedc77e27940a7ULL+0xee8d836fce66fbULL));
+ TmpS -= 0xee8d836fce66fbULL; BOOST_CHECK(TmpS == 0xbedc77e27940a7ULL);
+ TmpS = R1S;
+ BOOST_CHECK(++TmpS == R1S+1);
+
+ BOOST_CHECK(R1S -(-R2S) == R1S+R2S);
+ BOOST_CHECK(R1S -(-OneS) == R1S+OneS);
+ BOOST_CHECK(R1S - OneS == R1S+(-OneS));
+ for (unsigned int i = 1; i < 160; ++i) {
+ BOOST_CHECK((MaxS>>i) - (-OneS) == (HalfS >> (i-1)));
+ BOOST_CHECK((HalfS >> (i-1)) - OneS == (MaxS>>i));
+ TmpS = (HalfS >> (i-1));
+ BOOST_CHECK(TmpS-- == (HalfS >> (i-1)));
+ BOOST_CHECK(TmpS == (MaxS >> i));
+ TmpS = (HalfS >> (i-1));
+ BOOST_CHECK(--TmpS == (MaxS >> i));
+ }
+ TmpS = R1S;
+ BOOST_CHECK(--TmpS == R1S-1);
+
+}
+
+bool almostEqual(double d1, double d2)
+{
+ return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits<double>::epsilon();
+}
+
+BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 GetSerializeSize, Serialize, Unserialize
+{
+ BOOST_CHECK(R1L.GetHex() == R1L.ToString());
+ BOOST_CHECK(R2L.GetHex() == R2L.ToString());
+ BOOST_CHECK(OneL.GetHex() == OneL.ToString());
+ BOOST_CHECK(MaxL.GetHex() == MaxL.ToString());
+ uint256 TmpL(R1L);
+ BOOST_CHECK(TmpL == R1L);
+ TmpL.SetHex(R2L.ToString()); BOOST_CHECK(TmpL == R2L);
+ TmpL.SetHex(ZeroL.ToString()); BOOST_CHECK(TmpL == 0);
+ TmpL.SetHex(HalfL.ToString()); BOOST_CHECK(TmpL == HalfL);
+
+ TmpL.SetHex(R1L.ToString());
+ BOOST_CHECK(memcmp(R1L.begin(), R1Array, 32)==0);
+ BOOST_CHECK(memcmp(TmpL.begin(), R1Array, 32)==0);
+ BOOST_CHECK(memcmp(R2L.begin(), R2Array, 32)==0);
+ BOOST_CHECK(memcmp(ZeroL.begin(), ZeroArray, 32)==0);
+ BOOST_CHECK(memcmp(OneL.begin(), OneArray, 32)==0);
+ BOOST_CHECK(R1L.size() == 32);
+ BOOST_CHECK(R2L.size() == 32);
+ BOOST_CHECK(ZeroL.size() == 32);
+ BOOST_CHECK(MaxL.size() == 32);
+ BOOST_CHECK(R1L.begin() + 32 == R1L.end());
+ BOOST_CHECK(R2L.begin() + 32 == R2L.end());
+ BOOST_CHECK(OneL.begin() + 32 == OneL.end());
+ BOOST_CHECK(MaxL.begin() + 32 == MaxL.end());
+ BOOST_CHECK(TmpL.begin() + 32 == TmpL.end());
+ BOOST_CHECK(R1L.GetLow64() == R1LLow64);
+ BOOST_CHECK(HalfL.GetLow64() ==0x0000000000000000ULL);
+ BOOST_CHECK(OneL.GetLow64() ==0x0000000000000001ULL);
+ BOOST_CHECK(R1L.GetSerializeSize(0,PROTOCOL_VERSION) == 32);
+ BOOST_CHECK(ZeroL.GetSerializeSize(0,PROTOCOL_VERSION) == 32);
+
+ std::stringstream ss;
+ R1L.Serialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+32));
+ TmpL.Unserialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(R1L == TmpL);
+ ss.str("");
+ ZeroL.Serialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+32));
+ TmpL.Unserialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ZeroL == TmpL);
+ ss.str("");
+ MaxL.Serialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+32));
+ TmpL.Unserialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(MaxL == TmpL);
+ ss.str("");
+
+ BOOST_CHECK(R1S.GetHex() == R1S.ToString());
+ BOOST_CHECK(R2S.GetHex() == R2S.ToString());
+ BOOST_CHECK(OneS.GetHex() == OneS.ToString());
+ BOOST_CHECK(MaxS.GetHex() == MaxS.ToString());
+ uint160 TmpS(R1S);
+ BOOST_CHECK(TmpS == R1S);
+ TmpS.SetHex(R2S.ToString()); BOOST_CHECK(TmpS == R2S);
+ TmpS.SetHex(ZeroS.ToString()); BOOST_CHECK(TmpS == 0);
+ TmpS.SetHex(HalfS.ToString()); BOOST_CHECK(TmpS == HalfS);
+
+ TmpS.SetHex(R1S.ToString());
+ BOOST_CHECK(memcmp(R1S.begin(), R1Array, 20)==0);
+ BOOST_CHECK(memcmp(TmpS.begin(), R1Array, 20)==0);
+ BOOST_CHECK(memcmp(R2S.begin(), R2Array, 20)==0);
+ BOOST_CHECK(memcmp(ZeroS.begin(), ZeroArray, 20)==0);
+ BOOST_CHECK(memcmp(OneS.begin(), OneArray, 20)==0);
+ BOOST_CHECK(R1S.size() == 20);
+ BOOST_CHECK(R2S.size() == 20);
+ BOOST_CHECK(ZeroS.size() == 20);
+ BOOST_CHECK(MaxS.size() == 20);
+ BOOST_CHECK(R1S.begin() + 20 == R1S.end());
+ BOOST_CHECK(R2S.begin() + 20 == R2S.end());
+ BOOST_CHECK(OneS.begin() + 20 == OneS.end());
+ BOOST_CHECK(MaxS.begin() + 20 == MaxS.end());
+ BOOST_CHECK(TmpS.begin() + 20 == TmpS.end());
+ BOOST_CHECK(R1S.GetLow64() == R1LLow64);
+ BOOST_CHECK(HalfS.GetLow64() ==0x0000000000000000ULL);
+ BOOST_CHECK(OneS.GetLow64() ==0x0000000000000001ULL);
+ BOOST_CHECK(R1S.GetSerializeSize(0,PROTOCOL_VERSION) == 20);
+ BOOST_CHECK(ZeroS.GetSerializeSize(0,PROTOCOL_VERSION) == 20);
+
+ R1S.Serialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20));
+ TmpS.Unserialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(R1S == TmpS);
+ ss.str("");
+ ZeroS.Serialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+20));
+ TmpS.Unserialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ZeroS == TmpS);
+ ss.str("");
+ MaxS.Serialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+20));
+ TmpS.Unserialize(ss,0,PROTOCOL_VERSION);
+ BOOST_CHECK(MaxS == TmpS);
+ ss.str("");
+
+ for (unsigned int i = 0; i < 255; ++i)
+ {
+ BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0,i));
+ if (i < 160) BOOST_CHECK((OneS << i).getdouble() == ldexp(1.0,i));
+ }
+ BOOST_CHECK(ZeroL.getdouble() == 0.0);
+ BOOST_CHECK(ZeroS.getdouble() == 0.0);
+ for (int i = 256; i > 53; --i)
+ BOOST_CHECK(almostEqual((R1L>>(256-i)).getdouble(), ldexp(R1Ldouble,i)));
+ for (int i = 160; i > 53; --i)
+ BOOST_CHECK(almostEqual((R1S>>(160-i)).getdouble(), ldexp(R1Sdouble,i)));
+ uint64_t R1L64part = (R1L>>192).GetLow64();
+ uint64_t R1S64part = (R1S>>96).GetLow64();
+ for (int i = 53; i > 0; --i) // doubles can store all integers in {0,...,2^54-1} exactly
+ {
+ BOOST_CHECK((R1L>>(256-i)).getdouble() == (double)(R1L64part >> (64-i)));
+ BOOST_CHECK((R1S>>(160-i)).getdouble() == (double)(R1S64part >> (64-i)));
+ }
+}
+
+BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% coverage
+{
+ // ~R1L give a base_uint<256>
+ BOOST_CHECK((~~R1L >> 10) == (R1L >> 10)); BOOST_CHECK((~~R1S >> 10) == (R1S >> 10));
+ BOOST_CHECK((~~R1L << 10) == (R1L << 10)); BOOST_CHECK((~~R1S << 10) == (R1S << 10));
+ BOOST_CHECK(!(~~R1L < R1L)); BOOST_CHECK(!(~~R1S < R1S));
+ BOOST_CHECK(~~R1L <= R1L); BOOST_CHECK(~~R1S <= R1S);
+ BOOST_CHECK(!(~~R1L > R1L)); BOOST_CHECK(!(~~R1S > R1S));
+ BOOST_CHECK(~~R1L >= R1L); BOOST_CHECK(~~R1S >= R1S);
+ BOOST_CHECK(!(R1L < ~~R1L)); BOOST_CHECK(!(R1S < ~~R1S));
+ BOOST_CHECK(R1L <= ~~R1L); BOOST_CHECK(R1S <= ~~R1S);
+ BOOST_CHECK(!(R1L > ~~R1L)); BOOST_CHECK(!(R1S > ~~R1S));
+ BOOST_CHECK(R1L >= ~~R1L); BOOST_CHECK(R1S >= ~~R1S);
+
+ BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L);
+ BOOST_CHECK(~~R1S + R2S == R1S + ~~R2S);
+ BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L);
+ BOOST_CHECK(~~R1S - R2S == R1S - ~~R2S);
+ BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L);
+ BOOST_CHECK(~R1S != R1S); BOOST_CHECK(R1S != ~R1S);
+ unsigned char TmpArray[32];
+ CHECKBITWISEOPERATOR(~R1,R2,|)
+ CHECKBITWISEOPERATOR(~R1,R2,^)
+ CHECKBITWISEOPERATOR(~R1,R2,&)
+ CHECKBITWISEOPERATOR(R1,~R2,|)
+ CHECKBITWISEOPERATOR(R1,~R2,^)
+ CHECKBITWISEOPERATOR(R1,~R2,&)
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
new file mode 100644
index 000000000..691f02a9d
--- /dev/null
+++ b/src/test/util_tests.cpp
@@ -0,0 +1,341 @@
+#include "util.h"
+
+#include "sync.h"
+
+#include <stdint.h>
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+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)
+{
+/*These are platform-dependant and thus removed to avoid useless test failures
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0), "1970-01-01 00:00:00");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0x7FFFFFFF), "2038-01-19 03:14:07");
+ // Formats used within Bitcoin
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 1317425777), "2011-09-30 23:36:17");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M", 1317425777), "2011-09-30 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", false), true);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest2", false), false);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest3", false), false);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest4", false), 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_t 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_CASE(util_seed_insecure_rand)
+{
+ int i;
+ int count=0;
+
+ seed_insecure_rand(true);
+
+ for (int mod=2;mod<11;mod++)
+ {
+ int mask = 1;
+ // Really rough binomal confidence approximation.
+ int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);
+ //mask is 2^ceil(log2(mod))-1
+ while(mask<mod-1)mask=(mask<<1)+1;
+
+ count = 0;
+ //How often does it get a zero from the uniform range [0,mod)?
+ for (i=0;i<10000;i++)
+ {
+ uint32_t rval;
+ do{
+ rval=insecure_rand()&mask;
+ }while(rval>=(uint32_t)mod);
+ count += rval==0;
+ }
+ BOOST_CHECK(count<=10000/mod+err);
+ BOOST_CHECK(count>=10000/mod-err);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(util_TimingResistantEqual)
+{
+ BOOST_CHECK(TimingResistantEqual(std::string(""), std::string("")));
+ BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("")));
+ BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc")));
+ BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa")));
+ BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a")));
+ BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc")));
+ BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba")));
+}
+
+/* Test strprintf formatting directives.
+ * Put a string before and after to ensure sanity of element sizes on stack. */
+#define B "check_prefix"
+#define E "check_postfix"
+BOOST_AUTO_TEST_CASE(strprintf_numbers)
+{
+ int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */
+ uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */
+ BOOST_CHECK(strprintf("%s %"PRId64" %s", B, s64t, E) == B" -9223372036854775807 "E);
+ BOOST_CHECK(strprintf("%s %"PRIu64" %s", B, u64t, E) == B" 18446744073709551615 "E);
+ BOOST_CHECK(strprintf("%s %"PRIx64" %s", B, u64t, E) == B" ffffffffffffffff "E);
+
+ size_t st = 12345678; /* unsigned size_t test value */
+ ssize_t sst = -12345678; /* signed size_t test value */
+ BOOST_CHECK(strprintf("%s %"PRIszd" %s", B, sst, E) == B" -12345678 "E);
+ BOOST_CHECK(strprintf("%s %"PRIszu" %s", B, st, E) == B" 12345678 "E);
+ BOOST_CHECK(strprintf("%s %"PRIszx" %s", B, st, E) == B" bc614e "E);
+
+ ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */
+ ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */
+ BOOST_CHECK(strprintf("%s %"PRIpdd" %s", B, spt, E) == B" -87654321 "E);
+ BOOST_CHECK(strprintf("%s %"PRIpdu" %s", B, pt, E) == B" 87654321 "E);
+ BOOST_CHECK(strprintf("%s %"PRIpdx" %s", B, pt, E) == B" 5397fb1 "E);
+}
+#undef B
+#undef E
+
+/* Check for mingw/wine issue #3494
+ * Remove this test before time.ctime(0xffffffff) == 'Sun Feb 7 07:28:15 2106'
+ */
+BOOST_AUTO_TEST_CASE(gettime)
+{
+ BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp
new file mode 100644
index 000000000..0acd94ef3
--- /dev/null
+++ b/src/test/wallet_tests.cpp
@@ -0,0 +1,300 @@
+#include "wallet.h"
+
+#include <set>
+#include <stdint.h>
+#include <utility>
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+
+// 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_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
+{
+ static int nextLockTime = 0;
+ CTransaction tx;
+ tx.nLockTime = nextLockTime++; // so all transactions get different hashes
+ tx.vout.resize(nInput+1);
+ tx.vout[nInput].nValue = nValue;
+ CWalletTx* wtx = new CWalletTx(&wallet, 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)
+{
+ CoinSet setCoinsRet, setCoinsRet2;
+ int64_t 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(), 3U); // 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(), 2U);
+
+ // 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(), 3U);
+
+ // 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(), 1U);
+
+ // 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(), 1U);
+
+ 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(), 3U);
+
+ 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(), 1U); // 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(), 2U);
+
+ // 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 BTC in 1 coin
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
+
+ BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
+
+ // 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(), 10U); // 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(), 1U);
+
+ // 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(), 2U); // 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(), 3U);
+
+ // 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(), 2U);
+
+ // 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);
+ }
+ }
+ empty_wallet();
+}
+
+BOOST_AUTO_TEST_SUITE_END()