diff --git a/api/worker.go b/api/worker.go
index 168b6d00..36a41bbc 100644
--- a/api/worker.go
+++ b/api/worker.go
@@ -241,7 +241,10 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool
}
}
ethSpecific = eth.GetEthereumTxData(bchainTx)
- feesSat.Mul(ethSpecific.GasPriceNum, ethSpecific.GasUsed)
+ // mempool txs do not have fees yet
+ if ethSpecific.GasUsed != nil {
+ feesSat.Mul(ethSpecific.GasPriceNum, ethSpecific.GasUsed)
+ }
if len(bchainTx.Vout) > 0 {
valInSat = bchainTx.Vout[0].ValueSat
}
diff --git a/bchain/coins/eth/ethparser.go b/bchain/coins/eth/ethparser.go
index fbaeff15..0256099b 100644
--- a/bchain/coins/eth/ethparser.go
+++ b/bchain/coins/eth/ethparser.go
@@ -430,7 +430,7 @@ func GetErc20FromTx(tx *bchain.Tx) ([]Erc20Transfer, error) {
var r []Erc20Transfer
var err error
csd, ok := tx.CoinSpecificData.(completeTransaction)
- if ok {
+ if ok && csd.Receipt != nil {
r, err = erc20GetTransfersFromLog(csd.Receipt.Logs)
if err != nil {
return nil, err
diff --git a/configs/coins/ethereum-classic.json b/configs/coins/ethereum-classic.json
index 7e472a81..fc4e5fa3 100644
--- a/configs/coins/ethereum-classic.json
+++ b/configs/coins/ethereum-classic.json
@@ -40,7 +40,7 @@
"system_user": "blockbook-ethereum-classic",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
- "explorer_url": "https://gastracker.io/",
+ "explorer_url": "",
"additional_params": "-resyncindexperiod=4441",
"block_chain": {
"parse": true,
diff --git a/configs/coins/ethereum.json b/configs/coins/ethereum.json
index a940a696..2f08fff3 100644
--- a/configs/coins/ethereum.json
+++ b/configs/coins/ethereum.json
@@ -42,7 +42,7 @@
"system_user": "blockbook-ethereum",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
- "explorer_url": "https://etherscan.io/",
+ "explorer_url": "",
"additional_params": "",
"block_chain": {
"parse": true,
diff --git a/configs/coins/ethereum_testnet_ropsten.json b/configs/coins/ethereum_testnet_ropsten.json
index 82127a88..03d1a6b8 100644
--- a/configs/coins/ethereum_testnet_ropsten.json
+++ b/configs/coins/ethereum_testnet_ropsten.json
@@ -41,7 +41,7 @@
"system_user": "blockbook-ethereum",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
- "explorer_url": "https://ropsten.etherscan.io/",
+ "explorer_url": "",
"additional_params": "",
"block_chain": {
"parse": true,
diff --git a/server/public.go b/server/public.go
index 4a882cd9..76e065dc 100644
--- a/server/public.go
+++ b/server/public.go
@@ -14,6 +14,7 @@ import (
"net/http"
"reflect"
"runtime"
+ "runtime/debug"
"strconv"
"strings"
"time"
@@ -81,7 +82,7 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
is: is,
debug: debugMode,
}
- s.templates = parseTemplates()
+ s.templates = s.parseTemplates()
// map only basic functions, the rest is enabled by method MapFullPublicInterface
serveMux.Handle(path+"favicon.ico", http.FileServer(http.Dir("./static/")))
@@ -202,6 +203,7 @@ func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, e
defer func() {
if e := recover(); e != nil {
glog.Error(getFunctionName(handler), " recovered from panic: ", e)
+ debug.PrintStack()
if s.debug {
data = jsonError{fmt.Sprint("Internal server error: recovered from panic ", e), http.StatusInternalServerError}
} else {
@@ -264,6 +266,7 @@ func (s *PublicServer) htmlTemplateHandler(handler func(w http.ResponseWriter, r
defer func() {
if e := recover(); e != nil {
glog.Error(getFunctionName(handler), " recovered from panic: ", e)
+ debug.PrintStack()
t = errorInternalTpl
if s.debug {
data = s.newTemplateDataWithError(fmt.Sprint("Internal server error: recovered from panic ", e))
@@ -286,7 +289,7 @@ func (s *PublicServer) htmlTemplateHandler(handler func(w http.ResponseWriter, r
if s.debug {
// reload templates on each request
// to reflect changes during development
- s.templates = parseTemplates()
+ s.templates = s.parseTemplates()
}
t, data, err = handler(w, r)
if err != nil || (data == nil && t != noTpl) {
@@ -349,7 +352,7 @@ type TemplateData struct {
Status string
}
-func parseTemplates() []*template.Template {
+func (s *PublicServer) parseTemplates() []*template.Template {
templateFuncMap := template.FuncMap{
"formatTime": formatTime,
"formatUnixTime": formatUnixTime,
@@ -361,11 +364,17 @@ func parseTemplates() []*template.Template {
t[errorTpl] = template.Must(template.New("error").Funcs(templateFuncMap).ParseFiles("./static/templates/error.html", "./static/templates/base.html"))
t[errorInternalTpl] = template.Must(template.New("error").Funcs(templateFuncMap).ParseFiles("./static/templates/error.html", "./static/templates/base.html"))
t[indexTpl] = template.Must(template.New("index").Funcs(templateFuncMap).ParseFiles("./static/templates/index.html", "./static/templates/base.html"))
- t[txTpl] = template.Must(template.New("tx").Funcs(templateFuncMap).ParseFiles("./static/templates/tx.html", "./static/templates/txdetail.html", "./static/templates/base.html"))
- t[addressTpl] = template.Must(template.New("address").Funcs(templateFuncMap).ParseFiles("./static/templates/address.html", "./static/templates/txdetail.html", "./static/templates/paging.html", "./static/templates/base.html"))
t[blocksTpl] = template.Must(template.New("blocks").Funcs(templateFuncMap).ParseFiles("./static/templates/blocks.html", "./static/templates/paging.html", "./static/templates/base.html"))
- t[blockTpl] = template.Must(template.New("block").Funcs(templateFuncMap).ParseFiles("./static/templates/block.html", "./static/templates/txdetail.html", "./static/templates/paging.html", "./static/templates/base.html"))
t[sendTransactionTpl] = template.Must(template.New("block").Funcs(templateFuncMap).ParseFiles("./static/templates/sendtx.html", "./static/templates/base.html"))
+ if s.chainParser.GetChainType() == bchain.ChainEthereumType {
+ t[txTpl] = template.Must(template.New("tx").Funcs(templateFuncMap).ParseFiles("./static/templates/tx.html", "./static/templates/txdetail_ethereumtype.html", "./static/templates/base.html"))
+ t[addressTpl] = template.Must(template.New("address").Funcs(templateFuncMap).ParseFiles("./static/templates/address.html", "./static/templates/txdetail_ethereumtype.html", "./static/templates/paging.html", "./static/templates/base.html"))
+ t[blockTpl] = template.Must(template.New("block").Funcs(templateFuncMap).ParseFiles("./static/templates/block.html", "./static/templates/txdetail_ethereumtype.html", "./static/templates/paging.html", "./static/templates/base.html"))
+ } else {
+ t[txTpl] = template.Must(template.New("tx").Funcs(templateFuncMap).ParseFiles("./static/templates/tx.html", "./static/templates/txdetail.html", "./static/templates/base.html"))
+ t[addressTpl] = template.Must(template.New("address").Funcs(templateFuncMap).ParseFiles("./static/templates/address.html", "./static/templates/txdetail.html", "./static/templates/paging.html", "./static/templates/base.html"))
+ t[blockTpl] = template.Must(template.New("block").Funcs(templateFuncMap).ParseFiles("./static/templates/block.html", "./static/templates/txdetail.html", "./static/templates/paging.html", "./static/templates/base.html"))
+ }
return t
}
diff --git a/server/socketio.go b/server/socketio.go
index 7ea7a432..7a12a0d7 100644
--- a/server/socketio.go
+++ b/server/socketio.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"math/big"
"net/http"
+ "runtime/debug"
"strconv"
"strings"
"time"
@@ -161,6 +162,7 @@ func (s *SocketIoServer) onMessage(c *gosocketio.Channel, req map[string]json.Ra
defer func() {
if r := recover(); r != nil {
glog.Error(c.Id(), " onMessage ", method, " recovered from panic: ", r)
+ debug.PrintStack()
e := resultError{}
e.Error.Message = "Internal error"
rv = e
@@ -664,6 +666,7 @@ func (s *SocketIoServer) onSubscribe(c *gosocketio.Channel, req []byte) interfac
defer func() {
if r := recover(); r != nil {
glog.Error(c.Id(), " onSubscribe recovered from panic: ", r)
+ debug.PrintStack()
}
}()
diff --git a/static/templates/tx.html b/static/templates/tx.html
index 98a5dc10..cea201d3 100644
--- a/static/templates/tx.html
+++ b/static/templates/tx.html
@@ -7,20 +7,46 @@
- {{if $tx.Confirmations}}
+ {{- if $tx.Confirmations -}}
| Mined Time |
{{formatUnixTime $tx.Blocktime}} |
-
{{end}}
+ {{end -}}
| In Block |
{{if $tx.Confirmations}}{{$tx.Blockhash}}{{else}}Unconfirmed{{end}} |
- {{if $tx.Confirmations}}
+ {{- if $tx.Confirmations -}}
| In Block Height |
{{$tx.Blockheight}} |
{{end}}
+ {{- if $tx.EthereumSpecific -}}
+
+ | Status |
+ {{- if $tx.EthereumSpecific.Status -}}
+ {{- if ne $tx.EthereumSpecific.Status 1 -}}
+ Pending |
+ {{- else -}}
+ Success |
+ {{- end -}}
+ {{- else -}}
+ Fail |
+ {{- end -}}
+
+
+ | Value |
+ {{formatAmount $tx.ValueOut}} {{$cs}} |
+
+
+ | Gas Used / Limit |
+ {{if $tx.EthereumSpecific.GasUsed}}{{$tx.EthereumSpecific.GasUsed}}{{else}}pending{{end}} / {{$tx.EthereumSpecific.GasLimit}} |
+
+
+ | Gas Price |
+ {{formatAmount $tx.EthereumSpecific.GasPrice}} {{$cs}} |
+
+ {{- else -}}
| Total Input |
{{formatAmount $tx.ValueIn}} {{$cs}} |
@@ -29,11 +55,12 @@
Total Output |
{{formatAmount $tx.ValueOut}} {{$cs}} |
- {{if $tx.Fees}}
+ {{- end -}}
+ {{- if $tx.Fees -}}
| Fees |
{{formatAmount $tx.Fees}} {{$cs}} |
-
{{end}}
+ {{end -}}
diff --git a/static/templates/txdetail_ethereumtype.html b/static/templates/txdetail_ethereumtype.html
new file mode 100644
index 00000000..a46cde45
--- /dev/null
+++ b/static/templates/txdetail_ethereumtype.html
@@ -0,0 +1,129 @@
+{{define "txdetail"}}{{$cs := .CoinShortcut}}{{$addr := .AddrStr}}{{$tx := .Tx}}
+
+
+
+ {{- if $tx.Confirmations -}}
+
mined {{formatUnixTime $tx.Blocktime}}
+ {{- end -}}
+
+
+
+
+
+
+ {{- range $vin := $tx.Vin -}}
+
+ |
+ {{- range $a := $vin.Addresses -}}
+
+ {{if and (ne $a $addr) $vin.Searchable}}{{$a}}{{else}}{{$a}}{{end}}
+
+ {{- else -}}
+ Unparsed address
+ {{- end -}}
+ |
+
+ {{- else -}}
+
+ | No Inputs |
+
+ {{- end -}}
+
+
+
+
+
+
+
+
+
+ {{- range $vout := $tx.Vout -}}
+
+ |
+ {{- range $a := $vout.ScriptPubKey.Addresses -}}
+
+ {{- if and (ne $a $addr) $vout.ScriptPubKey.Searchable}}{{$a}}{{else}}{{$a}}{{- end -}}
+
+ {{- else -}}
+ Unparsed address
+ {{- end -}}
+ |
+
+ {{- else -}}
+
+ | No Outputs |
+
+ {{- end -}}
+
+
+
+
+
+ {{formatAmount $tx.ValueOut}} {{$cs}}
+
+
+ {{- if $tx.Erc20Transfers -}}
+
+ ERC20 Token Transfers
+
+ {{- range $erc20 := $tx.Erc20Transfers -}}
+
+
+
+
+
+
+ |
+ {{if ne $erc20.From $addr}}{{$erc20.From}}{{else}}{{$erc20.From}}{{end}}
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+ {{if ne $erc20.To $addr}}{{$erc20.To}}{{else}}{{$erc20.To}}{{end}}
+ |
+
+
+
+
+
+
{{formatAmount $erc20.Tokens}} {{$erc20.Symbol}}
+
+ {{- end -}}
+
+ {{- end -}}
+
+
+ {{- if $tx.Fees -}}
+ Fee: {{formatAmount $tx.Fees}} {{$cs}}
+ {{- end -}}
+
+
+ {{- if $tx.Confirmations -}}
+ {{$tx.Confirmations}} Confirmations
+ {{- else -}}
+ Unconfirmed Transaction!
+ {{- end -}}
+ {{formatAmount $tx.ValueOut}} {{$cs}}
+
+
+
+{{end}}
\ No newline at end of file