From 8b9a3ea6c396cdd20998333b6d14ee971c00c1d7 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Fri, 11 Sep 2020 20:01:37 -0700 Subject: [PATCH 1/3] implement initial lotus-gateway program --- cmd/lotus-gateway/api.go | 52 ++++++++++++++++++ cmd/lotus-gateway/main.go | 112 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 cmd/lotus-gateway/api.go create mode 100644 cmd/lotus-gateway/main.go diff --git a/cmd/lotus-gateway/api.go b/cmd/lotus-gateway/api.go new file mode 100644 index 000000000..06c9a3ae5 --- /dev/null +++ b/cmd/lotus-gateway/api.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "fmt" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + + "go.opencensus.io/trace" +) + +const LookbackCap = time.Hour + +var ( + ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap) +) + +type GatewayAPI struct { + api api.FullNode +} + +func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey) (time.Time, error) { + if tsk.IsEmpty() { + return time.Now(), nil + } + + ts, err := a.api.ChainGetTipSet(ctx, tsk) + if err != nil { + return time.Time{}, err + } + + return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil +} + +func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) { + ctx, span := trace.StartSpan(ctx, "StateGetActor") + defer span.End() + + when, err := a.getTipsetTimestamp(ctx, ts) + if err != nil { + return nil, err + } + + if time.Since(when) > time.Hour { + return nil, ErrLookbackTooLong + } + + return a.api.StateGetActor(ctx, actor, ts) +} diff --git a/cmd/lotus-gateway/main.go b/cmd/lotus-gateway/main.go new file mode 100644 index 000000000..7adf5dd8c --- /dev/null +++ b/cmd/lotus-gateway/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "context" + "net" + "net/http" + "os" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/lotuslog" + logging "github.com/ipfs/go-log" + + "github.com/gorilla/mux" + "github.com/urfave/cli/v2" +) + +var log = logging.Logger("gateway") + +func main() { + lotuslog.SetupLogLevels() + + local := []*cli.Command{ + runCmd, + } + + app := &cli.App{ + Name: "lotus-gateway", + Usage: "Public API server for lotus", + Version: build.UserVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, + + Commands: local, + } + app.Setup() + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + return + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start api server", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "listen", + Usage: "host address and port the api server will listen on", + Value: "0.0.0.0:1777", + }, + }, + Action: func(cctx *cli.Context) error { + log.Info("Starting lotus wallet") + + ctx := lcli.ReqContext(cctx) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + address := cctx.String("listen") + mux := mux.NewRouter() + + log.Info("Setting up API endpoint at " + address) + + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", &GatewayAPI{api: api}) + + mux.Handle("/rpc/v0", rpcServer) + mux.PathPrefix("/").Handler(http.DefaultServeMux) + + /*ah := &auth.Handler{ + Verify: nodeApi.AuthVerify, + Next: mux.ServeHTTP, + }*/ + + srv := &http.Server{ + Handler: mux, + BaseContext: func(listener net.Listener) context.Context { + return ctx + }, + } + + go func() { + <-ctx.Done() + log.Warn("Shutting down...") + if err := srv.Shutdown(context.TODO()); err != nil { + log.Errorf("shutting down RPC server failed: %s", err) + } + log.Warn("Graceful shutdown successful") + }() + + nl, err := net.Listen("tcp", address) + if err != nil { + return err + } + + return srv.Serve(nl) + }, +} From 3401cb349b88c39ebf87a95151928c885b8cdf7e Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Fri, 11 Sep 2020 23:07:20 -0700 Subject: [PATCH 2/3] add mpool push and chainHead --- cmd/lotus-gateway/api.go | 52 ++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/cmd/lotus-gateway/api.go b/cmd/lotus-gateway/api.go index 06c9a3ae5..42e9e4829 100644 --- a/cmd/lotus-gateway/api.go +++ b/cmd/lotus-gateway/api.go @@ -8,6 +8,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" "go.opencensus.io/trace" ) @@ -35,18 +36,55 @@ func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil } +func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error { + when, err := a.getTipsetTimestamp(ctx, ts) + if err != nil { + return err + } + + if time.Since(when) > time.Hour { + return ErrLookbackTooLong + } + + return nil +} + func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) { ctx, span := trace.StartSpan(ctx, "StateGetActor") defer span.End() - when, err := a.getTipsetTimestamp(ctx, ts) - if err != nil { - return nil, err - } - - if time.Since(when) > time.Hour { - return nil, ErrLookbackTooLong + if err := a.checkTipset(ctx, ts); err != nil { + return nil, fmt.Errorf("bad tipset: %w", err) } return a.api.StateGetActor(ctx, actor, ts) } + +func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) { + ctx, span := trace.StartSpan(ctx, "ChainHead") + defer span.End() + // TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify) + + return a.api.ChainHead(ctx) +} + +func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { + ctx, span := trace.StartSpan(ctx, "ChainGetTipSet") + defer span.End() + + if err := a.checkTipset(ctx, tsk); err != nil { + return nil, fmt.Errorf("bad tipset: %w", err) + } + + // TODO: since we're limiting lookbacks, should just cache this (could really even cache the json response bytes) + return a.api.ChainGetTipSet(ctx, tsk) +} + +func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) { + ctx, span := trace.StartSpan(ctx, "MpoolPush") + defer span.End() + + // TODO: additional anti-spam checks + + return a.api.MpoolPush(ctx, sm) +} From 285fc69f6a3f00979cb3041bce63ac4af0041a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 15 Sep 2020 11:45:03 +0200 Subject: [PATCH 3/3] gateway: address review --- .gitignore | 1 + Makefile | 6 ++++++ cmd/lotus-gateway/main.go | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0424c1f24..940f37b3f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /lotus-fountain /lotus-stats /lotus-bench +/lotus-gateway /bench.json /lotuspond/front/node_modules /lotuspond/front/build diff --git a/Makefile b/Makefile index 4f6ece417..56ab361ec 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,12 @@ lotus-shed: $(BUILD_DEPS) .PHONY: lotus-shed BINS+=lotus-shed +lotus-gateway: $(BUILD_DEPS) + rm -f lotus-gateway + go build $(GOFLAGS) -o lotus-gateway ./cmd/lotus-gateway +.PHONY: lotus-gateway +BINS+=lotus-gateway + build: lotus lotus-miner lotus-worker @[[ $$(type -P "lotus") ]] && echo "Caution: you have \ an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true diff --git a/cmd/lotus-gateway/main.go b/cmd/lotus-gateway/main.go index 7adf5dd8c..c19599084 100644 --- a/cmd/lotus-gateway/main.go +++ b/cmd/lotus-gateway/main.go @@ -54,11 +54,11 @@ var runCmd = &cli.Command{ &cli.StringFlag{ Name: "listen", Usage: "host address and port the api server will listen on", - Value: "0.0.0.0:1777", + Value: "0.0.0.0:2346", }, }, Action: func(cctx *cli.Context) error { - log.Info("Starting lotus wallet") + log.Info("Starting lotus gateway") ctx := lcli.ReqContext(cctx) ctx, cancel := context.WithCancel(ctx)