Improve tx creation performance.
Unspent inputs were being sorted multiple times in an inner loop. This change moves the sort outside the loop so it is only performed once. While here, also move the transaction confirmation filter outside the inner loop, as these can be calculated just once.
This commit is contained in:
parent
c0e990fb3f
commit
83b70e6c7e
1 changed files with 23 additions and 30 deletions
53
createtx.go
53
createtx.go
|
@ -75,40 +75,17 @@ func (u ByAmount) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
|
||||||
|
|
||||||
// selectInputs selects the minimum number possible of unspent
|
// selectInputs selects the minimum number possible of unspent
|
||||||
// outputs to use to create a new transaction that spends amt satoshis.
|
// outputs to use to create a new transaction that spends amt satoshis.
|
||||||
// Previous outputs with less than minconf confirmations are ignored. btcout
|
// btcout is the total number of satoshis which would be spent by the
|
||||||
// is the total number of satoshis which would be spent by the combination
|
// combination of all selected previous outputs. err will equal
|
||||||
// of all selected previous outputs. err will equal ErrInsufficientFunds if there
|
// ErrInsufficientFunds if there are not enough unspent outputs to spend amt
|
||||||
// are not enough unspent outputs to spend amt.
|
// amt.
|
||||||
func selectInputs(credits []*txstore.Credit, amt btcutil.Amount,
|
func selectInputs(eligible []*txstore.Credit, amt btcutil.Amount,
|
||||||
minconf int) (selected []*txstore.Credit, out btcutil.Amount, err error) {
|
minconf int) (selected []*txstore.Credit, out btcutil.Amount, err error) {
|
||||||
|
|
||||||
bs, err := GetCurBlock()
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create list of eligible unspent previous outputs to use as tx
|
|
||||||
// inputs, and sort by the amount in reverse order so a minimum number
|
|
||||||
// of inputs is needed.
|
|
||||||
eligible := make([]*txstore.Credit, 0, len(credits))
|
|
||||||
for _, c := range credits {
|
|
||||||
if c.Confirmed(minconf, bs.Height) {
|
|
||||||
// Coinbase transactions must have have reached maturity
|
|
||||||
// before their outputs may be spent.
|
|
||||||
if c.IsCoinbase() {
|
|
||||||
target := btcchain.CoinbaseMaturity
|
|
||||||
if !c.Confirmed(target, bs.Height) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eligible = append(eligible, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(ByAmount(eligible)))
|
|
||||||
|
|
||||||
// Iterate throguh eligible transactions, appending to outputs and
|
// Iterate throguh eligible transactions, appending to outputs and
|
||||||
// increasing out. This is finished when out is greater than the
|
// increasing out. This is finished when out is greater than the
|
||||||
// requested amt to spend.
|
// requested amt to spend.
|
||||||
|
selected = make([]*txstore.Credit, 0, len(eligible))
|
||||||
for _, e := range eligible {
|
for _, e := range eligible {
|
||||||
selected = append(selected, e)
|
selected = append(selected, e)
|
||||||
out += e.Amount()
|
out += e.Amount()
|
||||||
|
@ -184,6 +161,7 @@ func (a *Account) txToPairs(pairs map[string]btcutil.Amount,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out unspendable outputs, that is, remove those that (at this
|
// Filter out unspendable outputs, that is, remove those that (at this
|
||||||
// time) are not P2PKH outputs. Other inputs must be manually included
|
// time) are not P2PKH outputs. Other inputs must be manually included
|
||||||
// in transactions and sent (for example, using createrawtransaction,
|
// in transactions and sent (for example, using createrawtransaction,
|
||||||
|
@ -192,12 +170,27 @@ func (a *Account) txToPairs(pairs map[string]btcutil.Amount,
|
||||||
for i := range unspent {
|
for i := range unspent {
|
||||||
switch btcscript.GetScriptClass(unspent[i].TxOut().PkScript) {
|
switch btcscript.GetScriptClass(unspent[i].TxOut().PkScript) {
|
||||||
case btcscript.PubKeyHashTy:
|
case btcscript.PubKeyHashTy:
|
||||||
|
if !unspent[i].Confirmed(minconf, bs.Height) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Coinbase transactions must have have reached maturity
|
||||||
|
// before their outputs may be spent.
|
||||||
|
if unspent[i].IsCoinbase() {
|
||||||
|
target := btcchain.CoinbaseMaturity
|
||||||
|
if !unspent[i].Confirmed(target, bs.Height) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
eligible = append(eligible, unspent[i])
|
eligible = append(eligible, unspent[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort eligible inputs, as selectInputs expects these to be sorted
|
||||||
|
// by amount in reverse order.
|
||||||
|
sort.Sort(sort.Reverse(ByAmount(eligible)))
|
||||||
|
|
||||||
var selectedInputs []*txstore.Credit
|
var selectedInputs []*txstore.Credit
|
||||||
// These are nil/zeroed until a change address is needed, and reused
|
// changeAddr is nil/zeroed until a change address is needed, and reused
|
||||||
// again in case a change utxo has already been chosen.
|
// again in case a change utxo has already been chosen.
|
||||||
var changeAddr btcutil.Address
|
var changeAddr btcutil.Address
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue