mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-25 00:06:49 +00:00

* [NOD-1551] Make UTXO-Diff implemented fully in utils/utxo * [NOD-1551] Fixes everywhere except database * [NOD-1551] Fix database * [NOD-1551] Add comments * [NOD-1551] Partial commit * [NOD-1551] Comlete making UTXOEntry immutable + don't clone it in UTXOCollectionClone * [NOD-1551] Rename ToUnmutable -> ToImmutable * [NOD-1551] Track immutable references generated from mutable UTXODiff, and invalidate them if the mutable one changed * [NOD-1551] Clone scriptPubKey in NewUTXOEntry * [NOD-1551] Remove redundant code * [NOD-1551] Remove redundant call for .CloneMutable and then .ToImmutable * [NOD-1551] Make utxoEntry pointert-receiver + clone ScriptPubKey in getter
104 lines
4.0 KiB
Go
104 lines
4.0 KiB
Go
package mempool
|
|
|
|
import (
|
|
"math"
|
|
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
|
|
|
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const unacceptedBlueScore = math.MaxUint64
|
|
|
|
func newMempoolUTXOSet() *mempoolUTXOSet {
|
|
return &mempoolUTXOSet{
|
|
transactionByPreviousOutpoint: make(map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.DomainTransaction),
|
|
poolUnspentOutputs: make(map[consensusexternalapi.DomainOutpoint]consensusexternalapi.UTXOEntry),
|
|
}
|
|
}
|
|
|
|
type mempoolUTXOSet struct {
|
|
transactionByPreviousOutpoint map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.DomainTransaction
|
|
poolUnspentOutputs map[consensusexternalapi.DomainOutpoint]consensusexternalapi.UTXOEntry
|
|
}
|
|
|
|
// Populate UTXO Entries in the transaction, to allow chained txs.
|
|
func (mpus *mempoolUTXOSet) populateUTXOEntries(tx *consensusexternalapi.DomainTransaction) (parentsInPool []consensusexternalapi.DomainOutpoint) {
|
|
for _, txIn := range tx.Inputs {
|
|
if utxoEntry, exists := mpus.poolUnspentOutputs[txIn.PreviousOutpoint]; exists {
|
|
txIn.UTXOEntry = utxoEntry
|
|
parentsInPool = append(parentsInPool, txIn.PreviousOutpoint)
|
|
}
|
|
}
|
|
return parentsInPool
|
|
}
|
|
|
|
func (mpus *mempoolUTXOSet) checkExists(tx *consensusexternalapi.DomainTransaction) bool {
|
|
// Check if it was already spent.
|
|
for _, txIn := range tx.Inputs {
|
|
if _, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; exists {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// Check if it creates an already existing UTXO
|
|
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)}
|
|
for i := range tx.Outputs {
|
|
outpoint.Index = uint32(i)
|
|
if _, exists := mpus.poolUnspentOutputs[outpoint]; exists {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// addTx adds a transaction to the mempool UTXO set. It assumes that it doesn't double spend another transaction
|
|
// in the mempool, and that its outputs doesn't exist in the mempool UTXO set, and returns error otherwise.
|
|
func (mpus *mempoolUTXOSet) addTx(tx *consensusexternalapi.DomainTransaction) error {
|
|
for _, txIn := range tx.Inputs {
|
|
if existingTx, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; exists {
|
|
return errors.Errorf("outpoint %s is already used by %s", txIn.PreviousOutpoint, consensushashing.TransactionID(existingTx))
|
|
}
|
|
mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint] = tx
|
|
}
|
|
|
|
for i, txOut := range tx.Outputs {
|
|
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx), Index: uint32(i)}
|
|
if _, exists := mpus.poolUnspentOutputs[outpoint]; exists {
|
|
return errors.Errorf("outpoint %s already exists", outpoint)
|
|
}
|
|
mpus.poolUnspentOutputs[outpoint] =
|
|
utxo.NewUTXOEntry(txOut.Value, txOut.ScriptPublicKey, false, unacceptedBlueScore)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// removeTx removes a transaction to the mempool UTXO set.
|
|
// Note: it doesn't re-add its previous outputs to the mempool UTXO set.
|
|
func (mpus *mempoolUTXOSet) removeTx(tx *consensusexternalapi.DomainTransaction) error {
|
|
for _, txIn := range tx.Inputs {
|
|
if _, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; !exists {
|
|
return errors.Errorf("outpoint %s doesn't exist", txIn.PreviousOutpoint)
|
|
}
|
|
delete(mpus.transactionByPreviousOutpoint, txIn.PreviousOutpoint)
|
|
}
|
|
|
|
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)}
|
|
for i := range tx.Outputs {
|
|
outpoint.Index = uint32(i)
|
|
if _, exists := mpus.poolUnspentOutputs[outpoint]; !exists {
|
|
return errors.Errorf("outpoint %s doesn't exist", outpoint)
|
|
}
|
|
delete(mpus.poolUnspentOutputs, outpoint)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mpus *mempoolUTXOSet) poolTransactionBySpendingOutpoint(outpoint consensusexternalapi.DomainOutpoint) (*consensusexternalapi.DomainTransaction, bool) {
|
|
tx, exists := mpus.transactionByPreviousOutpoint[outpoint]
|
|
return tx, exists
|
|
}
|