Highlight xpub addresses in explorer
This commit is contained in:
parent
9d3cd3b3e9
commit
266b0575b6
@ -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
|
||||
|
||||
34
api/xpub.go
34
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -151,7 +151,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
`td class="data">0 FAKE</td>`,
|
||||
`<a href="/address/mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj">mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj</a>`,
|
||||
`13.60030331 FAKE`,
|
||||
`<td><span class="float-left">No Inputs (Newly Generated Coins)</span></td>`,
|
||||
`<td><span class="tx-addr">No Inputs (Newly Generated Coins)</span></td>`,
|
||||
`</html>`,
|
||||
},
|
||||
},
|
||||
@ -168,8 +168,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
`<td class="data">0.00012345 FAKE</td>`,
|
||||
`<a href="/tx/7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25">7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25</a>`,
|
||||
`3172.83951061 FAKE <a class="text-danger" href="/spending/7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25/0" title="Spent">➡</a></span>`,
|
||||
`<td><span class="ellipsis float-left"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="float-right">`,
|
||||
`td><span class="ellipsis float-left"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="float-right">`,
|
||||
`<td><span class="ellipsis tx-addr"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="tx-amt">`,
|
||||
`td><span class="ellipsis tx-addr"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="tx-amt">`,
|
||||
`9172.83951061 FAKE <span class="text-success" title="Unspent"> <b>×</b></span></span>`,
|
||||
`<a href="/tx/00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840">00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840</a>`,
|
||||
`</html>`,
|
||||
@ -290,7 +290,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
`td class="data">0 FAKE</td>`,
|
||||
`<a href="/address/mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj">mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj</a>`,
|
||||
`13.60030331 FAKE`,
|
||||
`<td><span class="float-left">No Inputs (Newly Generated Coins)</span></td>`,
|
||||
`<td><span class="tx-addr">No Inputs (Newly Generated Coins)</span></td>`,
|
||||
`</html>`,
|
||||
},
|
||||
},
|
||||
@ -307,8 +307,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
`<td class="data">0.00012345 FAKE</td>`,
|
||||
`<a href="/tx/7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25">7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25</a>`,
|
||||
`3172.83951061 FAKE <a class="text-danger" href="/spending/7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25/0" title="Spent">➡</a></span>`,
|
||||
`<td><span class="ellipsis float-left"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="float-right">`,
|
||||
`td><span class="ellipsis float-left"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="float-right">`,
|
||||
`<td><span class="ellipsis tx-addr"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="tx-amt">`,
|
||||
`td><span class="ellipsis tx-addr"><a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a></span><span class="tx-amt">`,
|
||||
`9172.83951061 FAKE <span class="text-success" title="Unspent"> <b>×</b></span></span>`,
|
||||
`<a href="/tx/00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840">00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840</a>`,
|
||||
`</html>`,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
{{define "txdetail"}}{{$cs := .CoinShortcut}}{{$addr := .AddrStr}}{{$tx := .Tx}}
|
||||
{{define "txdetail"}}{{$cs := .CoinShortcut}}{{$addr := .AddrStr}}{{$tx := .Tx}}{{$data := .}}
|
||||
<div class="alert alert-data">
|
||||
<div class="row line-bot">
|
||||
<div class="col-xs-7 col-md-8 ellipsis">
|
||||
@ -10,23 +10,23 @@
|
||||
</div>
|
||||
<div class="row line-mid">
|
||||
<div class="col-md-5">
|
||||
<div class="row">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
{{- range $vin := $tx.Vin -}}
|
||||
<tr>
|
||||
<tr{{if isOwnAddress $data $vin.Addresses}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
{{- if $vin.Txid -}}
|
||||
<a class="float-left text-muted" href="/tx/{{$vin.Txid}}" title="Outpoint {{$vin.Txid}},{{$vin.Vout}}">➡ </a>
|
||||
{{- end -}}
|
||||
{{- range $a := $vin.Addresses -}}
|
||||
<span class="ellipsis float-left">
|
||||
<span class="ellipsis tx-addr">
|
||||
{{if and (ne $a $addr) $vin.Searchable}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{end}}
|
||||
</span>
|
||||
{{- else -}}
|
||||
<span class="float-left">{{- if $vin.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}}</span>
|
||||
<span class="tx-addr">{{- if $vin.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}}</span>
|
||||
{{- end -}}{{- if $vin.Addresses -}}
|
||||
<span class="float-right{{if stringInSlice $addr $vin.Addresses}} text-danger{{end}}">{{formatAmount $vin.ValueSat}} {{$cs}}</span>
|
||||
<span class="tx-amt">{{formatAmount $vin.ValueSat}} {{$cs}}</span>
|
||||
{{- end -}}
|
||||
</td>
|
||||
</tr>
|
||||
@ -45,20 +45,20 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="row">
|
||||
<div class="row tx-out">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
{{- range $vout := $tx.Vout -}}
|
||||
<tr>
|
||||
<tr{{if isOwnAddress $data $vout.Addresses}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
{{- range $a := $vout.Addresses -}}
|
||||
<span class="ellipsis float-left">
|
||||
<span class="ellipsis tx-addr">
|
||||
{{- if and (ne $a $addr) $vout.Searchable}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{- end -}}
|
||||
</span>
|
||||
{{- else -}}
|
||||
<span class="float-left">Unparsed address</span>
|
||||
<span class="tx-addr">Unparsed address</span>
|
||||
{{- end -}}
|
||||
<span class="float-right{{if stringInSlice $addr $vout.Addresses}} text-success{{end}}">
|
||||
<span class="tx-amt">
|
||||
{{formatAmount $vout.ValueSat}} {{$cs}} {{if $vout.Spent}}<a class="text-danger" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" title="Spent">➡</a>{{else -}}
|
||||
<span class="text-success" title="Unspent"> <b>×</b></span>
|
||||
{{- end -}}
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
<td>Total XPUB Addresses</td>
|
||||
<td class="data">{{$addr.TotalTokens}}</td>
|
||||
</tr>
|
||||
{{- if $addr.Tokens -}}
|
||||
{{- if $addr.TotalTokens -}}
|
||||
<tr>
|
||||
<td>{{if $data.AllTokens}}XPUB Addresses{{else}}XPUB Addresses with Balance{{end}}</td>
|
||||
<td style="padding: 0;">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user