Remove outputs spent by mempool tx from GetAddressUtxo
This commit is contained in:
parent
f1affaf92e
commit
446ba5cd9d
@ -478,35 +478,54 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAddressUtxo returns unspent outputs for given address
|
// GetAddressUtxo returns unspent outputs for given address
|
||||||
func (w *Worker) GetAddressUtxo(address string) ([]AddressUtxo, error) {
|
func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUtxo, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
addrDesc, err := w.chainParser.GetAddrDescFromAddress(address)
|
addrDesc, err := w.chainParser.GetAddrDescFromAddress(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true)
|
return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true)
|
||||||
}
|
}
|
||||||
|
spentInMempool := make(map[string]struct{})
|
||||||
r := make([]AddressUtxo, 0, 8)
|
r := make([]AddressUtxo, 0, 8)
|
||||||
// get utxo from mempool
|
if !onlyConfirmed {
|
||||||
txm, err := w.getAddressTxids(addrDesc, true)
|
// get utxo from mempool
|
||||||
if err != nil {
|
txm, err := w.getAddressTxids(addrDesc, true)
|
||||||
return nil, errors.Annotatef(err, "getAddressTxids %v true", address)
|
|
||||||
}
|
|
||||||
txm = UniqueTxidsInReverse(txm)
|
|
||||||
for _, txid := range txm {
|
|
||||||
bchainTx, _, err := w.txCache.GetTransaction(txid)
|
|
||||||
// mempool transaction may fail
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("GetTransaction in mempool ", txid, ": ", err)
|
return nil, errors.Annotatef(err, "getAddressTxids %v true", address)
|
||||||
} else {
|
}
|
||||||
for i := range bchainTx.Vout {
|
txm = UniqueTxidsInReverse(txm)
|
||||||
bchainVout := &bchainTx.Vout[i]
|
mc := make([]*bchain.Tx, len(txm))
|
||||||
vad, err := w.chainParser.GetAddrDescFromVout(bchainVout)
|
for i, txid := range txm {
|
||||||
if err == nil && bytes.Equal(addrDesc, vad) {
|
// get mempool txs and process their inputs to detect spends between mempool txs
|
||||||
r = append(r, AddressUtxo{
|
bchainTx, _, err := w.txCache.GetTransaction(txid)
|
||||||
Txid: bchainTx.Txid,
|
// mempool transaction may fail
|
||||||
Vout: uint32(i),
|
if err != nil {
|
||||||
AmountSat: bchainVout.ValueSat,
|
glog.Error("GetTransaction in mempool ", txid, ": ", err)
|
||||||
Amount: w.chainParser.AmountToDecimalString(&bchainVout.ValueSat),
|
} else {
|
||||||
})
|
mc[i] = bchainTx
|
||||||
|
// get outputs spent by the mempool tx
|
||||||
|
for i := range bchainTx.Vin {
|
||||||
|
vin := &bchainTx.Vin[i]
|
||||||
|
spentInMempool[vin.Txid+strconv.Itoa(int(vin.Vout))] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, bchainTx := range mc {
|
||||||
|
if bchainTx != nil {
|
||||||
|
for i := range bchainTx.Vout {
|
||||||
|
vout := &bchainTx.Vout[i]
|
||||||
|
vad, err := w.chainParser.GetAddrDescFromVout(vout)
|
||||||
|
if err == nil && bytes.Equal(addrDesc, vad) {
|
||||||
|
// report only outpoints that are not spent in mempool
|
||||||
|
_, e := spentInMempool[bchainTx.Txid+strconv.Itoa(i)]
|
||||||
|
if !e {
|
||||||
|
r = append(r, AddressUtxo{
|
||||||
|
Txid: bchainTx.Txid,
|
||||||
|
Vout: uint32(i),
|
||||||
|
AmountSat: vout.ValueSat,
|
||||||
|
Amount: w.chainParser.AmountToDecimalString(&vout.ValueSat),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -558,14 +577,18 @@ func (w *Worker) GetAddressUtxo(address string) ([]AddressUtxo, error) {
|
|||||||
} else {
|
} else {
|
||||||
if !ta.Outputs[o.vout].Spent {
|
if !ta.Outputs[o.vout].Spent {
|
||||||
v := ta.Outputs[o.vout].ValueSat
|
v := ta.Outputs[o.vout].ValueSat
|
||||||
r = append(r, AddressUtxo{
|
// report only outpoints that are not spent in mempool
|
||||||
Txid: o.txid,
|
_, e := spentInMempool[o.txid+strconv.Itoa(int(o.vout))]
|
||||||
Vout: o.vout,
|
if !e {
|
||||||
AmountSat: v,
|
r = append(r, AddressUtxo{
|
||||||
Amount: w.chainParser.AmountToDecimalString(&v),
|
Txid: o.txid,
|
||||||
Height: int(ta.Height),
|
Vout: o.vout,
|
||||||
Confirmations: bestheight - int(ta.Height) + 1,
|
AmountSat: v,
|
||||||
})
|
Amount: w.chainParser.AmountToDecimalString(&v),
|
||||||
|
Height: int(ta.Height),
|
||||||
|
Confirmations: bestheight - int(ta.Height) + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
checksum.Sub(&checksum, &v)
|
checksum.Sub(&checksum, &v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -691,7 +691,15 @@ func (s *PublicServer) apiAddressUtxo(r *http.Request) (interface{}, error) {
|
|||||||
var err error
|
var err error
|
||||||
s.metrics.ExplorerViews.With(common.Labels{"action": "api-address"}).Inc()
|
s.metrics.ExplorerViews.With(common.Labels{"action": "api-address"}).Inc()
|
||||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
utxo, err = s.api.GetAddressUtxo(r.URL.Path[i+1:])
|
onlyConfirmed := false
|
||||||
|
c := r.URL.Query().Get("confirmed")
|
||||||
|
if len(c) > 0 {
|
||||||
|
onlyConfirmed, err = strconv.ParseBool(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, api.NewAPIError("Parameter 'confirmed' cannot be converted to boolean", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utxo, err = s.api.GetAddressUtxo(r.URL.Path[i+1:], onlyConfirmed)
|
||||||
}
|
}
|
||||||
return utxo, err
|
return utxo, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user