Add a benchmark for calling ConnectBlock on a block with many inputs

Requires placing block-107134.tar.gz (containing the block, and a fake CoinsDB
containing its inputs) into the base directory of the repository. This can be
generated using qa/zcash/create_benchmark_archive.py (see the script for usage
details).

To facilitate generation of the fake CoinsDB, an additional field 'valueZat' has
been added to 'getrawtransaction' containing the integer number of zatoshis
instead of a decimal number of ZEC.

Closes #2355.
This commit is contained in:
Jack Grigg
2017-05-12 13:00:15 +12:00
parent 20d61ac0ea
commit c66c731adf
8 changed files with 369 additions and 5 deletions

View File

@@ -137,6 +137,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("valueZat", txout.nValue));
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);

View File

@@ -65,6 +65,9 @@ void static BatchWriteHashBestAnchor(CLevelDBBatch &batch, const uint256 &hash)
batch.Write(DB_BEST_ANCHOR, hash);
}
CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) {
}
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}

View File

@@ -31,6 +31,7 @@ class CCoinsViewDB : public CCoinsView
{
protected:
CLevelDBWrapper db;
CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);

View File

@@ -2589,6 +2589,11 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
} else if (benchmarktype == "incnotewitnesses") {
int nTxs = params[2].get_int();
sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
} else if (benchmarktype == "connectblockslow") {
if (Params().NetworkIDString() != "regtest") {
throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
}
sample_times.push_back(benchmark_connectblock_slow());
} else {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
}

View File

@@ -1,4 +1,6 @@
#include <cstdio>
#include <future>
#include <map>
#include <thread>
#include <unistd.h>
#include <boost/filesystem.hpp>
@@ -9,6 +11,7 @@
#include "primitives/transaction.h"
#include "base58.h"
#include "crypto/equihash.h"
#include "chain.h"
#include "chainparams.h"
#include "consensus/validation.h"
#include "main.h"
@@ -17,6 +20,7 @@
#include "script/sign.h"
#include "sodium.h"
#include "streams.h"
#include "txdb.h"
#include "utiltest.h"
#include "wallet/wallet.h"
@@ -322,3 +326,82 @@ double benchmark_increment_note_witnesses(size_t nTxs)
return timer_stop(tv_start);
}
// Fake the input of a given block
class FakeCoinsViewDB : public CCoinsViewDB {
uint256 hash;
ZCIncrementalMerkleTree t;
public:
FakeCoinsViewDB(std::string dbName, uint256& hash) : CCoinsViewDB(dbName, 100, false, false), hash(hash) {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
if (rt == t.root()) {
tree = t;
return true;
}
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
uint256 GetBestBlock() const {
return hash;
}
uint256 GetBestAnchor() const {
return t.root();
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
double benchmark_connectblock_slow()
{
// Test for issue 2017-05-01.a
SelectParams(CBaseChainParams::MAIN);
CBlock block;
FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb");
if (!fp) throw new std::runtime_error("Failed to open block data file");
CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION);
blkFile >> block;
blkFile.fclose();
// Fake its inputs
auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef");
FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev);
CCoinsViewCache view(&fakeDB);
// Fake the chain
CBlockIndex index(block);
index.nHeight = 107134;
CBlockIndex indexPrev;
indexPrev.phashBlock = &hashPrev;
indexPrev.nHeight = index.nHeight - 1;
index.pprev = &indexPrev;
mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev));
CValidationState state;
struct timeval tv_start;
timer_start(tv_start);
assert(ConnectBlock(block, state, &index, view, true));
auto duration = timer_stop(tv_start);
// Undo alterations to global state
mapBlockIndex.erase(hashPrev);
SelectParamsFromCommandLine();
return duration;
}

View File

@@ -15,5 +15,6 @@ extern double benchmark_verify_equihash();
extern double benchmark_large_tx();
extern double benchmark_try_decrypt_notes(size_t nAddrs);
extern double benchmark_increment_note_witnesses(size_t nTxs);
extern double benchmark_connectblock_slow();
#endif