Add tokens to return level choice to websocket interface

pull/133/head
Martin Boehm 2019-03-01 15:25:16 +01:00
parent e54998dccc
commit 1c35c632cb
8 changed files with 54 additions and 40 deletions

View File

@ -204,8 +204,8 @@ type Paging struct {
ItemsOnPage int `json:"itemsOnPage,omitempty"`
}
// TokenDetailLevel specifies detail level of tokens returned by GetAddress and GetXpubAddress
type TokenDetailLevel int
// TokensToReturn specifies what tokens are returned by GetAddress and GetXpubAddress
type TokensToReturn int
const (
// AddressFilterVoutOff disables filtering of transactions by vout
@ -215,21 +215,21 @@ const (
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
AddressFilterVoutOutputs = -3
// TokenDetailNonzeroBalance - use to return only tokens with nonzero balance
TokenDetailNonzeroBalance TokenDetailLevel = 0
// TokenDetailUsed - use to return tokens with some transfers (even if they have zero balance now)
TokenDetailUsed TokenDetailLevel = 1
// TokenDetailDiscovered - use to return all discovered tokens
TokenDetailDiscovered TokenDetailLevel = 2
// TokensToReturnNonzeroBalance - return only tokens with nonzero balance
TokensToReturnNonzeroBalance TokensToReturn = 0
// TokensToReturnUsed - return tokens with some transfers (even if they have zero balance now)
TokensToReturnUsed TokensToReturn = 1
// TokensToReturnDerived - return all derived tokens
TokensToReturnDerived TokensToReturn = 2
)
// AddressFilter is used to filter data returned from GetAddress api method
type AddressFilter struct {
Vout int
Contract string
FromHeight uint32
ToHeight uint32
TokenLevel TokenDetailLevel
Vout int
Contract string
FromHeight uint32
ToHeight uint32
TokensToReturn TokensToReturn
// OnlyConfirmed set to true will ignore mempool transactions; mempool is also ignored if FromHeight/ToHeight filter is specified
OnlyConfirmed bool
}

View File

@ -906,6 +906,9 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) (Utxos, erro
return nil, NewAPIError(fmt.Sprintf("Invalid address '%v', %v", address, err), true)
}
r, err := w.getAddrDescUtxo(addrDesc, nil, onlyConfirmed, false)
if err != nil {
return nil, err
}
glog.Info("GetAddressUtxo ", address, ", ", len(r), " utxos, finished in ", time.Since(start))
return r, nil
}

View File

@ -502,9 +502,9 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
}
if option > AccountDetailsBasic {
token := w.tokenFromXpubAddress(data, ad, ci, i, option)
if filter.TokenLevel == TokenDetailDiscovered ||
filter.TokenLevel == TokenDetailUsed && ad.balance != nil ||
filter.TokenLevel == TokenDetailNonzeroBalance && ad.balance != nil && !IsZeroBigInt(&ad.balance.BalanceSat) {
if filter.TokensToReturn == TokensToReturnDerived ||
filter.TokensToReturn == TokensToReturnUsed && ad.balance != nil ||
filter.TokensToReturn == TokensToReturnNonzeroBalance && ad.balance != nil && !IsZeroBigInt(&ad.balance.BalanceSat) {
tokens = append(tokens, token)
}
xpubAddresses[token.Name] = struct{}{}

View File

@ -607,7 +607,7 @@ func (s *PublicServer) explorerAddress(w http.ResponseWriter, r *http.Request) (
return addressTpl, data, nil
}
func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int, option api.AccountDetails) (*api.Address, api.TokenDetailLevel, error) {
func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int, option api.AccountDetails) (*api.Address, api.TokensToReturn, error) {
var fn = api.AddressFilterVoutOff
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
if ec != nil {
@ -622,7 +622,6 @@ func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int
} else {
fn, ec = strconv.Atoi(filter)
if ec != nil || fn < 0 {
filter = ""
fn = api.AddressFilterVoutOff
}
}
@ -631,26 +630,26 @@ func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int
if ec != nil {
gap = 0
}
tokenLevel := api.TokenDetailNonzeroBalance
switch r.URL.Query().Get("tokenlevel") {
case "discovered":
tokenLevel = api.TokenDetailDiscovered
tokensToReturn := api.TokensToReturnNonzeroBalance
switch r.URL.Query().Get("tokens") {
case "derived":
tokensToReturn = api.TokensToReturnDerived
case "used":
tokenLevel = api.TokenDetailUsed
tokensToReturn = api.TokensToReturnUsed
case "nonzero":
tokenLevel = api.TokenDetailNonzeroBalance
tokensToReturn = api.TokensToReturnNonzeroBalance
}
a, err := s.api.GetXpubAddress(xpub, page, pageSize, option, &api.AddressFilter{Vout: fn, TokenLevel: tokenLevel}, gap)
return a, tokenLevel, err
a, err := s.api.GetXpubAddress(xpub, page, pageSize, option, &api.AddressFilter{Vout: fn, TokensToReturn: tokensToReturn}, gap)
return a, tokensToReturn, err
}
func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
var address *api.Address
var tokenLevel api.TokenDetailLevel
var tokensToReturn api.TokensToReturn
var err error
s.metrics.ExplorerViews.With(common.Labels{"action": "xpub"}).Inc()
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
address, tokenLevel, err = s.getXpubAddress(r, r.URL.Path[i+1:], txsOnPage, api.AccountDetailsTxHistoryLight)
address, tokensToReturn, err = s.getXpubAddress(r, r.URL.Path[i+1:], txsOnPage, api.AccountDetailsTxHistoryLight)
if err != nil {
return errorTpl, nil, err
}
@ -665,7 +664,7 @@ func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl
data.PageParams = template.URL("&filter=" + filter)
data.Address.Filter = filter
}
data.NonZeroBalanceTokens = tokenLevel == api.TokenDetailNonzeroBalance
data.NonZeroBalanceTokens = tokensToReturn == api.TokensToReturnNonzeroBalance
return xpubTpl, data, nil
}

