feat: add end-to-end test for lite mode
This commit is contained in:
parent
7b1bec91ed
commit
ef73b964fb
@ -37,7 +37,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
|
||||
func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
n, sn := b(t, OneFull, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
|
@ -48,7 +48,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -85,7 +85,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -149,7 +149,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -204,7 +204,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
@ -25,7 +25,7 @@ var log = logging.Logger("apitest")
|
||||
|
||||
func (ts *testSuite) testMining(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@ -54,7 +54,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@ -93,7 +93,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
// test making a deal with a fresh miner, and see if it starts to mine
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, []StorageMiner{
|
||||
n, sn := b(t, OneFull, []StorageMiner{
|
||||
{Full: 0, Preseal: PresealGenesis},
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
||||
})
|
||||
|
@ -33,7 +33,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 2, OneMiner)
|
||||
n, sn := b(t, TwoFull, OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
|
@ -40,12 +40,14 @@ type StorageMiner struct {
|
||||
Preseal int
|
||||
}
|
||||
|
||||
type OptionGenerator func([]TestNode) node.Option
|
||||
|
||||
// APIBuilder is a function which is invoked in test suite to provide
|
||||
// test nodes and networks
|
||||
//
|
||||
// storage array defines storage nodes, numbers in the array specify full node
|
||||
// index the storage node 'belongs' to
|
||||
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode)
|
||||
type APIBuilder func(t *testing.T, full []OptionGenerator, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode)
|
||||
type testSuite struct {
|
||||
makeNodes APIBuilder
|
||||
}
|
||||
@ -63,13 +65,25 @@ func TestApis(t *testing.T, b APIBuilder) {
|
||||
t.Run("testMiningReal", ts.testMiningReal)
|
||||
}
|
||||
|
||||
func DefaultFullOpts(nFull int) []OptionGenerator {
|
||||
full := make([]OptionGenerator, nFull)
|
||||
for i := range full {
|
||||
full[i] = func(nodes []TestNode) node.Option {
|
||||
return node.Options()
|
||||
}
|
||||
}
|
||||
return full
|
||||
}
|
||||
|
||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
var OneFull = DefaultFullOpts(1)
|
||||
var TwoFull = DefaultFullOpts(2)
|
||||
|
||||
func (ts *testSuite) testVersion(t *testing.T) {
|
||||
build.RunningNodeType = build.NodeFull
|
||||
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
@ -81,7 +95,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testID(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
id, err := api.ID(ctx)
|
||||
@ -93,7 +107,7 @@ func (ts *testSuite) testID(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testConnectTwo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 2, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, TwoFull, OneMiner)
|
||||
|
||||
p, err := apis[0].NetPeers(ctx)
|
||||
if err != nil {
|
||||
|
@ -34,7 +34,7 @@ func init() {
|
||||
|
||||
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -133,7 +133,7 @@ func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration,
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
n, sn := b(t, OneFull, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
@ -21,7 +20,7 @@ const dsKeyActorNonce = "ActorNextNonce"
|
||||
|
||||
var log = logging.Logger("messagesigner")
|
||||
|
||||
type mpoolAPI interface {
|
||||
type MpoolNonceAPI interface {
|
||||
GetNonce(address.Address) (uint64, error)
|
||||
}
|
||||
|
||||
@ -30,15 +29,11 @@ type mpoolAPI interface {
|
||||
type MessageSigner struct {
|
||||
wallet *wallet.Wallet
|
||||
lk sync.Mutex
|
||||
mpool mpoolAPI
|
||||
mpool MpoolNonceAPI
|
||||
ds datastore.Batching
|
||||
}
|
||||
|
||||
func NewMessageSigner(wallet *wallet.Wallet, mpool *messagepool.MessagePool, ds dtypes.MetadataDS) *MessageSigner {
|
||||
return newMessageSigner(wallet, mpool, ds)
|
||||
}
|
||||
|
||||
func newMessageSigner(wallet *wallet.Wallet, mpool mpoolAPI, ds dtypes.MetadataDS) *MessageSigner {
|
||||
func NewMessageSigner(wallet *wallet.Wallet, mpool MpoolNonceAPI, ds dtypes.MetadataDS) *MessageSigner {
|
||||
ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
|
||||
return &MessageSigner{
|
||||
wallet: wallet,
|
||||
|
@ -177,7 +177,7 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mpool := newMockMpool()
|
||||
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
|
||||
ms := newMessageSigner(w, mpool, ds)
|
||||
ms := NewMessageSigner(w, mpool, ds)
|
||||
|
||||
for _, m := range tt.msgs {
|
||||
if len(m.mpoolNonce) == 1 {
|
||||
|
@ -390,7 +390,7 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
|
||||
}
|
||||
|
||||
func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) {
|
||||
n, sn := builder.RPCMockSbBuilder(t, 2, test.OneMiner)
|
||||
n, sn := builder.RPCMockSbBuilder(t, test.TwoFull, test.OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
|
183
cmd/lotus-gateway/api_test.go
Normal file
183
cmd/lotus-gateway/api_test.go
Normal file
@ -0,0 +1,183 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
lookbackTimestamp := uint64(time.Now().Unix()) - uint64(LookbackCap.Seconds())
|
||||
type args struct {
|
||||
h abi.ChainEpoch
|
||||
tskh abi.ChainEpoch
|
||||
genesisTS uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expErr bool
|
||||
}{{
|
||||
name: "basic",
|
||||
args: args{
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
},
|
||||
}, {
|
||||
name: "genesis",
|
||||
args: args{
|
||||
h: abi.ChainEpoch(0),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
},
|
||||
}, {
|
||||
name: "same epoch as tipset",
|
||||
args: args{
|
||||
h: abi.ChainEpoch(5),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
},
|
||||
}, {
|
||||
name: "tipset too old",
|
||||
args: args{
|
||||
// Tipset height is 5, genesis is at LookbackCap - 10 epochs.
|
||||
// So resulting tipset height will be 5 epochs earlier than LookbackCap.
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
genesisTS: lookbackTimestamp - build.BlockDelaySecs*10,
|
||||
},
|
||||
expErr: true,
|
||||
}, {
|
||||
name: "lookup height too old",
|
||||
args: args{
|
||||
// Tipset height is 5, lookup height is 1, genesis is at LookbackCap - 3 epochs.
|
||||
// So
|
||||
// - lookup height will be 2 epochs earlier than LookbackCap.
|
||||
// - tipset height will be 2 epochs later than LookbackCap.
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
genesisTS: lookbackTimestamp - build.BlockDelaySecs*3,
|
||||
},
|
||||
expErr: true,
|
||||
}, {
|
||||
name: "tipset and lookup height within acceptable range",
|
||||
args: args{
|
||||
// Tipset height is 5, lookup height is 1, genesis is at LookbackCap.
|
||||
// So
|
||||
// - lookup height will be 1 epoch later than LookbackCap.
|
||||
// - tipset height will be 5 epochs later than LookbackCap.
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
genesisTS: lookbackTimestamp,
|
||||
},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &mockRPCAPI{}
|
||||
a := &GatewayAPI{rpc: mock}
|
||||
|
||||
// Create tipsets from genesis up to tskh and return the highest
|
||||
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
|
||||
|
||||
got, err := a.ChainGetTipSetByHeight(ctx, tt.args.h, ts.Key())
|
||||
if tt.expErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.args.h, got.Height())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockRPCAPI struct {
|
||||
lk sync.RWMutex
|
||||
tipsets []*types.TipSet
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
m.lk.RLock()
|
||||
defer m.lk.RUnlock()
|
||||
|
||||
return m.tipsets[len(m.tipsets)-1], nil
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
m.lk.RLock()
|
||||
defer m.lk.RUnlock()
|
||||
|
||||
for _, ts := range m.tipsets {
|
||||
if ts.Key() == tsk {
|
||||
return ts, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// createTipSets creates tipsets from genesis up to tskh and returns the highest
|
||||
func (m *mockRPCAPI) createTipSets(h abi.ChainEpoch, genesisTimestamp uint64) *types.TipSet {
|
||||
m.lk.Lock()
|
||||
defer m.lk.Unlock()
|
||||
|
||||
targeth := h + 1 // add one for genesis block
|
||||
if genesisTimestamp == 0 {
|
||||
genesisTimestamp = uint64(time.Now().Unix()) - build.BlockDelaySecs*uint64(targeth)
|
||||
}
|
||||
var currts *types.TipSet
|
||||
for currh := abi.ChainEpoch(0); currh < targeth; currh++ {
|
||||
blks := mock.MkBlock(currts, 1, 1)
|
||||
if currh == 0 {
|
||||
blks.Timestamp = genesisTimestamp
|
||||
}
|
||||
currts = mock.TipSet(blks)
|
||||
m.tipsets = append(m.tipsets, currts)
|
||||
}
|
||||
|
||||
return m.tipsets[len(m.tipsets)-1]
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
m.lk.Lock()
|
||||
defer m.lk.Unlock()
|
||||
|
||||
return m.tipsets[h], nil
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockRPCAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) {
|
||||
panic("implement me")
|
||||
}
|
140
cmd/lotus-gateway/endtoend_test.go
Normal file
140
cmd/lotus-gateway/endtoend_test.go
Normal file
@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
builder "github.com/filecoin-project/lotus/node/test"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/test"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
func TestEndToEnd(t *testing.T) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
blocktime := 5 * time.Millisecond
|
||||
ctx := context.Background()
|
||||
full, lite, closer := startNodes(ctx, t, blocktime)
|
||||
defer closer()
|
||||
|
||||
// The full node starts with a wallet
|
||||
fullWalletAddr, err := full.WalletDefaultAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check the full node's wallet balance from the lite node
|
||||
balance, err := lite.WalletBalance(ctx, fullWalletAddr)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(balance)
|
||||
|
||||
// Create a wallet on the lite node
|
||||
liteWalletAddr, err := lite.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Send some funds from the full node to the lite node
|
||||
err = sendFunds(ctx, t, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Send some funds from the lite node back to the full node
|
||||
err = sendFunds(ctx, t, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
|
||||
require.NoError(t, err)
|
||||
|
||||
data := []byte("hello")
|
||||
sig, err := lite.WalletSign(ctx, liteWalletAddr, data)
|
||||
require.NoError(t, err)
|
||||
|
||||
ok, err := lite.WalletVerify(ctx, liteWalletAddr, data, sig)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
func sendFunds(ctx context.Context, t *testing.T, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error {
|
||||
msg := &types.Message{
|
||||
From: fromAddr,
|
||||
To: toAddr,
|
||||
Value: amt,
|
||||
}
|
||||
|
||||
sm, err := fromNode.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
|
||||
var closer jsonrpc.ClientCloser
|
||||
|
||||
opts := append(
|
||||
// Full node
|
||||
test.OneFull,
|
||||
// Lite node
|
||||
func(nodes []test.TestNode) node.Option {
|
||||
fullNode := nodes[0]
|
||||
|
||||
addr, err := builder.WSMultiAddrToString(fullNode.ListenAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a gateway API that connects to the full node
|
||||
var gapi api.GatewayAPI
|
||||
gapi, closer, err = client.NewGatewayRPC(ctx, addr, nil)
|
||||
require.NoError(t, err)
|
||||
return node.LiteModeOverrides(gapi)
|
||||
},
|
||||
)
|
||||
n, sn := builder.RPCMockSbBuilderWithOpts(t, opts, test.OneMiner)
|
||||
|
||||
full := n[0]
|
||||
lite := n[1]
|
||||
miner := sn[0]
|
||||
|
||||
// Get the listener address for the full node
|
||||
fullAddr, err := full.NetAddrsListen(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Connect the miner and the full node
|
||||
err = miner.NetConnect(ctx, fullAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Start mining blocks
|
||||
bm := test.NewBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.MineBlocks()
|
||||
|
||||
return full, lite, closer
|
||||
}
|
@ -64,8 +64,8 @@ func TestMinerAllInfo(t *testing.T) {
|
||||
require.NoError(t, infoAllCmd.Action(cctx))
|
||||
}
|
||||
|
||||
bp := func(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
n, sn = builder.Builder(t, nFull, storage, opts...)
|
||||
bp := func(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
n, sn = builder.Builder(t, fullOpts, storage, opts...)
|
||||
|
||||
t.Run("pre-info-all", run)
|
||||
|
||||
|
@ -39,7 +39,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/ulimit"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/modules/testing"
|
||||
@ -255,20 +254,7 @@ var DaemonCmd = &cli.Command{
|
||||
}
|
||||
|
||||
defer closer()
|
||||
|
||||
liteMode = node.Options(
|
||||
node.Override(new(api.GatewayAPI), gapi),
|
||||
node.Override(new(full.ChainModuleAPI), node.From(new(api.GatewayAPI))),
|
||||
node.Override(new(full.GasModuleAPI), node.From(new(api.GatewayAPI))),
|
||||
node.Override(new(full.MpoolModuleAPI), node.From(new(api.GatewayAPI))),
|
||||
node.Override(new(full.StateModuleAPI), node.From(new(api.GatewayAPI))),
|
||||
node.Override(new(stmgr.StateManagerAPI), modules.NewRPCStateManager),
|
||||
node.Unset(node.RunHelloKey),
|
||||
node.Unset(node.RunChainExchangeKey),
|
||||
node.Unset(node.RunPeerMgrKey),
|
||||
node.Unset(node.HandleIncomingBlocksKey),
|
||||
node.Unset(node.HandleIncomingMessagesKey),
|
||||
)
|
||||
liteMode = node.LiteModeOverrides(gapi)
|
||||
}
|
||||
|
||||
var api api.FullNode
|
||||
|
@ -264,6 +264,7 @@ func Online() Option {
|
||||
Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule),
|
||||
Override(new(stmgr.StateManagerAPI), From(new(*stmgr.StateManager))),
|
||||
Override(new(*wallet.Wallet), wallet.NewWallet),
|
||||
Override(new(messagesigner.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
|
||||
Override(new(*messagesigner.MessageSigner), messagesigner.NewMessageSigner),
|
||||
|
||||
Override(new(full.ChainModuleAPI), From(new(full.ChainModule))),
|
||||
@ -401,6 +402,23 @@ func StorageMiner(out *api.StorageMiner) Option {
|
||||
)
|
||||
}
|
||||
|
||||
func LiteModeOverrides(gapi api.GatewayAPI) Option {
|
||||
return Options(
|
||||
Override(new(messagesigner.MpoolNonceAPI), From(new(modules.MpoolNonceAPI))),
|
||||
Override(new(api.GatewayAPI), gapi),
|
||||
Override(new(full.ChainModuleAPI), From(new(api.GatewayAPI))),
|
||||
Override(new(full.GasModuleAPI), From(new(api.GatewayAPI))),
|
||||
Override(new(full.MpoolModuleAPI), From(new(api.GatewayAPI))),
|
||||
Override(new(full.StateModuleAPI), From(new(api.GatewayAPI))),
|
||||
Override(new(stmgr.StateManagerAPI), modules.NewRPCStateManager),
|
||||
Unset(RunHelloKey),
|
||||
Unset(RunChainExchangeKey),
|
||||
Unset(RunPeerMgrKey),
|
||||
Unset(HandleIncomingBlocksKey),
|
||||
Unset(HandleIncomingMessagesKey),
|
||||
)
|
||||
}
|
||||
|
||||
// Config sets up constructors based on the provided Config
|
||||
func ConfigCommon(cfg *config.Common) Option {
|
||||
return Options(
|
||||
|
@ -180,7 +180,7 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe
|
||||
|
||||
// Sign and push the message
|
||||
return a.MessageSigner.SignMessage(ctx, msg, func(smsg *types.SignedMessage) error {
|
||||
if _, err := a.Mpool.Push(smsg); err != nil {
|
||||
if _, err := a.MpoolModuleAPI.MpoolPush(ctx, smsg); err != nil {
|
||||
return xerrors.Errorf("mpool push: failed to push message: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
33
node/modules/mpoolnonceapi.go
Normal file
33
node/modules/mpoolnonceapi.go
Normal file
@ -0,0 +1,33 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/messagesigner"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
)
|
||||
|
||||
// MpoolNonceAPI substitutes the mpool nonce with an implementation that
|
||||
// doesn't rely on the mpool - it just gets the nonce from actor state
|
||||
type MpoolNonceAPI struct {
|
||||
fx.In
|
||||
|
||||
StateAPI full.StateAPI
|
||||
}
|
||||
|
||||
// GetNonce gets the nonce from actor state
|
||||
func (a *MpoolNonceAPI) GetNonce(addr address.Address) (uint64, error) {
|
||||
act, err := a.StateAPI.StateGetActor(context.Background(), addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return act.Nonce, nil
|
||||
}
|
||||
|
||||
var _ messagesigner.MpoolNonceAPI = (*MpoolNonceAPI)(nil)
|
@ -7,10 +7,13 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@ -117,6 +120,7 @@ func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Addr
|
||||
if err != nil {
|
||||
t.Fatalf("failed to construct node: %v", err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
/*// Bootstrap with full node
|
||||
@ -137,13 +141,33 @@ func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Addr
|
||||
return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne}
|
||||
}
|
||||
|
||||
func Builder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
func Builder(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return mockBuilderOpts(t, fullOpts, storage, opts, false)
|
||||
}
|
||||
|
||||
func MockSbBuilder(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return mockSbBuilderOpts(t, fullOpts, storage, opts, false)
|
||||
}
|
||||
|
||||
func RPCBuilder(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return mockBuilderOpts(t, fullOpts, storage, opts, true)
|
||||
}
|
||||
|
||||
func RPCMockSbBuilder(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
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) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
fulls := make([]test.TestNode, len(fullOpts))
|
||||
storers := make([]test.TestStorageNode, len(storage))
|
||||
|
||||
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
@ -208,7 +232,7 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.
|
||||
|
||||
// END PRESEAL SECTION
|
||||
|
||||
for i := 0; i < nFull; i++ {
|
||||
for i := 0; i < len(fullOpts); i++ {
|
||||
var genesis node.Option
|
||||
if i == 0 {
|
||||
genesis = node.Override(new(modules.Genesis), testing2.MakeGenesisMem(&genbuf, *templ))
|
||||
@ -224,12 +248,18 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.
|
||||
node.Test(),
|
||||
|
||||
genesis,
|
||||
fullOpts[i](fulls),
|
||||
node.Options(opts...),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
if rpc {
|
||||
fulls[i] = fullRpc(t, fulls[i])
|
||||
}
|
||||
}
|
||||
|
||||
for i, def := range storage {
|
||||
@ -261,6 +291,9 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.
|
||||
|
||||
psd := presealDirs[i]
|
||||
*/
|
||||
if rpc {
|
||||
storers[i] = storerRpc(t, storers[i])
|
||||
}
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
@ -286,11 +319,13 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, options ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
ctx := context.Background()
|
||||
func mockSbBuilderOpts(t *testing.T, fullOpts []test.OptionGenerator, storage []test.StorageMiner, options []node.Option, rpc bool) ([]test.TestNode, []test.TestStorageNode) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
fulls := make([]test.TestNode, len(fullOpts))
|
||||
storers := make([]test.TestStorageNode, len(storage))
|
||||
|
||||
var genbuf bytes.Buffer
|
||||
@ -354,7 +389,7 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, options
|
||||
|
||||
// END PRESEAL SECTION
|
||||
|
||||
for i := 0; i < nFull; i++ {
|
||||
for i := 0; i < len(fullOpts); i++ {
|
||||
var genesis node.Option
|
||||
if i == 0 {
|
||||
genesis = node.Override(new(modules.Genesis), testing2.MakeGenesisMem(&genbuf, *templ))
|
||||
@ -374,12 +409,18 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, options
|
||||
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
|
||||
|
||||
genesis,
|
||||
fullOpts[i](fulls),
|
||||
node.Options(options...),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
if rpc {
|
||||
fulls[i] = fullRpc(t, fulls[i])
|
||||
}
|
||||
}
|
||||
|
||||
for i, def := range storage {
|
||||
@ -414,6 +455,10 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, options
|
||||
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
|
||||
node.Unset(new(*sectorstorage.Manager)),
|
||||
))
|
||||
|
||||
if rpc {
|
||||
storers[i] = storerRpc(t, storers[i])
|
||||
}
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
@ -438,69 +483,66 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, options
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func RPCBuilder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return rpcWithBuilder(t, Builder, nFull, storage, opts...)
|
||||
func fullRpc(t *testing.T, nd test.TestNode) test.TestNode {
|
||||
ma, listenAddr, err := CreateRPCServer(nd)
|
||||
require.NoError(t, err)
|
||||
|
||||
var full test.TestNode
|
||||
full.FullNode, _, err = client.NewFullNodeRPC(context.Background(), listenAddr, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
full.ListenAddr = ma
|
||||
return full
|
||||
}
|
||||
|
||||
func RPCMockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return rpcWithBuilder(t, MockSbBuilder, nFull, storage, opts...)
|
||||
func storerRpc(t *testing.T, nd test.TestStorageNode) test.TestStorageNode {
|
||||
ma, listenAddr, err := CreateRPCServer(nd)
|
||||
require.NoError(t, err)
|
||||
|
||||
var storer test.TestStorageNode
|
||||
storer.StorageMiner, _, err = client.NewStorageMinerRPC(context.Background(), listenAddr, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
storer.ListenAddr = ma
|
||||
storer.MineOne = nd.MineOne
|
||||
return storer
|
||||
}
|
||||
|
||||
func rpcWithBuilder(t *testing.T, b test.APIBuilder, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
||||
fullApis, storaApis := b(t, nFull, storage, opts...)
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, len(storage))
|
||||
func CreateRPCServer(handler interface{}) (multiaddr.Multiaddr, string, error) {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", handler)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
for i, a := range fullApis {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", a)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
addr := testServ.Listener.Addr()
|
||||
listenAddr := "ws://" + addr.String()
|
||||
var err error
|
||||
fulls[i].FullNode, _, err = client.NewFullNodeRPC(context.Background(), listenAddr, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ma, err := parseWSSMultiAddr(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fulls[i].ListenAddr = ma
|
||||
addr := testServ.Listener.Addr()
|
||||
listenAddr := "ws://" + addr.String()
|
||||
ma, err := parseWSMultiAddr(addr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
for i, a := range storaApis {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", a)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
addr := testServ.Listener.Addr()
|
||||
listenAddr := "ws://" + addr.String()
|
||||
var err error
|
||||
storers[i].StorageMiner, _, err = client.NewStorageMinerRPC(context.Background(), listenAddr, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ma, err := parseWSSMultiAddr(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
storers[i].ListenAddr = ma
|
||||
storers[i].MineOne = a.MineOne
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
return ma, listenAddr, err
|
||||
}
|
||||
|
||||
func parseWSSMultiAddr(addr net.Addr) (multiaddr.Multiaddr, error) {
|
||||
func parseWSMultiAddr(addr net.Addr) (multiaddr.Multiaddr, error) {
|
||||
host, port, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ma, err := multiaddr.NewMultiaddr("/ip4/" + host + "/" + addr.Network() + "/" + port + "/wss")
|
||||
ma, err := multiaddr.NewMultiaddr("/ip4/" + host + "/" + addr.Network() + "/" + port + "/ws")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ma, nil
|
||||
}
|
||||
|
||||
func WSMultiAddrToString(addr multiaddr.Multiaddr) (string, error) {
|
||||
parts := strings.Split(addr.String(), "/")
|
||||
if len(parts) != 6 || parts[0] != "" {
|
||||
return "", xerrors.Errorf("Malformed ws multiaddr %s", addr)
|
||||
}
|
||||
|
||||
host := parts[2]
|
||||
port := parts[4]
|
||||
proto := parts[5]
|
||||
|
||||
return proto + "://" + host + ":" + port + "/rpc/v0", nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user