From c6719888f55c426db0da225df1bda161caec1cb3 Mon Sep 17 00:00:00 2001 From: frrist Date: Tue, 23 Feb 2021 14:36:44 -0800 Subject: [PATCH 1/7] feat(sentinel): add sentinel module scaffolding and API - allows lotus to be started in sentinel mode and start a watch that logs tipsets as they are received. --- api/api_full.go | 1 + api/api_sentinel.go | 12 ++++++++ api/apistruct/permissioned.go | 1 + api/apistruct/struct.go | 12 ++++++++ api/client/client.go | 1 + chain/events/events.go | 51 ++++++++++++++++++++++++++++++---- cli/cmd.go | 1 + cli/sentinel.go | 39 ++++++++++++++++++++++++++ cmd/lotus/daemon.go | 45 +++++++++++++++++++++++++----- go.sum | 1 + metrics/proxy.go | 1 + node/builder.go | 29 ++++++++++++++++--- node/impl/full.go | 1 + node/impl/sentinel/sentinel.go | 38 +++++++++++++++++++++++++ node/modules/sentinel.go | 21 ++++++++++++++ sentinel/observer.go | 27 ++++++++++++++++++ 16 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 api/api_sentinel.go create mode 100644 cli/sentinel.go create mode 100644 node/impl/sentinel/sentinel.go create mode 100644 node/modules/sentinel.go create mode 100644 sentinel/observer.go diff --git a/api/api_full.go b/api/api_full.go index 9c967ca32fd..7e90c3d4829 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -35,6 +35,7 @@ import ( // FullNode API is a low-level interface to the Filecoin network full node type FullNode interface { Common + Sentinel // MethodGroup: Chain // The Chain method group contains methods for interacting with the diff --git a/api/api_sentinel.go b/api/api_sentinel.go new file mode 100644 index 00000000000..fbc07b1334d --- /dev/null +++ b/api/api_sentinel.go @@ -0,0 +1,12 @@ +package api + +import ( + "context" +) + +type Sentinel interface { + // MethodGroup: Sentinel + + // WatchStart start a watch against the chain + WatchStart(context.Context) error +} diff --git a/api/apistruct/permissioned.go b/api/apistruct/permissioned.go index 86902d31b29..fa17f1daf56 100644 --- a/api/apistruct/permissioned.go +++ b/api/apistruct/permissioned.go @@ -28,6 +28,7 @@ func PermissionedFullAPI(a api.FullNode) api.FullNode { var out FullNodeStruct auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal) + auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.SentinelStruct.Internal) return &out } diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index ded34ac5ad8..53ef7d5350c 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -79,6 +79,7 @@ type CommonStruct struct { // FullNodeStruct implements API passing calls to user-provided function values. type FullNodeStruct struct { CommonStruct + SentinelStruct Internal struct { ChainNotify func(context.Context) (<-chan []*api.HeadChange, error) `perm:"read"` @@ -470,6 +471,12 @@ type WalletStruct struct { } } +type SentinelStruct struct { + Internal struct { + WatchStart func(ctx context.Context) error `perm:"admin"` + } +} + // CommonStruct func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) { @@ -1854,9 +1861,14 @@ func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) e return c.Internal.WalletDelete(ctx, addr) } +func (s *SentinelStruct) WatchStart(ctx context.Context) error { + return s.Internal.WatchStart(ctx) +} + var _ api.Common = &CommonStruct{} var _ api.FullNode = &FullNodeStruct{} var _ api.StorageMiner = &StorageMinerStruct{} var _ api.WorkerAPI = &WorkerStruct{} var _ api.GatewayAPI = &GatewayStruct{} var _ api.WalletAPI = &WalletStruct{} +var _ api.Sentinel = &SentinelStruct{} diff --git a/api/client/client.go b/api/client/client.go index 7d8a466d333..0a6e162e874 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -33,6 +33,7 @@ func NewFullNodeRPC(ctx context.Context, addr string, requestHeader http.Header) closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", []interface{}{ &res.CommonStruct.Internal, + &res.SentinelStruct.Internal, &res.Internal, }, requestHeader) diff --git a/chain/events/events.go b/chain/events/events.go index acb65d2c111..8b53266933c 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -55,11 +55,15 @@ type Events struct { heightEvents *hcEvents + + observers []TipSetObserver } func NewEvents(ctx context.Context, api eventAPI) *Events { - gcConfidence := 2 * build.ForkLengthThreshold + return NewEventsWithConfidence(ctx, api, 2*build.ForkLengthThreshold) +} +func NewEventsWithConfidence(ctx context.Context, api eventAPI, gcConfidence abi.ChainEpoch) *Events { tsc := newTSCache(gcConfidence, api) e := &Events{ @@ -77,8 +81,9 @@ func NewEvents(ctx context.Context, api eventAPI) *Events { htHeights: map[abi.ChainEpoch][]uint64{}, }, - hcEvents: newHCEvents(ctx, api, tsc, uint64(gcConfidence)), - ready: make(chan struct{}), + hcEvents: newHCEvents(ctx, api, tsc, uint64(gcConfidence)), + ready: make(chan struct{}), + observers: []TipSetObserver{}, } go e.listenHeadChanges(ctx) @@ -90,6 +95,7 @@ func NewEvents(ctx context.Context, api eventAPI) *Events { } return e + } func (e *Events) listenHeadChanges(ctx context.Context) { @@ -164,7 +170,7 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error { } } - if err := e.headChange(rev, app); err != nil { + if err := e.headChange(ctx, rev, app); err != nil { log.Warnf("headChange failed: %s", err) } @@ -177,7 +183,7 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error { return nil } -func (e *Events) headChange(rev, app []*types.TipSet) error { +func (e *Events) headChange(ctx context.Context, rev, app []*types.TipSet) error { if len(app) == 0 { return xerrors.New("events.headChange expected at least one applied tipset") } @@ -189,5 +195,40 @@ func (e *Events) headChange(rev, app []*types.TipSet) error { return err } + if err := e.observeChanges(ctx, rev, app); err != nil { + return err + } + return e.processHeadChangeEvent(rev, app) } + +// A TipSetObserver receives notifications of tipsets +type TipSetObserver interface { + Apply(ctx context.Context, ts *types.TipSet) error + Revert(ctx context.Context, ts *types.TipSet) error +} + +// TODO: add a confidence level so we can have observers with difference levels of confidence +func (e *Events) Observe(obs TipSetObserver) error { + e.lk.Lock() + defer e.lk.Unlock() + e.observers = append(e.observers, obs) + return nil +} + +// observeChanges expects caller to hold e.lk +func (e *Events) observeChanges(ctx context.Context, rev, app []*types.TipSet) error { + for _, ts := range rev { + for _, o := range e.observers { + _ = o.Revert(ctx, ts) + } + } + + for _, ts := range app { + for _, o := range e.observers { + _ = o.Apply(ctx, ts) + } + } + + return nil +} diff --git a/cli/cmd.go b/cli/cmd.go index 12ea768554f..30eb5f883fb 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -319,6 +319,7 @@ var Commands = []*cli.Command{ WithCategory("developer", fetchParamCmd), WithCategory("network", netCmd), WithCategory("network", syncCmd), + WithCategory("sentinel", sentinelCmd), pprofCmd, VersionCmd, } diff --git a/cli/sentinel.go b/cli/sentinel.go new file mode 100644 index 00000000000..04efa742111 --- /dev/null +++ b/cli/sentinel.go @@ -0,0 +1,39 @@ +package cli + +import ( + "github.com/urfave/cli/v2" +) + +var sentinelCmd = &cli.Command{ + Name: "sentinel", + Usage: "Interact with the sentinel module", + Subcommands: []*cli.Command{ + sentinelStartWatchCmd, + }, +} + +var sentinelStartWatchCmd = &cli.Command{ + Name: "watch", + Usage: "start a watch against the chain", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "confidence", + }, + }, + Action: func(cctx *cli.Context) error { + apic, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + //confidence := abi.ChainEpoch(cctx.Int64("confidence")) + + if err := apic.WatchStart(ctx); err != nil { + return err + } + + return nil + }, +} diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 4226c33f775..c810520f681 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -51,6 +51,15 @@ const ( preTemplateFlag = "genesis-template" ) +type daemonMode int + +const ( + modeUnknown daemonMode = 0 // no valid mode could be determined + modeStandard daemonMode = 1 // standard mode + modeLite daemonMode = 2 // lite mode, backed by gateway + modeSentinel daemonMode = 3 // stats collection mode, analyses chain events +) + var daemonStopCmd = &cli.Command{ Name: "stop", Usage: "Stop a running lotus daemon", @@ -119,6 +128,10 @@ var DaemonCmd = &cli.Command{ Usage: "start lotus in lite mode", Hidden: true, }, + &cli.BoolFlag{ + Name: "sentinel", + Usage: "start lotus in sentinel mode.", + }, &cli.StringFlag{ Name: "pprof", Usage: "specify name of file for writing cpu profile to", @@ -154,13 +167,15 @@ var DaemonCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - isLite := cctx.Bool("lite") + daemonMode, err := getDaemonMode(cctx) + if err != nil { + return err + } - err := runmetrics.Enable(runmetrics.RunMetricOptions{ + if err := runmetrics.Enable(runmetrics.RunMetricOptions{ EnableCPU: true, EnableMemory: true, - }) - if err != nil { + }); err != nil { return xerrors.Errorf("enabling runtime metrics: %w", err) } @@ -217,7 +232,7 @@ var DaemonCmd = &cli.Command{ } freshRepo := err != repo.ErrRepoExists - if !isLite { + if daemonMode != modeLite { if err := paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), 0); err != nil { return xerrors.Errorf("fetching proof parameters: %w", err) } @@ -279,7 +294,7 @@ var DaemonCmd = &cli.Command{ // If the daemon is started in "lite mode", provide a GatewayAPI // for RPC calls liteModeDeps := node.Options() - if isLite { + if daemonMode == modeLite { gapi, closer, err := lcli.GetGatewayAPI(cctx) if err != nil { return err @@ -298,7 +313,7 @@ var DaemonCmd = &cli.Command{ var api api.FullNode stop, err := node.New(ctx, - node.FullAPI(&api, node.Lite(isLite)), + node.FullAPI(&api, node.Lite(daemonMode == modeLite), node.Sentinel(daemonMode == modeSentinel)), node.Override(new(dtypes.Bootstrapper), isBootstrapper), node.Override(new(dtypes.ShutdownChan), shutdownChan), @@ -499,3 +514,19 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool) return nil } + +func getDaemonMode(cctx *cli.Context) (daemonMode, error) { + isLite := cctx.Bool("lite") + isSentinel := cctx.Bool("sentinel") + + switch { + case !isLite && !isSentinel: + return modeStandard, nil + case isLite && !isSentinel: + return modeLite, nil + case !isLite && isSentinel: + return modeSentinel, nil + default: + return modeUnknown, xerrors.Errorf("cannot specify more than one mode") + } +} diff --git a/go.sum b/go.sum index 4d0ecd0e479..d4bc17d3c20 100644 --- a/go.sum +++ b/go.sum @@ -1402,6 +1402,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/metrics/proxy.go b/metrics/proxy.go index f3714ec2e7d..5f3be535eed 100644 --- a/metrics/proxy.go +++ b/metrics/proxy.go @@ -21,6 +21,7 @@ func MetricedFullAPI(a api.FullNode) api.FullNode { var out apistruct.FullNodeStruct proxy(a, &out.Internal) proxy(a, &out.CommonStruct.Internal) + proxy(a, &out.SentinelStruct.Internal) return &out } diff --git a/node/builder.go b/node/builder.go index 0766d934afe..6790acb4c8b 100644 --- a/node/builder.go +++ b/node/builder.go @@ -9,12 +9,15 @@ import ( metricsi "github.com/ipfs/go-metrics-interface" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/node/hello" + "github.com/filecoin-project/lotus/node/impl/sentinel" "github.com/filecoin-project/lotus/system" logging "github.com/ipfs/go-log" @@ -166,9 +169,10 @@ type Settings struct { nodeType repo.RepoType - Online bool // Online option applied - Config bool // Config option applied - Lite bool // Start node in "lite" mode + Online bool // Online option applied + Config bool // Config option applied + Lite bool // Start node in "lite" mode + Sentinel bool // Start node in "sentinel" mode } // Basic lotus-app services @@ -244,6 +248,7 @@ func isType(t repo.RepoType) func(s *Settings) bool { func isFullOrLiteNode(s *Settings) bool { return s.nodeType == repo.FullNode } func isFullNode(s *Settings) bool { return s.nodeType == repo.FullNode && !s.Lite } func isLiteNode(s *Settings) bool { return s.nodeType == repo.FullNode && s.Lite } +func isSentinelNode(s *Settings) bool { return s.nodeType == repo.FullNode && s.Sentinel } // Chain node provides access to the Filecoin blockchain, by setting up a full // validator node, or by delegating some actions to other nodes (lite mode) @@ -352,6 +357,9 @@ var ChainNode = Options( Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), ), + + // Sentinel API is unavailable by default + Override(new(api.Sentinel), From(new(sentinel.SentinelUnavailable))), ) var MinerNode = Options( @@ -433,9 +441,13 @@ var MinerNode = Options( Override(new(dtypes.GetExpectedSealDurationFunc), modules.NewGetExpectedSealDurationFunc), ) +var SentinelNode = Options( + Override(new(*events.Events), modules.NewEvents), + Override(new(api.Sentinel), From(new(sentinel.SentinelAPI))), +) + // Online sets up basic libp2p node func Online() Option { - return Options( // make sure that online is applied before Config. // This is important because Config overrides some of Online units @@ -448,6 +460,8 @@ func Online() Option { ApplyIf(isFullOrLiteNode, ChainNode), ApplyIf(isType(repo.StorageMiner), MinerNode), + // sentinel node must apply after chain node else sentinel api is unavailable. + ApplyIf(isSentinelNode, SentinelNode), ) } @@ -626,6 +640,13 @@ func Lite(enable bool) FullOption { } } +func Sentinel(enable bool) FullOption { + return func(s *Settings) error { + s.Sentinel = enable + return nil + } +} + func FullAPI(out *api.FullNode, fopts ...FullOption) Option { return Options( func(s *Settings) error { diff --git a/node/impl/full.go b/node/impl/full.go index add40917c84..19d54ebc23d 100644 --- a/node/impl/full.go +++ b/node/impl/full.go @@ -29,6 +29,7 @@ type FullNodeAPI struct { full.WalletAPI full.SyncAPI full.BeaconAPI + api.Sentinel DS dtypes.MetadataDS } diff --git a/node/impl/sentinel/sentinel.go b/node/impl/sentinel/sentinel.go new file mode 100644 index 00000000000..b8e9f34de0f --- /dev/null +++ b/node/impl/sentinel/sentinel.go @@ -0,0 +1,38 @@ +package sentinel + +import ( + "context" + + logging "github.com/ipfs/go-log/v2" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/sentinel" +) + +var log = logging.Logger("sentinel-module") + +// SentinelAPI is an implementation of the sentinel api that logs each tipset as its applied and reverted. +type SentinelAPI struct { + fx.In + + Events *events.Events +} + +func (m *SentinelAPI) WatchStart(ctx context.Context) error { + log.Info("starting sentinel watch") + return m.Events.Observe(&sentinel.LoggingTipSetObserver{}) +} + +// SentinelUnavailable is an implementation of the sentinel api that returns an unavailable error for every request. +type SentinelUnavailable struct { + fx.In +} + +func (SentinelUnavailable) WatchStart(ctx context.Context) error { + return xerrors.Errorf("sentinel unavailable") +} + +var _ api.Sentinel = &SentinelAPI{} diff --git a/node/modules/sentinel.go b/node/modules/sentinel.go new file mode 100644 index 00000000000..08932284a60 --- /dev/null +++ b/node/modules/sentinel.go @@ -0,0 +1,21 @@ +package modules + +import ( + "go.uber.org/fx" + + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +func NewEvents(mctx helpers.MetricsCtx, lc fx.Lifecycle, chainAPI full.ChainModuleAPI, stateAPI full.StateModuleAPI) *events.Events { + api := struct { + full.ChainModuleAPI + full.StateModuleAPI + }{ + ChainModuleAPI: chainAPI, + StateModuleAPI: stateAPI, + } + + return events.NewEventsWithConfidence(mctx, api, 10) +} diff --git a/sentinel/observer.go b/sentinel/observer.go new file mode 100644 index 00000000000..da4525488f2 --- /dev/null +++ b/sentinel/observer.go @@ -0,0 +1,27 @@ +package sentinel + +import ( + "context" + + logging "github.com/ipfs/go-log/v2" + + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/types" +) + +var log = logging.Logger("sentinel-observer") + +var _ events.TipSetObserver = (*LoggingTipSetObserver)(nil) + +type LoggingTipSetObserver struct { +} + +func (o *LoggingTipSetObserver) Apply(ctx context.Context, ts *types.TipSet) error { + log.Infof("TipSetObserver.Apply(%q)", ts.Key()) + return nil +} + +func (o *LoggingTipSetObserver) Revert(ctx context.Context, ts *types.TipSet) error { + log.Infof("TipSetObserver.Revert(%q)", ts.Key()) + return nil +} From 67893922339dd8dedde7a58d97705ad0de27bead Mon Sep 17 00:00:00 2001 From: frrist Date: Wed, 24 Feb 2021 14:21:36 -0800 Subject: [PATCH 2/7] polish(sentinel): add mode for building lotus in sentinel mode - replaces the sentinel flag on daemon command. --- Makefile | 8 ++++++++ build/sentinel.go | 3 +++ cmd/lotus/daemon.go | 10 +++++----- 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 build/sentinel.go diff --git a/Makefile b/Makefile index 0fd1d7a922f..ef2130f452e 100644 --- a/Makefile +++ b/Makefile @@ -331,3 +331,11 @@ docsgen: print-%: @echo $*=$($*) + +# Sentinel build mode +lotus-sentinel: $(BUILD_DEPS) + rm -f lotus + go build $(GOFLAGS) -ldflags="-X=github.com/filecoin-project/lotus/build.SentinelMode=true" -o lotus ./cmd/lotus + go run github.com/GeertJohan/go.rice/rice append --exec lotus -i ./build + +.PHONY: lotus diff --git a/build/sentinel.go b/build/sentinel.go new file mode 100644 index 00000000000..e8575f644f5 --- /dev/null +++ b/build/sentinel.go @@ -0,0 +1,3 @@ +package build + +var SentinelMode string = "false" diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index c810520f681..1e4b7abf01e 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -13,6 +13,7 @@ import ( "net/http" "os" "runtime/pprof" + "strconv" "strings" paramfetch "github.com/filecoin-project/go-paramfetch" @@ -128,10 +129,6 @@ var DaemonCmd = &cli.Command{ Usage: "start lotus in lite mode", Hidden: true, }, - &cli.BoolFlag{ - Name: "sentinel", - Usage: "start lotus in sentinel mode.", - }, &cli.StringFlag{ Name: "pprof", Usage: "specify name of file for writing cpu profile to", @@ -517,7 +514,10 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool) func getDaemonMode(cctx *cli.Context) (daemonMode, error) { isLite := cctx.Bool("lite") - isSentinel := cctx.Bool("sentinel") + isSentinel, err := strconv.ParseBool(build.SentinelMode) + if err != nil { + return modeUnknown, err + } switch { case !isLite && !isSentinel: From 6f5e45759b374aa9f560f4414eee374a0502fcf9 Mon Sep 17 00:00:00 2001 From: frrist Date: Thu, 25 Feb 2021 14:07:44 -0800 Subject: [PATCH 3/7] fixup! feat(sentinel): add sentinel module scaffolding and API --- api/apistruct/struct.go | 2 +- node/builder.go | 3 --- node/impl/sentinel/sentinel.go | 10 ---------- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 53ef7d5350c..d674a956793 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -79,7 +79,7 @@ type CommonStruct struct { // FullNodeStruct implements API passing calls to user-provided function values. type FullNodeStruct struct { CommonStruct - SentinelStruct + SentinelStruct `optional:"true"` Internal struct { ChainNotify func(context.Context) (<-chan []*api.HeadChange, error) `perm:"read"` diff --git a/node/builder.go b/node/builder.go index 6790acb4c8b..c0d14b2a484 100644 --- a/node/builder.go +++ b/node/builder.go @@ -357,9 +357,6 @@ var ChainNode = Options( Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), ), - - // Sentinel API is unavailable by default - Override(new(api.Sentinel), From(new(sentinel.SentinelUnavailable))), ) var MinerNode = Options( diff --git a/node/impl/sentinel/sentinel.go b/node/impl/sentinel/sentinel.go index b8e9f34de0f..d842c52a07b 100644 --- a/node/impl/sentinel/sentinel.go +++ b/node/impl/sentinel/sentinel.go @@ -5,7 +5,6 @@ import ( logging "github.com/ipfs/go-log/v2" "go.uber.org/fx" - "golang.org/x/xerrors" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/events" @@ -26,13 +25,4 @@ func (m *SentinelAPI) WatchStart(ctx context.Context) error { return m.Events.Observe(&sentinel.LoggingTipSetObserver{}) } -// SentinelUnavailable is an implementation of the sentinel api that returns an unavailable error for every request. -type SentinelUnavailable struct { - fx.In -} - -func (SentinelUnavailable) WatchStart(ctx context.Context) error { - return xerrors.Errorf("sentinel unavailable") -} - var _ api.Sentinel = &SentinelAPI{} From 45ab7c538765c813dacfb8abf2d430e985fafdbe Mon Sep 17 00:00:00 2001 From: frrist Date: Thu, 25 Feb 2021 14:08:45 -0800 Subject: [PATCH 4/7] fixup! feat(sentinel): add sentinel module scaffolding and API --- api/api_sentinel.go | 2 +- api/apistruct/struct.go | 2 +- cli/sentinel.go | 2 +- node/impl/sentinel/sentinel.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/api_sentinel.go b/api/api_sentinel.go index fbc07b1334d..d2b4904ee34 100644 --- a/api/api_sentinel.go +++ b/api/api_sentinel.go @@ -8,5 +8,5 @@ type Sentinel interface { // MethodGroup: Sentinel // WatchStart start a watch against the chain - WatchStart(context.Context) error + SentinelWatchStart(context.Context) error } diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index d674a956793..d308375b620 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -1861,7 +1861,7 @@ func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) e return c.Internal.WalletDelete(ctx, addr) } -func (s *SentinelStruct) WatchStart(ctx context.Context) error { +func (s *SentinelStruct) SentinelWatchStart(ctx context.Context) error { return s.Internal.WatchStart(ctx) } diff --git a/cli/sentinel.go b/cli/sentinel.go index 04efa742111..c5e83627b1c 100644 --- a/cli/sentinel.go +++ b/cli/sentinel.go @@ -30,7 +30,7 @@ var sentinelStartWatchCmd = &cli.Command{ //confidence := abi.ChainEpoch(cctx.Int64("confidence")) - if err := apic.WatchStart(ctx); err != nil { + if err := apic.SentinelWatchStart(ctx); err != nil { return err } diff --git a/node/impl/sentinel/sentinel.go b/node/impl/sentinel/sentinel.go index d842c52a07b..65e70342ba0 100644 --- a/node/impl/sentinel/sentinel.go +++ b/node/impl/sentinel/sentinel.go @@ -20,7 +20,7 @@ type SentinelAPI struct { Events *events.Events } -func (m *SentinelAPI) WatchStart(ctx context.Context) error { +func (m *SentinelAPI) SentinelWatchStart(ctx context.Context) error { log.Info("starting sentinel watch") return m.Events.Observe(&sentinel.LoggingTipSetObserver{}) } From a50b2e3f0b448cc97e907fd6f66bf87fbcfb4ca7 Mon Sep 17 00:00:00 2001 From: frrist Date: Thu, 25 Feb 2021 14:30:03 -0800 Subject: [PATCH 5/7] fixup! feat(sentinel): add sentinel module scaffolding and API --- node/impl/full.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full.go b/node/impl/full.go index 19d54ebc23d..0801631cb80 100644 --- a/node/impl/full.go +++ b/node/impl/full.go @@ -29,7 +29,7 @@ type FullNodeAPI struct { full.WalletAPI full.SyncAPI full.BeaconAPI - api.Sentinel + api.Sentinel `optional:"true"` DS dtypes.MetadataDS } From 7787c94b40c846efeff29fb1f66e03eb548a6f9a Mon Sep 17 00:00:00 2001 From: frrist Date: Thu, 25 Feb 2021 14:34:46 -0800 Subject: [PATCH 6/7] fixup! feat(sentinel): add sentinel module scaffolding and API --- api/apistruct/struct.go | 4 ++-- api/docgen/docgen.go | 8 ++++++-- documentation/en/api-methods.md | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index d308375b620..23edfe2daae 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -473,7 +473,7 @@ type WalletStruct struct { type SentinelStruct struct { Internal struct { - WatchStart func(ctx context.Context) error `perm:"admin"` + SentinelWatchStart func(ctx context.Context) error `perm:"admin"` } } @@ -1862,7 +1862,7 @@ func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) e } func (s *SentinelStruct) SentinelWatchStart(ctx context.Context) error { - return s.Internal.WatchStart(ctx) + return s.Internal.SentinelWatchStart(ctx) } var _ api.Common = &CommonStruct{} diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 7d3ac4bcf75..32805f4f820 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -405,13 +405,14 @@ func main() { groups := make(map[string]*MethodGroup) var t reflect.Type - var permStruct, commonPermStruct reflect.Type + var permStruct, commonPermStruct, sentinelPermStruct reflect.Type switch os.Args[2] { case "FullNode": t = reflect.TypeOf(new(struct{ api.FullNode })).Elem() permStruct = reflect.TypeOf(apistruct.FullNodeStruct{}.Internal) commonPermStruct = reflect.TypeOf(apistruct.CommonStruct{}.Internal) + sentinelPermStruct = reflect.TypeOf(apistruct.SentinelStruct{}.Internal) case "StorageMiner": t = reflect.TypeOf(new(struct{ api.StorageMiner })).Elem() permStruct = reflect.TypeOf(apistruct.StorageMinerStruct{}.Internal) @@ -499,7 +500,10 @@ func main() { if !ok { meth, ok = commonPermStruct.FieldByName(m.Name) if !ok { - panic("no perms for method: " + m.Name) + meth, ok = sentinelPermStruct.FieldByName(m.Name) + if !ok { + panic("no perms for method: " + m.Name) + } } } diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 84a86f943cd..7b5a9e41948 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -140,6 +140,8 @@ * [PaychVoucherCreate](#PaychVoucherCreate) * [PaychVoucherList](#PaychVoucherList) * [PaychVoucherSubmit](#PaychVoucherSubmit) +* [Sentinel](#Sentinel) + * [SentinelWatchStart](#SentinelWatchStart) * [State](#State) * [StateAccountKey](#StateAccountKey) * [StateAllMinerFaults](#StateAllMinerFaults) @@ -3310,6 +3312,18 @@ Response: } ``` +## Sentinel + + +### SentinelWatchStart + + +Perms: admin + +Inputs: `null` + +Response: `{}` + ## State The State methods are used to query, inspect, and interact with chain state. Most methods take a TipSetKey as a parameter. The state looked up is the parent state of the tipset. From cae8ad4f489f0f813b10d66c6fd3b2ca77e6a9d1 Mon Sep 17 00:00:00 2001 From: frrist Date: Thu, 25 Feb 2021 14:41:59 -0800 Subject: [PATCH 7/7] fixup! feat(sentinel): add sentinel module scaffolding and API --- api/api_sentinel.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/api_sentinel.go b/api/api_sentinel.go index d2b4904ee34..ea7bd040352 100644 --- a/api/api_sentinel.go +++ b/api/api_sentinel.go @@ -7,6 +7,6 @@ import ( type Sentinel interface { // MethodGroup: Sentinel - // WatchStart start a watch against the chain + // SentinelWatchStart start a watch against the chain SentinelWatchStart(context.Context) error }