Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

feat(BUX-322): save inputs from beef tx #479

Merged
18 changes: 18 additions & 0 deletions beef_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,21 @@ func hydrateTransaction(ctx context.Context, tx *Transaction) error {

return nil
}

func getParentTransactionsForInput(ctx context.Context, client ClientInterface, input *TransactionInput) ([]*bt.Tx, error) {
inputTx, err := client.GetTransactionByID(ctx, input.UtxoPointer.TransactionID)
if err != nil {
return nil, err
}

if inputTx.MerkleProof.TxOrID != "" {
inputBtTx, err := bt.NewTxFromString(inputTx.Hex)
if err != nil {
return nil, fmt.Errorf("cannot convert to bt.Tx from hex (tx.ID: %s). Reason: %w", inputTx.ID, err)
}

return []*bt.Tx{inputBtTx}, nil
}

return nil, fmt.Errorf("transaction is not mined yet (tx.ID: %s)", inputTx.ID) // TODO: handle it in next iterration
pawellewandowski98 marked this conversation as resolved.
Show resolved Hide resolved
}
16 changes: 8 additions & 8 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 14 additions & 14 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 93 additions & 0 deletions paymail_service_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"database/sql"
"encoding/hex"
"fmt"
"github.com/libsv/go-bt/v2"
"reflect"
"time"

"github.com/bitcoin-sv/go-paymail"
Expand Down Expand Up @@ -173,6 +175,15 @@ func (p *PaymailDefaultServiceProvider) RecordTransaction(ctx context.Context,
return nil, err
}

if p2pTx.DecodedBeef == nil {
return &paymail.P2PTransactionPayload{
Note: p2pTx.MetaData.Note,
TxID: transaction.ID,
}, nil
}

saveBEEFTxInputs(ctx, p.client, p2pTx, rts)
arkadiuszos4chain marked this conversation as resolved.
Show resolved Hide resolved

// Return the response from the p2p request
return &paymail.P2PTransactionPayload{
Note: p2pTx.MetaData.Note,
Expand Down Expand Up @@ -306,3 +317,85 @@ func deriveKey(rawXPubKey string, num uint32) (k *derivedPubKey, err error) {
k.pubKey = hex.EncodeToString(k.ecPubKey.SerialiseCompressed())
return
}

func saveBEEFTxInputs(ctx context.Context, c ClientInterface, p2pTx *paymail.P2PTransaction, rts recordIncomingTxStrategy) {
if reflect.TypeOf(rts) != reflect.TypeOf(&externalIncomingTx{}) {
return
}

inputsToAdd, err := getInputsWhichAreNotInDb(ctx, c, p2pTx)
if err != nil {
c.Logger().Error(ctx, "error in saveBEEFTxInputs", err)
}

for _, input := range inputsToAdd {
err := saveBeefTransactionInput(ctx, c, input)
if err != nil {
c.Logger().Error(ctx, "error in saveBEEFTxInputs", err)
}
}

}

func getInputsWhichAreNotInDb(ctx context.Context, c ClientInterface, p2pTx *paymail.P2PTransaction) ([]*bt.Tx, error) {
var txIDs []string
for _, tx := range p2pTx.DecodedBeef.Transactions {
txIDs = append(txIDs, tx.GetTxID())
}
dbTxs, err := c.GetTransactionsByIDs(ctx, txIDs)
if err != nil {
return nil, fmt.Errorf("error during getting txs from db: %s", err)
}

txs := make([]*bt.Tx, 0)

if len(dbTxs) == len(txIDs) {
return txs, nil
}

for _, input := range p2pTx.DecodedBeef.Transactions {
arkadiuszos4chain marked this conversation as resolved.
Show resolved Hide resolved
found := false
for _, dbTx := range dbTxs {
if dbTx.GetID() == input.GetTxID() {
found = true
break
}
}
if !found {
txs = append(txs, input.Transaction)
}
}

return txs, nil
}

func saveBeefTransactionInput(ctx context.Context, c ClientInterface, input *bt.Tx) error {
pawellewandowski98 marked this conversation as resolved.
Show resolved Hide resolved
inputTx, err := c.GetTransactionByID(ctx, input.TxID())
if err != nil && err != ErrMissingTransaction {
return fmt.Errorf("error in saveBeefTransactionInput during getting transaction: %s", err.Error())
}

if inputTx != nil {
return nil
}

newOpts := c.DefaultModelOptions(New())
inputTx = newTransaction(input.String(), newOpts...)

sync := newSyncTransaction(
inputTx.GetID(),
inputTx.Client().DefaultSyncConfig(),
inputTx.GetOptions(true)...,
)
sync.BroadcastStatus = SyncStatusSkipped
sync.P2PStatus = SyncStatusSkipped
sync.SyncStatus = SyncStatusReady
pawellewandowski98 marked this conversation as resolved.
Show resolved Hide resolved

inputTx.syncTransaction = sync

err = inputTx.Save(ctx)
if err != nil {
return fmt.Errorf("error in saveBeefTransactionInput during saving tx: %s", err.Error())
}
return nil
}