Show coin specific transaction data in explorer and api
This commit is contained in:
parent
71969ebd23
commit
8140af1a69
@ -180,6 +180,11 @@ 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) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("GetTransactionSpecific", s, err) }(time.Now())
|
||||||
|
return c.b.GetTransactionSpecific(txid)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
|
func (c *blockChainWithMetrics) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetTransactionForMempool", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("GetTransactionForMempool", s, err) }(time.Now())
|
||||||
return c.b.GetTransactionForMempool(txid)
|
return c.b.GetTransactionForMempool(txid)
|
||||||
|
|||||||
@ -670,6 +670,19 @@ 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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tx, err := b.Parser.ParseTxFromJson(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
|
}
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
||||||
|
func (b *BitcoinRPC) GetTransactionSpecific(txid string) (json.RawMessage, error) {
|
||||||
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
||||||
|
|
||||||
res := ResGetRawTransaction{}
|
res := ResGetRawTransaction{}
|
||||||
@ -684,11 +697,7 @@ func (b *BitcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
||||||
}
|
}
|
||||||
tx, err := b.Parser.ParseTxFromJson(res.Result)
|
return res.Result, nil
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
|
||||||
}
|
|
||||||
return tx, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResyncMempool gets mempool transactions and maps output scripts to transactions.
|
// ResyncMempool gets mempool transactions and maps output scripts to transactions.
|
||||||
|
|||||||
@ -491,6 +491,20 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
return btx, nil
|
return btx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
||||||
|
func (b *EthereumRPC) GetTransactionSpecific(txid string) (json.RawMessage, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
|
defer cancel()
|
||||||
|
var tx json.RawMessage
|
||||||
|
err := b.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", ethcommon.HexToHash(txid))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if tx == nil {
|
||||||
|
return nil, ethereum.NotFound
|
||||||
|
}
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
type rpcMempoolBlock struct {
|
type rpcMempoolBlock struct {
|
||||||
Transactions []string `json:"transactions"`
|
Transactions []string `json:"transactions"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -167,6 +167,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)
|
||||||
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)
|
||||||
|
|||||||
@ -124,6 +124,7 @@ func (s *PublicServer) ConnectFullPublicInterface() {
|
|||||||
// API calls
|
// API calls
|
||||||
serveMux.HandleFunc(path+"api/block-index/", s.jsonHandler(s.apiBlockIndex))
|
serveMux.HandleFunc(path+"api/block-index/", s.jsonHandler(s.apiBlockIndex))
|
||||||
serveMux.HandleFunc(path+"api/tx/", s.jsonHandler(s.apiTx))
|
serveMux.HandleFunc(path+"api/tx/", s.jsonHandler(s.apiTx))
|
||||||
|
serveMux.HandleFunc(path+"api/tx-specific/", s.jsonHandler(s.apiTxSpecific))
|
||||||
serveMux.HandleFunc(path+"api/address/", s.jsonHandler(s.apiAddress))
|
serveMux.HandleFunc(path+"api/address/", s.jsonHandler(s.apiAddress))
|
||||||
serveMux.HandleFunc(path+"api/block/", s.jsonHandler(s.apiBlock))
|
serveMux.HandleFunc(path+"api/block/", s.jsonHandler(s.apiBlock))
|
||||||
// socket.io interface
|
// socket.io interface
|
||||||
@ -318,6 +319,7 @@ 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
|
||||||
@ -370,6 +372,7 @@ 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 {
|
||||||
@ -378,9 +381,14 @@ func (s *PublicServer) explorerTx(w http.ResponseWriter, r *http.Request) (tpl,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errorTpl, nil, err
|
return errorTpl, nil, err
|
||||||
}
|
}
|
||||||
|
txSpecific, err = s.chain.GetTransactionSpecific(txid)
|
||||||
|
if err != nil {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,6 +611,17 @@ func (s *PublicServer) apiTx(r *http.Request) (interface{}, error) {
|
|||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *PublicServer) apiTxSpecific(r *http.Request) (interface{}, error) {
|
||||||
|
var tx json.RawMessage
|
||||||
|
var err error
|
||||||
|
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tx-specific"}).Inc()
|
||||||
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
|
txid := r.URL.Path[i+1:]
|
||||||
|
tx, err = s.chain.GetTransactionSpecific(txid)
|
||||||
|
}
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *PublicServer) apiAddress(r *http.Request) (interface{}, error) {
|
func (s *PublicServer) apiAddress(r *http.Request) (interface{}, error) {
|
||||||
var address *api.Address
|
var address *api.Address
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@ -272,3 +272,23 @@ h3 {
|
|||||||
.page-item.active .page-link {
|
.page-item.active .page-link {
|
||||||
background-color: #428bca;
|
background-color: #428bca;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#txSpecific {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.string {
|
||||||
|
color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number, .boolean {
|
||||||
|
color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.null {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key {
|
||||||
|
color: #333 ;
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
{{define "specific"}}{{$cs := .CoinShortcut}}{{$tx := .Tx}}
|
{{define "specific"}}{{$cs := .CoinShortcut}}{{$tx := .Tx}}{{$txSpecific := .TxSpecific}}
|
||||||
<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>
|
||||||
@ -42,9 +42,32 @@
|
|||||||
{{template "txdetail" .}}
|
{{template "txdetail" .}}
|
||||||
</div>
|
</div>
|
||||||
<div class="data-div">
|
<div class="data-div">
|
||||||
<h5>Hex</h5>
|
<h5>Transaction Data</h5>
|
||||||
<div class="alert alert-data" style="word-wrap: break-word; font-size: smaller;">
|
<div class="alert alert-data" style="word-wrap: break-word; font-size: smaller;">
|
||||||
<span>{{$tx.Hex}}</span>
|
<pre id="txSpecific"></pre>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
txSpecific = {{ $txSpecific }};
|
||||||
|
function syntaxHighlight(json) {
|
||||||
|
json = JSON.stringify(json, undefined, 2);
|
||||||
|
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||||
|
var cls = 'number';
|
||||||
|
if (/^"/.test(match)) {
|
||||||
|
if (/:$/.test(match)) {
|
||||||
|
cls = 'key';
|
||||||
|
} else {
|
||||||
|
cls = 'string';
|
||||||
|
}
|
||||||
|
} else if (/true|false/.test(match)) {
|
||||||
|
cls = 'boolean';
|
||||||
|
} else if (/null/.test(match)) {
|
||||||
|
cls = 'null';
|
||||||
|
}
|
||||||
|
return '<span class="' + cls + '">' + match + '</span>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.getElementById('txSpecific').innerHTML = syntaxHighlight(txSpecific);
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
Loading…
Reference in New Issue
Block a user