From 266b0575b6ab140fa3e41f96055d9e1c73e7a02c Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Mon, 4 Feb 2019 16:53:49 +0100 Subject: [PATCH] Highlight xpub addresses in explorer --- api/types.go | 4 +++- api/xpub.go | 34 +++++++++++++++++++++++++++------- server/public.go | 19 ++++++++++++++++++- server/public_test.go | 12 ++++++------ server/socketio.go | 9 --------- static/css/main.css | 22 +++++++++++++++++++++- static/templates/txdetail.html | 22 +++++++++++----------- static/templates/xpub.html | 2 +- 8 files changed, 87 insertions(+), 37 deletions(-) diff --git a/api/types.go b/api/types.go index 6cea9243..86a48a03 100644 --- a/api/types.go +++ b/api/types.go @@ -233,7 +233,9 @@ type Address struct { TotalTokens int `json:"totalTokens,omitempty"` Tokens []Token `json:"tokens,omitempty"` Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"` - Filter string `json:"-"` + // helpers for explorer + Filter string `json:"-"` + XPubAddresses map[string]struct{} `json:"-"` } // AddressUtxo holds information about address and its transactions diff --git a/api/xpub.go b/api/xpub.go index 141b8381..5a456003 100644 --- a/api/xpub.go +++ b/api/xpub.go @@ -235,6 +235,10 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option } // gap is increased one as there must be gap of empty addresses before the derivation is stopped gap++ + page-- + if page < 0 { + page = 0 + } var processedHash string cachedXpubsMux.Lock() data, found := cachedXpubs[xpub] @@ -305,7 +309,7 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option if option >= TxidHistory { txc := make(xpubTxids, 0, 32) var addTxids func(ad *xpubAddress) - if filter.FromHeight != 0 || filter.ToHeight != 0 || filter.Vout != AddressFilterVoutOff { + if filter.FromHeight == 0 && filter.ToHeight == 0 && filter.Vout == AddressFilterVoutOff { addTxids = func(ad *xpubAddress) { txc = append(txc, ad.txids...) } @@ -372,13 +376,21 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option } } totalTokens := 0 + xpubAddresses := make(map[string]struct{}) tokens := make([]Token, 0, 4) for i := range data.addresses { ad := &data.addresses[i] if ad.balance != nil { totalTokens++ if filter.AllTokens || !IsZeroBigInt(&ad.balance.BalanceSat) { - tokens = append(tokens, w.tokenFromXpubAddress(ad, 0, i)) + t := w.tokenFromXpubAddress(ad, 0, i) + tokens = append(tokens, t) + xpubAddresses[t.Name] = struct{}{} + } else { + a, _, _ := w.chainParser.GetAddressesFromAddrDesc(ad.addrDesc) + if len(a) > 0 { + xpubAddresses[a[0]] = struct{}{} + } } } } @@ -387,7 +399,14 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option if ad.balance != nil { totalTokens++ if filter.AllTokens || !IsZeroBigInt(&ad.balance.BalanceSat) { - tokens = append(tokens, w.tokenFromXpubAddress(ad, 1, i)) + t := w.tokenFromXpubAddress(ad, 1, i) + tokens = append(tokens, t) + xpubAddresses[t.Name] = struct{}{} + } else { + a, _, _ := w.chainParser.GetAddressesFromAddrDesc(ad.addrDesc) + if len(a) > 0 { + xpubAddresses[a[0]] = struct{}{} + } } } } @@ -402,10 +421,11 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option Txs: int(data.txs), // UnconfirmedBalanceSat: (*Amount)(&uBalSat), // UnconfirmedTxs: len(txm), - Transactions: txs, - Txids: txids, - TotalTokens: totalTokens, - Tokens: tokens, + Transactions: txs, + Txids: txids, + TotalTokens: totalTokens, + Tokens: tokens, + XPubAddresses: xpubAddresses, } glog.Info("GetAddressForXpub ", xpub[:16], ", ", len(data.addresses)+len(data.changeAddresses), " derived addresses, ", data.txs, " total txs finished in ", time.Since(start)) return &addr, nil diff --git a/server/public.go b/server/public.go index d40567c3..ecad94d0 100644 --- a/server/public.go +++ b/server/public.go @@ -415,7 +415,7 @@ func (s *PublicServer) parseTemplates() []*template.Template { "formatAmount": s.formatAmount, "formatAmountWithDecimals": formatAmountWithDecimals, "setTxToTemplateData": setTxToTemplateData, - "stringInSlice": stringInSlice, + "isOwnAddress": isOwnAddress, } var createTemplate func(filenames ...string) *template.Template if s.debug { @@ -504,6 +504,23 @@ func setTxToTemplateData(td *TemplateData, tx *api.Tx) *TemplateData { return td } +// returns true if addresses are "own", +// i.e. either the address of the address detail or belonging to the xpub +func isOwnAddress(td *TemplateData, addresses []string) bool { + if len(addresses) == 1 { + a := addresses[0] + if a == td.AddrStr { + return true + } + if td.Address != nil && td.Address.XPubAddresses != nil { + if _, found := td.Address.XPubAddresses[a]; found { + return true + } + } + } + return false +} + func (s *PublicServer) explorerTx(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) { var tx *api.Tx var err error diff --git a/server/public_test.go b/server/public_test.go index 525a7248..a6feca10 100644 --- a/server/public_test.go +++ b/server/public_test.go @@ -151,7 +151,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) { `td class="data">0 FAKE`, `mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj`, `13.60030331 FAKE`, - `No Inputs (Newly Generated Coins)`, + `No Inputs (Newly Generated Coins)`, ``, }, }, @@ -168,8 +168,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) { `0.00012345 FAKE`, `7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25`, `3172.83951061 FAKE `, - `mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, - `td>mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, + `mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, + `td>mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, `9172.83951061 FAKE ×`, `00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840`, ``, @@ -290,7 +290,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) { `td class="data">0 FAKE`, `mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj`, `13.60030331 FAKE`, - `No Inputs (Newly Generated Coins)`, + `No Inputs (Newly Generated Coins)`, ``, }, }, @@ -307,8 +307,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) { `0.00012345 FAKE`, `7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25`, `3172.83951061 FAKE `, - `mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, - `td>mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, + `mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, + `td>mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL`, `9172.83951061 FAKE ×`, `00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840`, ``, diff --git a/server/socketio.go b/server/socketio.go index e742f3cb..fc70510d 100644 --- a/server/socketio.go +++ b/server/socketio.go @@ -292,15 +292,6 @@ type resultGetAddressHistory struct { } `json:"result"` } -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - func txToResTx(tx *api.Tx) resTx { inputs := make([]txInputs, len(tx.Vin)) for i := range tx.Vin { diff --git a/static/css/main.css b/static/css/main.css index c4ef6a48..e94e97a9 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -182,6 +182,26 @@ h3 { text-transform: uppercase; } +.tx-own { + background-color: #fff6e6; +} + +.tx-amt { + float: right!important; +} + +.tx-in .tx-own .tx-amt { + color: #dc3545!important; +} + +.tx-out .tx-own .tx-amt { + color: #28a745!important; +} + +.tx-addr { + float: left!important; +} + .ellipsis { overflow: hidden; text-overflow: ellipsis; @@ -283,5 +303,5 @@ table.data-table table.data-table th { } .key { - color: #333 ; + color: #333; } \ No newline at end of file diff --git a/static/templates/txdetail.html b/static/templates/txdetail.html index 97121b13..57bde9c9 100644 --- a/static/templates/txdetail.html +++ b/static/templates/txdetail.html @@ -1,4 +1,4 @@ -{{define "txdetail"}}{{$cs := .CoinShortcut}}{{$addr := .AddrStr}}{{$tx := .Tx}} +{{define "txdetail"}}{{$cs := .CoinShortcut}}{{$addr := .AddrStr}}{{$tx := .Tx}}{{$data := .}}
@@ -10,23 +10,23 @@
-
+
{{- range $vin := $tx.Vin -}} - + @@ -45,20 +45,20 @@
-
+
{{- if $vin.Txid -}} ➡  {{- end -}} {{- range $a := $vin.Addresses -}} - + {{if and (ne $a $addr) $vin.Searchable}}{{$a}}{{else}}{{$a}}{{end}} {{- else -}} - {{- if $vin.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}} + {{- if $vin.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}} {{- end -}}{{- if $vin.Addresses -}} - {{formatAmount $vin.ValueSat}} {{$cs}} + {{formatAmount $vin.ValueSat}} {{$cs}} {{- end -}}
{{- range $vout := $tx.Vout -}} - + - {{- if $addr.Tokens -}} + {{- if $addr.TotalTokens -}}
{{- range $a := $vout.Addresses -}} - + {{- if and (ne $a $addr) $vout.Searchable}}{{$a}}{{else}}{{$a}}{{- end -}} {{- else -}} - Unparsed address + Unparsed address {{- end -}} - + {{formatAmount $vout.ValueSat}} {{$cs}} {{if $vout.Spent}}{{else -}} × {{- end -}} diff --git a/static/templates/xpub.html b/static/templates/xpub.html index 54cb612d..1696c4a7 100644 --- a/static/templates/xpub.html +++ b/static/templates/xpub.html @@ -29,7 +29,7 @@ Total XPUB Addresses {{$addr.TotalTokens}}
{{if $data.AllTokens}}XPUB Addresses{{else}}XPUB Addresses with Balance{{end}}