Page MenuHomePhabricator

No OneTemporary

diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 6c84b5bb83..4d7730cc0b 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -1,271 +1,271 @@
// 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 <blockencodings.h>
#include <chainparams.h>
#include <config.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
#include <crypto/siphash.h>
#include <random.h>
#include <streams.h>
#include <txmempool.h>
#include <util.h>
#include <validation.h>
#include <unordered_map>
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock &block)
: nonce(GetRand(std::numeric_limits<uint64_t>::max())),
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
FillShortTxIDSelector();
// TODO: Use our mempool prior to block acceptance to predictively fill more
// than just the coinbase.
prefilledtxn[0] = {0, block.vtx[0]};
for (size_t i = 1; i < block.vtx.size(); i++) {
const CTransaction &tx = *block.vtx[i];
shorttxids[i - 1] = GetShortID(tx.GetHash());
}
}
void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << header << nonce;
CSHA256 hasher;
hasher.Write((uint8_t *)&(*stream.begin()), stream.end() - stream.begin());
uint256 shorttxidhash;
hasher.Finalize(shorttxidhash.begin());
shorttxidk0 = shorttxidhash.GetUint64(0);
shorttxidk1 = shorttxidhash.GetUint64(1);
}
uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256 &txhash) const {
static_assert(SHORTTXIDS_LENGTH == 6,
"shorttxids calculation assumes 6-byte shorttxids");
return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;
}
ReadStatus PartiallyDownloadedBlock::InitData(
const CBlockHeaderAndShortTxIDs &cmpctblock,
const std::vector<std::pair<uint256, CTransactionRef>> &extra_txns) {
if (cmpctblock.header.IsNull() ||
(cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) {
return READ_STATUS_INVALID;
}
if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() >
config->GetMaxBlockSize() / MIN_TRANSACTION_SIZE) {
return READ_STATUS_INVALID;
}
assert(header.IsNull() && txns_available.empty());
header = cmpctblock.header;
txns_available.resize(cmpctblock.BlockTxCount());
int64_t lastprefilledindex = -1;
for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) {
auto &prefilledtxn = cmpctblock.prefilledtxn[i];
if (prefilledtxn.tx->IsNull()) {
return READ_STATUS_INVALID;
}
// index is a uint32_t, so can't overflow here.
lastprefilledindex += prefilledtxn.index + 1;
if (lastprefilledindex > std::numeric_limits<uint32_t>::max()) {
return READ_STATUS_INVALID;
}
if (uint32_t(lastprefilledindex) > cmpctblock.shorttxids.size() + i) {
// If we are inserting a tx at an index greater than our full list
// of shorttxids plus the number of prefilled txn we've inserted,
// then we have txn for which we have neither a prefilled txn or a
// shorttxid!
return READ_STATUS_INVALID;
}
txns_available[lastprefilledindex] = prefilledtxn.tx;
}
prefilled_count = cmpctblock.prefilledtxn.size();
// Calculate map of txids -> positions and check mempool to see what we have
// (or don't). Because well-formed cmpctblock messages will have a
// (relatively) uniform distribution of short IDs, any highly-uneven
// distribution of elements can be safely treated as a READ_STATUS_FAILED.
std::unordered_map<uint64_t, uint32_t> shorttxids(
cmpctblock.shorttxids.size());
uint32_t index_offset = 0;
for (size_t i = 0; i < cmpctblock.shorttxids.size(); i++) {
while (txns_available[i + index_offset]) {
index_offset++;
}
shorttxids[cmpctblock.shorttxids[i]] = i + index_offset;
// To determine the chance that the number of entries in a bucket
// exceeds N, we use the fact that the number of elements in a single
// bucket is binomially distributed (with n = the number of shorttxids
// S, and p = 1 / the number of buckets), that in the worst case the
// number of buckets is equal to S (due to std::unordered_map having a
// default load factor of 1.0), and that the chance for any bucket to
// exceed N elements is at most buckets * (the chance that any given
// bucket is above N elements). Thus: P(max_elements_per_bucket > N) <=
// S * (1 - cdf(binomial(n=S,p=1/S), N)). If we assume blocks of up to
// 16000, allowing 12 elements per bucket should only fail once per ~1
// million block transfers (per peer and connection).
if (shorttxids.bucket_size(
shorttxids.bucket(cmpctblock.shorttxids[i])) > 12) {
return READ_STATUS_FAILED;
}
}
// TODO: in the shortid-collision case, we should instead request both
// transactions which collided. Falling back to full-block-request here is
// overkill.
if (shorttxids.size() != cmpctblock.shorttxids.size()) {
// Short ID collision
return READ_STATUS_FAILED;
}
std::vector<bool> have_txn(txns_available.size());
{
LOCK(pool->cs);
const std::vector<std::pair<uint256, CTxMemPool::txiter>> &vTxHashes =
pool->vTxHashes;
for (auto txHash : vTxHashes) {
uint64_t shortid = cmpctblock.GetShortID(txHash.first);
std::unordered_map<uint64_t, uint32_t>::iterator idit =
shorttxids.find(shortid);
if (idit != shorttxids.end()) {
if (!have_txn[idit->second]) {
txns_available[idit->second] = txHash.second->GetSharedTx();
have_txn[idit->second] = true;
mempool_count++;
} else {
// If we find two mempool txn that match the short id, just
// request it. This should be rare enough that the extra
// bandwidth doesn't matter, but eating a round-trip due to
// FillBlock failure would be annoying.
if (txns_available[idit->second]) {
txns_available[idit->second].reset();
mempool_count--;
}
}
}
// Though ideally we'd continue scanning for the
// two-txn-match-shortid case, the performance win of an early exit
// here is too good to pass up and worth the extra risk.
if (mempool_count == shorttxids.size()) {
break;
}
}
}
for (auto &extra_txn : extra_txns) {
uint64_t shortid = cmpctblock.GetShortID(extra_txn.first);
std::unordered_map<uint64_t, uint32_t>::iterator idit =
shorttxids.find(shortid);
if (idit != shorttxids.end()) {
if (!have_txn[idit->second]) {
txns_available[idit->second] = extra_txn.second;
have_txn[idit->second] = true;
mempool_count++;
extra_count++;
} else {
// If we find two mempool/extra txn that match the short id,
// just request it. This should be rare enough that the extra
// bandwidth doesn't matter, but eating a round-trip due to
// FillBlock failure would be annoying. Note that we don't want
// duplication between extra_txns and mempool to trigger this
// case, so we compare hashes first.
if (txns_available[idit->second] &&
txns_available[idit->second]->GetHash() !=
extra_txn.second->GetHash()) {
txns_available[idit->second].reset();
mempool_count--;
extra_count--;
}
}
}
// Though ideally we'd continue scanning for the two-txn-match-shortid
// case, the performance win of an early exit here is too good to pass
// up and worth the extra risk.
if (mempool_count == shorttxids.size()) {
break;
}
}
LogPrint(BCLog::CMPCTBLOCK,
"Initialized PartiallyDownloadedBlock for block %s using a "
"cmpctblock of size %lu\n",
cmpctblock.header.GetHash().ToString(),
GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));
return READ_STATUS_OK;
}
bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const {
assert(!header.IsNull());
assert(index < txns_available.size());
- return txns_available[index] ? true : false;
+ return txns_available[index] != nullptr;
}
ReadStatus PartiallyDownloadedBlock::FillBlock(
CBlock &block, const std::vector<CTransactionRef> &vtx_missing) {
assert(!header.IsNull());
uint256 hash = header.GetHash();
block = header;
block.vtx.resize(txns_available.size());
size_t tx_missing_offset = 0;
for (size_t i = 0; i < txns_available.size(); i++) {
auto &txn_available = txns_available[i];
if (!txn_available) {
if (vtx_missing.size() <= tx_missing_offset) {
return READ_STATUS_INVALID;
}
block.vtx[i] = vtx_missing[tx_missing_offset++];
} else {
block.vtx[i] = std::move(txn_available);
}
}
// Make sure we can't call FillBlock again.
header.SetNull();
txns_available.clear();
if (vtx_missing.size() != tx_missing_offset) {
return READ_STATUS_INVALID;
}
CValidationState state;
if (!CheckBlock(*config, block, state)) {
// TODO: We really want to just check merkle tree manually here, but
// that is expensive, and CheckBlock caches a block's "checked-status"
// (in the CBlock?). CBlock should be able to check its own merkle root
// and cache that check.
if (state.CorruptionPossible()) {
// Possible Short ID collision.
return READ_STATUS_FAILED;
}
return READ_STATUS_CHECKBLOCK_FAILED;
}
LogPrint(BCLog::CMPCTBLOCK,
"Successfully reconstructed block %s with %lu txn prefilled, %lu "
"txn from mempool (incl at least %lu from extra pool) and %lu txn "
"requested\n",
hash.ToString(), prefilled_count, mempool_count, extra_count,
vtx_missing.size());
if (vtx_missing.size() < 5) {
for (const auto &tx : vtx_missing) {
LogPrint(BCLog::CMPCTBLOCK,
"Reconstructed block %s required tx %s\n", hash.ToString(),
tx->GetId().ToString());
}
}
return READ_STATUS_OK;
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 0f7567857e..2cef26fbcf 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -1,730 +1,730 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-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 <base58.h>
#include <chain.h>
#include <clientversion.h>
#include <config.h>
#include <dstencode.h>
#include <init.h>
#include <net.h>
#include <netbase.h>
#include <rpc/blockchain.h>
#include <rpc/misc.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <timedata.h>
#include <util.h>
#include <utilstrencodings.h>
#include <validation.h>
#ifdef ENABLE_WALLET
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
#endif
#include <warnings.h>
#include <univalue.h>
#include <cstdint>
#ifdef HAVE_MALLOC_INFO
#include <malloc.h>
#endif
/**
* @note Do not add or change anything in the information returned by this
* method. `getinfo` exists for backwards-compatibility only. It combines
* information from wildly different sources in the program, which is a mess,
* and is thus planned to be deprecated eventually.
*
* Based on the source of the information, new information should be added to:
* - `getblockchaininfo`,
* - `getnetworkinfo` or
* - `getwalletinfo`
*
* Or alternatively, create a specific query method for the information.
**/
static UniValue getinfo(const Config &config, const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
"getinfo\n"
"\nDEPRECATED. Returns an object containing various state info.\n"
"\nResult:\n"
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
" \"balance\": xxxxxxx, (numeric) the total bitcoin "
"balance of the wallet\n"
" \"blocks\": xxxxxx, (numeric) the current number of "
"blocks processed in the server\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of "
"connections\n"
" \"proxy\": \"host:port\", (string, optional) the proxy used "
"by the server\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"testnet\": true|false, (boolean) if the server is using "
"testnet or not\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds "
"since Unix epoch) of the oldest pre-generated key in the key "
"pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are "
"pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in "
"seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is "
"unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set "
"in " +
CURRENCY_UNIT +
"/kB\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for "
"non-free transactions in " +
CURRENCY_UNIT +
"/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", ""));
}
#ifdef ENABLE_WALLET
CWallet *const pwallet = GetWalletForJSONRPCRequest(request);
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
proxyType proxy;
GetProxy(NET_IPV4, proxy);
UniValue obj(UniValue::VOBJ);
obj.pushKV("version", CLIENT_VERSION);
obj.pushKV("protocolversion", PROTOCOL_VERSION);
#ifdef ENABLE_WALLET
if (pwallet) {
obj.pushKV("walletversion", pwallet->GetVersion());
obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance()));
}
#endif
obj.pushKV("blocks", (int)chainActive.Height());
obj.pushKV("timeoffset", GetTimeOffset());
if (g_connman) {
obj.pushKV("connections",
(int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
}
obj.pushKV("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort()
: std::string()));
obj.pushKV("difficulty", double(GetDifficulty(chainActive.Tip())));
obj.pushKV("testnet", config.GetChainParams().NetworkIDString() ==
CBaseChainParams::TESTNET);
#ifdef ENABLE_WALLET
if (pwallet) {
obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
obj.pushKV("keypoolsize", (int)pwallet->GetKeyPoolSize());
}
if (pwallet && pwallet->IsCrypted()) {
obj.pushKV("unlocked_until", pwallet->nRelockTime);
}
obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()));
#endif
obj.pushKV("relayfee",
ValueFromAmount(config.GetMinFeePerKB().GetFeePerK()));
obj.pushKV("errors", GetWarnings("statusbar"));
return obj;
}
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<UniValue> {
public:
CWallet *const pwallet;
explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
void ProcessSubScript(const CScript &subscript, UniValue &obj,
bool include_addresses = false) const {
// Always present: script type and redeemscript
txnouttype which_type;
std::vector<std::vector<unsigned char>> solutions_data;
Solver(subscript, which_type, solutions_data);
obj.pushKV("script", GetTxnOutputType(which_type));
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
CTxDestination embedded;
UniValue a(UniValue::VARR);
if (ExtractDestination(subscript, embedded)) {
// Only when the script corresponds to an address.
UniValue subobj = boost::apply_visitor(*this, embedded);
subobj.pushKV("address", EncodeDestination(embedded));
subobj.pushKV("scriptPubKey",
HexStr(subscript.begin(), subscript.end()));
// Always report the pubkey at the top level, so that
// `getnewaddress()['pubkey']` always works.
if (subobj.exists("pubkey")) {
obj.pushKV("pubkey", subobj["pubkey"]);
}
obj.pushKV("embedded", std::move(subobj));
if (include_addresses) {
a.push_back(EncodeDestination(embedded));
}
} else if (which_type == TX_MULTISIG) {
// Also report some information on multisig scripts (which do not
// have a corresponding address).
// TODO: abstract out the common functionality between this logic
// and ExtractDestinations.
obj.pushKV("sigsrequired", solutions_data[0][0]);
UniValue pubkeys(UniValue::VARR);
for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
if (include_addresses) {
a.push_back(EncodeDestination(key.GetID()));
}
pubkeys.push_back(HexStr(key.begin(), key.end()));
}
obj.pushKV("pubkeys", std::move(pubkeys));
}
// The "addresses" field is confusing because it refers to public keys
// using their P2PKH address. For that reason, only add the 'addresses'
// field when needed for backward compatibility. New applications can
// use the 'pubkeys' field for inspecting multisig participants.
if (include_addresses) {
obj.pushKV("addresses", std::move(a));
}
}
UniValue operator()(const CNoDestination &dest) const {
return UniValue(UniValue::VOBJ);
}
UniValue operator()(const CKeyID &keyID) const {
UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.pushKV("isscript", false);
if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
obj.pushKV("pubkey", HexStr(vchPubKey));
obj.pushKV("iscompressed", vchPubKey.IsCompressed());
}
return obj;
}
UniValue operator()(const CScriptID &scriptID) const {
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.pushKV("isscript", true);
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
ProcessSubScript(subscript, obj, true);
}
return obj;
}
};
#endif
static UniValue validateaddress(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"validateaddress \"address\"\n"
"\nReturn information about the given bitcoin address.\n"
"\nArguments:\n"
"1. \"address\" (string, required) The bitcoin address to "
"validate\n"
"\nResult:\n"
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is "
"valid or not. If not, this is the only property returned.\n"
" \"address\" : \"address\", (string) The bitcoin address "
"validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded "
"scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is "
"yours or not\n"
" \"iswatchonly\" : true|false, (boolean) If the address is "
"watchonly\n"
" \"isscript\" : true|false, (boolean, optional) If the key "
"is a script.\n"
" \"script\" : \"type\" (string, optional) The output "
"script type. Only if \"isscript\" is true and the redeemscript is "
"known. Possible types: nonstandard, pubkey, pubkeyhash, "
"scripthash, multisig, nulldata\n"
" \"hex\" : \"hex\", (string, optional) The "
"redeemscript for the P2SH address\n"
" \"pubkeys\" (string, optional) Array of "
"pubkeys associated with the known redeemscript (only if "
"\"script\" is \"multisig\")\n"
" [\n"
" \"pubkey\"\n"
" ,...\n"
" ]\n"
" \"sigsrequired\" : xxxxx (numeric, optional) Number of "
"signatures required to spend multisig output (only if \"script\" "
"is \"multisig\")\n"
" \"pubkey\" : \"publickeyhex\", (string, optional) The hex "
"value of the raw public key, for single-key addresses (possibly "
"embedded in P2SH)\n"
" \"embedded\" : {...}, (object, optional) information "
"about the address embedded in P2SH, if relevant and known. It "
"includes all validateaddress output fields for the embedded "
"address, excluding \"isvalid\", metadata (\"timestamp\", "
"\"hdkeypath\", \"hdmasterkeyid\") and relation to the wallet "
"(\"ismine\", \"iswatchonly\", \"account\").\n"
" \"iscompressed\" : true|false, (boolean) If the address is "
"compressed\n"
" \"account\" : \"account\" (string) DEPRECATED. The "
"account associated with the address, \"\" is the default account\n"
" \"timestamp\" : timestamp, (number, optional) The "
"creation time of the key if available in seconds since epoch (Jan "
"1 1970 GMT)\n"
" \"hdkeypath\" : \"keypath\" (string, optional) The HD "
"keypath if the key is HD and available\n"
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The "
"Hash160 of the HD master pubkey\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("validateaddress",
"\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") +
HelpExampleRpc("validateaddress",
"\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\""));
}
#ifdef ENABLE_WALLET
CWallet *const pwallet = GetWalletForJSONRPCRequest(request);
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
CTxDestination dest =
DecodeDestination(request.params[0].get_str(), config.GetChainParams());
bool isValid = IsValidDestination(dest);
UniValue ret(UniValue::VOBJ);
ret.pushKV("isvalid", isValid);
if (isValid) {
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
CScript scriptPubKey = GetScriptForDestination(dest);
ret.pushKV("scriptPubKey",
HexStr(scriptPubKey.begin(), scriptPubKey.end()));
#ifdef ENABLE_WALLET
isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO;
- ret.pushKV("ismine", (mine & ISMINE_SPENDABLE) ? true : false);
- ret.pushKV("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true : false);
+ ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
+ ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
UniValue detail =
boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);
ret.pushKVs(detail);
if (pwallet && pwallet->mapAddressBook.count(dest)) {
ret.pushKV("account", pwallet->mapAddressBook[dest].name);
}
if (pwallet) {
const CKeyMetadata *meta = nullptr;
CKeyID key_id = GetKeyForDestination(*pwallet, dest);
if (!key_id.IsNull()) {
auto it = pwallet->mapKeyMetadata.find(key_id);
if (it != pwallet->mapKeyMetadata.end()) {
meta = &it->second;
}
}
if (!meta) {
auto it =
pwallet->m_script_metadata.find(CScriptID(scriptPubKey));
if (it != pwallet->m_script_metadata.end()) {
meta = &it->second;
}
}
if (meta) {
ret.pushKV("timestamp", meta->nCreateTime);
if (!meta->hdKeypath.empty()) {
ret.pushKV("hdkeypath", meta->hdKeypath);
ret.pushKV("hdmasterkeyid", meta->hdMasterKeyID.GetHex());
}
}
}
#endif
}
return ret;
}
// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
class CWallet;
static UniValue createmultisig(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() < 2 ||
request.params.size() > 2) {
std::string msg =
"createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys "
"required.\n"
"It returns a json object with the address and redeemScript.\n"
"DEPRECATION WARNING: Using addresses with createmultisig is "
"deprecated. Clients must\n"
"transition to using addmultisigaddress to create multisig "
"addresses with addresses known\n"
"to the wallet before upgrading to v0.20. To use the deprecated "
"functionality, start bitcoind with -deprecatedrpc=createmultisig\n"
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required "
"signatures out of the n keys or addresses.\n"
"2. \"keys\" (string, required) A json array of hex-encoded "
"public keys\n"
" [\n"
" \"key\" (string) The hex-encoded public key\n"
" ,...\n"
" ]\n"
"\nResult:\n"
"{\n"
" \"address\":\"multisigaddress\", (string) The value of the new "
"multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of "
"the hex-encoded redemption script.\n"
"}\n"
"\nExamples:\n"
"\nCreate a multisig address from 2 public keys\n" +
HelpExampleCli("createmultisig",
"2 "
"\"["
"\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3"
"42cf11ae157a7ace5fd\\\","
"\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1"
"7e107ef3f6aa5a61626\\\"]\"") +
"\nAs a json rpc call\n" +
HelpExampleRpc("createmultisig",
"2, "
"\"["
"\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3"
"42cf11ae157a7ace5fd\\\","
"\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1"
"7e107ef3f6aa5a61626\\\"]\"");
throw std::runtime_error(msg);
}
int required = request.params[0].get_int();
// Get the public keys
const UniValue &keys = request.params[1].get_array();
std::vector<CPubKey> pubkeys;
for (size_t i = 0; i < keys.size(); ++i) {
if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 ||
keys[i].get_str().length() == 130)) {
pubkeys.push_back(HexToPubKey(keys[i].get_str()));
} else {
#ifdef ENABLE_WALLET
CWallet *const pwallet = GetWalletForJSONRPCRequest(request);
if (IsDeprecatedRPCEnabled(gArgs, "createmultisig") &&
EnsureWalletIsAvailable(pwallet, false)) {
pubkeys.push_back(AddrToPubKey(config.GetChainParams(), pwallet,
keys[i].get_str()));
} else
#endif
throw JSONRPCError(
RPC_INVALID_ADDRESS_OR_KEY,
strprintf("Invalid public key: %s\nNote that from v0.19.6, "
"createmultisig no longer accepts addresses."
" Clients must transition to using "
"addmultisigaddress to create multisig addresses "
"with addresses known to the wallet before "
"upgrading to v0.20."
" To use the deprecated functionality, start "
"bitcoind with -deprecatedrpc=createmultisig",
keys[i].get_str()));
}
}
// Construct using pay-to-script-hash:
CScript inner = CreateMultisigRedeemscript(required, pubkeys);
CScriptID innerID(inner);
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(innerID));
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
return result;
}
static UniValue verifymessage(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 3) {
throw std::runtime_error(
"verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
"1. \"address\" (string, required) The bitcoin address to "
"use for the signature.\n"
"2. \"signature\" (string, required) The signature provided "
"by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was "
"signed.\n"
"\nResult:\n"
"true|false (boolean) If the signature is verified or not.\n"
"\nExamples:\n"
"\nUnlock the wallet for 30 seconds\n" +
HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n" +
HelpExampleCli(
"signmessage",
"\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n" +
HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4"
"XX\" \"signature\" \"my "
"message\"") +
"\nAs json rpc\n" +
HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4"
"XX\", \"signature\", \"my "
"message\""));
}
LOCK(cs_main);
std::string strAddress = request.params[0].get_str();
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
CTxDestination destination =
DecodeDestination(strAddress, config.GetChainParams());
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
const CKeyID *keyID = boost::get<CKeyID>(&destination);
if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
bool fInvalid = false;
std::vector<uint8_t> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
if (fInvalid) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
"Malformed base64 encoding");
}
CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
CPubKey pubkey;
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) {
return false;
}
return (pubkey.GetID() == *keyID);
}
static UniValue signmessagewithprivkey(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
"\nArguments:\n"
"1. \"privkey\" (string, required) The private key to sign "
"the message with.\n"
"2. \"message\" (string, required) The message to create a "
"signature of.\n"
"\nResult:\n"
"\"signature\" (string) The signature of the message "
"encoded in base 64\n"
"\nExamples:\n"
"\nCreate the signature\n" +
HelpExampleCli("signmessagewithprivkey",
"\"privkey\" \"my message\"") +
"\nVerify the signature\n" +
HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4"
"XX\" \"signature\" \"my "
"message\"") +
"\nAs json rpc\n" +
HelpExampleRpc("signmessagewithprivkey",
"\"privkey\", \"my message\""));
}
std::string strPrivkey = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strPrivkey);
if (!fGood) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
}
CKey key = vchSecret.GetKey();
if (!key.IsValid()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
"Private key outside allowed range");
}
CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
std::vector<uint8_t> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
}
return EncodeBase64(&vchSig[0], vchSig.size());
}
static UniValue setmocktime(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
"1. timestamp (integer, required) Unix seconds-since-epoch "
"timestamp\n"
" Pass 0 to go back to using the system time.");
}
if (!config.GetChainParams().MineBlocksOnDemand()) {
throw std::runtime_error(
"setmocktime for regression testing (-regtest mode) only");
}
// For now, don't change mocktime if we're in the middle of validation, as
// this could have an effect on mempool time-based eviction, as well as
// IsInitialBlockDownload().
// TODO: figure out the right way to synchronize around mocktime, and
// ensure all call sites of GetTime() are accessing this safely.
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VNUM});
SetMockTime(request.params[0].get_int64());
return NullUniValue;
}
static UniValue RPCLockedMemoryInfo() {
LockedPool::Stats stats = LockedPoolManager::Instance().stats();
UniValue obj(UniValue::VOBJ);
obj.pushKV("used", uint64_t(stats.used));
obj.pushKV("free", uint64_t(stats.free));
obj.pushKV("total", uint64_t(stats.total));
obj.pushKV("locked", uint64_t(stats.locked));
obj.pushKV("chunks_used", uint64_t(stats.chunks_used));
obj.pushKV("chunks_free", uint64_t(stats.chunks_free));
return obj;
}
#ifdef HAVE_MALLOC_INFO
static std::string RPCMallocInfo() {
char *ptr = nullptr;
size_t size = 0;
FILE *f = open_memstream(&ptr, &size);
if (f) {
malloc_info(0, f);
fclose(f);
if (ptr) {
std::string rv(ptr, size);
free(ptr);
return rv;
}
}
return "";
}
#endif
static UniValue getmemoryinfo(const Config &config,
const JSONRPCRequest &request) {
/* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other "memory pool"
*/
if (request.fHelp || request.params.size() > 1) {
throw std::runtime_error(
"getmemoryinfo (\"mode\")\n"
"Returns an object containing information about memory usage.\n"
"Arguments:\n"
"1. \"mode\" determines what kind of information is returned. This "
"argument is optional, the default mode is \"stats\".\n"
" - \"stats\" returns general statistics about memory usage in "
"the daemon.\n"
" - \"mallocinfo\" returns an XML string describing low-level "
"heap state (only available if compiled with glibc 2.10+).\n"
"\nResult (mode \"stats\"):\n"
"{\n"
" \"locked\": { (json object) Information about "
"locked memory manager\n"
" \"used\": xxxxx, (numeric) Number of bytes used\n"
" \"free\": xxxxx, (numeric) Number of bytes available "
"in current arenas\n"
" \"total\": xxxxxxx, (numeric) Total number of bytes "
"managed\n"
" \"locked\": xxxxxx, (numeric) Amount of bytes that "
"succeeded locking. If this number is smaller than total, locking "
"pages failed at some point and key data could be swapped to "
"disk.\n"
" \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n"
" \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
" }\n"
"}\n"
"\nResult (mode \"mallocinfo\"):\n"
"\"<malloc version=\"1\">...\"\n"
"\nExamples:\n" +
HelpExampleCli("getmemoryinfo", "") +
HelpExampleRpc("getmemoryinfo", ""));
}
std::string mode = (request.params.size() < 1 || request.params[0].isNull())
? "stats"
: request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ);
obj.pushKV("locked", RPCLockedMemoryInfo());
return obj;
} else if (mode == "mallocinfo") {
#ifdef HAVE_MALLOC_INFO
return RPCMallocInfo();
#else
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"mallocinfo is only available when compiled with glibc 2.10+");
#endif
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode);
}
}
static UniValue echo(const Config &config, const JSONRPCRequest &request) {
if (request.fHelp) {
throw std::runtime_error(
"echo|echojson \"message\" ...\n"
"\nSimply echo back the input arguments. This command is for "
"testing.\n"
"\nThe difference between echo and echojson is that echojson has "
"argument conversion enabled in the client-side table in"
"bitcoin-cli and the GUI. There is no server-side difference.");
}
return request.params;
}
// clang-format off
static const ContextFreeRPCCommand commands[] = {
// category name actor (function) argNames
// ------------------- ------------------------ ---------------------- ----------
{ "control", "getinfo", getinfo, {} }, /* uses wallet if enabled */
{ "control", "getmemoryinfo", getmemoryinfo, {"mode"} },
{ "util", "validateaddress", validateaddress, {"address"} }, /* uses wallet if enabled */
{ "util", "createmultisig", createmultisig, {"nrequired","keys"} },
{ "util", "verifymessage", verifymessage, {"address","signature","message"} },
{ "util", "signmessagewithprivkey", signmessagewithprivkey, {"privkey","message"} },
/* Not shown in help */
{ "hidden", "setmocktime", setmocktime, {"timestamp"}},
{ "hidden", "echo", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
{ "hidden", "echojson", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
};
// clang-format on
void RegisterMiscRPCCommands(CRPCTable &t) {
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 60af69ec64..ae58952fac 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -1,773 +1,773 @@
// Copyright (c) 2011-2016 The Bitcoin Core developers
// Copyright (c) 2017-2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <miner.h>
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
#include <config.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <policy/policy.h>
#include <pubkey.h>
#include <script/standard.h>
#include <txmempool.h>
#include <uint256.h>
#include <util.h>
#include <utilstrencodings.h>
#include <validation.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <memory>
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB);
static struct {
uint8_t extranonce;
uint32_t nonce;
} blockinfo[] = {
{4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5},
{2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84},
{2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4},
{2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa},
{1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb},
{3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406},
{2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38},
{2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9},
{1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7},
{2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34},
{1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c},
{1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f},
{1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81},
{1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78},
{1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c},
{2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049},
{2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169},
{1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10},
{1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d},
{2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323},
{1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6},
{1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408},
{1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602},
{0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459},
{2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668},
{1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce},
{2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e},
{2, 0xbbbeb305}, {2, 0xfe1c810a},
};
CBlockIndex CreateBlockIndex(int nHeight) {
CBlockIndex index;
index.nHeight = nHeight;
index.pprev = chainActive.Tip();
return index;
}
bool TestSequenceLocks(const CTransaction &tx, int flags) {
LOCK(g_mempool.cs);
return CheckSequenceLocks(tx, flags);
}
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case, to
// allow reusing the blockchain created in CreateNewBlock_validity.
// Note that this test assumes blockprioritypercentage is 0.
void TestPackageSelection(Config &config, CScript scriptPubKey,
std::vector<CTransactionRef> &txFirst) {
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
// these 3 tests assume blockprioritypercentage is 0.
config.SetBlockPriorityPercentage(0);
// Test that a medium fee transaction will be selected after a higher fee
// rate package with a low fee rate parent.
CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout.resize(1);
tx.vout[0].nValue = int64_t(5000000000LL - 1000) * SATOSHI;
// This tx has a low fee: 1000 satoshis.
// Save this txid for later use.
TxId parentTxId = tx.GetId();
g_mempool.addUnchecked(parentTxId, entry.Fee(1000 * SATOSHI)
.Time(GetTime())
.SpendsCoinbase(true)
.FromTx(tx));
// This tx has a medium fee: 10000 satoshis.
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
tx.vout[0].nValue = int64_t(5000000000LL - 10000) * SATOSHI;
TxId mediumFeeTxId = tx.GetId();
g_mempool.addUnchecked(mediumFeeTxId, entry.Fee(10000 * SATOSHI)
.Time(GetTime())
.SpendsCoinbase(true)
.FromTx(tx));
// This tx has a high fee, but depends on the first transaction.
tx.vin[0].prevout = COutPoint(parentTxId, 0);
// 50k satoshi fee.
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
TxId highFeeTxId = tx.GetId();
g_mempool.addUnchecked(highFeeTxId, entry.Fee(50000 * SATOSHI)
.Time(GetTime())
.SpendsCoinbase(false)
.FromTx(tx));
std::unique_ptr<CBlockTemplate> pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId);
BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId);
// Test that a package below the block min tx fee doesn't get included
tx.vin[0].prevout = COutPoint(highFeeTxId, 0);
// 0 fee.
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
TxId freeTxId = tx.GetId();
g_mempool.addUnchecked(freeTxId, entry.Fee(Amount::zero()).FromTx(tx));
size_t freeTxSize = CTransaction(tx).GetBillableSize();
// Calculate a fee on child transaction that will put the package just
// below the block min tx fee (assuming 1 child tx of the same size).
Amount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - SATOSHI;
tx.vin[0].prevout = COutPoint(freeTxId, 0);
tx.vout[0].nValue =
int64_t(5000000000LL - 1000 - 50000) * SATOSHI - feeToUse;
TxId lowFeeTxId = tx.GetId();
g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected.
for (const auto &txn : pblocktemplate->block.vtx) {
BOOST_CHECK(txn->GetId() != freeTxId);
BOOST_CHECK(txn->GetId() != lowFeeTxId);
}
// Test that packages above the min relay fee do get included, even if one
// of the transactions is below the min relay fee. Remove the low fee
// transaction and replace with a higher fee transaction
g_mempool.removeRecursive(CTransaction(tx));
// Now we should be just over the min relay fee.
tx.vout[0].nValue -= 2 * SATOSHI;
lowFeeTxId = tx.GetId();
g_mempool.addUnchecked(lowFeeTxId,
entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId);
// Test that transaction selection properly updates ancestor fee
// calculations as ancestor transactions get included in a block. Add a
// 0-fee transaction that has 2 outputs.
tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0);
tx.vout.resize(2);
tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI;
// 1BCC output.
tx.vout[1].nValue = 100000000 * SATOSHI;
TxId freeTxId2 = tx.GetId();
g_mempool.addUnchecked(
freeTxId2, entry.Fee(Amount::zero()).SpendsCoinbase(true).FromTx(tx));
// This tx can't be mined by itself.
tx.vin[0].prevout = COutPoint(freeTxId2, 0);
tx.vout.resize(1);
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI - feeToUse;
TxId lowFeeTxId2 = tx.GetId();
g_mempool.addUnchecked(
lowFeeTxId2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
// Verify that this tx isn't selected.
for (const auto &txn : pblocktemplate->block.vtx) {
BOOST_CHECK(txn->GetId() != freeTxId2);
BOOST_CHECK(txn->GetId() != lowFeeTxId2);
}
// This tx will be mineable, and should cause lowFeeTxId2 to be selected as
// well.
tx.vin[0].prevout = COutPoint(freeTxId2, 1);
// 10k satoshi fee.
tx.vout[0].nValue = (100000000 - 10000) * SATOSHI;
g_mempool.addUnchecked(tx.GetId(), entry.Fee(10000 * SATOSHI).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2);
}
void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg) {
GlobalConfig config;
config.SetMaxBlockSize(eb);
CScript scriptPubKey =
CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
"a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
"de5c384df7ba0b8d578a4c702b6bf11d5f")
<< OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
CBlock *pblock = &pblocktemplate->block;
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
IncrementExtraNonce(config, pblock, chainActive.Tip(), extraNonce);
unsigned int nHeight = chainActive.Tip()->nHeight + 1;
std::vector<uint8_t> vec(cbmsg.begin(), cbmsg.end());
BOOST_CHECK(pblock->vtx[0]->vin[0].scriptSig ==
((CScript() << nHeight << CScriptNum(extraNonce) << vec) +
COINBASE_FLAGS));
}
// Coinbase scriptSig has to contains the correct EB value
// converted to MB, rounded down to the first decimal
BOOST_AUTO_TEST_CASE(CheckCoinbase_EB) {
TestCoinbaseMessageEB(1000001, "/EB1.0/");
TestCoinbaseMessageEB(2000000, "/EB2.0/");
TestCoinbaseMessageEB(8000000, "/EB8.0/");
TestCoinbaseMessageEB(8320000, "/EB8.3/");
}
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) {
// Note that by default, these tests run with size accounting enabled.
CScript scriptPubKey =
CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
"a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
"de5c384df7ba0b8d578a4c702b6bf11d5f")
<< OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx, tx2;
CScript script;
uint256 hash;
TestMemPoolEntryHelper entry;
entry.nFee = 11 * SATOSHI;
entry.dPriority = 111.0;
entry.nHeight = 11;
fCheckpointsEnabled = false;
GlobalConfig config;
// Simple block creation, nothing special yet:
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
// We can't make transactions until we have inputs. Therefore, load 100
// blocks :)
int baseheight = 0;
std::vector<CTransactionRef> txFirst;
for (size_t i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) {
// pointer for convenience.
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast() + 1;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
txCoinbase.vout.resize(1);
txCoinbase.vout[0].scriptPubKey = CScript();
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
if (txFirst.size() == 0) {
baseheight = chainActive.Height();
}
if (txFirst.size() < 4) {
txFirst.push_back(pblock->vtx[0]);
}
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
}
std::shared_ptr<const CBlock> shared_pblock =
std::make_shared<const CBlock>(*pblock);
BOOST_CHECK(ProcessNewBlock(config, shared_pblock, true, nullptr));
pblock->hashPrevBlock = pblock->GetHash();
}
LOCK(cs_main);
// Just to make sure we can still make simple blocks.
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
const Amount BLOCKSUBSIDY = 50 * COIN;
const Amount LOWFEE = CENT;
const Amount HIGHFEE = COIN;
const Amount HIGHERFEE = 4 * COIN;
// block sigops > limit: 1000 CHECKMULTISIG + 1
tx.vin.resize(1);
// NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP
<< OP_CHECKMULTISIG << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout.resize(1);
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i) {
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
// Only first tx spends coinbase.
- bool spendsCoinbase = (i == 0) ? true : false;
+ bool spendsCoinbase = i == 0;
// If we don't set the # of sig ops in the CTxMemPoolEntry, template
// creation fails.
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE)
.Time(GetTime())
.SpendsCoinbase(spendsCoinbase)
.FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
}
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i) {
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
// Only first tx spends coinbase.
- bool spendsCoinbase = (i == 0) ? true : false;
+ bool spendsCoinbase = i == 0;
// If we do set the # of sig ops in the CTxMemPoolEntry, template
// creation passes.
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE)
.Time(GetTime())
.SpendsCoinbase(spendsCoinbase)
.SigOpsCost(80)
.FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
g_mempool.clear();
// block size > limit
tx.vin[0].scriptSig = CScript();
// 18 * (520char + DROP) + OP_1 = 9433 bytes
std::vector<uint8_t> vchData(520);
for (unsigned int i = 0; i < 18; ++i) {
tx.vin[0].scriptSig << vchData << OP_DROP;
}
tx.vin[0].scriptSig << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 128; ++i) {
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
// Only first tx spends coinbase.
- bool spendsCoinbase = (i == 0) ? true : false;
+ bool spendsCoinbase = i == 0;
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE)
.Time(GetTime())
.SpendsCoinbase(spendsCoinbase)
.FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
g_mempool.clear();
// Orphan in mempool, template creation fails.
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
// Child with higher priority than parent.
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
tx.vin.resize(2);
tx.vin[1].scriptSig = CScript() << OP_1;
tx.vin[1].prevout = COutPoint(txFirst[0]->GetId(), 0);
// First txn output + fresh coinbase - new txn fee.
tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
g_mempool.clear();
// Coinbase in mempool, template creation fails.
tx.vin.resize(1);
tx.vin[0].prevout = COutPoint();
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
tx.vout[0].nValue = Amount::zero();
hash = tx.GetId();
// Give it a fee so it'll get mined.
g_mempool.addUnchecked(
hash,
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
// Invalid (pre-p2sh) txn in mempool, template creation fails.
std::array<int64_t, CBlockIndex::nMedianTimeSpan> times;
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Trick the MedianTimePast.
times[i] = chainActive.Tip()
->GetAncestor(chainActive.Tip()->nHeight - i)
->nTime;
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime =
P2SH_ACTIVATION_TIME;
}
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE;
script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
tx.vin[0].scriptSig = CScript()
<< std::vector<uint8_t>(script.begin(), script.end());
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Restore the MedianTimePast.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime =
times[i];
}
// Double spend txn pair in mempool, template creation fails.
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
tx.vout[0].scriptPubKey = CScript() << OP_1;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
// Subsidy changing.
int nHeight = chainActive.Height();
// Create an actual 209999-long block chain (without valid blocks).
while (chainActive.Tip()->nHeight < 209999) {
CBlockIndex *prev = chainActive.Tip();
CBlockIndex *next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
chainActive.SetTip(next);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
while (chainActive.Tip()->nHeight < 210000) {
CBlockIndex *prev = chainActive.Tip();
CBlockIndex *next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
chainActive.SetTip(next);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex *del = chainActive.Tip();
chainActive.SetTip(del->pprev);
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del;
}
// non-final txs in mempool
SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
uint32_t flags = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST;
// height map
std::vector<int> prevheights;
// Relative height locked.
tx.nVersion = 2;
tx.vin.resize(1);
prevheights.resize(1);
// Only 1 transaction.
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
// txFirst[0] is the 2nd block
tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1;
prevheights[0] = baseheight + 1;
tx.vout.resize(1);
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
tx.vout[0].scriptPubKey = CScript() << OP_1;
tx.nLockTime = 0;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
{
// Locktime passes.
CValidationState state;
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
}
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
// Sequence locks pass on 2nd block.
BOOST_CHECK(
SequenceLocks(CTransaction(tx), flags, &prevheights,
CreateBlockIndex(chainActive.Tip()->nHeight + 2)));
// Relative time locked.
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
// txFirst[1] is the 3rd block.
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG |
(((chainActive.Tip()->GetMedianTimePast() + 1 -
chainActive[1]->GetMedianTimePast()) >>
CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) +
1);
prevheights[0] = baseheight + 2;
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
{
// Locktime passes.
CValidationState state;
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
}
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Trick the MedianTimePast.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime +=
512;
}
// Sequence locks pass 512 seconds later.
BOOST_CHECK(
SequenceLocks(CTransaction(tx), flags, &prevheights,
CreateBlockIndex(chainActive.Tip()->nHeight + 1)));
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Undo tricked MTP.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -=
512;
}
// Absolute height locked.
tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0);
tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1;
prevheights[0] = baseheight + 3;
tx.nLockTime = chainActive.Tip()->nHeight + 1;
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
{
// Locktime fails.
CValidationState state;
BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
}
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
{
// Locktime passes on 2nd block.
CValidationState state;
int64_t nMedianTimePast = chainActive.Tip()->GetMedianTimePast();
BOOST_CHECK(ContextualCheckTransaction(
config, CTransaction(tx), state, chainActive.Tip()->nHeight + 2,
nMedianTimePast, nMedianTimePast));
}
// Absolute time locked.
tx.vin[0].prevout = COutPoint(txFirst[3]->GetId(), 0);
tx.nLockTime = chainActive.Tip()->GetMedianTimePast();
prevheights.resize(1);
prevheights[0] = baseheight + 4;
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
{
// Locktime fails.
CValidationState state;
BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
}
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
{
// Locktime passes 1 second later.
CValidationState state;
int64_t nMedianTimePast = chainActive.Tip()->GetMedianTimePast() + 1;
BOOST_CHECK(ContextualCheckTransaction(
config, CTransaction(tx), state, chainActive.Tip()->nHeight + 1,
nMedianTimePast, nMedianTimePast));
}
// mempool-dependent transactions (not added)
tx.vin[0].prevout = COutPoint(hash, 0);
prevheights[0] = chainActive.Tip()->nHeight + 1;
tx.nLockTime = 0;
tx.vin[0].nSequence = 0;
{
// Locktime passes.
CValidationState state;
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
}
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
tx.vin[0].nSequence = 1;
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate);
// None of the of the absolute height/time locked tx should have made it
// into the template because we still check IsFinalTx in CreateNewBlock, but
// relative locked txs will if inconsistently added to g_mempool. For now
// these will still generate a valid template until BIP68 soft fork.
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL);
// However if we advance height by 1 and time by 512, all of them should be
// mined.
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Trick the MedianTimePast.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime +=
512;
}
chainActive.Tip()->nHeight++;
SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL);
chainActive.Tip()->nHeight--;
SetMockTime(0);
g_mempool.clear();
TestPackageSelection(config, scriptPubKey, txFirst);
fCheckpointsEnabled = true;
}
void CheckBlockMaxSize(const Config &config, uint64_t size, uint64_t expected) {
gArgs.ForceSetArg("-blockmaxsize", std::to_string(size));
BlockAssembler ba(config, g_mempool);
BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected);
}
BOOST_AUTO_TEST_CASE(BlockAssembler_construction) {
GlobalConfig config;
// We are working on a fake chain and need to protect ourselves.
LOCK(cs_main);
// Test around historical 1MB (plus one byte because that's mandatory)
config.SetMaxBlockSize(ONE_MEGABYTE + 1);
CheckBlockMaxSize(config, 0, 1000);
CheckBlockMaxSize(config, 1000, 1000);
CheckBlockMaxSize(config, 1001, 1001);
CheckBlockMaxSize(config, 12345, 12345);
CheckBlockMaxSize(config, ONE_MEGABYTE - 1001, ONE_MEGABYTE - 1001);
CheckBlockMaxSize(config, ONE_MEGABYTE - 1000, ONE_MEGABYTE - 1000);
CheckBlockMaxSize(config, ONE_MEGABYTE - 999, ONE_MEGABYTE - 999);
CheckBlockMaxSize(config, ONE_MEGABYTE, ONE_MEGABYTE - 999);
// Test around default cap
config.SetMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE);
// Now we can use the default max block size.
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE - 1001,
DEFAULT_MAX_BLOCK_SIZE - 1001);
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE - 1000,
DEFAULT_MAX_BLOCK_SIZE - 1000);
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE - 999,
DEFAULT_MAX_BLOCK_SIZE - 1000);
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE,
DEFAULT_MAX_BLOCK_SIZE - 1000);
// If the parameter is not specified, we use
// DEFAULT_MAX_GENERATED_BLOCK_SIZE
{
gArgs.ClearArg("-blockmaxsize");
BlockAssembler ba(config, g_mempool);
BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(),
DEFAULT_MAX_GENERATED_BLOCK_SIZE);
}
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 5a34f51f1f..65517be7e3 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -1,162 +1,159 @@
// Copyright (c) 2015-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.
#ifndef BITCOIN_TEST_TEST_BITCOIN_H
#define BITCOIN_TEST_TEST_BITCOIN_H
#include <chainparamsbase.h>
#include <fs.h>
#include <key.h>
#include <pubkey.h>
#include <random.h>
#include <scheduler.h>
#include <txmempool.h>
/**
* Version of Boost::test prior to 1.64 have issues when dealing with nullptr_t.
* In order to work around this, we ensure that the null pointers are typed in a
* way that Boost will like better.
*
* TODO: Use nullptr directly once the minimum version of boost is 1.64 or more.
*/
#define NULLPTR(T) static_cast<T *>(nullptr)
extern uint256 insecure_rand_seed;
extern FastRandomContext insecure_rand_ctx;
static inline void SeedInsecureRand(bool fDeterministic = false) {
if (fDeterministic) {
insecure_rand_seed = uint256();
} else {
insecure_rand_seed = GetRandHash();
}
insecure_rand_ctx = FastRandomContext(insecure_rand_seed);
}
static inline uint32_t insecure_rand() {
return insecure_rand_ctx.rand32();
}
static inline uint256 InsecureRand256() {
return insecure_rand_ctx.rand256();
}
static inline uint64_t InsecureRandBits(int bits) {
return insecure_rand_ctx.randbits(bits);
}
static inline uint64_t InsecureRandRange(uint64_t range) {
return insecure_rand_ctx.randrange(range);
}
static inline bool InsecureRandBool() {
return insecure_rand_ctx.randbool();
}
-static inline std::vector<uint8_t> InsecureRandBytes(size_t len) {
- return insecure_rand_ctx.randbytes(len);
-}
/**
* Basic testing setup.
* This just configures logging and chain parameters.
*/
struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle;
explicit BasicTestingSetup(
const std::string &chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
/** Testing setup that configures a complete environment.
* Included are data directory, coins database, script check threads setup.
*/
class CConnman;
class CNode;
struct CConnmanTest {
static void AddNode(CNode &node);
static void ClearNodes();
};
class PeerLogicValidation;
struct TestingSetup : public BasicTestingSetup {
fs::path pathTemp;
boost::thread_group threadGroup;
CConnman *connman;
CScheduler scheduler;
std::unique_ptr<PeerLogicValidation> peerLogic;
explicit TestingSetup(
const std::string &chainName = CBaseChainParams::MAIN);
~TestingSetup();
};
class CBlock;
class CMutableTransaction;
class CScript;
//
// Testing fixture that pre-creates a
// 100-block REGTEST-mode block chain
//
struct TestChain100Setup : public TestingSetup {
TestChain100Setup();
// Create a new block with just given transactions, coinbase paying to
// scriptPubKey, and try to add it to the current chain.
CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction> &txns,
const CScript &scriptPubKey);
~TestChain100Setup();
// For convenience, coinbase transactions.
std::vector<CTransaction> coinbaseTxns;
// private/public key needed to spend coinbase transactions.
CKey coinbaseKey;
};
class CTxMemPoolEntry;
class CTxMemPool;
struct TestMemPoolEntryHelper {
// Default values
Amount nFee;
int64_t nTime;
double dPriority;
unsigned int nHeight;
bool spendsCoinbase;
unsigned int sigOpCost;
LockPoints lp;
TestMemPoolEntryHelper()
: nFee(), nTime(0), dPriority(0.0), nHeight(1), spendsCoinbase(false),
sigOpCost(4) {}
CTxMemPoolEntry FromTx(const CMutableTransaction &tx,
CTxMemPool *pool = nullptr);
CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = nullptr);
// Change the default value
TestMemPoolEntryHelper &Fee(Amount _fee) {
nFee = _fee;
return *this;
}
TestMemPoolEntryHelper &Time(int64_t _time) {
nTime = _time;
return *this;
}
TestMemPoolEntryHelper &Priority(double _priority) {
dPriority = _priority;
return *this;
}
TestMemPoolEntryHelper &Height(unsigned int _height) {
nHeight = _height;
return *this;
}
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) {
spendsCoinbase = _flag;
return *this;
}
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) {
sigOpCost = _sigopsCost;
return *this;
}
};
#endif

File Metadata

Mime Type
text/x-diff
Expires
Wed, May 21, 20:31 (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5865883
Default Alt Text
(78 KB)

Event Timeline