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

Commit

Permalink
fix?: use bt structure in BEEF impl
Browse files Browse the repository at this point in the history
  • Loading branch information
arkadiuszos4chain committed Oct 18, 2023
1 parent 52f3a4b commit 13f64a8
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 139 deletions.
30 changes: 19 additions & 11 deletions beef_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/hex"
"errors"
"fmt"

"github.com/libsv/go-bt/v2"
)

const maxBeefVer = uint32(0xFFFF) // value from BRC-62
Expand All @@ -27,7 +29,7 @@ func ToBeefHex(ctx context.Context, tx *Transaction) (string, error) {
type beefTx struct {
version uint32
compoundMerklePaths CMPSlice
transactions []*Transaction
transactions []*bt.Tx
}

func newBeefTx(ctx context.Context, version uint32, tx *Transaction) (*beefTx, error) {
Expand All @@ -46,10 +48,11 @@ func newBeefTx(ctx context.Context, version uint32, tx *Transaction) (*beefTx, e

// get inputs parent transactions
inputs := tx.draftTransaction.Configuration.Inputs
transactions := make([]*Transaction, 0, len(inputs)+1)
transactions := make([]*bt.Tx, 0, len(inputs)+1)

for _, input := range inputs {
prevTxs, err := getParentTransactionsForInput(ctx, tx.client, input)
var prevTxs []*bt.Tx
prevTxs, err = getParentTransactionsForInput(ctx, tx.client, input)
if err != nil {
return nil, fmt.Errorf("retrieve input parent transaction failed: %w", err)
}
Expand All @@ -58,7 +61,11 @@ func newBeefTx(ctx context.Context, version uint32, tx *Transaction) (*beefTx, e
}

// add current transaction
transactions = append(transactions, tx)
btTx, err := bt.NewTxFromString(tx.Hex)
if err != nil {
return nil, fmt.Errorf("cannot convert new transaction to bt.Tx from hex (tx.ID: %s). Reason: %w", tx.ID, err)
}
transactions = append(transactions, btTx)

beef := &beefTx{
version: version,
Expand All @@ -75,7 +82,7 @@ func hydrateTransaction(ctx context.Context, tx *Transaction) error {
ctx, tx.XPubID, tx.DraftID, tx.GetOptions(false)...,
)

if err != nil {
if err != nil || dTx == nil {
return fmt.Errorf("retrieve DraftTransaction failed: %w", err)
}

Expand All @@ -99,18 +106,19 @@ func validateCompoundMerklePathes(compountedPaths CMPSlice) error {
return nil
}

func getParentTransactionsForInput(ctx context.Context, client ClientInterface, input *TransactionInput) ([]*Transaction, error) {
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 err = hydrateTransaction(ctx, inputTx); err != nil {
return nil, err
}

if inputTx.MerkleProof.TxOrID != "" {
return []*Transaction{inputTx}, nil
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
Expand Down
18 changes: 6 additions & 12 deletions beef_tx_bytes.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package bux

import (
"encoding/hex"
"errors"
"fmt"

"github.com/libsv/go-bt/v2"
)
Expand Down Expand Up @@ -36,7 +34,7 @@ func (beefTx *beefTx) toBeefBytes() ([]byte, error) {
transactions := make([][]byte, 0, len(beefTx.transactions))

for _, t := range beefTx.transactions {
txBytes, err := t.toBeefBytes(beefTx.compoundMerklePaths)
txBytes, err := toBeefBytes(t, beefTx.compoundMerklePaths)
if err != nil {
return nil, err
}
Expand All @@ -60,14 +58,10 @@ func (beefTx *beefTx) toBeefBytes() ([]byte, error) {
return buffer, nil
}

func (tx *Transaction) toBeefBytes(compountedPaths CMPSlice) ([]byte, error) {
txBeefBytes, err := hex.DecodeString(tx.Hex)
func toBeefBytes(tx *bt.Tx, compountedPaths CMPSlice) ([]byte, error) {
txBeefBytes := tx.Bytes()

if err != nil {
return nil, fmt.Errorf("decoding tx (ID: %s) hex failed: %w", tx.ID, err)
}

cmpIdx := tx.getCompountedMarklePathIndex(compountedPaths)
cmpIdx := getCompountedMarklePathIndex(tx, compountedPaths)
if cmpIdx > -1 {
txBeefBytes = append(txBeefBytes, hasCmp)
txBeefBytes = append(txBeefBytes, bt.VarInt(cmpIdx).Bytes()...)
Expand All @@ -78,12 +72,12 @@ func (tx *Transaction) toBeefBytes(compountedPaths CMPSlice) ([]byte, error) {
return txBeefBytes, nil
}

func (tx *Transaction) getCompountedMarklePathIndex(compountedPaths CMPSlice) int {
func getCompountedMarklePathIndex(tx *bt.Tx, compountedPaths CMPSlice) int {
pathIdx := -1

for i, cmp := range compountedPaths {
for txID := range cmp[0] {
if txID == tx.ID {
if txID == tx.TxID() { // TODO: perf
pathIdx = i
}
}
Expand Down
30 changes: 16 additions & 14 deletions beef_tx_sorting.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package bux

func kahnTopologicalSortTransactions(transactions []*Transaction) []*Transaction {
import "github.com/libsv/go-bt/v2"

func kahnTopologicalSortTransactions(transactions []*bt.Tx) []*bt.Tx {
txByID, incomingEdgesMap, zeroIncomingEdgeQueue := prepareSortStructures(transactions)
result := make([]*Transaction, 0, len(transactions))
result := make([]*bt.Tx, 0, len(transactions))

for len(zeroIncomingEdgeQueue) > 0 {
txID := zeroIncomingEdgeQueue[0]
Expand All @@ -18,14 +20,14 @@ func kahnTopologicalSortTransactions(transactions []*Transaction) []*Transaction
return result
}

func prepareSortStructures(dag []*Transaction) (txByID map[string]*Transaction, incomingEdgesMap map[string]int, zeroIncomingEdgeQueue []string) {
func prepareSortStructures(dag []*bt.Tx) (txByID map[string]*bt.Tx, incomingEdgesMap map[string]int, zeroIncomingEdgeQueue []string) {
dagLen := len(dag)
txByID = make(map[string]*Transaction, dagLen)
txByID = make(map[string]*bt.Tx, dagLen)
incomingEdgesMap = make(map[string]int, dagLen)

for _, tx := range dag {
txByID[tx.ID] = tx
incomingEdgesMap[tx.ID] = 0
txByID[tx.TxID()] = tx // TODO: perf
incomingEdgesMap[tx.TxID()] = 0
}

calculateIncomingEdges(incomingEdgesMap, txByID)
Expand All @@ -34,11 +36,11 @@ func prepareSortStructures(dag []*Transaction) (txByID map[string]*Transaction,
return
}

func calculateIncomingEdges(inDegree map[string]int, txByID map[string]*Transaction) {
func calculateIncomingEdges(inDegree map[string]int, txByID map[string]*bt.Tx) {
for _, tx := range txByID {
for _, input := range tx.draftTransaction.Configuration.Inputs {
inputUtxoTxID := input.UtxoPointer.TransactionID
if _, ok := txByID[inputUtxoTxID]; ok { // transaction can contains inputs we are not interested in
for _, input := range tx.Inputs {
inputUtxoTxID := input.PreviousTxIDStr() // TODO: perf
if _, ok := txByID[inputUtxoTxID]; ok { // transaction can contains inputs we are not interested in
inDegree[inputUtxoTxID]++
}
}
Expand All @@ -57,9 +59,9 @@ func getTxWithZeroIncomingEdges(incomingEdgesMap map[string]int) []string {
return zeroIncomingEdgeQueue
}

func removeTxFromIncomingEdges(tx *Transaction, incomingEdgesMap map[string]int, zeroIncomingEdgeQueue []string) []string {
for _, input := range tx.draftTransaction.Configuration.Inputs {
neighborID := input.UtxoPointer.TransactionID
func removeTxFromIncomingEdges(tx *bt.Tx, incomingEdgesMap map[string]int, zeroIncomingEdgeQueue []string) []string {
for _, input := range tx.Inputs {
neighborID := input.PreviousTxIDStr() // TODO: perf
incomingEdgesMap[neighborID]--

if incomingEdgesMap[neighborID] == 0 {
Expand All @@ -70,7 +72,7 @@ func removeTxFromIncomingEdges(tx *Transaction, incomingEdgesMap map[string]int,
return zeroIncomingEdgeQueue
}

func reverseInPlace(collection []*Transaction) {
func reverseInPlace(collection []*bt.Tx) {
for i, j := 0, len(collection)-1; i < j; i, j = i+1, j-1 {
collection[i], collection[j] = collection[j], collection[i]
}
Expand Down
Loading

0 comments on commit 13f64a8

Please sign in to comment.