diff --git a/src/init.cpp b/src/init.cpp index 6dfe22404d..20d0059514 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -608,7 +608,7 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to given address and whitelist peers connecting to it. " "Use [host]:port notation for IPv6. Allowed permissions are bloomfilter (allow requesting BIP37 filtered blocks and transactions), " "noban (do not ban for misbehavior), " - "forcerelay (relay even non-standard transactions), " + "forcerelay (relay transactions that are already in the mempool; implies relay), " "relay (relay even in -blocksonly mode), " "and mempool (allow requesting BIP35 mempool contents). " "Specify multiple permissions separated by commas (default: noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -753,7 +753,7 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool or violate local relay policy. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-whitelistrelay", strprintf("Add 'relay' permission to whitelisted inbound peers with default permissions. This will accept relayed transactions even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-blockmaxsize=", strprintf("Set maximum block size in bytes (default: %d)", DEFAULT_BLOCK_MAX_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); diff --git a/src/net_permissions.h b/src/net_permissions.h index e8dac927a9..4066c73133 100644 --- a/src/net_permissions.h +++ b/src/net_permissions.h @@ -18,7 +18,7 @@ enum NetPermissionFlags PF_BLOOMFILTER = (1U << 1), // Relay and accept transactions from this peer, even if -blocksonly is true PF_RELAY = (1U << 3), - // Always relay transactions from this peer, even if already in mempool or rejected from policy + // Always relay transactions from this peer, even if already in mempool // Keep parameter interaction: forcerelay implies relay PF_FORCERELAY = (1U << 2) | PF_RELAY, // Can't be banned/disconnected/discouraged for misbehavior diff --git a/src/net_processing.cpp b/src/net_processing.cpp index eada299bbc..45fa731410 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1167,17 +1167,6 @@ bool IsBanned(NodeId pnode) return false; } -/** - * Returns true if the given validation state result may result in a peer - * banning/disconnecting us. We use this to determine which unaccepted - * transactions from a whitelisted peer that we can safely relay. - */ -static bool TxRelayMayResultInDisconnect(const CValidationState& state) -{ - assert(IsTransactionReason(state.GetReason())); - return state.GetReason() == ValidationInvalidReason::CONSENSUS; -} - /** * Potentially mark a node discouraged based on the contents of a CValidationState object * @@ -1187,10 +1176,9 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state) * txs, the peer should not be punished. See BIP 152. * * @return Returns true if the peer was punished (probably disconnected) - * - * Changes here may need to be reflected in TxRelayMayResultInDisconnect(). */ -static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") { +static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") +{ switch (state.GetReason()) { case ValidationInvalidReason::NONE: break; @@ -1254,12 +1242,6 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v } - - - - - - ////////////////////////////////////////////////////////////////////////////// // // blockchain -> download logic notification @@ -3469,14 +3451,11 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (pfrom->HasPermission(PF_FORCERELAY)) { // Always relay transactions received from whitelisted peers, even - // if they were already in the mempool or rejected from it due - // to policy, allowing the node to function as a gateway for + // if they were already in the mempool, + // allowing the node to function as a gateway for // nodes hidden behind it. - // - // Never relay transactions that might result in being - // disconnected (or banned). - if (state.IsInvalid() && TxRelayMayResultInDisconnect(state)) { - LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state)); + if (!mempool.exists(tx.GetHash())) { + LogPrintf("Not relaying non-mempool transaction %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->GetId()); } else { LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->GetId()); RelayTransaction(tx.GetHash(), *connman); diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index aa7f8f10d2..c1d87d5ff2 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -140,6 +140,16 @@ class P2PPermissionsTests(BitcoinTestFramework): p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1]) wait_until(in_mempool) + self.log.debug("Check that node[1] will not send an invalid tx to node[0]") + tx.vout[0].nValue += 1 + txid = tx.rehash() + p2p_rebroadcast_wallet.send_txs_and_test( + [tx], + self.nodes[1], + success=False, + reject_reason='Not relaying non-mempool transaction {} from whitelisted peer=0'.format(txid), + ) + def checkpermission(self, args, expectedPermissions, whitelisted): self.restart_node(1, args) self.connect_nodes(0, 1)