Hide xpub addresses with zero balance in explorer by default

xpub
Martin Boehm 2019-01-31 15:04:09 +01:00
parent 8f1f1c87ac
commit 57b40ad6dc
5 changed files with 63 additions and 39 deletions

View File

@ -52,6 +52,11 @@ func NewAPIError(s string, public bool) error {
// Amount is datatype holding amounts
type Amount big.Int
// IsZeroBigInt if big int has zero value
func IsZeroBigInt(b *big.Int) bool {
return len(b.Bits()) == 0
}
// MarshalJSON Amount serialization
func (a *Amount) MarshalJSON() (out []byte, err error) {
if a == nil {
@ -207,6 +212,7 @@ type AddressFilter struct {
Contract string
FromHeight uint32
ToHeight uint32
AllTokens bool
}
// Address holds information about address and its transactions
@ -223,6 +229,7 @@ type Address struct {
Transactions []*Tx `json:"transactions,omitempty"`
Txids []string `json:"txids,omitempty"`
Nonce string `json:"nonce,omitempty"`
TotalTokens int `json:"totalTokens,omitempty"`
Tokens []Token `json:"tokens,omitempty"`
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
Filter string `json:"-"`

View File

@ -825,7 +825,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
}
var checksum big.Int
// ba can be nil if the address is only in mempool!
if ba != nil && ba.BalanceSat.Uint64() > 0 {
if ba != nil && !IsZeroBigInt(&ba.BalanceSat) {
outpoints := make([]bchain.Outpoint, 0, 8)
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, height uint32, indexes []int32) error {
for _, index := range indexes {

View File

@ -233,17 +233,24 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option
cachedXpubsMux.Lock()
cachedXpubs[xpub] = data
cachedXpubsMux.Unlock()
totalTokens := 0
tokens := make([]Token, 0, 4)
for i := range data.addresses {
ad := &data.addresses[i]
if ad.balance != nil {
tokens = append(tokens, w.tokenFromXpubAddress(ad, 0, i))
totalTokens++
if filter.AllTokens || !IsZeroBigInt(&ad.balance.BalanceSat) {
tokens = append(tokens, w.tokenFromXpubAddress(ad, 0, i))
}
}
}
for i := range data.changeAddresses {
ad := &data.changeAddresses[i]
if ad.balance != nil {
tokens = append(tokens, w.tokenFromXpubAddress(ad, 1, i))
totalTokens++
if filter.AllTokens || !IsZeroBigInt(&ad.balance.BalanceSat) {
tokens = append(tokens, w.tokenFromXpubAddress(ad, 1, i))
}
}
}
var totalReceived big.Int
@ -259,7 +266,8 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option
// UnconfirmedTxs: len(txm),
// Transactions: txs,
// Txids: txids,
Tokens: tokens,
TotalTokens: totalTokens,
Tokens: tokens,
// Erc20Contract: erc20c,
// Nonce: nonce,
}

View File

@ -405,6 +405,7 @@ type TemplateData struct {
TOSLink string
SendTxHex string
Status string
AllTokens bool
}
func (s *PublicServer) parseTemplates() []*template.Template {
@ -582,36 +583,40 @@ func (s *PublicServer) explorerAddress(w http.ResponseWriter, r *http.Request) (
return addressTpl, data, nil
}
func (s *PublicServer) getAddressForXpub(r *http.Request, xpub string, pageSize int, option api.GetAddressOption) (*api.Address, error) {
var fn = api.AddressFilterVoutOff
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
if ec != nil {
page = 0
}
filter := r.URL.Query().Get("filter")
if len(filter) > 0 {
if filter == "inputs" {
fn = api.AddressFilterVoutInputs
} else if filter == "outputs" {
fn = api.AddressFilterVoutOutputs
} else {
fn, ec = strconv.Atoi(filter)
if ec != nil || fn < 0 {
filter = ""
fn = api.AddressFilterVoutOff
}
}
}
gap, ec := strconv.Atoi(r.URL.Query().Get("gap"))
if ec != nil {
gap = 0
}
allAddresses, _ := strconv.ParseBool(r.URL.Query().Get("alladdresses"))
return s.api.GetAddressForXpub(xpub, page, pageSize, option, &api.AddressFilter{Vout: fn, AllTokens: allAddresses}, gap)
}
func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
var address *api.Address
var filter string
var fn = api.AddressFilterVoutOff
var err error
s.metrics.ExplorerViews.With(common.Labels{"action": "xpub"}).Inc()
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
if ec != nil {
page = 0
}
filter = r.URL.Query().Get("filter")
if len(filter) > 0 {
if filter == "inputs" {
fn = api.AddressFilterVoutInputs
} else if filter == "outputs" {
fn = api.AddressFilterVoutOutputs
} else {
fn, ec = strconv.Atoi(filter)
if ec != nil || fn < 0 {
filter = ""
fn = api.AddressFilterVoutOff
}
}
}
gap, ec := strconv.Atoi(r.URL.Query().Get("gap"))
if ec != nil {
gap = 0
}
address, err = s.api.GetAddressForXpub(r.URL.Path[i+1:], page, txsOnPage, api.TxHistoryLight, &api.AddressFilter{Vout: fn}, gap)
address, err = s.getAddressForXpub(r, r.URL.Path[i+1:], txsOnPage, api.TxHistoryLight)
if err != nil {
return errorTpl, nil, err
}
@ -621,10 +626,13 @@ func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl
data.Address = address
data.Page = address.Page
data.PagingRange, data.PrevPage, data.NextPage = getPagingRange(address.Page, address.TotalPages)
filter := r.URL.Query().Get("filter")
if filter != "" {
data.PageParams = template.URL("&filter=" + filter)
data.Address.Filter = filter
}
allAddresses := r.URL.Query().Get("alladdresses")
data.AllTokens, _ = strconv.ParseBool(allAddresses)
return xpubTpl, data, nil
}
@ -879,15 +887,7 @@ func (s *PublicServer) apiXpub(r *http.Request, apiVersion int) (interface{}, er
var err error
s.metrics.ExplorerViews.With(common.Labels{"action": "api-xpub"}).Inc()
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
if ec != nil {
page = 0
}
gap, ec := strconv.Atoi(r.URL.Query().Get("gap"))
if ec != nil {
gap = 0
}
address, err = s.api.GetAddressForXpub(r.URL.Path[i+1:], page, txsInAPI, api.TxidHistory, &api.AddressFilter{Vout: api.AddressFilterVoutOff}, gap)
address, err = s.getAddressForXpub(r, r.URL.Path[i+1:], txsInAPI, api.TxidHistory)
if err == nil && apiVersion == apiV1 {
return s.api.AddressToV1(address), nil
}

View File

@ -25,9 +25,13 @@
<td>No. Transactions</td>
<td class="data">{{$addr.Txs}}</td>
</tr>
<tr>
<td>Total XPUB addresses</td>
<td class="data">{{$addr.TotalTokens}}</td>
</tr>
{{- if $addr.Tokens -}}
<tr>
<td>XPUB addresses</td>
<td>{{if $data.AllTokens}}XPUB Addresses{{else}}Nonzero XPUB Addresses{{end}}</td>
<td style="padding: 0;">
<table class="table data-table">
<tbody>
@ -45,6 +49,11 @@
<td class="data">{{$t.Contract}}</td>
</tr>
{{- end -}}
{{- if not $data.AllTokens -}}
<tr>
<td colspan="4"><a href="?alladdresses=true">Show all XPUB addresses</a></td>
</tr>
{{- end -}}
</tbody>
</table>
</td>