Show coin specific transaction data in explorer and api
parent
71969ebd23
commit
8140af1a69
|
@ -180,6 +180,11 @@ func (c *blockChainWithMetrics) GetTransaction(txid string) (v *bchain.Tx, err e
|
|||
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) {
|
||||
defer func(s time.Time) { c.observeRPCLatency("GetTransactionForMempool", s, err) }(time.Now())
|
||||
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.
|
||||
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)
|
||||
|
||||
res := ResGetRawTransaction{}
|
||||
|
@ -684,11 +697,7 @@ func (b *BitcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||
if res.Error != nil {
|
||||
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
||||
}
|
||||
tx, err := b.Parser.ParseTxFromJson(res.Result)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
return tx, nil
|
||||
return res.Result, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Transactions []string `json:"transactions"`
|
||||
}
|
||||
|
|
|
@ -167,6 +167,7 @@ type BlockChain interface {
|
|||
GetMempool() ([]string, error)
|
||||
GetTransaction(txid string) (*Tx, error)
|
||||
GetTransactionForMempool(txid string) (*Tx, error)
|
||||
GetTransactionSpecific(txid string) (json.RawMessage, error)
|
||||
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
|
||||
EstimateFee(blocks int) (big.Int, error)
|
||||
SendRawTransaction(tx string) (string, error)
|
||||
|
|
|
@ -124,6 +124,7 @@ func (s *PublicServer) ConnectFullPublicInterface() {
|
|||
// API calls
|
||||
serveMux.HandleFunc(path+"api/block-index/", s.jsonHandler(s.apiBlockIndex))
|
||||
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/block/", s.jsonHandler(s.apiBlock))
|
||||
// socket.io interface
|
||||
|
@ -318,6 +319,7 @@ type TemplateData struct {
|
|||
Address *api.Address
|
||||
AddrStr string
|
||||
Tx *api.Tx
|
||||
TxSpecific json.RawMessage
|
||||
Error *api.ApiError
|
||||
Blocks *api.Blocks
|
||||
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) {
|
||||
var tx *api.Tx
|
||||
var txSpecific json.RawMessage
|
||||
var err error
|
||||
s.metrics.ExplorerViews.With(common.Labels{"action": "tx"}).Inc()
|
||||
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 {
|
||||
return errorTpl, nil, err
|
||||
}
|
||||
txSpecific, err = s.chain.GetTransactionSpecific(txid)
|
||||
if err != nil {
|
||||
return errorTpl, nil, err
|
||||
}
|
||||
}
|
||||
data := s.newTemplateData()
|
||||
data.Tx = tx
|
||||
data.TxSpecific = txSpecific
|
||||
return txTpl, data, nil
|
||||
}
|
||||
|
||||
|
@ -603,6 +611,17 @@ func (s *PublicServer) apiTx(r *http.Request) (interface{}, error) {
|
|||
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) {
|
||||
var address *api.Address
|
||||
var err error
|
||||
|
|
|
@ -271,4 +271,24 @@ h3 {
|
|||
|
||||
.page-item.active .page-link {
|
||||
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>
|
||||
<div class="alert alert-data ellipsis">
|
||||
<span class="data">{{$tx.Txid}}</span>
|
||||
|
@ -42,9 +42,32 @@
|
|||
{{template "txdetail" .}}
|
||||
</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;">
|
||||
<span>{{$tx.Hex}}</span>
|
||||
<pre id="txSpecific"></pre>
|
||||
</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>
|
||||
{{end}}
|
Loading…
Reference in New Issue