Compare commits

...

2 Commits

Author SHA1 Message Date
Ori Newman
169e92a94b Set DefaultMaxMessages = 20000 2023-11-01 11:20:57 +02:00
Ori Newman
92574e623f
Anti-spam measurements against dust attack (#2223)
* BlockCandidateTransactions patch

* Fix condition

* Fix fee

* Fix bug

* Reject from mempool

* Fix hasCoinbaseInput

* Fix position

* Bump version to v0.12.14
2023-09-26 21:29:17 +03:00
6 changed files with 71 additions and 4 deletions

View File

@ -51,6 +51,7 @@ const (
RejectDifficulty RejectCode = 0x44 RejectDifficulty RejectCode = 0x44
RejectImmatureSpend RejectCode = 0x45 RejectImmatureSpend RejectCode = 0x45
RejectBadOrphan RejectCode = 0x64 RejectBadOrphan RejectCode = 0x64
RejectSpamTx RejectCode = 0x65
) )
// Map of reject codes back strings for pretty printing. // Map of reject codes back strings for pretty printing.

View File

@ -1,6 +1,8 @@
package mempool package mempool
import ( import (
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"sync" "sync"
"github.com/kaspanet/kaspad/domain/consensusreference" "github.com/kaspanet/kaspad/domain/consensusreference"
@ -141,7 +143,57 @@ func (mp *mempool) BlockCandidateTransactions() []*externalapi.DomainTransaction
mp.mtx.RLock() mp.mtx.RLock()
defer mp.mtx.RUnlock() defer mp.mtx.RUnlock()
return mp.transactionsPool.allReadyTransactions() readyTxs := mp.transactionsPool.allReadyTransactions()
var candidateTxs []*externalapi.DomainTransaction
var spamTx *externalapi.DomainTransaction
var spamTxNewestUTXODaaScore uint64
for _, tx := range readyTxs {
if len(tx.Outputs) > len(tx.Inputs) {
hasCoinbaseInput := false
for _, input := range tx.Inputs {
if input.UTXOEntry.IsCoinbase() {
hasCoinbaseInput = true
break
}
}
numExtraOuts := len(tx.Outputs) - len(tx.Inputs)
if !hasCoinbaseInput && numExtraOuts > 2 && tx.Fee < uint64(numExtraOuts)*constants.SompiPerKaspa {
log.Debugf("Filtered spam tx %s", consensushashing.TransactionID(tx))
continue
}
if hasCoinbaseInput || tx.Fee > uint64(numExtraOuts)*constants.SompiPerKaspa {
candidateTxs = append(candidateTxs, tx)
} else {
txNewestUTXODaaScore := tx.Inputs[0].UTXOEntry.BlockDAAScore()
for _, input := range tx.Inputs {
if input.UTXOEntry.BlockDAAScore() > txNewestUTXODaaScore {
txNewestUTXODaaScore = input.UTXOEntry.BlockDAAScore()
}
}
if spamTx != nil {
if txNewestUTXODaaScore < spamTxNewestUTXODaaScore {
spamTx = tx
spamTxNewestUTXODaaScore = txNewestUTXODaaScore
}
} else {
spamTx = tx
spamTxNewestUTXODaaScore = txNewestUTXODaaScore
}
}
} else {
candidateTxs = append(candidateTxs, tx)
}
}
if spamTx != nil {
log.Debugf("Adding spam tx candidate %s", consensushashing.TransactionID(spamTx))
candidateTxs = append(candidateTxs, spamTx)
}
return candidateTxs
} }
func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error) { func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error) {

View File

@ -2,7 +2,6 @@ package mempool
import ( import (
"fmt" "fmt"
"github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"

View File

@ -2,6 +2,7 @@ package mempool
import ( import (
"fmt" "fmt"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
@ -44,6 +45,20 @@ func (mp *mempool) validateTransactionInIsolation(transaction *externalapi.Domai
} }
func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error { func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error {
hasCoinbaseInput := false
for _, input := range transaction.Inputs {
if input.UTXOEntry.IsCoinbase() {
hasCoinbaseInput = true
break
}
}
numExtraOuts := len(transaction.Outputs) - len(transaction.Inputs)
if !hasCoinbaseInput && numExtraOuts > 2 && transaction.Fee < uint64(numExtraOuts)*constants.SompiPerKaspa {
log.Warnf("Rejected spam tx %s from mempool (%d outputs)", consensushashing.TransactionID(transaction), len(transaction.Outputs))
return transactionRuleError(RejectSpamTx, fmt.Sprintf("Rejected spam tx %s from mempool", consensushashing.TransactionID(transaction)))
}
if !mp.config.AcceptNonStandard { if !mp.config.AcceptNonStandard {
err := mp.checkTransactionStandardInContext(transaction) err := mp.checkTransactionStandardInContext(transaction)
if err != nil { if err != nil {

View File

@ -12,7 +12,7 @@ import (
const ( const (
// DefaultMaxMessages is the default capacity for a route with a capacity defined // DefaultMaxMessages is the default capacity for a route with a capacity defined
DefaultMaxMessages = 200 DefaultMaxMessages = 20000
) )
var ( var (

View File

@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
const ( const (
appMajor uint = 0 appMajor uint = 0
appMinor uint = 12 appMinor uint = 12
appPatch uint = 13 appPatch uint = 14
) )
// appBuild is defined as a variable so it can be overridden during the build // appBuild is defined as a variable so it can be overridden during the build