Skip to content

Commit

Permalink
multi: Expose disablerelaytx
Browse files Browse the repository at this point in the history
This setting allows the wallet to not sync mempool transactions when in
SPV mode. This is useful to reduce cpu, memory and bandwidth consumption
for wallets that see very few useful mempool transactions, such as
wallets meant for only occasional use or mobile wallets.

The setting is exposed as a CLI or config argument --spvdisablerelaytx.
  • Loading branch information
matheusd committed Apr 26, 2024
1 parent 44c0f78 commit eb5b1b7
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 8 deletions.
5 changes: 3 additions & 2 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ type config struct {
Offline bool `long:"offline" description:"Do not sync the wallet"`

// SPV options
SPV bool `long:"spv" description:"Sync using simplified payment verification"`
SPVConnect []string `long:"spvconnect" description:"SPV sync only with specified peers; disables DNS seeding"`
SPV bool `long:"spv" description:"Sync using simplified payment verification"`
SPVConnect []string `long:"spvconnect" description:"SPV sync only with specified peers; disables DNS seeding"`
SPVDisableRelayTx bool `long:"spvdisablerelaytx" description:"Disable receiving mempool transactions when in SPV mode"`

// RPC server options
RPCCert *cfgutil.ExplicitString `long:"rpccert" description:"RPC server TLS certificate"`
Expand Down
1 change: 1 addition & 0 deletions dcrwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ func spvLoop(ctx context.Context, w *wallet.Wallet) {
amgr := addrmgr.New(amgrDir, cfg.lookup)
lp := p2p.NewLocalPeer(w.ChainParams(), addr, amgr)
lp.SetDialFunc(cfg.dial)
lp.SetDisableRelayTx(cfg.SPVDisableRelayTx)
syncer := spv.NewSyncer(w, lp)
if len(cfg.SPVConnect) > 0 {
syncer.SetPersistentPeers(cfg.SPVConnect)
Expand Down
53 changes: 47 additions & 6 deletions p2p/peering.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ type LocalPeer struct {
announcedHeaders chan *inMsg
receivedInitState chan *inMsg

extaddr net.Addr
amgr *addrmgr.AddrManager
chainParams *chaincfg.Params
extaddr net.Addr
amgr *addrmgr.AddrManager
chainParams *chaincfg.Params
disableRelayTx bool

rpByID map[uint64]*RemotePeer
rpMu sync.Mutex
Expand Down Expand Up @@ -168,6 +169,13 @@ func (lp *LocalPeer) SetDialFunc(dial DialFunc) {
lp.dial = dial
}

// SetDisableRelayTx sets whether remote peers will be asked to relay
// transactions to the local peer. This must be called before the local peer
// runs.
func (lp *LocalPeer) SetDisableRelayTx(disableRelayTx bool) {
lp.disableRelayTx = disableRelayTx
}

func isCGNAT(ip net.IP) bool {
if ip4 := ip.To4(); ip4 != nil {
return ip4[0] == 100 && ip4[1]&0xc0 == 64 // 100.64.0.0/10
Expand Down Expand Up @@ -210,6 +218,7 @@ func (lp *LocalPeer) newMsgVersion(pver uint32, c net.Conn) (*wire.MsgVersion, e
v := wire.NewMsgVersion(la, ra, nonce, 0)
v.AddUserAgent(uaName, uaVersion)
v.ProtocolVersion = int32(pver)
v.DisableRelayTx = lp.disableRelayTx
return v, nil
}

Expand Down Expand Up @@ -738,9 +747,7 @@ func (rp *RemotePeer) readMessages(ctx context.Context) error {
case *wire.MsgHeaders:
rp.receivedHeaders(ctx, m)
case *wire.MsgInv:
if rp.lp.messageIsMasked(MaskInv) {
rp.lp.receivedInv <- newInMsg(rp, msg)
}
rp.receivedInv(ctx, m)
case *wire.MsgGetMiningState:
rp.receivedGetMiningState(ctx)
case *wire.MsgGetInitState:
Expand Down Expand Up @@ -1847,3 +1854,37 @@ func (rp *RemotePeer) GetInitState(ctx context.Context, msg *wire.MsgGetInitStat
}
}
}

// invVecContainsTx returns true if at least one inv vector is of type
// transaction.
func invVecContainsTx(inv []*wire.InvVect) bool {
for i := range inv {
if inv[i].Type == wire.InvTypeTx {
return true
}
}
return false
}

// receivedInv is called when an inv message is received from the remote peer.
func (rp *RemotePeer) receivedInv(ctx context.Context, inv *wire.MsgInv) {
const opf = "remotepeer(%v).receivedInv"

// When tx relay is disabled, we don't expect transactions on invs.
if rp.lp.disableRelayTx && invVecContainsTx(inv.InvList) {
op := errors.Opf(opf, rp.raddr)
err := errors.E(op, errors.Protocol, "received tx in msginv when tx relaying is disabled")
rp.Disconnect(err)
return
}

// Ignore if the user is not interested in invs.
if !rp.lp.messageIsMasked(MaskInv) {
return
}

select {
case rp.lp.receivedInv <- newInMsg(rp, inv):
case <-ctx.Done():
}
}
18 changes: 18 additions & 0 deletions sample-dcrwallet.conf
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,24 @@
; dcrdpassword=


; ------------------------------------------------------------------------------
; SPV settings
; ------------------------------------------------------------------------------

; Enable SPV mode by setting SPV to 1.
; spv=1

; spvconnect may be used to specify specific peers to connect to, when using
; SPV mode. Multiple peers may be specified. When spvconnect is set, the wallet
; will connect _only_ to the listed peers.
; spvconnect=

; Set spvdisablerelaytx to 1 to disable receiving transactions from remote peers
; in SPV mode. This reduces bandwidth consumption but effectively disables the
; mempool.
; spvdisablerelaytx=1


; ------------------------------------------------------------------------------
; Debug
; ------------------------------------------------------------------------------
Expand Down

0 comments on commit eb5b1b7

Please sign in to comment.