From 82b0e3c312c9b1fe1293738a5df41710317f5b54 Mon Sep 17 00:00:00 2001 From: superzordon Date: Mon, 14 Oct 2024 17:33:37 -0400 Subject: [PATCH] Add new consumer fields to txindex computation --- consumer/helpers.go | 146 ++++++++++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 47 deletions(-) diff --git a/consumer/helpers.go b/consumer/helpers.go index ddabe3a..739ecff 100644 --- a/consumer/helpers.go +++ b/consumer/helpers.go @@ -320,10 +320,58 @@ func getDisconnectOperationTypeForPrevEntry(prevEntry lib.DeSoEncoder) lib.State } } +// TransactionExtraMetadata tracks additional metadata for a transaction that isn't stored in txindex. +type TransactionExtraMetadata interface{} + +// Additional fields needed for SubmitPost transactions. +type PostTransactionExtraMetadata struct { + PosterPublicKeyBase58Check string + RelatedPublicKeyBase58Check string +} + +// A combined view of the existing txindex metadata struct and the additional metadata fields. +type ConsumerTxIndexMetadata struct { + lib.DeSoEncoder + TransactionExtraMetadata +} + +// Combine the JSON data from the DeSoEncoder and the TransactionExtraMetadata into a single JSON object. +func (c ConsumerTxIndexMetadata) MarshalJSON() ([]byte, error) { + // Create temporary maps to hold each interface's JSON data + encoderData, err := json.Marshal(c.DeSoEncoder) + if err != nil { + return nil, err + } + + metadataData, err := json.Marshal(c.TransactionExtraMetadata) + if err != nil { + return nil, err + } + + // Unmarshal the JSON data into separate maps + var encoderMap map[string]interface{} + var metadataMap map[string]interface{} + if err := json.Unmarshal(encoderData, &encoderMap); err != nil { + return nil, err + } + if err := json.Unmarshal(metadataData, &metadataMap); err != nil { + return nil, err + } + + // Combine both maps + for k, v := range metadataMap { + encoderMap[k] = v + } + + // Marshal the combined map back into JSON + return json.Marshal(encoderMap) +} + func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params *lib.DeSoParams, - fees uint64, txnIndexInBlock uint64, utxoOps []*lib.UtxoOperation) (*lib.TransactionMetadata, error) { + fees uint64, txnIndexInBlock uint64, utxoOps []*lib.UtxoOperation) (*lib.TransactionMetadata, *TransactionExtraMetadata, error) { var err error + var transactionExtraMetadata TransactionExtraMetadata txnMeta := &lib.TransactionMetadata{ TxnIndexInBlock: txnIndexInBlock, TxnType: txn.TxnMeta.GetTxnType().String(), @@ -369,12 +417,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeCreatorCoin) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing creator coin utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing creator coin utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.CreatorCoinStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing creator coin state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing creator coin state change metadata error: %v", txn.Hash().String()) } // Rosetta needs to know the change in DESOLockedNanos so it can model the change in @@ -416,12 +464,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params realTxMeta := txn.TxnMeta.(*lib.CreatorCoinTransferMetadataa) utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeCreatorCoinTransfer) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing cc transfer utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing cc transfer utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.CCTransferStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing cc transfer state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing cc transfer state change metadata error: %v", txn.Hash().String()) } txnMeta.CreatorCoinTransferTxindexMetadata = &lib.CreatorCoinTransferTxindexMetadata{ @@ -470,12 +518,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeSubmitPost) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing submit post utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing submit post utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.SubmitPostStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing submit post state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing submit post state change metadata error: %v", txn.Hash().String()) } txnMeta.SubmitPostTxindexMetadata = &lib.SubmitPostTxindexMetadata{} @@ -511,8 +559,9 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params PublicKeyBase58Check: lib.PkToString(postEntry.PosterPublicKey, params), Metadata: "ParentPosterPublicKeyBase58Check", }) - txnMeta.SubmitPostTxindexMetadata.RelatedPublicKeyBase58Check = lib.PkToString( - postEntry.PosterPublicKey, params) + transactionExtraMetadata = &PostTransactionExtraMetadata{ + PosterPublicKeyBase58Check: lib.PkToString(postEntry.PosterPublicKey, params), + } } } @@ -546,8 +595,9 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params PublicKeyBase58Check: lib.PkToString(repostPost.PosterPublicKey, params), Metadata: "RepostedPublicKeyBase58Check", }) - txnMeta.SubmitPostTxindexMetadata.RelatedPublicKeyBase58Check = lib.PkToString( - repostPost.PosterPublicKey, params) + transactionExtraMetadata = &PostTransactionExtraMetadata{ + RelatedPublicKeyBase58Check: lib.PkToString(repostPost.PosterPublicKey, params), + } } } } @@ -556,12 +606,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeLike) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing like utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing like utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.LikeStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing like state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing like state change metadata error: %v", txn.Hash().String()) } txnMeta.LikeTxindexMetadata = &lib.LikeTxindexMetadata{ @@ -616,12 +666,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeSwapIdentity) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing swap identity utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing swap identity utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.SwapIdentityStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing swap identity state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing swap identity state change metadata error: %v", txn.Hash().String()) } // Rosetta needs to know the current locked deso in each profile so it can model the swap of @@ -663,7 +713,7 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeNFTBid) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing nft bid utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing nft bid utxo op error: %v", txn.Hash().String()) } var nftRoyaltiesMetadata lib.NFTRoyaltiesMetadata var ownerPublicKeyBase58Check string @@ -672,7 +722,7 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params if realTxMeta.SerialNumber != 0 { stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.NFTBidStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing nft bid state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing nft bid state change metadata error: %v", txn.Hash().String()) } postEntry := stateChangeMetadata.PostEntry @@ -746,11 +796,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeAcceptNFTBid) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing accept bid utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing accept bid utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.AcceptNFTBidStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing accept bid state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing accept bid state change metadata error: %v", txn.Hash().String()) } creatorPublicKeyBase58Check := lib.PkToString(utxoOp.PrevPostEntry.PosterPublicKey, params) @@ -808,11 +858,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeCreateNFT) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing create nft utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing create nft utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.CreateNFTStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing create nft state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing create nft state change metadata error: %v", txn.Hash().String()) } additionalDESORoyaltiesMap := stateChangeMetadata.AdditionalDESORoyaltiesMap @@ -841,11 +891,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeUpdateNFT) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing update nft utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing update nft utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.UpdateNFTStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing update nft state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing update nft state change metadata error: %v", txn.Hash().String()) } postEntry := stateChangeMetadata.NFTPostEntry @@ -925,11 +975,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeDAOCoin) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.DAOCoinStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin state change metadata error: %v", txn.Hash().String()) } creatorProfileEntry := stateChangeMetadata.CreatorProfileEntry @@ -968,11 +1018,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeDAOCoinTransfer) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin transfer utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin transfer utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.DAOCoinTransferStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin transfer state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin transfer state change metadata error: %v", txn.Hash().String()) } creatorProfileEntry := stateChangeMetadata.CreatorProfileEntry @@ -990,12 +1040,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeDAOCoinLimitOrder) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin limit order utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin limit order utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.DAOCoinLimitOrderStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin limit order state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin limit order state change metadata error: %v", txn.Hash().String()) } // We only update the mempool if the transactor submitted a new @@ -1070,11 +1120,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params realTxMeta := txn.TxnMeta.(*lib.DeleteUserAssociationMetadata) utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeDeleteUserAssociation) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing delete user association utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing delete user association utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.DeleteUserAssociationStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing delete user association state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing delete user association state change metadata error: %v", txn.Hash().String()) } prevAssociationEntry := &lib.UserAssociationEntry{} @@ -1103,11 +1153,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params realTxMeta := txn.TxnMeta.(*lib.CreatePostAssociationMetadata) utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeCreatePostAssociation) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing create post association utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing create post association utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.CreatePostAssociationStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing create post association state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing create post association state change metadata error: %v", txn.Hash().String()) } appPublicKeyBase58Check := lib.PkToString(realTxMeta.AppPublicKey.ToBytes(), params) @@ -1115,13 +1165,14 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params postEntry := stateChangeMetadata.PostEntry txnMeta.CreatePostAssociationTxindexMetadata = &lib.CreatePostAssociationTxindexMetadata{ - PostHashHex: hex.EncodeToString(realTxMeta.PostHash.ToBytes()), - PosterPublicKeyBase58Check: lib.PkToString(postEntry.PosterPublicKey, params), - AppPublicKeyBase58Check: appPublicKeyBase58Check, - AssociationType: string(realTxMeta.AssociationType), - AssociationValue: string(realTxMeta.AssociationValue), + PostHashHex: hex.EncodeToString(realTxMeta.PostHash.ToBytes()), + AppPublicKeyBase58Check: appPublicKeyBase58Check, + AssociationType: string(realTxMeta.AssociationType), + AssociationValue: string(realTxMeta.AssociationValue), } + transactionExtraMetadata = &PostTransactionExtraMetadata{PosterPublicKeyBase58Check: lib.PkToString(postEntry.PosterPublicKey, params)} + txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &lib.AffectedPublicKey{ PublicKeyBase58Check: lib.PkToString(postEntry.PosterPublicKey, params), Metadata: "AssociationTargetPostCreatorPublicKeyBase58Check", @@ -1131,11 +1182,11 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params realTxMeta := txn.TxnMeta.(*lib.DeletePostAssociationMetadata) utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeDeletePostAssociation) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing delete post association utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing delete post association utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.DeletePostAssociationStateChangeMetadata) if !ok { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing delete post association state change metadata error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing delete post association state change metadata error: %v", txn.Hash().String()) } prevAssociationEntry := &lib.PostAssociationEntry{} @@ -1241,12 +1292,12 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params utxoOp := GetUtxoOpByOperationType(utxoOps, lib.OperationTypeUnregisterAsValidator) if utxoOp == nil || utxoOp.StateChangeMetadata == nil { - return nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin utxo op error: %v", txn.Hash().String()) + return nil, nil, fmt.Errorf("ComputeTransactionMetadata: missing dao coin utxo op error: %v", txn.Hash().String()) } stateChangeMetadata, ok := utxoOp.StateChangeMetadata.(*lib.UnregisterAsValidatorStateChangeMetadata) if !ok { - return nil, fmt.Errorf( + return nil, nil, fmt.Errorf( "ComputeTransactionMetadata: missing unregister as validator state change metadata error: %v", txn.Hash().String()) } @@ -1425,16 +1476,16 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params } // This should never happen. if atomicWrapperUtxoOp == nil { - return nil, errors.New("ComputeTransactionMetadata: Could not find utxo op for atomic txn wrapper") + return nil, nil, errors.New("ComputeTransactionMetadata: Could not find utxo op for atomic txn wrapper") } innerUtxoOps := atomicWrapperUtxoOp.AtomicTxnsInnerUtxoOps if len(innerUtxoOps) != len(realTxMeta.Txns) { - return nil, errors.New("ComputeTransactionMetadata: Number of inner utxo ops does not match number of inner txns") + return nil, nil, errors.New("ComputeTransactionMetadata: Number of inner utxo ops does not match number of inner txns") } for ii, innerTxn := range realTxMeta.Txns { // Compute the transaction metadata for each inner transaction. var innerTxnsTxnMetadata *lib.TransactionMetadata - innerTxnsTxnMetadata, err = ComputeTransactionMetadata( + innerTxnsTxnMetadata, _, err = ComputeTransactionMetadata( innerTxn, blockHashHex, params, @@ -1443,7 +1494,7 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params innerUtxoOps[ii], ) if err != nil { - return nil, errors.Wrapf(err, "ComputeTransactionMetadata: Error computing inner transaction metadata") + return nil, nil, errors.Wrapf(err, "ComputeTransactionMetadata: Error computing inner transaction metadata") } txnMeta.AtomicTxnsWrapperTxindexMetadata.InnerTxnsTransactionMetadata = append( txnMeta.AtomicTxnsWrapperTxindexMetadata.InnerTxnsTransactionMetadata, innerTxnsTxnMetadata) @@ -1471,7 +1522,8 @@ func ComputeTransactionMetadata(txn *lib.MsgDeSoTxn, blockHashHex string, params }) } } - return txnMeta, nil + + return txnMeta, &transactionExtraMetadata, nil } func GetUtxoOpByOperationType(utxoOps []*lib.UtxoOperation, operationType lib.OperationType) *lib.UtxoOperation {