aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bench/bench.cpp7
-rw-r--r--src/bitcoin-cli.cpp28
-rw-r--r--src/bitcoin-tx.cpp24
-rw-r--r--src/bitcoind.cpp6
-rw-r--r--src/compat.h1
-rw-r--r--src/core_io.h2
-rw-r--r--src/core_write.cpp4
-rw-r--r--src/init.cpp10
-rw-r--r--src/main.cpp23
-rw-r--r--src/miner.cpp4
-rw-r--r--src/net.cpp7
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/bantablemodel.cpp7
-rw-r--r--src/qt/bantablemodel.h3
-rw-r--r--src/qt/bitcoin.cpp28
-rw-r--r--src/qt/bitcoingui.cpp8
-rw-r--r--src/qt/clientmodel.cpp3
-rw-r--r--src/qt/coincontroldialog.cpp50
-rw-r--r--src/qt/coincontroldialog.h43
-rw-r--r--src/qt/forms/overviewpage.ui5
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/overviewpage.cpp11
-rw-r--r--src/qt/overviewpage.h3
-rw-r--r--src/qt/paymentserver.cpp45
-rw-r--r--src/qt/paymentserver.h5
-rw-r--r--src/qt/peertablemodel.cpp9
-rw-r--r--src/qt/peertablemodel.h3
-rw-r--r--src/qt/receivecoinsdialog.cpp5
-rw-r--r--src/qt/receiverequestdialog.cpp2
-rw-r--r--src/qt/recentrequeststablemodel.cpp2
-rw-r--r--src/qt/rpcconsole.cpp28
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/splashscreen.cpp1
-rw-r--r--src/qt/transactionview.cpp6
-rw-r--r--src/qt/utilitydialog.cpp8
-rw-r--r--src/qt/utilitydialog.h2
-rw-r--r--src/rest.cpp4
-rw-r--r--src/rpc/blockchain.cpp4
-rw-r--r--src/rpc/mining.cpp6
-rw-r--r--src/rpc/misc.cpp2
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp2
-rw-r--r--src/rpc/server.cpp10
-rw-r--r--src/rpc/server.h5
-rw-r--r--src/script/interpreter.cpp4
-rw-r--r--src/test/data/tx_invalid.json26
-rw-r--r--src/test/data/tx_valid.json23
-rw-r--r--src/test/miner_tests.cpp1
-rw-r--r--src/wallet/rpcwallet.cpp4
-rw-r--r--src/zmq/zmqpublishnotifier.cpp5
51 files changed, 303 insertions, 197 deletions
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 227546a7a7..8942da8c74 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -64,8 +64,11 @@ bool State::KeepRunning()
return true;
}
if (elapsed*16 < maxElapsed) {
- countMask = ((countMask<<1)|1) & ((1LL<<60)-1);
- countMaskInv = 1./(countMask+1);
+ uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
+ if ((count & newCountMask)==0) {
+ countMask = newCountMask;
+ countMaskInv = 1./(countMask+1);
+ }
}
}
lastTime = now;
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index a04101d3ed..bf6f11a50d 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -28,6 +28,7 @@ using namespace std;
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
+static const int CONTINUE_EXECUTION=-1;
std::string HelpMessageCli()
{
@@ -67,7 +68,11 @@ public:
};
-static bool AppInitRPC(int argc, char* argv[])
+//
+// This function returns either one of EXIT_ codes when it's expected to stop the process or
+// CONTINUE_EXECUTION when it's expected to continue further.
+//
+static int AppInitRPC(int argc, char* argv[])
{
//
// Parameters
@@ -85,31 +90,35 @@ static bool AppInitRPC(int argc, char* argv[])
}
fprintf(stdout, "%s", strUsage.c_str());
- return false;
+ if (argc < 2) {
+ fprintf(stderr, "Error: too few parameters\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
if (!boost::filesystem::is_directory(GetDataDir(false))) {
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
- return false;
+ return EXIT_FAILURE;
}
try {
ReadConfigFile(mapArgs, mapMultiArgs);
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
- return false;
+ return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
try {
SelectBaseParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
- return false;
+ return EXIT_FAILURE;
}
if (GetBoolArg("-rpcssl", false))
{
fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
- return false;
+ return EXIT_FAILURE;
}
- return true;
+ return CONTINUE_EXECUTION;
}
@@ -318,8 +327,9 @@ int main(int argc, char* argv[])
}
try {
- if(!AppInitRPC(argc, argv))
- return EXIT_FAILURE;
+ int ret = AppInitRPC(argc, argv);
+ if (ret != CONTINUE_EXECUTION)
+ return ret;
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInitRPC()");
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 8e8ac47455..c5ae33da88 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -30,8 +30,13 @@ using namespace std;
static bool fCreateBlank;
static map<string,UniValue> registers;
+static const int CONTINUE_EXECUTION=-1;
-static bool AppInitRawTx(int argc, char* argv[])
+//
+// This function returns either one of EXIT_ codes when it's expected to stop the process or
+// CONTINUE_EXECUTION when it's expected to continue further.
+//
+static int AppInitRawTx(int argc, char* argv[])
{
//
// Parameters
@@ -43,7 +48,7 @@ static bool AppInitRawTx(int argc, char* argv[])
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
- return false;
+ return EXIT_FAILURE;
}
fCreateBlank = GetBoolArg("-create", false);
@@ -89,9 +94,13 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
fprintf(stdout, "%s", strUsage.c_str());
- return false;
+ if (argc < 2) {
+ fprintf(stderr, "Error: too few parameters\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
- return true;
+ return CONTINUE_EXECUTION;
}
static void RegisterSetJson(const string& key, const string& rawJson)
@@ -164,7 +173,7 @@ static void RegisterLoad(const string& strInput)
static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
{
int64_t newVersion = atoi64(cmdVal);
- if (newVersion < 1 || newVersion > CTransaction::CURRENT_VERSION)
+ if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
throw runtime_error("Invalid TX version requested");
tx.nVersion = (int) newVersion;
@@ -680,8 +689,9 @@ int main(int argc, char* argv[])
SetupEnvironment();
try {
- if(!AppInitRawTx(argc, argv))
- return EXIT_FAILURE;
+ int ret = AppInitRawTx(argc, argv);
+ if (ret != CONTINUE_EXECUTION)
+ return ret;
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInitRawTx()");
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 28bc374acc..823b9ce581 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -93,7 +93,7 @@ bool AppInit(int argc, char* argv[])
}
fprintf(stdout, "%s", strUsage.c_str());
- return false;
+ return true;
}
try
@@ -127,7 +127,7 @@ bool AppInit(int argc, char* argv[])
if (fCommandLine)
{
fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
#ifndef WIN32
fDaemon = GetBoolArg("-daemon", false);
@@ -187,5 +187,5 @@ int main(int argc, char* argv[])
// Connect bitcoind signal handlers
noui_connect();
- return (AppInit(argc, argv) ? 0 : 1);
+ return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/src/compat.h b/src/compat.h
index 79a297e5e4..2578d6d344 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -34,6 +34,7 @@
#else
#include <sys/fcntl.h>
#include <sys/mman.h>
+#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
diff --git a/src/core_io.h b/src/core_io.h
index b559d44bf5..44a732b697 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -25,7 +25,7 @@ extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::strin
// core_write.cpp
extern std::string FormatScript(const CScript& script);
-extern std::string EncodeHexTx(const CTransaction& tx);
+extern std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
diff --git a/src/core_write.cpp b/src/core_write.cpp
index ea01ddc10d..9f859ba9e1 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -116,9 +116,9 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
return str;
}
-string EncodeHexTx(const CTransaction& tx)
+string EncodeHexTx(const CTransaction& tx, const int serialFlags)
{
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags);
ssTx << tx;
return HexStr(ssTx.begin(), ssTx.end());
}
diff --git a/src/init.cpp b/src/init.cpp
index eab8de8d02..8e40c4388d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -364,6 +364,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort()));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
+ strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(>0) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION));
strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect"));
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
@@ -376,7 +377,7 @@ std::string HelpMessage(HelpMessageMode mode)
#endif
#endif
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
- strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
+ strUsage += HelpMessageOpt("-whitelist=<IP address or network>", _("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
@@ -854,7 +855,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
// Make sure enough file descriptors are available
- int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
+ int nBind = std::max(
+ (mapMultiArgs.count("-bind") ? mapMultiArgs.at("-bind").size() : 0) +
+ (mapMultiArgs.count("-whitebind") ? mapMultiArgs.at("-whitebind").size() : 0), size_t(1));
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0);
@@ -980,6 +983,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
+ if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
+ return InitError("rpcserialversion must be non-negative.");
+
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
diff --git a/src/main.cpp b/src/main.cpp
index 5f04c19162..f10cce2422 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -510,8 +510,8 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front());
if (pnodeStop) {
pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
- lNodesAnnouncingHeaderAndIDs.pop_front();
}
+ lNodesAnnouncingHeaderAndIDs.pop_front();
}
fAnnounceUsingCMPCTBLOCK = true;
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
@@ -1591,7 +1591,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return res;
}
-/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
+/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */
bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
{
CBlockIndex *pindexSlow = NULL;
@@ -3174,6 +3174,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
InvalidChainFound(pindex);
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true;
}
@@ -3501,15 +3502,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
{
std::vector<unsigned char> commitment;
int commitpos = GetWitnessCommitmentIndex(block);
- bool fHaveWitness = false;
- for (size_t t = 1; t < block.vtx.size(); t++) {
- if (!block.vtx[t].wit.IsNull()) {
- fHaveWitness = true;
- break;
- }
- }
std::vector<unsigned char> ret(32, 0x00);
- if (fHaveWitness && IsWitnessEnabled(pindexPrev, consensusParams)) {
+ if (consensusParams.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
if (commitpos == -1) {
uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL);
CHash256().Write(witnessroot.begin(), 32).Write(&ret[0], 32).Finalize(witnessroot.begin());
@@ -5591,10 +5585,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
if (!fRejectedParents) {
+ uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
- CInv inv(MSG_TX, txin.prevout.hash);
- pfrom->AddInventoryKnown(inv);
- if (!AlreadyHave(inv)) pfrom->AskFor(inv);
+ CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash);
+ pfrom->AddInventoryKnown(_inv);
+ if (!AlreadyHave(_inv)) pfrom->AskFor(_inv);
}
AddOrphanTx(tx, pfrom->GetId());
@@ -6860,7 +6855,7 @@ bool SendMessages(CNode* pto)
// Message: feefilter
//
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
- if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ if (!pto->fDisconnect && pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
!(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
int64_t timeNow = GetTimeMicros();
diff --git a/src/miner.cpp b/src/miner.cpp
index 9575858840..6cb40dae8d 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -168,7 +168,6 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
nLastBlockTx = nBlockTx;
nLastBlockSize = nBlockSize;
nLastBlockWeight = nBlockWeight;
- LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOpsCost);
// Create coinbase transaction.
CMutableTransaction coinbaseTx;
@@ -182,6 +181,9 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
pblocktemplate->vTxFees[0] = -nFees;
+ uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
+ LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
+
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
diff --git a/src/net.cpp b/src/net.cpp
index faa7b00281..7cb612ee96 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -877,7 +877,7 @@ struct NodeEvictionCandidate
int64_t nMinPingUsecTime;
int64_t nLastBlockTime;
int64_t nLastTXTime;
- bool fNetworkNode;
+ bool fRelevantServices;
bool fRelayTxes;
bool fBloomFilter;
CAddress addr;
@@ -902,7 +902,7 @@ static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvict
{
// There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime;
- if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode;
+ if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
return a.nTimeConnected > b.nTimeConnected;
}
@@ -936,7 +936,8 @@ static bool AttemptToEvictConnection() {
if (node->fDisconnect)
continue;
NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime,
- node->nLastBlockTime, node->nLastTXTime, node->fNetworkNode,
+ node->nLastBlockTime, node->nLastTXTime,
+ (node->nServices & nRelevantServices) == nRelevantServices,
node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup};
vEvictionCandidates.push_back(candidate);
}
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 135f15ffa8..727956c88d 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -83,7 +83,7 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode,
deleteAction = new QAction(ui->deleteAddress->text(), this);
// Build context menu
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(editAction);
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index d95106b5ac..7707ce7b6b 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -86,7 +86,7 @@ BanTableModel::BanTableModel(ClientModel *parent) :
clientModel(parent)
{
columns << tr("IP/Netmask") << tr("Banned Until");
- priv = new BanTablePriv();
+ priv.reset(new BanTablePriv());
// default to unsorted
priv->sortColumn = -1;
@@ -94,6 +94,11 @@ BanTableModel::BanTableModel(ClientModel *parent) :
refresh();
}
+BanTableModel::~BanTableModel()
+{
+ // Intentionally left empty
+}
+
int BanTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h
index fe9600ac0b..3c03d05c05 100644
--- a/src/qt/bantablemodel.h
+++ b/src/qt/bantablemodel.h
@@ -40,6 +40,7 @@ class BanTableModel : public QAbstractTableModel
public:
explicit BanTableModel(ClientModel *parent = 0);
+ ~BanTableModel();
void startAutoRefresh();
void stopAutoRefresh();
@@ -66,7 +67,7 @@ public Q_SLOTS:
private:
ClientModel *clientModel;
QStringList columns;
- BanTablePriv *priv;
+ std::unique_ptr<BanTablePriv> priv;
};
#endif // BITCOIN_QT_BANTABLEMODEL_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 430e6dd0e8..dbf372b12f 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -245,6 +245,7 @@ private:
#endif
int returnValue;
const PlatformStyle *platformStyle;
+ std::unique_ptr<QWidget> shutdownWindow;
void startThread();
};
@@ -365,9 +366,8 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
SplashScreen *splash = new SplashScreen(0, networkStyle);
- // We don't hold a direct pointer to the splash screen after creation, so use
- // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
- splash->setAttribute(Qt::WA_DeleteOnClose);
+ // We don't hold a direct pointer to the splash screen after creation, but the splash
+ // screen will take care of deleting itself when slotFinish happens.
splash->show();
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close()));
@@ -409,6 +409,11 @@ void BitcoinApplication::requestInitialize()
void BitcoinApplication::requestShutdown()
{
+ // Show a simple window indicating shutdown status
+ // Do this first as some of the steps may take some time below,
+ // for example the RPC console may still be executing a command.
+ shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));
+
qDebug() << __func__ << ": Requesting shutdown";
startThread();
window->hide();
@@ -423,9 +428,6 @@ void BitcoinApplication::requestShutdown()
delete clientModel;
clientModel = 0;
- // Show a simple window indicating shutdown status
- ShutdownWindow::showShutdownWindow(window);
-
// Request shutdown from core thread
Q_EMIT requestedShutdown();
}
@@ -496,7 +498,7 @@ void BitcoinApplication::shutdownResult(int retval)
void BitcoinApplication::handleRunawayException(const QString &message)
{
QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message);
- ::exit(1);
+ ::exit(EXIT_FAILURE);
}
WId BitcoinApplication::getMainWinId() const
@@ -573,13 +575,13 @@ int main(int argc, char *argv[])
{
HelpMessageDialog help(NULL, mapArgs.count("-version"));
help.showOrPrint();
- return 1;
+ return EXIT_SUCCESS;
}
/// 5. Now that settings and translations are available, ask user for data directory
// User language is set up: pick a data directory
if (!Intro::pickDataDirectory())
- return 0;
+ return EXIT_SUCCESS;
/// 6. Determine availability of data directory and parse bitcoin.conf
/// - Do not call GetDataDir(true) before this step finishes
@@ -587,14 +589,14 @@ int main(int argc, char *argv[])
{
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
- return 1;
+ return EXIT_FAILURE;
}
try {
ReadConfigFile(mapArgs, mapMultiArgs);
} catch (const std::exception& e) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
- return false;
+ return EXIT_FAILURE;
}
/// 7. Determine network (and switch to network specific options)
@@ -608,7 +610,7 @@ int main(int argc, char *argv[])
SelectParams(ChainNameFromCommandLine());
} catch(std::exception &e) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
- return 1;
+ return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
// Parse URIs on command line -- this can affect Params()
@@ -630,7 +632,7 @@ int main(int argc, char *argv[])
// - Do this after creating app and setting up translations, so errors are
// translated properly.
if (PaymentServer::ipcSendCommandLine())
- exit(0);
+ exit(EXIT_SUCCESS);
// Start up the payment server early, too, so impatient users that click on
// bitcoin: links repeatedly have their payment requests routed to this process:
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2afefb733e..1a5d27f6eb 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -496,6 +496,12 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
// Disable context menu on tray icon
trayIconMenu->clear();
}
+ // Propagate cleared model to child objects
+ rpcConsole->setClientModel(nullptr);
+#ifdef ENABLE_WALLET
+ walletFrame->setClientModel(nullptr);
+#endif // ENABLE_WALLET
+ unitDisplayControl->setOptionsModel(nullptr);
}
}
@@ -1147,7 +1153,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
void UnitDisplayStatusBarControl::createContextMenu()
{
- menu = new QMenu();
+ menu = new QMenu(this);
Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 14661b857a..9530b63a27 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -6,6 +6,7 @@
#include "bantablemodel.h"
#include "guiconstants.h"
+#include "guiutil.h"
#include "peertablemodel.h"
#include "chainparams.h"
@@ -186,7 +187,7 @@ QString ClientModel::formatClientStartupTime() const
QString ClientModel::dataDir() const
{
- return QString::fromStdString(GetDataDir().string());
+ return GUIUtil::boostPathToQString(GetDataDir());
}
void ClientModel::updateBanlist()
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 837f8ba6c1..866d3872c6 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -35,6 +35,13 @@ QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
bool CoinControlDialog::fSubtractFeeFromAmount = false;
+bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
+ int column = treeWidget()->sortColumn();
+ if (column == CoinControlDialog::COLUMN_AMOUNT || column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_CONFIRMATIONS)
+ return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong();
+ return QTreeWidgetItem::operator<(other);
+}
+
CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::CoinControlDialog),
@@ -52,7 +59,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
// context menu
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyAmountAction);
@@ -132,12 +139,9 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it
// default view is sorted by amount desc
- sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);
+ sortView(COLUMN_AMOUNT, Qt::DescendingOrder);
// restore list mode and sortorder as a convenience feature
QSettings settings;
@@ -169,15 +173,6 @@ void CoinControlDialog::setModel(WalletModel *model)
}
}
-// helper function str_pad
-QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding)
-{
- while (s.length() < nPadLength)
- s = sPadding + s;
-
- return s;
-}
-
// ok button
void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
{
@@ -349,7 +344,7 @@ void CoinControlDialog::sortView(int column, Qt::SortOrder order)
sortColumn = column;
sortOrder = order;
ui->treeWidget->sortItems(column, order);
- ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
+ ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
}
// treeview: clicked on header
@@ -357,12 +352,10 @@ void CoinControlDialog::headerSectionClicked(int logicalIndex)
{
if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
{
- ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
+ ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
}
else
{
- logicalIndex = getMappedColumn(logicalIndex, false);
-
if (sortColumn == logicalIndex)
sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
else
@@ -708,7 +701,7 @@ void CoinControlDialog::updateView()
model->listCoins(mapCoins);
BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
- QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
+ CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
QString sWalletAddress = coins.first;
QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
@@ -739,9 +732,9 @@ void CoinControlDialog::updateView()
nSum += out.tx->vout[out.i].nValue;
nChildren++;
- QTreeWidgetItem *itemOutput;
- if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress);
- else itemOutput = new QTreeWidgetItem(ui->treeWidget);
+ CCoinControlWidgetItem *itemOutput;
+ if (treeMode) itemOutput = new CCoinControlWidgetItem(itemWalletAddress);
+ else itemOutput = new CCoinControlWidgetItem(ui->treeWidget);
itemOutput->setFlags(flgCheckbox);
itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
@@ -779,19 +772,20 @@ void CoinControlDialog::updateView()
// amount
itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
- itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly
+ itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly
// date
itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
- itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " "));
+ itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime()));
// confirmations
- itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
+ itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth));
+ itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth));
// priority
double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority));
- itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
+ itemOutput->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong)dPriority));
dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
nInputSum += nInputSize;
@@ -822,9 +816,9 @@ void CoinControlDialog::updateView()
dPrioritySum = dPrioritySum / (nInputSum + 78);
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
- itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
+ itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum));
itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority));
- itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
+ itemWalletAddress->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong)dPrioritySum));
}
}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 1a467eb2ff..785079b1ad 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -28,6 +28,17 @@ namespace Ui {
#define ASYMP_UTF8 "\xE2\x89\x88"
+class CCoinControlWidgetItem : public QTreeWidgetItem
+{
+public:
+ CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
+ CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+
+ bool operator<(const QTreeWidgetItem &other) const;
+};
+
+
class CoinControlDialog : public QDialog
{
Q_OBJECT
@@ -60,13 +71,12 @@ private:
const PlatformStyle *platformStyle;
- QString strPad(QString, int, QString);
void sortView(int, Qt::SortOrder);
void updateView();
enum
{
- COLUMN_CHECKBOX,
+ COLUMN_CHECKBOX = 0,
COLUMN_AMOUNT,
COLUMN_LABEL,
COLUMN_ADDRESS,
@@ -75,35 +85,8 @@ private:
COLUMN_PRIORITY,
COLUMN_TXHASH,
COLUMN_VOUT_INDEX,
- COLUMN_AMOUNT_INT64,
- COLUMN_PRIORITY_INT64,
- COLUMN_DATE_INT64
};
-
- // some columns have a hidden column containing the value used for sorting
- int getMappedColumn(int column, bool fVisibleColumn = true)
- {
- if (fVisibleColumn)
- {
- if (column == COLUMN_AMOUNT_INT64)
- return COLUMN_AMOUNT;
- else if (column == COLUMN_PRIORITY_INT64)
- return COLUMN_PRIORITY;
- else if (column == COLUMN_DATE_INT64)
- return COLUMN_DATE;
- }
- else
- {
- if (column == COLUMN_AMOUNT)
- return COLUMN_AMOUNT_INT64;
- else if (column == COLUMN_PRIORITY)
- return COLUMN_PRIORITY_INT64;
- else if (column == COLUMN_DATE)
- return COLUMN_DATE_INT64;
- }
-
- return column;
- }
+ friend class CCoinControlWidgetItem;
private Q_SLOTS:
void showMenu(const QPoint &);
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 6d792d1475..4a6ee92508 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -20,7 +20,7 @@
<bool>false</bool>
</property>
<property name="styleSheet">
- <string notr="true">background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000;</string>
+ <string notr="true">QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -28,6 +28,9 @@
<property name="margin">
<number>3</number>
</property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
</widget>
</item>
<item>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 947a4c6821..dec3e56ec5 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -591,7 +591,8 @@ void TableViewLastColumnResizingFixer::on_geometriesChanged()
* Initializes all internal variables and prepares the
* the resize modes of the last 2 columns of the table and
*/
-TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth) :
+TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent) :
+ QObject(parent),
tableView(table),
lastColumnMinimumWidth(lastColMinimumWidth),
allColumnsMinimumWidth(allColsMinimumWidth)
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 9267e0a6c9..83cd6b5d46 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -150,7 +150,7 @@ namespace GUIUtil
Q_OBJECT
public:
- TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth);
+ TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent);
void stretchColumnWidth(int column);
private:
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 6a0404cbf7..a010f01021 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -25,8 +25,8 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(const PlatformStyle *platformStyle):
- QAbstractItemDelegate(), unit(BitcoinUnits::BTC),
+ TxViewDelegate(const PlatformStyle *platformStyle, QObject *parent=nullptr):
+ QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(platformStyle)
{
@@ -119,8 +119,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
currentWatchOnlyBalance(-1),
currentWatchUnconfBalance(-1),
currentWatchImmatureBalance(-1),
- txdelegate(new TxViewDelegate(platformStyle)),
- filter(0)
+ txdelegate(new TxViewDelegate(platformStyle, this))
{
ui->setupUi(this);
@@ -213,7 +212,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
if(model && model->getOptionsModel())
{
// Set up transaction list
- filter = new TransactionFilterProxy();
+ filter.reset(new TransactionFilterProxy());
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
@@ -221,7 +220,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
filter->setShowInactive(false);
filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
- ui->listTransactions->setModel(filter);
+ ui->listTransactions->setModel(filter.get());
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 911443c76a..23746a6b48 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -8,6 +8,7 @@
#include "amount.h"
#include <QWidget>
+#include <memory>
class ClientModel;
class TransactionFilterProxy;
@@ -55,7 +56,7 @@ private:
CAmount currentWatchImmatureBalance;
TxViewDelegate *txdelegate;
- TransactionFilterProxy *filter;
+ std::unique_ptr<TransactionFilterProxy> filter;
private Q_SLOTS:
void updateDisplayUnit();
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index c80aebb009..1ef224b521 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -58,14 +58,19 @@ const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest"
// BIP70 max payment request size in bytes (DoS protection)
const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
-X509_STORE* PaymentServer::certStore = NULL;
-void PaymentServer::freeCertStore()
+struct X509StoreDeleter {
+ void operator()(X509_STORE* b) {
+ X509_STORE_free(b);
+ }
+};
+
+struct X509Deleter {
+ void operator()(X509* b) { X509_free(b); }
+};
+
+namespace // Anon namespace
{
- if (PaymentServer::certStore != NULL)
- {
- X509_STORE_free(PaymentServer::certStore);
- PaymentServer::certStore = NULL;
- }
+ std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
}
//
@@ -80,7 +85,7 @@ static QString ipcServerName()
// Append a simple hash of the datadir
// Note that GetDataDir(true) returns a different path
// for -testnet versus main net
- QString ddir(QString::fromStdString(GetDataDir(true).string()));
+ QString ddir(GUIUtil::boostPathToQString(GetDataDir(true)));
name.append(QString::number(qHash(ddir)));
return name;
@@ -107,20 +112,15 @@ static void ReportInvalidCertificate(const QSslCertificate& cert)
//
void PaymentServer::LoadRootCAs(X509_STORE* _store)
{
- if (PaymentServer::certStore == NULL)
- atexit(PaymentServer::freeCertStore);
- else
- freeCertStore();
-
// Unit tests mostly use this, to pass in fake root CAs:
if (_store)
{
- PaymentServer::certStore = _store;
+ certStore.reset(_store);
return;
}
// Normal execution, use either -rootcertificates or system certs:
- PaymentServer::certStore = X509_STORE_new();
+ certStore.reset(X509_STORE_new());
// Note: use "-system-" default here so that users can pass -rootcertificates=""
// and get 'I don't like X.509 certificates, don't trust anybody' behavior:
@@ -167,11 +167,11 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
QByteArray certData = cert.toDer();
const unsigned char *data = (const unsigned char *)certData.data();
- X509* x509 = d2i_X509(0, &data, certData.size());
- if (x509 && X509_STORE_add_cert(PaymentServer::certStore, x509))
+ std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
+ if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
{
- // Note: X509_STORE_free will free the X509* objects when
- // the PaymentServer is destroyed
+ // Note: X509_STORE increases the reference count to the X509 object,
+ // we still have to release our reference to it.
++nRootCerts;
}
else
@@ -550,7 +550,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
recipient.paymentRequest = request;
recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
- request.getMerchant(PaymentServer::certStore, recipient.authenticatedMerchant);
+ request.getMerchant(certStore.get(), recipient.authenticatedMerchant);
QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
QStringList addresses;
@@ -807,3 +807,8 @@ bool PaymentServer::verifyAmount(const CAmount& requestAmount)
}
return fVerified;
}
+
+X509_STORE* PaymentServer::getCertStore()
+{
+ return certStore.get();
+}
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 2d27ed078b..7202e7dada 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -83,7 +83,7 @@ public:
static void LoadRootCAs(X509_STORE* store = NULL);
// Return certificate store
- static X509_STORE* getCertStore() { return certStore; }
+ static X509_STORE* getCertStore();
// OptionsModel is used for getting proxy settings and display unit
void setOptionsModel(OptionsModel *optionsModel);
@@ -140,9 +140,6 @@ private:
bool saveURIs; // true during startup
QLocalServer* uriServer;
- static X509_STORE* certStore; // Trusted root certificates
- static void freeCertStore();
-
QNetworkAccessManager* netManager; // Used to fetch payment requests
OptionsModel *optionsModel;
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 84ad0052fd..3829696e0e 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -115,12 +115,12 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
timer(0)
{
columns << tr("Node/Service") << tr("User Agent") << tr("Ping Time");
- priv = new PeerTablePriv();
+ priv.reset(new PeerTablePriv());
// default to unsorted
priv->sortColumn = -1;
// set up timer for auto refresh
- timer = new QTimer();
+ timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(refresh()));
timer->setInterval(MODEL_UPDATE_DELAY);
@@ -128,6 +128,11 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
refresh();
}
+PeerTableModel::~PeerTableModel()
+{
+ // Intentionally left empty
+}
+
void PeerTableModel::startAutoRefresh()
{
timer->start();
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index a2aaaa5d24..8227b5ec76 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -46,6 +46,7 @@ class PeerTableModel : public QAbstractTableModel
public:
explicit PeerTableModel(ClientModel *parent = 0);
+ ~PeerTableModel();
const CNodeCombinedStats *getNodeStats(int idx);
int getRowByNodeId(NodeId nodeid);
void startAutoRefresh();
@@ -74,7 +75,7 @@ public Q_SLOTS:
private:
ClientModel *clientModel;
QStringList columns;
- PeerTablePriv *priv;
+ std::unique_ptr<PeerTablePriv> priv;
QTimer *timer;
};
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 0b355837ab..752a05a409 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -25,6 +25,7 @@
ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::ReceiveCoinsDialog),
+ columnResizingFixer(0),
model(0),
platformStyle(platformStyle)
{
@@ -48,7 +49,7 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
// context menu
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyMessageAction);
contextMenu->addAction(copyAmountAction);
@@ -88,7 +89,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *model)
SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
// Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
- columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH);
+ columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
}
}
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index b13ea3df70..04cc2003c5 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -32,7 +32,7 @@
QRImageWidget::QRImageWidget(QWidget *parent):
QLabel(parent), contextMenu(0)
{
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
QAction *saveImageAction = new QAction(tr("&Save Image..."), this);
connect(saveImageAction, SIGNAL(triggered()), this, SLOT(saveImage()));
contextMenu->addAction(saveImageAction);
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 2335d6b282..35d37bb22b 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -14,7 +14,7 @@
#include <boost/foreach.hpp>
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
- walletModel(parent)
+ QAbstractTableModel(parent), walletModel(parent)
{
Q_UNUSED(wallet);
nReceiveRequestsMaxId = 0;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 650ff8b00d..167a3474c1 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -288,7 +288,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
// based timer interface
RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
- startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
ui->detailWidget->hide();
@@ -302,7 +301,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
- Q_EMIT stopExecutor();
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
@@ -389,7 +387,7 @@ void RPCConsole::setClientModel(ClientModel *model)
QAction* banAction365d = new QAction(tr("Ban Node for") + " " + tr("1 &year"), this);
// create peer table context menu
- peersTableContextMenu = new QMenu();
+ peersTableContextMenu = new QMenu(this);
peersTableContextMenu->addAction(disconnectAction);
peersTableContextMenu->addAction(banAction1h);
peersTableContextMenu->addAction(banAction24h);
@@ -435,7 +433,7 @@ void RPCConsole::setClientModel(ClientModel *model)
QAction* unbanAction = new QAction(tr("&Unban Node"), this);
// create ban table context menu
- banTableContextMenu = new QMenu();
+ banTableContextMenu = new QMenu(this);
banTableContextMenu->addAction(unbanAction);
// ban table context menu signals
@@ -466,6 +464,14 @@ void RPCConsole::setClientModel(ClientModel *model)
autoCompleter = new QCompleter(wordList, this);
ui->lineEdit->setCompleter(autoCompleter);
autoCompleter->popup()->installEventFilter(this);
+ // Start thread to execute RPC commands.
+ startExecutor();
+ }
+ if (!model) {
+ // Client model is being set to 0, this means shutdown() is about to be called.
+ // Make sure we clean up the executor thread
+ Q_EMIT stopExecutor();
+ thread.wait();
}
}
@@ -646,9 +652,8 @@ void RPCConsole::browseHistory(int offset)
void RPCConsole::startExecutor()
{
- QThread *thread = new QThread;
RPCExecutor *executor = new RPCExecutor();
- executor->moveToThread(thread);
+ executor->moveToThread(&thread);
// Replies from executor object must go to this object
connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
@@ -656,16 +661,15 @@ void RPCConsole::startExecutor()
connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
// On stopExecutor signal
- // - queue executor for deletion (in execution thread)
// - quit the Qt event loop in the execution thread
- connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
- connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
- // Queue the thread for deletion (in this thread) when it is finished
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ connect(this, SIGNAL(stopExecutor()), &thread, SLOT(quit()));
+ // - queue executor for deletion (in execution thread)
+ connect(&thread, SIGNAL(finished()), executor, SLOT(deleteLater()), Qt::DirectConnection);
+ connect(&thread, SIGNAL(finished()), this, SLOT(test()), Qt::DirectConnection);
// Default implementation of QThread::run() simply spins up an event loop in the thread,
// which is what we want.
- thread->start();
+ thread.start();
}
void RPCConsole::on_tabWidget_currentChanged(int index)
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 28affa954d..c1efa95f8c 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -12,6 +12,7 @@
#include <QWidget>
#include <QCompleter>
+#include <QThread>
class ClientModel;
class PlatformStyle;
@@ -140,6 +141,7 @@ private:
QMenu *banTableContextMenu;
int consoleFontSize;
QCompleter *autoCompleter;
+ QThread thread;
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index e36d86fddd..68e9ffeb94 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -147,6 +147,7 @@ void SplashScreen::slotFinish(QWidget *mainWin)
if (isMinimized())
showNormal();
hide();
+ deleteLater(); // No more need for this
}
static void InitMessage(SplashScreen *splash, const std::string &message)
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 48cf940502..79af4a1f9c 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -37,7 +37,7 @@
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
- transactionView(0), abandonAction(0)
+ transactionView(0), abandonAction(0), columnResizingFixer(0)
{
// Build filter row
setContentsMargins(0,0,0,0);
@@ -147,7 +147,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
QAction *editLabelAction = new QAction(tr("Edit label"), this);
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyAmountAction);
@@ -212,7 +212,7 @@ void TransactionView::setModel(WalletModel *model)
transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
- columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH);
+ columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH, this);
if (model->getOptionsModel())
{
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 947bcdb15a..4ec022881c 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -171,22 +171,20 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f):
setLayout(layout);
}
-void ShutdownWindow::showShutdownWindow(BitcoinGUI *window)
+QWidget *ShutdownWindow::showShutdownWindow(BitcoinGUI *window)
{
if (!window)
- return;
+ return nullptr;
// Show a simple window indicating shutdown status
QWidget *shutdownWindow = new ShutdownWindow();
- // We don't hold a direct pointer to the shutdown window after creation, so use
- // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
- shutdownWindow->setAttribute(Qt::WA_DeleteOnClose);
shutdownWindow->setWindowTitle(window->windowTitle());
// Center shutdown window at where main window was
const QPoint global = window->mapToGlobal(window->rect().center());
shutdownWindow->move(global.x() - shutdownWindow->width() / 2, global.y() - shutdownWindow->height() / 2);
shutdownWindow->show();
+ return shutdownWindow;
}
void ShutdownWindow::closeEvent(QCloseEvent *event)
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index 843bd7f67b..b930429578 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -43,7 +43,7 @@ class ShutdownWindow : public QWidget
public:
ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
- static void showShutdownWindow(BitcoinGUI *window);
+ static QWidget *showShutdownWindow(BitcoinGUI *window);
protected:
void closeEvent(QCloseEvent *event);
diff --git a/src/rest.cpp b/src/rest.cpp
index 2dff8d7dad..57cd9baeb7 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -228,7 +228,7 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
switch (rf) {
@@ -367,7 +367,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssTx << tx;
switch (rf) {
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 6f97671f52..b4d53a9f3d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -607,7 +607,7 @@ UniValue getblock(const UniValue& params, bool fHelp)
if (!fVerbose)
{
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
return strHex;
@@ -719,7 +719,7 @@ UniValue gettxout(const UniValue& params, bool fHelp)
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"2. n (numeric, required) vout number\n"
- "3. includemempool (boolean, optional) Whether to include the mem pool\n"
+ "3. includemempool (boolean, optional) Whether to include the mempool\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index a574709d97..30c495f297 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -229,7 +229,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
" \"errors\": \"...\" (string) Current errors\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
- " \"pooledtx\": n (numeric) The size of the mem pool\n"
+ " \"pooledtx\": n (numeric) The size of the mempool\n"
" \"testnet\": true|false (boolean) If using testnet or not\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
@@ -683,7 +683,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
- if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
+
+ const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
+ if (!pblocktemplate->vchCoinbaseCommitment.empty() && setClientRules.find(segwit_info.name) != setClientRules.end()) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 06489566ba..11befb529f 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -57,7 +57,7 @@ UniValue getinfo(const UniValue& params, bool fHelp)
" \"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 GMT epoch) of the oldest pre-generated key in the key pool\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"
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 89035aaa84..51f9d1c333 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -344,7 +344,7 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
- " \"timemillis\": t, (numeric) Total cpu time\n"
+ " \"timemillis\": t, (numeric) Current UNIX time in milliseconds\n"
" \"uploadtarget\":\n"
" {\n"
" \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n"
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b2bbb8b3ed..2719829e65 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -209,7 +209,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
- string strHex = EncodeHexTx(tx);
+ string strHex = EncodeHexTx(tx, RPCSerializationFlags());
if (!fVerbose)
return strHex;
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 23149baa6d..deeabcb8d7 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -146,6 +146,8 @@ uint256 ParseHashV(const UniValue& v, string strName)
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ if (64 != strHex.length())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
uint256 result;
result.SetHex(strHex);
return result;
@@ -493,4 +495,12 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
}
+int RPCSerializationFlags()
+{
+ int flag = 0;
+ if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
+ flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
+ return flag;
+}
+
CRPCTable tableRPC;
diff --git a/src/rpc/server.h b/src/rpc/server.h
index b5ccc153d0..1ed8f2466d 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -19,6 +19,8 @@
#include <univalue.h>
+static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;
+
class CRPCCommand;
namespace RPCServer
@@ -195,4 +197,7 @@ void InterruptRPC();
void StopRPC();
std::string JSONRPCExecBatch(const UniValue& vReq);
+// Retrieves any serialization flags requested in command line argument
+int RPCSerializationFlags();
+
#endif // BITCOIN_RPCSERVER_H
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 836cf9ee35..0e17ddc130 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -890,7 +890,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
- // Drop the signature, since there's no way for a signature to sign itself
+ // Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig));
}
@@ -951,7 +951,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
- // Drop the signatures, since there's no way for a signature to sign itself
+ // Drop the signature in pre-segwit scripts but not segwit scripts
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index f8baee0577..f7d9e1847f 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -314,5 +314,31 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x60 0x21 0xff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbff", 1000]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "P2SH,WITNESS,DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"],
+["FindAndDelete tests"],
+["This is a test of FindAndDelete. The first tx is a spend of normal scriptPubKey and the second tx is a spend of bare P2WSH."],
+["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."],
+["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <pubkey>,"],
+["where the pubkey is obtained through key recovery with sig and the wrong sighash."],
+["This is to show that FindAndDelete is applied only to non-segwit scripts"],
+["To show that the tests are 'correctly wrong', they should pass by modifying OP_CHECKSIG under interpreter.cpp"],
+["by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE)"],
+["Non-segwit: wrong sighash (without FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]],
+"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012103b12a1ec8428fc74166926318c15e17408fea82dbb157575e16a8c365f546248f4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: wrong sighash (with FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]],
+"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9d7ed6e161f0e255c10bbfcca0128a9e2035c2c8da58899c54d22d3a31afdef4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"],
+["This is multisig version of the FindAndDelete tests"],
+["Script is 2 CHECKMULTISIGVERIFY <sig1> <sig2> DROP"],
+["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"],
+["Signature is 0 <sig1> <sig2> 2 <key1> <key2>"],
+["Should pass by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE) under OP_CHECKMULTISIG"],
+["Non-segwit: wrong sighash (without FindAndDelete) = 4bc6a53e8e16ef508c19e38bba08831daba85228b0211f323d4cb0999cf2a5e8"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]],
+"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596015221023fd5dd42b44769c5653cbc5947ff30ab8871f240ad0c0e7432aefe84b5b4ff3421039d52178dbde360b83f19cf348deb04fa8360e1bf5634577be8e50fafc2b0e4ef4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: wrong sighash (with FindAndDelete) = 17c50ec2181ecdfdc85ca081174b248199ba81fff730794d4f69b8ec031f2dce"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]],
+"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601010221023cb6055f4b57a1580c5a753e19610cafaedf7e0ff377731c77837fd666eae1712102c1b1db303ac232ffa8e5e7cc2cf5f96c6e40d3e6914061204c0541cb2043a0969552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 1ea70135b4..2f299aa5fe 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -487,5 +487,28 @@
[[["6eb98797a21c6c10aa74edf29d618be109f48a8e94c694f3701e08ca69186436", 1, "HASH160 0x14 0x9993a429037b5d912407a71c252019287b8d27a5 EQUAL", 987654321]],
"0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", "P2SH,WITNESS"],
+["FindAndDelete tests"],
+["This is a test of FindAndDelete. The first tx is a spend of normal P2SH and the second tx is a spend of bare P2WSH."],
+["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."],
+["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <pubkey>,"],
+["where the pubkey is obtained through key recovery with sig and correct sighash."],
+["This is to show that FindAndDelete is applied only to non-segwit scripts"],
+["Non-segwit: correct sighash (with FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]],
+"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0121037a3fb04bcdb09eba90f69961ba1692a3528e45e67c85b200df820212d7594d334aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: correct sighash (without FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]],
+"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"],
+["This is multisig version of the FindAndDelete tests"],
+["Script is 2 CHECKMULTISIGVERIFY <sig1> <sig2> DROP"],
+["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"],
+["Signature is 0 <sig1> <sig2> 2 <key1> <key2>"],
+["Non-segwit: correct sighash (with FindAndDelete) = 1d50f00ba4db2917b903b0ec5002e017343bb38876398c9510570f5dce099295"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]],
+"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601522102cd74a2809ffeeed0092bc124fd79836706e41f048db3f6ae9df8708cefb83a1c2102e615999372426e46fd107b76eaf007156a507584aa2cc21de9eee3bdbd26d36c4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: correct sighash (without FindAndDelete) = c1628a1e7c67f14ca0c27c06e4fdeec2e6d1a73c7a91d7c046ff83e835aebb72"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]],
+"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 70ba707795..f2bd082cba 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -213,6 +213,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
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); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
txCoinbase.vout[0].scriptPubKey = CScript();
pblock->vtx[0] = CTransaction(txCoinbase);
if (txFirst.size() == 0)
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 2ad379e46b..17bda050c3 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1780,7 +1780,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
ListTransactions(wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
+ string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -2274,7 +2274,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
" \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
" \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
- " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\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 configuration, set in " + CURRENCY_UNIT + "/kB\n"
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index b6c907980f..cdef17e08c 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -6,6 +6,7 @@
#include "zmqpublishnotifier.h"
#include "main.h"
#include "util.h"
+#include "rpc/server.h"
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
@@ -165,7 +166,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex());
const Consensus::Params& consensusParams = Params().GetConsensus();
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
{
LOCK(cs_main);
CBlock block;
@@ -185,7 +186,7 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr
{
uint256 hash = transaction.GetHash();
LogPrint("zmq", "zmq: Publish rawtx %s\n", hash.GetHex());
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ss << transaction;
return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
}