Skip to content

Commit

Permalink
Add filtering of utxos used in transaction building
Browse files Browse the repository at this point in the history
  • Loading branch information
KonradStaniec committed Oct 16, 2024
1 parent 4e8d094 commit b34531d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
4 changes: 4 additions & 0 deletions itest/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ func (tm *TestManager) FinalizeUntilEpoch(t *testing.T, epoch uint64) {
},
2000,
tm.MinerAddr,
nil,
)
require.NoError(t, err)
_, err = tm.Sa.Wallet().SendRawTransaction(tx1, true)
Expand All @@ -557,6 +558,7 @@ func (tm *TestManager) FinalizeUntilEpoch(t *testing.T, epoch uint64) {
},
2000,
tm.MinerAddr,
nil,
)
require.NoError(t, err)
_, err = tm.Sa.Wallet().SendRawTransaction(tx2, true)
Expand Down Expand Up @@ -804,6 +806,7 @@ func (tm *TestManager) sendWatchedStakingTx(
[]*wire.TxOut{stakingInfo.StakingOutput},
2000,
tm.MinerAddr,
nil,
)
require.NoError(t, err)
txHash := tx.TxHash()
Expand Down Expand Up @@ -1677,6 +1680,7 @@ func TestBitcoindWalletRpcApi(t *testing.T) {
[]*wire.TxOut{newOutput},
btcutil.Amount(2000),
walletAddress,
nil,
)
require.NoError(t, err)

Expand Down
21 changes: 20 additions & 1 deletion staker/stakerapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,20 @@ func (app *StakerApp) WatchStaking(
}
}

func (app *StakerApp) filteUtxoFnGen() walletcontroller.UseUtxoFn {
return func(utxo walletcontroller.Utxo) bool {
outpoint := utxo.OutPoint

used, err := app.txTracker.OutpointUsed(&outpoint)

if err != nil {
return false
}

return !used
}
}

func (app *StakerApp) StakeFunds(
stakerAddress btcutil.Address,
stakingAmount btcutil.Amount,
Expand Down Expand Up @@ -1809,7 +1823,12 @@ func (app *StakerApp) StakeFunds(

// Create unsigned transaction by wallet without signing. Signing will happen
// in next steps
tx, err := app.wc.CreateTransaction([]*wire.TxOut{stakingInfo.StakingOutput}, btcutil.Amount(feeRate), stakerAddress)
tx, err := app.wc.CreateTransaction(
[]*wire.TxOut{stakingInfo.StakingOutput},
btcutil.Amount(feeRate),
stakerAddress,
app.filteUtxoFnGen(),
)

if err != nil {
return nil, err
Expand Down
22 changes: 18 additions & 4 deletions walletcontroller/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ func (w *RpcWalletController) NetworkName() string {
func (w *RpcWalletController) CreateTransaction(
outputs []*wire.TxOut,
feeRatePerKb btcutil.Amount,
changeAddres btcutil.Address) (*wire.MsgTx, error) {
changeAddres btcutil.Address,
useUtxoFn UseUtxoFn,
) (*wire.MsgTx, error) {

utxoResults, err := w.ListUnspent()

Expand All @@ -154,17 +156,28 @@ func (w *RpcWalletController) CreateTransaction(
return nil, err
}

var utxosToUse []Utxo
if useUtxoFn != nil {
for _, u := range utxos {
if useUtxoFn(u) {
utxosToUse = append(utxosToUse, u)
}
}
} else {
utxosToUse = utxos
}

// sort utxos by amount from highest to lowest, this is effectively strategy of using
// largest inputs first
sort.Sort(sort.Reverse(byAmount(utxos)))
sort.Sort(sort.Reverse(byAmount(utxosToUse)))

changeScript, err := txscript.PayToAddrScript(changeAddres)

if err != nil {
return nil, err
}

tx, err := buildTxFromOutputs(utxos, outputs, feeRatePerKb, changeScript)
tx, err := buildTxFromOutputs(utxosToUse, outputs, feeRatePerKb, changeScript)

if err != nil {
return nil, err
Expand All @@ -177,8 +190,9 @@ func (w *RpcWalletController) CreateAndSignTx(
outputs []*wire.TxOut,
feeRatePerKb btcutil.Amount,
changeAddress btcutil.Address,
useUtxoFn UseUtxoFn,
) (*wire.MsgTx, error) {
tx, err := w.CreateTransaction(outputs, feeRatePerKb, changeAddress)
tx, err := w.CreateTransaction(outputs, feeRatePerKb, changeAddress, useUtxoFn)

if err != nil {
return nil, err
Expand Down
12 changes: 11 additions & 1 deletion walletcontroller/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,31 @@ type TaprootSigningResult struct {
FullInputWitness wire.TxWitness
}

// Function to filer utxos that should be used in transaction creation
type UseUtxoFn func(utxo Utxo) bool

type WalletController interface {
UnlockWallet(timeoutSecs int64) error
AddressPublicKey(address btcutil.Address) (*btcec.PublicKey, error)
ImportPrivKey(privKeyWIF *btcutil.WIF) error
NetworkName() string
// passning nil usedUtxoFilter will use all possible spendable utxos to choose
// inputs
CreateTransaction(
outputs []*wire.TxOut,
feeRatePerKb btcutil.Amount,
changeScript btcutil.Address) (*wire.MsgTx, error)
changeScript btcutil.Address,
usedUtxoFilter UseUtxoFn,
) (*wire.MsgTx, error)
SignRawTransaction(tx *wire.MsgTx) (*wire.MsgTx, bool, error)
// requires wallet to be unlocked
// passning nil usedUtxoFilter will use all possible spendable utxos to choose
// inputs
CreateAndSignTx(
outputs []*wire.TxOut,
feeRatePerKb btcutil.Amount,
changeAddress btcutil.Address,
usedUtxoFilter UseUtxoFn,
) (*wire.MsgTx, error)
SendRawTransaction(tx *wire.MsgTx, allowHighFees bool) (*chainhash.Hash, error)
ListOutputs(onlySpendable bool) ([]Utxo, error)
Expand Down

0 comments on commit b34531d

Please sign in to comment.