Use AddressDescriptor for queries in api worker

This commit is contained in:
Martin Boehm 2018-08-31 15:23:04 +02:00
parent 6f25785109
commit 1109cd7878
3 changed files with 75 additions and 48 deletions

View File

@ -1,6 +1,9 @@
package api package api
import "math/big" import (
"blockbook/bchain"
"math/big"
)
type ApiError struct { type ApiError struct {
Text string Text string
@ -24,23 +27,25 @@ type ScriptSig struct {
} }
type Vin struct { type Vin struct {
Txid string `json:"txid"` Txid string `json:"txid"`
Vout uint32 `json:"vout"` Vout uint32 `json:"vout"`
Sequence int64 `json:"sequence,omitempty"` Sequence int64 `json:"sequence,omitempty"`
N int `json:"n"` N int `json:"n"`
ScriptSig ScriptSig `json:"scriptSig"` ScriptSig ScriptSig `json:"scriptSig"`
Addresses []string `json:"addresses"` AddrDesc bchain.AddressDescriptor `json:"-"`
Searchable bool `json:"-"` Addresses []string `json:"addresses"`
Value string `json:"value"` Searchable bool `json:"-"`
ValueSat big.Int `json:"-"` Value string `json:"value"`
ValueSat big.Int `json:"-"`
} }
type ScriptPubKey struct { type ScriptPubKey struct {
Hex string `json:"hex"` Hex string `json:"hex"`
Asm string `json:"asm,omitempty"` Asm string `json:"asm,omitempty"`
Addresses []string `json:"addresses"` AddrDesc bchain.AddressDescriptor `json:"-"`
Searchable bool `json:"-"` Addresses []string `json:"addresses"`
Type string `json:"type,omitempty"` Searchable bool `json:"-"`
Type string `json:"type,omitempty"`
} }
type Vout struct { type Vout struct {
Value string `json:"value"` Value string `json:"value"`

View File

@ -4,6 +4,7 @@ import (
"blockbook/bchain" "blockbook/bchain"
"blockbook/common" "blockbook/common"
"blockbook/db" "blockbook/db"
"bytes"
"fmt" "fmt"
"math/big" "math/big"
"time" "time"
@ -33,12 +34,13 @@ func NewWorker(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is
return w, nil return w, nil
} }
func (w *Worker) getAddressesFromVout(vout *bchain.Vout) ([]string, bool, error) { func (w *Worker) getAddressesFromVout(vout *bchain.Vout) (bchain.AddressDescriptor, []string, bool, error) {
addrDesc, err := w.chainParser.GetAddrDescFromVout(vout) addrDesc, err := w.chainParser.GetAddrDescFromVout(vout)
if err != nil { if err != nil {
return nil, false, err return nil, nil, false, err
} }
return w.chainParser.GetAddressesFromAddrDesc(addrDesc) a, s, err := w.chainParser.GetAddressesFromAddrDesc(addrDesc)
return addrDesc, a, s, err
} }
// GetTransaction reads transaction data from txid // GetTransaction reads transaction data from txid
@ -47,6 +49,10 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTxs bool
if err != nil { if err != nil {
return nil, NewApiError(fmt.Sprintf("Tx not found, %v", err), true) return nil, NewApiError(fmt.Sprintf("Tx not found, %v", err), true)
} }
ta, err := w.db.GetTxAddresses(txid)
if err != nil {
return nil, errors.Annotatef(err, "GetTxAddresses %v", txid)
}
var blockhash string var blockhash string
if bchainTx.Confirmations > 0 { if bchainTx.Confirmations > 0 {
blockhash, err = w.db.GetBlockHash(height) blockhash, err = w.db.GetBlockHash(height)
@ -66,11 +72,11 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTxs bool
// bchainVin.Txid=="" is coinbase transaction // bchainVin.Txid=="" is coinbase transaction
if bchainVin.Txid != "" { if bchainVin.Txid != "" {
// load spending addresses from TxAddresses // load spending addresses from TxAddresses
ta, err := w.db.GetTxAddresses(bchainVin.Txid) tas, err := w.db.GetTxAddresses(bchainVin.Txid)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "GetTxAddresses %v", bchainVin.Txid) return nil, errors.Annotatef(err, "GetTxAddresses %v", bchainVin.Txid)
} }
if ta == nil { if tas == nil {
// mempool transactions are not in TxAddresses, all confirmed should be there, log a problem // mempool transactions are not in TxAddresses, all confirmed should be there, log a problem
if bchainTx.Confirmations > 0 { if bchainTx.Confirmations > 0 {
glog.Warning("DB inconsistency: tx ", bchainVin.Txid, ": not found in txAddresses") glog.Warning("DB inconsistency: tx ", bchainVin.Txid, ": not found in txAddresses")
@ -83,14 +89,14 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTxs bool
if len(otx.Vout) > int(vin.Vout) { if len(otx.Vout) > int(vin.Vout) {
vout := &otx.Vout[vin.Vout] vout := &otx.Vout[vin.Vout]
vin.ValueSat = vout.ValueSat vin.ValueSat = vout.ValueSat
vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout) vin.AddrDesc, vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout)
if err != nil { if err != nil {
glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout) glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout)
} }
} }
} else { } else {
if len(ta.Outputs) > int(vin.Vout) { if len(tas.Outputs) > int(vin.Vout) {
output := &ta.Outputs[vin.Vout] output := &tas.Outputs[vin.Vout]
vin.ValueSat = output.ValueSat vin.ValueSat = output.ValueSat
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat) vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser) vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser)
@ -112,9 +118,12 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTxs bool
vout.Value = w.chainParser.AmountToDecimalString(&bchainVout.ValueSat) vout.Value = w.chainParser.AmountToDecimalString(&bchainVout.ValueSat)
valOutSat.Add(&valOutSat, &bchainVout.ValueSat) valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = w.getAddressesFromVout(bchainVout) vout.ScriptPubKey.AddrDesc, vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = w.getAddressesFromVout(bchainVout)
if spendingTxs { if ta != nil {
// TODO vout.Spent = ta.Outputs[i].Spent
if spendingTxs && vout.Spent {
// TODO
}
} }
} }
// for coinbase transactions valIn is 0 // for coinbase transactions valIn is 0
@ -143,11 +152,11 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTxs bool
return r, nil return r, nil
} }
func (w *Worker) getAddressTxids(address string, mempool bool) ([]string, error) { func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool) ([]string, error) {
var err error var err error
txids := make([]string, 0) txids := make([]string, 0)
if !mempool { if !mempool {
err = w.db.GetTransactions(address, 0, ^uint32(0), func(txid string, vout uint32, isOutput bool) error { err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, vout uint32, isOutput bool) error {
txids = append(txids, txid) txids = append(txids, txid)
return nil return nil
}) })
@ -155,7 +164,7 @@ func (w *Worker) getAddressTxids(address string, mempool bool) ([]string, error)
return nil, err return nil, err
} }
} else { } else {
m, err := w.chain.GetMempoolTransactions(address) m, err := w.chain.GetMempoolTransactionsForAddrDesc(addrDesc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -164,25 +173,21 @@ func (w *Worker) getAddressTxids(address string, mempool bool) ([]string, error)
return txids, nil return txids, nil
} }
func (t *Tx) getAddrVoutValue(addr string) *big.Int { func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
var val big.Int var val big.Int
for _, vout := range t.Vout { for _, vout := range t.Vout {
for _, a := range vout.ScriptPubKey.Addresses { if bytes.Equal(vout.ScriptPubKey.AddrDesc, addrDesc) {
if a == addr { val.Add(&val, &vout.ValueSat)
val.Add(&val, &vout.ValueSat)
}
} }
} }
return &val return &val
} }
func (t *Tx) getAddrVinValue(addr string) *big.Int { func (t *Tx) getAddrVinValue(addrDesc bchain.AddressDescriptor) *big.Int {
var val big.Int var val big.Int
for _, vin := range t.Vin { for _, vin := range t.Vin {
for _, a := range vin.Addresses { if bytes.Equal(vin.AddrDesc, addrDesc) {
if a == addr { val.Add(&val, &vin.ValueSat)
val.Add(&val, &vin.ValueSat)
}
} }
} }
return &val return &val
@ -260,27 +265,37 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
if page < 0 { if page < 0 {
page = 0 page = 0
} }
ba, err := w.db.GetAddressBalance(address) addrDesc, err := w.chainParser.GetAddrDescFromAddress(address)
if err != nil { if err != nil {
return nil, NewApiError(fmt.Sprintf("Address not found, %v", err), true) return nil, NewApiError(fmt.Sprintf("Address not found, %v", err), true)
} }
if ba == nil { // ba can be nil if the address is only in mempool!
return nil, NewApiError("Address not found", true) ba, err := w.db.GetAddrDescBalance(addrDesc)
if err != nil {
return nil, NewApiError(fmt.Sprintf("Address not found, %v", err), true)
} }
txc, err := w.getAddressTxids(address, false) txc, err := w.getAddressTxids(addrDesc, false)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "getAddressTxids %v false", address) return nil, errors.Annotatef(err, "getAddressTxids %v false", address)
} }
txc = UniqueTxidsInReverse(txc) txc = UniqueTxidsInReverse(txc)
var txm []string var txm []string
// mempool only on the first page // mempool only on the first page or if there are no confirmed transactions
if page == 0 { if page == 0 || ba == nil {
txm, err = w.getAddressTxids(address, true) if ba == nil {
ba = &db.AddrBalance{}
page = 0
}
txm, err = w.getAddressTxids(addrDesc, true)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "getAddressTxids %v true", address) return nil, errors.Annotatef(err, "getAddressTxids %v true", address)
} }
txm = UniqueTxidsInReverse(txm) txm = UniqueTxidsInReverse(txm)
} }
// check if the address exist
if len(txc)+len(txm) == 0 {
return nil, NewApiError("Address not found", true)
}
bestheight, _, err := w.db.GetBestBlock() bestheight, _, err := w.db.GetBestBlock()
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "GetBestBlock") return nil, errors.Annotatef(err, "GetBestBlock")
@ -309,7 +324,9 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
if err != nil { if err != nil {
glog.Error("GetTransaction in mempool ", tx, ": ", err) glog.Error("GetTransaction in mempool ", tx, ": ", err)
} else { } else {
uBalSat.Sub(tx.getAddrVoutValue(address), tx.getAddrVinValue(address)) uBalSat.Add(&uBalSat, tx.getAddrVoutValue(addrDesc))
uBalSat.Sub(&uBalSat, tx.getAddrVinValue(addrDesc))
glog.Info("uBalSat ", uBalSat, tx.getAddrVoutValue(addrDesc), tx.getAddrVinValue(addrDesc))
txs[txi] = tx txs[txi] = tx
txi++ txi++
} }
@ -347,6 +364,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
UnconfirmedBalance: w.chainParser.AmountToDecimalString(&uBalSat), UnconfirmedBalance: w.chainParser.AmountToDecimalString(&uBalSat),
UnconfirmedTxApperances: len(txm), UnconfirmedTxApperances: len(txm),
Transactions: txs[:txi], Transactions: txs[:txi],
Txids: nil,
Page: page, Page: page,
TotalPages: totalPages, TotalPages: totalPages,
TxsOnPage: txsOnPage, TxsOnPage: txsOnPage,

View File

@ -177,6 +177,10 @@ h3 {
padding: .4rem; padding: .4rem;
} }
.data-table span.ellipsis {
max-width: 100%;
}
.data { .data {
font-weight: bold; font-weight: bold;
} }
@ -188,4 +192,4 @@ h3 {
.navbar-nav .nav-link { .navbar-nav .nav-link {
padding-right: 0; padding-right: 0;
padding-left: .25rem; padding-left: .25rem;
} }