From 2510baac35b6eb86a4a96ce8eab4cd8c49c1b0ca Mon Sep 17 00:00:00 2001 From: David Hill Date: Fri, 28 Oct 2016 12:50:08 -0400 Subject: [PATCH] btcd: support feefilter requests. This only adds support for handling remote peer requests. --- btcjson/chainsvrresults.go | 1 + mempool/mempool.go | 9 +++++---- mining/mining.go | 6 ++++-- rpcserver.go | 1 + rpcserverhelp.go | 1 + server.go | 40 ++++++++++++++++++++++++++++++-------- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 183cc017..4ab80767 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -179,6 +179,7 @@ type GetPeerInfoResult struct { StartingHeight int32 `json:"startingheight"` CurrentHeight int32 `json:"currentheight,omitempty"` BanScore int32 `json:"banscore"` + FeeFilter int64 `json:"feefilter"` SyncNode bool `json:"syncnode"` } diff --git a/mempool/mempool.go b/mempool/mempool.go index c669cb35..89ddee7f 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -510,10 +510,11 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil // as spent by the pool. txD := &TxDesc{ TxDesc: mining.TxDesc{ - Tx: tx, - Added: time.Now(), - Height: height, - Fee: fee, + Tx: tx, + Added: time.Now(), + Height: height, + Fee: fee, + FeePerKB: fee * 1000 / int64(tx.MsgTx().SerializeSize()), }, StartingPriority: mining.CalcPriority(tx.MsgTx(), utxoView, height), } diff --git a/mining/mining.go b/mining/mining.go index 5c36c5cd..4e8d99fa 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -55,6 +55,9 @@ type TxDesc struct { // Fee is the total fee the transaction associated with the entry pays. Fee int64 + + // FeePerKB is the fee the transaction pays in Satoshi per 1000 bytes. + FeePerKB int64 } // TxSource represents a source of transactions to consider for inclusion in @@ -575,8 +578,7 @@ mempoolLoop: nextBlockHeight) // Calculate the fee in Satoshi/kB. - txSize := tx.MsgTx().SerializeSize() - prioItem.feePerKB = (txDesc.Fee * 1000) / int64(txSize) + prioItem.feePerKB = txDesc.FeePerKB prioItem.fee = txDesc.Fee // Add the transaction to the priority queue to mark it ready diff --git a/rpcserver.go b/rpcserver.go index c039c7a8..87541df7 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2229,6 +2229,7 @@ func handleGetPeerInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) StartingHeight: statsSnap.StartingHeight, CurrentHeight: statsSnap.LastBlock, BanScore: int32(p.banScore.Int()), + FeeFilter: atomic.LoadInt64(&p.feeFilter), SyncNode: p == syncPeer, } if p.LastPingNonce() != 0 { diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 727bc0e5..2adaef29 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -391,6 +391,7 @@ var helpDescsEnUS = map[string]string{ "getpeerinforesult-startingheight": "The latest block height the peer knew about when the connection was established", "getpeerinforesult-currentheight": "The current height of the peer", "getpeerinforesult-banscore": "The ban score", + "getpeerinforesult-feefilter": "The requested minimum fee a transaction must have to be announced to the peer", "getpeerinforesult-syncnode": "Whether or not the peer is the sync peer", // GetPeerInfoCmd help. diff --git a/server.go b/server.go index 82c1ee0b..9b3e045d 100644 --- a/server.go +++ b/server.go @@ -181,6 +181,9 @@ type server struct { // serverPeer extends the peer to maintain state shared by the server and // the blockmanager. type serverPeer struct { + // The following variables must only be used atomically + feeFilter int64 + *peer.Peer connReq *connmgr.ConnReq @@ -782,6 +785,18 @@ func (sp *serverPeer) enforceNodeBloomFlag(cmd string) bool { return true } +func (sp *serverPeer) OnFeeFilter(p *peer.Peer, msg *wire.MsgFeeFilter) { + // Check that the passed minimum fee is a valid amount. + if msg.MinFee < 0 || msg.MinFee > btcutil.MaxSatoshi { + peerLog.Debugf("Peer %v sent an invalid feefilter '%v' -- "+ + "disconnecting", sp, btcutil.Amount(msg.MinFee)) + sp.Disconnect() + return + } + + atomic.StoreInt64(&sp.feeFilter, msg.MinFee) +} + // OnFilterAdd is invoked when a peer receives a filteradd bitcoin // message and is used by remote peers to add data to an already loaded bloom // filter. The peer will be disconnected if a filter is not loaded when this @@ -1316,16 +1331,24 @@ func (s *server) handleRelayInvMsg(state *peerState, msg relayMsg) { if sp.relayTxDisabled() { return } + + txD, ok := msg.data.(*mempool.TxDesc) + if !ok { + peerLog.Warnf("Underlying data for tx" + + " inv relay is not a *mempool.TxDesc") + return + } + + // Don't relay the transaction if the transaction fee-per-kb + // is less than the peer's feefilter. + feeFilter := atomic.LoadInt64(&sp.feeFilter) + if feeFilter > 0 && txD.FeePerKB < feeFilter { + return + } + // Don't relay the transaction if there is a bloom // filter loaded and the transaction doesn't match it. if sp.filter.IsLoaded() { - txD, ok := msg.data.(*mempool.TxDesc) - if !ok { - peerLog.Warnf("Underlying data for tx" + - " inv relay is not a *mempool.TxDesc") - return - } - if !sp.filter.MatchTxAndUpdate(txD.Tx) { return } @@ -1528,6 +1551,7 @@ func newPeerConfig(sp *serverPeer) *peer.Config { OnGetData: sp.OnGetData, OnGetBlocks: sp.OnGetBlocks, OnGetHeaders: sp.OnGetHeaders, + OnFeeFilter: sp.OnFeeFilter, OnFilterAdd: sp.OnFilterAdd, OnFilterClear: sp.OnFilterClear, OnFilterLoad: sp.OnFilterLoad, @@ -1550,7 +1574,7 @@ func newPeerConfig(sp *serverPeer) *peer.Config { ChainParams: sp.server.chainParams, Services: sp.server.services, DisableRelayTx: cfg.BlocksOnly, - ProtocolVersion: wire.SendHeadersVersion, + ProtocolVersion: wire.FeeFilterVersion, } }