diff --git a/api/text.go b/api/text.go index 6892c35c..a4e51c0f 100644 --- a/api/text.go +++ b/api/text.go @@ -8,6 +8,7 @@ import ( "github.com/gobuffalo/packr" ) +// Text contains static overridable texts used in explorer var Text struct { BlockbookAbout, TOSLink string } diff --git a/api/types.go b/api/types.go index 51109371..8a535f24 100644 --- a/api/types.go +++ b/api/types.go @@ -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"` diff --git a/api/worker.go b/api/worker.go index 23668309..f7572058 100644 --- a/api/worker.go +++ b/api/worker.go @@ -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, diff --git a/server/public.go b/server/public.go index 1996240b..e581d81f 100644 --- a/server/public.go +++ b/server/public.go @@ -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) }