Hide xpub addresses with zero balance in explorer by default
This commit is contained in:
parent
8f1f1c87ac
commit
57b40ad6dc
@ -52,6 +52,11 @@ func NewAPIError(s string, public bool) error {
|
|||||||
// Amount is datatype holding amounts
|
// Amount is datatype holding amounts
|
||||||
type Amount big.Int
|
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
|
// MarshalJSON Amount serialization
|
||||||
func (a *Amount) MarshalJSON() (out []byte, err error) {
|
func (a *Amount) MarshalJSON() (out []byte, err error) {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
@ -207,6 +212,7 @@ type AddressFilter struct {
|
|||||||
Contract string
|
Contract string
|
||||||
FromHeight uint32
|
FromHeight uint32
|
||||||
ToHeight uint32
|
ToHeight uint32
|
||||||
|
AllTokens bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address holds information about address and its transactions
|
// Address holds information about address and its transactions
|
||||||
@ -223,6 +229,7 @@ type Address struct {
|
|||||||
Transactions []*Tx `json:"transactions,omitempty"`
|
Transactions []*Tx `json:"transactions,omitempty"`
|
||||||
Txids []string `json:"txids,omitempty"`
|
Txids []string `json:"txids,omitempty"`
|
||||||
Nonce string `json:"nonce,omitempty"`
|
Nonce string `json:"nonce,omitempty"`
|
||||||
|
TotalTokens int `json:"totalTokens,omitempty"`
|
||||||
Tokens []Token `json:"tokens,omitempty"`
|
Tokens []Token `json:"tokens,omitempty"`
|
||||||
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
|
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
|
||||||
Filter string `json:"-"`
|
Filter string `json:"-"`
|
||||||
|
|||||||
@ -825,7 +825,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
|
|||||||
}
|
}
|
||||||
var checksum big.Int
|
var checksum big.Int
|
||||||
// ba can be nil if the address is only in mempool!
|
// 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)
|
outpoints := make([]bchain.Outpoint, 0, 8)
|
||||||
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, height uint32, indexes []int32) error {
|
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, height uint32, indexes []int32) error {
|
||||||
for _, index := range indexes {
|
for _, index := range indexes {
|
||||||
|
|||||||
14
api/xpub.go
14
api/xpub.go
@ -233,17 +233,24 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option
|
|||||||
cachedXpubsMux.Lock()
|
cachedXpubsMux.Lock()
|
||||||
cachedXpubs[xpub] = data
|
cachedXpubs[xpub] = data
|
||||||
cachedXpubsMux.Unlock()
|
cachedXpubsMux.Unlock()
|
||||||
|
totalTokens := 0
|
||||||
tokens := make([]Token, 0, 4)
|
tokens := make([]Token, 0, 4)
|
||||||
for i := range data.addresses {
|
for i := range data.addresses {
|
||||||
ad := &data.addresses[i]
|
ad := &data.addresses[i]
|
||||||
if ad.balance != nil {
|
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 {
|
for i := range data.changeAddresses {
|
||||||
ad := &data.changeAddresses[i]
|
ad := &data.changeAddresses[i]
|
||||||
if ad.balance != nil {
|
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
|
var totalReceived big.Int
|
||||||
@ -259,7 +266,8 @@ func (w *Worker) GetAddressForXpub(xpub string, page int, txsOnPage int, option
|
|||||||
// UnconfirmedTxs: len(txm),
|
// UnconfirmedTxs: len(txm),
|
||||||
// Transactions: txs,
|
// Transactions: txs,
|
||||||
// Txids: txids,
|
// Txids: txids,
|
||||||
Tokens: tokens,
|
TotalTokens: totalTokens,
|
||||||
|
Tokens: tokens,
|
||||||
// Erc20Contract: erc20c,
|
// Erc20Contract: erc20c,
|
||||||
// Nonce: nonce,
|
// Nonce: nonce,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -405,6 +405,7 @@ type TemplateData struct {
|
|||||||
TOSLink string
|
TOSLink string
|
||||||
SendTxHex string
|
SendTxHex string
|
||||||
Status string
|
Status string
|
||||||
|
AllTokens bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublicServer) parseTemplates() []*template.Template {
|
func (s *PublicServer) parseTemplates() []*template.Template {
|
||||||
@ -582,36 +583,40 @@ func (s *PublicServer) explorerAddress(w http.ResponseWriter, r *http.Request) (
|
|||||||
return addressTpl, data, nil
|
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) {
|
func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
|
||||||
var address *api.Address
|
var address *api.Address
|
||||||
var filter string
|
|
||||||
var fn = api.AddressFilterVoutOff
|
|
||||||
var err error
|
var err error
|
||||||
s.metrics.ExplorerViews.With(common.Labels{"action": "xpub"}).Inc()
|
s.metrics.ExplorerViews.With(common.Labels{"action": "xpub"}).Inc()
|
||||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
|
address, err = s.getAddressForXpub(r, r.URL.Path[i+1:], txsOnPage, api.TxHistoryLight)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorTpl, nil, err
|
return errorTpl, nil, err
|
||||||
}
|
}
|
||||||
@ -621,10 +626,13 @@ func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl
|
|||||||
data.Address = address
|
data.Address = address
|
||||||
data.Page = address.Page
|
data.Page = address.Page
|
||||||
data.PagingRange, data.PrevPage, data.NextPage = getPagingRange(address.Page, address.TotalPages)
|
data.PagingRange, data.PrevPage, data.NextPage = getPagingRange(address.Page, address.TotalPages)
|
||||||
|
filter := r.URL.Query().Get("filter")
|
||||||
if filter != "" {
|
if filter != "" {
|
||||||
data.PageParams = template.URL("&filter=" + filter)
|
data.PageParams = template.URL("&filter=" + filter)
|
||||||
data.Address.Filter = filter
|
data.Address.Filter = filter
|
||||||
}
|
}
|
||||||
|
allAddresses := r.URL.Query().Get("alladdresses")
|
||||||
|
data.AllTokens, _ = strconv.ParseBool(allAddresses)
|
||||||
return xpubTpl, data, nil
|
return xpubTpl, data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,15 +887,7 @@ func (s *PublicServer) apiXpub(r *http.Request, apiVersion int) (interface{}, er
|
|||||||
var err error
|
var err error
|
||||||
s.metrics.ExplorerViews.With(common.Labels{"action": "api-xpub"}).Inc()
|
s.metrics.ExplorerViews.With(common.Labels{"action": "api-xpub"}).Inc()
|
||||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
|
address, err = s.getAddressForXpub(r, r.URL.Path[i+1:], txsInAPI, api.TxidHistory)
|
||||||
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)
|
|
||||||
if err == nil && apiVersion == apiV1 {
|
if err == nil && apiVersion == apiV1 {
|
||||||
return s.api.AddressToV1(address), nil
|
return s.api.AddressToV1(address), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,9 +25,13 @@
|
|||||||
<td>No. Transactions</td>
|
<td>No. Transactions</td>
|
||||||
<td class="data">{{$addr.Txs}}</td>
|
<td class="data">{{$addr.Txs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Total XPUB addresses</td>
|
||||||
|
<td class="data">{{$addr.TotalTokens}}</td>
|
||||||
|
</tr>
|
||||||
{{- if $addr.Tokens -}}
|
{{- if $addr.Tokens -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>XPUB addresses</td>
|
<td>{{if $data.AllTokens}}XPUB Addresses{{else}}Nonzero XPUB Addresses{{end}}</td>
|
||||||
<td style="padding: 0;">
|
<td style="padding: 0;">
|
||||||
<table class="table data-table">
|
<table class="table data-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -45,6 +49,11 @@
|
|||||||
<td class="data">{{$t.Contract}}</td>
|
<td class="data">{{$t.Contract}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
{{- if not $data.AllTokens -}}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><a href="?alladdresses=true">Show all XPUB addresses</a></td>
|
||||||
|
</tr>
|
||||||
|
{{- end -}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user