mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge pull request #4289 from Munkybooty/backports-0.18-pr11
Backports 0.18 pr11
This commit is contained in:
commit
4ead0a71b7
@ -253,6 +253,15 @@ after_success:
|
||||
DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
|
||||
GOAL="install"
|
||||
BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
|
||||
# x86_64 Linux (xenial, no depends, only system libs)
|
||||
- stage: test
|
||||
env: >-
|
||||
HOST=x86_64-unknown-linux-gnu
|
||||
DOCKER_NAME_TAG=ubuntu:16.04
|
||||
PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev"
|
||||
NO_DEPENDS=1
|
||||
GOAL="install"
|
||||
BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER"
|
||||
# x86_64 Linux (no depends, only system libs)
|
||||
- stage: test
|
||||
env: >-
|
||||
|
@ -301,13 +301,13 @@ static bool ThreadHTTP(struct event_base* base)
|
||||
/** Bind HTTP server to specified addresses */
|
||||
static bool HTTPBindAddresses(struct evhttp* http)
|
||||
{
|
||||
int defaultPort = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
|
||||
int http_port = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
|
||||
std::vector<std::pair<std::string, uint16_t> > endpoints;
|
||||
|
||||
// Determine what addresses to bind to
|
||||
if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs
|
||||
endpoints.push_back(std::make_pair("::1", defaultPort));
|
||||
endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
|
||||
endpoints.push_back(std::make_pair("::1", http_port));
|
||||
endpoints.push_back(std::make_pair("127.0.0.1", http_port));
|
||||
if (gArgs.IsArgSet("-rpcallowip")) {
|
||||
LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n");
|
||||
}
|
||||
@ -316,11 +316,14 @@ static bool HTTPBindAddresses(struct evhttp* http)
|
||||
}
|
||||
} else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address
|
||||
for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) {
|
||||
int port = defaultPort;
|
||||
int port = http_port;
|
||||
std::string host;
|
||||
SplitHostPort(strRPCBind, port, host);
|
||||
endpoints.push_back(std::make_pair(host, port));
|
||||
}
|
||||
} else { // No specific bind address specified, bind to any
|
||||
endpoints.push_back(std::make_pair("::", http_port));
|
||||
endpoints.push_back(std::make_pair("0.0.0.0", http_port));
|
||||
}
|
||||
|
||||
// Bind addresses
|
||||
|
@ -342,8 +342,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
bool tryGetTxStatus(const uint256& txid,
|
||||
interfaces::WalletTxStatus& tx_status,
|
||||
int64_t& adjusted_time) override
|
||||
interfaces::WalletTxStatus& tx_status) override
|
||||
{
|
||||
TRY_LOCK(::cs_main, locked_chain);
|
||||
if (!locked_chain) {
|
||||
@ -357,7 +356,6 @@ public:
|
||||
if (mi == m_wallet.mapWallet.end()) {
|
||||
return false;
|
||||
}
|
||||
adjusted_time = GetAdjustedTime();
|
||||
tx_status = MakeWalletTxStatus(mi->second);
|
||||
return true;
|
||||
}
|
||||
@ -365,14 +363,12 @@ public:
|
||||
WalletTxStatus& tx_status,
|
||||
WalletOrderForm& order_form,
|
||||
bool& in_mempool,
|
||||
int& num_blocks,
|
||||
int64_t& adjusted_time) override
|
||||
int& num_blocks) override
|
||||
{
|
||||
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||
auto mi = m_wallet.mapWallet.find(txid);
|
||||
if (mi != m_wallet.mapWallet.end()) {
|
||||
num_blocks = ::chainActive.Height();
|
||||
adjusted_time = GetAdjustedTime();
|
||||
in_mempool = mi->second.InMempool();
|
||||
order_form = mi->second.vOrderForm;
|
||||
tx_status = MakeWalletTxStatus(mi->second);
|
||||
|
@ -183,16 +183,14 @@ public:
|
||||
|
||||
//! Try to get updated status for a particular transaction, if possible without blocking.
|
||||
virtual bool tryGetTxStatus(const uint256& txid,
|
||||
WalletTxStatus& tx_status,
|
||||
int64_t& adjusted_time) = 0;
|
||||
WalletTxStatus& tx_status) = 0;
|
||||
|
||||
//! Get transaction details.
|
||||
virtual WalletTx getWalletTxDetails(const uint256& txid,
|
||||
WalletTxStatus& tx_status,
|
||||
WalletOrderForm& order_form,
|
||||
bool& in_mempool,
|
||||
int& num_blocks,
|
||||
int64_t& adjusted_time) = 0;
|
||||
int& num_blocks) = 0;
|
||||
|
||||
// Get the number of coinjoin rounds an output went through
|
||||
virtual int getRealOutpointCoinJoinRounds(const COutPoint& outpoint) = 0;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime)
|
||||
QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks)
|
||||
{
|
||||
if (!status.is_final)
|
||||
{
|
||||
@ -61,11 +61,10 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i
|
||||
QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
|
||||
{
|
||||
int numBlocks;
|
||||
int64_t adjustedTime;
|
||||
interfaces::WalletTxStatus status;
|
||||
interfaces::WalletOrderForm orderForm;
|
||||
bool inMempool;
|
||||
interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks, adjustedTime);
|
||||
interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks);
|
||||
|
||||
QString strHTML;
|
||||
|
||||
@ -77,7 +76,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
|
||||
CAmount nDebit = wtx.debit;
|
||||
CAmount nNet = nCredit - nDebit;
|
||||
|
||||
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks, adjustedTime);
|
||||
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks);
|
||||
strHTML += "<br>";
|
||||
|
||||
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
private:
|
||||
TransactionDesc() {}
|
||||
|
||||
static QString FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime);
|
||||
static QString FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_QT_TRANSACTIONDESC_H
|
||||
|
@ -252,7 +252,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Wal
|
||||
return parts;
|
||||
}
|
||||
|
||||
void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime, int chainLockHeight)
|
||||
void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int chainLockHeight)
|
||||
{
|
||||
// Determine transaction status
|
||||
|
||||
|
@ -161,7 +161,7 @@ public:
|
||||
|
||||
/** Update status from core wallet tx.
|
||||
*/
|
||||
void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime, int chainLockHeight);
|
||||
void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int chainLockHeight);
|
||||
|
||||
/** Return whether a status update is needed.
|
||||
*/
|
||||
|
@ -200,9 +200,8 @@ public:
|
||||
// try to update the status of this transaction from the wallet.
|
||||
// Otherwise, simply re-use the cached status.
|
||||
interfaces::WalletTxStatus wtx;
|
||||
int64_t adjustedTime;
|
||||
if (rec->statusUpdateNeeded(numBlocks, parent->getChainLockHeight()) && wallet.tryGetTxStatus(rec->hash, wtx, adjustedTime)) {
|
||||
rec->updateStatus(wtx, numBlocks, adjustedTime, parent->getChainLockHeight());
|
||||
if (rec->statusUpdateNeeded(numBlocks, parent->getChainLockHeight()) && wallet.tryGetTxStatus(rec->hash, wtx)) {
|
||||
rec->updateStatus(wtx, numBlocks, parent->getChainLockHeight());
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
@ -276,6 +276,7 @@ struct PSBTInput
|
||||
template <typename Stream>
|
||||
inline void Unserialize(Stream& s) {
|
||||
// Read loop
|
||||
bool found_sep = false;
|
||||
while(!s.empty()) {
|
||||
// Read
|
||||
std::vector<unsigned char> key;
|
||||
@ -283,7 +284,10 @@ struct PSBTInput
|
||||
|
||||
// the key is empty if that was actually a separator byte
|
||||
// This is a special case for key lengths 0 as those are not allowed (except for separator)
|
||||
if (key.empty()) return;
|
||||
if (key.empty()) {
|
||||
found_sep = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// First byte of key is the type
|
||||
unsigned char type = key[0];
|
||||
@ -366,6 +370,10 @@ struct PSBTInput
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_sep) {
|
||||
throw std::ios_base::failure("Separator is missing at the end of an input map");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
@ -412,6 +420,7 @@ struct PSBTOutput
|
||||
template <typename Stream>
|
||||
inline void Unserialize(Stream& s) {
|
||||
// Read loop
|
||||
bool found_sep = false;
|
||||
while(!s.empty()) {
|
||||
// Read
|
||||
std::vector<unsigned char> key;
|
||||
@ -419,7 +428,10 @@ struct PSBTOutput
|
||||
|
||||
// the key is empty if that was actually a separator byte
|
||||
// This is a special case for key lengths 0 as those are not allowed (except for separator)
|
||||
if (key.empty()) return;
|
||||
if (key.empty()) {
|
||||
found_sep = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// First byte of key is the type
|
||||
unsigned char type = key[0];
|
||||
@ -454,6 +466,10 @@ struct PSBTOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_sep) {
|
||||
throw std::ios_base::failure("Separator is missing at the end of an output map");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
@ -528,6 +544,7 @@ struct PartiallySignedTransaction
|
||||
}
|
||||
|
||||
// Read global data
|
||||
bool found_sep = false;
|
||||
while(!s.empty()) {
|
||||
// Read
|
||||
std::vector<unsigned char> key;
|
||||
@ -535,7 +552,10 @@ struct PartiallySignedTransaction
|
||||
|
||||
// the key is empty if that was actually a separator byte
|
||||
// This is a special case for key lengths 0 as those are not allowed (except for separator)
|
||||
if (key.empty()) break;
|
||||
if (key.empty()) {
|
||||
found_sep = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// First byte of key is the type
|
||||
unsigned char type = key[0];
|
||||
@ -573,6 +593,10 @@ struct PartiallySignedTransaction
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_sep) {
|
||||
throw std::ios_base::failure("Separator is missing at the end of the global map");
|
||||
}
|
||||
|
||||
// Make sure that we got an unsigned tx
|
||||
if (!tx) {
|
||||
throw std::ios_base::failure("No unsigned transcation was provided");
|
||||
|
@ -85,8 +85,8 @@ static CBlockIndex CreateBlockIndex(int nHeight)
|
||||
|
||||
static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
return CheckSequenceLocks(tx, flags);
|
||||
LOCK(::mempool.cs);
|
||||
return CheckSequenceLocks(::mempool, tx, flags);
|
||||
}
|
||||
|
||||
// Test suite for ancestor feerate transaction selection.
|
||||
|
@ -760,7 +760,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
||||
const CTransaction& tx = it->GetTx();
|
||||
LockPoints lp = it->GetLockPoints();
|
||||
bool validLP = TestLockPointValidity(&lp);
|
||||
if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) {
|
||||
if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(*this, tx, flags, &lp, validLP)) {
|
||||
// Note if CheckSequenceLocks fails the LockPoints may still be invalid
|
||||
// So it's critical that we remove the tx and not depend on the LockPoints.
|
||||
txToRemove.insert(it);
|
||||
|
@ -379,10 +379,10 @@ bool TestLockPointValidity(const LockPoints* lp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints)
|
||||
bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
AssertLockHeld(mempool.cs);
|
||||
AssertLockHeld(pool.cs);
|
||||
|
||||
CBlockIndex* tip = chainActive.Tip();
|
||||
assert(tip != nullptr);
|
||||
@ -405,7 +405,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
|
||||
}
|
||||
else {
|
||||
// pcoinsTip contains the UTXO set for chainActive.Tip()
|
||||
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool);
|
||||
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
|
||||
std::vector<int> prevheights;
|
||||
prevheights.resize(tx.vin.size());
|
||||
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
||||
@ -738,7 +738,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
||||
// be mined yet.
|
||||
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
|
||||
// CoinsViewCache instead of create its own
|
||||
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
|
||||
if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
|
||||
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
|
||||
|
||||
CAmount nFees = 0;
|
||||
|
@ -365,7 +365,7 @@ bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_mai
|
||||
*
|
||||
* See consensus/consensus.h for flag definitions.
|
||||
*/
|
||||
bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
/**
|
||||
* Closure representing one script verification
|
||||
|
@ -64,7 +64,7 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
|
||||
|
||||
void WalletInit::AddWalletOptions() const
|
||||
{
|
||||
gArgs.AddArg("-avoidpartialspends", strprintf(_("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)"), DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
|
||||
gArgs.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
|
||||
gArgs.AddArg("-createwalletbackups=<n>", strprintf("Number of automatic wallet backups (default: %u)", nWalletBackups), false, OptionsCategory::WALLET);
|
||||
gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET);
|
||||
gArgs.AddArg("-instantsendnotify=<cmd>", "Execute command when a wallet InstantSend transaction is successfully locked (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
|
||||
|
@ -4165,6 +4165,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||
" \"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) If the key is a script\n"
|
||||
" \"ischange\" : true|false, (boolean) If the address was used for change output\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"
|
||||
@ -4222,6 +4223,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||
ret.pushKV("account", pwallet->mapAddressBook[dest].name);
|
||||
}
|
||||
}
|
||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
|
||||
const CKeyMetadata* meta = nullptr;
|
||||
const CKeyID *key_id = boost::get<CKeyID>(&dest);
|
||||
if (key_id != nullptr && !key_id->IsNull()) {
|
||||
|
@ -1717,6 +1717,11 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons
|
||||
}
|
||||
|
||||
bool CWallet::IsChange(const CTxOut& txout) const
|
||||
{
|
||||
return IsChange(txout.scriptPubKey);
|
||||
}
|
||||
|
||||
bool CWallet::IsChange(const CScript& script) const
|
||||
{
|
||||
// TODO: fix handling of 'change' outputs. The assumption is that any
|
||||
// payment to a script that is ours, but is not in the address book
|
||||
@ -1725,10 +1730,10 @@ bool CWallet::IsChange(const CTxOut& txout) const
|
||||
// a better way of identifying which outputs are 'the send' and which are
|
||||
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
|
||||
// which output, if any, was change).
|
||||
if (::IsMine(*this, txout.scriptPubKey))
|
||||
if (::IsMine(*this, script))
|
||||
{
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(txout.scriptPubKey, address))
|
||||
if (!ExtractDestination(script, address))
|
||||
return true;
|
||||
|
||||
LOCK(cs_wallet);
|
||||
|
@ -1164,6 +1164,7 @@ public:
|
||||
isminetype IsMine(const CTxOut& txout) const;
|
||||
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
|
||||
bool IsChange(const CTxOut& txout) const;
|
||||
bool IsChange(const CScript& script) const;
|
||||
CAmount GetChange(const CTxOut& txout) const;
|
||||
bool IsMine(const CTransaction& tx) const;
|
||||
/** should probably be renamed to IsRelevantToMe */
|
||||
|
@ -16,7 +16,8 @@
|
||||
"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"
|
||||
],
|
||||
"valid" : [
|
||||
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA",
|
||||
|
57
test/functional/p2p_leak_tx.py
Executable file
57
test/functional/p2p_leak_tx.py
Executable file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2017-2018 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test that we don't leak txs to inbound peers that we haven't yet announced to"""
|
||||
|
||||
from test_framework.messages import msg_getdata, CInv
|
||||
from test_framework.mininode import P2PDataStore
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
)
|
||||
|
||||
|
||||
class P2PNode(P2PDataStore):
|
||||
def on_inv(self, msg):
|
||||
pass
|
||||
|
||||
|
||||
class P2PLeakTxTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
gen_node = self.nodes[0] # The block and tx generating node
|
||||
gen_node.generate(1)
|
||||
|
||||
inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer
|
||||
|
||||
MAX_REPEATS = 100
|
||||
self.log.info("Running test up to {} times.".format(MAX_REPEATS))
|
||||
for i in range(MAX_REPEATS):
|
||||
self.log.info('Run repeat {}'.format(i + 1))
|
||||
txid = gen_node.sendtoaddress(gen_node.getnewaddress(), 0.01)
|
||||
|
||||
want_tx = msg_getdata()
|
||||
want_tx.inv.append(CInv(t=1, h=int(txid, 16)))
|
||||
inbound_peer.last_message.pop('notfound', None)
|
||||
inbound_peer.send_message(want_tx)
|
||||
inbound_peer.sync_with_ping()
|
||||
|
||||
if inbound_peer.last_message.get('notfound'):
|
||||
self.log.debug('tx {} was not yet announced to us.'.format(txid))
|
||||
self.log.debug("node has responded with a notfound message. End test.")
|
||||
assert_equal(inbound_peer.last_message['notfound'].vec[0].hash, int(txid, 16))
|
||||
inbound_peer.last_message.pop('notfound')
|
||||
break
|
||||
else:
|
||||
self.log.debug('tx {} was already announced to us. Try test again.'.format(txid))
|
||||
assert int(txid, 16) in [inv.hash for inv in inbound_peer.last_message['inv'].inv]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
P2PLeakTxTest().main()
|
@ -1397,6 +1397,23 @@ class msg_mempool():
|
||||
def __repr__(self):
|
||||
return "msg_mempool()"
|
||||
|
||||
class msg_notfound:
|
||||
__slots__ = ("vec", )
|
||||
command = b"notfound"
|
||||
|
||||
def __init__(self, vec=None):
|
||||
self.vec = vec or []
|
||||
|
||||
def deserialize(self, f):
|
||||
self.vec = deser_vector(f, CInv)
|
||||
|
||||
def serialize(self):
|
||||
return ser_vector(self.vec)
|
||||
|
||||
def __repr__(self):
|
||||
return "msg_notfound(vec=%s)" % (repr(self.vec))
|
||||
|
||||
|
||||
class msg_sendheaders():
|
||||
command = b"sendheaders"
|
||||
|
||||
|
@ -23,7 +23,42 @@ import sys
|
||||
import time
|
||||
import threading
|
||||
|
||||
from test_framework.messages import CBlockHeader, MIN_VERSION_SUPPORTED, msg_addr, msg_addrv2, msg_block, msg_blocktxn, msg_clsig, msg_cmpctblock, msg_getaddr, msg_getblocks, msg_getblocktxn, msg_getdata, msg_getheaders, msg_getmnlistd, msg_headers, msg_inv, msg_islock, msg_mempool, msg_mnlistdiff, msg_ping, msg_pong, msg_qdata, msg_qgetdata, msg_reject, msg_sendaddrv2, msg_sendcmpct, msg_sendheaders, msg_tx, msg_verack, msg_version, MY_SUBVERSION, NODE_NETWORK, sha256
|
||||
from test_framework.messages import (
|
||||
CBlockHeader,
|
||||
MIN_VERSION_SUPPORTED,
|
||||
msg_addr,
|
||||
msg_addrv2,
|
||||
msg_block,
|
||||
msg_blocktxn,
|
||||
msg_clsig,
|
||||
msg_cmpctblock,
|
||||
msg_getaddr,
|
||||
msg_getblocks,
|
||||
msg_getblocktxn,
|
||||
msg_getdata,
|
||||
msg_getheaders,
|
||||
msg_getmnlistd,
|
||||
msg_headers,
|
||||
msg_inv,
|
||||
msg_islock,
|
||||
msg_mempool,
|
||||
msg_mnlistdiff,
|
||||
msg_notfound,
|
||||
msg_ping,
|
||||
msg_pong,
|
||||
msg_qdata,
|
||||
msg_qgetdata,
|
||||
msg_reject,
|
||||
msg_sendaddrv2,
|
||||
msg_sendcmpct,
|
||||
msg_sendheaders,
|
||||
msg_tx,
|
||||
msg_verack,
|
||||
msg_version,
|
||||
MY_SUBVERSION,
|
||||
NODE_NETWORK,
|
||||
sha256,
|
||||
)
|
||||
from test_framework.util import wait_until
|
||||
|
||||
MSG_TX = 1
|
||||
@ -62,7 +97,7 @@ MESSAGEMAP = {
|
||||
b"govsync": None,
|
||||
b"islock": msg_islock,
|
||||
b"mnlistdiff": msg_mnlistdiff,
|
||||
b"notfound": None,
|
||||
b"notfound": msg_notfound,
|
||||
b"qfcommit": None,
|
||||
b"qsendrecsigs": None,
|
||||
b"qgetdata": msg_qgetdata,
|
||||
@ -338,6 +373,7 @@ class P2PInterface(P2PConnection):
|
||||
def on_getheaders(self, message): pass
|
||||
def on_headers(self, message): pass
|
||||
def on_mempool(self, message): pass
|
||||
def on_notfound(self, message): pass
|
||||
def on_pong(self, message): pass
|
||||
def on_reject(self, message): pass
|
||||
def on_sendaddrv2(self, message): pass
|
||||
|
@ -52,9 +52,6 @@ if os.name == 'posix':
|
||||
TEST_EXIT_PASSED = 0
|
||||
TEST_EXIT_SKIPPED = 77
|
||||
|
||||
# 30 minutes represented in seconds
|
||||
TRAVIS_TIMEOUT_DURATION = 30 * 60
|
||||
|
||||
BASE_SCRIPTS = [
|
||||
# Scripts that are run by the travis build process.
|
||||
# Longest test should go first, to favor running tests in parallel
|
||||
@ -154,6 +151,7 @@ BASE_SCRIPTS = [
|
||||
'feature_versionbits_warning.py',
|
||||
'rpc_preciousblock.py',
|
||||
'wallet_importprunedfunds.py',
|
||||
'p2p_leak_tx.py',
|
||||
'rpc_signmessage.py',
|
||||
'feature_nulldummy.py',
|
||||
'mempool_accept.py',
|
||||
@ -347,12 +345,12 @@ def main():
|
||||
jobs=args.jobs,
|
||||
enable_coverage=args.coverage,
|
||||
args=passon_args,
|
||||
runs_ci=args.ci,
|
||||
combined_logs_len=args.combinedlogslen,
|
||||
failfast=args.failfast
|
||||
failfast=args.failfast,
|
||||
runs_ci=args.ci,
|
||||
)
|
||||
|
||||
def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, runs_ci=False, combined_logs_len=0,failfast=False):
|
||||
def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0,failfast=False, runs_ci=False):
|
||||
args = args or []
|
||||
|
||||
# Warn if dashd is already running (unix only)
|
||||
@ -394,7 +392,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
|
||||
tmpdir=tmpdir,
|
||||
test_list=test_list,
|
||||
flags=flags,
|
||||
timeout_duration=TRAVIS_TIMEOUT_DURATION if runs_ci else float('inf'), # in seconds
|
||||
timeout_duration=30 * 60 if runs_ci else float('inf'), # in seconds
|
||||
)
|
||||
start_time = time.time()
|
||||
test_results = []
|
||||
@ -605,6 +603,7 @@ def check_script_list(*, src_dir, fail_on_warn):
|
||||
# On travis this warning is an error to prevent merging incomplete commits into master
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class RPCCoverage():
|
||||
"""
|
||||
Coverage reporting utilities for test_runner.
|
||||
|
@ -496,7 +496,7 @@ class WalletTest(BitcoinTestFramework):
|
||||
# Verify nothing new in wallet
|
||||
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
|
||||
|
||||
# Test getaddressinfo. Note that these addresses are taken from disablewallet.py
|
||||
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
|
||||
assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
|
||||
address_info = self.nodes[0].getaddressinfo("yjQ5gLvGRtmq1cwc4kePLCrzQ8GVCh9Gaz")
|
||||
assert_equal(address_info['address'], "yjQ5gLvGRtmq1cwc4kePLCrzQ8GVCh9Gaz")
|
||||
@ -504,6 +504,22 @@ class WalletTest(BitcoinTestFramework):
|
||||
assert not address_info["ismine"]
|
||||
assert not address_info["iswatchonly"]
|
||||
assert not address_info["isscript"]
|
||||
assert not address_info["ischange"]
|
||||
|
||||
# Test getaddressinfo 'ischange' field on change address.
|
||||
self.nodes[0].generate(1)
|
||||
destination = self.nodes[1].getnewaddress()
|
||||
txid = self.nodes[0].sendtoaddress(destination, 0.123)
|
||||
tx = self.nodes[0].decoderawtransaction(self.nodes[0].getrawtransaction(txid))
|
||||
output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]]
|
||||
assert len(output_addresses) > 1
|
||||
for address in output_addresses:
|
||||
ischange = self.nodes[0].getaddressinfo(address)['ischange']
|
||||
assert_equal(ischange, address != destination)
|
||||
if ischange:
|
||||
change = address
|
||||
self.nodes[0].setlabel(change, 'foobar')
|
||||
assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
WalletTest().main()
|
||||
|
Loading…
Reference in New Issue
Block a user