Handle coin specific tx data more efficiently
This commit is contained in:
parent
975c98b5b7
commit
6072aa5e9e
37
api/types.go
37
api/types.go
@ -70,24 +70,25 @@ type Vout struct {
|
|||||||
|
|
||||||
// Tx holds information about a transaction
|
// Tx holds information about a transaction
|
||||||
type Tx struct {
|
type Tx struct {
|
||||||
Txid string `json:"txid"`
|
Txid string `json:"txid"`
|
||||||
Version int32 `json:"version,omitempty"`
|
Version int32 `json:"version,omitempty"`
|
||||||
Locktime uint32 `json:"locktime,omitempty"`
|
Locktime uint32 `json:"locktime,omitempty"`
|
||||||
Vin []Vin `json:"vin"`
|
Vin []Vin `json:"vin"`
|
||||||
Vout []Vout `json:"vout"`
|
Vout []Vout `json:"vout"`
|
||||||
Blockhash string `json:"blockhash,omitempty"`
|
Blockhash string `json:"blockhash,omitempty"`
|
||||||
Blockheight int `json:"blockheight"`
|
Blockheight int `json:"blockheight"`
|
||||||
Confirmations uint32 `json:"confirmations"`
|
Confirmations uint32 `json:"confirmations"`
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
Blocktime int64 `json:"blocktime"`
|
Blocktime int64 `json:"blocktime"`
|
||||||
ValueOut string `json:"valueOut"`
|
ValueOut string `json:"valueOut"`
|
||||||
ValueOutSat big.Int `json:"-"`
|
ValueOutSat big.Int `json:"-"`
|
||||||
Size int `json:"size,omitempty"`
|
Size int `json:"size,omitempty"`
|
||||||
ValueIn string `json:"valueIn"`
|
ValueIn string `json:"valueIn"`
|
||||||
ValueInSat big.Int `json:"-"`
|
ValueInSat big.Int `json:"-"`
|
||||||
Fees string `json:"fees"`
|
Fees string `json:"fees"`
|
||||||
FeesSat big.Int `json:"-"`
|
FeesSat big.Int `json:"-"`
|
||||||
Hex string `json:"hex"`
|
Hex string `json:"hex"`
|
||||||
|
CoinSpecificData interface{} `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paging contains information about paging for address, blocks and block
|
// Paging contains information about paging for address, blocks and block
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"blockbook/common"
|
"blockbook/common"
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -82,7 +83,7 @@ func (w *Worker) setSpendingTxToVout(vout *Vout, txid string, height uint32) err
|
|||||||
// GetSpendingTxid returns transaction id of transaction that spent given output
|
// GetSpendingTxid returns transaction id of transaction that spent given output
|
||||||
func (w *Worker) GetSpendingTxid(txid string, n int) (string, error) {
|
func (w *Worker) GetSpendingTxid(txid string, n int) (string, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
tx, err := w.GetTransaction(txid, false)
|
tx, err := w.GetTransaction(txid, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -98,7 +99,7 @@ func (w *Worker) GetSpendingTxid(txid string, n int) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTransaction reads transaction data from txid
|
// GetTransaction reads transaction data from txid
|
||||||
func (w *Worker) GetTransaction(txid string, spendingTxs bool) (*Tx, error) {
|
func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificData bool) (*Tx, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
bchainTx, height, err := w.txCache.GetTransaction(txid)
|
bchainTx, height, err := w.txCache.GetTransaction(txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -210,24 +211,32 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool) (*Tx, error) {
|
|||||||
}
|
}
|
||||||
// for now do not return size, we would have to compute vsize of segwit transactions
|
// for now do not return size, we would have to compute vsize of segwit transactions
|
||||||
// size:=len(bchainTx.Hex) / 2
|
// size:=len(bchainTx.Hex) / 2
|
||||||
|
var sd json.RawMessage
|
||||||
|
if specificData {
|
||||||
|
sd, err = w.chain.GetTransactionSpecific(bchainTx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
r := &Tx{
|
r := &Tx{
|
||||||
Blockhash: blockhash,
|
Blockhash: blockhash,
|
||||||
Blockheight: int(height),
|
Blockheight: int(height),
|
||||||
Blocktime: bchainTx.Blocktime,
|
Blocktime: bchainTx.Blocktime,
|
||||||
Confirmations: bchainTx.Confirmations,
|
Confirmations: bchainTx.Confirmations,
|
||||||
Fees: w.chainParser.AmountToDecimalString(&feesSat),
|
Fees: w.chainParser.AmountToDecimalString(&feesSat),
|
||||||
FeesSat: feesSat,
|
FeesSat: feesSat,
|
||||||
Locktime: bchainTx.LockTime,
|
Locktime: bchainTx.LockTime,
|
||||||
Time: bchainTx.Time,
|
Time: bchainTx.Time,
|
||||||
Txid: bchainTx.Txid,
|
Txid: bchainTx.Txid,
|
||||||
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
|
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
|
||||||
ValueInSat: valInSat,
|
ValueInSat: valInSat,
|
||||||
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
|
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
|
||||||
ValueOutSat: valOutSat,
|
ValueOutSat: valOutSat,
|
||||||
Version: bchainTx.Version,
|
Version: bchainTx.Version,
|
||||||
Hex: bchainTx.Hex,
|
Hex: bchainTx.Hex,
|
||||||
Vin: vins,
|
Vin: vins,
|
||||||
Vout: vouts,
|
Vout: vouts,
|
||||||
|
CoinSpecificData: sd,
|
||||||
}
|
}
|
||||||
if spendingTxs {
|
if spendingTxs {
|
||||||
glog.Info("GetTransaction ", txid, " finished in ", time.Since(start))
|
glog.Info("GetTransaction ", txid, " finished in ", time.Since(start))
|
||||||
@ -426,7 +435,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
|
|||||||
// load mempool transactions
|
// load mempool transactions
|
||||||
var uBalSat big.Int
|
var uBalSat big.Int
|
||||||
for _, tx := range txm {
|
for _, tx := range txm {
|
||||||
tx, err := w.GetTransaction(tx, false)
|
tx, err := w.GetTransaction(tx, false, false)
|
||||||
// mempool transaction may fail
|
// mempool transaction may fail
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("GetTransaction in mempool ", tx, ": ", err)
|
glog.Error("GetTransaction in mempool ", tx, ": ", err)
|
||||||
|
|||||||
@ -187,9 +187,9 @@ func (c *blockChainWithMetrics) GetTransaction(txid string) (v *bchain.Tx, err e
|
|||||||
return c.b.GetTransaction(txid)
|
return c.b.GetTransaction(txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetTransactionSpecific(txid string) (v json.RawMessage, err error) {
|
func (c *blockChainWithMetrics) GetTransactionSpecific(tx *bchain.Tx) (v json.RawMessage, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetTransactionSpecific", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("GetTransactionSpecific", s, err) }(time.Now())
|
||||||
return c.b.GetTransactionSpecific(txid)
|
return c.b.GetTransactionSpecific(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
|
func (c *blockChainWithMetrics) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
|
||||||
|
|||||||
@ -670,11 +670,12 @@ func (b *BitcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
|
|||||||
|
|
||||||
// GetTransaction returns a transaction by the transaction ID
|
// GetTransaction returns a transaction by the transaction ID
|
||||||
func (b *BitcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
func (b *BitcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||||
r, err := b.GetTransactionSpecific(txid)
|
r, err := b.getRawTransaction(txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tx, err := b.Parser.ParseTxFromJson(r)
|
tx, err := b.Parser.ParseTxFromJson(r)
|
||||||
|
tx.CoinSpecificData = r
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
}
|
}
|
||||||
@ -682,7 +683,15 @@ func (b *BitcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
||||||
func (b *BitcoinRPC) GetTransactionSpecific(txid string) (json.RawMessage, error) {
|
func (b *BitcoinRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
||||||
|
if csd, ok := tx.CoinSpecificData.(json.RawMessage); ok {
|
||||||
|
return csd, nil
|
||||||
|
}
|
||||||
|
return b.getRawTransaction(tx.Txid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRawTransaction returns json as returned by backend, with all coin specific data
|
||||||
|
func (b *BitcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
||||||
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
||||||
|
|
||||||
res := ResGetRawTransaction{}
|
res := ResGetRawTransaction{}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ func ethNumber(n string) (int64, error) {
|
|||||||
return 0, errors.Errorf("Not a number: '%v'", n)
|
return 0, errors.Errorf("Not a number: '%v'", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, blocktime int64, confirmations uint32) (*bchain.Tx, error) {
|
func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, blocktime int64, confirmations uint32, marshallHex bool) (*bchain.Tx, error) {
|
||||||
txid := ethHashToHash(tx.Hash)
|
txid := ethHashToHash(tx.Hash)
|
||||||
var (
|
var (
|
||||||
fa, ta []string
|
fa, ta []string
|
||||||
@ -91,22 +91,24 @@ func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, bloc
|
|||||||
if len(tx.To) > 2 {
|
if len(tx.To) > 2 {
|
||||||
ta = []string{tx.To}
|
ta = []string{tx.To}
|
||||||
}
|
}
|
||||||
|
|
||||||
// completeTransaction without BlockHash is marshalled and hex encoded to bchain.Tx.Hex
|
|
||||||
bh := tx.BlockHash
|
|
||||||
tx.BlockHash = nil
|
|
||||||
ct := completeTransaction{
|
ct := completeTransaction{
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
Receipt: receipt,
|
Receipt: receipt,
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(ct)
|
var h string
|
||||||
if err != nil {
|
if marshallHex {
|
||||||
return nil, err
|
// completeTransaction without BlockHash is marshalled and hex encoded to bchain.Tx.Hex
|
||||||
}
|
bh := tx.BlockHash
|
||||||
tx.BlockHash = bh
|
tx.BlockHash = nil
|
||||||
h := hex.EncodeToString(b)
|
b, err := json.Marshal(ct)
|
||||||
if receipt != nil {
|
if err != nil {
|
||||||
glog.Info(tx.Hash.Hex(), ": ", h)
|
return nil, err
|
||||||
|
}
|
||||||
|
tx.BlockHash = bh
|
||||||
|
h = hex.EncodeToString(b)
|
||||||
|
if receipt != nil {
|
||||||
|
glog.Info(tx.Hash.Hex(), ": ", h)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vs, err := hexutil.DecodeBig(tx.Value)
|
vs, err := hexutil.DecodeBig(tx.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -139,6 +141,7 @@ func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, bloc
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
CoinSpecificData: ct,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +333,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|||||||
Logs: logs,
|
Logs: logs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx, err := p.ethTxToTx(&rt, rr, int64(pt.BlockTime), 0)
|
tx, err := p.ethTxToTx(&rt, rr, int64(pt.BlockTime), 0, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -199,6 +199,8 @@ func TestEthereumParser_UnpackTx(t *testing.T) {
|
|||||||
t.Errorf("EthereumParser.UnpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("EthereumParser.UnpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// CoinSpecificData are not set in want struct
|
||||||
|
got.CoinSpecificData = nil
|
||||||
// DeepEqual compares empty nil slices as not equal
|
// DeepEqual compares empty nil slices as not equal
|
||||||
if fmt.Sprint(got) != fmt.Sprint(tt.want) {
|
if fmt.Sprint(got) != fmt.Sprint(tt.want) {
|
||||||
t.Errorf("EthereumParser.UnpackTx() got = %+v, want %+v", got, tt.want)
|
t.Errorf("EthereumParser.UnpackTx() got = %+v, want %+v", got, tt.want)
|
||||||
|
|||||||
@ -447,7 +447,7 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
|
|||||||
// TODO - get ERC20 events
|
// TODO - get ERC20 events
|
||||||
btxs := make([]bchain.Tx, len(body.Transactions))
|
btxs := make([]bchain.Tx, len(body.Transactions))
|
||||||
for i, tx := range body.Transactions {
|
for i, tx := range body.Transactions {
|
||||||
btx, err := b.Parser.ethTxToTx(&tx, nil, int64(head.Time.Uint64()), uint32(bbh.Confirmations))
|
btx, err := b.Parser.ethTxToTx(&tx, nil, int64(head.Time.Uint64()), uint32(bbh.Confirmations), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash.String())
|
return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash.String())
|
||||||
}
|
}
|
||||||
@ -493,7 +493,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
var btx *bchain.Tx
|
var btx *bchain.Tx
|
||||||
if tx.BlockNumber == "" {
|
if tx.BlockNumber == "" {
|
||||||
// mempool tx
|
// mempool tx
|
||||||
btx, err = b.Parser.ethTxToTx(tx, nil, 0, 0)
|
btx, err = b.Parser.ethTxToTx(tx, nil, 0, 0, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
}
|
}
|
||||||
@ -516,7 +516,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
}
|
}
|
||||||
btx, err = b.Parser.ethTxToTx(tx, &receipt, h.Time.Int64(), confirmations)
|
btx, err = b.Parser.ethTxToTx(tx, &receipt, h.Time.Int64(), confirmations, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
}
|
}
|
||||||
@ -525,17 +525,20 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
||||||
func (b *EthereumRPC) GetTransactionSpecific(txid string) (json.RawMessage, error) {
|
func (b *EthereumRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
csd, ok := tx.CoinSpecificData.(completeTransaction)
|
||||||
defer cancel()
|
if !ok {
|
||||||
var tx json.RawMessage
|
ntx, err := b.GetTransaction(tx.Txid)
|
||||||
err := b.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", ethcommon.HexToHash(txid))
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
} else if tx == nil {
|
csd, ok = ntx.CoinSpecificData.(completeTransaction)
|
||||||
return nil, ethereum.NotFound
|
if !ok {
|
||||||
|
return nil, errors.New("Cannot get CoinSpecificData")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tx, nil
|
m, err := json.Marshal(&csd)
|
||||||
|
return json.RawMessage(m), err
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcMempoolBlock struct {
|
type rpcMempoolBlock struct {
|
||||||
|
|||||||
@ -75,9 +75,10 @@ type Tx struct {
|
|||||||
Vin []Vin `json:"vin"`
|
Vin []Vin `json:"vin"`
|
||||||
Vout []Vout `json:"vout"`
|
Vout []Vout `json:"vout"`
|
||||||
// BlockHash string `json:"blockhash,omitempty"`
|
// BlockHash string `json:"blockhash,omitempty"`
|
||||||
Confirmations uint32 `json:"confirmations,omitempty"`
|
Confirmations uint32 `json:"confirmations,omitempty"`
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
Blocktime int64 `json:"blocktime,omitempty"`
|
Blocktime int64 `json:"blocktime,omitempty"`
|
||||||
|
CoinSpecificData interface{} `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block is block header and list of transactions
|
// Block is block header and list of transactions
|
||||||
@ -185,7 +186,7 @@ type BlockChain interface {
|
|||||||
GetMempool() ([]string, error)
|
GetMempool() ([]string, error)
|
||||||
GetTransaction(txid string) (*Tx, error)
|
GetTransaction(txid string) (*Tx, error)
|
||||||
GetTransactionForMempool(txid string) (*Tx, error)
|
GetTransactionForMempool(txid string) (*Tx, error)
|
||||||
GetTransactionSpecific(txid string) (json.RawMessage, error)
|
GetTransactionSpecific(tx *Tx) (json.RawMessage, error)
|
||||||
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
|
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
|
||||||
EstimateFee(blocks int) (big.Int, error)
|
EstimateFee(blocks int) (big.Int, error)
|
||||||
SendRawTransaction(tx string) (string, error)
|
SendRawTransaction(tx string) (string, error)
|
||||||
|
|||||||
@ -336,7 +336,6 @@ type TemplateData struct {
|
|||||||
Address *api.Address
|
Address *api.Address
|
||||||
AddrStr string
|
AddrStr string
|
||||||
Tx *api.Tx
|
Tx *api.Tx
|
||||||
TxSpecific json.RawMessage
|
|
||||||
Error *api.APIError
|
Error *api.APIError
|
||||||
Blocks *api.Blocks
|
Blocks *api.Blocks
|
||||||
Block *api.Block
|
Block *api.Block
|
||||||
@ -392,23 +391,17 @@ func setTxToTemplateData(td *TemplateData, tx *api.Tx) *TemplateData {
|
|||||||
|
|
||||||
func (s *PublicServer) explorerTx(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
|
func (s *PublicServer) explorerTx(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
|
||||||
var tx *api.Tx
|
var tx *api.Tx
|
||||||
var txSpecific json.RawMessage
|
|
||||||
var err error
|
var err error
|
||||||
s.metrics.ExplorerViews.With(common.Labels{"action": "tx"}).Inc()
|
s.metrics.ExplorerViews.With(common.Labels{"action": "tx"}).Inc()
|
||||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
txid := r.URL.Path[i+1:]
|
txid := r.URL.Path[i+1:]
|
||||||
tx, err = s.api.GetTransaction(txid, false)
|
tx, err = s.api.GetTransaction(txid, false, true)
|
||||||
if err != nil {
|
|
||||||
return errorTpl, nil, err
|
|
||||||
}
|
|
||||||
txSpecific, err = s.chain.GetTransactionSpecific(txid)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorTpl, nil, err
|
return errorTpl, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data := s.newTemplateData()
|
data := s.newTemplateData()
|
||||||
data.Tx = tx
|
data.Tx = tx
|
||||||
data.TxSpecific = txSpecific
|
|
||||||
return txTpl, data, nil
|
return txTpl, data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +514,7 @@ func (s *PublicServer) explorerSearch(w http.ResponseWriter, r *http.Request) (t
|
|||||||
http.Redirect(w, r, joinURL("/block/", block.Hash), 302)
|
http.Redirect(w, r, joinURL("/block/", block.Hash), 302)
|
||||||
return noTpl, nil, nil
|
return noTpl, nil, nil
|
||||||
}
|
}
|
||||||
tx, err = s.api.GetTransaction(q, false)
|
tx, err = s.api.GetTransaction(q, false, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
http.Redirect(w, r, joinURL("/tx/", tx.Txid), 302)
|
http.Redirect(w, r, joinURL("/tx/", tx.Txid), 302)
|
||||||
return noTpl, nil, nil
|
return noTpl, nil, nil
|
||||||
@ -656,7 +649,7 @@ func (s *PublicServer) apiTx(r *http.Request) (interface{}, error) {
|
|||||||
return nil, api.NewAPIError("Parameter 'spending' cannot be converted to boolean", true)
|
return nil, api.NewAPIError("Parameter 'spending' cannot be converted to boolean", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx, err = s.api.GetTransaction(txid, spendingTxs)
|
tx, err = s.api.GetTransaction(txid, spendingTxs, false)
|
||||||
}
|
}
|
||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
@ -667,7 +660,7 @@ func (s *PublicServer) apiTxSpecific(r *http.Request) (interface{}, error) {
|
|||||||
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tx-specific"}).Inc()
|
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tx-specific"}).Inc()
|
||||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
txid := r.URL.Path[i+1:]
|
txid := r.URL.Path[i+1:]
|
||||||
tx, err = s.chain.GetTransactionSpecific(txid)
|
tx, err = s.chain.GetTransactionSpecific(&bchain.Tx{Txid: txid})
|
||||||
}
|
}
|
||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -387,7 +387,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
|
|||||||
to = opts.To
|
to = opts.To
|
||||||
}
|
}
|
||||||
for txi := opts.From; txi < to; txi++ {
|
for txi := opts.From; txi < to; txi++ {
|
||||||
tx, err := s.api.GetTransaction(txids[txi], false)
|
tx, err := s.api.GetTransaction(txids[txi], false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@ -627,7 +627,7 @@ type resultGetDetailedTransaction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetailedTransaction, err error) {
|
func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetailedTransaction, err error) {
|
||||||
tx, err := s.api.GetTransaction(txid, false)
|
tx, err := s.api.GetTransaction(txid, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{{define "specific"}}{{$cs := .CoinShortcut}}{{$tx := .Tx}}{{$txSpecific := .TxSpecific}}
|
{{define "specific"}}{{$cs := .CoinShortcut}}{{$tx := .Tx}}
|
||||||
<h1>Transaction</h1>
|
<h1>Transaction</h1>
|
||||||
<div class="alert alert-data ellipsis">
|
<div class="alert alert-data ellipsis">
|
||||||
<span class="data">{{$tx.Txid}}</span>
|
<span class="data">{{$tx.Txid}}</span>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<pre id="txSpecific"></pre>
|
<pre id="txSpecific"></pre>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
txSpecific = {{ $txSpecific }};
|
txSpecific = {{$tx.CoinSpecificData}};
|
||||||
function syntaxHighlight(json) {
|
function syntaxHighlight(json) {
|
||||||
json = JSON.stringify(json, undefined, 2);
|
json = JSON.stringify(json, undefined, 2);
|
||||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
|||||||
@ -141,8 +141,8 @@ func (c *fakeBlockChain) GetTransaction(txid string) (v *bchain.Tx, err error) {
|
|||||||
return nil, errors.New("Not found")
|
return nil, errors.New("Not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetTransactionSpecific(txid string) (v json.RawMessage, err error) {
|
func (c *fakeBlockChain) GetTransactionSpecific(tx *bchain.Tx) (v json.RawMessage, err error) {
|
||||||
tx, err := c.GetTransaction(txid)
|
tx, err = c.GetTransaction(tx.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user