Pass txstore.Credit/Debits directly, not pointers.
The Credit and Debits structures are simple wrappers around an embedded *txstore.TxRecord, as well as an output index in the case of Credit. This means that a Credit is at most two words, while a Debits struct is just one. To avoid the unnecessary garbage of creating Credit and Debits structures on the heap (where the underlying TxRecord likely already is), simply pass around everywhere as non-pointer types, and modify the receivers for all Credit and Debits methods to non-pointer receivers since none of them ever modify the value.
This commit is contained in:
parent
9153a342e4
commit
6a72a0ad4d
6 changed files with 57 additions and 58 deletions
|
@ -651,7 +651,7 @@ func (a *Account) RecoverAddresses(n int) error {
|
|||
|
||||
// ReqSpentUtxoNtfns sends a message to btcd to request updates for when
|
||||
// a stored UTXO has been spent.
|
||||
func ReqSpentUtxoNtfns(credits []*txstore.Credit) {
|
||||
func ReqSpentUtxoNtfns(credits []txstore.Credit) {
|
||||
ops := make([]*btcwire.OutPoint, 0, len(credits))
|
||||
for _, c := range credits {
|
||||
op := c.OutPoint()
|
||||
|
|
16
createtx.go
16
createtx.go
|
@ -61,13 +61,13 @@ var TxFeeIncrement = struct {
|
|||
|
||||
type CreatedTx struct {
|
||||
tx *btcutil.Tx
|
||||
inputs []*txstore.Credit
|
||||
inputs []txstore.Credit
|
||||
changeAddr btcutil.Address
|
||||
}
|
||||
|
||||
// ByAmount defines the methods needed to satisify sort.Interface to
|
||||
// sort a slice of Utxos by their amount.
|
||||
type ByAmount []*txstore.Credit
|
||||
type ByAmount []txstore.Credit
|
||||
|
||||
func (u ByAmount) Len() int { return len(u) }
|
||||
func (u ByAmount) Less(i, j int) bool { return u[i].Amount() < u[j].Amount() }
|
||||
|
@ -79,13 +79,13 @@ func (u ByAmount) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
|
|||
// combination of all selected previous outputs. err will equal
|
||||
// ErrInsufficientFunds if there are not enough unspent outputs to spend amt
|
||||
// amt.
|
||||
func selectInputs(eligible []*txstore.Credit, amt btcutil.Amount,
|
||||
minconf int) (selected []*txstore.Credit, out btcutil.Amount, err error) {
|
||||
func selectInputs(eligible []txstore.Credit, amt btcutil.Amount,
|
||||
minconf int) (selected []txstore.Credit, out btcutil.Amount, err error) {
|
||||
|
||||
// Iterate throguh eligible transactions, appending to outputs and
|
||||
// increasing out. This is finished when out is greater than the
|
||||
// requested amt to spend.
|
||||
selected = make([]*txstore.Credit, 0, len(eligible))
|
||||
selected = make([]txstore.Credit, 0, len(eligible))
|
||||
for _, e := range eligible {
|
||||
selected = append(selected, e)
|
||||
out += e.Amount()
|
||||
|
@ -166,7 +166,7 @@ func (a *Account) txToPairs(pairs map[string]btcutil.Amount,
|
|||
// time) are not P2PKH outputs. Other inputs must be manually included
|
||||
// in transactions and sent (for example, using createrawtransaction,
|
||||
// signrawtransaction, and sendrawtransaction).
|
||||
eligible := make([]*txstore.Credit, 0, len(unspent))
|
||||
eligible := make([]txstore.Credit, 0, len(unspent))
|
||||
for i := range unspent {
|
||||
switch btcscript.GetScriptClass(unspent[i].TxOut().PkScript) {
|
||||
case btcscript.PubKeyHashTy:
|
||||
|
@ -189,7 +189,7 @@ func (a *Account) txToPairs(pairs map[string]btcutil.Amount,
|
|||
// by amount in reverse order.
|
||||
sort.Sort(sort.Reverse(ByAmount(eligible)))
|
||||
|
||||
var selectedInputs []*txstore.Credit
|
||||
var selectedInputs []txstore.Credit
|
||||
// changeAddr is nil/zeroed until a change address is needed, and reused
|
||||
// again in case a change utxo has already been chosen.
|
||||
var changeAddr btcutil.Address
|
||||
|
@ -355,7 +355,7 @@ func minimumFee(tx *btcwire.MsgTx, allowFree bool) btcutil.Amount {
|
|||
// allowFree calculates the transaction priority and checks that the
|
||||
// priority reaches a certain threshhold. If the threshhold is
|
||||
// reached, a free transaction fee is allowed.
|
||||
func allowFree(curHeight int32, txouts []*txstore.Credit, txSize int) bool {
|
||||
func allowFree(curHeight int32, txouts []txstore.Credit, txSize int) bool {
|
||||
const blocksPerDayEstimate = 144
|
||||
const txSizeEstimate = 250
|
||||
|
||||
|
|
|
@ -1477,7 +1477,7 @@ func GetTransaction(icmd btcjson.Cmd) (interface{}, error) {
|
|||
}
|
||||
|
||||
received := btcutil.Amount(0)
|
||||
var debitTx *txstore.TxRecord
|
||||
var debits *txstore.Debits
|
||||
var debitAccount string
|
||||
var targetAddr string
|
||||
|
||||
|
@ -1516,17 +1516,16 @@ func GetTransaction(icmd btcjson.Cmd) (interface{}, error) {
|
|||
})
|
||||
}
|
||||
|
||||
if e.Tx.Debits() != nil {
|
||||
if d, err := e.Tx.Debits(); err == nil {
|
||||
// There should only be a single debits record for any
|
||||
// of the account's transaction records.
|
||||
debitTx = e.Tx
|
||||
debits = &d
|
||||
debitAccount = e.Account
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount := received
|
||||
if debitTx != nil {
|
||||
debits := debitTx.Debits()
|
||||
if debits != nil {
|
||||
totalAmount -= debits.InputAmount()
|
||||
info := btcjson.GetTransactionDetailsResult{
|
||||
Account: debitAccount,
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
// }
|
||||
//
|
||||
// // Mark r2 as debiting from record 1's 0th credit.
|
||||
// d2, err := r2.AddDebits([]*txstore.Credit{c1o0})
|
||||
// d2, err := r2.AddDebits([]txstore.Credit{c1o0})
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
|
|
|
@ -30,7 +30,7 @@ func (t *TxRecord) ToJSON(account string, chainHeight int32,
|
|||
net *btcnet.Params) ([]btcjson.ListTransactionsResult, error) {
|
||||
|
||||
results := []btcjson.ListTransactionsResult{}
|
||||
if d := t.Debits(); d != nil {
|
||||
if d, err := t.Debits(); err == nil {
|
||||
r, err := d.ToJSON(account, chainHeight, net)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -613,21 +613,21 @@ func (t *TxRecord) Block() (*Block, error) {
|
|||
// AddDebits marks a transaction record as having debited from all them transaction
|
||||
// credits in the spent slice. If spent is nil, the previous debits will be found,
|
||||
// however this is an expensive lookup and should be avoided if possible.
|
||||
func (t *TxRecord) AddDebits(spent []*Credit) (*Debits, error) {
|
||||
func (t *TxRecord) AddDebits(spent []Credit) (Debits, error) {
|
||||
if t.debits == nil {
|
||||
// Find now-spent credits if no debits have been previously set
|
||||
// and none were passed in by the caller.
|
||||
if len(spent) == 0 {
|
||||
foundSpent, err := t.s.findPreviousCredits(t.Tx())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return Debits{}, err
|
||||
}
|
||||
spent = foundSpent
|
||||
}
|
||||
|
||||
debitAmount, err := t.s.markOutputsSpent(spent, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return Debits{}, err
|
||||
}
|
||||
t.debits = &debits{amount: debitAmount}
|
||||
}
|
||||
|
@ -655,20 +655,20 @@ func (t *TxRecord) AddDebits(spent []*Credit) (*Debits, error) {
|
|||
err := t.txRecord.setDebitsSpends(prevOutputKeys, t.tx)
|
||||
if err != nil {
|
||||
if err == ErrDuplicateInsert {
|
||||
return &Debits{t}, nil
|
||||
return Debits{t}, nil
|
||||
}
|
||||
return nil, err
|
||||
return Debits{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return &Debits{t}, nil
|
||||
return Debits{t}, nil
|
||||
}
|
||||
|
||||
// findPreviousCredits searches for all unspent credits that make up the inputs
|
||||
// for tx.
|
||||
func (s *Store) findPreviousCredits(tx *btcutil.Tx) ([]*Credit, error) {
|
||||
func (s *Store) findPreviousCredits(tx *btcutil.Tx) ([]Credit, error) {
|
||||
type createdCredit struct {
|
||||
credit *Credit
|
||||
credit Credit
|
||||
err error
|
||||
}
|
||||
|
||||
|
@ -688,11 +688,11 @@ func (s *Store) findPreviousCredits(tx *btcutil.Tx) ([]*Credit, error) {
|
|||
return
|
||||
}
|
||||
t := &TxRecord{key, r, s}
|
||||
c := &Credit{t, op.Index}
|
||||
c := Credit{t, op.Index}
|
||||
creditChans[i] <- createdCredit{credit: c}
|
||||
}(i, txIn.PreviousOutpoint)
|
||||
}
|
||||
spent := make([]*Credit, 0, len(inputs))
|
||||
spent := make([]Credit, 0, len(inputs))
|
||||
for _, c := range creditChans {
|
||||
cc, ok := <-c
|
||||
if !ok {
|
||||
|
@ -708,7 +708,7 @@ func (s *Store) findPreviousCredits(tx *btcutil.Tx) ([]*Credit, error) {
|
|||
|
||||
// markOutputsSpent marks each previous credit spent by t as spent. The total
|
||||
// input of all spent previous outputs is returned.
|
||||
func (s *Store) markOutputsSpent(spent []*Credit, t *TxRecord) (btcutil.Amount, error) {
|
||||
func (s *Store) markOutputsSpent(spent []Credit, t *TxRecord) (btcutil.Amount, error) {
|
||||
var a btcutil.Amount
|
||||
for _, prev := range spent {
|
||||
op := prev.OutPoint()
|
||||
|
@ -755,17 +755,17 @@ func (s *Store) markOutputsSpent(spent []*Credit, t *TxRecord) (btcutil.Amount,
|
|||
// AddCredit marks the transaction record as containing a transaction output
|
||||
// spendable by wallet. The output is added unspent, and is marked spent
|
||||
// when a new transaction spending the output is inserted into the store.
|
||||
func (t *TxRecord) AddCredit(index uint32, change bool) (*Credit, error) {
|
||||
func (t *TxRecord) AddCredit(index uint32, change bool) (Credit, error) {
|
||||
if len(t.tx.MsgTx().TxOut) <= int(index) {
|
||||
return nil, errors.New("transaction output does not exist")
|
||||
return Credit{}, errors.New("transaction output does not exist")
|
||||
}
|
||||
|
||||
c := &credit{change: change}
|
||||
if err := t.txRecord.setCredit(c, index, t.tx); err != nil {
|
||||
if err == ErrDuplicateInsert {
|
||||
return &Credit{t, index}, nil
|
||||
return Credit{t, index}, nil
|
||||
}
|
||||
return nil, err
|
||||
return Credit{}, err
|
||||
}
|
||||
|
||||
switch t.BlockHeight {
|
||||
|
@ -773,7 +773,7 @@ func (t *TxRecord) AddCredit(index uint32, change bool) (*Credit, error) {
|
|||
default:
|
||||
b, err := t.s.lookupBlock(t.BlockHeight)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return Credit{}, err
|
||||
}
|
||||
|
||||
// New outputs are added unspent.
|
||||
|
@ -787,7 +787,7 @@ func (t *TxRecord) AddCredit(index uint32, change bool) (*Credit, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return &Credit{t, index}, nil
|
||||
return Credit{t, index}, nil
|
||||
}
|
||||
|
||||
// Rollback removes all blocks at height onwards, moving any transactions within
|
||||
|
@ -1024,9 +1024,9 @@ func (s *Store) removeConflict(r *txRecord) error {
|
|||
|
||||
// UnspentOutputs returns all unspent received transaction outputs.
|
||||
// The order is undefined.
|
||||
func (s *Store) UnspentOutputs() ([]*Credit, error) {
|
||||
func (s *Store) UnspentOutputs() ([]Credit, error) {
|
||||
type createdCredit struct {
|
||||
credit *Credit
|
||||
credit Credit
|
||||
err error
|
||||
}
|
||||
|
||||
|
@ -1041,13 +1041,13 @@ func (s *Store) UnspentOutputs() ([]*Credit, error) {
|
|||
return
|
||||
}
|
||||
t := &TxRecord{key, r, s}
|
||||
c := &Credit{t, opIndex}
|
||||
c := Credit{t, opIndex}
|
||||
creditChans[i] <- createdCredit{credit: c}
|
||||
}(i, op.Index)
|
||||
i++
|
||||
}
|
||||
|
||||
unspent := make([]*Credit, 0, len(s.unspent))
|
||||
unspent := make([]Credit, 0, len(s.unspent))
|
||||
for _, c := range creditChans {
|
||||
cc, ok := <-c
|
||||
if !ok {
|
||||
|
@ -1066,7 +1066,7 @@ func (s *Store) UnspentOutputs() ([]*Credit, error) {
|
|||
}
|
||||
key := BlockTxKey{BlockHeight: -1}
|
||||
txRecord := &TxRecord{key, r, s}
|
||||
c := &Credit{txRecord, uint32(outputIndex)}
|
||||
c := Credit{txRecord, uint32(outputIndex)}
|
||||
unspent = append(unspent, c)
|
||||
}
|
||||
}
|
||||
|
@ -1082,7 +1082,7 @@ type unspentTx struct {
|
|||
sliceIndex uint32
|
||||
}
|
||||
|
||||
type creditSlice []*Credit
|
||||
type creditSlice []Credit
|
||||
|
||||
func (s creditSlice) Len() int {
|
||||
return len(s)
|
||||
|
@ -1124,10 +1124,10 @@ func (s creditSlice) Swap(i, j int) {
|
|||
// in the same block (same number of confirmations) are sorted by block
|
||||
// index in increasing order. Credits (outputs) from the same transaction
|
||||
// are sorted by output index in increasing order.
|
||||
func (s *Store) SortedUnspentOutputs() ([]*Credit, error) {
|
||||
func (s *Store) SortedUnspentOutputs() ([]Credit, error) {
|
||||
unspent, err := s.UnspentOutputs()
|
||||
if err != nil {
|
||||
return []*Credit{}, err
|
||||
return []Credit{}, err
|
||||
}
|
||||
sort.Sort(sort.Reverse(creditSlice(unspent)))
|
||||
return unspent, nil
|
||||
|
@ -1258,29 +1258,29 @@ func (r byReceiveDate) Len() int { return len(r) }
|
|||
func (r byReceiveDate) Less(i, j int) bool { return r[i].received.Before(r[j].received) }
|
||||
func (r byReceiveDate) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
|
||||
// Debits returns the debit record for the transaction, or nil if the
|
||||
// transaction does not debit from any previous transaction credits.
|
||||
func (t *TxRecord) Debits() *Debits {
|
||||
// Debits returns the debit record for the transaction, or a non-nil error if
|
||||
// the transaction does not debit from any previous transaction credits.
|
||||
func (t *TxRecord) Debits() (Debits, error) {
|
||||
if t.debits == nil {
|
||||
return nil
|
||||
return Debits{}, errors.New("no debits")
|
||||
}
|
||||
return &Debits{t}
|
||||
return Debits{t}, nil
|
||||
}
|
||||
|
||||
// Credits returns all credit records for this transaction's outputs that are or
|
||||
// were spendable by wallet.
|
||||
func (t *TxRecord) Credits() []*Credit {
|
||||
credits := make([]*Credit, 0, len(t.credits))
|
||||
func (t *TxRecord) Credits() []Credit {
|
||||
credits := make([]Credit, 0, len(t.credits))
|
||||
for i, c := range t.credits {
|
||||
if c != nil {
|
||||
credits = append(credits, &Credit{t, uint32(i)})
|
||||
credits = append(credits, Credit{t, uint32(i)})
|
||||
}
|
||||
}
|
||||
return credits
|
||||
}
|
||||
|
||||
// InputAmount returns the total amount debited from previous credits.
|
||||
func (d *Debits) InputAmount() btcutil.Amount {
|
||||
func (d Debits) InputAmount() btcutil.Amount {
|
||||
return d.txRecord.debits.amount
|
||||
}
|
||||
|
||||
|
@ -1301,13 +1301,13 @@ func (t *TxRecord) OutputAmount(ignoreChange bool) btcutil.Amount {
|
|||
|
||||
// Fee returns the difference between the debited amount and the total
|
||||
// transaction output.
|
||||
func (d *Debits) Fee() btcutil.Amount {
|
||||
func (d Debits) Fee() btcutil.Amount {
|
||||
return d.InputAmount() - d.OutputAmount(false)
|
||||
}
|
||||
|
||||
// Addresses parses the pubkey script, extracting all addresses for a
|
||||
// standard script.
|
||||
func (c *Credit) Addresses(net *btcnet.Params) (btcscript.ScriptClass,
|
||||
func (c Credit) Addresses(net *btcnet.Params) (btcscript.ScriptClass,
|
||||
[]btcutil.Address, int, error) {
|
||||
|
||||
msgTx := c.Tx().MsgTx()
|
||||
|
@ -1316,7 +1316,7 @@ func (c *Credit) Addresses(net *btcnet.Params) (btcscript.ScriptClass,
|
|||
}
|
||||
|
||||
// Change returns whether the credit is the result of a change output.
|
||||
func (c *Credit) Change() bool {
|
||||
func (c Credit) Change() bool {
|
||||
return c.txRecord.credits[c.OutputIndex].change
|
||||
}
|
||||
|
||||
|
@ -1338,19 +1338,19 @@ func (t *TxRecord) IsCoinbase() bool {
|
|||
}
|
||||
|
||||
// Amount returns the amount credited to the account from a transaction output.
|
||||
func (c *Credit) Amount() btcutil.Amount {
|
||||
func (c Credit) Amount() btcutil.Amount {
|
||||
msgTx := c.Tx().MsgTx()
|
||||
return btcutil.Amount(msgTx.TxOut[c.OutputIndex].Value)
|
||||
}
|
||||
|
||||
// OutPoint returns the outpoint needed to include in a transaction input
|
||||
// to spend this output.
|
||||
func (c *Credit) OutPoint() *btcwire.OutPoint {
|
||||
func (c Credit) OutPoint() *btcwire.OutPoint {
|
||||
return btcwire.NewOutPoint(c.Tx().Sha(), c.OutputIndex)
|
||||
}
|
||||
|
||||
// outputKey creates and returns the block lookup key for this credit.
|
||||
func (c *Credit) outputKey() *BlockOutputKey {
|
||||
func (c Credit) outputKey() *BlockOutputKey {
|
||||
return &BlockOutputKey{
|
||||
BlockTxKey: c.BlockTxKey,
|
||||
OutputIndex: c.OutputIndex,
|
||||
|
@ -1358,12 +1358,12 @@ func (c *Credit) outputKey() *BlockOutputKey {
|
|||
}
|
||||
|
||||
// Spent returns whether the transaction output is currently spent or not.
|
||||
func (c *Credit) Spent() bool {
|
||||
func (c Credit) Spent() bool {
|
||||
return c.txRecord.credits[c.OutputIndex].spentBy != nil
|
||||
}
|
||||
|
||||
// TxOut returns the transaction output which this credit references.
|
||||
func (c *Credit) TxOut() *btcwire.TxOut {
|
||||
func (c Credit) TxOut() *btcwire.TxOut {
|
||||
return c.Tx().MsgTx().TxOut[c.OutputIndex]
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue