From 59497e3c975dbc72314ed4472a8ae62ddea90058 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Wed, 22 Aug 2018 00:48:53 +0200 Subject: [PATCH] Get address data for explorer using index v3 - WIP --- api/worker.go | 84 ++++++++++++++++++++++++++++++++++++++++++---- db/rocksdb.go | 20 +++++------ db/rocksdb_test.go | 8 ++--- 3 files changed, 91 insertions(+), 21 deletions(-) diff --git a/api/worker.go b/api/worker.go index 64a93bff..b0ddfe89 100644 --- a/api/worker.go +++ b/api/worker.go @@ -170,8 +170,57 @@ func UniqueTxidsInReverse(txids []string) []string { return ut[i:] } +func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockInfo, bestheight uint32) *Tx { + var valInSat, valOutSat, feesSat big.Int + vins := make([]Vin, len(ta.Inputs)) + for i := range ta.Inputs { + tai := &ta.Inputs[i] + vin := &vins[i] + vin.N = i + vin.ValueSat = tai.ValueSat + vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat) + valInSat.Add(&valInSat, &vin.ValueSat) + a, err := tai.Addresses(w.chainParser) + if err != nil && len(a) == 1 { + vin.Addr = a[0] + } + } + vouts := make([]Vout, len(ta.Outputs)) + for i := range ta.Outputs { + tao := &ta.Outputs[i] + vout := &vouts[i] + vout.N = i + vout.ValueSat = tao.ValueSat + vout.Value = w.chainParser.AmountToDecimalString(&vout.ValueSat) + valOutSat.Add(&valOutSat, &vout.ValueSat) + a, err := tao.Addresses(w.chainParser) + if err != nil { + vout.ScriptPubKey.Addresses = a + } + } + // for coinbase transactions valIn is 0 + feesSat.Sub(&valInSat, &valOutSat) + if feesSat.Sign() == -1 { + feesSat.SetUint64(0) + } + r := &Tx{ + Blockhash: bi.BlockHash, + Blockheight: int(ta.Height), + Blocktime: bi.Time.Unix(), + Confirmations: bestheight - ta.Height + 1, + Fees: w.chainParser.AmountToDecimalString(&feesSat), + Time: bi.Time.Unix(), + Txid: txid, + ValueIn: w.chainParser.AmountToDecimalString(&valInSat), + ValueOut: w.chainParser.AmountToDecimalString(&valOutSat), + Vin: vins, + Vout: vouts, + } + return r +} + // GetAddress computes address value and gets transactions for given address -func (w *Worker) GetAddressNew(address string, page int, txsOnPage int) (*Address, error) { +func (w *Worker) GetAddress(address string, page int, txsOnPage int) (*Address, error) { glog.Info(address, " start") ba, err := w.db.GetAddressBalance(address) if err != nil { @@ -227,9 +276,29 @@ func (w *Worker) GetAddressNew(address string, page int, txsOnPage int) (*Addres } } if len(txc) != int(ba.Txs) { - glog.Warning("DB inconsistency in address ", address, ": number of txs from column addresses ", len(txc), ", from addressBalance ", ba.Txs) + glog.Warning("DB inconsistency for address ", address, ": number of txs from column addresses ", len(txc), ", from addressBalance ", ba.Txs) + } + for i := from; i < to; i++ { + txid := txc[i] + ta, err := w.db.GetTxAddresses(txid) + if err != nil { + return nil, err + } + if ta == nil { + glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses") + continue + } + bi, err := w.db.GetBlockInfo(ta.Height) + if err != nil { + return nil, err + } + if bi == nil { + glog.Warning("DB inconsistency: block height ", ta.Height, ": not found in db") + continue + } + txs[txi] = w.txFromTxAddress(txid, ta, bi, bestheight) + txi++ } - r := &Address{ AddrStr: address, Balance: w.chainParser.AmountToDecimalString(&ba.BalanceSat), @@ -238,16 +307,17 @@ func (w *Worker) GetAddressNew(address string, page int, txsOnPage int) (*Addres TxApperances: len(txc), UnconfirmedBalance: w.chainParser.AmountToDecimalString(&uBalSat), UnconfirmedTxApperances: len(txm), - Page: page, - TotalPages: totalPages, - TxsOnPage: txsOnPage, + Transactions: txs[:txi], + Page: page, + TotalPages: totalPages, + TxsOnPage: txsOnPage, } glog.Info(address, " finished") return r, nil } // GetAddress computes address value and gets transactions for given address -func (w *Worker) GetAddress(addrID string, page int, txsOnPage int) (*Address, error) { +func (w *Worker) GetAddressOld(addrID string, page int, txsOnPage int) (*Address, error) { glog.Info(addrID, " start") txc, err := w.getAddressTxids(addrID, false) txc = UniqueTxidsInReverse(txc) diff --git a/db/rocksdb.go b/db/rocksdb.go index 6c4ebf9f..6f6b3793 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -1125,10 +1125,10 @@ func (d *RocksDB) writeAddressesNonUTXO(wb *gorocksdb.WriteBatch, block *bchain. // Block index type BlockInfo struct { - Txid string - Time time.Time - Txs uint32 - Size uint32 + BlockHash string + Time time.Time + Txs uint32 + Size uint32 } func (d *RocksDB) packBlockInfo(block *bchain.Block) ([]byte, error) { @@ -1161,10 +1161,10 @@ func (d *RocksDB) unpackBlockInfo(buf []byte) (*BlockInfo, error) { txs, l := unpackVaruint(buf[pl+4:]) size, _ := unpackVaruint(buf[pl+4+l:]) return &BlockInfo{ - Txid: txid, - Time: time.Unix(int64(t), 0), - Txs: uint32(txs), - Size: uint32(size), + BlockHash: txid, + Time: time.Unix(int64(t), 0), + Txs: uint32(txs), + Size: uint32(size), }, nil } @@ -1179,7 +1179,7 @@ func (d *RocksDB) GetBestBlock() (uint32, string, error) { if glog.V(1) { glog.Infof("rocksdb: bestblock %d %+v", bestHeight, info) } - return bestHeight, info.Txid, err + return bestHeight, info.BlockHash, err } } return 0, "", nil @@ -1197,7 +1197,7 @@ func (d *RocksDB) GetBlockHash(height uint32) (string, error) { if info == nil { return "", err } - return info.Txid, nil + return info.BlockHash, nil } // GetBlockInfo returns block info stored in db diff --git a/db/rocksdb_test.go b/db/rocksdb_test.go index 732ae410..e74d0664 100644 --- a/db/rocksdb_test.go +++ b/db/rocksdb_test.go @@ -731,10 +731,10 @@ func TestRocksDB_Index_UTXO(t *testing.T) { t.Fatal(err) } iw := &BlockInfo{ - Txid: "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6", - Txs: 4, - Size: 2345678, - Time: time.Unix(1534859123, 0), + BlockHash: "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6", + Txs: 4, + Size: 2345678, + Time: time.Unix(1534859123, 0), } if !reflect.DeepEqual(info, iw) { t.Errorf("GetAddressBalance() = %+v, want %+v", info, iw)