Skip to content

Commit

Permalink
Created new node HTTP API route: GET /alias/by-alias/{alias}
Browse files Browse the repository at this point in the history
  • Loading branch information
nickeskov committed Jul 2, 2021
1 parent 31f6b7b commit 98429c5
Show file tree
Hide file tree
Showing 14 changed files with 227 additions and 37 deletions.
6 changes: 5 additions & 1 deletion cmd/custom/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,12 @@ func main() {
}
}

apiConfig := api.AppConfig{
BlockchainType: "",
BuildVersion: buildVersion,
}
// TODO hardcore
app, err := api.NewApp("integration-test-rest-api", scheduler, nodeServices, buildVersion)
app, err := api.NewApp("integration-test-rest-api", scheduler, nodeServices, apiConfig)
if err != nil {
zap.S().Error(err)
cancel()
Expand Down
7 changes: 6 additions & 1 deletion cmd/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,12 @@ func main() {
}
}

app, err := api.NewApp(*apiKey, minerScheduler, svs, buildVersion)
apiConfig := api.AppConfig{
BlockchainType: *blockchainType,
BuildVersion: buildVersion,
}

app, err := api.NewApp(*apiKey, minerScheduler, svs, apiConfig)
if err != nil {
zap.S().Error(err)
cancel()
Expand Down
24 changes: 19 additions & 5 deletions pkg/api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,24 @@ type App struct {
peers peer_manager.PeerManager
sync types.StateSync
services services.Services
buildVersion string
config AppConfig
}

func NewApp(apiKey string, scheduler SchedulerEmits, services services.Services, buildVersion string) (*App, error) {
type AppConfig struct {
BlockchainType string
BuildVersion string
}

func (ac *AppConfig) Validate() error {
// TODO(nickeskov): implement me
return nil
}

func NewApp(apiKey string, scheduler SchedulerEmits, services services.Services, config AppConfig) (*App, error) {
if err := config.Validate(); err != nil {
return nil, err
}

digest, err := crypto.SecureHash([]byte(apiKey))
if err != nil {
return nil, err
Expand All @@ -52,12 +66,12 @@ func NewApp(apiKey string, scheduler SchedulerEmits, services services.Services,
utx: services.UtxPool,
peers: services.Peers,
services: services,
buildVersion: buildVersion,
config: config,
}, nil
}

func (a *App) BuildVersion() string {
return a.buildVersion
func (a *App) Config() *AppConfig {
return &a.config
}

func (a *App) TransactionsBroadcast(ctx context.Context, b []byte) error {
Expand Down
18 changes: 18 additions & 0 deletions pkg/api/app_alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package api

import (
"github.com/pkg/errors"
"github.com/wavesplatform/gowaves/pkg/proto"
"github.com/wavesplatform/gowaves/pkg/state"
)

func (a *App) AddrByAlias(alias proto.Alias) (proto.Address, error) {
addr, err := a.state.AddrByAlias(alias)
if err != nil {
if state.IsNotFound(err) {
return proto.Address{}, err
}
return proto.Address{}, errors.Wrapf(err, "failed to find addr by alias %q", alias.String())
}
return addr, nil
}
4 changes: 2 additions & 2 deletions pkg/api/app_blocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestApp_BlocksFirst(t *testing.T) {
s := mock.NewMockState(ctrl)
s.EXPECT().BlockByHeight(proto.Height(1)).Return(g, nil)

app, err := NewApp("api-key", nil, services.Services{State: s}, "")
app, err := NewApp("api-key", nil, services.Services{State: s}, AppConfig{})
require.NoError(t, err)
first, err := app.BlocksFirst()
require.NoError(t, err)
Expand All @@ -40,7 +40,7 @@ func TestApp_BlocksLast(t *testing.T) {
s.EXPECT().Height().Return(proto.Height(1), nil)
s.EXPECT().BlockByHeight(proto.Height(1)).Return(g, nil)

app, err := NewApp("api-key", nil, services.Services{State: s}, "")
app, err := NewApp("api-key", nil, services.Services{State: s}, AppConfig{})
require.NoError(t, err)
first, err := app.BlocksLast()
require.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/app_peers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestApp_PeersKnown(t *testing.T) {
addr := proto.NewTCPAddr(net.ParseIP("127.0.0.1"), 6868).ToIpPort()
peerManager.EXPECT().KnownPeers().Return([]storage.KnownPeer{storage.KnownPeer(addr)})

app, err := NewApp("key", nil, services.Services{Peers: peerManager}, "")
app, err := NewApp("key", nil, services.Services{Peers: peerManager}, AppConfig{})
require.NoError(t, err)

rs2, err := app.PeersKnown()
Expand Down Expand Up @@ -56,7 +56,7 @@ func TestApp_PeersSuspended(t *testing.T) {

peerManager.EXPECT().Suspended().Return(testData)

app, err := NewApp("key", nil, services.Services{Peers: peerManager}, "")
app, err := NewApp("key", nil, services.Services{Peers: peerManager}, AppConfig{})
require.NoError(t, err)

suspended := app.PeersSuspended()
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func TestAppAuth(t *testing.T) {
app, _ := NewApp("apiKey", nil, services.Services{}, "")
app, _ := NewApp("apiKey", nil, services.Services{}, AppConfig{})
require.Error(t, app.checkAuth("bla"))
require.NoError(t, app.checkAuth("apiKey"))
}
21 changes: 21 additions & 0 deletions pkg/api/errors/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package errors

import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"net/http"
)
Expand Down Expand Up @@ -152,3 +153,23 @@ var (
},
}
)

func NewCustomValidationError(msg string) *CustomValidationError {
return &CustomValidationError{
genericError: genericError{
ID: CustomValidationErrorErrorID,
HttpCode: http.StatusBadRequest,
Message: msg,
},
}
}

func NewAliasDoesNotExistError(aliasFull string) *AliasDoesNotExistError {
return &AliasDoesNotExistError{
genericError: genericError{
ID: AliasDoesNotExistErrorID,
HttpCode: http.StatusNotFound,
Message: fmt.Sprintf("alias '%s' doesn't exist", aliasFull),
},
}
}
25 changes: 24 additions & 1 deletion pkg/api/helpers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package api

import "time"
import (
"encoding/json"
"github.com/pkg/errors"
"io"
"time"
)

func unixMillis(t time.Time) int64 {
return t.UnixNano() / 1_000_000
Expand All @@ -11,3 +16,21 @@ func fromUnixMillis(timestampMillis int64) time.Time {
nsec := (timestampMillis % 1_000) * 1_000_000
return time.Unix(sec, nsec)
}

// tryParseJson receives reader and out params. out MUST be a pointer
func tryParseJson(r io.Reader, out interface{}) error {
// TODO(nickeskov): check empty reader
err := json.NewDecoder(r).Decode(out)
if err != nil {
return errors.Wrapf(err, "Failed to unmarshal %T as JSON into %T", r, out)
}
return nil
}

func trySendJson(w io.Writer, v interface{}) error {
err := json.NewEncoder(w).Encode(v)
if err != nil {
return errors.Wrapf(err, "Failed to marshal %T to JSON and write it to %T", v, w)
}
return nil
}
54 changes: 34 additions & 20 deletions pkg/api/node_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
Expand Down Expand Up @@ -472,7 +471,7 @@ func (a *NodeApi) BuildVersion(w http.ResponseWriter, _ *http.Request) error {
Version string `json:"version"`
}

buildVersion := a.app.BuildVersion()
buildVersion := a.app.Config().BuildVersion

out := ver{Version: fmt.Sprintf("GoWaves %s", buildVersion)}
if err := trySendJson(w, out); err != nil {
Expand All @@ -481,6 +480,39 @@ func (a *NodeApi) BuildVersion(w http.ResponseWriter, _ *http.Request) error {
return nil
}

func (a *NodeApi) AddrByAlias(w http.ResponseWriter, r *http.Request) error {
type addrResponse struct {
Address string `json:"address"`
}

// nickeskov: alias as plain text without an 'alias' prefix and chain ID (scheme)
aliasShort := chi.URLParam(r, "alias")

chainID := proto.SchemeFromString(a.app.Config().BlockchainType)

alias := proto.NewAlias(chainID, aliasShort)
if _, err := alias.Valid(); err != nil {
// TODO(nickeskov): check that error msg looks like in scala
msg := err.Error()
return apiErrs.NewCustomValidationError(msg)
}

addr, err := a.app.AddrByAlias(*alias)
if err != nil {
origErr := errors.Cause(err)
if state.IsNotFound(origErr) {
return apiErrs.NewAliasDoesNotExistError(alias.String())
}
return errors.Wrapf(err, "failed to find addr by short alias %q", aliasShort)
}

resp := addrResponse{Address: addr.String()}
if err := trySendJson(w, resp); err != nil {
return errors.Wrap(err, "AddrByAlias")
}
return nil
}

func (a *NodeApi) nodeProcesses(w http.ResponseWriter, _ *http.Request) error {
rs := a.app.NodeProcesses()
if err := trySendJson(w, rs); err != nil {
Expand Down Expand Up @@ -548,21 +580,3 @@ func (a *NodeApi) walletSeed(w http.ResponseWriter, _ *http.Request) error {
}
return nil
}

// tryParseJson receives reader and out params. out MUST be a pointer
func tryParseJson(r io.Reader, out interface{}) error {
// TODO(nickeskov): check empty reader
err := json.NewDecoder(r).Decode(out)
if err != nil {
return errors.Wrapf(err, "Failed to unmarshal %T as JSON into %T", r, out)
}
return nil
}

func trySendJson(w io.Writer, v interface{}) error {
err := json.NewEncoder(w).Encode(v)
if err != nil {
return errors.Wrapf(err, "Failed to marshal %T to JSON and write it to %T", v, w)
}
return nil
}
35 changes: 35 additions & 0 deletions pkg/api/node_api_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package api

import (
"context"
"github.com/go-chi/chi"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"github.com/wavesplatform/gowaves/pkg/mock"
"net/http"
"net/http/httptest"
"strings"
"testing"
Expand Down Expand Up @@ -79,3 +85,32 @@ func TestNodeApi_FindFirstInvalidRuneInBase58String(t *testing.T) {
actual := findFirstInvalidRuneInBase58String("42354")
assert.Nil(t, actual)
}

func TestNodeApi_AddrByAlias(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

testAlias := "some_alias"

req := httptest.NewRequest(http.MethodGet, "/", nil)
resp := httptest.NewRecorder()

stateMock := mock.NewMockState(ctrl)
stateMock.EXPECT().
AddrByAlias(*proto.NewAlias(proto.TestNetScheme, testAlias)).
Return(proto.Address{}, nil)

api := NodeApi{
app: &App{
state: stateMock,
config: AppConfig{BlockchainType: "testnet"},
},
}

rctx := chi.NewRouteContext()
rctx.URLParams.Add("alias", testAlias)
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))

err := api.AddrByAlias(resp, req)
require.NoError(t, err)
}
4 changes: 4 additions & 0 deletions pkg/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (a *NodeApi) routes(opts *RunOptions) (chi.Router, error) {
r.Get("/", wrapper(a.Addresses))
})

r.Route("/alias", func(r chi.Router) {
r.Get("/by-alias/{alias}", wrapper(a.AddrByAlias))
})

r.Route("/transactions", func(r chi.Router) {
r.Get("/unconfirmed/size", wrapper(a.unconfirmedSize))

Expand Down
34 changes: 30 additions & 4 deletions pkg/proto/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ const (
AliasAlphabet = "-.0123456789@_abcdefghijklmnopqrstuvwxyz"
AliasPrefix = "alias"

MainNetScheme byte = 'W'
TestNetScheme byte = 'T'
StageNetScheme byte = 'S'
CustomNetScheme byte = 'E'
MainNetScheme Scheme = 'W'
TestNetScheme Scheme = 'T'
StageNetScheme Scheme = 'S'
CustomNetScheme Scheme = 'E'
)

// Address is the transformed Public Key with additional bytes of the version, a blockchain scheme and a checksum.
Expand Down Expand Up @@ -531,3 +531,29 @@ func (r *Recipient) String() string {
}
return r.Address.String()
}

// SchemeFromString returns Scheme from string representation (short or full).
func SchemeFromString(scheme string) Scheme {
switch len(scheme) {
case 0:
return CustomNetScheme
case 1:
switch b := scheme[0]; b {
case MainNetScheme, StageNetScheme, TestNetScheme:
return b
default:
return CustomNetScheme
}
default:
switch scheme {
case "mainnet":
return MainNetScheme
case "stagenet":
return StageNetScheme
case "testnet":
return TestNetScheme
default:
return CustomNetScheme
}
}
}
Loading

0 comments on commit 98429c5

Please sign in to comment.