Rate limit free-to-relay transactions.

Closes #40

ok @davecgh
This commit is contained in:
Owain G. Ainsworth 2014-02-19 18:15:47 +00:00
parent 28929ff429
commit cb1f3cf48c
3 changed files with 32 additions and 3 deletions

View file

@ -37,6 +37,7 @@ const (
defaultMaxRPCWebsockets = 25
defaultVerifyEnabled = false
defaultDbType = "leveldb"
defaultFreeTxRelayLimit = 15.0
)
var (
@ -93,6 +94,7 @@ type config struct {
CpuProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"`
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`
Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"`
FreeTxRelayLimit float64 `long:"limitfreerelay" description:"Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute"`
onionlookup func(string) ([]net.IP, error)
lookup func(string) ([]net.IP, error)
oniondial func(string, string) (net.Conn, error)
@ -293,6 +295,7 @@ func loadConfig() (*config, []string, error) {
DbType: defaultDbType,
RPCKey: defaultRPCKeyFile,
RPCCert: defaultRPCCertFile,
FreeTxRelayLimit: defaultFreeTxRelayLimit,
}
// Service options which are only added on Windows.

3
doc.go
View file

@ -74,6 +74,9 @@ Application Options:
the log level for individual subsystems -- Use show
to list available subsystems (info)
--upnp Use UPnP to map our listening port outside of NAT
--limitfreerelay= Limit relay of transactions with no transaction fee
to the given amount in thousands of bytes per minute
(15)
Help Options:
-h, --help Show this help message

View file

@ -97,6 +97,9 @@ type txMemPool struct {
orphans map[btcwire.ShaHash]*btcutil.Tx
orphansByPrev map[btcwire.ShaHash]*list.List
outpoints map[btcwire.OutPoint]*btcutil.Tx
pennyTotal float64 // exponentially decaying total for penny spends.
lastPennyUnix int64 // unix time of last ``penny spend''
}
// isDust returns whether or not the passed transaction output amount is
@ -858,9 +861,29 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isOrphan *bool, isNe
return TxRuleError(str)
}
// TODO(davec): Rate-limit 'free' transactions. That is to say
// transactions which are less than the minimum relay fee and are
// therefore considered free.
// Free-to-relay transactions are rate limited here to prevent
// penny-flooding with tiny transactions as a form of attack.
if minRequiredFee == 0 {
nowUnix := time.Now().Unix()
// we decay passed data with an exponentially decaying ~10
// minutes window - matches bitcoind handling.
mp.pennyTotal *= math.Pow(1.0-1.0/600.0,
float64(nowUnix-mp.lastPennyUnix))
mp.lastPennyUnix = nowUnix
// Are we still over the limit?
if mp.pennyTotal >= cfg.FreeTxRelayLimit*10*1000 {
str := fmt.Sprintf("transaction %v has 0 fees and has "+
"been rejected by the rate limiter", txHash)
return TxRuleError(str)
}
oldTotal := mp.pennyTotal
mp.pennyTotal += float64(tx.MsgTx().SerializeSize())
txmpLog.Debugf("rate limit: curTotal %v, nextTotal: %v, "+
"limit %v", oldTotal, mp.pennyTotal,
cfg.FreeTxRelayLimit*10*1000)
}
// Verify crypto signatures for each input and reject the transaction if
// any don't verify.