mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-06-02 07:22:33 +02:00
Merge #19610: p2p: refactor AlreadyHave(), CInv::type, INV/TX processing
fb56d37612
p2p: ensure inv is GenMsgTx before ToGenTxid in inv processing (John Newbery)aa3621385e
test: use CInv::MSG_WITNESS_TX flag in p2p_segwit (Jon Atack)24ee4f01ea
p2p: make gtxid(.hash) and fAlreadyHave localvars const (Jon Atack)b1c855453b
p2p: use CInv block message helpers in net_processing.cpp (Jon Atack)acd6642167
[net processing] Change AlreadyHaveTx() to take a GenTxid (John Newbery)5fdfb80b86
[net processing] Change AlreadyHaveBlock() to take block_hash argument (John Newbery)430e183b89
[net processing] Remove mempool argument from AlreadyHaveBlock() (John Newbery)42ca5618ca
[net processing] Split AlreadyHave() into separate block and tx functions (John Newbery)39f1dc9445
p2p: remove nFetchFlags from NetMsgType TX and INV processing (Jon Atack)471714e1f0
p2p: add CInv block message helper methods (Jon Atack) Pull request description: Building on #19590 and the recent `wtxid` and `GenTxid` changes, this is a refactoring and cleanup PR to simplify and improve some of the net processing code. Some of the diffs are best reviewed with `-w` to ignore spacing. Co-authored by John Newbery. ACKs for top commit: laanwj: Code review ACKfb56d37612
jnewbery: utACKfb56d37612
vasild: ACKfb56d3761
Tree-SHA512: ba39b58e6aaf850880a842fe5f6295e9f1870906ef690206acfc17140aae2ac854981e1066dbcd4238062478762fbd040ef772fdc2c50eea6869997c583e6a6d
This commit is contained in:
commit
505b39e72b
@ -1465,47 +1465,40 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidatio
|
|||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
bool static AlreadyHave(const CInv& inv, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
bool static AlreadyHaveTx(const GenTxid& gtxid, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
switch (inv.type)
|
assert(recentRejects);
|
||||||
{
|
if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
|
||||||
case MSG_TX:
|
// If the chain tip has changed previously rejected transactions
|
||||||
case MSG_WITNESS_TX:
|
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
|
||||||
case MSG_WTX:
|
// or a double-spend. Reset the rejects filter and give those
|
||||||
{
|
// txs a second chance.
|
||||||
assert(recentRejects);
|
hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
|
||||||
if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip)
|
recentRejects->reset();
|
||||||
{
|
|
||||||
// If the chain tip has changed previously rejected transactions
|
|
||||||
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
|
|
||||||
// or a double-spend. Reset the rejects filter and give those
|
|
||||||
// txs a second chance.
|
|
||||||
hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
|
|
||||||
recentRejects->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
LOCK(g_cs_orphans);
|
|
||||||
if (!inv.IsMsgWtx() && mapOrphanTransactions.count(inv.hash)) {
|
|
||||||
return true;
|
|
||||||
} else if (inv.IsMsgWtx() && g_orphans_by_wtxid.count(inv.hash)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
LOCK(g_cs_recent_confirmed_transactions);
|
|
||||||
if (g_recent_confirmed_transactions->contains(inv.hash)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return recentRejects->contains(inv.hash) || mempool.exists(ToGenTxid(inv));
|
|
||||||
}
|
|
||||||
case MSG_BLOCK:
|
|
||||||
case MSG_WITNESS_BLOCK:
|
|
||||||
return LookupBlockIndex(inv.hash) != nullptr;
|
|
||||||
}
|
}
|
||||||
// Don't know what it is, just say we already got one
|
|
||||||
return true;
|
const uint256& hash = gtxid.GetHash();
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(g_cs_orphans);
|
||||||
|
if (!gtxid.IsWtxid() && mapOrphanTransactions.count(hash)) {
|
||||||
|
return true;
|
||||||
|
} else if (gtxid.IsWtxid() && g_orphans_by_wtxid.count(hash)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(g_cs_recent_confirmed_transactions);
|
||||||
|
if (g_recent_confirmed_transactions->contains(hash)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return recentRejects->contains(hash) || mempool.exists(gtxid);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
|
{
|
||||||
|
return LookupBlockIndex(block_hash) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
|
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
|
||||||
@ -1608,7 +1601,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|||||||
// disconnect node in case we have reached the outbound limit for serving historical blocks
|
// disconnect node in case we have reached the outbound limit for serving historical blocks
|
||||||
if (send &&
|
if (send &&
|
||||||
connman.OutboundTargetReached(true) &&
|
connman.OutboundTargetReached(true) &&
|
||||||
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) &&
|
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
|
||||||
!pfrom.HasPermission(PF_DOWNLOAD) // nodes with the download permission may exceed target
|
!pfrom.HasPermission(PF_DOWNLOAD) // nodes with the download permission may exceed target
|
||||||
) {
|
) {
|
||||||
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
|
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
|
||||||
@ -1634,7 +1627,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|||||||
std::shared_ptr<const CBlock> pblock;
|
std::shared_ptr<const CBlock> pblock;
|
||||||
if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
|
if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
|
||||||
pblock = a_recent_block;
|
pblock = a_recent_block;
|
||||||
} else if (inv.type == MSG_WITNESS_BLOCK) {
|
} else if (inv.IsMsgWitnessBlk()) {
|
||||||
// Fast-path: in this case it is possible to serve the block directly from disk,
|
// Fast-path: in this case it is possible to serve the block directly from disk,
|
||||||
// as the network format matches the format on disk
|
// as the network format matches the format on disk
|
||||||
std::vector<uint8_t> block_data;
|
std::vector<uint8_t> block_data;
|
||||||
@ -1651,12 +1644,11 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|||||||
pblock = pblockRead;
|
pblock = pblockRead;
|
||||||
}
|
}
|
||||||
if (pblock) {
|
if (pblock) {
|
||||||
if (inv.type == MSG_BLOCK)
|
if (inv.IsMsgBlk()) {
|
||||||
connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
|
connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
|
||||||
else if (inv.type == MSG_WITNESS_BLOCK)
|
} else if (inv.IsMsgWitnessBlk()) {
|
||||||
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
|
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
|
||||||
else if (inv.type == MSG_FILTERED_BLOCK)
|
} else if (inv.IsMsgFilteredBlk()) {
|
||||||
{
|
|
||||||
bool sendMerkleBlock = false;
|
bool sendMerkleBlock = false;
|
||||||
CMerkleBlock merkleBlock;
|
CMerkleBlock merkleBlock;
|
||||||
if (pfrom.m_tx_relay != nullptr) {
|
if (pfrom.m_tx_relay != nullptr) {
|
||||||
@ -1680,9 +1672,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
// no response
|
// no response
|
||||||
}
|
} else if (inv.IsMsgCmpctBlk()) {
|
||||||
else if (inv.type == MSG_CMPCT_BLOCK)
|
|
||||||
{
|
|
||||||
// If a peer is asking for old blocks, we're almost guaranteed
|
// If a peer is asking for old blocks, we're almost guaranteed
|
||||||
// they won't have a useful mempool to match against a compact block,
|
// they won't have a useful mempool to match against a compact block,
|
||||||
// and we don't feel like constructing the object for them, so
|
// and we don't feel like constructing the object for them, so
|
||||||
@ -1810,7 +1800,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
|
|||||||
// expensive to process.
|
// expensive to process.
|
||||||
if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) {
|
if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) {
|
||||||
const CInv &inv = *it++;
|
const CInv &inv = *it++;
|
||||||
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) {
|
if (inv.IsGenBlkMsg()) {
|
||||||
ProcessGetBlockData(pfrom, chainparams, inv, connman);
|
ProcessGetBlockData(pfrom, chainparams, inv, connman);
|
||||||
}
|
}
|
||||||
// else: If the first item on the queue is an unknown type, we erase it
|
// else: If the first item on the queue is an unknown type, we erase it
|
||||||
@ -2692,14 +2682,11 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
|
|||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
uint32_t nFetchFlags = GetFetchFlags(pfrom);
|
|
||||||
const auto current_time = GetTime<std::chrono::microseconds>();
|
const auto current_time = GetTime<std::chrono::microseconds>();
|
||||||
uint256* best_block{nullptr};
|
uint256* best_block{nullptr};
|
||||||
|
|
||||||
for (CInv &inv : vInv)
|
for (CInv& inv : vInv) {
|
||||||
{
|
if (interruptMsgProc) return;
|
||||||
if (interruptMsgProc)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Ignore INVs that don't match wtxidrelay setting.
|
// Ignore INVs that don't match wtxidrelay setting.
|
||||||
// Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
|
// Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
|
||||||
@ -2710,14 +2697,10 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
|
|||||||
if (inv.IsMsgWtx()) continue;
|
if (inv.IsMsgWtx()) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fAlreadyHave = AlreadyHave(inv, m_mempool);
|
if (inv.IsMsgBlk()) {
|
||||||
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
|
const bool fAlreadyHave = AlreadyHaveBlock(inv.hash);
|
||||||
|
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
|
||||||
|
|
||||||
if (inv.IsMsgTx()) {
|
|
||||||
inv.type |= nFetchFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inv.type == MSG_BLOCK) {
|
|
||||||
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
|
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
|
||||||
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
|
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
|
||||||
// Headers-first is the primary method of announcement on
|
// Headers-first is the primary method of announcement on
|
||||||
@ -2727,15 +2710,21 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
|
|||||||
// then fetch the blocks we need to catch up.
|
// then fetch the blocks we need to catch up.
|
||||||
best_block = &inv.hash;
|
best_block = &inv.hash;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (inv.IsGenTxMsg()) {
|
||||||
|
const GenTxid gtxid = ToGenTxid(inv);
|
||||||
|
const bool fAlreadyHave = AlreadyHaveTx(gtxid, mempool);
|
||||||
|
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
|
||||||
|
|
||||||
pfrom.AddKnownTx(inv.hash);
|
pfrom.AddKnownTx(inv.hash);
|
||||||
if (fBlocksOnly) {
|
if (fBlocksOnly) {
|
||||||
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
|
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
|
||||||
pfrom.fDisconnect = true;
|
pfrom.fDisconnect = true;
|
||||||
return;
|
return;
|
||||||
} else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
|
} else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
|
||||||
RequestTx(State(pfrom.GetId()), ToGenTxid(inv), current_time);
|
RequestTx(State(pfrom.GetId()), gtxid, current_time);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LogPrint(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3006,7 +2995,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
|
|||||||
// already; and an adversary can already relay us old transactions
|
// already; and an adversary can already relay us old transactions
|
||||||
// (older than our recency filter) if trying to DoS us, without any need
|
// (older than our recency filter) if trying to DoS us, without any need
|
||||||
// for witness malleation.
|
// for witness malleation.
|
||||||
if (!AlreadyHave(CInv(MSG_WTX, wtxid), m_mempool) &&
|
if (!AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid), m_mempool) &&
|
||||||
AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
m_mempool.check(&::ChainstateActive().CoinsTip());
|
m_mempool.check(&::ChainstateActive().CoinsTip());
|
||||||
RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
|
RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
|
||||||
@ -3050,7 +3039,6 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!fRejectedParents) {
|
if (!fRejectedParents) {
|
||||||
uint32_t nFetchFlags = GetFetchFlags(pfrom);
|
|
||||||
const auto current_time = GetTime<std::chrono::microseconds>();
|
const auto current_time = GetTime<std::chrono::microseconds>();
|
||||||
|
|
||||||
for (const uint256& parent_txid : unique_parents) {
|
for (const uint256& parent_txid : unique_parents) {
|
||||||
@ -3059,9 +3047,9 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
|
|||||||
// wtxidrelay peers.
|
// wtxidrelay peers.
|
||||||
// Eventually we should replace this with an improved
|
// Eventually we should replace this with an improved
|
||||||
// protocol for getting all unconfirmed parents.
|
// protocol for getting all unconfirmed parents.
|
||||||
CInv _inv(MSG_TX | nFetchFlags, parent_txid);
|
const GenTxid gtxid{/* is_wtxid=*/false, parent_txid};
|
||||||
pfrom.AddKnownTx(parent_txid);
|
pfrom.AddKnownTx(parent_txid);
|
||||||
if (!AlreadyHave(_inv, m_mempool)) RequestTx(State(pfrom.GetId()), ToGenTxid(_inv), current_time);
|
if (!AlreadyHaveTx(gtxid, m_mempool)) RequestTx(State(pfrom.GetId()), gtxid, current_time);
|
||||||
}
|
}
|
||||||
AddOrphanTx(ptx, pfrom.GetId());
|
AddOrphanTx(ptx, pfrom.GetId());
|
||||||
|
|
||||||
@ -4611,7 +4599,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
|||||||
// processing at a later time, see below)
|
// processing at a later time, see below)
|
||||||
tx_process_time.erase(tx_process_time.begin());
|
tx_process_time.erase(tx_process_time.begin());
|
||||||
CInv inv(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash());
|
CInv inv(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash());
|
||||||
if (!AlreadyHave(inv, m_mempool)) {
|
if (!AlreadyHaveTx(ToGenTxid(inv), m_mempool)) {
|
||||||
// If this transaction was last requested more than 1 minute ago,
|
// If this transaction was last requested more than 1 minute ago,
|
||||||
// then request.
|
// then request.
|
||||||
const auto last_request_time = GetTxRequestTime(gtxid);
|
const auto last_request_time = GetTxRequestTime(gtxid);
|
||||||
|
@ -247,7 +247,7 @@ extern const char* CFCHECKPT;
|
|||||||
* txid.
|
* txid.
|
||||||
* @since protocol version 70016 as described by BIP 339.
|
* @since protocol version 70016 as described by BIP 339.
|
||||||
*/
|
*/
|
||||||
extern const char *WTXIDRELAY;
|
extern const char* WTXIDRELAY;
|
||||||
}; // namespace NetMsgType
|
}; // namespace NetMsgType
|
||||||
|
|
||||||
/* Get a vector of all valid message types (see above) */
|
/* Get a vector of all valid message types (see above) */
|
||||||
@ -418,12 +418,22 @@ public:
|
|||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
|
|
||||||
// Single-message helper methods
|
// Single-message helper methods
|
||||||
bool IsMsgTx() const { return type == MSG_TX; }
|
bool IsMsgTx() const { return type == MSG_TX; }
|
||||||
bool IsMsgWtx() const { return type == MSG_WTX; }
|
bool IsMsgBlk() const { return type == MSG_BLOCK; }
|
||||||
bool IsMsgWitnessTx() const { return type == MSG_WITNESS_TX; }
|
bool IsMsgWtx() const { return type == MSG_WTX; }
|
||||||
|
bool IsMsgFilteredBlk() const { return type == MSG_FILTERED_BLOCK; }
|
||||||
|
bool IsMsgCmpctBlk() const { return type == MSG_CMPCT_BLOCK; }
|
||||||
|
bool IsMsgWitnessBlk() const { return type == MSG_WITNESS_BLOCK; }
|
||||||
|
|
||||||
// Combined-message helper methods
|
// Combined-message helper methods
|
||||||
bool IsGenTxMsg() const { return type == MSG_TX || type == MSG_WTX || type == MSG_WITNESS_TX; }
|
bool IsGenTxMsg() const
|
||||||
|
{
|
||||||
|
return type == MSG_TX || type == MSG_WTX || type == MSG_WITNESS_TX;
|
||||||
|
}
|
||||||
|
bool IsGenBlkMsg() const
|
||||||
|
{
|
||||||
|
return type == MSG_BLOCK || type == MSG_FILTERED_BLOCK || type == MSG_CMPCT_BLOCK || type == MSG_WITNESS_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
|
@ -25,6 +25,7 @@ from test_framework.messages import (
|
|||||||
MSG_BLOCK,
|
MSG_BLOCK,
|
||||||
MSG_TX,
|
MSG_TX,
|
||||||
MSG_WITNESS_FLAG,
|
MSG_WITNESS_FLAG,
|
||||||
|
MSG_WITNESS_TX,
|
||||||
MSG_WTX,
|
MSG_WTX,
|
||||||
NODE_NETWORK,
|
NODE_NETWORK,
|
||||||
NODE_WITNESS,
|
NODE_WITNESS,
|
||||||
@ -2157,7 +2158,7 @@ class SegWitTest(BitcoinTestFramework):
|
|||||||
self.wtx_node.wait_for_getdata([tx.sha256], 60)
|
self.wtx_node.wait_for_getdata([tx.sha256], 60)
|
||||||
with p2p_lock:
|
with p2p_lock:
|
||||||
lgd = self.wtx_node.lastgetdata[:]
|
lgd = self.wtx_node.lastgetdata[:]
|
||||||
assert_equal(lgd, [CInv(MSG_TX|MSG_WITNESS_FLAG, tx.sha256)])
|
assert_equal(lgd, [CInv(MSG_WITNESS_TX, tx.sha256)])
|
||||||
|
|
||||||
# Send tx through
|
# Send tx through
|
||||||
test_transaction_acceptance(self.nodes[0], self.wtx_node, tx, with_witness=False, accepted=True)
|
test_transaction_acceptance(self.nodes[0], self.wtx_node, tx, with_witness=False, accepted=True)
|
||||||
|
@ -63,6 +63,7 @@ MSG_CMPCT_BLOCK = 4
|
|||||||
MSG_WTX = 5
|
MSG_WTX = 5
|
||||||
MSG_WITNESS_FLAG = 1 << 30
|
MSG_WITNESS_FLAG = 1 << 30
|
||||||
MSG_TYPE_MASK = 0xffffffff >> 2
|
MSG_TYPE_MASK = 0xffffffff >> 2
|
||||||
|
MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG
|
||||||
|
|
||||||
FILTER_TYPE_BASIC = 0
|
FILTER_TYPE_BASIC = 0
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user