Add explorer api worker
This commit is contained in:
parent
278b18a37f
commit
604b41f10a
49
api/types.go
Normal file
49
api/types.go
Normal 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
95
api/worker.go
Normal 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
|
||||||
|
}
|
||||||
@ -58,9 +58,9 @@ type Vout struct {
|
|||||||
// Tx is blockchain transaction
|
// Tx is blockchain transaction
|
||||||
// unnecessary fields are commented out to avoid overhead
|
// unnecessary fields are commented out to avoid overhead
|
||||||
type Tx struct {
|
type Tx struct {
|
||||||
Hex string `json:"hex"`
|
Hex string `json:"hex"`
|
||||||
Txid string `json:"txid"`
|
Txid string `json:"txid"`
|
||||||
// Version int32 `json:"version"`
|
Version int32 `json:"version"`
|
||||||
LockTime uint32 `json:"locktime"`
|
LockTime uint32 `json:"locktime"`
|
||||||
Vin []Vin `json:"vin"`
|
Vin []Vin `json:"vin"`
|
||||||
Vout []Vout `json:"vout"`
|
Vout []Vout `json:"vout"`
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"blockbook/api"
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/common"
|
"blockbook/common"
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
@ -27,6 +28,7 @@ type PublicServer struct {
|
|||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
api *api.Worker
|
||||||
explorerURL string
|
explorerURL string
|
||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
@ -35,6 +37,11 @@ type PublicServer struct {
|
|||||||
// NewPublicServerS creates new public server http interface to blockbook and returns its handle
|
// 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) {
|
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)
|
socketio, err := NewSocketIoServer(db, chain, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -51,6 +58,7 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
|
|||||||
binding: binding,
|
binding: binding,
|
||||||
certFiles: certFiles,
|
certFiles: certFiles,
|
||||||
https: https,
|
https: https,
|
||||||
|
api: api,
|
||||||
socketio: socketio,
|
socketio: socketio,
|
||||||
db: db,
|
db: db,
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
@ -66,6 +74,8 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
|
|||||||
// redirect to Bitcore for details of transaction
|
// redirect to Bitcore for details of transaction
|
||||||
serveMux.HandleFunc(path+"tx/", s.txRedirect)
|
serveMux.HandleFunc(path+"tx/", s.txRedirect)
|
||||||
serveMux.HandleFunc(path+"address/", s.addressRedirect)
|
serveMux.HandleFunc(path+"address/", s.addressRedirect)
|
||||||
|
// explorer
|
||||||
|
serveMux.HandleFunc(path+"explorer/tx/", s.explorerTx)
|
||||||
// API call used to detect state of Blockbook
|
// API call used to detect state of Blockbook
|
||||||
serveMux.HandleFunc(path+"api/block-index/", s.apiBlockIndex)
|
serveMux.HandleFunc(path+"api/block-index/", s.apiBlockIndex)
|
||||||
// handle socket.io
|
// 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 {
|
type resAboutBlockbookPublic struct {
|
||||||
Coin string `json:"coin"`
|
Coin string `json:"coin"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
|
|||||||
@ -598,7 +598,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
if len(otx.Vout) > int(vin.Vout) {
|
if len(otx.Vout) > int(vin.Vout) {
|
||||||
vout := otx.Vout[vin.Vout]
|
vout := &otx.Vout[vin.Vout]
|
||||||
if vout.Address != nil {
|
if vout.Address != nil {
|
||||||
a := vout.Address.String()
|
a := vout.Address.String()
|
||||||
ai.Address = &a
|
ai.Address = &a
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user