Use AddressDescriptor for queries in api worker
This commit is contained in:
parent
6f25785109
commit
1109cd7878
35
api/types.go
35
api/types.go
@ -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"`
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user