kaspad/domain/miningmanager/mempool/mempool_utxo_set.go
Svarog 639183ba0e
Add support for auto-compound in kaspawallet send (#1951)
* Add GetUTXOsByBalances command to rpc

* Fix wrong commands in GetBalanceByAddress

* Moved calculation of TransactionMass out of TransactionValidator, so t that it can be used in kaspawallet

* Allow CreateUnsignedTransaction to return multiple transactions

* Start working on split

* Implement maybeSplitTransactionInner

* estimateMassIncreaseForSignatures should multiply by the number of inputs

* Implement createSplitTransaction

* Implement mergeTransactions

* Broadcast all transaction, not only 1

* workaround missing UTXOEntry in partially signed transaction

* Bugfix in broadcast loop

* Add underscores in some constants

* Make all nets RelayNonStdTxs: false

* Change estimateMassIncreaseForSignatures to estimateMassAfterSignatures

* Allow situations where merge transaction doesn't have enough funds to pay fees

* Add comments

* A few of renames

* Handle missed errors

* Fix clone of PubKeySignaturePair  to properly clone nil signatures

* Add sanity check to make sure originalTransaction has exactly two outputs

* Re-use change address for splitAddress

* Add one more utxo if the total amount is smaller then what we need to send due to fees

* Fix off-by-1 error in splitTrasnaction

* Add a comment to maybeAutoCompoundTransaction

* Add comment on why we are increasing inputCountPerSplit

* Add comment explaining while originalTransaction has 1 or 2 outputs

* Move oneMoreUTXOForMergeTransaction to split_transaction.go

* Allow to add multiple utxos to pay fee for mergeTransactions, if needed

* calculate split input counts and sizes properly

* Allow multiple transactions inside the create-unsigned-transaction -> sign -> broadcast workflow

* Print the number of transaction which was sent, in case there were multiple

* Rename broadcastConfig.Transaction(File) to Transactions(File)

* Convert alreadySelectedUTXOs to a map

* Fix a typo

* Add comment explaining that we assume all inputs are the same

* Revert over-refactor of rename of config.Transaction -> config.Transactions

* Rename: inputPerSplitCount -> inputsPerSplitCount

* Add comment for splitAndInputPerSplitCounts

* Use createSplitTransaction to calculate the upper bound of mass for split transactions
2022-03-27 20:06:55 +03:00

83 lines
3.0 KiB
Go

package mempool
import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
)
type mempoolUTXOSet struct {
mempool *mempool
poolUnspentOutputs model.OutpointToUTXOEntryMap
transactionByPreviousOutpoint model.OutpointToTransactionMap
}
func newMempoolUTXOSet(mp *mempool) *mempoolUTXOSet {
return &mempoolUTXOSet{
mempool: mp,
poolUnspentOutputs: model.OutpointToUTXOEntryMap{},
transactionByPreviousOutpoint: model.OutpointToTransactionMap{},
}
}
func (mpus *mempoolUTXOSet) addTransaction(transaction *model.MempoolTransaction) {
outpoint := &externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID()}
for i, input := range transaction.Transaction().Inputs {
outpoint.Index = uint32(i)
// Delete the output this input spends, in case it was created by mempool.
// If the outpoint doesn't exist in mpus.poolUnspentOutputs - this means
// it was created in the DAG (a.k.a. in consensus).
delete(mpus.poolUnspentOutputs, *outpoint)
mpus.transactionByPreviousOutpoint[input.PreviousOutpoint] = transaction
}
for i, output := range transaction.Transaction().Outputs {
outpoint := externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID(), Index: uint32(i)}
mpus.poolUnspentOutputs[outpoint] =
utxo.NewUTXOEntry(output.Value, output.ScriptPublicKey, false, constants.UnacceptedDAAScore)
}
}
func (mpus *mempoolUTXOSet) removeTransaction(transaction *model.MempoolTransaction) {
for _, input := range transaction.Transaction().Inputs {
// If the transaction creating the output spent by this input is in the mempool - restore it's UTXO
if _, ok := mpus.mempool.transactionsPool.getTransaction(&input.PreviousOutpoint.TransactionID); ok {
mpus.poolUnspentOutputs[input.PreviousOutpoint] = input.UTXOEntry
}
delete(mpus.transactionByPreviousOutpoint, input.PreviousOutpoint)
}
outpoint := externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID()}
for i := range transaction.Transaction().Outputs {
outpoint.Index = uint32(i)
delete(mpus.poolUnspentOutputs, outpoint)
}
}
func (mpus *mempoolUTXOSet) checkDoubleSpends(transaction *externalapi.DomainTransaction) error {
outpoint := externalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(transaction)}
for i, input := range transaction.Inputs {
outpoint.Index = uint32(i)
if existingTransaction, exists := mpus.transactionByPreviousOutpoint[input.PreviousOutpoint]; exists {
str := fmt.Sprintf("output %s already spent by transaction %s in the memory pool",
input.PreviousOutpoint, existingTransaction.TransactionID())
return transactionRuleError(RejectDuplicate, str)
}
}
return nil
}