aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/addrman_tests.cpp9
-rw-r--r--src/test/crypto_tests.cpp126
-rw-r--r--src/test/denialofservice_tests.cpp5
-rw-r--r--src/test/multisig_tests.cpp4
-rw-r--r--src/test/script_p2sh_tests.cpp8
-rw-r--r--src/test/script_standard_tests.cpp2
-rw-r--r--src/test/script_tests.cpp4
-rw-r--r--src/test/setup_common.cpp1
-rw-r--r--src/test/transaction_tests.cpp14
-rw-r--r--src/test/txvalidationcache_tests.cpp4
-rw-r--r--src/test/util.cpp11
-rw-r--r--src/test/validation_block_tests.cpp152
12 files changed, 299 insertions, 41 deletions
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index eeb54b4cf0..da0abd495a 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -533,9 +533,6 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
BOOST_CHECK(addrman.size() == 0);
// Empty addrman should return blank addrman info.
@@ -568,9 +565,6 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
// Add twenty two addresses.
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) {
@@ -627,9 +621,6 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
BOOST_CHECK(addrman.size() == 0);
// Empty addrman should return blank addrman info.
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 4e2acca4c3..4ac12bf969 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -4,6 +4,7 @@
#include <crypto/aes.h>
#include <crypto/chacha20.h>
+#include <crypto/chacha_poly_aead.h>
#include <crypto/poly1305.h>
#include <crypto/hkdf_sha256_32.h>
#include <crypto/hmac_sha256.h>
@@ -585,6 +586,131 @@ BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests)
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d");
}
+static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aad_length, const std::string& hex_m, const std::string& hex_k1, const std::string& hex_k2, const std::string& hex_aad_keystream, const std::string& hex_encrypted_message, const std::string& hex_encrypted_message_seq_999)
+{
+ // we need two sequence numbers, one for the payload cipher instance...
+ uint32_t seqnr_payload = 0;
+ // ... and one for the AAD (length) cipher instance
+ uint32_t seqnr_aad = 0;
+ // we need to keep track of the position in the AAD cipher instance
+ // keystream since we use the same 64byte output 21 times
+ // (21 times 3 bytes length < 64)
+ int aad_pos = 0;
+
+ std::vector<unsigned char> aead_K_1 = ParseHex(hex_k1);
+ std::vector<unsigned char> aead_K_2 = ParseHex(hex_k2);
+ std::vector<unsigned char> plaintext_buf = ParseHex(hex_m);
+ std::vector<unsigned char> expected_aad_keystream = ParseHex(hex_aad_keystream);
+ std::vector<unsigned char> expected_ciphertext_and_mac = ParseHex(hex_encrypted_message);
+ std::vector<unsigned char> expected_ciphertext_and_mac_sequence999 = ParseHex(hex_encrypted_message_seq_999);
+
+ std::vector<unsigned char> ciphertext_buf(plaintext_buf.size() + POLY1305_TAGLEN, 0);
+ std::vector<unsigned char> plaintext_buf_new(plaintext_buf.size(), 0);
+ std::vector<unsigned char> cmp_ctx_buffer(64);
+ uint32_t out_len = 0;
+
+ // create the AEAD instance
+ ChaCha20Poly1305AEAD aead(aead_K_1.data(), aead_K_1.size(), aead_K_2.data(), aead_K_2.size());
+
+ // create a chacha20 instance to compare against
+ ChaCha20 cmp_ctx(aead_K_2.data(), 32);
+
+ // encipher
+ bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
+ // make sure the operation succeeded if expected to succeed
+ BOOST_CHECK_EQUAL(res, must_succeed);
+ if (!res) return;
+
+ // verify ciphertext & mac against the test vector
+ BOOST_CHECK_EQUAL(expected_ciphertext_and_mac.size(), ciphertext_buf.size());
+ BOOST_CHECK(memcmp(ciphertext_buf.data(), expected_ciphertext_and_mac.data(), ciphertext_buf.size()) == 0);
+
+ // manually construct the AAD keystream
+ cmp_ctx.SetIV(seqnr_aad);
+ cmp_ctx.Seek(0);
+ cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
+ BOOST_CHECK(memcmp(expected_aad_keystream.data(), cmp_ctx_buffer.data(), expected_aad_keystream.size()) == 0);
+ // crypt the 3 length bytes and compare the length
+ uint32_t len_cmp = 0;
+ len_cmp = (ciphertext_buf[0] ^ cmp_ctx_buffer[aad_pos + 0]) |
+ (ciphertext_buf[1] ^ cmp_ctx_buffer[aad_pos + 1]) << 8 |
+ (ciphertext_buf[2] ^ cmp_ctx_buffer[aad_pos + 2]) << 16;
+ BOOST_CHECK_EQUAL(len_cmp, expected_aad_length);
+
+ // encrypt / decrypt 1000 packets
+ for (size_t i = 0; i < 1000; ++i) {
+ res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
+ BOOST_CHECK(res);
+ BOOST_CHECK(aead.GetLength(&out_len, seqnr_aad, aad_pos, ciphertext_buf.data()));
+ BOOST_CHECK_EQUAL(out_len, expected_aad_length);
+ res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, plaintext_buf_new.data(), plaintext_buf_new.size(), ciphertext_buf.data(), ciphertext_buf.size(), false);
+ BOOST_CHECK(res);
+
+ // make sure we repetitive get the same plaintext
+ BOOST_CHECK(memcmp(plaintext_buf.data(), plaintext_buf_new.data(), plaintext_buf.size()) == 0);
+
+ // compare sequence number 999 against the test vector
+ if (seqnr_payload == 999) {
+ BOOST_CHECK(memcmp(ciphertext_buf.data(), expected_ciphertext_and_mac_sequence999.data(), expected_ciphertext_and_mac_sequence999.size()) == 0);
+ }
+ // set nonce and block counter, output the keystream
+ cmp_ctx.SetIV(seqnr_aad);
+ cmp_ctx.Seek(0);
+ cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
+
+ // crypt the 3 length bytes and compare the length
+ len_cmp = 0;
+ len_cmp = (ciphertext_buf[0] ^ cmp_ctx_buffer[aad_pos + 0]) |
+ (ciphertext_buf[1] ^ cmp_ctx_buffer[aad_pos + 1]) << 8 |
+ (ciphertext_buf[2] ^ cmp_ctx_buffer[aad_pos + 2]) << 16;
+ BOOST_CHECK_EQUAL(len_cmp, expected_aad_length);
+
+ // increment the sequence number(s)
+ // always increment the payload sequence number
+ // increment the AAD keystream position by its size (3)
+ // increment the AAD sequence number if we would hit the 64 byte limit
+ seqnr_payload++;
+ aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
+ if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
+ aad_pos = 0;
+ seqnr_aad++;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(chacha20_poly1305_aead_testvector)
+{
+ /* test chacha20poly1305@bitcoin AEAD */
+
+ // must fail with no message
+ TestChaCha20Poly1305AEAD(false, 0,
+ "",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000", "", "", "");
+
+ TestChaCha20Poly1305AEAD(true, 0,
+ /* m */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* k1 (payload) */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* k2 (AAD) */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* AAD keystream */ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
+ /* encrypted message & MAC */ "76b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32d2fc11829c1b6c1df1f551cd6131ff08",
+ /* encrypted message & MAC at sequence 999 */ "b0a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3aaa7aa16ec62c5e24f040c08bb20c3598");
+ TestChaCha20Poly1305AEAD(true, 1,
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
+ "77b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32baf0c85b6dff8602b06cf52a6aefc62e",
+ "b1a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3a8bd94d54b5ecabbc41ffbb0c90924080");
+ TestChaCha20Poly1305AEAD(true, 255,
+ "ff0000f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78fab78c9",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "ff0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "c640c1711e3ee904ac35c57ab9791c8a1c408603a90b77a83b54f6c844cb4b06d94e7fc6c800e165acd66147e80ec45a567f6ce66d05ec0cae679dceeb890017",
+ "3940c1e92da4582ff6f92a776aeb14d014d384eeb30f660dacf70a14a23fd31e91212701334e2ce1acf5199dc84f4d61ddbe6571bca5af874b4c9226c26e650995d157644e1848b96ed6c2102d5489a050e71d29a5a66ece11de5fb5c9558d54da28fe45b0bc4db4e5b88030bfc4a352b4b7068eccf656bae7ad6a35615315fc7c49d4200388d5eca67c2e822e069336c69b40db67e0f3c81209c50f3216a4b89fb3ae1b984b7851a2ec6f68ab12b101ab120e1ea7313bb93b5a0f71185c7fea017ddb92769861c29dba4fbc432280d5dff21b36d1c4c790128b22699950bb18bf74c448cdfe547d8ed4f657d8005fdc0cd7a050c2d46050a44c4376355858981fbe8b184288276e7a93eabc899c4a",
+ "f039c6689eaeef0456685200feaab9d54bbd9acde4410a3b6f4321296f4a8ca2604b49727d8892c57e005d799b2a38e85e809f20146e08eec75169691c8d4f54a0d51a1e1c7b381e0474eb02f994be9415ef3ffcbd2343f0601e1f3b172a1d494f838824e4df570f8e3b0c04e27966e36c82abd352d07054ef7bd36b84c63f9369afe7ed79b94f953873006b920c3fa251a771de1b63da927058ade119aa898b8c97e42a606b2f6df1e2d957c22f7593c1e2002f4252f4c9ae4bf773499e5cfcfe14dfc1ede26508953f88553bf4a76a802f6a0068d59295b01503fd9a600067624203e880fdf53933b96e1f4d9eb3f4e363dd8165a278ff667a41ee42b9892b077cefff92b93441f7be74cf10e6cd");
+}
+
BOOST_AUTO_TEST_CASE(countbits_tests)
{
FastRandomContext ctx;
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 93883d1d98..a50d6854f8 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -6,10 +6,11 @@
#include <banman.h>
#include <chainparams.h>
-#include <keystore.h>
#include <net.h>
#include <net_processing.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
+#include <script/standard.h>
#include <serialize.h>
#include <util/memory.h>
#include <util/system.h>
@@ -369,7 +370,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
CKey key;
key.MakeNewKey(true);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(key));
// 50 orphan transactions:
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 11e79937be..7c60abb93f 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -3,12 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
-#include <keystore.h>
#include <policy/policy.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/interpreter.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <tinyformat.h>
#include <uint256.h>
#include <test/setup_common.h>
@@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
BOOST_AUTO_TEST_CASE(multisig_Sign)
{
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[4];
for (int i = 0; i < 4; i++)
{
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index 735b67c06e..f451d80984 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -4,13 +4,13 @@
#include <consensus/tx_verify.h>
#include <key.h>
-#include <keystore.h>
#include <validation.h>
#include <policy/policy.h>
#include <script/script.h>
#include <script/script_error.h>
#include <policy/settings.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <test/setup_common.h>
#include <vector>
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(sign)
// scriptPubKey: HASH160 <hash> EQUAL
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[4];
for (int i = 0; i < 4; i++)
{
@@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(set)
{
LOCK(cs_main);
// Test the CScript::Set* methods
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[4];
std::vector<CPubKey> keys;
for (int i = 0; i < 4; i++)
@@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
LOCK(cs_main);
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[6];
std::vector<CPubKey> keys;
for (int i = 0; i < 6; i++)
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 046b220e3f..412a57dd9d 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
-#include <keystore.h>
#include <script/script.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <test/setup_common.h>
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index ae903df0ad..84a70fe78b 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -6,10 +6,10 @@
#include <core_io.h>
#include <key.h>
-#include <keystore.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <test/setup_common.h>
@@ -1199,7 +1199,7 @@ SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction&
BOOST_AUTO_TEST_CASE(script_combineSigs)
{
// Test the ProduceSignature's ability to combine signatures function
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
std::vector<CKey> keys;
std::vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++)
diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp
index e3ba9cddb0..24c7d51898 100644
--- a/src/test/setup_common.cpp
+++ b/src/test/setup_common.cpp
@@ -73,7 +73,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
const CChainParams& chainparams = Params();
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
-
RegisterAllCoreRPCCommands(tableRPC);
// We have to run a scheduler thread to prevent ActivateBestChain
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index f77b77a972..34192c6b6a 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -12,12 +12,12 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <key.h>
-#include <keystore.h>
#include <validation.h>
#include <policy/policy.h>
#include <policy/settings.h>
#include <script/script.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <script/script_error.h>
#include <script/standard.h>
#include <streams.h>
@@ -289,7 +289,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEYHASH.
//
static std::vector<CMutableTransaction>
-SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
+SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
{
std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
@@ -322,7 +322,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
BOOST_AUTO_TEST_CASE(test_Get)
{
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
@@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
BOOST_CHECK_EQUAL(coins.GetValueIn(CTransaction(t1)), (50+21+22)*CENT);
}
-static void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
+static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
{
CMutableTransaction outputm;
outputm.nVersion = 1;
@@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
CKey key;
key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKeyPubKey(key, key.GetPubKey()));
CKeyID hash = key.GetPubKey().GetID();
CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
@@ -507,7 +507,7 @@ SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutabl
BOOST_AUTO_TEST_CASE(test_witness)
{
- CBasicKeyStore keystore, keystore2;
+ FillableSigningProvider keystore, keystore2;
CKey key1, key2, key3, key1L, key2L;
CPubKey pubkey1, pubkey2, pubkey3, pubkey1L, pubkey2L;
key1.MakeNewKey(true);
@@ -682,7 +682,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
BOOST_AUTO_TEST_CASE(test_IsStandard)
{
LOCK(cs_main);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 45c97fa2aa..f99a3748c9 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -8,8 +8,8 @@
#include <txmempool.h>
#include <script/standard.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <test/setup_common.h>
-#include <keystore.h>
#include <boost/test/unit_test.hpp>
@@ -161,7 +161,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(coinbaseKey));
BOOST_CHECK(keystore.AddCScript(p2pk_scriptPubKey));
diff --git a/src/test/util.cpp b/src/test/util.cpp
index a2ea648324..b7bb6deeaa 100644
--- a/src/test/util.cpp
+++ b/src/test/util.cpp
@@ -23,14 +23,9 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
std::string getnewaddress(CWallet& w)
{
constexpr auto output_type = OutputType::BECH32;
-
- CPubKey new_key;
- if (!w.GetKeyFromPool(new_key)) assert(false);
-
- w.LearnRelatedScripts(new_key, output_type);
- const auto dest = GetDestinationForKey(new_key, output_type);
-
- w.SetAddressBook(dest, /* label */ "", "receive");
+ CTxDestination dest;
+ std::string error;
+ if (!w.GetNewDestination(output_type, "", dest, error)) assert(false);
return EncodeDestination(dest);
}
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 6a9813442b..b3368d44b6 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -10,6 +10,7 @@
#include <miner.h>
#include <pow.h>
#include <random.h>
+#include <script/standard.h>
#include <test/setup_common.h>
#include <util/time.h>
#include <validation.h>
@@ -21,6 +22,8 @@ struct RegtestingSetup : public TestingSetup {
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
};
+static const std::vector<unsigned char> V_OP_TRUE{OP_TRUE};
+
BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup)
struct TestSubscriber : public CValidationInterface {
@@ -62,8 +65,21 @@ std::shared_ptr<CBlock> Block(const uint256& prev_hash)
pblock->hashPrevBlock = prev_hash;
pblock->nTime = ++time;
+ pubKey.clear();
+ {
+ WitnessV0ScriptHash witness_program;
+ CSHA256().Write(&V_OP_TRUE[0], V_OP_TRUE.size()).Finalize(witness_program.begin());
+ pubKey << OP_0 << ToByteVector(witness_program);
+ }
+
+ // Make the coinbase transaction with two outputs:
+ // One zero-value one that has a unique pubkey to make sure that blocks at the same height can have a different hash
+ // Another one that has the coinbase reward in a P2WSH with OP_TRUE as witness program to make it easy to spend
CMutableTransaction txCoinbase(*pblock->vtx[0]);
- txCoinbase.vout.resize(1);
+ txCoinbase.vout.resize(2);
+ txCoinbase.vout[1].scriptPubKey = pubKey;
+ txCoinbase.vout[1].nValue = txCoinbase.vout[0].nValue;
+ txCoinbase.vout[0].nValue = 0;
txCoinbase.vin[0].scriptWitness.SetNull();
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
@@ -72,6 +88,9 @@ std::shared_ptr<CBlock> Block(const uint256& prev_hash)
std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock)
{
+ LOCK(cs_main); // For LookupBlockIndex
+ GenerateCoinbaseCommitment(*pblock, LookupBlockIndex(pblock->hashPrevBlock), Params().GetConsensus());
+
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
@@ -82,13 +101,13 @@ std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock)
}
// construct a valid block
-const std::shared_ptr<const CBlock> GoodBlock(const uint256& prev_hash)
+std::shared_ptr<const CBlock> GoodBlock(const uint256& prev_hash)
{
return FinalizeBlock(Block(prev_hash));
}
// construct an invalid block (but with a valid header)
-const std::shared_ptr<const CBlock> BadBlock(const uint256& prev_hash)
+std::shared_ptr<const CBlock> BadBlock(const uint256& prev_hash)
{
auto pblock = Block(prev_hash);
@@ -188,4 +207,131 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
}
+/**
+ * Test that mempool updates happen atomically with reorgs.
+ *
+ * This prevents RPC clients, among others, from retrieving immediately-out-of-date mempool data
+ * during large reorgs.
+ *
+ * The test verifies this by creating a chain of `num_txs` blocks, matures their coinbases, and then
+ * submits txns spending from their coinbase to the mempool. A fork chain is then processed,
+ * invalidating the txns and evicting them from the mempool.
+ *
+ * We verify that the mempool updates atomically by polling it continuously
+ * from another thread during the reorg and checking that its size only changes
+ * once. The size changing exactly once indicates that the polling thread's
+ * view of the mempool is either consistent with the chain state before reorg,
+ * or consistent with the chain state after the reorg, and not just consistent
+ * with some intermediate state during the reorg.
+ */
+BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
+{
+ bool ignored;
+ auto ProcessBlock = [&ignored](std::shared_ptr<const CBlock> block) -> bool {
+ return ProcessNewBlock(Params(), block, /* fForceProcessing */ true, /* fNewBlock */ &ignored);
+ };
+
+ // Process all mined blocks
+ BOOST_REQUIRE(ProcessBlock(std::make_shared<CBlock>(Params().GenesisBlock())));
+ auto last_mined = GoodBlock(Params().GenesisBlock().GetHash());
+ BOOST_REQUIRE(ProcessBlock(last_mined));
+
+ // Run the test multiple times
+ for (int test_runs = 3; test_runs > 0; --test_runs) {
+ BOOST_CHECK_EQUAL(last_mined->GetHash(), ::ChainActive().Tip()->GetBlockHash());
+
+ // Later on split from here
+ const uint256 split_hash{last_mined->hashPrevBlock};
+
+ // Create a bunch of transactions to spend the miner rewards of the
+ // most recent blocks
+ std::vector<CTransactionRef> txs;
+ for (int num_txs = 22; num_txs > 0; --num_txs) {
+ CMutableTransaction mtx;
+ mtx.vin.push_back(CTxIn{COutPoint{last_mined->vtx[0]->GetHash(), 1}, CScript{}});
+ mtx.vin[0].scriptWitness.stack.push_back(V_OP_TRUE);
+ mtx.vout.push_back(last_mined->vtx[0]->vout[1]);
+ mtx.vout[0].nValue -= 1000;
+ txs.push_back(MakeTransactionRef(mtx));
+
+ last_mined = GoodBlock(last_mined->GetHash());
+ BOOST_REQUIRE(ProcessBlock(last_mined));
+ }
+
+ // Mature the inputs of the txs
+ for (int j = COINBASE_MATURITY; j > 0; --j) {
+ last_mined = GoodBlock(last_mined->GetHash());
+ BOOST_REQUIRE(ProcessBlock(last_mined));
+ }
+
+ // Mine a reorg (and hold it back) before adding the txs to the mempool
+ const uint256 tip_init{last_mined->GetHash()};
+
+ std::vector<std::shared_ptr<const CBlock>> reorg;
+ last_mined = GoodBlock(split_hash);
+ reorg.push_back(last_mined);
+ for (size_t j = COINBASE_MATURITY + txs.size() + 1; j > 0; --j) {
+ last_mined = GoodBlock(last_mined->GetHash());
+ reorg.push_back(last_mined);
+ }
+
+ // Add the txs to the tx pool
+ {
+ LOCK(cs_main);
+ CValidationState state;
+ std::list<CTransactionRef> plTxnReplaced;
+ for (const auto& tx : txs) {
+ BOOST_REQUIRE(AcceptToMemoryPool(
+ ::mempool,
+ state,
+ tx,
+ /* pfMissingInputs */ &ignored,
+ &plTxnReplaced,
+ /* bypass_limits */ false,
+ /* nAbsurdFee */ 0));
+ }
+ }
+
+ // Check that all txs are in the pool
+ {
+ LOCK(::mempool.cs);
+ BOOST_CHECK_EQUAL(::mempool.mapTx.size(), txs.size());
+ }
+
+ // Run a thread that simulates an RPC caller that is polling while
+ // validation is doing a reorg
+ std::thread rpc_thread{[&]() {
+ // This thread is checking that the mempool either contains all of
+ // the transactions invalidated by the reorg, or none of them, and
+ // not some intermediate amount.
+ while (true) {
+ LOCK(::mempool.cs);
+ if (::mempool.mapTx.size() == 0) {
+ // We are done with the reorg
+ break;
+ }
+ // Internally, we might be in the middle of the reorg, but
+ // externally the reorg to the most-proof-of-work chain should
+ // be atomic. So the caller assumes that the returned mempool
+ // is consistent. That is, it has all txs that were there
+ // before the reorg.
+ assert(::mempool.mapTx.size() == txs.size());
+ continue;
+ }
+ LOCK(cs_main);
+ // We are done with the reorg, so the tip must have changed
+ assert(tip_init != ::ChainActive().Tip()->GetBlockHash());
+ }};
+
+ // Submit the reorg in this thread to invalidate and remove the txs from the tx pool
+ for (const auto& b : reorg) {
+ ProcessBlock(b);
+ }
+ // Check that the reorg was eventually successful
+ BOOST_CHECK_EQUAL(last_mined->GetHash(), ::ChainActive().Tip()->GetBlockHash());
+
+ // We can join the other thread, which returns when the reorg was successful
+ rpc_thread.join();
+ }
+}
BOOST_AUTO_TEST_SUITE_END()