Wladimir J. van der Laan
8 years ago
5 changed files with 372 additions and 1 deletions
@ -0,0 +1,87 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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