Show valid address with zero transaction in explorer #82

pull/85/head
Martin Boehm 2018-11-05 11:26:23 +01:00
parent 7d28b710e3
commit 2dca694f95
4 changed files with 42 additions and 25 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/gobuffalo/packr"
)
// Text contains static overridable texts used in explorer
var Text struct {
BlockbookAbout, TOSLink string
}

View File

@ -8,27 +8,31 @@ import (
"time"
)
type ApiError struct {
// APIError extends error by information if the error details should be returned to the end user
type APIError struct {
Text string
Public bool
}
func (e *ApiError) Error() string {
func (e *APIError) Error() string {
return e.Text
}
func NewApiError(s string, public bool) error {
return &ApiError{
// NewAPIError creates ApiError
func NewAPIError(s string, public bool) error {
return &APIError{
Text: s,
Public: public,
}
}
// ScriptSig contains input script
type ScriptSig struct {
Hex string `json:"hex"`
Asm string `json:"asm,omitempty"`
}
// Vin contains information about single transaction input
type Vin struct {
Txid string `json:"txid"`
Vout uint32 `json:"vout"`
@ -42,6 +46,7 @@ type Vin struct {
ValueSat big.Int `json:"-"`
}
// ScriptPubKey contains output script and addresses derived from it
type ScriptPubKey struct {
Hex string `json:"hex"`
Asm string `json:"asm,omitempty"`
@ -50,6 +55,8 @@ type ScriptPubKey struct {
Searchable bool `json:"-"`
Type string `json:"type,omitempty"`
}
// Vout contains information about single transaction output
type Vout struct {
Value string `json:"value"`
ValueSat big.Int `json:"-"`
@ -61,6 +68,7 @@ type Vout struct {
SpentHeight int `json:"spentHeight,omitempty"`
}
// Tx holds information about a transaction
type Tx struct {
Txid string `json:"txid"`
Version int32 `json:"version,omitempty"`
@ -82,12 +90,14 @@ type Tx struct {
Hex string `json:"hex"`
}
// Paging contains information about paging for address, blocks and block
type Paging struct {
Page int `json:"page"`
TotalPages int `json:"totalPages"`
ItemsOnPage int `json:"itemsOnPage"`
}
// Address holds information about address and its transactions
type Address struct {
Paging
AddrStr string `json:"addrStr"`
@ -101,11 +111,13 @@ type Address struct {
Txids []string `json:"transactions,omitempty"`
}
// Blocks is list of blocks with paging information
type Blocks struct {
Paging
Blocks []db.BlockInfo `json:"blocks"`
}
// Block contains information about block
type Block struct {
Paging
bchain.BlockInfo
@ -113,6 +125,7 @@ type Block struct {
Transactions []*Tx `json:"txs,omitempty"`
}
// BlockbookInfo contains information about the running blockbook instance
type BlockbookInfo struct {
Coin string `json:"coin"`
Host string `json:"host"`
@ -133,6 +146,7 @@ type BlockbookInfo struct {
About string `json:"about"`
}
// SystemInfo contains information about the running blockbook and backend instance
type SystemInfo struct {
Blockbook *BlockbookInfo `json:"blockbook"`
Backend *bchain.ChainInfo `json:"backend"`

View File

@ -85,7 +85,7 @@ func (w *Worker) GetSpendingTxid(txid string, n int) (string, error) {
return "", err
}
if n >= len(tx.Vout) || n < 0 {
return "", NewApiError(fmt.Sprintf("Passed incorrect vout index %v for tx %v, len vout %v", n, tx.Txid, len(tx.Vout)), false)
return "", NewAPIError(fmt.Sprintf("Passed incorrect vout index %v for tx %v, len vout %v", n, tx.Txid, len(tx.Vout)), false)
}
err = w.setSpendingTxToVout(&tx.Vout[n], tx.Txid, uint32(tx.Blockheight))
if err != nil {
@ -100,7 +100,7 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool) (*Tx, error) {
start := time.Now()
bchainTx, height, err := w.txCache.GetTransaction(txid)
if err != nil {
return nil, NewApiError(fmt.Sprintf("Tx not found, %v", err), true)
return nil, NewAPIError(fmt.Sprintf("Tx not found, %v", err), true)
}
ta, err := w.db.GetTxAddresses(txid)
if err != nil {
@ -357,12 +357,12 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
}
addrDesc, err := w.chainParser.GetAddrDescFromAddress(address)
if err != nil {
return nil, NewApiError(fmt.Sprintf("Address not found, %v", err), true)
return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true)
}
// ba can be nil if the address is only in mempool!
ba, err := w.db.GetAddrDescBalance(addrDesc)
if err != nil {
return nil, NewApiError(fmt.Sprintf("Address not found, %v", err), true)
return nil, NewAPIError(fmt.Sprintf("Address not found, %v", err), true)
}
// convert the address to the format defined by the parser
addresses, _, err := w.chainParser.GetAddressesFromAddrDesc(addrDesc)
@ -390,7 +390,9 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, onlyTxids b
txm = UniqueTxidsInReverse(txm)
// check if the address exist
if len(txc)+len(txm) == 0 {
return nil, NewApiError("Address not found", true)
return &Address{
AddrStr: address,
}, nil
}
bestheight, _, err := w.db.GetBestBlock()
if err != nil {
@ -526,9 +528,9 @@ func (w *Worker) GetBlock(bid string, page int, txsOnPage int) (*Block, error) {
bi, err := w.chain.GetBlockInfo(hash)
if err != nil {
if err == bchain.ErrBlockNotFound {
return nil, NewApiError("Block not found", true)
return nil, NewAPIError("Block not found", true)
}
return nil, NewApiError(fmt.Sprintf("Block not found, %v", err), true)
return nil, NewAPIError(fmt.Sprintf("Block not found, %v", err), true)
}
dbi := &db.BlockInfo{
Hash: bi.Hash,

View File

@ -215,7 +215,7 @@ func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, e
}()
data, err = handler(r)
if err != nil || data == nil {
if apiErr, ok := err.(*api.ApiError); ok {
if apiErr, ok := err.(*api.APIError); ok {
if apiErr.Public {
data = jsonError{apiErr.Error(), http.StatusBadRequest}
} else {
@ -251,7 +251,7 @@ func (s *PublicServer) newTemplateData() *TemplateData {
func (s *PublicServer) newTemplateDataWithError(text string) *TemplateData {
td := s.newTemplateData()
td.Error = &api.ApiError{Text: text}
td.Error = &api.APIError{Text: text}
return td
}
@ -290,7 +290,7 @@ func (s *PublicServer) htmlTemplateHandler(handler func(w http.ResponseWriter, r
t, data, err = handler(w, r)
if err != nil || (data == nil && t != noTpl) {
t = errorInternalTpl
if apiErr, ok := err.(*api.ApiError); ok {
if apiErr, ok := err.(*api.APIError); ok {
data = s.newTemplateData()
data.Error = apiErr
if apiErr.Public {
@ -336,7 +336,7 @@ type TemplateData struct {
AddrStr string
Tx *api.Tx
TxSpecific json.RawMessage
Error *api.ApiError
Error *api.APIError
Blocks *api.Blocks
Block *api.Block
Info *api.SystemInfo
@ -427,7 +427,7 @@ func (s *PublicServer) explorerSpendingTx(w http.ResponseWriter, r *http.Request
}
}
if err == nil {
err = api.NewApiError("Transaction not found", true)
err = api.NewAPIError("Transaction not found", true)
}
return errorTpl, nil, err
}
@ -531,7 +531,7 @@ func (s *PublicServer) explorerSearch(w http.ResponseWriter, r *http.Request) (t
return noTpl, nil, nil
}
}
return errorTpl, nil, api.NewApiError(fmt.Sprintf("No matching records found for '%v'", q), true)
return errorTpl, nil, api.NewAPIError(fmt.Sprintf("No matching records found for '%v'", q), true)
}
func (s *PublicServer) explorerSendTx(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
@ -547,7 +547,7 @@ func (s *PublicServer) explorerSendTx(w http.ResponseWriter, r *http.Request) (t
res, err := s.chain.SendRawTransaction(hex)
if err != nil {
data.SendTxHex = hex
data.Error = &api.ApiError{Text: err.Error(), Public: true}
data.Error = &api.APIError{Text: err.Error(), Public: true}
return sendTransactionTpl, data, nil
}
data.Status = "Transaction sent, result " + res
@ -652,7 +652,7 @@ func (s *PublicServer) apiTx(r *http.Request) (interface{}, error) {
if len(p) > 0 {
spendingTxs, err = strconv.ParseBool(p)
if err != nil {
return nil, api.NewApiError("Parameter 'spending' cannot be converted to boolean", true)
return nil, api.NewAPIError("Parameter 'spending' cannot be converted to boolean", true)
}
}
tx, err = s.api.GetTransaction(txid, spendingTxs)
@ -711,7 +711,7 @@ func (s *PublicServer) apiSendTx(r *http.Request) (interface{}, error) {
if r.Method == http.MethodPost {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, api.NewApiError("Missing tx blob", true)
return nil, api.NewAPIError("Missing tx blob", true)
}
hex = string(data)
} else {
@ -722,11 +722,11 @@ func (s *PublicServer) apiSendTx(r *http.Request) (interface{}, error) {
if len(hex) > 0 {
res.Result, err = s.chain.SendRawTransaction(hex)
if err != nil {
return nil, api.NewApiError(err.Error(), true)
return nil, api.NewAPIError(err.Error(), true)
}
return res, nil
}
return nil, api.NewApiError("Missing tx blob", true)
return nil, api.NewAPIError("Missing tx blob", true)
}
type resultEstimateFeeAsString struct {
@ -741,14 +741,14 @@ func (s *PublicServer) apiEstimateFee(r *http.Request) (interface{}, error) {
if len(b) > 0 {
blocks, err := strconv.Atoi(b)
if err != nil {
return nil, api.NewApiError("Parameter 'number of blocks' is not a number", true)
return nil, api.NewAPIError("Parameter 'number of blocks' is not a number", true)
}
conservative := true
c := r.URL.Query().Get("conservative")
if len(c) > 0 {
conservative, err = strconv.ParseBool(c)
if err != nil {
return nil, api.NewApiError("Parameter 'conservative' cannot be converted to boolean", true)
return nil, api.NewAPIError("Parameter 'conservative' cannot be converted to boolean", true)
}
}
var fee big.Int
@ -763,5 +763,5 @@ func (s *PublicServer) apiEstimateFee(r *http.Request) (interface{}, error) {
return res, nil
}
}
return nil, api.NewApiError("Missing parameter 'number of blocks'", true)
return nil, api.NewAPIError("Missing parameter 'number of blocks'", true)
}