kaspad/domain/miningmanager/mempool/validate_transaction.go
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

80 lines
2.6 KiB
Go

package mempool
import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
)
func (mp *mempool) validateTransactionPreUTXOEntry(transaction *externalapi.DomainTransaction) error {
err := mp.validateTransactionInIsolation(transaction)
if err != nil {
return err
}
if err := mp.mempoolUTXOSet.checkDoubleSpends(transaction); err != nil {
return err
}
return nil
}
func (mp *mempool) validateTransactionInIsolation(transaction *externalapi.DomainTransaction) error {
transactionID := consensushashing.TransactionID(transaction)
if _, ok := mp.transactionsPool.allTransactions[*transactionID]; ok {
return transactionRuleError(RejectDuplicate,
fmt.Sprintf("transaction %s is already in the mempool", transactionID))
}
if !mp.config.AcceptNonStandard {
if err := mp.checkTransactionStandardInIsolation(transaction); err != nil {
// Attempt to extract a reject code from the error so
// it can be retained. When not possible, fall back to
// a non standard error.
rejectCode, found := extractRejectCode(err)
if !found {
rejectCode = RejectNonstandard
}
str := fmt.Sprintf("transaction %s is not standard: %s", transactionID, err)
return transactionRuleError(rejectCode, str)
}
}
return nil
}
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 {
err := mp.checkTransactionStandardInContext(transaction)
if err != nil {
// Attempt to extract a reject code from the error so
// it can be retained. When not possible, fall back to
// a non standard error.
rejectCode, found := extractRejectCode(err)
if !found {
rejectCode = RejectNonstandard
}
str := fmt.Sprintf("transaction inputs %s are not standard: %s",
consensushashing.TransactionID(transaction), err)
return transactionRuleError(rejectCode, str)
}
}
return nil
}