feat: lotus-lite - replace wallet StateManager with thin client to gateway

This commit is contained in:
Dirk McCormick 2020-09-29 17:25:45 +02:00
parent bacac245c7
commit e19cd9ed01
10 changed files with 163 additions and 15 deletions

17
api/api_gateway.go Normal file
View File

@ -0,0 +1,17 @@
package api
import (
"context"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
)
type GatewayAPI interface {
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
ChainHead(ctx context.Context) (*types.TipSet, error)
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
}

View File

@ -361,6 +361,17 @@ type WorkerStruct struct {
} }
} }
type GatewayStruct struct {
Internal struct {
// TODO: does the gateway need perms?
StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
ChainHead func(ctx context.Context) (*types.TipSet, error)
ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
}
}
// CommonStruct // CommonStruct
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) { func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
@ -1372,7 +1383,28 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
return w.Internal.Closing(ctx) return w.Internal.Closing(ctx)
} }
func (g GatewayStruct) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
return g.Internal.StateGetActor(ctx, actor, ts)
}
func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
return g.Internal.ChainHead(ctx)
}
func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
return g.Internal.ChainGetTipSet(ctx, tsk)
}
func (g GatewayStruct) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
return g.Internal.MpoolPush(ctx, sm)
}
func (g GatewayStruct) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
return g.Internal.StateAccountKey(ctx, addr, tsk)
}
var _ api.Common = &CommonStruct{} var _ api.Common = &CommonStruct{}
var _ api.FullNode = &FullNodeStruct{} var _ api.FullNode = &FullNodeStruct{}
var _ api.StorageMiner = &StorageMinerStruct{} var _ api.StorageMiner = &StorageMinerStruct{}
var _ api.WorkerAPI = &WorkerStruct{} var _ api.WorkerAPI = &WorkerStruct{}
var _ api.GatewayAPI = &GatewayStruct{}

View File

@ -82,3 +82,17 @@ func NewWorkerRPC(ctx context.Context, addr string, requestHeader http.Header) (
return &res, closer, err return &res, closer, err
} }
// NewGatewayRPC creates a new http jsonrpc client for a gateway node.
func NewGatewayRPC(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
var res apistruct.GatewayStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{
&res.Internal,
},
requestHeader,
opts...,
)
return &res, closer, err
}

View File

@ -40,6 +40,11 @@ import (
var log = logging.Logger("statemgr") var log = logging.Logger("statemgr")
type StateManagerAPI interface {
LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error)
ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
}
type versionSpec struct { type versionSpec struct {
networkVersion network.Version networkVersion network.Version
atOrBelow abi.ChainEpoch atOrBelow abi.ChainEpoch
@ -1393,3 +1398,5 @@ func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (m
} }
return actState, nil return actState, nil
} }
var _ StateManagerAPI = (*StateManager)(nil)

View File

