diff --git a/api/worker.go b/api/worker.go index 1a350ddc..adf4fd4c 100644 --- a/api/worker.go +++ b/api/worker.go @@ -222,7 +222,7 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool) (*Tx, error) { func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool) ([]string, error) { var err error - txids := make([]string, 0) + txids := make([]string, 0, 4) if !mempool { err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, vout uint32, isOutput bool) error { txids = append(txids, txid) @@ -484,7 +484,7 @@ func (w *Worker) GetAddressUtxo(address string) ([]AddressUtxo, error) { if err != nil { return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true) } - var r []AddressUtxo + r := make([]AddressUtxo, 0, 8) // get utxo from mempool txm, err := w.getAddressTxids(addrDesc, true) if err != nil { @@ -516,16 +516,17 @@ func (w *Worker) GetAddressUtxo(address string) ([]AddressUtxo, error) { if err != nil { return nil, NewAPIError(fmt.Sprintf("Address not found, %v", err), true) } + var checksum big.Int // ba can be nil if the address is only in mempool! if ba != nil && ba.BalanceSat.Uint64() > 0 { type outpoint struct { txid string vout uint32 } - txids := make([]outpoint, 0) + outpoints := make([]outpoint, 0, 8) err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, vout uint32, isOutput bool) error { if isOutput { - txids = append(txids, outpoint{txid, vout}) + outpoints = append(outpoints, outpoint{txid, vout}) } return nil }) @@ -534,14 +535,14 @@ func (w *Worker) GetAddressUtxo(address string) ([]AddressUtxo, error) { } var lastTxid string var ta *db.TxAddresses - total := ba.BalanceSat + checksum = ba.BalanceSat b, _, err := w.db.GetBestBlock() if err != nil { return nil, err } bestheight := int(b) - for i := len(txids) - 1; i >= 0 && total.Int64() > 0; i-- { - o := txids[i] + for i := len(outpoints) - 1; i >= 0 && checksum.Int64() > 0; i-- { + o := outpoints[i] if lastTxid != o.txid { ta, err = w.db.GetTxAddresses(o.txid) if err != nil { @@ -555,20 +556,25 @@ func (w *Worker) GetAddressUtxo(address string) ([]AddressUtxo, error) { if len(ta.Outputs) <= int(o.vout) { glog.Warning("DB inconsistency: txAddresses ", o.txid, " does not have enough outputs") } else { - v := ta.Outputs[o.vout].ValueSat - r = append(r, AddressUtxo{ - Txid: o.txid, - Vout: o.vout, - AmountSat: v, - Amount: w.chainParser.AmountToDecimalString(&v), - Height: int(ta.Height), - Confirmations: bestheight - int(ta.Height) + 1, - }) - total.Sub(&total, &v) + if !ta.Outputs[o.vout].Spent { + v := ta.Outputs[o.vout].ValueSat + r = append(r, AddressUtxo{ + Txid: o.txid, + Vout: o.vout, + AmountSat: v, + Amount: w.chainParser.AmountToDecimalString(&v), + Height: int(ta.Height), + Confirmations: bestheight - int(ta.Height) + 1, + }) + checksum.Sub(&checksum, &v) + } } } } } + if checksum.Uint64() != 0 { + glog.Warning("DB inconsistency: ", address, ": checksum is not zero") + } glog.Info("GetAddressUtxo ", address, ", ", len(r), " utxos, finished in ", time.Since(start)) return r, nil } diff --git a/db/rocksdb.go b/db/rocksdb.go index e4e163f5..dcd8044c 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -637,7 +637,7 @@ func (d *RocksDB) getBlockTxs(height uint32) ([]blockTxs, error) { } defer val.Free() buf := val.Data() - bt := make([]blockTxs, 0) + bt := make([]blockTxs, 0, 8) for i := 0; i < len(buf); { if len(buf)-i < pl { glog.Error("rocksdb: Inconsistent data in blockTxs ", hex.EncodeToString(buf)) @@ -796,7 +796,7 @@ func unpackTxOutput(to *TxOutput, buf []byte) int { } func (d *RocksDB) packOutpoints(outpoints []outpoint) []byte { - buf := make([]byte, 0) + buf := make([]byte, 0, 32) bvout := make([]byte, vlq.MaxLen32) for _, o := range outpoints { l := packVarint32(o.index, bvout) @@ -808,7 +808,7 @@ func (d *RocksDB) packOutpoints(outpoints []outpoint) []byte { func (d *RocksDB) unpackOutpoints(buf []byte) ([]outpoint, error) { txidUnpackedLen := d.chainParser.PackedTxidLen() - outpoints := make([]outpoint, 0) + outpoints := make([]outpoint, 0, 8) for i := 0; i < len(buf); { btxID := append([]byte(nil), buf[i:i+txidUnpackedLen]...) i += txidUnpackedLen diff --git a/server/socketio.go b/server/socketio.go index 2cdd1361..9c7632d3 100644 --- a/server/socketio.go +++ b/server/socketio.go @@ -210,7 +210,7 @@ type resultAddressTxids struct { } func (s *SocketIoServer) getAddressTxids(addr []string, opts *addrOpts) (res resultAddressTxids, err error) { - txids := make([]string, 0) + txids := make([]string, 0, 8) lower, higher := uint32(opts.End), uint32(opts.Start) for _, address := range addr { if !opts.QueryMempoolOnly { @@ -381,7 +381,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r } txids := txr.Result res.Result.TotalCount = len(txids) - res.Result.Items = make([]addressHistoryItem, 0) + res.Result.Items = make([]addressHistoryItem, 0, 8) to := len(txids) if to > opts.To { to = opts.To