From 2bcedcf55f82677181efe4dc91475bb6b7aeb854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 26 May 2021 00:04:13 +0100 Subject: [PATCH] initial version of the new itest kit. Still need to migrate all integration tests, add godocs, and probably zap bugs. --- itests/api_test.go | 238 ++---- ...tch_deal_test.go => batch_deal_test.go.no} | 0 ...ccupgrade_test.go => ccupgrade_test.go.no} | 1 + itests/{cli_test.go => cli_test.go.no} | 0 ...deadlines_test.go => deadlines_test.go.no} | 0 itests/{deals_test.go => deals_test.go.no} | 28 +- .../{gateway_test.go => gateway_test.go.no} | 2 +- itests/kit/blockminer.go | 6 +- itests/kit/deals.go | 25 +- itests/kit/ensemble.go | 708 ++++++++++++++++++ itests/kit/ensemble_presets.go | 21 + itests/kit/funds.go | 19 +- itests/kit/init.go | 25 + itests/kit/net.go | 125 +--- itests/kit/node_builder.go | 606 --------------- itests/kit/node_full.go | 22 + itests/kit/node_miner.go | 97 +++ itests/kit/nodes.go | 133 ---- itests/kit/pledge.go | 64 -- .../{multisig_test.go => multisig_test.go.no} | 0 ...paych_api_test.go => paych_api_test.go.no} | 0 ...paych_cli_test.go => paych_cli_test.go.no} | 0 ...upgrade_test.go => sdr_upgrade_test.go.no} | 0 ...ledge_test.go => sector_pledge_test.go.no} | 0 ...te_test.go => sector_terminate_test.go.no} | 0 itests/{tape_test.go => tape_test.go.no} | 0 ...pute_test.go => wdpost_dispute_test.go.no} | 0 itests/{wdpost_test.go => wdpost_test.go.no} | 0 28 files changed, 1025 insertions(+), 1095 deletions(-) rename itests/{batch_deal_test.go => batch_deal_test.go.no} (100%) rename itests/{ccupgrade_test.go => ccupgrade_test.go.no} (98%) rename itests/{cli_test.go => cli_test.go.no} (100%) rename itests/{deadlines_test.go => deadlines_test.go.no} (100%) rename itests/{deals_test.go => deals_test.go.no} (94%) rename itests/{gateway_test.go => gateway_test.go.no} (99%) create mode 100644 itests/kit/ensemble.go create mode 100644 itests/kit/ensemble_presets.go create mode 100644 itests/kit/init.go delete mode 100644 itests/kit/node_builder.go create mode 100644 itests/kit/node_full.go create mode 100644 itests/kit/node_miner.go delete mode 100644 itests/kit/nodes.go delete mode 100644 itests/kit/pledge.go rename itests/{multisig_test.go => multisig_test.go.no} (100%) rename itests/{paych_api_test.go => paych_api_test.go.no} (100%) rename itests/{paych_cli_test.go => paych_cli_test.go.no} (100%) rename itests/{sdr_upgrade_test.go => sdr_upgrade_test.go.no} (100%) rename itests/{sector_pledge_test.go => sector_pledge_test.go.no} (100%) rename itests/{sector_terminate_test.go => sector_terminate_test.go.no} (100%) rename itests/{tape_test.go => tape_test.go.no} (100%) rename itests/{wdpost_dispute_test.go => wdpost_dispute_test.go.no} (100%) rename itests/{wdpost_test.go => wdpost_test.go.no} (100%) diff --git a/itests/api_test.go b/itests/api_test.go index ee70a337b..22bbc6f6e 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -8,33 +8,30 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/node/impl" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestAPI(t *testing.T) { t.Run("direct", func(t *testing.T) { - runAPITest(t, kit.Builder) + runAPITest(t) }) t.Run("rpc", func(t *testing.T) { - runAPITest(t, kit.RPCBuilder) + runAPITest(t, kit.ThroughRPC()) }) } type apiSuite struct { - makeNodes kit.APIBuilder + opts []kit.NodeOpt } // runAPITest is the entry point to API test suite -func runAPITest(t *testing.T, b kit.APIBuilder) { - ts := apiSuite{ - makeNodes: b, - } +func runAPITest(t *testing.T, opts ...kit.NodeOpt) { + ts := apiSuite{opts: opts} t.Run("version", ts.testVersion) t.Run("id", ts.testID) @@ -51,145 +48,114 @@ func (ts *apiSuite) testVersion(t *testing.T) { lapi.RunningNodeType = lapi.NodeUnknown }) - ctx := context.Background() - apis, _ := ts.makeNodes(t, kit.OneFull, kit.OneMiner) - napi := apis[0] + full, _, _ := kit.EnsembleMinimum(t, ts.opts...) + + v, err := full.Version(context.Background()) + require.NoError(t, err) - v, err := napi.Version(ctx) - if err != nil { - t.Fatal(err) - } versions := strings.Split(v.Version, "+") - if len(versions) <= 0 { - t.Fatal("empty version") - } + require.NotZero(t, len(versions), "empty version") require.Equal(t, versions[0], build.BuildVersion) } -func (ts *apiSuite) testSearchMsg(t *testing.T) { - apis, miners := ts.makeNodes(t, kit.OneFull, kit.OneMiner) +func (ts *apiSuite) testID(t *testing.T) { + ctx := context.Background() - api := apis[0] - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - senderAddr, err := api.WalletDefaultAddress(ctx) + full, _, _ := kit.EnsembleMinimum(t, ts.opts...) + + id, err := full.ID(ctx) if err != nil { t.Fatal(err) } + require.Regexp(t, "^12", id.Pretty()) +} + +func (ts *apiSuite) testConnectTwo(t *testing.T) { + ctx := context.Background() + + one, two, _, ens := kit.EnsembleTwo(t, ts.opts...) + + p, err := one.NetPeers(ctx) + require.NoError(t, err) + require.Empty(t, p, "node one has peers") + + p, err = two.NetPeers(ctx) + require.NoError(t, err) + require.Empty(t, p, "node two has peers") + + ens.InterconnectAll() + + peers, err := one.NetPeers(ctx) + require.NoError(t, err) + require.Lenf(t, peers, 1, "node one doesn't have 1 peer") + + peers, err = two.NetPeers(ctx) + require.NoError(t, err) + require.Lenf(t, peers, 1, "node two doesn't have 1 peer") +} + +func (ts *apiSuite) testSearchMsg(t *testing.T) { + ctx := context.Background() + + full, _, ens := kit.EnsembleMinimum(t, ts.opts...) + + senderAddr, err := full.WalletDefaultAddress(ctx) + require.NoError(t, err) msg := &types.Message{ From: senderAddr, To: senderAddr, Value: big.Zero(), } - bm := kit.NewBlockMiner(t, miners[0]) - bm.MineBlocks(ctx, 100*time.Millisecond) - defer bm.Stop() - sm, err := api.MpoolPushMessage(ctx, msg, nil) - if err != nil { - t.Fatal(err) - } - res, err := api.StateWaitMsg(ctx, sm.Cid(), 1, lapi.LookbackNoLimit, true) - if err != nil { - t.Fatal(err) - } - if res.Receipt.ExitCode != 0 { - t.Fatal("did not successfully send message") - } + ens.BeginMining(100 * time.Millisecond) - searchRes, err := api.StateSearchMsg(ctx, types.EmptyTSK, sm.Cid(), lapi.LookbackNoLimit, true) - if err != nil { - t.Fatal(err) - } + sm, err := full.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) - if searchRes.TipSet != res.TipSet { - t.Fatalf("search ts: %s, different from wait ts: %s", searchRes.TipSet, res.TipSet) - } + res, err := full.StateWaitMsg(ctx, sm.Cid(), 1, lapi.LookbackNoLimit, true) + require.NoError(t, err) -} + require.Equal(t, exitcode.Ok, res.Receipt.ExitCode, "message not successful") -func (ts *apiSuite) testID(t *testing.T) { - ctx := context.Background() - apis, _ := ts.makeNodes(t, kit.OneFull, kit.OneMiner) - api := apis[0] + searchRes, err := full.StateSearchMsg(ctx, types.EmptyTSK, sm.Cid(), lapi.LookbackNoLimit, true) + require.NoError(t, err) - id, err := api.ID(ctx) - if err != nil { - t.Fatal(err) - } - assert.Regexp(t, "^12", id.Pretty()) -} - -func (ts *apiSuite) testConnectTwo(t *testing.T) { - ctx := context.Background() - apis, _ := ts.makeNodes(t, kit.TwoFull, kit.OneMiner) - - p, err := apis[0].NetPeers(ctx) - if err != nil { - t.Fatal(err) - } - if len(p) != 0 { - t.Error("Node 0 has a peer") - } - - p, err = apis[1].NetPeers(ctx) - if err != nil { - t.Fatal(err) - } - if len(p) != 0 { - t.Error("Node 1 has a peer") - } - - addrs, err := apis[1].NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := apis[0].NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - p, err = apis[0].NetPeers(ctx) - if err != nil { - t.Fatal(err) - } - if len(p) != 1 { - t.Error("Node 0 doesn't have 1 peer") - } - - p, err = apis[1].NetPeers(ctx) - if err != nil { - t.Fatal(err) - } - if len(p) != 1 { - t.Error("Node 0 doesn't have 1 peer") - } + require.Equalf(t, res.TipSet, searchRes.TipSet, "search ts: %s, different from wait ts: %s", searchRes.TipSet, res.TipSet) } func (ts *apiSuite) testMining(t *testing.T) { ctx := context.Background() - fulls, miners := ts.makeNodes(t, kit.OneFull, kit.OneMiner) - api := fulls[0] - newHeads, err := api.ChainNotify(ctx) + full, miner, _ := kit.EnsembleMinimum(t, ts.opts...) + + newHeads, err := full.ChainNotify(ctx) require.NoError(t, err) initHead := (<-newHeads)[0] baseHeight := initHead.Val.Height() - h1, err := api.ChainHead(ctx) + h1, err := full.ChainHead(ctx) require.NoError(t, err) require.Equal(t, int64(h1.Height()), int64(baseHeight)) - bm := kit.NewBlockMiner(t, miners[0]) - bm.MineUntilBlock(ctx, fulls[0], nil) + bm := kit.NewBlockMiner(t, miner) + bm.MineUntilBlock(ctx, full, nil) require.NoError(t, err) <-newHeads - h2, err := api.ChainHead(ctx) + h2, err := full.ChainHead(ctx) require.NoError(t, err) require.Greater(t, int64(h2.Height()), int64(h1.Height())) + + bm.MineUntilBlock(ctx, full, nil) + require.NoError(t, err) + + <-newHeads + + h3, err := full.ChainHead(ctx) + require.NoError(t, err) + require.Greater(t, int64(h3.Height()), int64(h2.Height())) } func (ts *apiSuite) testMiningReal(t *testing.T) { @@ -198,66 +164,26 @@ func (ts *apiSuite) testMiningReal(t *testing.T) { build.InsecurePoStValidation = true }() - ctx := context.Background() - fulls, miners := ts.makeNodes(t, kit.OneFull, kit.OneMiner) - api := fulls[0] - - newHeads, err := api.ChainNotify(ctx) - require.NoError(t, err) - at := (<-newHeads)[0].Val.Height() - - h1, err := api.ChainHead(ctx) - require.NoError(t, err) - require.Equal(t, int64(at), int64(h1.Height())) - - bm := kit.NewBlockMiner(t, miners[0]) - - bm.MineUntilBlock(ctx, fulls[0], nil) - require.NoError(t, err) - - <-newHeads - - h2, err := api.ChainHead(ctx) - require.NoError(t, err) - require.Greater(t, int64(h2.Height()), int64(h1.Height())) - - bm.MineUntilBlock(ctx, fulls[0], nil) - require.NoError(t, err) - - <-newHeads - - h3, err := api.ChainHead(ctx) - require.NoError(t, err) - require.Greater(t, int64(h3.Height()), int64(h2.Height())) + ts.testMining(t) } func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { ctx := context.Background() - n, sn := ts.makeNodes(t, - []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1)}, - []kit.StorageMiner{{Full: 0, Preseal: kit.PresealGenesis}}, - ) - full, ok := n[0].FullNode.(*impl.FullNodeAPI) - if !ok { - t.Skip("not testing with a full node") - return - } - genesisMiner := sn[0] + full, genesisMiner, ens := kit.EnsembleMinimum(t, ts.opts...) - bm := kit.NewBlockMiner(t, genesisMiner) - bm.MineBlocks(ctx, 4*time.Millisecond) - t.Cleanup(bm.Stop) + ens.BeginMining(4 * time.Millisecond) gaa, err := genesisMiner.ActorAddress(ctx) require.NoError(t, err) - gmi, err := full.StateMinerInfo(ctx, gaa, types.EmptyTSK) + _, err = full.StateMinerInfo(ctx, gaa, types.EmptyTSK) require.NoError(t, err) - testm := n[0].Stb(ctx, t, kit.TestSpt, gmi.Owner) + var newMiner kit.TestMiner + ens.Miner(&newMiner, full, kit.OwnerAddr(full.DefaultKey)).Start() - ta, err := testm.ActorAddress(ctx) + ta, err := newMiner.ActorAddress(ctx) require.NoError(t, err) tid, err := address.IDFromAddress(ta) diff --git a/itests/batch_deal_test.go b/itests/batch_deal_test.go.no similarity index 100% rename from itests/batch_deal_test.go rename to itests/batch_deal_test.go.no diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go.no similarity index 98% rename from itests/ccupgrade_test.go rename to itests/ccupgrade_test.go.no index 28abac171..f6ba87820 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go.no @@ -8,6 +8,7 @@ import ( "time" "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-state-types/abi" diff --git a/itests/cli_test.go b/itests/cli_test.go.no similarity index 100% rename from itests/cli_test.go rename to itests/cli_test.go.no diff --git a/itests/deadlines_test.go b/itests/deadlines_test.go.no similarity index 100% rename from itests/deadlines_test.go rename to itests/deadlines_test.go.no diff --git a/itests/deals_test.go b/itests/deals_test.go.no similarity index 94% rename from itests/deals_test.go rename to itests/deals_test.go.no index a7599a8b7..f34aea91d 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go.no @@ -20,6 +20,7 @@ import ( "github.com/filecoin-project/lotus/miner" "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/impl" + "github.com/filecoin-project/lotus/node/impl/client" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" "github.com/stretchr/testify/require" ) @@ -66,15 +67,15 @@ func TestAPIDealFlowReal(t *testing.T) { }) t.Run("basic", func(t *testing.T) { - runFullDealCycles(t, 1, kit.Builder, time.Second, false, false, 0) + runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, false, 0) }) t.Run("fast-retrieval", func(t *testing.T) { - runFullDealCycles(t, 1, kit.Builder, time.Second, false, true, 0) + runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, true, 0) }) t.Run("retrieval-second", func(t *testing.T) { - runSecondDealRetrievalTest(t, kit.Builder, time.Second) + runSecondDealRetrievalTest(t, kit.FullNodeBuilder, time.Second) }) } @@ -309,6 +310,7 @@ func TestDealMining(t *testing.T) { } func runFullDealCycles(t *testing.T, n int, b kit.APIBuilder, blocktime time.Duration, carExport, fastRet bool, startEpoch abi.ChainEpoch) { + fulls, miners := b(t, kit.OneFull, kit.OneMiner) client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] @@ -325,21 +327,23 @@ func runFullDealCycles(t *testing.T, n int, b kit.APIBuilder, blocktime time.Dur func runFastRetrievalDealFlowT(t *testing.T, b kit.APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch) { ctx := context.Background() - fulls, miners := b(t, kit.OneFull, kit.OneMiner) - client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] + var ( + nb = kit.NewNodeBuilder(t) + full = nb.FullNode() + miner = nb.Miner(full) + ) - kit.ConnectAndStartMining(t, blocktime, miner, client) + nb.Create() - dh := kit.NewDealHarness(t, client, miner) + kit.ConnectAndStartMining(t, blocktime, miner, full) + dh := kit.NewDealHarness(t, full, miner) data := make([]byte, 1600) rand.New(rand.NewSource(int64(8))).Read(data) r := bytes.NewReader(data) - fcid, err := client.ClientImportLocal(ctx, r) - if err != nil { - t.Fatal(err) - } + fcid, err := full.FullNode.(*impl.FullNodeAPI).ClientImportLocal(ctx, r) + require.NoError(t, err) fmt.Println("FILE CID: ", fcid) @@ -349,7 +353,7 @@ func runFastRetrievalDealFlowT(t *testing.T, b kit.APIBuilder, blocktime time.Du fmt.Println("deal published, retrieving") // Retrieval - info, err := client.ClientGetDealInfo(ctx, *deal) + info, err := full.ClientGetDealInfo(ctx, *deal) require.NoError(t, err) dh.TestRetrieval(ctx, fcid, &info.PieceCID, false, data) diff --git a/itests/gateway_test.go b/itests/gateway_test.go.no similarity index 99% rename from itests/gateway_test.go rename to itests/gateway_test.go.no index 5c7fc4be0..d532f3423 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go.no @@ -291,7 +291,7 @@ func startNodes( }, }, ) - n, sn := kit.RPCMockMinerBuilder(t, opts, kit.OneMiner) + n, sn := kit.MinerRPCMockMinerBuilder(t, opts, kit.OneMiner) full := n[0] lite := n[1] diff --git a/itests/kit/blockminer.go b/itests/kit/blockminer.go index 3b1f1fedf..b7951c4f8 100644 --- a/itests/kit/blockminer.go +++ b/itests/kit/blockminer.go @@ -15,14 +15,14 @@ import ( // BlockMiner is a utility that makes a test miner Mine blocks on a timer. type BlockMiner struct { t *testing.T - miner TestMiner + miner *TestMiner nextNulls int64 wg sync.WaitGroup cancel context.CancelFunc } -func NewBlockMiner(t *testing.T, miner TestMiner) *BlockMiner { +func NewBlockMiner(t *testing.T, miner *TestMiner) *BlockMiner { return &BlockMiner{ t: t, miner: miner, @@ -69,7 +69,7 @@ func (bm *BlockMiner) InjectNulls(rounds abi.ChainEpoch) { atomic.AddInt64(&bm.nextNulls, int64(rounds)) } -func (bm *BlockMiner) MineUntilBlock(ctx context.Context, fn TestFullNode, cb func(abi.ChainEpoch)) { +func (bm *BlockMiner) MineUntilBlock(ctx context.Context, fn *TestFullNode, cb func(abi.ChainEpoch)) { for i := 0; i < 1000; i++ { var ( success bool diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 986cda39c..2a1ca5ba5 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -31,11 +31,11 @@ import ( type DealHarness struct { t *testing.T client api.FullNode - miner TestMiner + miner *TestMiner } // NewDealHarness creates a test harness that contains testing utilities for deals. -func NewDealHarness(t *testing.T, client api.FullNode, miner TestMiner) *DealHarness { +func NewDealHarness(t *testing.T, client api.FullNode, miner *TestMiner) *DealHarness { return &DealHarness{ t: t, client: client, @@ -252,27 +252,6 @@ type DealsScaffold struct { BlockMiner *BlockMiner } -func ConnectAndStartMining(t *testing.T, blocktime time.Duration, miner TestMiner, clients ...api.FullNode) *BlockMiner { - ctx := context.Background() - - for _, c := range clients { - addrinfo, err := c.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - } - - time.Sleep(time.Second) - - blockMiner := NewBlockMiner(t, miner) - blockMiner.MineBlocks(ctx, blocktime) - - return blockMiner -} - type TestDealState int const ( diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go new file mode 100644 index 000000000..90a09c82b --- /dev/null +++ b/itests/kit/ensemble.go @@ -0,0 +1,708 @@ +package kit + +import ( + "bytes" + "context" + "crypto/rand" + "io/ioutil" + "net/http" + "net/http/httptest" + "sync" + "testing" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc/auth" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-storedcounter" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/gen" + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" + sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" + "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" + "github.com/filecoin-project/lotus/extern/sector-storage/mock" + "github.com/filecoin-project/lotus/genesis" + lotusminer "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" + testing2 "github.com/filecoin-project/lotus/node/modules/testing" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage/mockstorage" + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" + "github.com/ipfs/go-datastore" + libp2pcrypto "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/stretchr/testify/require" +) + +func init() { + chain.BootstrapPeerThreshold = 1 + messagepool.HeadChangeCoalesceMinDelay = time.Microsecond + messagepool.HeadChangeCoalesceMaxDelay = 2 * time.Microsecond + messagepool.HeadChangeCoalesceMergeInterval = 100 * time.Nanosecond +} + +type BuilderOpt func(opts *BuilderOpts) error + +type BuilderOpts struct { + pastOffset time.Duration + spt abi.RegisteredSealProof +} + +var DefaultBuilderOpts = BuilderOpts{ + pastOffset: 10000 * time.Second, + spt: abi.RegisteredSealProof_StackedDrg2KiBV1, +} + +func ProofType(proofType abi.RegisteredSealProof) BuilderOpt { + return func(opts *BuilderOpts) error { + opts.spt = proofType + return nil + } +} + +// Ensemble is a collection of nodes instantiated within a test. Ensemble +// supports building full nodes and miners. +type Ensemble struct { + t *testing.T + bootstrapped bool + genesisBlock bytes.Buffer + mn mocknet.Mocknet + options *BuilderOpts + + inactive struct { + fullnodes []*TestFullNode + miners []*TestMiner + } + active struct { + fullnodes []*TestFullNode + miners []*TestMiner + } + genesis struct { + miners []genesis.Miner + accounts []genesis.Actor + } +} + +// NewEnsemble +func NewEnsemble(t *testing.T, opts ...BuilderOpt) *Ensemble { + options := DefaultBuilderOpts + for _, o := range opts { + err := o(&options) + require.NoError(t, err) + } + return &Ensemble{t: t, options: &options} +} + +type NodeOpts struct { + balance abi.TokenAmount + lite bool + sectors int + mockProofs bool + rpc bool + ownerKey *wallet.Key +} + +var DefaultNodeOpts = NodeOpts{ + balance: big.Mul(big.NewInt(100000000), types.NewInt(build.FilecoinPrecision)), + sectors: 2, +} + +type NodeOpt func(opts *NodeOpts) error + +// OwnerBalance specifies the balance to be attributed to a miner's owner account. +// +// Only used when creating a miner. +func OwnerBalance(balance abi.TokenAmount) NodeOpt { + return func(opts *NodeOpts) error { + opts.balance = balance + return nil + } +} + +// LiteNode specifies that this node will be a lite node. +// +// Only used when creating a fullnode. +func LiteNode() NodeOpt { + return func(opts *NodeOpts) error { + opts.lite = true + return nil + } +} + +// PresealSectors specifies the amount of preseal sectors to give to a miner +// at genesis. +// +// Only used when creating a miner. +func PresealSectors(sectors int) NodeOpt { + return func(opts *NodeOpts) error { + opts.sectors = sectors + return nil + } +} + +// MockProofs activates mock proofs for the entire ensemble. +func MockProofs() NodeOpt { + return func(opts *NodeOpts) error { + opts.mockProofs = true + return nil + } +} + +func ThroughRPC() NodeOpt { + return func(opts *NodeOpts) error { + opts.rpc = true + return nil + } +} + +func OwnerAddr(wk *wallet.Key) NodeOpt { + return func(opts *NodeOpts) error { + opts.ownerKey = wk + return nil + } +} + +// FullNode enrolls a new full node. +func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { + options := DefaultNodeOpts + for _, o := range opts { + err := o(&options) + require.NoError(n.t, err) + } + + var key *wallet.Key + if !n.bootstrapped && !options.balance.IsZero() { + // create a key+ddress, and assign it some FIL. + // this will be set as the default wallet. + var err error + key, err = wallet.GenerateKey(types.KTBLS) + require.NoError(n.t, err) + + genacc := genesis.Actor{ + Type: genesis.TAccount, + Balance: options.balance, + Meta: (&genesis.AccountMeta{Owner: key.Address}).ActorMeta(), + } + + n.genesis.accounts = append(n.genesis.accounts, genacc) + } + + *full = TestFullNode{options: options, DefaultKey: key} + n.inactive.fullnodes = append(n.inactive.fullnodes, full) + return n +} + +// Miner enrolls a new miner, using the provided full node for chain +// interactions. +func (n *Ensemble) Miner(miner *TestMiner, full *TestFullNode, opts ...NodeOpt) *Ensemble { + require.NotNil(n.t, full, "full node required when instantiating miner") + + options := DefaultNodeOpts + for _, o := range opts { + err := o(&options) + require.NoError(n.t, err) + } + + privkey, _, err := libp2pcrypto.GenerateEd25519Key(rand.Reader) + require.NoError(n.t, err) + + peerId, err := peer.IDFromPrivateKey(privkey) + require.NoError(n.t, err) + + tdir, err := ioutil.TempDir("", "preseal-memgen") + require.NoError(n.t, err) + + minerCnt := len(n.inactive.miners) + len(n.active.miners) + + actorAddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(minerCnt)) + require.NoError(n.t, err) + + ownerKey := options.ownerKey + if !n.bootstrapped { + var ( + sectors = options.sectors + k *types.KeyInfo + genm *genesis.Miner + ) + + // create the preseal commitment. + if options.mockProofs { + genm, k, err = mockstorage.PreSeal(abi.RegisteredSealProof_StackedDrg2KiBV1, actorAddr, sectors) + } else { + genm, k, err = seed.PreSeal(actorAddr, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, sectors, tdir, []byte("make genesis mem random"), nil, true) + } + require.NoError(n.t, err) + + genm.PeerId = peerId + + // create an owner key, and assign it some FIL. + ownerKey, err = wallet.NewKey(*k) + require.NoError(n.t, err) + + genacc := genesis.Actor{ + Type: genesis.TAccount, + Balance: options.balance, + Meta: (&genesis.AccountMeta{Owner: ownerKey.Address}).ActorMeta(), + } + + n.genesis.miners = append(n.genesis.miners, *genm) + n.genesis.accounts = append(n.genesis.accounts, genacc) + } else { + require.NotNil(n.t, ownerKey, "worker key can't be null if initializing a miner after genesis") + } + + *miner = TestMiner{ + ActorAddr: actorAddr, + OwnerKey: ownerKey, + FullNode: full, + PresealDir: tdir, + options: options, + } + + miner.Libp2p.PeerID = peerId + miner.Libp2p.PrivKey = privkey + + n.inactive.miners = append(n.inactive.miners, miner) + + return n +} + +// Start starts all enrolled nodes. +func (n *Ensemble) Start() *Ensemble { + ctx, cancel := context.WithCancel(context.Background()) + n.t.Cleanup(cancel) + + var gtempl *genesis.Template + if !n.bootstrapped { + // We haven't been bootstrapped yet, we need to generate genesis and + // create the networking backbone. + gtempl = n.generateGenesis() + n.mn = mocknet.New(ctx) + } + + // Create all inactive full nodes. + for i, full := range n.inactive.fullnodes { + opts := []node.Option{ + node.FullAPI(&full.FullNode, node.Lite(full.options.lite)), + node.Online(), + node.Repo(repo.NewMemory(nil)), + node.MockHost(n.mn), + node.Test(), + + // so that we subscribe to pubsub topics immediately + node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), + } + + // Either generate the genesis or inject it. + if i == 0 && !n.bootstrapped { + opts = append(opts, node.Override(new(modules.Genesis), testing2.MakeGenesisMem(&n.genesisBlock, *gtempl))) + } else { + opts = append(opts, node.Override(new(modules.Genesis), modules.LoadGenesis(n.genesisBlock.Bytes()))) + } + + // Are we mocking proofs? + if full.options.mockProofs { + opts = append(opts, node.Override(new(ffiwrapper.Verifier), mock.MockVerifier)) + } + + // Construct the full node. + stop, err := node.New(ctx, opts...) + + // fullOpts[i].Opts(fulls), + require.NoError(n.t, err) + + addr, err := full.WalletImport(context.Background(), &full.DefaultKey.KeyInfo) + require.NoError(n.t, err) + + err = full.WalletSetDefault(context.Background(), addr) + require.NoError(n.t, err) + + // Are we hitting this node through its RPC? + if full.options.rpc { + withRPC := fullRpc(n.t, full) + n.inactive.fullnodes[i] = withRPC + } + + n.t.Cleanup(func() { _ = stop(context.Background()) }) + + n.active.fullnodes = append(n.active.fullnodes, full) + } + + // If we are here, we have processed all inactive fullnodes and moved them + // to active, so clear the slice. + n.inactive.fullnodes = n.inactive.fullnodes[:0] + + // Link all the nodes. + err := n.mn.LinkAll() + require.NoError(n.t, err) + + // Create all inactive miners. + for i, m := range n.inactive.miners { + if n.bootstrapped { + // this is a miner created after genesis, so it won't have a preseal. + // we need to create it on chain. + params, aerr := actors.SerializeParams(&power2.CreateMinerParams{ + Owner: m.OwnerKey.Address, + Worker: m.OwnerKey.Address, + SealProofType: n.options.spt, + Peer: abi.PeerID(m.Libp2p.PeerID), + }) + require.NoError(n.t, aerr) + + createStorageMinerMsg := &types.Message{ + From: m.OwnerKey.Address, + To: power.Address, + Value: big.Zero(), + + Method: power.Methods.CreateMiner, + Params: params, + + GasLimit: 0, + GasPremium: big.NewInt(5252), + } + signed, err := m.FullNode.FullNode.MpoolPushMessage(ctx, createStorageMinerMsg, nil) + require.NoError(n.t, err) + + mw, err := m.FullNode.FullNode.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence, api.LookbackNoLimit, true) + require.NoError(n.t, err) + require.Equal(n.t, exitcode.Ok, mw.Receipt.ExitCode) + + var retval power2.CreateMinerReturn + err = retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)) + require.NoError(n.t, err, "failed to create miner") + + m.ActorAddr = retval.IDAddress + } + + has, err := m.FullNode.WalletHas(ctx, m.OwnerKey.Address) + require.NoError(n.t, err) + + // Only import the owner's full key into our companion full node, if we + // don't have it still. + if !has { + _, err = m.FullNode.WalletImport(ctx, &m.OwnerKey.KeyInfo) + require.NoError(n.t, err) + } + + // // Set it as the default address. + // err = m.FullNode.WalletSetDefault(ctx, m.OwnerAddr.Address) + // require.NoError(n.t, err) + + r := repo.NewMemory(nil) + + lr, err := r.Lock(repo.StorageMiner) + require.NoError(n.t, err) + + ks, err := lr.KeyStore() + require.NoError(n.t, err) + + pk, err := m.Libp2p.PrivKey.Bytes() + require.NoError(n.t, err) + + err = ks.Put("libp2p-host", types.KeyInfo{ + Type: "libp2p-host", + PrivateKey: pk, + }) + require.NoError(n.t, err) + + ds, err := lr.Datastore(context.TODO(), "/metadata") + require.NoError(n.t, err) + + err = ds.Put(datastore.NewKey("miner-address"), m.ActorAddr.Bytes()) + require.NoError(n.t, err) + + nic := storedcounter.New(ds, datastore.NewKey(modules.StorageCounterDSPrefix)) + for i := 0; i < m.options.sectors; i++ { + _, err := nic.Next() + require.NoError(n.t, err) + } + _, err = nic.Next() + require.NoError(n.t, err) + + err = lr.Close() + require.NoError(n.t, err) + + enc, err := actors.SerializeParams(&miner2.ChangePeerIDParams{NewID: abi.PeerID(m.Libp2p.PeerID)}) + require.NoError(n.t, err) + + msg := &types.Message{ + From: m.OwnerKey.Address, + To: m.ActorAddr, + Method: miner.Methods.ChangePeerID, + Params: enc, + Value: types.NewInt(0), + } + + _, err = m.FullNode.MpoolPushMessage(ctx, msg, nil) + require.NoError(n.t, err) + + var mineBlock = make(chan lotusminer.MineReq) + opts := []node.Option{ + node.StorageMiner(&m.StorageMiner), + node.Online(), + node.Repo(r), + node.Test(), + + node.MockHost(n.mn), + + node.Override(new(v1api.FullNode), m.FullNode), + node.Override(new(*lotusminer.Miner), lotusminer.NewTestMiner(mineBlock, m.ActorAddr)), + } + + idAddr, err := address.IDFromAddress(m.ActorAddr) + require.NoError(n.t, err) + + if !n.bootstrapped && m.options.mockProofs { + s := n.genesis.miners[i].Sectors + sectors := make([]abi.SectorID, len(s)) + for i, sector := range s { + sectors[i] = abi.SectorID{ + Miner: abi.ActorID(idAddr), + Number: sector.SectorID, + } + } + opts = append(opts, + node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { + return mock.NewMockSectorMgr(sectors), nil + }), + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Unset(new(*sectorstorage.Manager)), + ) + } + + // start node + stop, err := node.New(ctx, opts...) + require.NoError(n.t, err) + + // using real proofs, therefore need real sectors. + if !n.bootstrapped && !m.options.mockProofs { + err := m.StorageAddLocal(ctx, m.PresealDir) + require.NoError(n.t, err) + } + + n.t.Cleanup(func() { _ = stop(context.Background()) }) + + // Are we hitting this node through its RPC? + if m.options.rpc { + withRPC := minerRpc(n.t, m) + n.inactive.miners[i] = withRPC + } + + mineOne := func(ctx context.Context, req lotusminer.MineReq) error { + select { + case mineBlock <- req: + return nil + case <-ctx.Done(): + return ctx.Err() + } + } + + m.MineOne = mineOne + m.Stop = stop + + n.active.miners = append(n.active.miners, m) + } + + // If we are here, we have processed all inactive miners and moved them + // to active, so clear the slice. + n.inactive.miners = n.inactive.miners[:0] + + // Link all the nodes. + err = n.mn.LinkAll() + require.NoError(n.t, err) + + if !n.bootstrapped && len(n.active.miners) > 0 { + // We have *just* bootstrapped, so + // mine 2 blocks to setup some CE stuff + // in some actors + var wait sync.Mutex + wait.Lock() + + observer := n.active.fullnodes[0] + + bm := NewBlockMiner(n.t, n.active.miners[0]) + n.t.Cleanup(bm.Stop) + + bm.MineUntilBlock(ctx, observer, func(epoch abi.ChainEpoch) { + wait.Unlock() + }) + wait.Lock() + bm.MineUntilBlock(ctx, observer, func(epoch abi.ChainEpoch) { + wait.Unlock() + }) + wait.Lock() + } + + n.bootstrapped = true + return n +} + +// InterconnectAll connects all full nodes one to another. We do not need to +// take action with miners, because miners only stay connected to their full +// nodes over JSON-RPC. +func (n *Ensemble) InterconnectAll() *Ensemble { + last := len(n.active.fullnodes) - 1 + for i, from := range n.active.fullnodes { + if i == last { + continue + } + n.Connect(from, n.active.fullnodes[i+1:]...) + } + return n +} + +// Connect connects one full node to the provided full nodes. +func (n *Ensemble) Connect(from *TestFullNode, to ...*TestFullNode) *Ensemble { + addr, err := from.NetAddrsListen(context.Background()) + require.NoError(n.t, err) + + for _, other := range to { + err = other.NetConnect(context.Background(), addr) + require.NoError(n.t, err) + } + return n +} + +// BeginMining kicks off mining for the specified miners. If nil or 0-length, +// it will kick off mining for all enrolled and active miners. +func (n *Ensemble) BeginMining(blocktime time.Duration, miners ...*TestMiner) []*BlockMiner { + ctx := context.Background() + + // wait one second to make sure that nodes are connected and have handshaken. + // TODO make this deterministic by listening to identify events on the + // libp2p eventbus instead (or something else). + time.Sleep(1 * time.Second) + + var bms []*BlockMiner + if len(miners) == 0 { + miners = n.active.miners + } + + for _, m := range miners { + bm := NewBlockMiner(n.t, m) + bm.MineBlocks(ctx, blocktime) + bms = append(bms, bm) + } + + return bms +} + +func (n *Ensemble) generateGenesis() *genesis.Template { + templ := &genesis.Template{ + Accounts: n.genesis.accounts, + Miners: n.genesis.miners, + NetworkName: "test", + Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past + VerifregRootKey: gen.DefaultVerifregRootkeyActor, + RemainderAccount: gen.DefaultRemainderAccountActor, + } + + return templ +} + +func CreateRPCServer(t *testing.T, handler http.Handler) (*httptest.Server, multiaddr.Multiaddr) { + testServ := httptest.NewServer(handler) + t.Cleanup(testServ.Close) + t.Cleanup(testServ.CloseClientConnections) + + addr := testServ.Listener.Addr() + maddr, err := manet.FromNetAddr(addr) + require.NoError(t, err) + return testServ, maddr +} + +func fullRpc(t *testing.T, f *TestFullNode) *TestFullNode { + tok, err := f.FullNode.AuthNew(context.Background(), []auth.Permission{"admin", "read", "write", "sign"}) + require.NoError(t, err) + + handler, err := node.FullNodeHandler(f.FullNode) + require.NoError(t, err) + + srv, maddr := CreateRPCServer(t, handler) + + cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", map[string][]string{ + "Authorization": {"Bearer " + string(tok)}, + }) + require.NoError(t, err) + t.Cleanup(stop) + f.ListenAddr, f.FullNode = maddr, cl + + return f +} + +func minerRpc(t *testing.T, m *TestMiner) *TestMiner { + tok, err := m.StorageMiner.AuthNew(context.Background(), []auth.Permission{"admin", "read", "write"}) + require.NoError(t, err) + + handler, err := node.MinerHandler(m.StorageMiner) + require.NoError(t, err) + + srv, maddr := CreateRPCServer(t, handler) + + cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v0", map[string][]string{ + "Authorization": {"Bearer " + string(tok)}, + }) + require.NoError(t, err) + t.Cleanup(stop) + + m.ListenAddr, m.StorageMiner = maddr, cl + return m +} + +func LatestActorsAt(upgradeHeight abi.ChainEpoch) node.Option { + if upgradeHeight == -1 { + upgradeHeight = 3 + } + + return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ + // prepare for upgrade. + Network: network.Version9, + Height: 1, + Migration: stmgr.UpgradeActorsV2, + }, { + Network: network.Version10, + Height: 2, + Migration: stmgr.UpgradeActorsV3, + }, { + Network: network.Version12, + Height: upgradeHeight, + Migration: stmgr.UpgradeActorsV4, + }}) +} + +func SDRUpgradeAt(calico, persian abi.ChainEpoch) node.Option { + return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ + Network: network.Version6, + Height: 1, + Migration: stmgr.UpgradeActorsV2, + }, { + Network: network.Version7, + Height: calico, + Migration: stmgr.UpgradeCalico, + }, { + Network: network.Version8, + Height: persian, + }}) + +} diff --git a/itests/kit/ensemble_presets.go b/itests/kit/ensemble_presets.go new file mode 100644 index 000000000..debad2ed1 --- /dev/null +++ b/itests/kit/ensemble_presets.go @@ -0,0 +1,21 @@ +package kit + +import "testing" + +func EnsembleMinimum(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestMiner, *Ensemble) { + var ( + full TestFullNode + miner TestMiner + ) + ensemble := NewEnsemble(t).FullNode(&full, opts...).Miner(&miner, &full, opts...).Start() + return &full, &miner, ensemble +} + +func EnsembleTwo(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestFullNode, *TestMiner, *Ensemble) { + var ( + one, two TestFullNode + miner TestMiner + ) + ensemble := NewEnsemble(t).FullNode(&one, opts...).FullNode(&two, opts...).Miner(&miner, &one, opts...).Start() + return &one, &two, &miner, ensemble +} diff --git a/itests/kit/funds.go b/itests/kit/funds.go index 4c739dc62..2ea822979 100644 --- a/itests/kit/funds.go +++ b/itests/kit/funds.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/filecoin-project/go-state-types/abi" + "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" @@ -15,9 +16,7 @@ import ( // to the recipient address. func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient address.Address, amount abi.TokenAmount) { senderAddr, err := sender.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) msg := &types.Message{ From: senderAddr, @@ -26,14 +25,10 @@ func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient } sm, err := sender.MpoolPushMessage(ctx, msg, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) + res, err := sender.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) - if err != nil { - t.Fatal(err) - } - if res.Receipt.ExitCode != 0 { - t.Fatal("did not successfully send money") - } + require.NoError(t, err) + + require.Equal(t, 0, res.Receipt.ExitCode, "did not successfully send funds") } diff --git a/itests/kit/init.go b/itests/kit/init.go new file mode 100644 index 000000000..57d60ad2a --- /dev/null +++ b/itests/kit/init.go @@ -0,0 +1,25 @@ +package kit + +import ( + "fmt" + "os" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/policy" + logging "github.com/ipfs/go-log/v2" +) + +func init() { + _ = logging.SetLogLevel("*", "INFO") + + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) + + err := os.Setenv("BELLMAN_NO_GPU", "1") + if err != nil { + panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err)) + } + build.InsecurePoStValidation = true +} diff --git a/itests/kit/net.go b/itests/kit/net.go index 54c72443f..aea609091 100644 --- a/itests/kit/net.go +++ b/itests/kit/net.go @@ -1,87 +1,42 @@ package kit -import ( - "context" - "testing" - "time" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/chain/types" - - "github.com/filecoin-project/go-address" -) - -func StartOneNodeOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) (TestFullNode, address.Address) { - n, sn := RPCMockMinerBuilder(t, OneFull, OneMiner) - - full := n[0] - miner := sn[0] - - // Get everyone connected - addrs, err := full.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - // Start mining blocks - bm := NewBlockMiner(t, miner) - bm.MineBlocks(ctx, blocktime) - t.Cleanup(bm.Stop) - - // Get the full node's wallet address - fullAddr, err := full.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } - - // Create mock CLI - return full, fullAddr -} - -func StartTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]TestFullNode, []address.Address) { - n, sn := RPCMockMinerBuilder(t, TwoFull, OneMiner) - - fullNode1 := n[0] - fullNode2 := n[1] - miner := sn[0] - - // Get everyone connected - addrs, err := fullNode1.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := fullNode2.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - // Start mining blocks - bm := NewBlockMiner(t, miner) - bm.MineBlocks(ctx, blocktime) - t.Cleanup(bm.Stop) - - // Send some funds to register the second node - fullNodeAddr2, err := fullNode2.WalletNew(ctx, types.KTSecp256k1) - if err != nil { - t.Fatal(err) - } - - SendFunds(ctx, t, fullNode1, fullNodeAddr2, abi.NewTokenAmount(1e18)) - - // Get the first node's address - fullNodeAddr1, err := fullNode1.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } - - // Create mock CLI - return n, []address.Address{fullNodeAddr1, fullNodeAddr2} -} +// +// func StartTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]TestFullNode, []address.Address) { +// n, sn := MinerRPCMockMinerBuilder(t, TwoFull, OneMiner) +// +// fullNode1 := n[0] +// fullNode2 := n[1] +// miner := sn[0] +// +// // Get everyone connected +// addrs, err := fullNode1.NetAddrsListen(ctx) +// if err != nil { +// t.Fatal(err) +// } +// +// if err := fullNode2.NetConnect(ctx, addrs); err != nil { +// t.Fatal(err) +// } +// +// // Start mining blocks +// bm := NewBlockMiner(t, miner) +// bm.MineBlocks(ctx, blocktime) +// t.Cleanup(bm.Stop) +// +// // Send some funds to register the second node +// fullNodeAddr2, err := fullNode2.WalletNew(ctx, types.KTSecp256k1) +// if err != nil { +// t.Fatal(err) +// } +// +// SendFunds(ctx, t, fullNode1, fullNodeAddr2, abi.NewTokenAmount(1e18)) +// +// // Get the first node's address +// fullNodeAddr1, err := fullNode1.WalletDefaultAddress(ctx) +// if err != nil { +// t.Fatal(err) +// } +// +// // Create mock CLI +// return n, []address.Address{fullNodeAddr1, fullNodeAddr2} +// } diff --git a/itests/kit/node_builder.go b/itests/kit/node_builder.go deleted file mode 100644 index 4115a1d2f..000000000 --- a/itests/kit/node_builder.go +++ /dev/null @@ -1,606 +0,0 @@ -package kit - -import ( - "bytes" - "context" - "crypto/rand" - "io/ioutil" - "net/http" - "net/http/httptest" - "sync" - "testing" - "time" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/go-storedcounter" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/api/client" - "github.com/filecoin-project/lotus/api/v1api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain" - "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - "github.com/filecoin-project/lotus/chain/actors/builtin/power" - "github.com/filecoin-project/lotus/chain/gen" - genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" - "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/cmd/lotus-seed/seed" - sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" - "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/lotus/genesis" - lotusminer "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/lotus/node" - "github.com/filecoin-project/lotus/node/modules" - "github.com/filecoin-project/lotus/node/modules/dtypes" - testing2 "github.com/filecoin-project/lotus/node/modules/testing" - "github.com/filecoin-project/lotus/node/repo" - "github.com/filecoin-project/lotus/storage/mockstorage" - miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" - power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" - "github.com/ipfs/go-datastore" - "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" - mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" - "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr/net" - "github.com/stretchr/testify/require" -) - -func init() { - chain.BootstrapPeerThreshold = 1 - messagepool.HeadChangeCoalesceMinDelay = time.Microsecond - messagepool.HeadChangeCoalesceMaxDelay = 2 * time.Microsecond - messagepool.HeadChangeCoalesceMergeInterval = 100 * time.Nanosecond -} - -func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Address, act address.Address, pk crypto.PrivKey, tnd TestFullNode, mn mocknet.Mocknet, opts node.Option) TestMiner { - r := repo.NewMemory(nil) - - lr, err := r.Lock(repo.StorageMiner) - require.NoError(t, err) - - ks, err := lr.KeyStore() - require.NoError(t, err) - - kbytes, err := pk.Bytes() - require.NoError(t, err) - - err = ks.Put("libp2p-host", types.KeyInfo{ - Type: "libp2p-host", - PrivateKey: kbytes, - }) - require.NoError(t, err) - - ds, err := lr.Datastore(context.TODO(), "/metadata") - require.NoError(t, err) - err = ds.Put(datastore.NewKey("miner-address"), act.Bytes()) - require.NoError(t, err) - - nic := storedcounter.New(ds, datastore.NewKey(modules.StorageCounterDSPrefix)) - for i := 0; i < GenesisPreseals; i++ { - _, err := nic.Next() - require.NoError(t, err) - } - _, err = nic.Next() - require.NoError(t, err) - - err = lr.Close() - require.NoError(t, err) - - peerid, err := peer.IDFromPrivateKey(pk) - require.NoError(t, err) - - enc, err := actors.SerializeParams(&miner2.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) - require.NoError(t, err) - - msg := &types.Message{ - To: act, - From: waddr, - Method: miner.Methods.ChangePeerID, - Params: enc, - Value: types.NewInt(0), - } - - _, err = tnd.MpoolPushMessage(ctx, msg, nil) - require.NoError(t, err) - - // start node - var minerapi api.StorageMiner - - mineBlock := make(chan lotusminer.MineReq) - stop, err := node.New(ctx, - node.StorageMiner(&minerapi), - node.Online(), - node.Repo(r), - node.Test(), - - node.MockHost(mn), - - node.Override(new(v1api.FullNode), tnd), - node.Override(new(*lotusminer.Miner), lotusminer.NewTestMiner(mineBlock, act)), - - opts, - ) - if err != nil { - t.Fatalf("failed to construct node: %v", err) - } - - t.Cleanup(func() { _ = stop(context.Background()) }) - - /*// Bootstrap with full node - remoteAddrs, err := tnd.NetAddrsListen(Ctx) - require.NoError(t, err) - - err = minerapi.NetConnect(Ctx, remoteAddrs) - require.NoError(t, err)*/ - mineOne := func(ctx context.Context, req lotusminer.MineReq) error { - select { - case mineBlock <- req: - return nil - case <-ctx.Done(): - return ctx.Err() - } - } - - return TestMiner{StorageMiner: minerapi, MineOne: mineOne, Stop: stop} -} - -func storageBuilder(parentNode TestFullNode, mn mocknet.Mocknet, opts node.Option) MinerBuilder { - return func(ctx context.Context, t *testing.T, spt abi.RegisteredSealProof, owner address.Address) TestMiner { - pk, _, err := crypto.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - - minerPid, err := peer.IDFromPrivateKey(pk) - require.NoError(t, err) - - params, serr := actors.SerializeParams(&power2.CreateMinerParams{ - Owner: owner, - Worker: owner, - SealProofType: spt, - Peer: abi.PeerID(minerPid), - }) - require.NoError(t, serr) - - createStorageMinerMsg := &types.Message{ - To: power.Address, - From: owner, - Value: big.Zero(), - - Method: power.Methods.CreateMiner, - Params: params, - - GasLimit: 0, - GasPremium: big.NewInt(5252), - } - - signed, err := parentNode.MpoolPushMessage(ctx, createStorageMinerMsg, nil) - require.NoError(t, err) - - mw, err := parentNode.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mw.Receipt.ExitCode) - - var retval power2.CreateMinerReturn - err = retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)) - require.NoError(t, err) - - return CreateTestStorageNode(ctx, t, owner, retval.IDAddress, pk, parentNode, mn, opts) - } -} - -func Builder(t *testing.T, fullOpts []FullNodeOpts, storage []StorageMiner) ([]TestFullNode, []TestMiner) { - return mockBuilderOpts(t, fullOpts, storage, false) -} - -func RPCBuilder(t *testing.T, fullOpts []FullNodeOpts, storage []StorageMiner) ([]TestFullNode, []TestMiner) { - return mockBuilderOpts(t, fullOpts, storage, true) -} - -func MockMinerBuilder(t *testing.T, fullOpts []FullNodeOpts, storage []StorageMiner) ([]TestFullNode, []TestMiner) { - return mockMinerBuilderOpts(t, fullOpts, storage, false) -} - -func RPCMockMinerBuilder(t *testing.T, fullOpts []FullNodeOpts, storage []StorageMiner) ([]TestFullNode, []TestMiner) { - return mockMinerBuilderOpts(t, fullOpts, storage, true) -} - -func mockBuilderOpts(t *testing.T, fullOpts []FullNodeOpts, storage []StorageMiner, rpc bool) ([]TestFullNode, []TestMiner) { - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - mn := mocknet.New(ctx) - - fulls := make([]TestFullNode, len(fullOpts)) - miners := make([]TestMiner, len(storage)) - - // ***** - pk, _, err := crypto.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - - minerPid, err := peer.IDFromPrivateKey(pk) - require.NoError(t, err) - - var genbuf bytes.Buffer - - if len(storage) > 1 { - panic("need more peer IDs") - } - // ***** - - // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE - // TODO: would be great if there was a better way to fake the preseals - - var ( - genms []genesis.Miner - maddrs []address.Address - genaccs []genesis.Actor - keys []*wallet.Key - ) - - var presealDirs []string - for i := 0; i < len(storage); i++ { - maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i)) - if err != nil { - t.Fatal(err) - } - tdir, err := ioutil.TempDir("", "preseal-memgen") - if err != nil { - t.Fatal(err) - } - genm, k, err := seed.PreSeal(maddr, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, GenesisPreseals, tdir, []byte("make genesis mem random"), nil, true) - if err != nil { - t.Fatal(err) - } - genm.PeerId = minerPid - - wk, err := wallet.NewKey(*k) - if err != nil { - return nil, nil - } - - genaccs = append(genaccs, genesis.Actor{ - Type: genesis.TAccount, - Balance: big.Mul(big.NewInt(400000000), types.NewInt(build.FilecoinPrecision)), - Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(), - }) - - keys = append(keys, wk) - presealDirs = append(presealDirs, tdir) - maddrs = append(maddrs, maddr) - genms = append(genms, *genm) - } - templ := &genesis.Template{ - Accounts: genaccs, - Miners: genms, - NetworkName: "test", - Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past - VerifregRootKey: gen.DefaultVerifregRootkeyActor, - RemainderAccount: gen.DefaultRemainderAccountActor, - } - - // END PRESEAL SECTION - - for i := 0; i < len(fullOpts); i++ { - var genesis node.Option - if i == 0 { - genesis = node.Override(new(modules.Genesis), testing2.MakeGenesisMem(&genbuf, *templ)) - } else { - genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes())) - } - - stop, err := node.New(ctx, - node.FullAPI(&fulls[i].FullNode, node.Lite(fullOpts[i].Lite)), - node.Online(), - node.Repo(repo.NewMemory(nil)), - node.MockHost(mn), - node.Test(), - - genesis, - - fullOpts[i].Opts(fulls), - ) - if err != nil { - t.Fatal(err) - } - - t.Cleanup(func() { _ = stop(context.Background()) }) - - if rpc { - fulls[i] = fullRpc(t, fulls[i]) - } - - fulls[i].Stb = storageBuilder(fulls[i], mn, node.Options()) - } - - for i, def := range storage { - // TODO: support non-bootstrap miners - if i != 0 { - t.Fatal("only one storage node supported") - } - if def.Full != 0 { - t.Fatal("storage nodes only supported on the first full node") - } - - f := fulls[def.Full] - if _, err := f.FullNode.WalletImport(ctx, &keys[i].KeyInfo); err != nil { - t.Fatal(err) - } - if err := f.FullNode.WalletSetDefault(ctx, keys[i].Address); err != nil { - t.Fatal(err) - } - - genMiner := maddrs[i] - wa := genms[i].Worker - - opts := def.Opts - if opts == nil { - opts = node.Options() - } - miners[i] = CreateTestStorageNode(ctx, t, wa, genMiner, pk, f, mn, opts) - if err := miners[i].StorageAddLocal(ctx, presealDirs[i]); err != nil { - t.Fatalf("%+v", err) - } - /* - sma := miners[i].StorageMiner.(*impl.StorageMinerAPI) - - psd := presealDirs[i] - */ - if rpc { - miners[i] = storerRpc(t, miners[i]) - } - } - - if err := mn.LinkAll(); err != nil { - t.Fatal(err) - } - - if len(miners) > 0 { - // Mine 2 blocks to setup some CE stuff in some actors - var wait sync.Mutex - wait.Lock() - - bm := NewBlockMiner(t, miners[0]) - t.Cleanup(bm.Stop) - - bm.MineUntilBlock(ctx, fulls[0], func(epoch abi.ChainEpoch) { - wait.Unlock() - }) - - wait.Lock() - bm.MineUntilBlock(ctx, fulls[0], func(epoch abi.ChainEpoch) { - wait.Unlock() - }) - wait.Lock() - } - - return fulls, miners -} - -func mockMinerBuilderOpts(t *testing.T, fullOpts []FullNodeOpts, storage []StorageMiner, rpc bool) ([]TestFullNode, []TestMiner) { - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - mn := mocknet.New(ctx) - - fulls := make([]TestFullNode, len(fullOpts)) - miners := make([]TestMiner, len(storage)) - - var genbuf bytes.Buffer - - // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE - // TODO: would be great if there was a better way to fake the preseals - - var ( - genms []genesis.Miner - genaccs []genesis.Actor - maddrs []address.Address - keys []*wallet.Key - pidKeys []crypto.PrivKey - ) - for i := 0; i < len(storage); i++ { - maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i)) - if err != nil { - t.Fatal(err) - } - - preseals := storage[i].Preseal - if preseals == PresealGenesis { - preseals = GenesisPreseals - } - - genm, k, err := mockstorage.PreSeal(abi.RegisteredSealProof_StackedDrg2KiBV1, maddr, preseals) - if err != nil { - t.Fatal(err) - } - - pk, _, err := crypto.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - - minerPid, err := peer.IDFromPrivateKey(pk) - require.NoError(t, err) - - genm.PeerId = minerPid - - wk, err := wallet.NewKey(*k) - if err != nil { - return nil, nil - } - - genaccs = append(genaccs, genesis.Actor{ - Type: genesis.TAccount, - Balance: big.Mul(big.NewInt(400000000), types.NewInt(build.FilecoinPrecision)), - Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(), - }) - - keys = append(keys, wk) - pidKeys = append(pidKeys, pk) - maddrs = append(maddrs, maddr) - genms = append(genms, *genm) - } - templ := &genesis.Template{ - Accounts: genaccs, - Miners: genms, - NetworkName: "test", - Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), - VerifregRootKey: gen.DefaultVerifregRootkeyActor, - RemainderAccount: gen.DefaultRemainderAccountActor, - } - - // END PRESEAL SECTION - - for i := 0; i < len(fullOpts); i++ { - var genesis node.Option - if i == 0 { - genesis = node.Override(new(modules.Genesis), testing2.MakeGenesisMem(&genbuf, *templ)) - } else { - genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes())) - } - - stop, err := node.New(ctx, - node.FullAPI(&fulls[i].FullNode, node.Lite(fullOpts[i].Lite)), - node.Online(), - node.Repo(repo.NewMemory(nil)), - node.MockHost(mn), - node.Test(), - - node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), - - // so that we subscribe to pubsub topics immediately - node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), - - genesis, - - fullOpts[i].Opts(fulls), - ) - if err != nil { - t.Fatalf("%+v", err) - } - - t.Cleanup(func() { _ = stop(context.Background()) }) - - if rpc { - fulls[i] = fullRpc(t, fulls[i]) - } - - fulls[i].Stb = storageBuilder(fulls[i], mn, node.Options( - node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { - return mock.NewMockSectorMgr(nil), nil - }), - node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), - node.Unset(new(*sectorstorage.Manager)), - )) - } - - for i, def := range storage { - // TODO: support non-bootstrap miners - - minerID := abi.ActorID(genesis2.MinerStart + uint64(i)) - - if def.Full != 0 { - t.Fatal("storage nodes only supported on the first full node") - } - - f := fulls[def.Full] - if _, err := f.FullNode.WalletImport(ctx, &keys[i].KeyInfo); err != nil { - return nil, nil - } - if err := f.FullNode.WalletSetDefault(ctx, keys[i].Address); err != nil { - return nil, nil - } - - sectors := make([]abi.SectorID, len(genms[i].Sectors)) - for i, sector := range genms[i].Sectors { - sectors[i] = abi.SectorID{ - Miner: minerID, - Number: sector.SectorID, - } - } - - opts := def.Opts - if opts == nil { - opts = node.Options() - } - miners[i] = CreateTestStorageNode(ctx, t, genms[i].Worker, maddrs[i], pidKeys[i], f, mn, node.Options( - node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { - return mock.NewMockSectorMgr(sectors), nil - }), - node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), - node.Unset(new(*sectorstorage.Manager)), - opts, - )) - - if rpc { - miners[i] = storerRpc(t, miners[i]) - } - } - - if err := mn.LinkAll(); err != nil { - t.Fatal(err) - } - - bm := NewBlockMiner(t, miners[0]) - - if len(miners) > 0 { - // Mine 2 blocks to setup some CE stuff in some actors - var wait sync.Mutex - wait.Lock() - - bm.MineUntilBlock(ctx, fulls[0], func(abi.ChainEpoch) { - wait.Unlock() - }) - wait.Lock() - bm.MineUntilBlock(ctx, fulls[0], func(abi.ChainEpoch) { - wait.Unlock() - }) - wait.Lock() - } - - return fulls, miners -} - -func CreateRPCServer(t *testing.T, handler http.Handler) (*httptest.Server, multiaddr.Multiaddr) { - testServ := httptest.NewServer(handler) - t.Cleanup(testServ.Close) - t.Cleanup(testServ.CloseClientConnections) - - addr := testServ.Listener.Addr() - maddr, err := manet.FromNetAddr(addr) - require.NoError(t, err) - return testServ, maddr -} - -func fullRpc(t *testing.T, nd TestFullNode) TestFullNode { - handler, err := node.FullNodeHandler(nd.FullNode) - require.NoError(t, err) - - srv, maddr := CreateRPCServer(t, handler) - - var ret TestFullNode - cl, stop, err := client.NewFullNodeRPCV1(context.Background(), srv.Listener.Addr().String()+"/rpc/v1", nil) - require.NoError(t, err) - t.Cleanup(stop) - ret.ListenAddr, ret.FullNode = maddr, cl - - return ret -} - -func storerRpc(t *testing.T, nd TestMiner) TestMiner { - handler, err := node.MinerHandler(nd.StorageMiner) - require.NoError(t, err) - - srv, maddr := CreateRPCServer(t, handler) - - var ret TestMiner - cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), srv.Listener.Addr().String()+"/rpc/v0", nil) - require.NoError(t, err) - t.Cleanup(stop) - - ret.ListenAddr, ret.StorageMiner, ret.MineOne = maddr, cl, nd.MineOne - return ret -} diff --git a/itests/kit/node_full.go b/itests/kit/node_full.go new file mode 100644 index 000000000..f8f13c724 --- /dev/null +++ b/itests/kit/node_full.go @@ -0,0 +1,22 @@ +package kit + +import ( + "testing" + + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/multiformats/go-multiaddr" +) + +type TestFullNode struct { + v1api.FullNode + + t *testing.T + + // ListenAddr is the address on which an API server is listening, if an + // API server is created for this Node. + ListenAddr multiaddr.Multiaddr + DefaultKey *wallet.Key + + options NodeOpts +} diff --git a/itests/kit/node_miner.go b/itests/kit/node_miner.go new file mode 100644 index 000000000..22278b64b --- /dev/null +++ b/itests/kit/node_miner.go @@ -0,0 +1,97 @@ +package kit + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/wallet" + sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + "github.com/filecoin-project/lotus/miner" + libp2pcrypto "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +type TestMiner struct { + lapi.StorageMiner + + t *testing.T + + // ListenAddr is the address on which an API server is listening, if an + // API server is created for this Node + ListenAddr multiaddr.Multiaddr + + ActorAddr address.Address + OwnerKey *wallet.Key + MineOne func(context.Context, miner.MineReq) error + Stop func(context.Context) error + + FullNode *TestFullNode + PresealDir string + + Libp2p struct { + PeerID peer.ID + PrivKey libp2pcrypto.PrivKey + } + + options NodeOpts +} + +var MineNext = miner.MineReq{ + InjectNulls: 0, + Done: func(bool, abi.ChainEpoch, error) {}, +} + +func (tm *TestMiner) PledgeSectors(ctx context.Context, n, existing int, blockNotif <-chan struct{}) { //nolint:golint + for i := 0; i < n; i++ { + if i%3 == 0 && blockNotif != nil { + <-blockNotif + tm.t.Log("WAIT") + } + tm.t.Logf("PLEDGING %d", i) + _, err := tm.PledgeSector(ctx) + require.NoError(tm.t, err) + } + + for { + s, err := tm.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM + require.NoError(tm.t, err) + fmt.Printf("Sectors: %d\n", len(s)) + if len(s) >= n+existing { + break + } + + build.Clock.Sleep(100 * time.Millisecond) + } + + fmt.Printf("All sectors is fsm\n") + + s, err := tm.SectorsList(ctx) + require.NoError(tm.t, err) + + toCheck := map[abi.SectorNumber]struct{}{} + for _, number := range s { + toCheck[number] = struct{}{} + } + + for len(toCheck) > 0 { + for n := range toCheck { + st, err := tm.SectorsStatus(ctx, n, false) + require.NoError(tm.t, err) + if st.State == lapi.SectorState(sealing.Proving) { + delete(toCheck, n) + } + require.NotContains(tm.t, string(st.State), "Fail", "sector in a failed state") + } + + build.Clock.Sleep(100 * time.Millisecond) + fmt.Printf("WaitSeal: %d\n", len(s)) + } +} diff --git a/itests/kit/nodes.go b/itests/kit/nodes.go deleted file mode 100644 index 2c3f89b9a..000000000 --- a/itests/kit/nodes.go +++ /dev/null @@ -1,133 +0,0 @@ -package kit - -import ( - "context" - "testing" - - "github.com/multiformats/go-multiaddr" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/network" - - lapi "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/api/v1api" - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/lotus/node" -) - -type MinerBuilder func(context.Context, *testing.T, abi.RegisteredSealProof, address.Address) TestMiner - -type TestFullNode struct { - v1api.FullNode - // ListenAddr is the address on which an API server is listening, if an - // API server is created for this Node - ListenAddr multiaddr.Multiaddr - - Stb MinerBuilder -} - -type TestMiner struct { - lapi.StorageMiner - // ListenAddr is the address on which an API server is listening, if an - // API server is created for this Node - ListenAddr multiaddr.Multiaddr - - MineOne func(context.Context, miner.MineReq) error - Stop func(context.Context) error -} - -var PresealGenesis = -1 - -const GenesisPreseals = 2 - -const TestSpt = abi.RegisteredSealProof_StackedDrg2KiBV1_1 - -// Options for setting up a mock storage Miner -type StorageMiner struct { - Full int - Opts node.Option - Preseal int -} - -type OptionGenerator func([]TestFullNode) node.Option - -// Options for setting up a mock full node -type FullNodeOpts struct { - Lite bool // run node in "lite" mode - Opts OptionGenerator // generate dependency injection options -} - -// APIBuilder is a function which is invoked in test suite to provide -// test nodes and networks -// -// fullOpts array defines options for each full node -// storage array defines storage nodes, numbers in the array specify full node -// index the storage node 'belongs' to -type APIBuilder func(t *testing.T, full []FullNodeOpts, storage []StorageMiner) ([]TestFullNode, []TestMiner) - -func DefaultFullOpts(nFull int) []FullNodeOpts { - full := make([]FullNodeOpts, nFull) - for i := range full { - full[i] = FullNodeOpts{ - Opts: func(nodes []TestFullNode) node.Option { - return node.Options() - }, - } - } - return full -} - -var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}} -var OneFull = DefaultFullOpts(1) -var TwoFull = DefaultFullOpts(2) - -var FullNodeWithLatestActorsAt = func(upgradeHeight abi.ChainEpoch) FullNodeOpts { - if upgradeHeight == -1 { - upgradeHeight = 3 - } - - return FullNodeOpts{ - Opts: func(nodes []TestFullNode) node.Option { - return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ - // prepare for upgrade. - Network: network.Version9, - Height: 1, - Migration: stmgr.UpgradeActorsV2, - }, { - Network: network.Version10, - Height: 2, - Migration: stmgr.UpgradeActorsV3, - }, { - Network: network.Version12, - Height: upgradeHeight, - Migration: stmgr.UpgradeActorsV4, - }}) - }, - } -} - -var FullNodeWithSDRAt = func(calico, persian abi.ChainEpoch) FullNodeOpts { - return FullNodeOpts{ - Opts: func(nodes []TestFullNode) node.Option { - return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ - Network: network.Version6, - Height: 1, - Migration: stmgr.UpgradeActorsV2, - }, { - Network: network.Version7, - Height: calico, - Migration: stmgr.UpgradeCalico, - }, { - Network: network.Version8, - Height: persian, - }}) - }, - } -} - -var MineNext = miner.MineReq{ - InjectNulls: 0, - Done: func(bool, abi.ChainEpoch, error) {}, -} diff --git a/itests/kit/pledge.go b/itests/kit/pledge.go deleted file mode 100644 index 1f2379e2b..000000000 --- a/itests/kit/pledge.go +++ /dev/null @@ -1,64 +0,0 @@ -package kit - -import ( - "context" - "fmt" - "strings" - "testing" - "time" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/stretchr/testify/require" -) - -func PledgeSectors(t *testing.T, ctx context.Context, miner TestMiner, n, existing int, blockNotif <-chan struct{}) { //nolint:golint - for i := 0; i < n; i++ { - if i%3 == 0 && blockNotif != nil { - <-blockNotif - t.Log("WAIT") - } - t.Logf("PLEDGING %d", i) - _, err := miner.PledgeSector(ctx) - require.NoError(t, err) - } - - for { - s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM - require.NoError(t, err) - fmt.Printf("Sectors: %d\n", len(s)) - if len(s) >= n+existing { - break - } - - build.Clock.Sleep(100 * time.Millisecond) - } - - fmt.Printf("All sectors is fsm\n") - - s, err := miner.SectorsList(ctx) - require.NoError(t, err) - - toCheck := map[abi.SectorNumber]struct{}{} - for _, number := range s { - toCheck[number] = struct{}{} - } - - for len(toCheck) > 0 { - for n := range toCheck { - st, err := miner.SectorsStatus(ctx, n, false) - require.NoError(t, err) - if st.State == api.SectorState(sealing.Proving) { - delete(toCheck, n) - } - if strings.Contains(string(st.State), "Fail") { - t.Fatal("sector in a failed state", st.State) - } - } - - build.Clock.Sleep(100 * time.Millisecond) - fmt.Printf("WaitSeal: %d\n", len(s)) - } -} diff --git a/itests/multisig_test.go b/itests/multisig_test.go.no similarity index 100% rename from itests/multisig_test.go rename to itests/multisig_test.go.no diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go.no similarity index 100% rename from itests/paych_api_test.go rename to itests/paych_api_test.go.no diff --git a/itests/paych_cli_test.go b/itests/paych_cli_test.go.no similarity index 100% rename from itests/paych_cli_test.go rename to itests/paych_cli_test.go.no diff --git a/itests/sdr_upgrade_test.go b/itests/sdr_upgrade_test.go.no similarity index 100% rename from itests/sdr_upgrade_test.go rename to itests/sdr_upgrade_test.go.no diff --git a/itests/sector_pledge_test.go b/itests/sector_pledge_test.go.no similarity index 100% rename from itests/sector_pledge_test.go rename to itests/sector_pledge_test.go.no diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go.no similarity index 100% rename from itests/sector_terminate_test.go rename to itests/sector_terminate_test.go.no diff --git a/itests/tape_test.go b/itests/tape_test.go.no similarity index 100% rename from itests/tape_test.go rename to itests/tape_test.go.no diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go.no similarity index 100% rename from itests/wdpost_dispute_test.go rename to itests/wdpost_dispute_test.go.no diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go.no similarity index 100% rename from itests/wdpost_test.go rename to itests/wdpost_test.go.no