Wladimir J. van der Laan
8 years ago
5 changed files with 372 additions and 1 deletions
@ -0,0 +1,87 @@ |
|||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "bench.h" |
||||||
|
#include "coins.h" |
||||||
|
#include "policy/policy.h" |
||||||
|
#include "wallet/crypter.h" |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
|
||||||
|
// FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp.
|
||||||
|
//
|
||||||
|
// 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<CMutableTransaction> |
||||||
|
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) |
||||||
|
{ |
||||||
|
std::vector<CMutableTransaction> 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 << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; |
||||||
|
dummyTransactions[0].vout[1].nValue = 50 * CENT; |
||||||
|
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; |
||||||
|
coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0); |
||||||
|
|
||||||
|
dummyTransactions[1].vout.resize(2); |
||||||
|
dummyTransactions[1].vout[0].nValue = 21 * CENT; |
||||||
|
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); |
||||||
|
dummyTransactions[1].vout[1].nValue = 22 * CENT; |
||||||
|
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); |
||||||
|
coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0); |
||||||
|
|
||||||
|
return dummyTransactions; |
||||||
|
} |
||||||
|
|
||||||
|
// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from
|
||||||
|
// laanwj, "replicating the actual usage patterns of the client is hard though,
|
||||||
|
// many times micro-benchmarks of the database showed completely different
|
||||||
|
// characteristics than e.g. reindex timings. But that's not a requirement of
|
||||||
|
// every benchmark."
|
||||||
|
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
|
||||||
|
static void CCoinsCaching(benchmark::State& state) |
||||||
|
{ |
||||||
|
CBasicKeyStore keystore; |
||||||
|
CCoinsView coinsDummy; |
||||||
|
CCoinsViewCache coins(&coinsDummy); |
||||||
|
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); |
||||||
|
|
||||||
|
CMutableTransaction 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; |
||||||
|
|
||||||
|
// Benchmark.
|
||||||
|
while (state.KeepRunning()) { |
||||||
|
bool success = AreInputsStandard(t1, coins); |
||||||
|
assert(success); |
||||||
|
CAmount value = coins.GetValueIn(t1); |
||||||
|
assert(value == (50 + 21 + 22) * CENT); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
BENCHMARK(CCoinsCaching); |
@ -0,0 +1,62 @@ |
|||||||
|
// Copyright (c) 2012-2015 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "bench.h" |
||||||
|
#include "wallet/wallet.h" |
||||||
|
|
||||||
|
#include <boost/foreach.hpp> |
||||||
|
#include <set> |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
|
||||||
|
static void addCoin(const CAmount& nValue, const CWallet& wallet, vector<COutput>& vCoins) |
||||||
|
{ |
||||||
|
int nInput = 0; |
||||||
|
|
||||||
|
static int nextLockTime = 0; |
||||||
|
CMutableTransaction 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); |
||||||
|
|
||||||
|
int nAge = 6 * 24; |
||||||
|
COutput output(wtx, nInput, nAge, true, true); |
||||||
|
vCoins.push_back(output); |
||||||
|
} |
||||||
|
|
||||||
|
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
|
||||||
|
// to build up more complicated scenarios in order to get meaningful
|
||||||
|
// measurements of performance. From laanwj, "Wallet coin selection is probably
|
||||||
|
// the hardest, as you need a wider selection of scenarios, just testing the
|
||||||
|
// same one over and over isn't too useful. Generating random isn't useful
|
||||||
|
// either for measurements."
|
||||||
|
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
|
||||||
|
static void CoinSelection(benchmark::State& state) |
||||||
|
{ |
||||||
|
const CWallet wallet; |
||||||
|
vector<COutput> vCoins; |
||||||
|
LOCK(wallet.cs_wallet); |
||||||
|
|
||||||
|
while (state.KeepRunning()) { |
||||||
|
// Empty wallet.
|
||||||
|
BOOST_FOREACH (COutput output, vCoins) |
||||||
|
delete output.tx; |
||||||
|
vCoins.clear(); |
||||||
|
|
||||||
|
// Add coins.
|
||||||
|
for (int i = 0; i < 1000; i++) |
||||||
|
addCoin(1000 * COIN, wallet, vCoins); |
||||||
|
addCoin(3 * COIN, wallet, vCoins); |
||||||
|
|
||||||
|
set<pair<const CWalletTx*, unsigned int> > setCoinsRet; |
||||||
|
CAmount nValueRet; |
||||||
|
bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet); |
||||||
|
assert(success); |
||||||
|
assert(nValueRet == 1003 * COIN); |
||||||
|
assert(setCoinsRet.size() == 2); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
BENCHMARK(CoinSelection); |
@ -0,0 +1,115 @@ |
|||||||
|
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "bench.h" |
||||||
|
#include "policy/policy.h" |
||||||
|
#include "txmempool.h" |
||||||
|
|
||||||
|
#include <list> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool) |
||||||
|
{ |
||||||
|
int64_t nTime = 0; |
||||||
|
double dPriority = 10.0; |
||||||
|
unsigned int nHeight = 1; |
||||||
|
bool spendsCoinbase = false; |
||||||
|
unsigned int sigOpCost = 4; |
||||||
|
LockPoints lp; |
||||||
|
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry( |
||||||
|
tx, nFee, nTime, dPriority, nHeight, pool.HasNoInputsOf(tx), |
||||||
|
tx.GetValueOut(), spendsCoinbase, sigOpCost, lp)); |
||||||
|
} |
||||||
|
|
||||||
|
// Right now this is only testing eviction performance in an extremely small
|
||||||
|
// mempool. Code needs to be written to generate a much wider variety of
|
||||||
|
// unique transactions for a more meaningful performance measurement.
|
||||||
|
static void MempoolEviction(benchmark::State& state) |
||||||
|
{ |
||||||
|
CMutableTransaction tx1 = CMutableTransaction(); |
||||||
|
tx1.vin.resize(1); |
||||||
|
tx1.vin[0].scriptSig = CScript() << OP_1; |
||||||
|
tx1.vout.resize(1); |
||||||
|
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; |
||||||
|
tx1.vout[0].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CMutableTransaction tx2 = CMutableTransaction(); |
||||||
|
tx2.vin.resize(1); |
||||||
|
tx2.vin[0].scriptSig = CScript() << OP_2; |
||||||
|
tx2.vout.resize(1); |
||||||
|
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; |
||||||
|
tx2.vout[0].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CMutableTransaction tx3 = CMutableTransaction(); |
||||||
|
tx3.vin.resize(1); |
||||||
|
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); |
||||||
|
tx3.vin[0].scriptSig = CScript() << OP_2; |
||||||
|
tx3.vout.resize(1); |
||||||
|
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; |
||||||
|
tx3.vout[0].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CMutableTransaction tx4 = CMutableTransaction(); |
||||||
|
tx4.vin.resize(2); |
||||||
|
tx4.vin[0].prevout.SetNull(); |
||||||
|
tx4.vin[0].scriptSig = CScript() << OP_4; |
||||||
|
tx4.vin[1].prevout.SetNull(); |
||||||
|
tx4.vin[1].scriptSig = CScript() << OP_4; |
||||||
|
tx4.vout.resize(2); |
||||||
|
tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL; |
||||||
|
tx4.vout[0].nValue = 10 * COIN; |
||||||
|
tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL; |
||||||
|
tx4.vout[1].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CMutableTransaction tx5 = CMutableTransaction(); |
||||||
|
tx5.vin.resize(2); |
||||||
|
tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0); |
||||||
|
tx5.vin[0].scriptSig = CScript() << OP_4; |
||||||
|
tx5.vin[1].prevout.SetNull(); |
||||||
|
tx5.vin[1].scriptSig = CScript() << OP_5; |
||||||
|
tx5.vout.resize(2); |
||||||
|
tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL; |
||||||
|
tx5.vout[0].nValue = 10 * COIN; |
||||||
|
tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL; |
||||||
|
tx5.vout[1].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CMutableTransaction tx6 = CMutableTransaction(); |
||||||
|
tx6.vin.resize(2); |
||||||
|
tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1); |
||||||
|
tx6.vin[0].scriptSig = CScript() << OP_4; |
||||||
|
tx6.vin[1].prevout.SetNull(); |
||||||
|
tx6.vin[1].scriptSig = CScript() << OP_6; |
||||||
|
tx6.vout.resize(2); |
||||||
|
tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL; |
||||||
|
tx6.vout[0].nValue = 10 * COIN; |
||||||
|
tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL; |
||||||
|
tx6.vout[1].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CMutableTransaction tx7 = CMutableTransaction(); |
||||||
|
tx7.vin.resize(2); |
||||||
|
tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0); |
||||||
|
tx7.vin[0].scriptSig = CScript() << OP_5; |
||||||
|
tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0); |
||||||
|
tx7.vin[1].scriptSig = CScript() << OP_6; |
||||||
|
tx7.vout.resize(2); |
||||||
|
tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; |
||||||
|
tx7.vout[0].nValue = 10 * COIN; |
||||||
|
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; |
||||||
|
tx7.vout[1].nValue = 10 * COIN; |
||||||
|
|
||||||
|
CTxMemPool pool(CFeeRate(1000)); |
||||||
|
|
||||||
|
while (state.KeepRunning()) { |
||||||
|
AddTx(tx1, 10000LL, pool); |
||||||
|
AddTx(tx2, 5000LL, pool); |
||||||
|
AddTx(tx3, 20000LL, pool); |
||||||
|
AddTx(tx4, 7000LL, pool); |
||||||
|
AddTx(tx5, 1000LL, pool); |
||||||
|
AddTx(tx6, 1100LL, pool); |
||||||
|
AddTx(tx7, 9000LL, pool); |
||||||
|
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); |
||||||
|
pool.TrimToSize(GetVirtualTransactionSize(tx1)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
BENCHMARK(MempoolEviction); |
@ -0,0 +1,103 @@ |
|||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "bench.h" |
||||||
|
#include "key.h" |
||||||
|
#if defined(HAVE_CONSENSUS_LIB) |
||||||
|
#include "script/bitcoinconsensus.h" |
||||||
|
#endif |
||||||
|
#include "script/script.h" |
||||||
|
#include "script/sign.h" |
||||||
|
#include "streams.h" |
||||||
|
|
||||||
|
// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
|
||||||
|
static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) |
||||||
|
{ |
||||||
|
CMutableTransaction txCredit; |
||||||
|
txCredit.nVersion = 1; |
||||||
|
txCredit.nLockTime = 0; |
||||||
|
txCredit.vin.resize(1); |
||||||
|
txCredit.vout.resize(1); |
||||||
|
txCredit.vin[0].prevout.SetNull(); |
||||||
|
txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); |
||||||
|
txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; |
||||||
|
txCredit.vout[0].scriptPubKey = scriptPubKey; |
||||||
|
txCredit.vout[0].nValue = 1; |
||||||
|
|
||||||
|
return txCredit; |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp.
|
||||||
|
static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit) |
||||||
|
{ |
||||||
|
CMutableTransaction txSpend; |
||||||
|
txSpend.nVersion = 1; |
||||||
|
txSpend.nLockTime = 0; |
||||||
|
txSpend.vin.resize(1); |
||||||
|
txSpend.vout.resize(1); |
||||||
|
txSpend.wit.vtxinwit.resize(1); |
||||||
|
txSpend.vin[0].prevout.hash = txCredit.GetHash(); |
||||||
|
txSpend.vin[0].prevout.n = 0; |
||||||
|
txSpend.vin[0].scriptSig = scriptSig; |
||||||
|
txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; |
||||||
|
txSpend.vout[0].scriptPubKey = CScript(); |
||||||
|
txSpend.vout[0].nValue = txCredit.vout[0].nValue; |
||||||
|
|
||||||
|
return txSpend; |
||||||
|
} |
||||||
|
|
||||||
|
// Microbenchmark for verification of a basic P2WPKH script. Can be easily
|
||||||
|
// modified to measure performance of other types of scripts.
|
||||||
|
static void VerifyScriptBench(benchmark::State& state) |
||||||
|
{ |
||||||
|
const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH; |
||||||
|
const int witnessversion = 0; |
||||||
|
|
||||||
|
// Keypair.
|
||||||
|
CKey key; |
||||||
|
const unsigned char vchKey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; |
||||||
|
key.Set(vchKey, vchKey + 32, false); |
||||||
|
CPubKey pubkey = key.GetPubKey(); |
||||||
|
uint160 pubkeyHash; |
||||||
|
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin()); |
||||||
|
|
||||||
|
// Script.
|
||||||
|
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash); |
||||||
|
CScript scriptSig; |
||||||
|
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG; |
||||||
|
CTransaction txCredit = BuildCreditingTransaction(scriptPubKey); |
||||||
|
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit); |
||||||
|
CScriptWitness& witness = txSpend.wit.vtxinwit[0].scriptWitness; |
||||||
|
witness.stack.emplace_back(); |
||||||
|
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0); |
||||||
|
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL)); |
||||||
|
witness.stack.push_back(ToByteVector(pubkey)); |
||||||
|
|
||||||
|
// Benchmark.
|
||||||
|
while (state.KeepRunning()) { |
||||||
|
ScriptError err; |
||||||
|
bool success = VerifyScript( |
||||||
|
txSpend.vin[0].scriptSig, |
||||||
|
txCredit.vout[0].scriptPubKey, |
||||||
|
&txSpend.wit.vtxinwit[0].scriptWitness, |
||||||
|
flags, |
||||||
|
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue), |
||||||
|
&err); |
||||||
|
assert(err == SCRIPT_ERR_OK); |
||||||
|
assert(success); |
||||||
|
|
||||||
|
#if defined(HAVE_CONSENSUS_LIB) |
||||||
|
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); |
||||||
|
stream << txSpend; |
||||||
|
int csuccess = bitcoinconsensus_verify_script_with_amount( |
||||||
|
begin_ptr(txCredit.vout[0].scriptPubKey), |
||||||
|
txCredit.vout[0].scriptPubKey.size(), |
||||||
|
txCredit.vout[0].nValue, |
||||||
|
(const unsigned char*)&stream[0], stream.size(), 0, flags, nullptr); |
||||||
|
assert(csuccess == 1); |
||||||
|
#endif |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
BENCHMARK(VerifyScriptBench); |
Loading…
Reference in new issue