Get data for explorer using index v3 - WIP

pull/56/head
Martin Boehm 2018-08-27 15:36:33 +02:00
parent b1e749dab9
commit b56b6c7a9b
4 changed files with 82 additions and 38 deletions

View File

@ -30,6 +30,7 @@ type Vin struct {
N int `json:"n"`
ScriptSig ScriptSig `json:"scriptSig"`
Addr string `json:"addr"`
AddrLink bool `json:"-"`
Value string `json:"value"`
ValueSat big.Int `json:"-"`
}
@ -38,6 +39,7 @@ type ScriptPubKey struct {
Hex string `json:"hex"`
Asm string `json:"asm,omitempty"`
Addresses []string `json:"addresses"`
AddrsLink []bool `json:"-"`
Type string `json:"type,omitempty"`
}
type Vout struct {
@ -45,6 +47,7 @@ type Vout struct {
ValueSat big.Int `json:"-"`
N int `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
Spent bool `json:"-"`
SpentTxID string `json:"spentTxId,omitempty"`
SpentIndex int `json:"spentIndex,omitempty"`
SpentHeight int `json:"spentHeight,omitempty"`
@ -69,15 +72,16 @@ type Tx struct {
}
type Address struct {
AddrStr string `json:"addrStr"`
Balance string `json:"balance"`
TotalReceived string `json:"totalReceived"`
TotalSent string `json:"totalSent"`
UnconfirmedBalance string `json:"unconfirmedBalance"`
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
TxApperances int `json:"txApperances"`
Transactions []*Tx `json:"transactions"`
Page int `json:"page"`
TotalPages int `json:"totalPages"`
TxsOnPage int `json:"txsOnPage"`
AddrStr string `json:"addrStr"`
Balance string `json:"balance"`
TotalReceived string `json:"totalReceived"`
TotalSent string `json:"totalSent"`
UnconfirmedBalance string `json:"unconfirmedBalance"`
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
TxApperances int `json:"txApperances"`
Transactions []*Tx `json:"transactions,omitempty"`
Txids []string `json:"transactions,omitempty"` // this is intentional, we return either Transactions or Txids
Page int `json:"page"`
TotalPages int `json:"totalPages"`
TxsOnPage int `json:"txsOnPage"`
}

View File

@ -4,6 +4,7 @@ import (
"blockbook/bchain"
"blockbook/common"
"blockbook/db"
"fmt"
"math/big"
"time"
@ -33,10 +34,10 @@ func NewWorker(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is
}
// GetTransaction reads transaction data from txid
func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool) (*Tx, error) {
func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTxs bool) (*Tx, error) {
bchainTx, height, err := w.txCache.GetTransaction(txid, bestheight)
if err != nil {
return nil, errors.Annotatef(err, "txCache.GetTransaction %v", txid)
return nil, NewApiError(fmt.Sprintf("Tx not found, %v", err), true)
}
var blockhash string
if bchainTx.Confirmations > 0 {
@ -56,20 +57,42 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
vin.ScriptSig.Hex = bchainVin.ScriptSig.Hex
// bchainVin.Txid=="" is coinbase transaction
if bchainVin.Txid != "" {
otx, _, err := w.txCache.GetTransaction(bchainVin.Txid, bestheight)
// load spending addresses from TxAddresses
ta, err := w.db.GetTxAddresses(bchainVin.Txid)
if err != nil {
return nil, errors.Annotatef(err, "txCache.GetTransaction %v", bchainVin.Txid)
return nil, errors.Annotatef(err, "GetTxAddresses %v", bchainVin.Txid)
}
if len(otx.Vout) > int(vin.Vout) {
vout := &otx.Vout[vin.Vout]
vin.ValueSat = vout.ValueSat
vin.Value = w.chainParser.AmountToDecimalString(&vout.ValueSat)
valInSat.Add(&valInSat, &vout.ValueSat)
if vout.Address != nil {
a := vout.Address.String()
vin.Addr = a
if ta == nil {
// mempool transactions are not in TxAddresses, all confirmed should be there, log a problem
if bchainTx.Confirmations > 0 {
glog.Warning("DB inconsistency: tx ", bchainVin.Txid, ": not found in txAddresses")
}
// try to load from backend
otx, _, err := w.txCache.GetTransaction(bchainVin.Txid, bestheight)
if err != nil {
return nil, errors.Annotatef(err, "txCache.GetTransaction %v", bchainVin.Txid)
}
if len(otx.Vout) > int(vin.Vout) {
vout := &otx.Vout[vin.Vout]
vin.ValueSat = vout.ValueSat
if vout.Address != nil {
a := vout.Address.String()
vin.Addr = a
}
}
} else {
if len(ta.Outputs) > int(vin.Vout) {
output := &ta.Outputs[vin.Vout]
vin.ValueSat = output.ValueSat
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
a, _ := output.Addresses(w.chainParser)
if len(a) > 0 {
vin.Addr = a[0]
}
}
}
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
valInSat.Add(&valInSat, &vin.ValueSat)
}
}
vouts := make([]Vout, len(bchainTx.Vout))
@ -82,7 +105,7 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
vout.ScriptPubKey.Addresses = bchainVout.ScriptPubKey.Addresses
if spendingTx {
if spendingTxs {
// TODO
}
}
@ -100,7 +123,7 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
Confirmations: bchainTx.Confirmations,
Fees: w.chainParser.AmountToDecimalString(&feesSat),
Locktime: bchainTx.LockTime,
WithSpends: spendingTx,
WithSpends: spendingTxs,
Time: bchainTx.Time,
Txid: bchainTx.Txid,
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
@ -112,11 +135,11 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
return r, nil
}
func (s *Worker) getAddressTxids(address string, mempool bool) ([]string, error) {
func (w *Worker) getAddressTxids(address string, mempool bool) ([]string, error) {
var err error
txids := make([]string, 0)
if !mempool {
err = s.db.GetTransactions(address, 0, ^uint32(0), func(txid string, vout uint32, isOutput bool) error {
err = w.db.GetTransactions(address, 0, ^uint32(0), func(txid string, vout uint32, isOutput bool) error {
txids = append(txids, txid)
return nil
})
@ -124,7 +147,7 @@ func (s *Worker) getAddressTxids(address string, mempool bool) ([]string, error)
return nil, err
}
} else {
m, err := s.chain.GetMempoolTransactions(address)
m, err := w.chain.GetMempoolTransactions(address)
if err != nil {
return nil, err
}
@ -223,9 +246,12 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
// GetAddress computes address value and gets transactions for given address
func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids bool) (*Address, error) {
start := time.Now()
if page < 0 {
page = 0
}
ba, err := w.db.GetAddressBalance(address)
if err != nil {
return nil, errors.Annotatef(err, "GetAddressBalance %v", address)
return nil, NewApiError(fmt.Sprintf("Address not found, %v", err), true)
}
if ba == nil {
return nil, NewApiError("Address not found", true)
@ -235,19 +261,20 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
return nil, errors.Annotatef(err, "getAddressTxids %v false", address)
}
txc = UniqueTxidsInReverse(txc)
txm, err := w.getAddressTxids(address, true)
if err != nil {
return nil, errors.Annotatef(err, "getAddressTxids %v true", address)
var txm []string
// mempool only on the first page
if page == 0 {
txm, err = w.getAddressTxids(address, true)
if err != nil {
return nil, errors.Annotatef(err, "getAddressTxids %v true", address)
}
txm = UniqueTxidsInReverse(txm)
}
txm = UniqueTxidsInReverse(txm)
bestheight, _, err := w.db.GetBestBlock()
if err != nil {
return nil, errors.Annotatef(err, "GetBestBlock")
}
// paging
if page < 0 {
page = 0
}
from := page * txsOnPage
totalPages := len(txc) / txsOnPage
if from >= len(txc) {

View File

@ -15,6 +15,14 @@ a {
text-decoration: none;
}
h1 small {
font-size: 65%;
}
h3 {
margin-top: 20px;
}
.octicon {
color: #777;
display: inline-block;
@ -175,4 +183,9 @@ a {
.alert .data-table {
margin: 0;
}
}
.navbar-nav .nav-link {
padding-right: 0;
padding-left: .25rem;
}

View File

@ -1,4 +1,4 @@
{{define "specific"}}
<h1>Error</h1>
<h3>{{.Error.Text}}</h3>
<h4>{{.Error.Text}}</h4>
{{end}}