feat: put gateway in middle of end-to-end test for lite mode
This commit is contained in:
parent
ef73b964fb
commit
e9e27cbbb0
@ -23,7 +23,9 @@ var (
|
|||||||
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
||||||
)
|
)
|
||||||
|
|
||||||
type rpcAPI interface {
|
// gatewayDepsAPI defines the API methods that the GatewayAPI depends on
|
||||||
|
// (to make it easy to mock for tests)
|
||||||
|
type gatewayDepsAPI interface {
|
||||||
ChainHead(ctx context.Context) (*types.TipSet, error)
|
ChainHead(ctx context.Context) (*types.TipSet, error)
|
||||||
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||||
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||||
@ -36,7 +38,7 @@ type rpcAPI interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GatewayAPI struct {
|
type GatewayAPI struct {
|
||||||
rpc rpcAPI
|
api gatewayDepsAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error {
|
func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error {
|
||||||
@ -44,7 +46,7 @@ func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ts, err := a.rpc.ChainGetTipSet(ctx, tsk)
|
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -82,15 +84,15 @@ func (a *GatewayAPI) checkTimestamp(at time.Time) error {
|
|||||||
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||||
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
||||||
|
|
||||||
return a.rpc.ChainHead(ctx)
|
return a.api.ChainHead(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||||
return a.rpc.ChainGetTipSet(ctx, tsk)
|
return a.api.ChainGetTipSet(ctx, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||||
ts, err := a.rpc.ChainGetTipSet(ctx, tsk)
|
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -105,7 +107,7 @@ func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoc
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.rpc.ChainGetTipSetByHeight(ctx, h, tsk)
|
return a.api.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
func (a *GatewayAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||||
@ -113,12 +115,12 @@ func (a *GatewayAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Messa
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.rpc.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
return a.api.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||||
// TODO: additional anti-spam checks
|
// TODO: additional anti-spam checks
|
||||||
return a.rpc.MpoolPushUntrusted(ctx, sm)
|
return a.api.MpoolPushUntrusted(ctx, sm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||||
@ -126,7 +128,7 @@ func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address,
|
|||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.rpc.StateAccountKey(ctx, addr, tsk)
|
return a.api.StateAccountKey(ctx, addr, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||||
@ -134,7 +136,7 @@ func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, t
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.rpc.StateGetActor(ctx, actor, tsk)
|
return a.api.StateGetActor(ctx, actor, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||||
@ -142,11 +144,11 @@ func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, ts
|
|||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.rpc.StateLookupID(ctx, addr, tsk)
|
return a.api.StateLookupID(ctx, addr, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
func (a *GatewayAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||||
return a.rpc.StateWaitMsgLimited(ctx, msg, confidence, stateWaitLookbackLimit)
|
return a.api.StateWaitMsgLimited(ctx, msg, confidence, stateWaitLookbackLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ api.GatewayAPI = (*GatewayAPI)(nil)
|
var _ api.GatewayAPI = (*GatewayAPI)(nil)
|
||||||
|
@ -87,8 +87,8 @@ func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
mock := &mockRPCAPI{}
|
mock := &mockGatewayDepsAPI{}
|
||||||
a := &GatewayAPI{rpc: mock}
|
a := &GatewayAPI{api: mock}
|
||||||
|
|
||||||
// Create tipsets from genesis up to tskh and return the highest
|
// Create tipsets from genesis up to tskh and return the highest
|
||||||
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
|
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
|
||||||
@ -104,19 +104,19 @@ func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockRPCAPI struct {
|
type mockGatewayDepsAPI struct {
|
||||||
lk sync.RWMutex
|
lk sync.RWMutex
|
||||||
tipsets []*types.TipSet
|
tipsets []*types.TipSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
func (m *mockGatewayDepsAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||||
m.lk.RLock()
|
m.lk.RLock()
|
||||||
defer m.lk.RUnlock()
|
defer m.lk.RUnlock()
|
||||||
|
|
||||||
return m.tipsets[len(m.tipsets)-1], nil
|
return m.tipsets[len(m.tipsets)-1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
func (m *mockGatewayDepsAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||||
m.lk.RLock()
|
m.lk.RLock()
|
||||||
defer m.lk.RUnlock()
|
defer m.lk.RUnlock()
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ func (m *mockRPCAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createTipSets creates tipsets from genesis up to tskh and returns the highest
|
// createTipSets creates tipsets from genesis up to tskh and returns the highest
|
||||||
func (m *mockRPCAPI) createTipSets(h abi.ChainEpoch, genesisTimestamp uint64) *types.TipSet {
|
func (m *mockGatewayDepsAPI) createTipSets(h abi.ChainEpoch, genesisTimestamp uint64) *types.TipSet {
|
||||||
m.lk.Lock()
|
m.lk.Lock()
|
||||||
defer m.lk.Unlock()
|
defer m.lk.Unlock()
|
||||||
|
|
||||||
@ -151,33 +151,33 @@ func (m *mockRPCAPI) createTipSets(h abi.ChainEpoch, genesisTimestamp uint64) *t
|
|||||||
return m.tipsets[len(m.tipsets)-1]
|
return m.tipsets[len(m.tipsets)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
func (m *mockGatewayDepsAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||||
m.lk.Lock()
|
m.lk.Lock()
|
||||||
defer m.lk.Unlock()
|
defer m.lk.Unlock()
|
||||||
|
|
||||||
return m.tipsets[h], nil
|
return m.tipsets[h], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
func (m *mockGatewayDepsAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
func (m *mockGatewayDepsAPI) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
func (m *mockGatewayDepsAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
func (m *mockGatewayDepsAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
func (m *mockGatewayDepsAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRPCAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) {
|
func (m *mockGatewayDepsAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ func init() {
|
|||||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestEndToEnd tests that API calls can be made on a lite node that is
|
||||||
|
// connected through a gateway to a full API node
|
||||||
func TestEndToEnd(t *testing.T) {
|
func TestEndToEnd(t *testing.T) {
|
||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
@ -66,10 +68,12 @@ func TestEndToEnd(t *testing.T) {
|
|||||||
err = sendFunds(ctx, t, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
|
err = sendFunds(ctx, t, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Sign some data with the lite node wallet address
|
||||||
data := []byte("hello")
|
data := []byte("hello")
|
||||||
sig, err := lite.WalletSign(ctx, liteWalletAddr, data)
|
sig, err := lite.WalletSign(ctx, liteWalletAddr, data)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
ok, err := lite.WalletVerify(ctx, liteWalletAddr, data, sig)
|
ok, err := lite.WalletVerify(ctx, liteWalletAddr, data, sig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
@ -101,6 +105,10 @@ func sendFunds(ctx context.Context, t *testing.T, fromNode test.TestNode, fromAd
|
|||||||
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
|
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
|
||||||
var closer jsonrpc.ClientCloser
|
var closer jsonrpc.ClientCloser
|
||||||
|
|
||||||
|
// Create one miner and two full nodes.
|
||||||
|
// - Put a gateway server in front of full node 1
|
||||||
|
// - Start full node 2 in lite mode
|
||||||
|
// - Connect lite node -> gateway server -> full node
|
||||||
opts := append(
|
opts := append(
|
||||||
// Full node
|
// Full node
|
||||||
test.OneFull,
|
test.OneFull,
|
||||||
@ -108,17 +116,20 @@ func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (tes
|
|||||||
func(nodes []test.TestNode) node.Option {
|
func(nodes []test.TestNode) node.Option {
|
||||||
fullNode := nodes[0]
|
fullNode := nodes[0]
|
||||||
|
|
||||||
addr, err := builder.WSMultiAddrToString(fullNode.ListenAddr)
|
// Create a gateway server in front of the full node
|
||||||
|
_, addr, err := builder.CreateRPCServer(&GatewayAPI{api: fullNode})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a gateway API that connects to the full node
|
// Create a gateway client API that connects to the gateway server
|
||||||
var gapi api.GatewayAPI
|
var gapi api.GatewayAPI
|
||||||
gapi, closer, err = client.NewGatewayRPC(ctx, addr, nil)
|
gapi, closer, err = client.NewGatewayRPC(ctx, addr, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Override this node with lite-mode options
|
||||||
return node.LiteModeOverrides(gapi)
|
return node.LiteModeOverrides(gapi)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
n, sn := builder.RPCMockSbBuilderWithOpts(t, opts, test.OneMiner)
|
n, sn := builder.RPCMockSbBuilder(t, opts, test.OneMiner)
|
||||||
|
|
||||||
full := n[0]
|
full := n[0]
|
||||||
lite := n[1]
|
lite := n[1]
|
||||||
|
@ -76,7 +76,7 @@ var runCmd = &cli.Command{
|
|||||||
log.Info("Setting up API endpoint at " + address)
|
log.Info("Setting up API endpoint at " + address)
|
||||||
|
|
||||||
rpcServer := jsonrpc.NewServer()
|
rpcServer := jsonrpc.NewServer()
|
||||||
rpcServer.Register("Filecoin", &GatewayAPI{rpc: api})
|
rpcServer.Register("Filecoin", &GatewayAPI{api: api})
|
||||||
|
|
||||||
mux.Handle("/rpc/v0", rpcServer)
|
mux.Handle("/rpc/v0", rpcServer)
|
||||||
mux.PathPrefix("/").Handler(http.DefaultServeMux)
|
mux.PathPrefix("/").Handler(http.DefaultServeMux)
|
||||||
|
@ -157,10 +157,6 @@ func RPCMockSbBuilder(t *testing.T, fullOpts []test.OptionGenerator, storage []t
|
|||||||
return mockSbBuilderOpts(t, fullOpts, storage, []node.Option{}, true)
|
return mockSbBuilderOpts(t, fullOpts, storage, []node.Option{}, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RPCMockSbBuilderWithOpts(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
|
||||||
return mockSbBuilderOpts(t, fullOpts, storage, []node.Option{}, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mockBuilderOpts(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, opts []node.Option, rpc bool) ([]test.TestNode, []test.TestStorageNode) {
|
func mockBuilderOpts(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, opts []node.Option, rpc bool) ([]test.TestNode, []test.TestStorageNode) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
Loading…
Reference in New Issue
Block a user