Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14864550
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
78 KB
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
rSTAGING Bitcoin ABC staging
Event Timeline
Log In to Comment