@ -289,6 +289,15 @@ func GetWorkerAPI(ctx *cli.Context) (api.WorkerAPI, jsonrpc.ClientCloser, error)
return client.NewWorkerRPC(ctx.Context, addr, headers) return client.NewWorkerRPC(ctx.Context, addr, headers)
} }
func GetGatewayAPI(ctx *cli.Context) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
addr, headers, err := GetRawAPI(ctx, repo.FullNode)
if err != nil {
return nil, nil, err
}
return client.NewGatewayRPC(ctx.Context, addr, headers)
}
func DaemonContext(cctx *cli.Context) context.Context { func DaemonContext(cctx *cli.Context) context.Context {
if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok { if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok {
return mtCtx.(context.Context) return mtCtx.(context.Context)

View File

@ -49,17 +49,6 @@ func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error
return nil 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()
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) { func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
ctx, span := trace.StartSpan(ctx, "ChainHead") ctx, span := trace.StartSpan(ctx, "ChainHead")
defer span.End() defer span.End()
@ -88,3 +77,25 @@ func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (ci
return a.api.MpoolPushUntrusted(ctx, sm) return a.api.MpoolPushUntrusted(ctx, sm)
} }
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()
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) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
ctx, span := trace.StartSpan(ctx, "StateAccountKey")
defer span.End()
if err := a.checkTipset(ctx, tsk); err != nil {
return address.Undef, fmt.Errorf("bad tipset: %w", err)
}
return a.api.StateAccountKey(ctx, addr, tsk)
}

View File

@ -15,6 +15,8 @@ import (
"runtime/pprof" "runtime/pprof"
"strings" "strings"
"go.uber.org/fx"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
paramfetch "github.com/filecoin-project/go-paramfetch" paramfetch "github.com/filecoin-project/go-paramfetch"
@ -114,6 +116,10 @@ var DaemonCmd = &cli.Command{
Name: "halt-after-import", Name: "halt-after-import",
Usage: "halt the process after importing chain from file", Usage: "halt the process after importing chain from file",
}, },
&cli.BoolFlag{
Name: "lite",
Usage: "start lotus in lite mode",
},
&cli.StringFlag{ &cli.StringFlag{
Name: "pprof", Name: "pprof",
Usage: "specify name of file for writing cpu profile to", Usage: "specify name of file for writing cpu profile to",
@ -240,6 +246,27 @@ var DaemonCmd = &cli.Command{
shutdownChan := make(chan struct{}) shutdownChan := make(chan struct{})
// If the daemon is started in "lite mode", replace the StateManager
// with a thin client to a gateway server
liteMode := node.Options()
if cctx.Bool("lite") {
gapi, closer, err := lcli.GetGatewayAPI(cctx)
if err != nil {
return err
}
createRPCStateMgr := func(lc fx.Lifecycle) *modules.RPCStateManager {
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
closer()
return nil
},
})
return modules.NewRPCStateManager(gapi)
}
liteMode = node.Override(new(stmgr.StateManagerAPI), createRPCStateMgr)
}
var api api.FullNode var api api.FullNode
stop, err := node.New(ctx, stop, err := node.New(ctx,
@ -251,6 +278,7 @@ var DaemonCmd = &cli.Command{
node.Repo(r), node.Repo(r),
genesis, genesis,
liteMode,
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") }, node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
node.Override(node.SetApiEndpointKey, func(lr repo.LockedRepo) error { node.Override(node.SetApiEndpointKey, func(lr repo.LockedRepo) error {

View File

@ -261,6 +261,7 @@ func Online() Option {
Override(new(*store.ChainStore), modules.ChainStore), Override(new(*store.ChainStore), modules.ChainStore),
Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()), Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()),
Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule), Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule),
Override(new(stmgr.StateManagerAPI), From(new(*stmgr.StateManager))),
Override(new(*wallet.Wallet), wallet.NewWallet), Override(new(*wallet.Wallet), wallet.NewWallet),
Override(new(*messagesigner.MessageSigner), messagesigner.NewMessageSigner), Override(new(*messagesigner.MessageSigner), messagesigner.NewMessageSigner),

View File

@ -19,8 +19,8 @@ import (
type WalletAPI struct { type WalletAPI struct {
fx.In fx.In
StateManager *stmgr.StateManager stmgr.StateManagerAPI
Wallet *wallet.Wallet Wallet *wallet.Wallet
} }
func (a *WalletAPI) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) { func (a *WalletAPI) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
@ -36,7 +36,7 @@ func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) {
} }
func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) {
act, err := a.StateManager.LoadActorTsk(ctx, addr, types.EmptyTSK) act, err := a.StateManagerAPI.LoadActorTsk(ctx, addr, types.EmptyTSK)
if xerrors.Is(err, types.ErrActorNotFound) { if xerrors.Is(err, types.ErrActorNotFound) {
return big.Zero(), nil return big.Zero(), nil
} else if err != nil { } else if err != nil {
@ -46,7 +46,7 @@ func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (ty
} }
func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) { func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) {
keyAddr, err := a.StateManager.ResolveToKeyAddress(ctx, k, nil) keyAddr, err := a.StateManagerAPI.ResolveToKeyAddress(ctx, k, nil)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr)
} }

View File

@ -0,0 +1,29 @@
package modules
import (
"context"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
)
type RPCStateManager struct {
gapi api.GatewayAPI
}
func NewRPCStateManager(api api.GatewayAPI) *RPCStateManager {
return &RPCStateManager{gapi: api}
}
func (s *RPCStateManager) LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) {
return s.gapi.StateGetActor(ctx, addr, tsk)
}
func (s *RPCStateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
return s.gapi.StateAccountKey(ctx, addr, ts.Key())
}
var _ stmgr.StateManagerAPI = (*RPCStateManager)(nil)