252 lines
7.9 KiB
C++
252 lines
7.9 KiB
C++
// Copyright (c) 2011-2013 The Bitcoin Core developers
|
|
// Copyright (c) 2016-2023 The Zcash developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
|
|
|
#define BOOST_TEST_MODULE Bitcoin Test Suite
|
|
|
|
#include "test_bitcoin.h"
|
|
|
|
#include "chainparams.h"
|
|
#include "consensus/consensus.h"
|
|
#include "consensus/validation.h"
|
|
#ifdef ENABLE_MINING
|
|
#include "crypto/equihash.h"
|
|
#endif
|
|
#include "crypto/sha256.h"
|
|
#include "fs.h"
|
|
#include "key.h"
|
|
#include "main.h"
|
|
#include "miner.h"
|
|
#include "pubkey.h"
|
|
#include "random.h"
|
|
#include "txdb.h"
|
|
#include "txmempool.h"
|
|
#include "ui_interface.h"
|
|
#include "rpc/server.h"
|
|
#include "rpc/register.h"
|
|
#include "script/sigcache.h"
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <boost/thread.hpp>
|
|
#include <sodium.h>
|
|
#include <tracing.h>
|
|
|
|
#include "librustzcash.h"
|
|
|
|
#include <rust/bridge.h>
|
|
|
|
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
|
|
|
|
CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h
|
|
|
|
TracingHandle* pTracingHandle = nullptr;
|
|
uint256 insecure_rand_seed = GetRandHash();
|
|
FastRandomContext insecure_rand_ctx(insecure_rand_seed);
|
|
|
|
extern bool fPrintToConsole;
|
|
extern void noui_connect();
|
|
|
|
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
|
|
{
|
|
assert(sodium_init() != -1);
|
|
SHA256AutoDetect();
|
|
ECC_Start();
|
|
SetupEnvironment();
|
|
SetupNetworking();
|
|
InitSignatureCache(DEFAULT_MAX_SIG_CACHE_SIZE * ((size_t) 1 << 20));
|
|
bundlecache::init(DEFAULT_MAX_SIG_CACHE_SIZE * ((size_t) 1 << 20));
|
|
|
|
// Uncomment this to log all errors to stdout so we see them in test output.
|
|
// We don't enable this by default because several tests intentionally cause
|
|
// verbose error output (while exercising failure cases).
|
|
// if (pTracingHandle == nullptr) {
|
|
// std::string initialFilter = "error";
|
|
// pTracingHandle = tracing_init(
|
|
// nullptr, 0,
|
|
// initialFilter.c_str(),
|
|
// false);
|
|
// }
|
|
|
|
fCheckBlockIndex = true;
|
|
SelectParams(chainName);
|
|
noui_connect();
|
|
TestSetIBD(false);
|
|
}
|
|
|
|
BasicTestingSetup::~BasicTestingSetup()
|
|
{
|
|
ECC_Stop();
|
|
}
|
|
|
|
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
|
|
{
|
|
fs::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params";
|
|
fs::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";
|
|
fs::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params";
|
|
|
|
static_assert(
|
|
sizeof(fs::path::value_type) == sizeof(codeunit),
|
|
"librustzcash not configured correctly");
|
|
auto sapling_spend_str = sapling_spend.native();
|
|
auto sapling_output_str = sapling_output.native();
|
|
auto sprout_groth16_str = sprout_groth16.native();
|
|
|
|
librustzcash_init_zksnark_params(
|
|
reinterpret_cast<const codeunit*>(sapling_spend_str.c_str()),
|
|
sapling_spend_str.length(),
|
|
reinterpret_cast<const codeunit*>(sapling_output_str.c_str()),
|
|
sapling_output_str.length(),
|
|
reinterpret_cast<const codeunit*>(sprout_groth16_str.c_str()),
|
|
sprout_groth16_str.length(),
|
|
// Only load the verifying keys, which some tests need.
|
|
false
|
|
);
|
|
|
|
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);
|
|
|
|
// Save current path, in case a test changes it
|
|
orig_current_path = fs::current_path();
|
|
|
|
ClearDatadirCache();
|
|
pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
|
|
fs::create_directories(pathTemp);
|
|
mapArgs["-datadir"] = pathTemp.string();
|
|
pblocktree = new CBlockTreeDB(1 << 20, true);
|
|
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
|
|
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
|
|
InitBlockIndex(chainparams);
|
|
{
|
|
CValidationState state;
|
|
bool ok = ActivateBestChain(state, chainparams);
|
|
BOOST_CHECK(ok);
|
|
}
|
|
nScriptCheckThreads = 3;
|
|
for (int i=0; i < nScriptCheckThreads-1; i++)
|
|
threadGroup.create_thread(&ThreadScriptCheck);
|
|
RegisterNodeSignals(GetNodeSignals());
|
|
}
|
|
|
|
TestingSetup::~TestingSetup()
|
|
{
|
|
UnregisterNodeSignals(GetNodeSignals());
|
|
threadGroup.interrupt_all();
|
|
threadGroup.join_all();
|
|
UnloadBlockIndex();
|
|
delete pcoinsTip;
|
|
delete pcoinsdbview;
|
|
delete pblocktree;
|
|
|
|
// Restore the previous current path so temporary directory can be deleted
|
|
fs::current_path(orig_current_path);
|
|
|
|
fs::remove_all(pathTemp);
|
|
}
|
|
|
|
#ifdef ENABLE_MINING
|
|
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
|
|
{
|
|
// Generate a 100-block chain:
|
|
coinbaseKey = CKey::TestOnlyRandomKey(true);
|
|
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
|
for (int i = 0; i < COINBASE_MATURITY; i++)
|
|
{
|
|
std::vector<CMutableTransaction> noTxns;
|
|
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
|
|
coinbaseTxns.push_back(b.vtx[0]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new block with just given transactions, coinbase paying to
|
|
// scriptPubKey, and try to add it to the current chain.
|
|
//
|
|
CBlock
|
|
TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
|
|
{
|
|
const CChainParams& chainparams = Params();
|
|
unsigned int n = chainparams.GetConsensus().nEquihashN;
|
|
unsigned int k = chainparams.GetConsensus().nEquihashK;
|
|
|
|
boost::shared_ptr<CReserveScript> mAddr(new CReserveScript());
|
|
mAddr->reserveScript = scriptPubKey;
|
|
|
|
CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(mAddr);
|
|
CBlock& block = pblocktemplate->block;
|
|
|
|
// Replace mempool-selected txns with just coinbase plus passed-in txns:
|
|
block.vtx.resize(1);
|
|
for (const CMutableTransaction& tx : txns)
|
|
block.vtx.push_back(tx);
|
|
// IncrementExtraNonce creates a valid coinbase and merkleRoot
|
|
unsigned int extraNonce = 0;
|
|
IncrementExtraNonce(pblocktemplate, chainActive.Tip(), extraNonce, chainparams.GetConsensus());
|
|
|
|
// Hash state
|
|
eh_HashState eh_state = EhInitialiseState(n, k);
|
|
|
|
// I = the block header minus nonce and solution.
|
|
CEquihashInput I{block};
|
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
|
ss << I;
|
|
|
|
// H(I||...
|
|
eh_state.Update((unsigned char*)&ss[0], ss.size());
|
|
|
|
bool found = false;
|
|
do {
|
|
block.nNonce = ArithToUint256(UintToArith256(block.nNonce) + 1);
|
|
|
|
// H(I||V||...
|
|
eh_HashState curr_state(eh_state);
|
|
curr_state.Update(block.nNonce.begin(), block.nNonce.size());
|
|
|
|
// (x_1, x_2, ...) = A(I, V, n, k)
|
|
std::function<bool(std::vector<unsigned char>)> validBlock =
|
|
[&block, &chainparams](std::vector<unsigned char> soln) {
|
|
block.nSolution = soln;
|
|
return CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus());
|
|
};
|
|
found = EhBasicSolveUncancellable(n, k, curr_state, validBlock);
|
|
} while (!found);
|
|
|
|
CValidationState state;
|
|
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
|
|
|
|
CBlock result = block;
|
|
delete pblocktemplate;
|
|
return result;
|
|
}
|
|
|
|
TestChain100Setup::~TestChain100Setup()
|
|
{
|
|
}
|
|
#endif // ENABLE_MINING
|
|
|
|
|
|
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) {
|
|
CTransaction txn(tx);
|
|
bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies;
|
|
|
|
return CTxMemPoolEntry(txn, nFee, nTime, nHeight,
|
|
hasNoDependencies, spendsCoinbase, sigOpCount, nBranchId);
|
|
}
|
|
|
|
void Shutdown(void* parg)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
void StartShutdown()
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
bool ShutdownRequested()
|
|
{
|
|
return false;
|
|
}
|