Add explorer api worker

This commit is contained in:
Martin Boehm 2018-06-26 13:02:53 +02:00
parent 278b18a37f
commit 604b41f10a
5 changed files with 177 additions and 4 deletions

49
api/types.go Normal file
View File

@ -0,0 +1,49 @@
package api
type ScriptSig struct {
Hex string `json:"hex"`
Asm string `json:"asm,omitempty"`
}
type Vin struct {
Txid string `json:"txid"`
Vout uint32 `json:"vout"`
Sequence int64 `json:"sequence,omitempty"`
N int `json:"n"`
ScriptSig ScriptSig `json:"scriptSig"`
Addr string `json:"addr"`
ValueSat int64 `json:"valueSat"`
Value float64 `json:"value"`
}
type ScriptPubKey struct {
Hex string `json:"hex"`
Asm string `json:"asm,omitempty"`
Addresses []string `json:"addresses"`
Type string `json:"type,omitempty"`
}
type Vout struct {
Value float64 `json:"value"`
N int `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
SpentTxID string `json:"spentTxId,omitempty"`
SpentIndex int `json:"spentIndex,omitempty"`
SpentHeight int `json:"spentHeight,omitempty"`
}
type Tx struct {
Txid string `json:"txid"`
Version int32 `json:"version,omitempty"`
Locktime uint32 `json:"locktime,omitempty"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`
Blockhash string `json:"blockhash,omitempty"`
Blockheight int `json:"blockheight"`
Confirmations uint32 `json:"confirmations"`
Time int64 `json:"time,omitempty"`
Blocktime int64 `json:"blocktime"`
ValueOut float64 `json:"valueOut"`
Size int `json:"size,omitempty"`
ValueIn float64 `json:"valueIn"`
Fees float64 `json:"fees"`
}

95
api/worker.go Normal file
View File

@ -0,0 +1,95 @@
package api
import (
"blockbook/bchain"
"blockbook/db"
)
// Worker is handle to api worker
type Worker struct {
db *db.RocksDB
txCache *db.TxCache
chain bchain.BlockChain
chainParser bchain.BlockChainParser
}
// NewWorker creates new api worker
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache) (*Worker, error) {
w := &Worker{
db: db,
txCache: txCache,
chain: chain,
chainParser: chain.GetChainParser(),
}
return w, nil
}
func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool) (*Tx, error) {
bchainTx, height, err := w.txCache.GetTransaction(txid, bestheight)
if err != nil {
return nil, err
}
var blockhash string
if bchainTx.Confirmations > 0 {
blockhash, err = w.db.GetBlockHash(height)
if err != nil {
return nil, err
}
}
var valIn, valOut, fees float64
vins := make([]Vin, len(bchainTx.Vin))
for i := range bchainTx.Vin {
bchainVin := &bchainTx.Vin[i]
vin := &vins[i]
vin.Txid = bchainVin.Txid
vin.N = i
vin.Vout = bchainVin.Vout
vin.ScriptSig.Hex = bchainVin.ScriptSig.Hex
otx, _, err := w.txCache.GetTransaction(bchainVin.Txid, bestheight)
if err != nil {
return nil, err
}
if len(otx.Vout) > int(vin.Vout) {
vout := &otx.Vout[vin.Vout]
vin.Value = vout.Value
valIn += vout.Value
vin.ValueSat = int64(vout.Value*1E8 + 0.5)
if vout.Address != nil {
a := vout.Address.String()
vin.Addr = a
}
}
}
vouts := make([]Vout, len(bchainTx.Vout))
for i := range bchainTx.Vout {
bchainVout := &bchainTx.Vout[i]
vout := &vouts[i]
vout.N = i
vout.Value = bchainVout.Value
valOut += bchainVout.Value
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
vout.ScriptPubKey.Addresses = bchainVout.ScriptPubKey.Addresses
if spendingTx {
// TODO
}
}
// for now do not return size, we would have to compute vsize of segwit transactions
// size:=len(bchainTx.Hex) / 2
fees = valIn - valOut
r := &Tx{
Blockhash: blockhash,
Blockheight: int(height),
Blocktime: bchainTx.Blocktime,
Confirmations: bchainTx.Confirmations,
Fees: fees,
Locktime: bchainTx.LockTime,
Time: bchainTx.Time,
Txid: txid,
ValueIn: valIn,
ValueOut: valOut,
Version: bchainTx.Version,
Vin: vins,
Vout: vouts,
}
return r, nil
}

View File

@ -58,9 +58,9 @@ type Vout struct {
// Tx is blockchain transaction
// unnecessary fields are commented out to avoid overhead
type Tx struct {
Hex string `json:"hex"`
Txid string `json:"txid"`
// Version int32 `json:"version"`
Hex string `json:"hex"`
Txid string `json:"txid"`
Version int32 `json:"version"`
LockTime uint32 `json:"locktime"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`

View File

@ -1,6 +1,7 @@
package server
import (
"blockbook/api"
"blockbook/bchain"
"blockbook/common"
"blockbook/db"
@ -27,6 +28,7 @@ type PublicServer struct {
txCache *db.TxCache
chain bchain.BlockChain
chainParser bchain.BlockChainParser
api *api.Worker
explorerURL string
metrics *common.Metrics
is *common.InternalState
@ -35,6 +37,11 @@ type PublicServer struct {
// NewPublicServerS creates new public server http interface to blockbook and returns its handle
func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState) (*PublicServer, error) {
api, err := api.NewWorker(db, chain, txCache)
if err != nil {
return nil, err
}
socketio, err := NewSocketIoServer(db, chain, txCache, metrics, is)
if err != nil {
return nil, err
@ -51,6 +58,7 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
binding: binding,
certFiles: certFiles,
https: https,
api: api,
socketio: socketio,
db: db,
txCache: txCache,
@ -66,6 +74,8 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
// redirect to Bitcore for details of transaction
serveMux.HandleFunc(path+"tx/", s.txRedirect)
serveMux.HandleFunc(path+"address/", s.addressRedirect)
// explorer
serveMux.HandleFunc(path+"explorer/tx/", s.explorerTx)
// API call used to detect state of Blockbook
serveMux.HandleFunc(path+"api/block-index/", s.apiBlockIndex)
// handle socket.io
@ -139,6 +149,25 @@ func (s *PublicServer) addressRedirect(w http.ResponseWriter, r *http.Request) {
}
}
func (s *PublicServer) explorerTx(w http.ResponseWriter, r *http.Request) {
var tx *api.Tx
var err error
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
txid := r.URL.Path[i+1:]
bestheight, _, err := s.db.GetBestBlock()
if err == nil {
tx, err = s.api.GetTransaction(txid, bestheight, true)
}
}
if err == nil {
buf, err := json.MarshalIndent(tx, "", " ")
if err != nil {
glog.Error(err)
}
w.Write(buf)
}
}
type resAboutBlockbookPublic struct {
Coin string `json:"coin"`
Host string `json:"host"`

View File

@ -598,7 +598,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
return res, err
}
if len(otx.Vout) > int(vin.Vout) {
vout := otx.Vout[vin.Vout]
vout := &otx.Vout[vin.Vout]
if vout.Address != nil {
a := vout.Address.String()
ai.Address = &a