View File

@ -461,7 +461,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
},
},
{
name: "apiXpub v2 tokenlevel=nonzero",
name: "apiXpub v2 tokens=nonzero",
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub),
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
@ -470,8 +470,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
},
},
{
name: "apiXpub v2 tokenlevel=used",
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokenlevel=used"),
name: "apiXpub v2 tokens=used",
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokens=used"),
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
@ -479,8 +479,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
},
},
{
name: "apiXpub v2 tokenlevel=discovered",
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokenlevel=discovered"),
name: "apiXpub v2 tokens=derived",
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokens=derived"),
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{

View File

@ -330,6 +330,7 @@ func (s *WebsocketServer) onRequest(c *websocketChannel, req *websocketReq) {
type accountInfoReq struct {
Descriptor string `json:"descriptor"`
Details string `json:"details"`
Tokens string `json:"tokens"`
PageSize int `json:"pageSize"`
Page int `json:"page"`
FromHeight int `json:"from"`
@ -360,12 +361,21 @@ func (s *WebsocketServer) getAccountInfo(req *accountInfoReq) (res *api.Address,
default:
opt = api.AccountDetailsBasic
}
var tokensToReturn api.TokensToReturn
switch req.Tokens {
case "used":
tokensToReturn = api.TokensToReturnUsed
case "nonzero":
tokensToReturn = api.TokensToReturnNonzeroBalance
default:
tokensToReturn = api.TokensToReturnDerived
}
filter := api.AddressFilter{
FromHeight: uint32(req.FromHeight),
ToHeight: uint32(req.ToHeight),
Contract: req.ContractFilter,
Vout: api.AddressFilterVoutOff,
TokenLevel: api.TokenDetailDiscovered,
FromHeight: uint32(req.FromHeight),
ToHeight: uint32(req.ToHeight),
Contract: req.ContractFilter,
Vout: api.AddressFilterVoutOff,
TokensToReturn: tokensToReturn,
}
a, err := s.api.GetXpubAddress(req.Descriptor, req.Page, req.PageSize, opt, &filter, 0)
if err != nil {

View File

@ -51,7 +51,7 @@
{{- end -}}
{{- if $data.NonZeroBalanceTokens -}}
<tr>
<td colspan="4"><a href="?tokenlevel=used">Show all XPUB addresses</a></td>
<td colspan="4"><a href="?tokens=used">Show all XPUB addresses</a></td>
</tr>
{{- end -}}
</tbody>

View File

@ -125,9 +125,11 @@
const contractFilter = document.getElementById("getAccountInfoContract").value.trim();
const pageSize = 10;
const method = 'getAccountInfo';
const tokens = "derived"; // could be "nonzero", "used", default is "derived" i.e. all
const params = {
descriptor,
details,
tokens,
page,
pageSize,
from,