kaspad/domain/mempool/mempool_utxoset.go
Ori Newman 6ab8ada9ff
[NOD-1406] remove mempool utxo diff (#938)
* [NOD-1406] Remove mempool UTXO diff

* [NOD-1406] Fix mempool tests

* [NOD-1406] Fetch mempool transactions before locking the dag in NewBlockTemplate

* [NOD-1406] Remove redundant comment

* [NOD-1406] Move mempool UTXO set to a different file

* [NOD-1406] Fix transactionRelatedUTXOEntries receiver's name

* [NOD-1406] Fix variable names and fix comments

* [NOD-1406] Rename inputsWithUTXOEntries->referencedUTXOEntries

* [NOD-1406] Remove debug logs
2020-09-27 16:40:07 +03:00

116 lines
3.8 KiB
Go

package mempool
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/blockdag"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/daghash"
"github.com/pkg/errors"
)
func newMempoolUTXOSet(dag *blockdag.BlockDAG) *mempoolUTXOSet {
return &mempoolUTXOSet{
transactionByPreviousOutpoint: make(map[appmessage.Outpoint]*util.Tx),
poolUnspentOutputs: make(map[appmessage.Outpoint]*blockdag.UTXOEntry),
dag: dag,
}
}
type mempoolUTXOSet struct {
transactionByPreviousOutpoint map[appmessage.Outpoint]*util.Tx
poolUnspentOutputs map[appmessage.Outpoint]*blockdag.UTXOEntry
dag *blockdag.BlockDAG
}
func (mpus *mempoolUTXOSet) utxoEntryByOutpoint(outpoint appmessage.Outpoint) (entry *blockdag.UTXOEntry, isInPool bool, exists bool) {
entry, exists = mpus.dag.GetUTXOEntry(outpoint)
if !exists {
entry, exists := mpus.poolUnspentOutputs[outpoint]
if !exists {
return nil, false, false
}
return entry, true, true
}
return entry, false, true
}
// 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 *util.Tx) error {
msgTx := tx.MsgTx()
for _, txIn := range msgTx.TxIn {
if existingTx, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; exists {
return errors.Errorf("outpoint %s is already used by %s", txIn.PreviousOutpoint, existingTx.ID())
}
mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint] = tx
}
for i, txOut := range msgTx.TxOut {
outpoint := appmessage.NewOutpoint(tx.ID(), uint32(i))
if _, exists := mpus.poolUnspentOutputs[*outpoint]; exists {
return errors.Errorf("outpoint %s already exists", outpoint)
}
mpus.poolUnspentOutputs[*outpoint] = blockdag.NewUTXOEntry(txOut, false, blockdag.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 *util.Tx) error {
msgTx := tx.MsgTx()
for _, txIn := range msgTx.TxIn {
if _, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; !exists {
return errors.Errorf("outpoint %s doesn't exist", txIn.PreviousOutpoint)
}
delete(mpus.transactionByPreviousOutpoint, txIn.PreviousOutpoint)
}
for i := range msgTx.TxOut {
outpoint := appmessage.NewOutpoint(tx.ID(), 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 appmessage.Outpoint) (*util.Tx, bool) {
tx, exists := mpus.transactionByPreviousOutpoint[outpoint]
return tx, exists
}
func (mpus *mempoolUTXOSet) transactionRelatedUTXOEntries(tx *util.Tx) (spentUTXOEntries []*blockdag.UTXOEntry, parentsInPool []*appmessage.Outpoint, missingParents []*daghash.TxID) {
msgTx := tx.MsgTx()
spentUTXOEntries = make([]*blockdag.UTXOEntry, len(msgTx.TxIn))
missingParents = make([]*daghash.TxID, 0)
parentsInPool = make([]*appmessage.Outpoint, 0)
isOrphan := false
for i, txIn := range msgTx.TxIn {
entry, isInPool, exists := mpus.utxoEntryByOutpoint(txIn.PreviousOutpoint)
if !exists {
isOrphan = true
missingParents = append(missingParents, &txIn.PreviousOutpoint.TxID)
}
if isOrphan {
continue
}
if isInPool {
parentsInPool = append(parentsInPool, &txIn.PreviousOutpoint)
}
spentUTXOEntries[i] = entry
}
if isOrphan {
return nil, nil, missingParents
}
return spentUTXOEntries, parentsInPool, nil
}