Show coin specific transaction data in explorer and api

This commit is contained in:
Martin Boehm 2018-10-16 12:25:31 +02:00
parent 71969ebd23
commit 8140af1a69
7 changed files with 99 additions and 8 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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"`
} }

View File

@ -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)

View File

@ -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

View File

@ -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 ;
}

View File

@ -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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
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}}