[NOD-1512] Implement utxo deserialization (#1003)

* [NOD-1512] Implement UTXO set deserialization

* [NOD-1512] Remove redundant file

* [NOD-1512] Don't use big endian for serialization

* [NOD-1512] Use Read/Write element

* [NOD-1512] Unexport ReadElement

* [NOD-1512] Fix StageVirtualUTXOSet

* [NOD-1512] Get rid of dagParams in consensusStateManager

* [NOD-1512] Get rid of dagParams in consensusStateManager
This commit is contained in:
Ori Newman 2020-11-05 00:59:49 -08:00 committed by GitHub
parent 52c73d3a08
commit 5566aaf95a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 415 additions and 250 deletions

View File

@ -180,7 +180,7 @@ func (u utxoSetIterator) Next() bool {
return u.cursor.Next()
}
func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry) {
func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) {
key, err := u.cursor.Key()
if err != nil {
panic(err)
@ -188,20 +188,20 @@ func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry
utxoEntryBytes, err := u.cursor.Value()
if err != nil {
panic(err)
return nil, nil, err
}
outpoint, err = deserializeOutpoint(key.Suffix())
if err != nil {
panic(err)
return nil, nil, err
}
utxoEntry, err = deserializeUTXOEntry(utxoEntryBytes)
if err != nil {
panic(err)
return nil, nil, err
}
return outpoint, utxoEntry
return outpoint, utxoEntry, nil
}
func (c consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error {
@ -211,7 +211,11 @@ func (c consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.Re
c.stagedVirtualUTXOSet = make(model.UTXOCollection)
for virtualUTXOSetIterator.Next() {
outpoint, entry := virtualUTXOSetIterator.Get()
outpoint, entry, err := virtualUTXOSetIterator.Get()
if err != nil {
return err
}
if _, exists := c.stagedVirtualUTXOSet[*outpoint]; exists {
return errors.Errorf("outpoint %s is found more than once in the given iterator", outpoint)
}

View File

@ -136,7 +136,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
)
consensusStateManager, err := consensusstatemanager.New(
dbManager,
dagParams,
dagParams.FinalityDepth(),
dagParams.PruningDepth(),
ghostdagManager,
dagTopologyManager,
dagTraversalManager,

View File

@ -12,5 +12,5 @@ type ReadOnlyUTXOSet interface {
// ReadOnlyUTXOSet
type ReadOnlyUTXOSetIterator interface {
Next() bool
Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry)
Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error)
}

View File

@ -7,7 +7,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
"github.com/kaspanet/kaspad/util/mstime"
@ -132,8 +132,8 @@ func (bp *blockProcessor) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHas
}
}
sort.Slice(acceptedTransactions, func(i, j int) bool {
acceptedTransactionIID := hashserialization.TransactionID(acceptedTransactions[i])
acceptedTransactionJID := hashserialization.TransactionID(acceptedTransactions[j])
acceptedTransactionIID := consensusserialization.TransactionID(acceptedTransactions[i])
acceptedTransactionJID := consensusserialization.TransactionID(acceptedTransactions[j])
return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID)
})

View File

@ -3,7 +3,7 @@ package blockprocessor
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/pkg/errors"
)
@ -17,7 +17,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
return errors.Errorf("cannot insert blocks while in %s mode", mode.State)
}
hash := hashserialization.HeaderHash(block.Header)
hash := consensusserialization.HeaderHash(block.Header)
if mode.State == externalapi.SyncStateHeadersFirst && len(block.Transactions) != 0 {
return errors.Errorf("block %s contains transactions while validating in header only mode", hash)
}
@ -148,7 +148,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex
return err
}
blockHash := hashserialization.HeaderHash(block.Header)
blockHash := consensusserialization.HeaderHash(block.Header)
err = bp.blockValidator.ValidateProofOfWorkAndDifficulty(blockHash)
if err != nil {
return err
@ -160,7 +160,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
bp.discardAllChanges()
hash := hashserialization.HeaderHash(block.Header)
hash := consensusserialization.HeaderHash(block.Header)
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
commitErr := bp.commitAllChanges()
if commitErr != nil {
@ -173,7 +173,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex
}
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
blockHash := hashserialization.HeaderHash(block.Header)
blockHash := consensusserialization.HeaderHash(block.Header)
hasHeader, err := bp.hasHeader(blockHash)
if err != nil {
@ -192,7 +192,7 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock)
}
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, mode *externalapi.SyncInfo) error {
blockHash := hashserialization.HeaderHash(block.Header)
blockHash := consensusserialization.HeaderHash(block.Header)
if mode.State != externalapi.SyncStateHeadersFirst {
bp.blockStore.Stage(blockHash, block)

View File

@ -3,7 +3,7 @@ package blockvalidator
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
"github.com/pkg/errors"
"math"
@ -40,7 +40,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.
// Ensure all transactions in the block are finalized.
for _, tx := range block.Transactions {
if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore, blockTime) {
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains unfinalized "+
"transaction %s", txID)
}

View File

@ -3,9 +3,9 @@ package blockvalidator
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
@ -141,7 +141,7 @@ func (v *blockValidator) checkTransactionsInIsolation(block *externalapi.DomainB
err := v.transactionValidator.ValidateTransactionInIsolation(tx)
if err != nil {
return errors.Wrapf(err, "transaction %s failed isolation "+
"check", hashserialization.TransactionID(tx))
"check", consensusserialization.TransactionID(tx))
}
}
@ -161,7 +161,7 @@ func (v *blockValidator) checkBlockHashMerkleRoot(block *externalapi.DomainBlock
func (v *blockValidator) checkBlockDuplicateTransactions(block *externalapi.DomainBlock) error {
existingTxIDs := make(map[externalapi.DomainTransactionID]struct{})
for _, tx := range block.Transactions {
id := hashserialization.TransactionID(tx)
id := consensusserialization.TransactionID(tx)
if _, exists := existingTxIDs[*id]; exists {
return errors.Wrapf(ruleerrors.ErrDuplicateTx, "block contains duplicate "+
"transaction %s", id)
@ -175,7 +175,7 @@ func (v *blockValidator) checkBlockDoubleSpends(block *externalapi.DomainBlock)
usedOutpoints := make(map[externalapi.DomainOutpoint]*externalapi.DomainTransactionID)
for _, tx := range block.Transactions {
for _, input := range tx.Inputs {
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
if spendingTxID, exists := usedOutpoints[input.PreviousOutpoint]; exists {
return errors.Wrapf(ruleerrors.ErrDoubleSpendInSameBlock, "transaction %s spends "+
"outpoint %s that was already spent by "+
@ -193,14 +193,14 @@ func (v *blockValidator) checkBlockHasNoChainedTransactions(block *externalapi.D
transactions := block.Transactions
transactionsSet := make(map[externalapi.DomainTransactionID]struct{}, len(transactions))
for _, transaction := range transactions {
txID := hashserialization.TransactionID(transaction)
txID := consensusserialization.TransactionID(transaction)
transactionsSet[*txID] = struct{}{}
}
for _, transaction := range transactions {
for i, transactionInput := range transaction.Inputs {
if _, ok := transactionsSet[transactionInput.PreviousOutpoint.TransactionID]; ok {
txID := hashserialization.TransactionID(transaction)
txID := consensusserialization.TransactionID(transaction)
return errors.Wrapf(ruleerrors.ErrChainedTransactions, "block contains chained "+
"transactions: Input %d of transaction %s spend "+
"an output of transaction %s", i, txID, transactionInput.PreviousOutpoint.TransactionID)

View File

@ -3,8 +3,8 @@ package blockvalidator
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/pkg/errors"
)
@ -81,7 +81,7 @@ func (v *blockValidator) validateMedianTime(header *externalapi.DomainBlockHeade
return nil
}
hash := hashserialization.HeaderHash(header)
hash := consensusserialization.HeaderHash(header)
ghostdagData, err := v.ghostdagDataStore.Get(v.databaseContext, hash)
if err != nil {
return err

View File

@ -5,9 +5,9 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/pkg/errors"
)
@ -33,7 +33,7 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain
}
func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader) error {
hash := hashserialization.HeaderHash(header)
hash := consensusserialization.HeaderHash(header)
if len(header.ParentHashes) == 0 && *hash != *v.genesisHash {
return errors.Wrapf(ruleerrors.ErrNoParents, "block has no parents")
}

View File

@ -3,8 +3,8 @@ package blockvalidator
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/util"
"github.com/pkg/errors"
)
@ -78,7 +78,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
// to avoid proof of work checks is set.
if !v.skipPoW {
// The block hash must be less than the claimed target.
hash := hashserialization.HeaderHash(header)
hash := consensusserialization.HeaderHash(header)
hashNum := hashes.ToBig(hash)
if hashNum.Cmp(target) > 0 {
return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block hash of %064x is higher than "+

View File

@ -179,7 +179,10 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external
pastUTXO := model.NewUTXODiff()
for virtualUTXOSetIterator.Next() {
outpoint, utxoEntry := virtualUTXOSetIterator.Get()
outpoint, utxoEntry, err := virtualUTXOSetIterator.Get()
if err != nil {
return nil, err
}
pastUTXO.ToAdd[*outpoint] = utxoEntry
}
@ -223,7 +226,7 @@ func (u utxoSetIterator) Next() bool {
return u.index != len(u.pairs)
}
func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry) {
func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) {
pair := u.pairs[u.index]
return &pair.outpoint, pair.entry
return &pair.outpoint, pair.entry, nil
}

View File

@ -2,12 +2,12 @@ package consensusstatemanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/dagconfig"
)
// consensusStateManager manages the node's consensus state
type consensusStateManager struct {
dagParams *dagconfig.Params
finalityDepth uint64
pruningDepth uint64
databaseContext model.DBManager
ghostdagManager model.GHOSTDAGManager
@ -37,7 +37,8 @@ type consensusStateManager struct {
// New instantiates a new ConsensusStateManager
func New(
databaseContext model.DBManager,
dagParams *dagconfig.Params,
finalityDepth uint64,
pruningDepth uint64,
ghostdagManager model.GHOSTDAGManager,
dagTopologyManager model.DAGTopologyManager,
dagTraversalManager model.DAGTraversalManager,
@ -60,7 +61,8 @@ func New(
headerTipsStore model.HeaderTipsStore) (model.ConsensusStateManager, error) {
csm := &consensusStateManager{
dagParams: dagParams,
finalityDepth: finalityDepth,
pruningDepth: pruningDepth,
databaseContext: databaseContext,
ghostdagManager: ghostdagManager,

View File

@ -25,7 +25,7 @@ func (csm *consensusStateManager) virtualFinalityPoint(virtualGHOSTDAGData *mode
*externalapi.DomainHash, error) {
return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(
model.VirtualBlockHash, virtualGHOSTDAGData.BlueScore-csm.dagParams.FinalityDepth())
model.VirtualBlockHash, virtualGHOSTDAGData.BlueScore-csm.finalityDepth)
}
func (csm *consensusStateManager) isViolatingFinality(

View File

@ -3,8 +3,9 @@ package consensusstatemanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
)
func (csm *consensusStateManager) calculateMultiset(
@ -47,7 +48,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.
for i, output := range transaction.Outputs {
outpoint := &externalapi.DomainOutpoint{
TransactionID: *hashserialization.TransactionID(transaction),
TransactionID: *consensusserialization.TransactionID(transaction),
Index: uint32(i),
}
utxoEntry := &externalapi.UTXOEntry{
@ -68,7 +69,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.
func addUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry,
outpoint *externalapi.DomainOutpoint) error {
serializedUTXO, err := hashserialization.SerializeUTXO(entry, outpoint)
serializedUTXO, err := consensusserialization.SerializeUTXO(entry, outpoint)
if err != nil {
return err
}
@ -80,7 +81,7 @@ func addUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry,
func removeUTXOFromMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry,
outpoint *externalapi.DomainOutpoint) error {
serializedUTXO, err := hashserialization.SerializeUTXO(entry, outpoint)
serializedUTXO, err := consensusserialization.SerializeUTXO(entry, outpoint)
if err != nil {
return err
}
@ -89,14 +90,10 @@ func removeUTXOFromMultiset(multiset model.Multiset, entry *externalapi.UTXOEntr
return nil
}
func calcMultisetFromUTXOSetIterator(iterator model.ReadOnlyUTXOSetIterator) (model.Multiset, error) {
func calcMultisetFromProtoUTXOSet(protoUTXOSet *utxoserialization.ProtoUTXOSet) (model.Multiset, error) {
ms := multiset.New()
for iterator.Next() {
entry, outpoint := iterator.Get()
err := addUTXOToMultiset(ms, outpoint, entry)
if err != nil {
return nil, err
}
for _, utxo := range protoUTXOSet.Utxos {
ms.Add(utxo.EntryOutpointPair)
}
return ms, nil
}

View File

@ -1,9 +1,12 @@
package consensusstatemanager
import (
"github.com/golang/protobuf/proto"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/pkg/errors"
)
@ -34,8 +37,13 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
return err
}
utxoSetIterator := deserializeUTXOSet(serializedUTXOSet)
utxoSetMultiSet, err := calcMultisetFromUTXOSetIterator(utxoSetIterator)
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
if err != nil {
return err
}
utxoSetMultiSet, err := calcMultisetFromProtoUTXOSet(protoUTXOSet)
if err != nil {
return err
}
@ -56,7 +64,7 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
return err
}
csm.consensusStateStore.StageVirtualUTXOSet(utxoSetIterator)
csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet))
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
if err != nil {
@ -94,8 +102,30 @@ func (csm *consensusStateManager) commitSetPruningPointUTXOSetAll() error {
return dbTx.Commit()
}
func deserializeUTXOSet(serializedUTXOSet []byte) model.ReadOnlyUTXOSetIterator {
panic("implement me")
type protoUTXOSetIterator struct {
utxoSet *utxoserialization.ProtoUTXOSet
index int
}
func (p protoUTXOSetIterator) Next() bool {
p.index++
return p.index != len(p.utxoSet.Utxos)
}
func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) {
entry, outpoint, err := consensusserialization.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair)
if err != nil {
if consensusserialization.IsMalformedError(err) {
return nil, nil, errors.Wrap(ruleerrors.ErrMalformedUTXO, "malformed utxo")
}
return nil, nil, err
}
return outpoint, entry, nil
}
func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator {
return &protoUTXOSetIterator{utxoSet: protoUTXOSet}
}
func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) {
@ -120,9 +150,5 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH
return nil, err
}
return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(virtualHeaderHash, virtualHeaderGHOSTDAGData.BlueScore-pruningDepth())
}
func pruningDepth() uint64 {
panic("unimplemented")
return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(virtualHeaderHash, virtualHeaderGHOSTDAGData.BlueScore-csm.pruningDepth)
}

View File

@ -3,7 +3,7 @@ package utxoalgebra
import (
"reflect"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
@ -33,7 +33,7 @@ func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.Domai
isCoinbase := transactionhelper.IsCoinBase(transaction)
for i, output := range transaction.Outputs {
outpoint := &externalapi.DomainOutpoint{
TransactionID: *hashserialization.TransactionID(transaction),
TransactionID: *consensusserialization.TransactionID(transaction),
Index: uint32(i),
}
entry := &externalapi.UTXOEntry{

View File

@ -5,7 +5,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
@ -104,8 +104,8 @@ func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData
}
sort.Slice(acceptedTransactions, func(i, j int) bool {
return transactionid.Less(
hashserialization.TransactionID(acceptedTransactions[i]),
hashserialization.TransactionID(acceptedTransactions[j]))
consensusserialization.TransactionID(acceptedTransactions[i]),
consensusserialization.TransactionID(acceptedTransactions[j]))
})
return merkle.CalculateIDMerkleRoot(acceptedTransactions)
@ -122,8 +122,8 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa
return err
}
coinbaseTransactionHash := hashserialization.TransactionHash(coinbaseTransaction)
expectedCoinbaseTransactionHash := hashserialization.TransactionHash(expectedCoinbaseTransaction)
coinbaseTransactionHash := consensusserialization.TransactionHash(coinbaseTransaction)
expectedCoinbaseTransactionHash := consensusserialization.TransactionHash(expectedCoinbaseTransaction)
if *coinbaseTransactionHash != *expectedCoinbaseTransactionHash {
return errors.Wrap(ruleerrors.ErrBadCoinbaseTransaction, "coinbase transaction is not built as expected")
}

View File

@ -4,7 +4,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
)
// pruningManager resolves and manages the current pruning point
@ -241,7 +241,7 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread
}
func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error) {
serializedUtxo, err := hashserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter)
serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter)
if err != nil {
return nil, err
}

View File

@ -3,7 +3,7 @@ package ruleerrors
import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/pkg/errors"
)
@ -233,6 +233,8 @@ var (
ErrBadPruningPointUTXOSet = newRuleError("ErrBadPruningPointUTXOSet")
ErrMissingBlockHeaderInIBD = newRuleError("ErrMissingBlockHeaderInIBD")
ErrMalformedUTXO = newRuleError("ErrMalformedUTXO")
)
// RuleError identifies a rule violation. It is used to indicate that
@ -291,7 +293,7 @@ type InvalidTransaction struct {
}
func (invalid InvalidTransaction) String() string {
return fmt.Sprintf("(%v: %s)", hashserialization.TransactionID(invalid.Transaction), invalid.err)
return fmt.Sprintf("(%v: %s)", consensusserialization.TransactionID(invalid.Transaction), invalid.err)
}
// ErrInvalidTransactionsInNewBlock indicates that some transactions in a new block are invalid

View File

@ -1,4 +1,4 @@
package hashserialization
package consensusserialization
import (
"encoding/binary"
@ -21,6 +21,8 @@ var (
// errNoEncodingForType signifies that there's no encoding for the given type.
var errNoEncodingForType = errors.New("there's no encoding for this type")
var errMalformed = errors.New("errMalformed")
// WriteElement writes the little endian representation of element to w.
func WriteElement(w io.Writer, element interface{}) error {
// Attempt to write the element based on the concrete type via fast
@ -102,3 +104,85 @@ func writeElements(w io.Writer, elements ...interface{}) error {
}
return nil
}
// readElement reads the next sequence of bytes from r using little endian
// depending on the concrete type of element pointed to.
func readElement(r io.Reader, element interface{}) error {
// Attempt to read the element based on the concrete type via fast
// type assertions first.
switch e := element.(type) {
case *int32:
rv, err := binaryserializer.Uint32(r, littleEndian)
if err != nil {
return err
}
*e = int32(rv)
return nil
case *uint32:
rv, err := binaryserializer.Uint32(r, littleEndian)
if err != nil {
return err
}
*e = rv
return nil
case *int64:
rv, err := binaryserializer.Uint64(r, littleEndian)
if err != nil {
return err
}
*e = int64(rv)
return nil
case *uint64:
rv, err := binaryserializer.Uint64(r, littleEndian)
if err != nil {
return err
}
*e = rv
return nil
case *uint8:
rv, err := binaryserializer.Uint8(r)
if err != nil {
return err
}
*e = rv
return nil
case *bool:
rv, err := binaryserializer.Uint8(r)
if err != nil {
return err
}
if rv == 0x00 {
*e = false
} else if rv == 0x01 {
*e = true
} else {
return errors.Wrapf(errMalformed, "in order to keep serialization canonical, true has to"+
" always be 0x01")
}
return nil
}
return errors.Wrapf(errNoEncodingForType, "couldn't find a way to read type %T", element)
}
// readElements reads multiple items from r. It is equivalent to multiple
// calls to readElement.
func readElements(r io.Reader, elements ...interface{}) error {
for _, element := range elements {
err := readElement(r, element)
if err != nil {
return err
}
}
return nil
}
// IsMalformedError returns whether the error indicates a malformed data source
func IsMalformedError(err error) bool {
return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, errMalformed)
}

View File

@ -1,4 +1,4 @@
package hashserialization
package consensusserialization
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"

View File

@ -1,4 +1,4 @@
package hashserialization
package consensusserialization
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"

View File

@ -0,0 +1,131 @@
package consensusserialization
import (
"bytes"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
"io"
"github.com/pkg/errors"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
const uint32Size = 4
// SerializeUTXO returns the byte-slice representation for given UTXOEntry-outpoint pair
func SerializeUTXO(entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) ([]byte, error) {
w := &bytes.Buffer{}
err := serializeOutpoint(w, outpoint)
if err != nil {
return nil, err
}
err = serializeUTXOEntry(w, entry)
if err != nil {
return nil, err
}
return w.Bytes(), nil
}
// DeserializeUTXO deserializes the given byte slice to UTXOEntry-outpoint pair
func DeserializeUTXO(utxoBytes []byte) (entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint, err error) {
r := bytes.NewReader(utxoBytes)
outpoint, err = deserializeOutpoint(r)
if err != nil {
return nil, nil, err
}
entry, err = deserializeUTXOEntry(r)
if err != nil {
return nil, nil, err
}
return entry, outpoint, nil
}
func serializeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error {
_, err := w.Write(outpoint.TransactionID[:])
if err != nil {
return err
}
err = WriteElement(w, outpoint.Index)
if err != nil {
return errors.WithStack(err)
}
return nil
}
func deserializeOutpoint(r io.Reader) (*externalapi.DomainOutpoint, error) {
transactionIDBytes := make([]byte, externalapi.DomainHashSize)
_, err := io.ReadFull(r, transactionIDBytes)
if err != nil {
return nil, err
}
transactionID, err := transactionid.FromBytes(transactionIDBytes)
if err != nil {
return nil, err
}
indexBytes := make([]byte, uint32Size)
_, err = io.ReadFull(r, indexBytes)
if err != nil {
return nil, err
}
var index uint32
err = readElement(r, &index)
if err != nil {
return nil, err
}
return &externalapi.DomainOutpoint{
TransactionID: *transactionID,
Index: index,
}, nil
}
func serializeUTXOEntry(w io.Writer, entry *externalapi.UTXOEntry) error {
err := writeElements(w, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase)
if err != nil {
return err
}
count := uint64(len(entry.ScriptPublicKey))
err = WriteElement(w, count)
if err != nil {
return err
}
_, err = w.Write(entry.ScriptPublicKey)
if err != nil {
return errors.WithStack(err)
}
return nil
}
func deserializeUTXOEntry(r io.Reader) (*externalapi.UTXOEntry, error) {
entry := &externalapi.UTXOEntry{}
err := readElements(r, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase)
if err != nil {
return nil, err
}
count := uint64(len(entry.ScriptPublicKey))
err = readElement(r, count)
if err != nil {
return nil, err
}
_, err = r.Read(entry.ScriptPublicKey)
if err != nil {
return nil, errors.WithStack(err)
}
return entry, nil
}

View File

@ -1,105 +0,0 @@
package hashserialization
import (
"bytes"
"encoding/binary"
"github.com/kaspanet/kaspad/domain/consensus/model"
"io"
"github.com/pkg/errors"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
// outpointIndexByteOrder is the byte order for serializing the outpoint index.
// It uses big endian to ensure that when outpoint is used as database key, the
// keys will be iterated in an ascending order by the outpoint index.
var outpointIndexByteOrder = binary.BigEndian
const (
outpointLen = externalapi.DomainHashSize + 4
entryMinLen = 8 + 1 + 8 + 8
averageScriptPubKeySize = 20
)
// ReadOnlyUTXOSetToProtoUTXOSet converts ReadOnlyUTXOSetIterator to ProtoUTXOSet
func ReadOnlyUTXOSetToProtoUTXOSet(iter model.ReadOnlyUTXOSetIterator) (*ProtoUTXOSet, error) {
protoUTXOSet := &ProtoUTXOSet{
Utxos: []*ProtoUTXO{},
}
for iter.Next() {
outpoint, entry := iter.Get()
serializedOutpoint := bytes.NewBuffer(make([]byte, 0, outpointLen))
err := serializeOutpoint(serializedOutpoint, outpoint)
if err != nil {
return nil, err
}
serializedEntry := bytes.NewBuffer(make([]byte, 0, entryMinLen+averageScriptPubKeySize))
err = serializeUTXOEntry(serializedEntry, entry)
if err != nil {
return nil, err
}
protoUTXOSet.Utxos = append(protoUTXOSet.Utxos, &ProtoUTXO{
Entry: serializedEntry.Bytes(),
Outpoint: serializedOutpoint.Bytes(),
})
}
return protoUTXOSet, nil
}
// SerializeUTXO returns the byte-slice representation for given UTXOEntry
func SerializeUTXO(entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) ([]byte, error) {
w := &bytes.Buffer{}
err := serializeOutpoint(w, outpoint)
if err != nil {
return nil, err
}
err = serializeUTXOEntry(w, entry)
if err != nil {
return nil, err
}
return w.Bytes(), nil
}
func serializeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error {
_, err := w.Write(outpoint.TransactionID[:])
if err != nil {
return err
}
var buf [4]byte
outpointIndexByteOrder.PutUint32(buf[:], outpoint.Index)
_, err = w.Write(buf[:])
if err != nil {
return errors.WithStack(err)
}
return nil
}
func serializeUTXOEntry(w io.Writer, entry *externalapi.UTXOEntry) error {
err := writeElements(w, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase)
if err != nil {
return err
}
count := uint64(len(entry.ScriptPublicKey))
err = WriteElement(w, count)
if err != nil {
return err
}
_, err = w.Write(entry.ScriptPublicKey)
if err != nil {
return errors.WithStack(err)
}
return nil
}

View File

@ -2,8 +2,8 @@ package merkle
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/pkg/errors"
"math"
)
@ -47,7 +47,7 @@ func hashMerkleBranches(left, right *externalapi.DomainHash) *externalapi.Domain
func CalculateHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash {
txHashes := make([]*externalapi.DomainHash, len(transactions))
for i, tx := range transactions {
txHashes[i] = hashserialization.TransactionHash(tx)
txHashes[i] = consensusserialization.TransactionHash(tx)
}
return merkleRoot(txHashes)
}
@ -57,7 +57,7 @@ func CalculateHashMerkleRoot(transactions []*externalapi.DomainTransaction) *ext
func CalculateIDMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash {
txIDs := make([]*externalapi.DomainHash, len(transactions))
for i, tx := range transactions {
txIDs[i] = (*externalapi.DomainHash)(hashserialization.TransactionID(tx))
txIDs[i] = (*externalapi.DomainHash)(consensusserialization.TransactionID(tx))
}
return merkleRoot(txIDs)
}

View File

@ -8,7 +8,7 @@ import (
"bytes"
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/pkg/errors"
)
@ -362,7 +362,7 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *external
// The final hash is the double sha256 of both the serialized modified
// transaction and the hash type (encoded as a 4-byte little-endian
// value) appended.
return hashserialization.TransactionHashForSigning(&txCopy, uint32(hashType)), nil
return consensusserialization.TransactionHashForSigning(&txCopy, uint32(hashType)), nil
}
// asSmallInt returns the passed opcode, which must be true according to

View File

@ -1,3 +1,3 @@
//go:generate protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative utxo.proto
package hashserialization
package utxoserialization

View File

@ -0,0 +1,30 @@
package utxoserialization
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
)
// ReadOnlyUTXOSetToProtoUTXOSet converts ReadOnlyUTXOSetIterator to ProtoUTXOSet
func ReadOnlyUTXOSetToProtoUTXOSet(iter model.ReadOnlyUTXOSetIterator) (*ProtoUTXOSet, error) {
protoUTXOSet := &ProtoUTXOSet{
Utxos: []*ProtoUTXO{},
}
for iter.Next() {
outpoint, entry, err := iter.Get()
if err != nil {
return nil, err
}
serializedUTXOBytes, err := consensusserialization.SerializeUTXO(entry, outpoint)
if err != nil {
return nil, err
}
protoUTXOSet.Utxos = append(protoUTXOSet.Utxos, &ProtoUTXO{
EntryOutpointPair: serializedUTXOBytes,
})
}
return protoUTXOSet, nil
}

View File

@ -1,10 +1,10 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.4
// protoc v3.12.3
// source: utxo.proto
package hashserialization
package utxoserialization
import (
proto "github.com/golang/protobuf/proto"
@ -30,8 +30,7 @@ type ProtoUTXO struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entry []byte `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"`
Outpoint []byte `protobuf:"bytes,2,opt,name=outpoint,proto3" json:"outpoint,omitempty"`
EntryOutpointPair []byte `protobuf:"bytes,1,opt,name=entryOutpointPair,proto3" json:"entryOutpointPair,omitempty"`
}
func (x *ProtoUTXO) Reset() {
@ -66,16 +65,9 @@ func (*ProtoUTXO) Descriptor() ([]byte, []int) {
return file_utxo_proto_rawDescGZIP(), []int{0}
}
func (x *ProtoUTXO) GetEntry() []byte {
func (x *ProtoUTXO) GetEntryOutpointPair() []byte {
if x != nil {
return x.Entry
}
return nil
}
func (x *ProtoUTXO) GetOutpoint() []byte {
if x != nil {
return x.Outpoint
return x.EntryOutpointPair
}
return nil
}
@ -130,22 +122,21 @@ func (x *ProtoUTXOSet) GetUtxos() []*ProtoUTXO {
var File_utxo_proto protoreflect.FileDescriptor
var file_utxo_proto_rawDesc = []byte{
0x0a, 0x0a, 0x75, 0x74, 0x78, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x68, 0x61,
0x73, 0x68, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
0x3d, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x12, 0x14, 0x0a, 0x05,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x42,
0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x12, 0x32,
0x0a, 0x05, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x52, 0x05, 0x75, 0x74, 0x78,
0x6f, 0x73, 0x42, 0x45, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64,
0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75,
0x73, 0x2f, 0x75, 0x74, 0x69, 0x6c, 0x73, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x0a, 0x0a, 0x75, 0x74, 0x78, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x75, 0x74,
0x78, 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
0x39, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x12, 0x2c, 0x0a, 0x11,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x61, 0x69,
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4f, 0x75,
0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x61, 0x69, 0x72, 0x22, 0x42, 0x0a, 0x0c, 0x50, 0x72,
0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x75, 0x74,
0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x75, 0x74, 0x78, 0x6f,
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72,
0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x52, 0x05, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x45,
0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73,
0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x64, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2f, 0x75, 0x74,
0x69, 0x6c, 0x73, 0x2f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -162,11 +153,11 @@ func file_utxo_proto_rawDescGZIP() []byte {
var file_utxo_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_utxo_proto_goTypes = []interface{}{
(*ProtoUTXO)(nil), // 0: hashserialization.ProtoUTXO
(*ProtoUTXOSet)(nil), // 1: hashserialization.ProtoUTXOSet
(*ProtoUTXO)(nil), // 0: utxoserialization.ProtoUTXO
(*ProtoUTXOSet)(nil), // 1: utxoserialization.ProtoUTXOSet
}
var file_utxo_proto_depIdxs = []int32{
0, // 0: hashserialization.ProtoUTXOSet.utxos:type_name -> hashserialization.ProtoUTXO
0, // 0: utxoserialization.ProtoUTXOSet.utxos:type_name -> utxoserialization.ProtoUTXO
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name

View File

@ -1,11 +1,10 @@
syntax = "proto3";
package hashserialization;
package utxoserialization;
option go_package = "github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization";
option go_package = "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization";
message ProtoUTXO {
bytes entry = 1;
bytes outpoint = 2;
bytes entryOutpointPair = 1;
}
message ProtoUTXOSet {

View File

@ -2,7 +2,7 @@ package blocktemplatebuilder
import (
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"math"
"math/rand"
@ -103,7 +103,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx)
if txsForBlockTemplate.totalMass+selectedTx.Mass < txsForBlockTemplate.totalMass ||
txsForBlockTemplate.totalMass+selectedTx.Mass > btb.policy.BlockMaxMass {
log.Tracef("Tx %s would exceed the max block mass. "+
"As such, stopping.", hashserialization.TransactionID(tx))
"As such, stopping.", consensusserialization.TransactionID(tx))
break
}
@ -121,7 +121,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx)
log.Tracef("Tx %s would exceed the gas limit in "+
"subnetwork %s. Removing all remaining txs from this "+
"subnetwork.",
hashserialization.TransactionID(tx), subnetworkID)
consensusserialization.TransactionID(tx), subnetworkID)
for _, candidateTx := range candidateTxs {
// candidateTxs are ordered by subnetwork, so we can safely assume
// that transactions after subnetworkID will not be relevant.
@ -146,7 +146,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx)
txsForBlockTemplate.totalFees += selectedTx.Fee
log.Tracef("Adding tx %s (feePerMegaGram %d)",
hashserialization.TransactionID(tx), selectedTx.Fee*1e6/selectedTx.Mass)
consensusserialization.TransactionID(tx), selectedTx.Fee*1e6/selectedTx.Mass)
markCandidateTxForDeletion(selectedTx)
}

View File

@ -10,8 +10,8 @@ import (
"github.com/kaspanet/kaspad/domain/consensus"
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util"
@ -133,7 +133,7 @@ type orphanTx struct {
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) removeOrphan(tx *consensusexternalapi.DomainTransaction, removeRedeemers bool) {
// Nothing to do if passed tx is not an orphan.
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
otx, exists := mp.orphans[*txID]
if !exists {
return
@ -234,7 +234,7 @@ func (mp *mempool) addOrphan(tx *consensusexternalapi.DomainTransaction) {
// This will periodically remove any expired orphans and evict a random
// orphan if space is still needed.
mp.limitNumOrphans()
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
mp.orphans[*txID] = &orphanTx{
tx: tx,
expiration: mstime.Now().Add(orphanTTL),
@ -247,7 +247,7 @@ func (mp *mempool) addOrphan(tx *consensusexternalapi.DomainTransaction) {
mp.orphansByPrev[txIn.PreviousOutpoint][*txID] = tx
}
log.Debugf("Stored orphan transaction %s (total: %d)", hashserialization.TransactionID(tx),
log.Debugf("Stored orphan transaction %s (total: %d)", consensusserialization.TransactionID(tx),
len(mp.orphans))
}
@ -343,7 +343,7 @@ func (mp *mempool) haveTransaction(txID *consensusexternalapi.DomainTransactionI
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) removeBlockTransactionsFromPool(txs []*consensusexternalapi.DomainTransaction) error {
for _, tx := range txs[util.CoinbaseTransactionIndex+1:] {
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
if _, exists := mp.fetchTxDesc(txID); !exists {
continue
@ -363,7 +363,7 @@ func (mp *mempool) removeBlockTransactionsFromPool(txs []*consensusexternalapi.D
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) removeTransactionAndItsChainedTransactions(tx *consensusexternalapi.DomainTransaction) error {
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
// Remove any transactions which rely on this one.
for i := uint32(0); i < uint32(len(tx.Outputs)); i++ {
prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *txID, Index: i}
@ -397,7 +397,7 @@ func (mp *mempool) cleanTransactionFromSets(tx *consensusexternalapi.DomainTrans
return err
}
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
delete(mp.pool, *txID)
delete(mp.chainedTransactions, *txID)
@ -410,7 +410,7 @@ func (mp *mempool) cleanTransactionFromSets(tx *consensusexternalapi.DomainTrans
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) updateBlockTransactionChainedTransactions(tx *consensusexternalapi.DomainTransaction) {
prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *hashserialization.TransactionID(tx)}
prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx)}
for txOutIdx := range tx.Outputs {
// Skip to the next available output if there are none.
prevOut.Index = uint32(txOutIdx)
@ -424,7 +424,7 @@ func (mp *mempool) updateBlockTransactionChainedTransactions(tx *consensusextern
if txDesc.depCount == 0 {
// Transaction may be already removed by recursive calls, if removeRedeemers is true.
// So avoid moving it into main pool
txDescID := hashserialization.TransactionID(txDesc.DomainTransaction)
txDescID := consensusserialization.TransactionID(txDesc.DomainTransaction)
if _, ok := mp.chainedTransactions[*txDescID]; ok {
delete(mp.chainedTransactions, *txDescID)
mp.pool[*txDescID] = txDesc
@ -438,7 +438,7 @@ func (mp *mempool) updateBlockTransactionChainedTransactions(tx *consensusextern
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) removeChainTransaction(tx *consensusexternalapi.DomainTransaction) {
delete(mp.chainedTransactions, *hashserialization.TransactionID(tx))
delete(mp.chainedTransactions, *consensusserialization.TransactionID(tx))
for _, txIn := range tx.Inputs {
delete(mp.chainedTransactionByPreviousOutpoint, txIn.PreviousOutpoint)
}
@ -452,10 +452,10 @@ func (mp *mempool) removeChainTransaction(tx *consensusexternalapi.DomainTransac
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) removeDoubleSpends(tx *consensusexternalapi.DomainTransaction) error {
txID := *hashserialization.TransactionID(tx)
txID := *consensusserialization.TransactionID(tx)
for _, txIn := range tx.Inputs {
if txRedeemer, ok := mp.mempoolUTXOSet.poolTransactionBySpendingOutpoint(txIn.PreviousOutpoint); ok {
if !(*hashserialization.TransactionID(txRedeemer) == txID) {
if !(*consensusserialization.TransactionID(txRedeemer) == txID) {
err := mp.removeTransactionAndItsChainedTransactions(txRedeemer)
if err != nil {
return err
@ -478,7 +478,7 @@ func (mp *mempool) addTransaction(tx *consensusexternalapi.DomainTransaction, ma
DomainTransaction: tx,
depCount: len(parentsInPool),
}
txID := *hashserialization.TransactionID(tx)
txID := *consensusserialization.TransactionID(tx)
if len(parentsInPool) == 0 {
mp.pool[txID] = txDescriptor
@ -508,7 +508,7 @@ func (mp *mempool) checkPoolDoubleSpend(tx *consensusexternalapi.DomainTransacti
if txR, exists := mp.mempoolUTXOSet.poolTransactionBySpendingOutpoint(txIn.PreviousOutpoint); exists {
str := fmt.Sprintf("output %s already spent by "+
"transaction %s in the memory pool",
txIn.PreviousOutpoint, hashserialization.TransactionID(txR))
txIn.PreviousOutpoint, consensusserialization.TransactionID(txR))
return txRuleError(RejectDuplicate, str)
}
}
@ -540,7 +540,7 @@ func (mp *mempool) fetchTxDesc(txID *consensusexternalapi.DomainTransactionID) (
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransaction, rejectDupOrphans bool) ([]consensusexternalapi.DomainOutpoint, *txDescriptor, error) {
txID := hashserialization.TransactionID(tx)
txID := consensusserialization.TransactionID(tx)
// Don't accept the transaction if it already exists in the pool. This
// applies to orphan transactions as well when the reject duplicate
@ -679,7 +679,7 @@ func (mp *mempool) processOrphans(acceptedTx *consensusexternalapi.DomainTransac
firstElement := processList.Remove(processList.Front())
processItem := firstElement.(*consensusexternalapi.DomainTransaction)
prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *hashserialization.TransactionID(processItem)}
prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(processItem)}
for txOutIdx := range processItem.Outputs {
// Look up all orphans that redeem the output that is
// now available. This will typically only be one, but
@ -759,7 +759,7 @@ func (mp *mempool) processOrphans(acceptedTx *consensusexternalapi.DomainTransac
//
// This function is safe for concurrent access.
func (mp *mempool) ValidateAndInsertTransaction(tx *consensusexternalapi.DomainTransaction, allowOrphan bool) error {
log.Tracef("Processing transaction %s", hashserialization.TransactionID(tx))
log.Tracef("Processing transaction %s", consensusserialization.TransactionID(tx))
// Protect concurrent access.
mp.mtx.Lock()
@ -801,7 +801,7 @@ func (mp *mempool) ValidateAndInsertTransaction(tx *consensusexternalapi.DomainT
// which is not really always the case.
str := fmt.Sprintf("orphan transaction %s references "+
"outputs of unknown or fully-spent "+
"transaction %s", hashserialization.TransactionID(tx), missingParents[0])
"transaction %s", consensusserialization.TransactionID(tx), missingParents[0])
return txRuleError(RejectDuplicate, str)
}
@ -870,7 +870,7 @@ func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.Domain
for _, tx := range txs[util.CoinbaseTransactionIndex+1:] {
err := mp.removeDoubleSpends(tx)
if err != nil {
log.Infof("Failed removing tx from mempool: %s, '%s'", hashserialization.TransactionID(tx), err)
log.Infof("Failed removing tx from mempool: %s, '%s'", consensusserialization.TransactionID(tx), err)
}
mp.removeOrphan(tx, false)
acceptedOrphans := mp.processOrphans(tx)
@ -888,7 +888,7 @@ func (mp *mempool) RemoveTransactions(txs []*consensusexternalapi.DomainTransact
for _, tx := range txs {
err := mp.removeDoubleSpends(tx)
if err != nil {
log.Infof("Failed removing tx from mempool: %s, '%s'", hashserialization.TransactionID(tx), err)
log.Infof("Failed removing tx from mempool: %s, '%s'", consensusserialization.TransactionID(tx), err)
}
mp.removeOrphan(tx, true)
}

View File

@ -3,7 +3,7 @@ package mempool
import (
"github.com/kaspanet/kaspad/domain/blockdag"
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/pkg/errors"
)
@ -39,7 +39,7 @@ func (mpus *mempoolUTXOSet) checkExists(tx *consensusexternalapi.DomainTransacti
}
// Check if it creates an already existing UTXO
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *hashserialization.TransactionID(tx)}
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx)}
for i := range tx.Outputs {
outpoint.Index = uint32(i)
if _, exists := mpus.poolUnspentOutputs[outpoint]; exists {
@ -54,13 +54,13 @@ func (mpus *mempoolUTXOSet) checkExists(tx *consensusexternalapi.DomainTransacti
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, hashserialization.TransactionID(existingTx))
return errors.Errorf("outpoint %s is already used by %s", txIn.PreviousOutpoint, consensusserialization.TransactionID(existingTx))
}
mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint] = tx
}
for i, txOut := range tx.Outputs {
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *hashserialization.TransactionID(tx), Index: uint32(i)}
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx), Index: uint32(i)}
if _, exists := mpus.poolUnspentOutputs[outpoint]; exists {
return errors.Errorf("outpoint %s already exists", outpoint)
}
@ -84,7 +84,7 @@ func (mpus *mempoolUTXOSet) removeTx(tx *consensusexternalapi.DomainTransaction)
delete(mpus.transactionByPreviousOutpoint, txIn.PreviousOutpoint)
}
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *hashserialization.TransactionID(tx)}
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx)}
for i := range tx.Outputs {
outpoint.Index = uint32(i)
if _, exists := mpus.poolUnspentOutputs[outpoint]; !exists {