Branch data Line data Source code
1 : : // Copyright (c) 2011-2022 The Bitcoin Core developers 2 : : // Distributed under the MIT software license, see the accompanying 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : : 5 : : #include <arith_uint256.h> 6 : : #include <pubkey.h> 7 : : #include <script/sign.h> 8 : : #include <script/signingprovider.h> 9 : : #include <test/util/random.h> 10 : : #include <test/util/setup_common.h> 11 : : #include <txorphanage.h> 12 : : 13 : : #include <array> 14 : : #include <cstdint> 15 : : 16 : : #include <boost/test/unit_test.hpp> 17 : 0 : 18 : 0 : BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup) 19 : : 20 : : class TxOrphanageTest : public TxOrphanage 21 : : { 22 : : public: 23 : 0 : inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) 24 : : { 25 : 0 : LOCK(m_mutex); 26 : 0 : return m_orphans.size(); 27 : 0 : } 28 : : 29 : 0 : CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) 30 : : { 31 : 0 : LOCK(m_mutex); 32 : 0 : std::map<uint256, OrphanTx>::iterator it; 33 : 0 : it = m_orphans.lower_bound(InsecureRand256()); 34 : 0 : if (it == m_orphans.end()) 35 : 0 : it = m_orphans.begin(); 36 : 0 : return it->second.tx; 37 : 0 : } 38 : : }; 39 : : 40 : 0 : static void MakeNewKeyWithFastRandomContext(CKey& key) 41 : : { 42 : 0 : std::vector<unsigned char> keydata; 43 : 0 : keydata = g_insecure_rand_ctx.randbytes(32); 44 : 0 : key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true); 45 : 0 : assert(key.IsValid()); 46 : 0 : } 47 : : 48 : 0 : BOOST_AUTO_TEST_CASE(DoS_mapOrphans) 49 : : { 50 : : // This test had non-deterministic coverage due to 51 : : // randomly selected seeds. 52 : : // This seed is chosen so that all branches of the function 53 : : // ecdsa_signature_parse_der_lax are executed during this test. 54 : : // Specifically branches that run only when an ECDSA 55 : : // signature's R and S values have leading zeros. 56 : 0 : g_insecure_rand_ctx = FastRandomContext{uint256{33}}; 57 : : 58 : 0 : TxOrphanageTest orphanage; 59 : 0 : CKey key; 60 : 0 : MakeNewKeyWithFastRandomContext(key); 61 : 0 : FillableSigningProvider keystore; 62 : 0 : BOOST_CHECK(keystore.AddKey(key)); 63 : : 64 : : // 50 orphan transactions: 65 : 0 : for (int i = 0; i < 50; i++) 66 : : { 67 : 0 : CMutableTransaction tx; 68 : 0 : tx.vin.resize(1); 69 : 0 : tx.vin[0].prevout.n = 0; 70 : 0 : tx.vin[0].prevout.hash = InsecureRand256(); 71 : 0 : tx.vin[0].scriptSig << OP_1; 72 : 0 : tx.vout.resize(1); 73 : 0 : tx.vout[0].nValue = 1*CENT; 74 : 0 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); 75 : : 76 : 0 : orphanage.AddTx(MakeTransactionRef(tx), i); 77 : 0 : } 78 : : 79 : : // ... and 50 that depend on other orphans: 80 : 0 : for (int i = 0; i < 50; i++) 81 : : { 82 : 0 : CTransactionRef txPrev = orphanage.RandomOrphan(); 83 : 0 : 84 : 0 : CMutableTransaction tx; 85 : 0 : tx.vin.resize(1); 86 : 0 : tx.vin[0].prevout.n = 0; 87 : 0 : tx.vin[0].prevout.hash = txPrev->GetHash(); 88 : 0 : tx.vout.resize(1); 89 : 0 : tx.vout[0].nValue = 1*CENT; 90 : 0 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); 91 : 0 : SignatureData empty; 92 : 0 : BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty)); 93 : : 94 : 0 : orphanage.AddTx(MakeTransactionRef(tx), i); 95 : 0 : } 96 : : 97 : : // This really-big orphan should be ignored: 98 : 0 : for (int i = 0; i < 10; i++) 99 : : { 100 : 0 : CTransactionRef txPrev = orphanage.RandomOrphan(); 101 : : 102 : 0 : CMutableTransaction tx; 103 : 0 : tx.vout.resize(1); 104 : 0 : tx.vout[0].nValue = 1*CENT; 105 : 0 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); 106 : 0 : tx.vin.resize(2777); 107 : 0 : for (unsigned int j = 0; j < tx.vin.size(); j++) 108 : : { 109 : 0 : tx.vin[j].prevout.n = j; 110 : 0 : tx.vin[j].prevout.hash = txPrev->GetHash(); 111 : 0 : } 112 : 0 : SignatureData empty; 113 : 0 : BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty)); 114 : : // Re-use same signature for other inputs 115 : : // (they don't have to be valid for this test) 116 : 0 : for (unsigned int j = 1; j < tx.vin.size(); j++) 117 : 0 : tx.vin[j].scriptSig = tx.vin[0].scriptSig; 118 : : 119 : 0 : BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i)); 120 : 0 : } 121 : : 122 : : // Test EraseOrphansFor: 123 : 0 : for (NodeId i = 0; i < 3; i++) 124 : : { 125 : 0 : size_t sizeBefore = orphanage.CountOrphans(); 126 : 0 : orphanage.EraseForPeer(i); 127 : 0 : BOOST_CHECK(orphanage.CountOrphans() < sizeBefore); 128 : 0 : } 129 : : 130 : : // Test LimitOrphanTxSize() function: 131 : 0 : orphanage.LimitOrphans(40); 132 : 0 : BOOST_CHECK(orphanage.CountOrphans() <= 40); 133 : 0 : orphanage.LimitOrphans(10); 134 : 0 : BOOST_CHECK(orphanage.CountOrphans() <= 10); 135 : 0 : orphanage.LimitOrphans(0); 136 : 0 : BOOST_CHECK(orphanage.CountOrphans() == 0); 137 : 0 : } 138 : : 139 : 0 : BOOST_AUTO_TEST_SUITE_END()