From 0067de8de6e6b13c97fb4d0064d1c9db5b4ed8a0 Mon Sep 17 00:00:00 2001 From: martonp Date: Sat, 16 Apr 2022 18:50:33 +0700 Subject: [PATCH] Don't sort transactions. --- client/asset/btc/btc.go | 128 +++++++---------------------------- client/asset/btc/btc_test.go | 12 ++-- 2 files changed, 32 insertions(+), 108 deletions(-) diff --git a/client/asset/btc/btc.go b/client/asset/btc/btc.go index 14d1acaa15..0588ee9021 100644 --- a/client/asset/btc/btc.go +++ b/client/asset/btc/btc.go @@ -1933,7 +1933,7 @@ func (btc *baseWallet) AccelerationEstimate(swapCoins, accelerationCoins []dex.B // since either the earliest unconfirmed transaction in the chain, or the // latest acceleration transaction. It also returns the minimum time when // the user can do an acceleration. -func tooEarlyToAccelerate(sortedTxChain []*GetTransactionResult, accelerationCoins []dex.Bytes) (bool, uint64, error) { +func tooEarlyToAccelerate(txs []*GetTransactionResult, accelerationCoins []dex.Bytes) (bool, uint64, error) { accelerationTxs := make(map[string]bool, len(accelerationCoins)) for _, accelerationCoin := range accelerationCoins { txHash, _, err := decodeCoinID(accelerationCoin) @@ -1943,24 +1943,30 @@ func tooEarlyToAccelerate(sortedTxChain []*GetTransactionResult, accelerationCoi accelerationTxs[txHash.String()] = true } - var timeToCompare uint64 - for _, tx := range sortedTxChain { + var latestAcceleration, earliestUnconfirmed uint64 + for _, tx := range txs { if tx.Confirmations > 0 { continue } - if timeToCompare == 0 { - timeToCompare = tx.Time + if accelerationTxs[tx.TxID] && tx.Time > latestAcceleration { + latestAcceleration = tx.Time continue } - if accelerationTxs[tx.TxID] { - timeToCompare = tx.Time + if earliestUnconfirmed == 0 || tx.Time < earliestUnconfirmed { + earliestUnconfirmed = tx.Time } } - - if timeToCompare == 0 { + if latestAcceleration == 0 && earliestUnconfirmed == 0 { return false, 0, fmt.Errorf("no need to accelerate because all tx are confirmed") } + var timeToCompare uint64 + if latestAcceleration != 0 { + timeToCompare = latestAcceleration + } else { + timeToCompare = earliestUnconfirmed + } + currentTime := uint64(time.Now().Unix()) minAccelerationTime := timeToCompare + minTimeBeforeAcceleration return minAccelerationTime > currentTime, minAccelerationTime, nil @@ -1984,13 +1990,13 @@ func (btc *baseWallet) PreAccelerate(swapCoins, accelerationCoins []dex.Bytes, c return makeError(err) } - sortedTxChain, err := btc.sortedTxChain(swapCoins, accelerationCoins, changeCoin) + txs, err := btc.getTransactions(append(swapCoins, accelerationCoins...)) if err != nil { return makeError(fmt.Errorf("failed to sort swap chain: %w", err)) } var swapTxsSize, feesAlreadyPaid uint64 - for _, tx := range sortedTxChain { + for _, tx := range txs { if tx.Confirmations > 0 { continue } @@ -2008,7 +2014,7 @@ func (btc *baseWallet) PreAccelerate(swapCoins, accelerationCoins []dex.Bytes, c } if btc.net != dex.Simnet { - tooEarly, minAccelerationTime, err := tooEarlyToAccelerate(sortedTxChain, accelerationCoins) + tooEarly, minAccelerationTime, err := tooEarlyToAccelerate(txs, accelerationCoins) if err != nil { return makeError(err) } @@ -2114,7 +2120,7 @@ func (btc *baseWallet) signedAccelerationTx(swapCoins, accelerationCoins []dex.B return makeError(err) } - sortedTxChain, err := btc.sortedTxChain(swapCoins, accelerationCoins, changeCoin) + txs, err := btc.getTransactions(append(swapCoins, accelerationCoins...)) if err != nil { return makeError(fmt.Errorf("failed to sort swap chain: %w", err)) } @@ -2124,7 +2130,7 @@ func (btc *baseWallet) signedAccelerationTx(swapCoins, accelerationCoins []dex.B return makeError(err) } - additionalFeesRequired, err := btc.additionalFeesRequired(sortedTxChain, newFeeRate) + additionalFeesRequired, err := btc.additionalFeesRequired(txs, newFeeRate) if err != nil { return makeError(err) } @@ -2134,7 +2140,7 @@ func (btc *baseWallet) signedAccelerationTx(swapCoins, accelerationCoins []dex.B } if btc.net != dex.Simnet { - tooEarly, minAccelerationTime, err := tooEarlyToAccelerate(sortedTxChain, accelerationCoins) + tooEarly, minAccelerationTime, err := tooEarlyToAccelerate(txs, accelerationCoins) if err != nil { return makeError(err) } @@ -2273,29 +2279,14 @@ func (btc *baseWallet) changeCanBeAccelerated(changeTxHash *chainhash.Hash, chan return nil } -// sortedTxChain takes a list of swap coins, acceleration tx IDs, and a change -// coin, and returns a sorted list of transactions. An error is returned if a -// sorted list of transactions that ends with a transaction containing the change -// cannot be created using each of the swap coins and acceleration transactions. -func (btc *baseWallet) sortedTxChain(swapCoins, accelerationCoins []dex.Bytes, change dex.Bytes) ([]*GetTransactionResult, error) { - txChain := make([]*GetTransactionResult, 0, len(swapCoins)+len(accelerationCoins)) - if len(swapCoins) == 0 { +// getTransactions retrieves the transactions that created coins. +func (btc *baseWallet) getTransactions(coins []dex.Bytes) ([]*GetTransactionResult, error) { + txChain := make([]*GetTransactionResult, 0, len(coins)) + if len(coins) == 0 { return txChain, nil } - for _, coinID := range swapCoins { - txHash, _, err := decodeCoinID(coinID) - if err != nil { - return nil, err - } - getTxRes, err := btc.node.getWalletTransaction(txHash) - if err != nil { - return nil, err - } - txChain = append(txChain, getTxRes) - } - - for _, coinID := range accelerationCoins { + for _, coinID := range coins { txHash, _, err := decodeCoinID(coinID) if err != nil { return nil, err @@ -2307,73 +2298,6 @@ func (btc *baseWallet) sortedTxChain(swapCoins, accelerationCoins []dex.Bytes, c txChain = append(txChain, getTxRes) } - msgTxs := make(map[string]*wire.MsgTx, len(txChain)) - for _, gtr := range txChain { - msgTx, err := msgTxFromBytes(gtr.Hex) - if err != nil { - return nil, err - } - msgTxs[gtr.TxID] = msgTx - } - - changeTxHash, _, err := decodeCoinID(change) - if err != nil { - return nil, err - } - - swap := func(i, j int) { - temp := txChain[j] - txChain[j] = txChain[i] - txChain[i] = temp - } - - // sourcesOfTxInputs finds the transaction IDs that the inputs - // for a certain transaction come from. If all the transactions - // are from the same order, only the first transaction in - // the chain can have multiple inputs. - sourcesOfTxInputs := func(txID string) (map[string]bool, error) { - lastTx, found := msgTxs[txID] - if !found { - // this should never happen - return nil, fmt.Errorf("could not find tx with id: %v", txID) - } - - inputSources := make(map[string]bool, len(lastTx.TxIn)) - for _, in := range lastTx.TxIn { - inputSources[in.PreviousOutPoint.Hash.String()] = true - } - return inputSources, nil - } - - // The last tx in the chain must have the same tx hash as the change. - for i, tx := range txChain { - if tx.TxID == changeTxHash.String() { - swap(i, len(txChain)-1) - break - } - if i == len(txChain)-1 { - return nil, fmt.Errorf("could not find tx containing change coin") - } - } - - // We work backwards to find each element of the swap chain. - for i := len(txChain) - 2; i >= 0; i-- { - lastTxInputs, err := sourcesOfTxInputs(txChain[i+1].TxID) - if err != nil { - return nil, err - } - - for j, getTxRes := range txChain { - if lastTxInputs[getTxRes.TxID] { - swap(i, j) - break - } - if j == len(txChain)-1 { - return nil, errors.New("could not find previous element of sorted chain") - } - } - } - return txChain, nil } diff --git a/client/asset/btc/btc_test.go b/client/asset/btc/btc_test.go index 3dcc30d215..8b8aaf3c3f 100644 --- a/client/asset/btc/btc_test.go +++ b/client/asset/btc/btc_test.go @@ -3846,7 +3846,7 @@ func testAccelerateOrder(t *testing.T, segwit bool, walletType string) { } } -func TestTooEarlyToAcceelrate(t *testing.T) { +func TestTooEarlyToAccelerate(t *testing.T) { tests := []struct { name string confirmations []uint64 @@ -3870,26 +3870,26 @@ func TestTooEarlyToAcceelrate(t *testing.T) { }, { name: "no accelerations, not too early", - confirmations: []uint64{2, 2, 0, 0}, + confirmations: []uint64{2, 0, 0, 2}, isAcceleration: []bool{false, false, false, false}, secondsBeforeNow: []uint64{ minTimeBeforeAcceleration + 1000, - minTimeBeforeAcceleration + 800, minTimeBeforeAcceleration + 500, minTimeBeforeAcceleration + 300, + minTimeBeforeAcceleration + 800, }, expectTooEarly: false, expectMinTimeToAccelerate: -500, }, { name: "acceleration after unconfirmed, not too early", - confirmations: []uint64{2, 2, 0, 0}, - isAcceleration: []bool{false, false, false, true}, + confirmations: []uint64{0, 2, 2, 0}, + isAcceleration: []bool{true, false, false, false}, secondsBeforeNow: []uint64{ + minTimeBeforeAcceleration + 300, minTimeBeforeAcceleration + 1000, minTimeBeforeAcceleration + 800, minTimeBeforeAcceleration + 500, - minTimeBeforeAcceleration + 300, }, expectTooEarly: false, expectMinTimeToAccelerate: -300,