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 01/72] initial version of the new itest kit. Still need to migrate all integration tests, add godocs, and probably zap bugs. --- itests/api_test.go | 226 ++---- ...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, 1019 insertions(+), 1089 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 ee70a337b35..22bbc6f6e99 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,213 +48,142 @@ 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) - - api := apis[0] - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - senderAddr, err := api.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(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") - } - - searchRes, err := api.StateSearchMsg(ctx, types.EmptyTSK, sm.Cid(), lapi.LookbackNoLimit, true) - if err != nil { - t.Fatal(err) - } - - if searchRes.TipSet != res.TipSet { - t.Fatalf("search ts: %s, different from wait ts: %s", searchRes.TipSet, res.TipSet) - } - -} - func (ts *apiSuite) testID(t *testing.T) { ctx := context.Background() - apis, _ := ts.makeNodes(t, kit.OneFull, kit.OneMiner) - api := apis[0] - id, err := api.ID(ctx) + full, _, _ := kit.EnsembleMinimum(t, ts.opts...) + + id, err := full.ID(ctx) if err != nil { t.Fatal(err) } - assert.Regexp(t, "^12", id.Pretty()) + require.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") - } + one, two, _, ens := kit.EnsembleTwo(t, ts.opts...) - p, err = apis[1].NetPeers(ctx) - if err != nil { - t.Fatal(err) - } - if len(p) != 0 { - t.Error("Node 1 has a peer") - } + p, err := one.NetPeers(ctx) + require.NoError(t, err) + require.Empty(t, p, "node one has peers") - addrs, err := apis[1].NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } + p, err = two.NetPeers(ctx) + require.NoError(t, err) + require.Empty(t, p, "node two has peers") - if err := apis[0].NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } + ens.InterconnectAll() - 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") - } + peers, err := one.NetPeers(ctx) + require.NoError(t, err) + require.Lenf(t, peers, 1, "node one 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") - } + peers, err = two.NetPeers(ctx) + require.NoError(t, err) + require.Lenf(t, peers, 1, "node two doesn't have 1 peer") } -func (ts *apiSuite) testMining(t *testing.T) { +func (ts *apiSuite) testSearchMsg(t *testing.T) { ctx := context.Background() - fulls, miners := ts.makeNodes(t, kit.OneFull, kit.OneMiner) - api := fulls[0] - newHeads, err := api.ChainNotify(ctx) + full, _, ens := kit.EnsembleMinimum(t, ts.opts...) + + senderAddr, err := full.WalletDefaultAddress(ctx) require.NoError(t, err) - initHead := (<-newHeads)[0] - baseHeight := initHead.Val.Height() - h1, err := api.ChainHead(ctx) + msg := &types.Message{ + From: senderAddr, + To: senderAddr, + Value: big.Zero(), + } + + ens.BeginMining(100 * time.Millisecond) + + sm, err := full.MpoolPushMessage(ctx, msg, nil) require.NoError(t, err) - require.Equal(t, int64(h1.Height()), int64(baseHeight)) - bm := kit.NewBlockMiner(t, miners[0]) - bm.MineUntilBlock(ctx, fulls[0], nil) + res, err := full.StateWaitMsg(ctx, sm.Cid(), 1, lapi.LookbackNoLimit, true) require.NoError(t, err) - <-newHeads + require.Equal(t, exitcode.Ok, res.Receipt.ExitCode, "message not successful") - h2, err := api.ChainHead(ctx) + searchRes, err := full.StateSearchMsg(ctx, types.EmptyTSK, sm.Cid(), lapi.LookbackNoLimit, true) require.NoError(t, err) - require.Greater(t, int64(h2.Height()), int64(h1.Height())) -} -func (ts *apiSuite) testMiningReal(t *testing.T) { - build.InsecurePoStValidation = false - defer func() { - build.InsecurePoStValidation = true - }() + 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) - require.NoError(t, err) - at := (<-newHeads)[0].Val.Height() + full, miner, _ := kit.EnsembleMinimum(t, ts.opts...) - h1, err := api.ChainHead(ctx) + newHeads, err := full.ChainNotify(ctx) require.NoError(t, err) - require.Equal(t, int64(at), int64(h1.Height())) + initHead := (<-newHeads)[0] + baseHeight := initHead.Val.Height() - bm := kit.NewBlockMiner(t, miners[0]) + h1, err := full.ChainHead(ctx) + require.NoError(t, err) + require.Equal(t, int64(h1.Height()), int64(baseHeight)) - 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, fulls[0], nil) + bm.MineUntilBlock(ctx, full, nil) require.NoError(t, err) <-newHeads - h3, err := api.ChainHead(ctx) + 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) { + build.InsecurePoStValidation = false + defer func() { + build.InsecurePoStValidation = true + }() + + 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] - bm := kit.NewBlockMiner(t, genesisMiner) - bm.MineBlocks(ctx, 4*time.Millisecond) - t.Cleanup(bm.Stop) + full, genesisMiner, ens := kit.EnsembleMinimum(t, ts.opts...) + + 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 28abac171a7..f6ba878202f 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 a7599a8b736..f34aea91d5b 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 5c7fc4be0b8..d532f3423c4 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 3b1f1fedfa7..b7951c4f89e 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 986cda39c82..2a1ca5ba518 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 00000000000..90a09c82b9c --- /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 00000000000..debad2ed149 --- /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 4c739dc62c2..2ea822979c4 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 00000000000..57d60ad2a5f --- /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 54c72443f43..aea60909148 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 4115a1d2f22..00000000000 --- 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 00000000000..f8f13c724a1 --- /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 00000000000..22278b64bf6 --- /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 2c3f89b9a86..00000000000 --- 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 1f2379e2ba9..00000000000 --- 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 From 71cd26850203924f0851c7d6c6345691f2fd3188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 4 Jun 2021 15:17:30 +0100 Subject: [PATCH 02/72] fix. --- cmd/lotus-storage-miner/allinfo_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-storage-miner/allinfo_test.go b/cmd/lotus-storage-miner/allinfo_test.go index cbe65524e11..0c99b47dc64 100644 --- a/cmd/lotus-storage-miner/allinfo_test.go +++ b/cmd/lotus-storage-miner/allinfo_test.go @@ -40,7 +40,7 @@ func TestMinerAllInfo(t *testing.T) { policy.SetPreCommitChallengeDelay(oldDelay) }) - n, sn := kit.Builder(t, kit.OneFull, kit.OneMiner) + n, sn := kit.FullNodeBuilder(t, kit.OneFull, kit.OneMiner) client, miner := n[0].FullNode, sn[0] kit.ConnectAndStartMining(t, time.Second, miner, client.(*impl.FullNodeAPI)) From 019394b9e5e64b638d3b60c824534a8c8227e5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 12:14:37 +0100 Subject: [PATCH 03/72] remove debug statements. --- itests/kit/init.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/itests/kit/init.go b/itests/kit/init.go index 84ca5ecfe26..57d60ad2a5f 100644 --- a/itests/kit/init.go +++ b/itests/kit/init.go @@ -3,8 +3,6 @@ package kit import ( "fmt" "os" - "runtime/debug" - "strings" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" @@ -24,9 +22,4 @@ func init() { panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err)) } build.InsecurePoStValidation = true - - debug.PrintStack() - - fmt.Println(strings.HasSuffix(os.Args[0], ".test")) - } From 0303a0297d477d27e5b23b42c8cb1246885a19e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 12:15:03 +0100 Subject: [PATCH 04/72] rename DealHarness.{TestRetrieval=>PerformRetrieval}. --- itests/kit/deals.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 21089a190ce..0ea19d9c722 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -62,7 +62,7 @@ func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, f info, err := dh.client.ClientGetDealInfo(ctx, *deal) require.NoError(dh.t, err) - dh.TestRetrieval(ctx, fcid, &info.PieceCID, carExport, data) + dh.PerformRetrieval(ctx, fcid, &info.PieceCID, carExport, data) } func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { @@ -184,7 +184,7 @@ func (dh *DealHarness) StartSealingWaiting(ctx context.Context) { } } -func (dh *DealHarness) TestRetrieval(ctx context.Context, fcid cid.Cid, piece *cid.Cid, carExport bool, expect []byte) { +func (dh *DealHarness) PerformRetrieval(ctx context.Context, fcid cid.Cid, piece *cid.Cid, carExport bool, expect []byte) { offers, err := dh.client.ClientFindData(ctx, fcid, piece) if err != nil { dh.t.Fatal(err) From 0d69c03a8d3a335c5cbb8240606dd07456dc0ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 12:17:39 +0100 Subject: [PATCH 05/72] deals harness: use require. --- itests/kit/deals.go | 77 +++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 0ea19d9c722..12504465642 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -45,9 +45,7 @@ func NewDealHarness(t *testing.T, client api.FullNode, miner *TestMiner) *DealHa func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, fastRet bool, startEpoch abi.ChainEpoch) { res, _, data, err := CreateImportFile(ctx, dh.client, rseed, 0) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) fcid := res.Root fmt.Println("FILE CID: ", fcid) @@ -67,14 +65,11 @@ func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, f func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { maddr, err := dh.miner.ActorAddress(ctx) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) addr, err := dh.client.WalletDefaultAddress(ctx) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + deal, err := dh.client.ClientStartDeal(ctx, &api.StartDealParams{ Data: &storagemarket.DataRef{ TransferType: storagemarket.TTGraphsync, @@ -140,10 +135,10 @@ loop: func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { subCtx, cancel := context.WithCancel(ctx) defer cancel() + updates, err := dh.miner.MarketGetDealUpdates(subCtx) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + for { select { case <-ctx.Done(): @@ -186,43 +181,34 @@ func (dh *DealHarness) StartSealingWaiting(ctx context.Context) { func (dh *DealHarness) PerformRetrieval(ctx context.Context, fcid cid.Cid, piece *cid.Cid, carExport bool, expect []byte) { offers, err := dh.client.ClientFindData(ctx, fcid, piece) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) if len(offers) < 1 { dh.t.Fatal("no offers") } rpath, err := ioutil.TempDir("", "lotus-retrieve-test-") - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + defer os.RemoveAll(rpath) //nolint:errcheck caddr, err := dh.client.WalletDefaultAddress(ctx) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) ref := &api.FileRef{ Path: filepath.Join(rpath, "ret"), IsCAR: carExport, } + updates, err := dh.client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + for update := range updates { - if update.Err != "" { - dh.t.Fatalf("retrieval failed: %s", update.Err) - } + require.Emptyf(dh.t, update.Err, "retrieval failed: %s", update.Err) } rdata, err := ioutil.ReadFile(filepath.Join(rpath, "ret")) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) if carExport { rdata = dh.ExtractCarData(ctx, rdata, rpath) @@ -236,30 +222,25 @@ func (dh *DealHarness) PerformRetrieval(ctx context.Context, fcid cid.Cid, piece func (dh *DealHarness) ExtractCarData(ctx context.Context, rdata []byte, rpath string) []byte { bserv := dstest.Bserv() ch, err := car.LoadCar(bserv.Blockstore(), bytes.NewReader(rdata)) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + b, err := bserv.GetBlock(ctx, ch.Roots[0]) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + nd, err := ipld.Decode(b) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + dserv := dag.NewDAGService(bserv) fil, err := unixfile.NewUnixfsFile(ctx, dserv, nd) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + outPath := filepath.Join(rpath, "retLoadedCAR") - if err := files.WriteTo(fil, outPath); err != nil { - dh.t.Fatal(err) - } + err = files.WriteTo(fil, outPath) + require.NoError(dh.t, err) + rdata, err = ioutil.ReadFile(outPath) - if err != nil { - dh.t.Fatal(err) - } + require.NoError(dh.t, err) + return rdata } From c27fdc263c3bdf9a50aaff64a37972ad3a89654b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 12:22:55 +0100 Subject: [PATCH 06/72] deals harness: more improvements. --- itests/kit/deals.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 12504465642..5d57a91b83f 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -3,7 +3,6 @@ package kit import ( "bytes" "context" - "fmt" "io/ioutil" "os" "path/filepath" @@ -48,7 +47,7 @@ func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, f require.NoError(dh.t, err) fcid := res.Root - fmt.Println("FILE CID: ", fcid) + dh.t.Logf("FILE CID: %s", fcid) deal := dh.StartDeal(ctx, fcid, fastRet, startEpoch) @@ -109,7 +108,7 @@ loop: case storagemarket.StorageDealError: dh.t.Fatal("deal errored", di.Message) case storagemarket.StorageDealActive: - fmt.Println("COMPLETE", di) + dh.t.Log("COMPLETE", di) break loop } @@ -124,7 +123,7 @@ loop: } } - fmt.Printf("Deal %d state: client:%s provider:%s\n", di.DealID, storagemarket.DealStates[di.State], storagemarket.DealStates[minerState]) + dh.t.Logf("Deal %d state: client:%s provider:%s\n", di.DealID, storagemarket.DealStates[di.State], storagemarket.DealStates[minerState]) time.Sleep(time.Second / 2) if cb != nil { cb() @@ -153,10 +152,10 @@ func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { case storagemarket.StorageDealError: dh.t.Fatal("deal errored", di.Message) case storagemarket.StorageDealFinalizing, storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing, storagemarket.StorageDealActive: - fmt.Println("COMPLETE", di) + dh.t.Log("COMPLETE", di) return } - fmt.Println("Deal state: ", storagemarket.DealStates[di.State]) + dh.t.Log("Deal state: ", storagemarket.DealStates[di.State]) } } } @@ -183,9 +182,7 @@ func (dh *DealHarness) PerformRetrieval(ctx context.Context, fcid cid.Cid, piece offers, err := dh.client.ClientFindData(ctx, fcid, piece) require.NoError(dh.t, err) - if len(offers) < 1 { - dh.t.Fatal("no offers") - } + require.NotEmpty(dh.t, offers, "no offers") rpath, err := ioutil.TempDir("", "lotus-retrieve-test-") require.NoError(dh.t, err) From cf0150e05723796b450e31131bfe4d0622109f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 12:23:27 +0100 Subject: [PATCH 07/72] deals harness: use require. --- itests/kit/deals.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 5d57a91b83f..14511dbd1d8 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -81,9 +81,8 @@ func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool MinBlocksDuration: uint64(build.MinDealDuration), FastRetrieval: fastRet, }) - if err != nil { - dh.t.Fatalf("%+v", err) - } + require.NoError(dh.t, err) + return deal } From 329970934ace9a12720d0f77b0442b12c9a5289d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 13:25:36 +0100 Subject: [PATCH 08/72] deals tests: begin migration. --- go.mod | 1 + itests/deals_test.go | 508 ++++++++++++++++++++++++++++++++++++++ itests/deals_test.go.no | 527 ---------------------------------------- itests/kit/ensemble.go | 93 +++++-- 4 files changed, 578 insertions(+), 551 deletions(-) create mode 100644 itests/deals_test.go delete mode 100644 itests/deals_test.go.no diff --git a/go.mod b/go.mod index e22be541a1e..b34ca93220e 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07 github.com/coreos/go-systemd/v22 v22.1.0 + github.com/davecgh/go-spew v1.1.1 // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.2007.2 github.com/docker/go-units v0.4.0 diff --git a/itests/deals_test.go b/itests/deals_test.go new file mode 100644 index 00000000000..977ebce086e --- /dev/null +++ b/itests/deals_test.go @@ -0,0 +1,508 @@ +package itests + +import ( + "bytes" + "context" + "fmt" + "testing" + "time" + + "github.com/davecgh/go-spew/spew" + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/markets/storageadapter" + "github.com/filecoin-project/lotus/node" + market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" + "github.com/stretchr/testify/require" +) + +// +// func TestDealCycle(t *testing.T) { +// kit.QuietMiningLogs() +// +// blockTime := 10 * time.Millisecond +// +// // For these tests where the block time is artificially short, just use +// // a deal start epoch that is guaranteed to be far enough in the future +// // so that the deal starts sealing in time +// dealStartEpoch := abi.ChainEpoch(2 << 12) +// +// t.Run("TestFullDealCycle_Single", func(t *testing.T) { +// runFullDealCycles(t, 1, kit.MockMinerBuilder, blockTime, false, false, dealStartEpoch) +// }) +// t.Run("TestFullDealCycle_Two", func(t *testing.T) { +// runFullDealCycles(t, 2, kit.MockMinerBuilder, blockTime, false, false, dealStartEpoch) +// }) +// t.Run("WithExportedCAR", func(t *testing.T) { +// runFullDealCycles(t, 1, kit.MockMinerBuilder, blockTime, true, false, dealStartEpoch) +// }) +// t.Run("TestFastRetrievalDealCycle", func(t *testing.T) { +// runFastRetrievalDealFlowT(t, kit.MockMinerBuilder, blockTime, dealStartEpoch) +// }) +// t.Run("TestZeroPricePerByteRetrievalDealFlow", func(t *testing.T) { +// runZeroPricePerByteRetrievalDealFlow(t, kit.MockMinerBuilder, blockTime, dealStartEpoch) +// }) +// } +// +// func TestAPIDealFlowReal(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode") +// } +// +// kit.QuietMiningLogs() +// +// // TODO: just set this globally? +// oldDelay := policy.GetPreCommitChallengeDelay() +// policy.SetPreCommitChallengeDelay(5) +// t.Cleanup(func() { +// policy.SetPreCommitChallengeDelay(oldDelay) +// }) +// +// t.Run("basic", func(t *testing.T) { +// runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, false, 0) +// }) +// +// t.Run("fast-retrieval", func(t *testing.T) { +// runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, true, 0) +// }) +// +// t.Run("retrieval-second", func(t *testing.T) { +// runSecondDealRetrievalTest(t, kit.FullNodeBuilder, time.Second) +// }) +// } + +func TestPublishDealsBatching(t *testing.T) { + var ( + ctx = context.Background() + publishPeriod = 10 * time.Second + maxDealsPerMsg = uint64(2) // Set max deals per publish deals message to 2 + startEpoch = abi.ChainEpoch(2 << 12) + ) + + kit.QuietMiningLogs() + + opts := node.Override(new(*storageadapter.DealPublisher), + storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ + Period: publishPeriod, + MaxDealsPerMsg: maxDealsPerMsg, + }), + ) + + client, miner, ens := kit.EnsembleMinimum(t, kit.MockProofs(), kit.ExtraNodeOpts(opts)) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + dh := kit.NewDealHarness(t, client, miner) + + fmt.Println("***********************") + spew.Dump(client.NetPeers(context.Background())) + + // Starts a deal and waits until it's published + runDealTillPublish := func(rseed int) { + res, _, _, err := kit.CreateImportFile(ctx, client, rseed, 0) + require.NoError(t, err) + + upds, err := client.ClientGetDealUpdates(ctx) + require.NoError(t, err) + + dh.StartDeal(ctx, res.Root, false, startEpoch) + + // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this + time.Sleep(time.Second) + + done := make(chan struct{}) + go func() { + for upd := range upds { + if upd.DataRef.Root == res.Root && upd.State == storagemarket.StorageDealAwaitingPreCommit { + done <- struct{}{} + } + } + }() + <-done + } + + // Run three deals in parallel + done := make(chan struct{}, maxDealsPerMsg+1) + for rseed := 1; rseed <= 3; rseed++ { + rseed := rseed + go func() { + runDealTillPublish(rseed) + done <- struct{}{} + }() + } + + // Wait for two of the deals to be published + for i := 0; i < int(maxDealsPerMsg); i++ { + <-done + } + + // Expect a single PublishStorageDeals message that includes the first two deals + msgCids, err := client.StateListMessages(ctx, &api.MessageMatch{To: market.Address}, types.EmptyTSK, 1) + require.NoError(t, err) + count := 0 + for _, msgCid := range msgCids { + msg, err := client.ChainGetMessage(ctx, msgCid) + require.NoError(t, err) + + if msg.Method == market.Methods.PublishStorageDeals { + count++ + var pubDealsParams market2.PublishStorageDealsParams + err = pubDealsParams.UnmarshalCBOR(bytes.NewReader(msg.Params)) + require.NoError(t, err) + require.Len(t, pubDealsParams.Deals, int(maxDealsPerMsg)) + } + } + require.Equal(t, 1, count) + + // The third deal should be published once the publish period expires. + // Allow a little padding as it takes a moment for the state change to + // be noticed by the client. + padding := 10 * time.Second + select { + case <-time.After(publishPeriod + padding): + require.Fail(t, "Expected 3rd deal to be published once publish period elapsed") + case <-done: // Success + } +} + +// +// func TestDealMining(t *testing.T) { +// // test making a deal with a fresh miner, and see if it starts to mine. +// if testing.Short() { +// t.Skip("skipping test in short mode") +// } +// +// kit.QuietMiningLogs() +// +// b := kit.MockMinerBuilder +// blocktime := 50 * time.Millisecond +// +// ctx := context.Background() +// fulls, miners := b(t, +// kit.OneFull, +// []kit.StorageMiner{ +// {Full: 0, Preseal: kit.PresealGenesis}, +// {Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node +// }) +// client := fulls[0].FullNode.(*impl.FullNodeAPI) +// genesisMiner := miners[0] +// provider := miners[1] +// +// addrinfo, err := client.NetAddrsListen(ctx) +// if err != nil { +// t.Fatal(err) +// } +// +// if err := provider.NetConnect(ctx, addrinfo); err != nil { +// t.Fatal(err) +// } +// +// if err := genesisMiner.NetConnect(ctx, addrinfo); err != nil { +// t.Fatal(err) +// } +// +// time.Sleep(time.Second) +// +// data := make([]byte, 600) +// rand.New(rand.NewSource(5)).Read(data) +// +// r := bytes.NewReader(data) +// fcid, err := client.ClientImportLocal(ctx, r) +// if err != nil { +// t.Fatal(err) +// } +// +// fmt.Println("FILE CID: ", fcid) +// +// var mine int32 = 1 +// done := make(chan struct{}) +// minedTwo := make(chan struct{}) +// +// m2addr, err := miners[1].ActorAddress(context.TODO()) +// if err != nil { +// t.Fatal(err) +// } +// +// go func() { +// defer close(done) +// +// complChan := minedTwo +// for atomic.LoadInt32(&mine) != 0 { +// wait := make(chan int) +// mdone := func(mined bool, _ abi.ChainEpoch, err error) { +// n := 0 +// if mined { +// n = 1 +// } +// wait <- n +// } +// +// if err := miners[0].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil { +// t.Error(err) +// } +// +// if err := miners[1].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil { +// t.Error(err) +// } +// +// expect := <-wait +// expect += <-wait +// +// time.Sleep(blocktime) +// if expect == 0 { +// // null block +// continue +// } +// +// var nodeOneMined bool +// for _, node := range miners { +// mb, err := node.MiningBase(ctx) +// if err != nil { +// t.Error(err) +// return +// } +// +// for _, b := range mb.Blocks() { +// if b.Miner == m2addr { +// nodeOneMined = true +// break +// } +// } +// +// } +// +// if nodeOneMined && complChan != nil { +// close(complChan) +// complChan = nil +// } +// +// } +// }() +// +// dh := kit.NewDealHarness(t, client, provider) +// +// deal := dh.StartDeal(ctx, fcid, false, 0) +// +// // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this +// time.Sleep(time.Second) +// +// dh.WaitDealSealed(ctx, deal, false, false, nil) +// +// <-minedTwo +// +// atomic.StoreInt32(&mine, 0) +// fmt.Println("shutting down mining") +// <-done +// } +// +// func TestOfflineDealFlow(t *testing.T) { +// blocktime := 10 * time.Millisecond +// +// // For these tests where the block time is artificially short, just use +// // a deal start epoch that is guaranteed to be far enough in the future +// // so that the deal starts sealing in time +// startEpoch := abi.ChainEpoch(2 << 12) +// +// runTest := func(t *testing.T, fastRet bool) { +// ctx := context.Background() +// fulls, miners := kit.MockMinerBuilder(t, kit.OneFull, kit.OneMiner) +// client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] +// +// kit.ConnectAndStartMining(t, blocktime, miner, client) +// +// dh := kit.NewDealHarness(t, client, miner) +// +// // Create a random file and import on the client. +// res, path, data, err := kit.CreateImportFile(ctx, client, 1, 0) +// require.NoError(t, err) +// +// // Get the piece size and commP +// fcid := res.Root +// pieceInfo, err := client.ClientDealPieceCID(ctx, fcid) +// require.NoError(t, err) +// fmt.Println("FILE CID: ", fcid) +// +// // Create a storage deal with the miner +// maddr, err := miner.ActorAddress(ctx) +// require.NoError(t, err) +// +// addr, err := client.WalletDefaultAddress(ctx) +// require.NoError(t, err) +// +// // Manual storage deal (offline deal) +// dataRef := &storagemarket.DataRef{ +// TransferType: storagemarket.TTManual, +// Root: fcid, +// PieceCid: &pieceInfo.PieceCID, +// PieceSize: pieceInfo.PieceSize.Unpadded(), +// } +// +// proposalCid, err := client.ClientStartDeal(ctx, &api.StartDealParams{ +// Data: dataRef, +// Wallet: addr, +// Miner: maddr, +// EpochPrice: types.NewInt(1000000), +// DealStartEpoch: startEpoch, +// MinBlocksDuration: uint64(build.MinDealDuration), +// FastRetrieval: fastRet, +// }) +// require.NoError(t, err) +// +// // Wait for the deal to reach StorageDealCheckForAcceptance on the client +// cd, err := client.ClientGetDealInfo(ctx, *proposalCid) +// require.NoError(t, err) +// require.Eventually(t, func() bool { +// cd, _ := client.ClientGetDealInfo(ctx, *proposalCid) +// return cd.State == storagemarket.StorageDealCheckForAcceptance +// }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) +// +// // Create a CAR file from the raw file +// carFileDir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-car") +// require.NoError(t, err) +// carFilePath := filepath.Join(carFileDir, "out.car") +// err = client.ClientGenCar(ctx, api.FileRef{Path: path}, carFilePath) +// require.NoError(t, err) +// +// // Import the CAR file on the miner - this is the equivalent to +// // transferring the file across the wire in a normal (non-offline) deal +// err = miner.DealsImportData(ctx, *proposalCid, carFilePath) +// require.NoError(t, err) +// +// // Wait for the deal to be published +// dh.WaitDealPublished(ctx, proposalCid) +// +// t.Logf("deal published, retrieving") +// +// // Retrieve the deal +// dh.PerformRetrieval(ctx, fcid, &pieceInfo.PieceCID, false, data) +// } +// +// t.Run("NormalRetrieval", func(t *testing.T) { +// runTest(t, false) +// }) +// t.Run("FastRetrieval", func(t *testing.T) { +// runTest(t, true) +// }) +// +// } +// +// func runFullDealCycles(t *testing.T, n int, b kit.APIBuilder, blocktime time.Duration, carExport, fastRet bool, startEpoch abi.ChainEpoch) { +// full, _, ens := kit.EnsembleMinimum(t) +// ens.BeginMining() +// dh := kit.NewDealHarness(t, client, miner) +// +// baseseed := 6 +// for i := 0; i < n; i++ { +// dh.MakeFullDeal(context.Background(), baseseed+i, carExport, fastRet, startEpoch) +// } +// } +// +// func runFastRetrievalDealFlowT(t *testing.T, b kit.APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch) { +// ctx := context.Background() +// +// var ( +// nb = kit.NewNodeBuilder(t) +// full = nb.FullNode() +// miner = nb.Miner(full) +// ) +// +// nb.Create() +// +// 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 := full.FullNode.(*impl.FullNodeAPI).ClientImportLocal(ctx, r) +// require.NoError(t, err) +// +// fmt.Println("FILE CID: ", fcid) +// +// deal := dh.StartDeal(ctx, fcid, true, startEpoch) +// dh.WaitDealPublished(ctx, deal) +// +// fmt.Println("deal published, retrieving") +// +// // Retrieval +// info, err := full.ClientGetDealInfo(ctx, *deal) +// require.NoError(t, err) +// +// dh.PerformRetrieval(ctx, fcid, &info.PieceCID, false, data) +// } +// +// func runSecondDealRetrievalTest(t *testing.T, b kit.APIBuilder, blocktime time.Duration) { +// ctx := context.Background() +// +// fulls, miners := b(t, kit.OneFull, kit.OneMiner) +// client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] +// +// kit.ConnectAndStartMining(t, blocktime, miner, client) +// +// dh := kit.NewDealHarness(t, client, miner) +// +// { +// data1 := make([]byte, 800) +// rand.New(rand.NewSource(int64(3))).Read(data1) +// r := bytes.NewReader(data1) +// +// fcid1, err := client.ClientImportLocal(ctx, r) +// if err != nil { +// t.Fatal(err) +// } +// +// data2 := make([]byte, 800) +// rand.New(rand.NewSource(int64(9))).Read(data2) +// r2 := bytes.NewReader(data2) +// +// fcid2, err := client.ClientImportLocal(ctx, r2) +// if err != nil { +// t.Fatal(err) +// } +// +// deal1 := dh.StartDeal(ctx, fcid1, true, 0) +// +// // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this +// time.Sleep(time.Second) +// dh.WaitDealSealed(ctx, deal1, true, false, nil) +// +// deal2 := dh.StartDeal(ctx, fcid2, true, 0) +// +// time.Sleep(time.Second) +// dh.WaitDealSealed(ctx, deal2, false, false, nil) +// +// // Retrieval +// info, err := client.ClientGetDealInfo(ctx, *deal2) +// require.NoError(t, err) +// +// rf, _ := miner.SectorsRefs(ctx) +// fmt.Printf("refs: %+v\n", rf) +// +// dh.PerformRetrieval(ctx, fcid2, &info.PieceCID, false, data2) +// } +// } +// +// func runZeroPricePerByteRetrievalDealFlow(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] +// +// kit.ConnectAndStartMining(t, blocktime, miner, client) +// +// dh := kit.NewDealHarness(t, client, miner) +// +// // Set price-per-byte to zero +// ask, err := miner.MarketGetRetrievalAsk(ctx) +// require.NoError(t, err) +// +// ask.PricePerByte = abi.NewTokenAmount(0) +// err = miner.MarketSetRetrievalAsk(ctx, ask) +// require.NoError(t, err) +// +// dh.MakeFullDeal(ctx, 6, false, false, startEpoch) +// } diff --git a/itests/deals_test.go.no b/itests/deals_test.go.no deleted file mode 100644 index b3c7cd9c70f..00000000000 --- a/itests/deals_test.go.no +++ /dev/null @@ -1,527 +0,0 @@ -package itests - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "math/rand" - "os" - "path/filepath" - "sync/atomic" - "testing" - "time" - - "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors/builtin/market" - "github.com/filecoin-project/lotus/chain/actors/policy" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/markets/storageadapter" - "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" -) - -func TestDealCycle(t *testing.T) { - kit.QuietMiningLogs() - - blockTime := 10 * time.Millisecond - - // For these tests where the block time is artificially short, just use - // a deal start epoch that is guaranteed to be far enough in the future - // so that the deal starts sealing in time - dealStartEpoch := abi.ChainEpoch(2 << 12) - - t.Run("TestFullDealCycle_Single", func(t *testing.T) { - runFullDealCycles(t, 1, kit.MockMinerBuilder, blockTime, false, false, dealStartEpoch) - }) - t.Run("TestFullDealCycle_Two", func(t *testing.T) { - runFullDealCycles(t, 2, kit.MockMinerBuilder, blockTime, false, false, dealStartEpoch) - }) - t.Run("WithExportedCAR", func(t *testing.T) { - runFullDealCycles(t, 1, kit.MockMinerBuilder, blockTime, true, false, dealStartEpoch) - }) - t.Run("TestFastRetrievalDealCycle", func(t *testing.T) { - runFastRetrievalDealFlowT(t, kit.MockMinerBuilder, blockTime, dealStartEpoch) - }) - t.Run("TestZeroPricePerByteRetrievalDealFlow", func(t *testing.T) { - runZeroPricePerByteRetrievalDealFlow(t, kit.MockMinerBuilder, blockTime, dealStartEpoch) - }) -} - -func TestAPIDealFlowReal(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode") - } - - kit.QuietMiningLogs() - - // TODO: just set this globally? - oldDelay := policy.GetPreCommitChallengeDelay() - policy.SetPreCommitChallengeDelay(5) - t.Cleanup(func() { - policy.SetPreCommitChallengeDelay(oldDelay) - }) - - t.Run("basic", func(t *testing.T) { - runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, false, 0) - }) - - t.Run("fast-retrieval", func(t *testing.T) { - runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, true, 0) - }) - - t.Run("retrieval-second", func(t *testing.T) { - runSecondDealRetrievalTest(t, kit.FullNodeBuilder, time.Second) - }) -} - -func TestPublishDealsBatching(t *testing.T) { - ctx := context.Background() - - kit.QuietMiningLogs() - - b := kit.MockMinerBuilder - blocktime := 10 * time.Millisecond - startEpoch := abi.ChainEpoch(2 << 12) - - publishPeriod := 10 * time.Second - maxDealsPerMsg := uint64(2) - - // Set max deals per publish deals message to 2 - minerDef := []kit.StorageMiner{{ - Full: 0, - Opts: node.Override( - new(*storageadapter.DealPublisher), - storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ - Period: publishPeriod, - MaxDealsPerMsg: maxDealsPerMsg, - })), - Preseal: kit.PresealGenesis, - }} - - // Create a connect client and miner node - n, sn := b(t, kit.OneFull, minerDef) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - kit.ConnectAndStartMining(t, blocktime, miner, client) - - dh := kit.NewDealHarness(t, client, miner) - - // Starts a deal and waits until it's published - runDealTillPublish := func(rseed int) { - res, _, _, err := kit.CreateImportFile(ctx, client, rseed, 0) - require.NoError(t, err) - - upds, err := client.ClientGetDealUpdates(ctx) - require.NoError(t, err) - - dh.StartDeal(ctx, res.Root, false, startEpoch) - - // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this - time.Sleep(time.Second) - - done := make(chan struct{}) - go func() { - for upd := range upds { - if upd.DataRef.Root == res.Root && upd.State == storagemarket.StorageDealAwaitingPreCommit { - done <- struct{}{} - } - } - }() - <-done - } - - // Run three deals in parallel - done := make(chan struct{}, maxDealsPerMsg+1) - for rseed := 1; rseed <= 3; rseed++ { - rseed := rseed - go func() { - runDealTillPublish(rseed) - done <- struct{}{} - }() - } - - // Wait for two of the deals to be published - for i := 0; i < int(maxDealsPerMsg); i++ { - <-done - } - - // Expect a single PublishStorageDeals message that includes the first two deals - msgCids, err := client.StateListMessages(ctx, &api.MessageMatch{To: market.Address}, types.EmptyTSK, 1) - require.NoError(t, err) - count := 0 - for _, msgCid := range msgCids { - msg, err := client.ChainGetMessage(ctx, msgCid) - require.NoError(t, err) - - if msg.Method == market.Methods.PublishStorageDeals { - count++ - var pubDealsParams market2.PublishStorageDealsParams - err = pubDealsParams.UnmarshalCBOR(bytes.NewReader(msg.Params)) - require.NoError(t, err) - require.Len(t, pubDealsParams.Deals, int(maxDealsPerMsg)) - } - } - require.Equal(t, 1, count) - - // The third deal should be published once the publish period expires. - // Allow a little padding as it takes a moment for the state change to - // be noticed by the client. - padding := 10 * time.Second - select { - case <-time.After(publishPeriod + padding): - require.Fail(t, "Expected 3rd deal to be published once publish period elapsed") - case <-done: // Success - } -} - -func TestDealMining(t *testing.T) { - // test making a deal with a fresh miner, and see if it starts to mine. - if testing.Short() { - t.Skip("skipping test in short mode") - } - - kit.QuietMiningLogs() - - b := kit.MockMinerBuilder - blocktime := 50 * time.Millisecond - - ctx := context.Background() - fulls, miners := b(t, - kit.OneFull, - []kit.StorageMiner{ - {Full: 0, Preseal: kit.PresealGenesis}, - {Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node - }) - client := fulls[0].FullNode.(*impl.FullNodeAPI) - genesisMiner := miners[0] - provider := miners[1] - - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := provider.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - - if err := genesisMiner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - - time.Sleep(time.Second) - - data := make([]byte, 600) - rand.New(rand.NewSource(5)).Read(data) - - r := bytes.NewReader(data) - fcid, err := client.ClientImportLocal(ctx, r) - if err != nil { - t.Fatal(err) - } - - fmt.Println("FILE CID: ", fcid) - - var mine int32 = 1 - done := make(chan struct{}) - minedTwo := make(chan struct{}) - - m2addr, err := miners[1].ActorAddress(context.TODO()) - if err != nil { - t.Fatal(err) - } - - go func() { - defer close(done) - - complChan := minedTwo - for atomic.LoadInt32(&mine) != 0 { - wait := make(chan int) - mdone := func(mined bool, _ abi.ChainEpoch, err error) { - n := 0 - if mined { - n = 1 - } - wait <- n - } - - if err := miners[0].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil { - t.Error(err) - } - - if err := miners[1].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil { - t.Error(err) - } - - expect := <-wait - expect += <-wait - - time.Sleep(blocktime) - if expect == 0 { - // null block - continue - } - - var nodeOneMined bool - for _, node := range miners { - mb, err := node.MiningBase(ctx) - if err != nil { - t.Error(err) - return - } - - for _, b := range mb.Blocks() { - if b.Miner == m2addr { - nodeOneMined = true - break - } - } - - } - - if nodeOneMined && complChan != nil { - close(complChan) - complChan = nil - } - - } - }() - - dh := kit.NewDealHarness(t, client, provider) - - deal := dh.StartDeal(ctx, fcid, false, 0) - - // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this - time.Sleep(time.Second) - - dh.WaitDealSealed(ctx, deal, false, false, nil) - - <-minedTwo - - atomic.StoreInt32(&mine, 0) - fmt.Println("shutting down mining") - <-done -} - -func TestOfflineDealFlow(t *testing.T) { - blocktime := 10 * time.Millisecond - - // For these tests where the block time is artificially short, just use - // a deal start epoch that is guaranteed to be far enough in the future - // so that the deal starts sealing in time - startEpoch := abi.ChainEpoch(2 << 12) - - runTest := func(t *testing.T, fastRet bool) { - ctx := context.Background() - fulls, miners := kit.MockMinerBuilder(t, kit.OneFull, kit.OneMiner) - client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] - - kit.ConnectAndStartMining(t, blocktime, miner, client) - - dh := kit.NewDealHarness(t, client, miner) - - // Create a random file and import on the client. - res, path, data, err := kit.CreateImportFile(ctx, client, 1, 0) - require.NoError(t, err) - - // Get the piece size and commP - fcid := res.Root - pieceInfo, err := client.ClientDealPieceCID(ctx, fcid) - require.NoError(t, err) - fmt.Println("FILE CID: ", fcid) - - // Create a storage deal with the miner - maddr, err := miner.ActorAddress(ctx) - require.NoError(t, err) - - addr, err := client.WalletDefaultAddress(ctx) - require.NoError(t, err) - - // Manual storage deal (offline deal) - dataRef := &storagemarket.DataRef{ - TransferType: storagemarket.TTManual, - Root: fcid, - PieceCid: &pieceInfo.PieceCID, - PieceSize: pieceInfo.PieceSize.Unpadded(), - } - - proposalCid, err := client.ClientStartDeal(ctx, &api.StartDealParams{ - Data: dataRef, - Wallet: addr, - Miner: maddr, - EpochPrice: types.NewInt(1000000), - DealStartEpoch: startEpoch, - MinBlocksDuration: uint64(build.MinDealDuration), - FastRetrieval: fastRet, - }) - require.NoError(t, err) - - // Wait for the deal to reach StorageDealCheckForAcceptance on the client - cd, err := client.ClientGetDealInfo(ctx, *proposalCid) - require.NoError(t, err) - require.Eventually(t, func() bool { - cd, _ := client.ClientGetDealInfo(ctx, *proposalCid) - return cd.State == storagemarket.StorageDealCheckForAcceptance - }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) - - // Create a CAR file from the raw file - carFileDir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-car") - require.NoError(t, err) - carFilePath := filepath.Join(carFileDir, "out.car") - err = client.ClientGenCar(ctx, api.FileRef{Path: path}, carFilePath) - require.NoError(t, err) - - // Import the CAR file on the miner - this is the equivalent to - // transferring the file across the wire in a normal (non-offline) deal - err = miner.DealsImportData(ctx, *proposalCid, carFilePath) - require.NoError(t, err) - - // Wait for the deal to be published - dh.WaitDealPublished(ctx, proposalCid) - - t.Logf("deal published, retrieving") - - // Retrieve the deal - dh.TestRetrieval(ctx, fcid, &pieceInfo.PieceCID, false, data) - } - - t.Run("NormalRetrieval", func(t *testing.T) { - runTest(t, false) - }) - t.Run("FastRetrieval", func(t *testing.T) { - runTest(t, true) - }) - -} - -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] - - kit.ConnectAndStartMining(t, blocktime, miner, client) - - dh := kit.NewDealHarness(t, client, miner) - - baseseed := 6 - for i := 0; i < n; i++ { - dh.MakeFullDeal(context.Background(), baseseed+i, carExport, fastRet, startEpoch) - } -} - -func runFastRetrievalDealFlowT(t *testing.T, b kit.APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch) { - ctx := context.Background() - - var ( - nb = kit.NewNodeBuilder(t) - full = nb.FullNode() - miner = nb.Miner(full) - ) - - nb.Create() - - 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 := full.FullNode.(*impl.FullNodeAPI).ClientImportLocal(ctx, r) - require.NoError(t, err) - - fmt.Println("FILE CID: ", fcid) - - deal := dh.StartDeal(ctx, fcid, true, startEpoch) - dh.WaitDealPublished(ctx, deal) - - fmt.Println("deal published, retrieving") - - // Retrieval - info, err := full.ClientGetDealInfo(ctx, *deal) - require.NoError(t, err) - - dh.TestRetrieval(ctx, fcid, &info.PieceCID, false, data) -} - -func runSecondDealRetrievalTest(t *testing.T, b kit.APIBuilder, blocktime time.Duration) { - ctx := context.Background() - - fulls, miners := b(t, kit.OneFull, kit.OneMiner) - client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] - - kit.ConnectAndStartMining(t, blocktime, miner, client) - - dh := kit.NewDealHarness(t, client, miner) - - { - data1 := make([]byte, 800) - rand.New(rand.NewSource(int64(3))).Read(data1) - r := bytes.NewReader(data1) - - fcid1, err := client.ClientImportLocal(ctx, r) - if err != nil { - t.Fatal(err) - } - - data2 := make([]byte, 800) - rand.New(rand.NewSource(int64(9))).Read(data2) - r2 := bytes.NewReader(data2) - - fcid2, err := client.ClientImportLocal(ctx, r2) - if err != nil { - t.Fatal(err) - } - - deal1 := dh.StartDeal(ctx, fcid1, true, 0) - - // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this - time.Sleep(time.Second) - dh.WaitDealSealed(ctx, deal1, true, false, nil) - - deal2 := dh.StartDeal(ctx, fcid2, true, 0) - - time.Sleep(time.Second) - dh.WaitDealSealed(ctx, deal2, false, false, nil) - - // Retrieval - info, err := client.ClientGetDealInfo(ctx, *deal2) - require.NoError(t, err) - - rf, _ := miner.SectorsRefs(ctx) - fmt.Printf("refs: %+v\n", rf) - - dh.TestRetrieval(ctx, fcid2, &info.PieceCID, false, data2) - } -} - -func runZeroPricePerByteRetrievalDealFlow(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] - - kit.ConnectAndStartMining(t, blocktime, miner, client) - - dh := kit.NewDealHarness(t, client, miner) - - // Set price-per-byte to zero - ask, err := miner.MarketGetRetrievalAsk(ctx) - require.NoError(t, err) - - ask.PricePerByte = abi.NewTokenAmount(0) - err = miner.MarketSetRetrievalAsk(ctx, ask) - require.NoError(t, err) - - dh.MakeFullDeal(ctx, 6, false, false, startEpoch) -} diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 00c84ddfa12..224df64e2d4 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -114,12 +114,13 @@ func NewEnsemble(t *testing.T, opts ...BuilderOpt) *Ensemble { } type NodeOpts struct { - balance abi.TokenAmount - lite bool - sectors int - mockProofs bool - rpc bool - ownerKey *wallet.Key + balance abi.TokenAmount + lite bool + sectors int + mockProofs bool + rpc bool + ownerKey *wallet.Key + extraNodeOpts []node.Option } var DefaultNodeOpts = NodeOpts{ @@ -182,6 +183,13 @@ func OwnerAddr(wk *wallet.Key) NodeOpt { } } +func ExtraNodeOpts(extra ...node.Option) NodeOpt { + return func(opts *NodeOpts) error { + opts.extraNodeOpts = extra + return nil + } +} + // FullNode enrolls a new full node. func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { options := DefaultNodeOpts @@ -300,6 +308,10 @@ func (n *Ensemble) Start() *Ensemble { n.mn = mocknet.New(ctx) } + // --------------------- + // FULL NODES + // --------------------- + // Create all inactive full nodes. for i, full := range n.inactive.fullnodes { opts := []node.Option{ @@ -313,6 +325,9 @@ func (n *Ensemble) Start() *Ensemble { node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), } + // append any node builder options. + opts = append(opts, full.options.extraNodeOpts...) + // 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))) @@ -322,7 +337,10 @@ func (n *Ensemble) Start() *Ensemble { // Are we mocking proofs? if full.options.mockProofs { - opts = append(opts, node.Override(new(ffiwrapper.Verifier), mock.MockVerifier)) + opts = append(opts, + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Override(new(ffiwrapper.Prover), mock.MockProver), + ) } // Construct the full node. @@ -356,6 +374,10 @@ func (n *Ensemble) Start() *Ensemble { err := n.mn.LinkAll() require.NoError(n.t, err) + // --------------------- + // MINERS + // --------------------- + // Create all inactive miners. for i, m := range n.inactive.miners { if n.bootstrapped { @@ -469,23 +491,35 @@ func (n *Ensemble) Start() *Ensemble { node.Override(new(*lotusminer.Miner), lotusminer.NewTestMiner(mineBlock, m.ActorAddr)), } + // append any node builder options. + opts = append(opts, m.options.extraNodeOpts...) + 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{ + // preload preseals if the network still hasn't bootstrapped. + var presealSectors []abi.SectorID + if !n.bootstrapped { + sectors := n.genesis.miners[i].Sectors + for _, sector := range sectors { + presealSectors = append(presealSectors, abi.SectorID{ Miner: abi.ActorID(idAddr), Number: sector.SectorID, - } + }) } + } + + if m.options.mockProofs { opts = append(opts, - node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { - return mock.NewMockSectorMgr(sectors), nil + node.Override(new(*mock.SectorMgr), func() (*mock.SectorMgr, error) { + return mock.NewMockSectorMgr(presealSectors), nil }), + node.Override(new(sectorstorage.SectorManager), node.From(new(*mock.SectorMgr))), + node.Override(new(sectorstorage.Unsealer), node.From(new(*mock.SectorMgr))), + node.Override(new(sectorstorage.PieceProvider), node.From(new(*mock.SectorMgr))), + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Override(new(ffiwrapper.Prover), mock.MockProver), node.Unset(new(*sectorstorage.Manager)), ) } @@ -532,9 +566,7 @@ func (n *Ensemble) Start() *Ensemble { 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 + // We have *just* bootstrapped, so mine 2 blocks to setup some CE stuff in some actors var wait sync.Mutex wait.Lock() @@ -557,22 +589,32 @@ func (n *Ensemble) Start() *Ensemble { 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. +// InterconnectAll connects all miners and full nodes to one another. func (n *Ensemble) InterconnectAll() *Ensemble { + // connect full nodes to miners. + for _, from := range n.active.fullnodes { + for _, to := range n.active.miners { + // []*TestMiner to []api.CommonAPI type coercion not possible + // so cannot use variadic form. + n.Connect(from, to) + } + } + + // connect full nodes between each other, skipping ourselves. 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:]...) + for _, to := range n.active.fullnodes[i+1:] { + n.Connect(from, to) + } } return n } // Connect connects one full node to the provided full nodes. -func (n *Ensemble) Connect(from *TestFullNode, to ...*TestFullNode) *Ensemble { +func (n *Ensemble) Connect(from api.Common, to ...api.Common) *Ensemble { addr, err := from.NetAddrsListen(context.Background()) require.NoError(n.t, err) @@ -584,7 +626,8 @@ func (n *Ensemble) Connect(from *TestFullNode, to ...*TestFullNode) *Ensemble { } // BeginMining kicks off mining for the specified miners. If nil or 0-length, -// it will kick off mining for all enrolled and active miners. +// it will kick off mining for all enrolled and active miners. It also adds a +// cleanup function to stop all mining operations on test teardown. func (n *Ensemble) BeginMining(blocktime time.Duration, miners ...*TestMiner) []*BlockMiner { ctx := context.Background() @@ -601,6 +644,8 @@ func (n *Ensemble) BeginMining(blocktime time.Duration, miners ...*TestMiner) [] for _, m := range miners { bm := NewBlockMiner(n.t, m) bm.MineBlocks(ctx, blocktime) + n.t.Cleanup(bm.Stop) + bms = append(bms, bm) } From 4f2aaa54d24983cc2fcd2abe1d0f62d61792ef1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 14:04:39 +0100 Subject: [PATCH 09/72] deals tests: refactor/simplify TestDealMining; now TestFirstDealEnablesMining. --- itests/api_test.go | 12 +- itests/deals_test.go | 202 +++++++++++---------------------- itests/kit/ensemble.go | 7 +- itests/kit/ensemble_presets.go | 24 +++- 4 files changed, 99 insertions(+), 146 deletions(-) diff --git a/itests/api_test.go b/itests/api_test.go index 22bbc6f6e99..c6694a554f6 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -48,7 +48,7 @@ func (ts *apiSuite) testVersion(t *testing.T) { lapi.RunningNodeType = lapi.NodeUnknown }) - full, _, _ := kit.EnsembleMinimum(t, ts.opts...) + full, _, _ := kit.EnsembleMinimal(t, ts.opts...) v, err := full.Version(context.Background()) require.NoError(t, err) @@ -61,7 +61,7 @@ func (ts *apiSuite) testVersion(t *testing.T) { func (ts *apiSuite) testID(t *testing.T) { ctx := context.Background() - full, _, _ := kit.EnsembleMinimum(t, ts.opts...) + full, _, _ := kit.EnsembleMinimal(t, ts.opts...) id, err := full.ID(ctx) if err != nil { @@ -73,7 +73,7 @@ func (ts *apiSuite) testID(t *testing.T) { func (ts *apiSuite) testConnectTwo(t *testing.T) { ctx := context.Background() - one, two, _, ens := kit.EnsembleTwo(t, ts.opts...) + one, two, _, ens := kit.EnsembleTwoOne(t, ts.opts...) p, err := one.NetPeers(ctx) require.NoError(t, err) @@ -97,7 +97,7 @@ func (ts *apiSuite) testConnectTwo(t *testing.T) { func (ts *apiSuite) testSearchMsg(t *testing.T) { ctx := context.Background() - full, _, ens := kit.EnsembleMinimum(t, ts.opts...) + full, _, ens := kit.EnsembleMinimal(t, ts.opts...) senderAddr, err := full.WalletDefaultAddress(ctx) require.NoError(t, err) @@ -127,7 +127,7 @@ func (ts *apiSuite) testSearchMsg(t *testing.T) { func (ts *apiSuite) testMining(t *testing.T) { ctx := context.Background() - full, miner, _ := kit.EnsembleMinimum(t, ts.opts...) + full, miner, _ := kit.EnsembleMinimal(t, ts.opts...) newHeads, err := full.ChainNotify(ctx) require.NoError(t, err) @@ -170,7 +170,7 @@ func (ts *apiSuite) testMiningReal(t *testing.T) { func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { ctx := context.Background() - full, genesisMiner, ens := kit.EnsembleMinimum(t, ts.opts...) + full, genesisMiner, ens := kit.EnsembleMinimal(t, ts.opts...) ens.BeginMining(4 * time.Millisecond) diff --git a/itests/deals_test.go b/itests/deals_test.go index 977ebce086e..ad9429dc1cd 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -3,11 +3,9 @@ package itests import ( "bytes" "context" - "fmt" "testing" "time" - "github.com/davecgh/go-spew/spew" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" @@ -92,14 +90,11 @@ func TestPublishDealsBatching(t *testing.T) { }), ) - client, miner, ens := kit.EnsembleMinimum(t, kit.MockProofs(), kit.ExtraNodeOpts(opts)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ExtraNodeOpts(opts)) ens.InterconnectAll().BeginMining(10 * time.Millisecond) dh := kit.NewDealHarness(t, client, miner) - fmt.Println("***********************") - spew.Dump(client.NetPeers(context.Background())) - // Starts a deal and waits until it's published runDealTillPublish := func(rseed int) { res, _, _, err := kit.CreateImportFile(ctx, client, rseed, 0) @@ -168,135 +163,70 @@ func TestPublishDealsBatching(t *testing.T) { } } -// -// func TestDealMining(t *testing.T) { -// // test making a deal with a fresh miner, and see if it starts to mine. -// if testing.Short() { -// t.Skip("skipping test in short mode") -// } -// -// kit.QuietMiningLogs() -// -// b := kit.MockMinerBuilder -// blocktime := 50 * time.Millisecond -// -// ctx := context.Background() -// fulls, miners := b(t, -// kit.OneFull, -// []kit.StorageMiner{ -// {Full: 0, Preseal: kit.PresealGenesis}, -// {Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node -// }) -// client := fulls[0].FullNode.(*impl.FullNodeAPI) -// genesisMiner := miners[0] -// provider := miners[1] -// -// addrinfo, err := client.NetAddrsListen(ctx) -// if err != nil { -// t.Fatal(err) -// } -// -// if err := provider.NetConnect(ctx, addrinfo); err != nil { -// t.Fatal(err) -// } -// -// if err := genesisMiner.NetConnect(ctx, addrinfo); err != nil { -// t.Fatal(err) -// } -// -// time.Sleep(time.Second) -// -// data := make([]byte, 600) -// rand.New(rand.NewSource(5)).Read(data) -// -// r := bytes.NewReader(data) -// fcid, err := client.ClientImportLocal(ctx, r) -// if err != nil { -// t.Fatal(err) -// } -// -// fmt.Println("FILE CID: ", fcid) -// -// var mine int32 = 1 -// done := make(chan struct{}) -// minedTwo := make(chan struct{}) -// -// m2addr, err := miners[1].ActorAddress(context.TODO()) -// if err != nil { -// t.Fatal(err) -// } -// -// go func() { -// defer close(done) -// -// complChan := minedTwo -// for atomic.LoadInt32(&mine) != 0 { -// wait := make(chan int) -// mdone := func(mined bool, _ abi.ChainEpoch, err error) { -// n := 0 -// if mined { -// n = 1 -// } -// wait <- n -// } -// -// if err := miners[0].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil { -// t.Error(err) -// } -// -// if err := miners[1].MineOne(ctx, miner.MineReq{Done: mdone}); err != nil { -// t.Error(err) -// } -// -// expect := <-wait -// expect += <-wait -// -// time.Sleep(blocktime) -// if expect == 0 { -// // null block -// continue -// } -// -// var nodeOneMined bool -// for _, node := range miners { -// mb, err := node.MiningBase(ctx) -// if err != nil { -// t.Error(err) -// return -// } -// -// for _, b := range mb.Blocks() { -// if b.Miner == m2addr { -// nodeOneMined = true -// break -// } -// } -// -// } -// -// if nodeOneMined && complChan != nil { -// close(complChan) -// complChan = nil -// } -// -// } -// }() -// -// dh := kit.NewDealHarness(t, client, provider) -// -// deal := dh.StartDeal(ctx, fcid, false, 0) -// -// // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this -// time.Sleep(time.Second) -// -// dh.WaitDealSealed(ctx, deal, false, false, nil) -// -// <-minedTwo -// -// atomic.StoreInt32(&mine, 0) -// fmt.Println("shutting down mining") -// <-done -// } +func TestFirstDealEnablesMining(t *testing.T) { + // test making a deal with a fresh miner, and see if it starts to mine. + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit.QuietMiningLogs() + + var ( + client kit.TestFullNode + genMiner kit.TestMiner // bootstrap + provider kit.TestMiner // no sectors, will need to create one + ) + + ens := kit.NewEnsemble(t) + ens.FullNode(&client, kit.MockProofs()) + ens.Miner(&genMiner, &client, kit.MockProofs()) + ens.Miner(&provider, &client, kit.MockProofs(), kit.PresealSectors(0)) + ens.Start().InterconnectAll().BeginMining(50 * time.Millisecond) + + ctx := context.Background() + + dh := kit.NewDealHarness(t, client, &provider) + + ref, _, _, err := kit.CreateImportFile(ctx, client, 5, 0) + require.NoError(t, err) + + t.Log("FILE CID:", ref.Root) + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // start a goroutine to monitor head changes from the client + // once the provider has mined a block, thanks to the power acquired from the deal, + // we pass the test. + providerMined := make(chan struct{}) + heads, err := client.ChainNotify(ctx) + go func() { + for chg := range heads { + for _, c := range chg { + if c.Type != "apply" { + continue + } + for _, b := range c.Val.Blocks() { + if b.Miner == provider.ActorAddr { + close(providerMined) + return + } + } + } + } + }() + + // now perform the deal. + deal := dh.StartDeal(ctx, ref.Root, false, 0) + + // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this + time.Sleep(time.Second) + + dh.WaitDealSealed(ctx, deal, false, false, nil) + + <-providerMined +} + // // func TestOfflineDealFlow(t *testing.T) { // blocktime := 10 * time.Millisecond @@ -390,7 +320,7 @@ func TestPublishDealsBatching(t *testing.T) { // } // // func runFullDealCycles(t *testing.T, n int, b kit.APIBuilder, blocktime time.Duration, carExport, fastRet bool, startEpoch abi.ChainEpoch) { -// full, _, ens := kit.EnsembleMinimum(t) +// full, _, ens := kit.EnsembleMinimal(t) // ens.BeginMining() // dh := kit.NewDealHarness(t, client, miner) // diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 224df64e2d4..cfc95e968fa 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -123,9 +123,11 @@ type NodeOpts struct { extraNodeOpts []node.Option } +const DefaultPresealsPerBootstrapMiner = 2 + var DefaultNodeOpts = NodeOpts{ balance: big.Mul(big.NewInt(100000000), types.NewInt(build.FilecoinPrecision)), - sectors: 2, + sectors: DefaultPresealsPerBootstrapMiner, } type NodeOpt func(opts *NodeOpts) error @@ -215,7 +217,7 @@ func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { n.genesis.accounts = append(n.genesis.accounts, genacc) } - *full = TestFullNode{options: options, DefaultKey: key} + *full = TestFullNode{t: n.t, options: options, DefaultKey: key} n.inactive.fullnodes = append(n.inactive.fullnodes, full) return n } @@ -280,6 +282,7 @@ func (n *Ensemble) Miner(miner *TestMiner, full *TestFullNode, opts ...NodeOpt) } *miner = TestMiner{ + t: n.t, ActorAddr: actorAddr, OwnerKey: ownerKey, FullNode: full, diff --git a/itests/kit/ensemble_presets.go b/itests/kit/ensemble_presets.go index debad2ed149..fa7746f9572 100644 --- a/itests/kit/ensemble_presets.go +++ b/itests/kit/ensemble_presets.go @@ -2,7 +2,9 @@ package kit import "testing" -func EnsembleMinimum(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestMiner, *Ensemble) { +// EnsembleMinimal creates and starts an ensemble with a single full node and a single miner. +// It does not interconnect nodes nor does it begin mining. +func EnsembleMinimal(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestMiner, *Ensemble) { var ( full TestFullNode miner TestMiner @@ -11,7 +13,9 @@ func EnsembleMinimum(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestMiner, return &full, &miner, ensemble } -func EnsembleTwo(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestFullNode, *TestMiner, *Ensemble) { +// EnsembleTwoOne creates and starts an ensemble with two full nodes and one miner. +// It does not interconnect nodes nor does it begin mining. +func EnsembleTwoOne(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestFullNode, *TestMiner, *Ensemble) { var ( one, two TestFullNode miner TestMiner @@ -19,3 +23,19 @@ func EnsembleTwo(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestFullNode, * ensemble := NewEnsemble(t).FullNode(&one, opts...).FullNode(&two, opts...).Miner(&miner, &one, opts...).Start() return &one, &two, &miner, ensemble } + +// EnsembleOneTwo creates and starts an ensemble with one full node and two miners. +// It does not interconnect nodes nor does it begin mining. +func EnsembleOneTwo(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestMiner, *TestMiner, *Ensemble) { + var ( + full TestFullNode + one, two TestMiner + ) + ensemble := NewEnsemble(t). + FullNode(&full, opts...). + Miner(&one, &full, opts...). + Miner(&two, &full, opts...). + Start() + + return &full, &one, &two, ensemble +} From dcd6fc239bb590864e06a50de9de232327be4dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 15:54:16 +0100 Subject: [PATCH 10/72] deals tests: migrate TestOfflineDealFlow. --- cmd/lotus-storage-miner/allinfo_test.go | 2 +- itests/deals_test.go | 189 ++++++++++++------------ itests/kit/deals.go | 2 +- 3 files changed, 98 insertions(+), 95 deletions(-) diff --git a/cmd/lotus-storage-miner/allinfo_test.go b/cmd/lotus-storage-miner/allinfo_test.go index 0c99b47dc64..0a4461b3199 100644 --- a/cmd/lotus-storage-miner/allinfo_test.go +++ b/cmd/lotus-storage-miner/allinfo_test.go @@ -61,7 +61,7 @@ func TestMinerAllInfo(t *testing.T) { t.Run("pre-info-all", run) dh := kit.NewDealHarness(t, client, miner) - dh.MakeFullDeal(context.Background(), 6, false, false, 0) + dh.MakeOnlineDeal(context.Background(), 6, false, false, 0) t.Run("post-info-all", run) } diff --git a/itests/deals_test.go b/itests/deals_test.go index ad9429dc1cd..2810f70d68a 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -3,12 +3,16 @@ package itests import ( "bytes" "context" + "io/ioutil" + "os" + "path/filepath" "testing" "time" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/itests/kit" @@ -227,97 +231,96 @@ func TestFirstDealEnablesMining(t *testing.T) { <-providerMined } -// -// func TestOfflineDealFlow(t *testing.T) { -// blocktime := 10 * time.Millisecond -// -// // For these tests where the block time is artificially short, just use -// // a deal start epoch that is guaranteed to be far enough in the future -// // so that the deal starts sealing in time -// startEpoch := abi.ChainEpoch(2 << 12) -// -// runTest := func(t *testing.T, fastRet bool) { -// ctx := context.Background() -// fulls, miners := kit.MockMinerBuilder(t, kit.OneFull, kit.OneMiner) -// client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] -// -// kit.ConnectAndStartMining(t, blocktime, miner, client) -// -// dh := kit.NewDealHarness(t, client, miner) -// -// // Create a random file and import on the client. -// res, path, data, err := kit.CreateImportFile(ctx, client, 1, 0) -// require.NoError(t, err) -// -// // Get the piece size and commP -// fcid := res.Root -// pieceInfo, err := client.ClientDealPieceCID(ctx, fcid) -// require.NoError(t, err) -// fmt.Println("FILE CID: ", fcid) -// -// // Create a storage deal with the miner -// maddr, err := miner.ActorAddress(ctx) -// require.NoError(t, err) -// -// addr, err := client.WalletDefaultAddress(ctx) -// require.NoError(t, err) -// -// // Manual storage deal (offline deal) -// dataRef := &storagemarket.DataRef{ -// TransferType: storagemarket.TTManual, -// Root: fcid, -// PieceCid: &pieceInfo.PieceCID, -// PieceSize: pieceInfo.PieceSize.Unpadded(), -// } -// -// proposalCid, err := client.ClientStartDeal(ctx, &api.StartDealParams{ -// Data: dataRef, -// Wallet: addr, -// Miner: maddr, -// EpochPrice: types.NewInt(1000000), -// DealStartEpoch: startEpoch, -// MinBlocksDuration: uint64(build.MinDealDuration), -// FastRetrieval: fastRet, -// }) -// require.NoError(t, err) -// -// // Wait for the deal to reach StorageDealCheckForAcceptance on the client -// cd, err := client.ClientGetDealInfo(ctx, *proposalCid) -// require.NoError(t, err) -// require.Eventually(t, func() bool { -// cd, _ := client.ClientGetDealInfo(ctx, *proposalCid) -// return cd.State == storagemarket.StorageDealCheckForAcceptance -// }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) -// -// // Create a CAR file from the raw file -// carFileDir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-car") -// require.NoError(t, err) -// carFilePath := filepath.Join(carFileDir, "out.car") -// err = client.ClientGenCar(ctx, api.FileRef{Path: path}, carFilePath) -// require.NoError(t, err) -// -// // Import the CAR file on the miner - this is the equivalent to -// // transferring the file across the wire in a normal (non-offline) deal -// err = miner.DealsImportData(ctx, *proposalCid, carFilePath) -// require.NoError(t, err) -// -// // Wait for the deal to be published -// dh.WaitDealPublished(ctx, proposalCid) -// -// t.Logf("deal published, retrieving") -// -// // Retrieve the deal -// dh.PerformRetrieval(ctx, fcid, &pieceInfo.PieceCID, false, data) -// } -// -// t.Run("NormalRetrieval", func(t *testing.T) { -// runTest(t, false) -// }) -// t.Run("FastRetrieval", func(t *testing.T) { -// runTest(t, true) -// }) -// -// } +func TestOfflineDealFlow(t *testing.T) { + blocktime := 10 * time.Millisecond + + // For these tests where the block time is artificially short, just use + // a deal start epoch that is guaranteed to be far enough in the future + // so that the deal starts sealing in time + startEpoch := abi.ChainEpoch(2 << 12) + + runTest := func(t *testing.T, fastRet bool) { + ctx := context.Background() + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(blocktime) + + dh := kit.NewDealHarness(t, client, miner) + + // Create a random file and import on the client. + res, path, data, err := kit.CreateImportFile(ctx, client, 1, 0) + require.NoError(t, err) + + // Get the piece size and commP + fcid := res.Root + pieceInfo, err := client.ClientDealPieceCID(ctx, fcid) + require.NoError(t, err) + t.Log("FILE CID:", fcid) + + // Create a storage deal with the miner + maddr, err := miner.ActorAddress(ctx) + require.NoError(t, err) + + addr, err := client.WalletDefaultAddress(ctx) + require.NoError(t, err) + + // Manual storage deal (offline deal) + dataRef := &storagemarket.DataRef{ + TransferType: storagemarket.TTManual, + Root: fcid, + PieceCid: &pieceInfo.PieceCID, + PieceSize: pieceInfo.PieceSize.Unpadded(), + } + + proposalCid, err := client.ClientStartDeal(ctx, &api.StartDealParams{ + Data: dataRef, + Wallet: addr, + Miner: maddr, + EpochPrice: types.NewInt(1000000), + DealStartEpoch: startEpoch, + MinBlocksDuration: uint64(build.MinDealDuration), + FastRetrieval: fastRet, + }) + require.NoError(t, err) + + // Wait for the deal to reach StorageDealCheckForAcceptance on the client + cd, err := client.ClientGetDealInfo(ctx, *proposalCid) + require.NoError(t, err) + require.Eventually(t, func() bool { + cd, _ := client.ClientGetDealInfo(ctx, *proposalCid) + return cd.State == storagemarket.StorageDealCheckForAcceptance + }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) + + // Create a CAR file from the raw file + carFileDir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-car") + require.NoError(t, err) + + carFilePath := filepath.Join(carFileDir, "out.car") + err = client.ClientGenCar(ctx, api.FileRef{Path: path}, carFilePath) + require.NoError(t, err) + + // Import the CAR file on the miner - this is the equivalent to + // transferring the file across the wire in a normal (non-offline) deal + err = miner.DealsImportData(ctx, *proposalCid, carFilePath) + require.NoError(t, err) + + // Wait for the deal to be published + dh.WaitDealPublished(ctx, proposalCid) + + t.Logf("deal published, retrieving") + + // Retrieve the deal + dh.PerformRetrieval(ctx, fcid, &pieceInfo.PieceCID, false, data) + } + + t.Run("NormalRetrieval", func(t *testing.T) { + runTest(t, false) + }) + t.Run("FastRetrieval", func(t *testing.T) { + runTest(t, true) + }) + +} + // // func runFullDealCycles(t *testing.T, n int, b kit.APIBuilder, blocktime time.Duration, carExport, fastRet bool, startEpoch abi.ChainEpoch) { // full, _, ens := kit.EnsembleMinimal(t) @@ -326,7 +329,7 @@ func TestFirstDealEnablesMining(t *testing.T) { // // baseseed := 6 // for i := 0; i < n; i++ { -// dh.MakeFullDeal(context.Background(), baseseed+i, carExport, fastRet, startEpoch) +// dh.MakeOnlineDeal(context.Background(), baseseed+i, carExport, fastRet, startEpoch) // } // } // @@ -434,5 +437,5 @@ func TestFirstDealEnablesMining(t *testing.T) { // err = miner.MarketSetRetrievalAsk(ctx, ask) // require.NoError(t, err) // -// dh.MakeFullDeal(ctx, 6, false, false, startEpoch) +// dh.MakeOnlineDeal(ctx, 6, false, false, startEpoch) // } diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 14511dbd1d8..5fc950cc5a7 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -42,7 +42,7 @@ func NewDealHarness(t *testing.T, client api.FullNode, miner *TestMiner) *DealHa } } -func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, fastRet bool, startEpoch abi.ChainEpoch) { +func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, rseed int, carExport, fastRet bool, startEpoch abi.ChainEpoch) { res, _, data, err := CreateImportFile(ctx, dh.client, rseed, 0) require.NoError(dh.t, err) From 8b037e2da3d4b8734ce969e1411f3f4f76004b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Jun 2021 18:25:02 +0100 Subject: [PATCH 11/72] deals tests: migrate deals cycles tests and add coverage. --- itests/deals_test.go | 129 ++++++++++++++++++++------------------- itests/kit/blockminer.go | 2 +- itests/kit/client.go | 45 +------------- itests/kit/deals.go | 63 ++++++++----------- itests/kit/files.go | 57 +++++++++++++++++ itests/kit/init.go | 10 ++- itests/kit/node_full.go | 10 +++ 7 files changed, 169 insertions(+), 147 deletions(-) create mode 100644 itests/kit/files.go diff --git a/itests/deals_test.go b/itests/deals_test.go index 2810f70d68a..a14a5bbb6ea 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -3,8 +3,7 @@ package itests import ( "bytes" "context" - "io/ioutil" - "os" + "fmt" "path/filepath" "testing" "time" @@ -20,36 +19,54 @@ import ( "github.com/filecoin-project/lotus/node" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" ) -// -// func TestDealCycle(t *testing.T) { -// kit.QuietMiningLogs() -// -// blockTime := 10 * time.Millisecond -// -// // For these tests where the block time is artificially short, just use -// // a deal start epoch that is guaranteed to be far enough in the future -// // so that the deal starts sealing in time -// dealStartEpoch := abi.ChainEpoch(2 << 12) -// -// t.Run("TestFullDealCycle_Single", func(t *testing.T) { -// runFullDealCycles(t, 1, kit.MockMinerBuilder, blockTime, false, false, dealStartEpoch) -// }) -// t.Run("TestFullDealCycle_Two", func(t *testing.T) { -// runFullDealCycles(t, 2, kit.MockMinerBuilder, blockTime, false, false, dealStartEpoch) -// }) -// t.Run("WithExportedCAR", func(t *testing.T) { -// runFullDealCycles(t, 1, kit.MockMinerBuilder, blockTime, true, false, dealStartEpoch) -// }) -// t.Run("TestFastRetrievalDealCycle", func(t *testing.T) { -// runFastRetrievalDealFlowT(t, kit.MockMinerBuilder, blockTime, dealStartEpoch) -// }) -// t.Run("TestZeroPricePerByteRetrievalDealFlow", func(t *testing.T) { -// runZeroPricePerByteRetrievalDealFlow(t, kit.MockMinerBuilder, blockTime, dealStartEpoch) -// }) -// } -// +func TestDealCyclesConcurrent(t *testing.T) { + kit.QuietMiningLogs() + + blockTime := 10 * time.Millisecond + + // For these tests where the block time is artificially short, just use + // a deal start epoch that is guaranteed to be far enough in the future + // so that the deal starts sealing in time + dealStartEpoch := abi.ChainEpoch(2 << 12) + + runTest := func(t *testing.T, n int, fastRetrieval bool, carExport bool) { + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(blockTime) + dh := kit.NewDealHarness(t, client, miner) + + errgrp, _ := errgroup.WithContext(context.Background()) + for i := 0; i < n; i++ { + i := i + errgrp.Go(func() (err error) { + defer func() { + // This is necessary because we use require, which invokes t.Fatal, + // and that's not + if r := recover(); r != nil { + err = fmt.Errorf("deal failed: %s", r) + } + }() + deal, res, inPath := dh.MakeOnlineDeal(context.Background(), 5+i, fastRetrieval, dealStartEpoch) + outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, carExport) + kit.FilesEqual(t, inPath, outPath) + return nil + }) + } + require.NoError(t, errgrp.Wait()) + } + + cycles := []int{1, 2, 4, 8} + for _, n := range cycles { + ns := fmt.Sprintf("%d", n) + t.Run(ns+"-fastretrieval-CAR", func(t *testing.T) { runTest(t, n, true, true) }) + t.Run(ns+"-fastretrieval-NoCAR", func(t *testing.T) { runTest(t, n, true, false) }) + t.Run(ns+"-stdretrieval-CAR", func(t *testing.T) { runTest(t, n, true, false) }) + t.Run(ns+"-stdretrieval-NoCAR", func(t *testing.T) { runTest(t, n, false, false) }) + } +} + // func TestAPIDealFlowReal(t *testing.T) { // if testing.Short() { // t.Skip("skipping test in short mode") @@ -101,8 +118,7 @@ func TestPublishDealsBatching(t *testing.T) { // Starts a deal and waits until it's published runDealTillPublish := func(rseed int) { - res, _, _, err := kit.CreateImportFile(ctx, client, rseed, 0) - require.NoError(t, err) + res, _ := client.CreateImportFile(ctx, rseed, 0) upds, err := client.ClientGetDealUpdates(ctx) require.NoError(t, err) @@ -189,10 +205,9 @@ func TestFirstDealEnablesMining(t *testing.T) { ctx := context.Background() - dh := kit.NewDealHarness(t, client, &provider) + dh := kit.NewDealHarness(t, &client, &provider) - ref, _, _, err := kit.CreateImportFile(ctx, client, 5, 0) - require.NoError(t, err) + ref, _ := client.CreateImportFile(ctx, 5, 0) t.Log("FILE CID:", ref.Root) @@ -204,6 +219,8 @@ func TestFirstDealEnablesMining(t *testing.T) { // we pass the test. providerMined := make(chan struct{}) heads, err := client.ChainNotify(ctx) + require.NoError(t, err) + go func() { for chg := range heads { for _, c := range chg { @@ -247,14 +264,13 @@ func TestOfflineDealFlow(t *testing.T) { dh := kit.NewDealHarness(t, client, miner) // Create a random file and import on the client. - res, path, data, err := kit.CreateImportFile(ctx, client, 1, 0) - require.NoError(t, err) + res, inFile := client.CreateImportFile(ctx, 1, 0) // Get the piece size and commP - fcid := res.Root - pieceInfo, err := client.ClientDealPieceCID(ctx, fcid) + rootCid := res.Root + pieceInfo, err := client.ClientDealPieceCID(ctx, rootCid) require.NoError(t, err) - t.Log("FILE CID:", fcid) + t.Log("FILE CID:", rootCid) // Create a storage deal with the miner maddr, err := miner.ActorAddress(ctx) @@ -266,7 +282,7 @@ func TestOfflineDealFlow(t *testing.T) { // Manual storage deal (offline deal) dataRef := &storagemarket.DataRef{ TransferType: storagemarket.TTManual, - Root: fcid, + Root: rootCid, PieceCid: &pieceInfo.PieceCID, PieceSize: pieceInfo.PieceSize.Unpadded(), } @@ -291,11 +307,9 @@ func TestOfflineDealFlow(t *testing.T) { }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) // Create a CAR file from the raw file - carFileDir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-car") - require.NoError(t, err) - + carFileDir := t.TempDir() carFilePath := filepath.Join(carFileDir, "out.car") - err = client.ClientGenCar(ctx, api.FileRef{Path: path}, carFilePath) + err = client.ClientGenCar(ctx, api.FileRef{Path: inFile}, carFilePath) require.NoError(t, err) // Import the CAR file on the miner - this is the equivalent to @@ -309,29 +323,16 @@ func TestOfflineDealFlow(t *testing.T) { t.Logf("deal published, retrieving") // Retrieve the deal - dh.PerformRetrieval(ctx, fcid, &pieceInfo.PieceCID, false, data) - } + outFile := dh.PerformRetrieval(ctx, proposalCid, rootCid, false) - t.Run("NormalRetrieval", func(t *testing.T) { - runTest(t, false) - }) - t.Run("FastRetrieval", func(t *testing.T) { - runTest(t, true) - }) + equal := kit.FilesEqual(t, inFile, outFile) + require.True(t, equal) + } + t.Run("NormalRetrieval", func(t *testing.T) { runTest(t, false) }) + t.Run("FastRetrieval", func(t *testing.T) { runTest(t, true) }) } -// -// func runFullDealCycles(t *testing.T, n int, b kit.APIBuilder, blocktime time.Duration, carExport, fastRet bool, startEpoch abi.ChainEpoch) { -// full, _, ens := kit.EnsembleMinimal(t) -// ens.BeginMining() -// dh := kit.NewDealHarness(t, client, miner) -// -// baseseed := 6 -// for i := 0; i < n; i++ { -// dh.MakeOnlineDeal(context.Background(), baseseed+i, carExport, fastRet, startEpoch) -// } -// } // // func runFastRetrievalDealFlowT(t *testing.T, b kit.APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch) { // ctx := context.Background() diff --git a/itests/kit/blockminer.go b/itests/kit/blockminer.go index b7951c4f89e..2c9bd47c6cf 100644 --- a/itests/kit/blockminer.go +++ b/itests/kit/blockminer.go @@ -93,7 +93,7 @@ func (bm *BlockMiner) MineUntilBlock(ctx context.Context, fn *TestFullNode, cb f if success { // Wait until it shows up on the given full nodes ChainHead - nloops := 50 + nloops := 200 for i := 0; i < nloops; i++ { ts, err := fn.ChainHead(ctx) require.NoError(bm.t, err) diff --git a/itests/kit/client.go b/itests/kit/client.go index 6b7d4626563..0d247043e3a 100644 --- a/itests/kit/client.go +++ b/itests/kit/client.go @@ -3,16 +3,12 @@ package kit import ( "context" "fmt" - "io/ioutil" - "math/rand" - "os" "path/filepath" "regexp" "strings" "testing" "time" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -43,7 +39,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) // Create a deal (non-interactive) // client deal --start-epoch= 1000000attofil - res, _, _, err := CreateImportFile(ctx, clientNode, 1, 0) + res, _ := clientNode.CreateImportFile(ctx, 1, 0) require.NoError(t, err) startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) @@ -60,7 +56,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) // // "no" (verified Client) // "yes" (confirm deal) - res, _, _, err = CreateImportFile(ctx, clientNode, 2, 0) + res, _ = clientNode.CreateImportFile(ctx, 2, 0) require.NoError(t, err) dataCid2 := res.Root duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) @@ -103,44 +99,9 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) // Retrieve the first file from the Miner // client retrieve - tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client") - require.NoError(t, err) + tmpdir := t.TempDir() path := filepath.Join(tmpdir, "outfile.dat") out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) fmt.Println("retrieve:\n", out) require.Regexp(t, regexp.MustCompile("Success"), out) } - -func CreateImportFile(ctx context.Context, client api.FullNode, rseed int, size int) (res *api.ImportRes, path string, data []byte, err error) { - data, path, err = createRandomFile(rseed, size) - if err != nil { - return nil, "", nil, err - } - - res, err = client.ClientImport(ctx, api.FileRef{Path: path}) - if err != nil { - return nil, "", nil, err - } - return res, path, data, nil -} - -func createRandomFile(rseed, size int) ([]byte, string, error) { - if size == 0 { - size = 1600 - } - data := make([]byte, size) - rand.New(rand.NewSource(int64(rseed))).Read(data) - - dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") - if err != nil { - return nil, "", err - } - - path := filepath.Join(dir, "sourcefile.dat") - err = ioutil.WriteFile(path, data, 0644) - if err != nil { - return nil, "", err - } - - return data, path, nil -} diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 5fc950cc5a7..d62c5a7bd3f 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -4,8 +4,6 @@ import ( "bytes" "context" "io/ioutil" - "os" - "path/filepath" "testing" "time" @@ -20,7 +18,6 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/node/impl" ipld "github.com/ipfs/go-ipld-format" dag "github.com/ipfs/go-merkledag" dstest "github.com/ipfs/go-merkledag/test" @@ -29,12 +26,12 @@ import ( type DealHarness struct { t *testing.T - client api.FullNode + client *TestFullNode 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 *TestFullNode, miner *TestMiner) *DealHarness { return &DealHarness{ t: t, client: client, @@ -42,24 +39,18 @@ func NewDealHarness(t *testing.T, client api.FullNode, miner *TestMiner) *DealHa } } -func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, rseed int, carExport, fastRet bool, startEpoch abi.ChainEpoch) { - res, _, data, err := CreateImportFile(ctx, dh.client, rseed, 0) - require.NoError(dh.t, err) +func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, rseed int, fastRet bool, startEpoch abi.ChainEpoch) (deal *cid.Cid, res *api.ImportRes, path string) { + res, path = dh.client.CreateImportFile(ctx, rseed, 0) - fcid := res.Root - dh.t.Logf("FILE CID: %s", fcid) + dh.t.Logf("FILE CID: %s", res.Root) - deal := dh.StartDeal(ctx, fcid, fastRet, startEpoch) + deal = dh.StartDeal(ctx, res.Root, fastRet, startEpoch) // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this time.Sleep(time.Second) dh.WaitDealSealed(ctx, deal, false, false, nil) - // Retrieval - info, err := dh.client.ClientGetDealInfo(ctx, *deal) - require.NoError(dh.t, err) - - dh.PerformRetrieval(ctx, fcid, &info.PieceCID, carExport, data) + return deal, res, path } func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { @@ -177,22 +168,25 @@ func (dh *DealHarness) StartSealingWaiting(ctx context.Context) { } } -func (dh *DealHarness) PerformRetrieval(ctx context.Context, fcid cid.Cid, piece *cid.Cid, carExport bool, expect []byte) { - offers, err := dh.client.ClientFindData(ctx, fcid, piece) +func (dh *DealHarness) PerformRetrieval(ctx context.Context, deal *cid.Cid, root cid.Cid, carExport bool) (path string) { + // perform retrieval. + info, err := dh.client.ClientGetDealInfo(ctx, *deal) require.NoError(dh.t, err) + offers, err := dh.client.ClientFindData(ctx, root, &info.PieceCID) + require.NoError(dh.t, err) require.NotEmpty(dh.t, offers, "no offers") - rpath, err := ioutil.TempDir("", "lotus-retrieve-test-") + tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "ret-car") require.NoError(dh.t, err) - defer os.RemoveAll(rpath) //nolint:errcheck + defer tmpfile.Close() caddr, err := dh.client.WalletDefaultAddress(ctx) require.NoError(dh.t, err) ref := &api.FileRef{ - Path: filepath.Join(rpath, "ret"), + Path: tmpfile.Name(), IsCAR: carExport, } @@ -203,19 +197,17 @@ func (dh *DealHarness) PerformRetrieval(ctx context.Context, fcid cid.Cid, piece require.Emptyf(dh.t, update.Err, "retrieval failed: %s", update.Err) } - rdata, err := ioutil.ReadFile(filepath.Join(rpath, "ret")) + rdata, err := ioutil.ReadFile(tmpfile.Name()) require.NoError(dh.t, err) if carExport { - rdata = dh.ExtractCarData(ctx, rdata, rpath) + rdata = dh.ExtractFileFromCAR(ctx, rdata) } - if !bytes.Equal(rdata, expect) { - dh.t.Fatal("wrong expect retrieved") - } + return tmpfile.Name() } -func (dh *DealHarness) ExtractCarData(ctx context.Context, rdata []byte, rpath string) []byte { +func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, rdata []byte) []byte { bserv := dstest.Bserv() ch, err := car.LoadCar(bserv.Blockstore(), bytes.NewReader(rdata)) require.NoError(dh.t, err) @@ -230,21 +222,18 @@ func (dh *DealHarness) ExtractCarData(ctx context.Context, rdata []byte, rpath s fil, err := unixfile.NewUnixfsFile(ctx, dserv, nd) require.NoError(dh.t, err) - outPath := filepath.Join(rpath, "retLoadedCAR") - err = files.WriteTo(fil, outPath) + tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "file-in-car") require.NoError(dh.t, err) - rdata, err = ioutil.ReadFile(outPath) + defer tmpfile.Close() + + err = files.WriteTo(fil, tmpfile.Name()) require.NoError(dh.t, err) - return rdata -} + rdata, err = ioutil.ReadFile(tmpfile.Name()) + require.NoError(dh.t, err) -type DealsScaffold struct { - Ctx context.Context - Client *impl.FullNodeAPI - Miner TestMiner - BlockMiner *BlockMiner + return rdata } func ConnectAndStartMining(t *testing.T, blocktime time.Duration, miner *TestMiner, clients ...api.FullNode) *BlockMiner { diff --git a/itests/kit/files.go b/itests/kit/files.go new file mode 100644 index 00000000000..d4e92fecfc4 --- /dev/null +++ b/itests/kit/files.go @@ -0,0 +1,57 @@ +package kit + +import ( + "bytes" + "io" + "math/rand" + "os" + "testing" + + "github.com/minio/blake2b-simd" + + "github.com/stretchr/testify/require" +) + +// CreateRandomFile creates a random file with the provided seed and the +// provided size. +func CreateRandomFile(t *testing.T, rseed, size int) (path string) { + if size == 0 { + size = 1600 + } + + source := io.LimitReader(rand.New(rand.NewSource(int64(rseed))), int64(size)) + + file, err := os.CreateTemp(t.TempDir(), "sourcefile.dat") + require.NoError(t, err) + + n, err := io.Copy(file, source) + require.NoError(t, err) + require.EqualValues(t, n, size) + + return file.Name() +} + +// FilesEqual compares two files by blake2b hash equality. +func FilesEqual(t *testing.T, left, right string) bool { + // initialize hashes. + leftH, rightH := blake2b.New256(), blake2b.New256() + + // open files. + leftF, err := os.Open(left) + require.NoError(t, err) + + rightF, err := os.Open(right) + require.NoError(t, err) + + // feed hash functions. + _, err = io.Copy(leftH, leftF) + require.NoError(t, err) + + _, err = io.Copy(rightH, rightF) + require.NoError(t, err) + + // compute digests. + leftD, rightD := leftH.Sum(nil), rightH.Sum(nil) + + return bytes.Equal(leftD, rightD) +} diff --git a/itests/kit/init.go b/itests/kit/init.go index 57d60ad2a5f..8df4922b864 100644 --- a/itests/kit/init.go +++ b/itests/kit/init.go @@ -17,9 +17,13 @@ func init() { policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) - err := os.Setenv("BELLMAN_NO_GPU", "1") - if err != nil { + build.InsecurePoStValidation = true + + if err := os.Setenv("BELLMAN_NO_GPU", "1"); err != nil { panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err)) } - build.InsecurePoStValidation = true + + if err := os.Setenv("LOTUS_DISABLE_WATCHDOG", "1"); err != nil { + panic(fmt.Sprintf("failed to set LOTUS_DISABLE_WATCHDOG env variable: %s", err)) + } } diff --git a/itests/kit/node_full.go b/itests/kit/node_full.go index f8f13c724a1..0e991206331 100644 --- a/itests/kit/node_full.go +++ b/itests/kit/node_full.go @@ -1,11 +1,14 @@ package kit import ( + "context" "testing" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/v1api" "github.com/filecoin-project/lotus/chain/wallet" "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" ) type TestFullNode struct { @@ -20,3 +23,10 @@ type TestFullNode struct { options NodeOpts } + +func (f *TestFullNode) CreateImportFile(ctx context.Context, rseed int, size int) (res *api.ImportRes, path string) { + path = CreateRandomFile(f.t, rseed, size) + res, err := f.ClientImport(ctx, api.FileRef{Path: path}) + require.NoError(f.t, err) + return res, path +} From e84b8ab3a0190cbd0d720b083cb8d8de0c9c112f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 11 Jun 2021 18:26:25 +0100 Subject: [PATCH 12/72] move new kit into kit2, re-enable unmigrated tests against kit1. --- cmd/lotus-storage-miner/allinfo_test.go | 4 +- itests/api_test.go | 26 +- ...tch_deal_test.go.no => batch_deal_test.go} | 0 ...ccupgrade_test.go.no => ccupgrade_test.go} | 0 itests/{cli_test.go.no => cli_test.go} | 0 ...deadlines_test.go.no => deadlines_test.go} | 0 itests/deals_test.go | 190 +++-- .../{gateway_test.go.no => gateway_test.go} | 2 +- itests/kit/blockminer.go | 8 +- itests/kit/client.go | 45 +- itests/kit/deals.go | 160 +++-- itests/kit/ensemble_presets.go | 41 -- itests/kit/funds.go | 19 +- itests/kit/init.go | 10 +- itests/kit/net.go | 125 ++-- itests/kit/node_builder.go | 658 ++++++++++++++++++ itests/kit/nodes.go | 153 ++++ itests/kit/pledge.go | 88 +++ itests/kit2/blockminer.go | 124 ++++ itests/kit2/client.go | 107 +++ itests/kit2/deals.go | 245 +++++++ itests/kit2/deals_state.go | 21 + itests/{kit => kit2}/ensemble.go | 263 ++----- itests/kit2/ensemble_opts.go | 35 + itests/kit2/ensemble_presets.go | 70 ++ itests/{kit => kit2}/files.go | 9 +- itests/kit2/funds.go | 34 + itests/kit2/init.go | 29 + itests/kit2/log.go | 19 + itests/{kit => kit2}/node_full.go | 7 +- itests/{kit => kit2}/node_miner.go | 10 +- itests/kit2/node_opts.go | 89 +++ itests/kit2/node_opts_nv.go | 65 ++ itests/kit2/rpc.go | 53 ++ .../{multisig_test.go.no => multisig_test.go} | 0 ...paych_api_test.go.no => paych_api_test.go} | 0 ...paych_cli_test.go.no => paych_cli_test.go} | 0 ...upgrade_test.go.no => sdr_upgrade_test.go} | 0 ...ledge_test.go.no => sector_pledge_test.go} | 0 ...te_test.go.no => sector_terminate_test.go} | 0 itests/{tape_test.go.no => tape_test.go} | 0 .../{verifreg_test.go.no => verifreg_test.go} | 0 ...pute_test.go.no => wdpost_dispute_test.go} | 0 itests/{wdpost_test.go.no => wdpost_test.go} | 0 44 files changed, 2199 insertions(+), 510 deletions(-) rename itests/{batch_deal_test.go.no => batch_deal_test.go} (100%) rename itests/{ccupgrade_test.go.no => ccupgrade_test.go} (100%) rename itests/{cli_test.go.no => cli_test.go} (100%) rename itests/{deadlines_test.go.no => deadlines_test.go} (100%) rename itests/{gateway_test.go.no => gateway_test.go} (99%) delete mode 100644 itests/kit/ensemble_presets.go create mode 100644 itests/kit/node_builder.go create mode 100644 itests/kit/nodes.go create mode 100644 itests/kit/pledge.go create mode 100644 itests/kit2/blockminer.go create mode 100644 itests/kit2/client.go create mode 100644 itests/kit2/deals.go create mode 100644 itests/kit2/deals_state.go rename itests/{kit => kit2}/ensemble.go (75%) create mode 100644 itests/kit2/ensemble_opts.go create mode 100644 itests/kit2/ensemble_presets.go rename itests/{kit => kit2}/files.go (82%) create mode 100644 itests/kit2/funds.go create mode 100644 itests/kit2/init.go create mode 100644 itests/kit2/log.go rename itests/{kit => kit2}/node_full.go (78%) rename itests/{kit => kit2}/node_miner.go (95%) create mode 100644 itests/kit2/node_opts.go create mode 100644 itests/kit2/node_opts_nv.go create mode 100644 itests/kit2/rpc.go rename itests/{multisig_test.go.no => multisig_test.go} (100%) rename itests/{paych_api_test.go.no => paych_api_test.go} (100%) rename itests/{paych_cli_test.go.no => paych_cli_test.go} (100%) rename itests/{sdr_upgrade_test.go.no => sdr_upgrade_test.go} (100%) rename itests/{sector_pledge_test.go.no => sector_pledge_test.go} (100%) rename itests/{sector_terminate_test.go.no => sector_terminate_test.go} (100%) rename itests/{tape_test.go.no => tape_test.go} (100%) rename itests/{verifreg_test.go.no => verifreg_test.go} (100%) rename itests/{wdpost_dispute_test.go.no => wdpost_dispute_test.go} (100%) rename itests/{wdpost_test.go.no => wdpost_test.go} (100%) diff --git a/cmd/lotus-storage-miner/allinfo_test.go b/cmd/lotus-storage-miner/allinfo_test.go index 0a4461b3199..cbe65524e11 100644 --- a/cmd/lotus-storage-miner/allinfo_test.go +++ b/cmd/lotus-storage-miner/allinfo_test.go @@ -40,7 +40,7 @@ func TestMinerAllInfo(t *testing.T) { policy.SetPreCommitChallengeDelay(oldDelay) }) - n, sn := kit.FullNodeBuilder(t, kit.OneFull, kit.OneMiner) + n, sn := kit.Builder(t, kit.OneFull, kit.OneMiner) client, miner := n[0].FullNode, sn[0] kit.ConnectAndStartMining(t, time.Second, miner, client.(*impl.FullNodeAPI)) @@ -61,7 +61,7 @@ func TestMinerAllInfo(t *testing.T) { t.Run("pre-info-all", run) dh := kit.NewDealHarness(t, client, miner) - dh.MakeOnlineDeal(context.Background(), 6, false, false, 0) + dh.MakeFullDeal(context.Background(), 6, false, false, 0) t.Run("post-info-all", run) } diff --git a/itests/api_test.go b/itests/api_test.go index c6694a554f6..a8abee92f9d 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -12,7 +12,7 @@ import ( 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/itests/kit2" "github.com/stretchr/testify/require" ) @@ -21,16 +21,16 @@ func TestAPI(t *testing.T) { runAPITest(t) }) t.Run("rpc", func(t *testing.T) { - runAPITest(t, kit.ThroughRPC()) + runAPITest(t, kit2.ThroughRPC()) }) } type apiSuite struct { - opts []kit.NodeOpt + opts []kit2.NodeOpt } // runAPITest is the entry point to API test suite -func runAPITest(t *testing.T, opts ...kit.NodeOpt) { +func runAPITest(t *testing.T, opts ...kit2.NodeOpt) { ts := apiSuite{opts: opts} t.Run("version", ts.testVersion) @@ -48,7 +48,7 @@ func (ts *apiSuite) testVersion(t *testing.T) { lapi.RunningNodeType = lapi.NodeUnknown }) - full, _, _ := kit.EnsembleMinimal(t, ts.opts...) + full, _, _ := kit2.EnsembleMinimal(t, ts.opts...) v, err := full.Version(context.Background()) require.NoError(t, err) @@ -61,7 +61,7 @@ func (ts *apiSuite) testVersion(t *testing.T) { func (ts *apiSuite) testID(t *testing.T) { ctx := context.Background() - full, _, _ := kit.EnsembleMinimal(t, ts.opts...) + full, _, _ := kit2.EnsembleMinimal(t, ts.opts...) id, err := full.ID(ctx) if err != nil { @@ -73,7 +73,7 @@ func (ts *apiSuite) testID(t *testing.T) { func (ts *apiSuite) testConnectTwo(t *testing.T) { ctx := context.Background() - one, two, _, ens := kit.EnsembleTwoOne(t, ts.opts...) + one, two, _, ens := kit2.EnsembleTwoOne(t, ts.opts...) p, err := one.NetPeers(ctx) require.NoError(t, err) @@ -97,7 +97,7 @@ func (ts *apiSuite) testConnectTwo(t *testing.T) { func (ts *apiSuite) testSearchMsg(t *testing.T) { ctx := context.Background() - full, _, ens := kit.EnsembleMinimal(t, ts.opts...) + full, _, ens := kit2.EnsembleMinimal(t, ts.opts...) senderAddr, err := full.WalletDefaultAddress(ctx) require.NoError(t, err) @@ -127,7 +127,7 @@ func (ts *apiSuite) testSearchMsg(t *testing.T) { func (ts *apiSuite) testMining(t *testing.T) { ctx := context.Background() - full, miner, _ := kit.EnsembleMinimal(t, ts.opts...) + full, miner, _ := kit2.EnsembleMinimal(t, ts.opts...) newHeads, err := full.ChainNotify(ctx) require.NoError(t, err) @@ -138,7 +138,7 @@ func (ts *apiSuite) testMining(t *testing.T) { require.NoError(t, err) require.Equal(t, int64(h1.Height()), int64(baseHeight)) - bm := kit.NewBlockMiner(t, miner) + bm := kit2.NewBlockMiner(t, miner) bm.MineUntilBlock(ctx, full, nil) require.NoError(t, err) @@ -170,7 +170,7 @@ func (ts *apiSuite) testMiningReal(t *testing.T) { func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { ctx := context.Background() - full, genesisMiner, ens := kit.EnsembleMinimal(t, ts.opts...) + full, genesisMiner, ens := kit2.EnsembleMinimal(t, ts.opts...) ens.BeginMining(4 * time.Millisecond) @@ -180,8 +180,8 @@ func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { _, err = full.StateMinerInfo(ctx, gaa, types.EmptyTSK) require.NoError(t, err) - var newMiner kit.TestMiner - ens.Miner(&newMiner, full, kit.OwnerAddr(full.DefaultKey)).Start() + var newMiner kit2.TestMiner + ens.Miner(&newMiner, full, kit2.OwnerAddr(full.DefaultKey)).Start() ta, err := newMiner.ActorAddress(ctx) require.NoError(t, err) diff --git a/itests/batch_deal_test.go.no b/itests/batch_deal_test.go similarity index 100% rename from itests/batch_deal_test.go.no rename to itests/batch_deal_test.go diff --git a/itests/ccupgrade_test.go.no b/itests/ccupgrade_test.go similarity index 100% rename from itests/ccupgrade_test.go.no rename to itests/ccupgrade_test.go diff --git a/itests/cli_test.go.no b/itests/cli_test.go similarity index 100% rename from itests/cli_test.go.no rename to itests/cli_test.go diff --git a/itests/deadlines_test.go.no b/itests/deadlines_test.go similarity index 100% rename from itests/deadlines_test.go.no rename to itests/deadlines_test.go diff --git a/itests/deals_test.go b/itests/deals_test.go index a14a5bbb6ea..b30e5ba699b 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -14,7 +14,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/markets/storageadapter" "github.com/filecoin-project/lotus/node" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" @@ -23,38 +23,30 @@ import ( ) func TestDealCyclesConcurrent(t *testing.T) { - kit.QuietMiningLogs() + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit2.QuietMiningLogs() blockTime := 10 * time.Millisecond // For these tests where the block time is artificially short, just use // a deal start epoch that is guaranteed to be far enough in the future // so that the deal starts sealing in time - dealStartEpoch := abi.ChainEpoch(2 << 12) + startEpoch := abi.ChainEpoch(2 << 12) runTest := func(t *testing.T, n int, fastRetrieval bool, carExport bool) { - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) ens.InterconnectAll().BeginMining(blockTime) - dh := kit.NewDealHarness(t, client, miner) - - errgrp, _ := errgroup.WithContext(context.Background()) - for i := 0; i < n; i++ { - i := i - errgrp.Go(func() (err error) { - defer func() { - // This is necessary because we use require, which invokes t.Fatal, - // and that's not - if r := recover(); r != nil { - err = fmt.Errorf("deal failed: %s", r) - } - }() - deal, res, inPath := dh.MakeOnlineDeal(context.Background(), 5+i, fastRetrieval, dealStartEpoch) - outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, carExport) - kit.FilesEqual(t, inPath, outPath) - return nil - }) - } - require.NoError(t, errgrp.Wait()) + dh := kit2.NewDealHarness(t, client, miner) + + runConcurrentDeals(t, dh, fullDealCyclesOpts{ + n: n, + fastRetrieval: fastRetrieval, + carExport: carExport, + startEpoch: startEpoch, + }) } cycles := []int{1, 2, 4, 8} @@ -67,32 +59,60 @@ func TestDealCyclesConcurrent(t *testing.T) { } } -// func TestAPIDealFlowReal(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode") -// } -// -// kit.QuietMiningLogs() -// -// // TODO: just set this globally? -// oldDelay := policy.GetPreCommitChallengeDelay() -// policy.SetPreCommitChallengeDelay(5) -// t.Cleanup(func() { -// policy.SetPreCommitChallengeDelay(oldDelay) -// }) -// -// t.Run("basic", func(t *testing.T) { -// runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, false, 0) -// }) -// -// t.Run("fast-retrieval", func(t *testing.T) { -// runFullDealCycles(t, 1, kit.FullNodeBuilder, time.Second, false, true, 0) -// }) -// -// t.Run("retrieval-second", func(t *testing.T) { -// runSecondDealRetrievalTest(t, kit.FullNodeBuilder, time.Second) -// }) -// } +type fullDealCyclesOpts struct { + n int + fastRetrieval bool + carExport bool + startEpoch abi.ChainEpoch +} + +func runConcurrentDeals(t *testing.T, dh *kit2.DealHarness, opts fullDealCyclesOpts) { + errgrp, _ := errgroup.WithContext(context.Background()) + for i := 0; i < opts.n; i++ { + i := i + errgrp.Go(func() (err error) { + defer func() { + // This is necessary because golang can't deal with test + // failures being reported from children goroutines ¯\_(ツ)_/¯ + if r := recover(); r != nil { + err = fmt.Errorf("deal failed: %s", r) + } + }() + deal, res, inPath := dh.MakeOnlineDeal(context.Background(), 5+i, opts.fastRetrieval, opts.startEpoch) + outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, opts.carExport) + kit2.AssertFilesEqual(t, inPath, outPath) + return nil + }) + } + require.NoError(t, errgrp.Wait()) +} + +func TestDealsWithSealingAndRPC(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit2.QuietMiningLogs() + + var blockTime = 1 * time.Second + + client, miner, ens := kit2.EnsembleMinimal(t, kit2.ThroughRPC()) // no mock proofs. + ens.InterconnectAll().BeginMining(blockTime) + dh := kit2.NewDealHarness(t, client, miner) + + t.Run("stdretrieval", func(t *testing.T) { + runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1}) + }) + + t.Run("fastretrieval", func(t *testing.T) { + runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1, fastRetrieval: true}) + }) + + t.Run("fastretrieval-twodeals-sequential", func(t *testing.T) { + runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1, fastRetrieval: true}) + runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1, fastRetrieval: true}) + }) +} func TestPublishDealsBatching(t *testing.T) { var ( @@ -102,7 +122,7 @@ func TestPublishDealsBatching(t *testing.T) { startEpoch = abi.ChainEpoch(2 << 12) ) - kit.QuietMiningLogs() + kit2.QuietMiningLogs() opts := node.Override(new(*storageadapter.DealPublisher), storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ @@ -111,10 +131,10 @@ func TestPublishDealsBatching(t *testing.T) { }), ) - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ExtraNodeOpts(opts)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ConstructorOpts(opts)) ens.InterconnectAll().BeginMining(10 * time.Millisecond) - dh := kit.NewDealHarness(t, client, miner) + dh := kit2.NewDealHarness(t, client, miner) // Starts a deal and waits until it's published runDealTillPublish := func(rseed int) { @@ -189,23 +209,23 @@ func TestFirstDealEnablesMining(t *testing.T) { t.Skip("skipping test in short mode") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() var ( - client kit.TestFullNode - genMiner kit.TestMiner // bootstrap - provider kit.TestMiner // no sectors, will need to create one + client kit2.TestFullNode + genMiner kit2.TestMiner // bootstrap + provider kit2.TestMiner // no sectors, will need to create one ) - ens := kit.NewEnsemble(t) - ens.FullNode(&client, kit.MockProofs()) - ens.Miner(&genMiner, &client, kit.MockProofs()) - ens.Miner(&provider, &client, kit.MockProofs(), kit.PresealSectors(0)) + ens := kit2.NewEnsemble(t, kit2.MockProofs()) + ens.FullNode(&client) + ens.Miner(&genMiner, &client) + ens.Miner(&provider, &client, kit2.PresealSectors(0)) ens.Start().InterconnectAll().BeginMining(50 * time.Millisecond) ctx := context.Background() - dh := kit.NewDealHarness(t, &client, &provider) + dh := kit2.NewDealHarness(t, &client, &provider) ref, _ := client.CreateImportFile(ctx, 5, 0) @@ -258,10 +278,10 @@ func TestOfflineDealFlow(t *testing.T) { runTest := func(t *testing.T, fastRet bool) { ctx := context.Background() - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) ens.InterconnectAll().BeginMining(blocktime) - dh := kit.NewDealHarness(t, client, miner) + dh := kit2.NewDealHarness(t, client, miner) // Create a random file and import on the client. res, inFile := client.CreateImportFile(ctx, 1, 0) @@ -325,49 +345,13 @@ func TestOfflineDealFlow(t *testing.T) { // Retrieve the deal outFile := dh.PerformRetrieval(ctx, proposalCid, rootCid, false) - equal := kit.FilesEqual(t, inFile, outFile) - require.True(t, equal) + kit2.AssertFilesEqual(t, inFile, outFile) } - t.Run("NormalRetrieval", func(t *testing.T) { runTest(t, false) }) - t.Run("FastRetrieval", func(t *testing.T) { runTest(t, true) }) + t.Run("stdretrieval", func(t *testing.T) { runTest(t, false) }) + t.Run("fastretrieval", func(t *testing.T) { runTest(t, true) }) } -// -// func runFastRetrievalDealFlowT(t *testing.T, b kit.APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch) { -// ctx := context.Background() -// -// var ( -// nb = kit.NewNodeBuilder(t) -// full = nb.FullNode() -// miner = nb.Miner(full) -// ) -// -// nb.Create() -// -// 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 := full.FullNode.(*impl.FullNodeAPI).ClientImportLocal(ctx, r) -// require.NoError(t, err) -// -// fmt.Println("FILE CID: ", fcid) -// -// deal := dh.StartDeal(ctx, fcid, true, startEpoch) -// dh.WaitDealPublished(ctx, deal) -// -// fmt.Println("deal published, retrieving") -// -// // Retrieval -// info, err := full.ClientGetDealInfo(ctx, *deal) -// require.NoError(t, err) -// -// dh.PerformRetrieval(ctx, fcid, &info.PieceCID, false, data) -// } // // func runSecondDealRetrievalTest(t *testing.T, b kit.APIBuilder, blocktime time.Duration) { // ctx := context.Background() diff --git a/itests/gateway_test.go.no b/itests/gateway_test.go similarity index 99% rename from itests/gateway_test.go.no rename to itests/gateway_test.go index 9401f20a01c..7f1b70f2d32 100644 --- a/itests/gateway_test.go.no +++ b/itests/gateway_test.go @@ -291,7 +291,7 @@ func startNodes( }, }, ) - n, sn := kit.MinerRPCMockMinerBuilder(t, opts, kit.OneMiner) + n, sn := kit.RPCMockMinerBuilder(t, opts, kit.OneMiner) full := n[0] lite := n[1] diff --git a/itests/kit/blockminer.go b/itests/kit/blockminer.go index 2c9bd47c6cf..3b1f1fedfa7 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 @@ -93,7 +93,7 @@ func (bm *BlockMiner) MineUntilBlock(ctx context.Context, fn *TestFullNode, cb f if success { // Wait until it shows up on the given full nodes ChainHead - nloops := 200 + nloops := 50 for i := 0; i < nloops; i++ { ts, err := fn.ChainHead(ctx) require.NoError(bm.t, err) diff --git a/itests/kit/client.go b/itests/kit/client.go index 0d247043e3a..6b7d4626563 100644 --- a/itests/kit/client.go +++ b/itests/kit/client.go @@ -3,12 +3,16 @@ package kit import ( "context" "fmt" + "io/ioutil" + "math/rand" + "os" "path/filepath" "regexp" "strings" "testing" "time" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -39,7 +43,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) // Create a deal (non-interactive) // client deal --start-epoch= 1000000attofil - res, _ := clientNode.CreateImportFile(ctx, 1, 0) + res, _, _, err := CreateImportFile(ctx, clientNode, 1, 0) require.NoError(t, err) startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) @@ -56,7 +60,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) // // "no" (verified Client) // "yes" (confirm deal) - res, _ = clientNode.CreateImportFile(ctx, 2, 0) + res, _, _, err = CreateImportFile(ctx, clientNode, 2, 0) require.NoError(t, err) dataCid2 := res.Root duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) @@ -99,9 +103,44 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) // Retrieve the first file from the Miner // client retrieve - tmpdir := t.TempDir() + tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client") + require.NoError(t, err) path := filepath.Join(tmpdir, "outfile.dat") out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) fmt.Println("retrieve:\n", out) require.Regexp(t, regexp.MustCompile("Success"), out) } + +func CreateImportFile(ctx context.Context, client api.FullNode, rseed int, size int) (res *api.ImportRes, path string, data []byte, err error) { + data, path, err = createRandomFile(rseed, size) + if err != nil { + return nil, "", nil, err + } + + res, err = client.ClientImport(ctx, api.FileRef{Path: path}) + if err != nil { + return nil, "", nil, err + } + return res, path, data, nil +} + +func createRandomFile(rseed, size int) ([]byte, string, error) { + if size == 0 { + size = 1600 + } + data := make([]byte, size) + rand.New(rand.NewSource(int64(rseed))).Read(data) + + dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") + if err != nil { + return nil, "", err + } + + path := filepath.Join(dir, "sourcefile.dat") + err = ioutil.WriteFile(path, data, 0644) + if err != nil { + return nil, "", err + } + + return data, path, nil +} diff --git a/itests/kit/deals.go b/itests/kit/deals.go index d62c5a7bd3f..c768eb87f3a 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -3,7 +3,10 @@ package kit import ( "bytes" "context" + "fmt" "io/ioutil" + "os" + "path/filepath" "testing" "time" @@ -18,6 +21,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + "github.com/filecoin-project/lotus/node/impl" ipld "github.com/ipfs/go-ipld-format" dag "github.com/ipfs/go-merkledag" dstest "github.com/ipfs/go-merkledag/test" @@ -26,12 +30,12 @@ import ( type DealHarness struct { t *testing.T - client *TestFullNode - miner *TestMiner + client api.FullNode + miner TestMiner } // NewDealHarness creates a test harness that contains testing utilities for deals. -func NewDealHarness(t *testing.T, client *TestFullNode, miner *TestMiner) *DealHarness { +func NewDealHarness(t *testing.T, client api.FullNode, miner TestMiner) *DealHarness { return &DealHarness{ t: t, client: client, @@ -39,27 +43,38 @@ func NewDealHarness(t *testing.T, client *TestFullNode, miner *TestMiner) *DealH } } -func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, rseed int, fastRet bool, startEpoch abi.ChainEpoch) (deal *cid.Cid, res *api.ImportRes, path string) { - res, path = dh.client.CreateImportFile(ctx, rseed, 0) +func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, fastRet bool, startEpoch abi.ChainEpoch) { + res, _, data, err := CreateImportFile(ctx, dh.client, rseed, 0) + if err != nil { + dh.t.Fatal(err) + } - dh.t.Logf("FILE CID: %s", res.Root) + fcid := res.Root + fmt.Println("FILE CID: ", fcid) - deal = dh.StartDeal(ctx, res.Root, fastRet, startEpoch) + deal := dh.StartDeal(ctx, fcid, fastRet, startEpoch) // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this time.Sleep(time.Second) dh.WaitDealSealed(ctx, deal, false, false, nil) - return deal, res, path + // Retrieval + info, err := dh.client.ClientGetDealInfo(ctx, *deal) + require.NoError(dh.t, err) + + dh.TestRetrieval(ctx, fcid, &info.PieceCID, carExport, data) } func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { maddr, err := dh.miner.ActorAddress(ctx) - require.NoError(dh.t, err) + if err != nil { + dh.t.Fatal(err) + } addr, err := dh.client.WalletDefaultAddress(ctx) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } deal, err := dh.client.ClientStartDeal(ctx, &api.StartDealParams{ Data: &storagemarket.DataRef{ TransferType: storagemarket.TTGraphsync, @@ -72,8 +87,9 @@ func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool MinBlocksDuration: uint64(build.MinDealDuration), FastRetrieval: fastRet, }) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatalf("%+v", err) + } return deal } @@ -98,7 +114,7 @@ loop: case storagemarket.StorageDealError: dh.t.Fatal("deal errored", di.Message) case storagemarket.StorageDealActive: - dh.t.Log("COMPLETE", di) + fmt.Println("COMPLETE", di) break loop } @@ -113,7 +129,7 @@ loop: } } - dh.t.Logf("Deal %d state: client:%s provider:%s\n", di.DealID, storagemarket.DealStates[di.State], storagemarket.DealStates[minerState]) + fmt.Printf("Deal %d state: client:%s provider:%s\n", di.DealID, storagemarket.DealStates[di.State], storagemarket.DealStates[minerState]) time.Sleep(time.Second / 2) if cb != nil { cb() @@ -124,10 +140,10 @@ loop: func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { subCtx, cancel := context.WithCancel(ctx) defer cancel() - updates, err := dh.miner.MarketGetDealUpdates(subCtx) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } for { select { case <-ctx.Done(): @@ -142,10 +158,10 @@ func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { case storagemarket.StorageDealError: dh.t.Fatal("deal errored", di.Message) case storagemarket.StorageDealFinalizing, storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing, storagemarket.StorageDealActive: - dh.t.Log("COMPLETE", di) + fmt.Println("COMPLETE", di) return } - dh.t.Log("Deal state: ", storagemarket.DealStates[di.State]) + fmt.Println("Deal state: ", storagemarket.DealStates[di.State]) } } } @@ -164,79 +180,97 @@ func (dh *DealHarness) StartSealingWaiting(ctx context.Context) { require.NoError(dh.t, dh.miner.SectorStartSealing(ctx, snum)) } - dh.miner.FlushSealingBatches(ctx) + flushSealingBatches(dh.t, ctx, dh.miner) } } -func (dh *DealHarness) PerformRetrieval(ctx context.Context, deal *cid.Cid, root cid.Cid, carExport bool) (path string) { - // perform retrieval. - info, err := dh.client.ClientGetDealInfo(ctx, *deal) - require.NoError(dh.t, err) - - offers, err := dh.client.ClientFindData(ctx, root, &info.PieceCID) - require.NoError(dh.t, err) - require.NotEmpty(dh.t, offers, "no offers") +func (dh *DealHarness) TestRetrieval(ctx context.Context, fcid cid.Cid, piece *cid.Cid, carExport bool, expect []byte) { + offers, err := dh.client.ClientFindData(ctx, fcid, piece) + if err != nil { + dh.t.Fatal(err) + } - tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "ret-car") - require.NoError(dh.t, err) + if len(offers) < 1 { + dh.t.Fatal("no offers") + } - defer tmpfile.Close() + rpath, err := ioutil.TempDir("", "lotus-retrieve-test-") + if err != nil { + dh.t.Fatal(err) + } + defer os.RemoveAll(rpath) //nolint:errcheck caddr, err := dh.client.WalletDefaultAddress(ctx) - require.NoError(dh.t, err) + if err != nil { + dh.t.Fatal(err) + } ref := &api.FileRef{ - Path: tmpfile.Name(), + Path: filepath.Join(rpath, "ret"), IsCAR: carExport, } - updates, err := dh.client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } for update := range updates { - require.Emptyf(dh.t, update.Err, "retrieval failed: %s", update.Err) + if update.Err != "" { + dh.t.Fatalf("retrieval failed: %s", update.Err) + } } - rdata, err := ioutil.ReadFile(tmpfile.Name()) - require.NoError(dh.t, err) + rdata, err := ioutil.ReadFile(filepath.Join(rpath, "ret")) + if err != nil { + dh.t.Fatal(err) + } if carExport { - rdata = dh.ExtractFileFromCAR(ctx, rdata) + rdata = dh.ExtractCarData(ctx, rdata, rpath) } - return tmpfile.Name() + if !bytes.Equal(rdata, expect) { + dh.t.Fatal("wrong expect retrieved") + } } -func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, rdata []byte) []byte { +func (dh *DealHarness) ExtractCarData(ctx context.Context, rdata []byte, rpath string) []byte { bserv := dstest.Bserv() ch, err := car.LoadCar(bserv.Blockstore(), bytes.NewReader(rdata)) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } b, err := bserv.GetBlock(ctx, ch.Roots[0]) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } nd, err := ipld.Decode(b) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } dserv := dag.NewDAGService(bserv) fil, err := unixfile.NewUnixfsFile(ctx, dserv, nd) - require.NoError(dh.t, err) - - tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "file-in-car") - require.NoError(dh.t, err) - - defer tmpfile.Close() - - err = files.WriteTo(fil, tmpfile.Name()) - require.NoError(dh.t, err) - - rdata, err = ioutil.ReadFile(tmpfile.Name()) - require.NoError(dh.t, err) - + if err != nil { + dh.t.Fatal(err) + } + outPath := filepath.Join(rpath, "retLoadedCAR") + if err := files.WriteTo(fil, outPath); err != nil { + dh.t.Fatal(err) + } + rdata, err = ioutil.ReadFile(outPath) + if err != nil { + dh.t.Fatal(err) + } return rdata } -func ConnectAndStartMining(t *testing.T, blocktime time.Duration, miner *TestMiner, clients ...api.FullNode) *BlockMiner { +type DealsScaffold struct { + Ctx context.Context + Client *impl.FullNodeAPI + Miner TestMiner + BlockMiner *BlockMiner +} + +func ConnectAndStartMining(t *testing.T, blocktime time.Duration, miner TestMiner, clients ...api.FullNode) *BlockMiner { ctx := context.Background() for _, c := range clients { diff --git a/itests/kit/ensemble_presets.go b/itests/kit/ensemble_presets.go deleted file mode 100644 index fa7746f9572..00000000000 --- a/itests/kit/ensemble_presets.go +++ /dev/null @@ -1,41 +0,0 @@ -package kit - -import "testing" - -// EnsembleMinimal creates and starts an ensemble with a single full node and a single miner. -// It does not interconnect nodes nor does it begin mining. -func EnsembleMinimal(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 -} - -// EnsembleTwoOne creates and starts an ensemble with two full nodes and one miner. -// It does not interconnect nodes nor does it begin mining. -func EnsembleTwoOne(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 -} - -// EnsembleOneTwo creates and starts an ensemble with one full node and two miners. -// It does not interconnect nodes nor does it begin mining. -func EnsembleOneTwo(t *testing.T, opts ...NodeOpt) (*TestFullNode, *TestMiner, *TestMiner, *Ensemble) { - var ( - full TestFullNode - one, two TestMiner - ) - ensemble := NewEnsemble(t). - FullNode(&full, opts...). - Miner(&one, &full, opts...). - Miner(&two, &full, opts...). - Start() - - return &full, &one, &two, ensemble -} diff --git a/itests/kit/funds.go b/itests/kit/funds.go index 2ea822979c4..4c739dc62c2 100644 --- a/itests/kit/funds.go +++ b/itests/kit/funds.go @@ -5,7 +5,6 @@ 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" @@ -16,7 +15,9 @@ 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) - require.NoError(t, err) + if err != nil { + t.Fatal(err) + } msg := &types.Message{ From: senderAddr, @@ -25,10 +26,14 @@ func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient } sm, err := sender.MpoolPushMessage(ctx, msg, nil) - require.NoError(t, err) - + if err != nil { + t.Fatal(err) + } res, err := sender.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - - require.Equal(t, 0, res.Receipt.ExitCode, "did not successfully send funds") + if err != nil { + t.Fatal(err) + } + if res.Receipt.ExitCode != 0 { + t.Fatal("did not successfully send money") + } } diff --git a/itests/kit/init.go b/itests/kit/init.go index 8df4922b864..57d60ad2a5f 100644 --- a/itests/kit/init.go +++ b/itests/kit/init.go @@ -17,13 +17,9 @@ func init() { policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) - build.InsecurePoStValidation = true - - if err := os.Setenv("BELLMAN_NO_GPU", "1"); err != nil { + err := os.Setenv("BELLMAN_NO_GPU", "1") + if err != nil { panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err)) } - - if err := os.Setenv("LOTUS_DISABLE_WATCHDOG", "1"); err != nil { - panic(fmt.Sprintf("failed to set LOTUS_DISABLE_WATCHDOG env variable: %s", err)) - } + build.InsecurePoStValidation = true } diff --git a/itests/kit/net.go b/itests/kit/net.go index aea60909148..54c72443f43 100644 --- a/itests/kit/net.go +++ b/itests/kit/net.go @@ -1,42 +1,87 @@ package kit -// -// 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} -// } +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} +} diff --git a/itests/kit/node_builder.go b/itests/kit/node_builder.go new file mode 100644 index 00000000000..3780a766900 --- /dev/null +++ b/itests/kit/node_builder.go @@ -0,0 +1,658 @@ +package kit + +import ( + "bytes" + "context" + "crypto/rand" + "io/ioutil" + "net/http" + "net/http/httptest" + "sync" + "testing" + "time" + + "github.com/filecoin-project/go-state-types/network" + + "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) + } + + rkhKey, err := wallet.GenerateKey(types.KTSecp256k1) + if err != nil { + return nil, nil + } + + vrk := genesis.Actor{ + Type: genesis.TAccount, + Balance: big.Mul(big.Div(big.NewInt(int64(build.FilBase)), big.NewInt(100)), big.NewInt(int64(build.FilecoinPrecision))), + Meta: (&genesis.AccountMeta{Owner: rkhKey.Address}).ActorMeta(), + } + keys = append(keys, rkhKey) + + templ := &genesis.Template{ + NetworkVersion: network.Version0, + Accounts: genaccs, + Miners: genms, + NetworkName: "test", + Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past + VerifregRootKey: vrk, + 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()) + } + + if _, err := fulls[0].FullNode.WalletImport(ctx, &rkhKey.KeyInfo); err != nil { + t.Fatal(err) + } + + 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) + } + + rkhKey, err := wallet.GenerateKey(types.KTSecp256k1) + if err != nil { + return nil, nil + } + + vrk := genesis.Actor{ + Type: genesis.TAccount, + Balance: big.Mul(big.Div(big.NewInt(int64(build.FilBase)), big.NewInt(100)), big.NewInt(int64(build.FilecoinPrecision))), + Meta: (&genesis.AccountMeta{Owner: rkhKey.Address}).ActorMeta(), + } + keys = append(keys, rkhKey) + + templ := &genesis.Template{ + NetworkVersion: network.Version0, + Accounts: genaccs, + Miners: genms, + NetworkName: "test", + Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), + VerifregRootKey: vrk, + 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), + node.Override(new(ffiwrapper.Prover), mock.MockProver), + + // 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(*mock.SectorMgr), func() (*mock.SectorMgr, error) { + return mock.NewMockSectorMgr(nil), nil + }), + + node.Override(new(sectorstorage.SectorManager), node.From(new(*mock.SectorMgr))), + node.Override(new(sectorstorage.Unsealer), node.From(new(*mock.SectorMgr))), + node.Override(new(sectorstorage.PieceProvider), node.From(new(*mock.SectorMgr))), + + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Override(new(ffiwrapper.Prover), mock.MockProver), + node.Unset(new(*sectorstorage.Manager)), + )) + } + + if _, err := fulls[0].FullNode.WalletImport(ctx, &rkhKey.KeyInfo); err != nil { + t.Fatal(err) + } + + 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(*mock.SectorMgr), func() (*mock.SectorMgr, error) { + return mock.NewMockSectorMgr(sectors), nil + }), + + node.Override(new(sectorstorage.SectorManager), node.From(new(*mock.SectorMgr))), + node.Override(new(sectorstorage.Unsealer), node.From(new(*mock.SectorMgr))), + node.Override(new(sectorstorage.PieceProvider), node.From(new(*mock.SectorMgr))), + + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Override(new(ffiwrapper.Prover), mock.MockProver), + 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, false) + require.NoError(t, err) + + srv, maddr := CreateRPCServer(t, handler) + + var ret TestFullNode + cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+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, false) + require.NoError(t, err) + + srv, maddr := CreateRPCServer(t, handler) + + var ret TestMiner + cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+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/nodes.go b/itests/kit/nodes.go new file mode 100644 index 00000000000..d9b04166a50 --- /dev/null +++ b/itests/kit/nodes.go @@ -0,0 +1,153 @@ +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 { + // Attention: Update this when introducing new actor versions or your tests will be sad + return FullNodeWithNetworkUpgradeAt(network.Version13, upgradeHeight) +} + +var FullNodeWithNetworkUpgradeAt = func(version network.Version, upgradeHeight abi.ChainEpoch) FullNodeOpts { + fullSchedule := 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: 3, + Migration: stmgr.UpgradeActorsV4, + }, { + Network: network.Version13, + Height: 4, + Migration: stmgr.UpgradeActorsV5, + }} + + schedule := stmgr.UpgradeSchedule{} + for _, upgrade := range fullSchedule { + if upgrade.Network > version { + break + } + + schedule = append(schedule, upgrade) + } + + if upgradeHeight > 0 { + schedule[len(schedule)-1].Height = upgradeHeight + } + + return FullNodeOpts{ + Opts: func(nodes []TestFullNode) node.Option { + return node.Override(new(stmgr.UpgradeSchedule), schedule) + }, + } +} + +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 new file mode 100644 index 00000000000..254f87bac58 --- /dev/null +++ b/itests/kit/pledge.go @@ -0,0 +1,88 @@ +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 + toCheck := StartPledge(t, ctx, miner, n, existing, blockNotif) + + for len(toCheck) > 0 { + flushSealingBatches(t, ctx, miner) + + states := map[api.SectorState]int{} + for n := range toCheck { + st, err := miner.SectorsStatus(ctx, n, false) + require.NoError(t, err) + states[st.State]++ + 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 %+v\n", len(toCheck), states) + } +} + +func flushSealingBatches(t *testing.T, ctx context.Context, miner TestMiner) { //nolint:golint + pcb, err := miner.SectorPreCommitFlush(ctx) + require.NoError(t, err) + if pcb != nil { + fmt.Printf("PRECOMMIT BATCH: %+v\n", pcb) + } + + cb, err := miner.SectorCommitFlush(ctx) + require.NoError(t, err) + if cb != nil { + fmt.Printf("COMMIT BATCH: %+v\n", cb) + } +} + +func StartPledge(t *testing.T, ctx context.Context, miner TestMiner, n, existing int, blockNotif <-chan struct{}) map[abi.SectorNumber]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{}{} + } + + return toCheck +} diff --git a/itests/kit2/blockminer.go b/itests/kit2/blockminer.go new file mode 100644 index 00000000000..04d425dd623 --- /dev/null +++ b/itests/kit2/blockminer.go @@ -0,0 +1,124 @@ +package kit2 + +import ( + "context" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/miner" + "github.com/stretchr/testify/require" +) + +// BlockMiner is a utility that makes a test miner Mine blocks on a timer. +type BlockMiner struct { + t *testing.T + miner *TestMiner + + nextNulls int64 + wg sync.WaitGroup + cancel context.CancelFunc +} + +func NewBlockMiner(t *testing.T, miner *TestMiner) *BlockMiner { + return &BlockMiner{ + t: t, + miner: miner, + cancel: func() {}, + } +} + +func (bm *BlockMiner) MineBlocks(ctx context.Context, blocktime time.Duration) { + time.Sleep(time.Second) + + // wrap context in a cancellable context. + ctx, bm.cancel = context.WithCancel(ctx) + + bm.wg.Add(1) + go func() { + defer bm.wg.Done() + + for { + select { + case <-time.After(blocktime): + case <-ctx.Done(): + return + } + + nulls := atomic.SwapInt64(&bm.nextNulls, 0) + err := bm.miner.MineOne(ctx, miner.MineReq{ + InjectNulls: abi.ChainEpoch(nulls), + Done: func(bool, abi.ChainEpoch, error) {}, + }) + switch { + case err == nil: // wrap around + case ctx.Err() != nil: // context fired. + return + default: // log error + bm.t.Error(err) + } + } + }() +} + +// InjectNulls injects the specified amount of null rounds in the next +// mining rounds. +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)) { + for i := 0; i < 1000; i++ { + var ( + success bool + err error + epoch abi.ChainEpoch + wait = make(chan struct{}) + ) + + doneFn := func(win bool, ep abi.ChainEpoch, e error) { + success = win + err = e + epoch = ep + wait <- struct{}{} + } + + mineErr := bm.miner.MineOne(ctx, miner.MineReq{Done: doneFn}) + require.NoError(bm.t, mineErr) + <-wait + + require.NoError(bm.t, err) + + if success { + // Wait until it shows up on the given full nodes ChainHead + nloops := 200 + for i := 0; i < nloops; i++ { + ts, err := fn.ChainHead(ctx) + require.NoError(bm.t, err) + + if ts.Height() == epoch { + break + } + + require.NotEqual(bm.t, i, nloops-1, "block never managed to sync to node") + time.Sleep(time.Millisecond * 10) + } + + if cb != nil { + cb(epoch) + } + return + } + bm.t.Log("did not Mine block, trying again", i) + } + bm.t.Fatal("failed to Mine 1000 times in a row...") +} + +// Stop stops the block miner. +func (bm *BlockMiner) Stop() { + bm.t.Log("shutting down mining") + bm.cancel() + bm.wg.Wait() +} diff --git a/itests/kit2/client.go b/itests/kit2/client.go new file mode 100644 index 00000000000..2777d8d2584 --- /dev/null +++ b/itests/kit2/client.go @@ -0,0 +1,107 @@ +package kit2 + +import ( + "context" + "fmt" + "path/filepath" + "regexp" + "strings" + "testing" + "time" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/v2/actors/builtin" + "github.com/stretchr/testify/require" + lcli "github.com/urfave/cli/v2" +) + +// RunClientTest exercises some of the Client CLI commands +func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Create mock CLI + mockCLI := NewMockCLI(ctx, t, cmds) + clientCLI := mockCLI.Client(clientNode.ListenAddr) + + // Get the Miner address + addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) + require.NoError(t, err) + require.Len(t, addrs, 1) + + minerAddr := addrs[0] + fmt.Println("Miner:", minerAddr) + + // client query-ask + out := clientCLI.RunCmd("client", "query-ask", minerAddr.String()) + require.Regexp(t, regexp.MustCompile("Ask:"), out) + + // Create a deal (non-interactive) + // client deal --start-epoch= 1000000attofil + res, _ := clientNode.CreateImportFile(ctx, 1, 0) + + require.NoError(t, err) + startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) + dataCid := res.Root + price := "1000000attofil" + duration := fmt.Sprintf("%d", build.MinDealDuration) + out = clientCLI.RunCmd("client", "deal", startEpoch, dataCid.String(), minerAddr.String(), price, duration) + fmt.Println("client deal", out) + + // Create a deal (interactive) + // client deal + // + // (in days) + // + // "no" (verified Client) + // "yes" (confirm deal) + res, _ = clientNode.CreateImportFile(ctx, 2, 0) + require.NoError(t, err) + dataCid2 := res.Root + duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) + cmd := []string{"client", "deal"} + interactiveCmds := []string{ + dataCid2.String(), + duration, + minerAddr.String(), + "no", + "yes", + } + out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds) + fmt.Println("client deal:\n", out) + + // Wait for provider to start sealing deal + dealStatus := "" + for { + // client list-deals + out = clientCLI.RunCmd("client", "list-deals") + fmt.Println("list-deals:\n", out) + + lines := strings.Split(out, "\n") + require.GreaterOrEqual(t, len(lines), 2) + re := regexp.MustCompile(`\s+`) + parts := re.Split(lines[1], -1) + if len(parts) < 4 { + require.Fail(t, "bad list-deals output format") + } + dealStatus = parts[3] + fmt.Println(" Deal status:", dealStatus) + + st := CategorizeDealState(dealStatus) + require.NotEqual(t, TestDealStateFailed, st) + if st == TestDealStateComplete { + break + } + + time.Sleep(time.Second) + } + + // Retrieve the first file from the Miner + // client retrieve + tmpdir := t.TempDir() + path := filepath.Join(tmpdir, "outfile.dat") + out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) + fmt.Println("retrieve:\n", out) + require.Regexp(t, regexp.MustCompile("Success"), out) +} diff --git a/itests/kit2/deals.go b/itests/kit2/deals.go new file mode 100644 index 00000000000..e2dc00d5258 --- /dev/null +++ b/itests/kit2/deals.go @@ -0,0 +1,245 @@ +package kit2 + +import ( + "bytes" + "context" + "io/ioutil" + "testing" + "time" + + "github.com/ipfs/go-cid" + files "github.com/ipfs/go-ipfs-files" + "github.com/ipld/go-car" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + ipld "github.com/ipfs/go-ipld-format" + dag "github.com/ipfs/go-merkledag" + dstest "github.com/ipfs/go-merkledag/test" + unixfile "github.com/ipfs/go-unixfs/file" +) + +type DealHarness struct { + t *testing.T + client *TestFullNode + miner *TestMiner +} + +// NewDealHarness creates a test harness that contains testing utilities for deals. +func NewDealHarness(t *testing.T, client *TestFullNode, miner *TestMiner) *DealHarness { + return &DealHarness{ + t: t, + client: client, + miner: miner, + } +} + +// MakeOnlineDeal makes an online deal, generating a random file with the +// supplied seed, and setting the specified fast retrieval flag and start epoch +// on the storage deal. It returns when the deal is sealed. +// +// TODO: convert input parameters to struct, and add size as an input param. +func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, rseed int, fastRet bool, startEpoch abi.ChainEpoch) (deal *cid.Cid, res *api.ImportRes, path string) { + res, path = dh.client.CreateImportFile(ctx, rseed, 0) + + dh.t.Logf("FILE CID: %s", res.Root) + + deal = dh.StartDeal(ctx, res.Root, fastRet, startEpoch) + + // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this + time.Sleep(time.Second) + dh.WaitDealSealed(ctx, deal, false, false, nil) + + return deal, res, path +} + +// StartDeal starts a storage deal between the client and the miner. +func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { + maddr, err := dh.miner.ActorAddress(ctx) + require.NoError(dh.t, err) + + addr, err := dh.client.WalletDefaultAddress(ctx) + require.NoError(dh.t, err) + + deal, err := dh.client.ClientStartDeal(ctx, &api.StartDealParams{ + Data: &storagemarket.DataRef{ + TransferType: storagemarket.TTGraphsync, + Root: fcid, + }, + Wallet: addr, + Miner: maddr, + EpochPrice: types.NewInt(1000000), + DealStartEpoch: startEpoch, + MinBlocksDuration: uint64(build.MinDealDuration), + FastRetrieval: fastRet, + }) + require.NoError(dh.t, err) + + return deal +} + +// WaitDealSealed waits until the deal is sealed. +func (dh *DealHarness) WaitDealSealed(ctx context.Context, deal *cid.Cid, noseal, noSealStart bool, cb func()) { +loop: + for { + di, err := dh.client.ClientGetDealInfo(ctx, *deal) + require.NoError(dh.t, err) + + switch di.State { + case storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing: + if noseal { + return + } + if !noSealStart { + dh.StartSealingWaiting(ctx) + } + case storagemarket.StorageDealProposalRejected: + dh.t.Fatal("deal rejected") + case storagemarket.StorageDealFailing: + dh.t.Fatal("deal failed") + case storagemarket.StorageDealError: + dh.t.Fatal("deal errored", di.Message) + case storagemarket.StorageDealActive: + dh.t.Log("COMPLETE", di) + break loop + } + + mds, err := dh.miner.MarketListIncompleteDeals(ctx) + require.NoError(dh.t, err) + + var minerState storagemarket.StorageDealStatus + for _, md := range mds { + if md.DealID == di.DealID { + minerState = md.State + break + } + } + + dh.t.Logf("Deal %d state: client:%s provider:%s\n", di.DealID, storagemarket.DealStates[di.State], storagemarket.DealStates[minerState]) + time.Sleep(time.Second / 2) + if cb != nil { + cb() + } + } +} + +// WaitDealSealed waits until the deal is published. +func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { + subCtx, cancel := context.WithCancel(ctx) + defer cancel() + + updates, err := dh.miner.MarketGetDealUpdates(subCtx) + require.NoError(dh.t, err) + + for { + select { + case <-ctx.Done(): + dh.t.Fatal("context timeout") + case di := <-updates: + if deal.Equals(di.ProposalCid) { + switch di.State { + case storagemarket.StorageDealProposalRejected: + dh.t.Fatal("deal rejected") + case storagemarket.StorageDealFailing: + dh.t.Fatal("deal failed") + case storagemarket.StorageDealError: + dh.t.Fatal("deal errored", di.Message) + case storagemarket.StorageDealFinalizing, storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing, storagemarket.StorageDealActive: + dh.t.Log("COMPLETE", di) + return + } + dh.t.Log("Deal state: ", storagemarket.DealStates[di.State]) + } + } + } +} + +func (dh *DealHarness) StartSealingWaiting(ctx context.Context) { + snums, err := dh.miner.SectorsList(ctx) + require.NoError(dh.t, err) + + for _, snum := range snums { + si, err := dh.miner.SectorsStatus(ctx, snum, false) + require.NoError(dh.t, err) + + dh.t.Logf("Sector state: %s", si.State) + if si.State == api.SectorState(sealing.WaitDeals) { + require.NoError(dh.t, dh.miner.SectorStartSealing(ctx, snum)) + } + + dh.miner.FlushSealingBatches(ctx) + } +} + +func (dh *DealHarness) PerformRetrieval(ctx context.Context, deal *cid.Cid, root cid.Cid, carExport bool) (path string) { + // perform retrieval. + info, err := dh.client.ClientGetDealInfo(ctx, *deal) + require.NoError(dh.t, err) + + offers, err := dh.client.ClientFindData(ctx, root, &info.PieceCID) + require.NoError(dh.t, err) + require.NotEmpty(dh.t, offers, "no offers") + + tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "ret-car") + require.NoError(dh.t, err) + + defer tmpfile.Close() + + caddr, err := dh.client.WalletDefaultAddress(ctx) + require.NoError(dh.t, err) + + ref := &api.FileRef{ + Path: tmpfile.Name(), + IsCAR: carExport, + } + + updates, err := dh.client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref) + require.NoError(dh.t, err) + + for update := range updates { + require.Emptyf(dh.t, update.Err, "retrieval failed: %s", update.Err) + } + + rdata, err := ioutil.ReadFile(tmpfile.Name()) + require.NoError(dh.t, err) + + if carExport { + rdata = dh.ExtractFileFromCAR(ctx, rdata) + } + + return tmpfile.Name() +} + +func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, rdata []byte) []byte { + bserv := dstest.Bserv() + ch, err := car.LoadCar(bserv.Blockstore(), bytes.NewReader(rdata)) + require.NoError(dh.t, err) + + b, err := bserv.GetBlock(ctx, ch.Roots[0]) + require.NoError(dh.t, err) + + nd, err := ipld.Decode(b) + require.NoError(dh.t, err) + + dserv := dag.NewDAGService(bserv) + fil, err := unixfile.NewUnixfsFile(ctx, dserv, nd) + require.NoError(dh.t, err) + + tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "file-in-car") + require.NoError(dh.t, err) + + defer tmpfile.Close() + + err = files.WriteTo(fil, tmpfile.Name()) + require.NoError(dh.t, err) + + rdata, err = ioutil.ReadFile(tmpfile.Name()) + require.NoError(dh.t, err) + + return rdata +} diff --git a/itests/kit2/deals_state.go b/itests/kit2/deals_state.go new file mode 100644 index 00000000000..be3a9e4db5b --- /dev/null +++ b/itests/kit2/deals_state.go @@ -0,0 +1,21 @@ +package kit2 + +type TestDealState int + +const ( + TestDealStateFailed = TestDealState(-1) + TestDealStateInProgress = TestDealState(0) + TestDealStateComplete = TestDealState(1) +) + +// CategorizeDealState categorizes deal states into one of three states: +// Complete, InProgress, Failed. +func CategorizeDealState(dealStatus string) TestDealState { + switch dealStatus { + case "StorageDealFailing", "StorageDealError": + return TestDealStateFailed + case "StorageDealStaged", "StorageDealAwaitingPreCommit", "StorageDealSealing", "StorageDealActive", "StorageDealExpired", "StorageDealSlashed": + return TestDealStateComplete + } + return TestDealStateInProgress +} diff --git a/itests/kit/ensemble.go b/itests/kit2/ensemble.go similarity index 75% rename from itests/kit/ensemble.go rename to itests/kit2/ensemble.go index cfc95e968fa..5d12c83e127 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit2/ensemble.go @@ -1,12 +1,10 @@ -package kit +package kit2 import ( "bytes" "context" "crypto/rand" "io/ioutil" - "net/http" - "net/http/httptest" "sync" "testing" "time" @@ -15,10 +13,8 @@ import ( "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" @@ -28,7 +24,6 @@ import ( "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" @@ -49,8 +44,6 @@ import ( 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" ) @@ -61,33 +54,51 @@ func init() { 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. +// Ensemble is a collection of nodes instantiated within a test. +// +// Create a new ensemble with: +// +// ens := kit.NewEnsemble() +// +// Create full nodes and miners: +// +// var full TestFullNode +// var miner TestMiner +// ens.FullNode(&full, opts...) // populates a full node +// ens.Miner(&miner, &full, opts...) // populates a miner, using the full node as its chain daemon +// +// It is possible to pass functional options to set initial balances, +// presealed sectors, owner keys, etc. +// +// After the initial nodes are added, call `ens.Start()` to forge genesis +// and start the network. Mining will NOT be started automatically. It needs +// to be started explicitly by calling `BeginMining`. +// +// Nodes also need to be connected with one another, either via `ens.Connect()` +// or `ens.InterconnectAll()`. A common inchantation for simple tests is to do: +// +// ens.InterconnectAll().BeginMining(blocktime) +// +// You can continue to add more nodes, but you must always follow with +// `ens.Start()` to activate the new nodes. +// +// The API is chainable, so it's possible to do a lot in a very succinct way: +// +// kit.NewEnsemble().FullNode(&full).Miner(&miner, &full).Start().InterconnectAll().BeginMining() +// +// You can also find convenient fullnode:miner presets, such as 1:1, 1:2, +// and 2:1, e.g.: +// +// kit.EnsembleMinimal() +// kit.EnsembleOneTwo() +// kit.EnsembleTwoOne() +// type Ensemble struct { t *testing.T bootstrapped bool genesisBlock bytes.Buffer mn mocknet.Mocknet - options *BuilderOpts + options *ensembleOpts inactive struct { fullnodes []*TestFullNode @@ -103,9 +114,10 @@ type Ensemble struct { } } -// NewEnsemble -func NewEnsemble(t *testing.T, opts ...BuilderOpt) *Ensemble { - options := DefaultBuilderOpts +// NewEnsemble instantiates a new blank Ensemble. This enables you to +// programmatically +func NewEnsemble(t *testing.T, opts ...EnsembleOpt) *Ensemble { + options := DefaultEnsembleOpts for _, o := range opts { err := o(&options) require.NoError(t, err) @@ -113,85 +125,6 @@ func NewEnsemble(t *testing.T, opts ...BuilderOpt) *Ensemble { return &Ensemble{t: t, options: &options} } -type NodeOpts struct { - balance abi.TokenAmount - lite bool - sectors int - mockProofs bool - rpc bool - ownerKey *wallet.Key - extraNodeOpts []node.Option -} - -const DefaultPresealsPerBootstrapMiner = 2 - -var DefaultNodeOpts = NodeOpts{ - balance: big.Mul(big.NewInt(100000000), types.NewInt(build.FilecoinPrecision)), - sectors: DefaultPresealsPerBootstrapMiner, -} - -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 - } -} - -func ExtraNodeOpts(extra ...node.Option) NodeOpt { - return func(opts *NodeOpts) error { - opts.extraNodeOpts = extra - return nil - } -} - // FullNode enrolls a new full node. func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { options := DefaultNodeOpts @@ -256,7 +189,7 @@ func (n *Ensemble) Miner(miner *TestMiner, full *TestFullNode, opts ...NodeOpt) ) // create the preseal commitment. - if options.mockProofs { + if n.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) @@ -339,7 +272,7 @@ func (n *Ensemble) Start() *Ensemble { } // Are we mocking proofs? - if full.options.mockProofs { + if n.options.mockProofs { opts = append(opts, node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), node.Override(new(ffiwrapper.Prover), mock.MockProver), @@ -389,7 +322,7 @@ func (n *Ensemble) Start() *Ensemble { params, aerr := actors.SerializeParams(&power2.CreateMinerParams{ Owner: m.OwnerKey.Address, Worker: m.OwnerKey.Address, - SealProofType: n.options.spt, + SealProofType: n.options.proofType, Peer: abi.PeerID(m.Libp2p.PeerID), }) require.NoError(n.t, aerr) @@ -512,7 +445,7 @@ func (n *Ensemble) Start() *Ensemble { } } - if m.options.mockProofs { + if n.options.mockProofs { opts = append(opts, node.Override(new(*mock.SectorMgr), func() (*mock.SectorMgr, error) { return mock.NewMockSectorMgr(presealSectors), nil @@ -532,7 +465,7 @@ func (n *Ensemble) Start() *Ensemble { require.NoError(n.t, err) // using real proofs, therefore need real sectors. - if !n.bootstrapped && !m.options.mockProofs { + if !n.bootstrapped && !n.options.mockProofs { err := m.StorageAddLocal(ctx, m.PresealDir) require.NoError(n.t, err) } @@ -667,99 +600,3 @@ func (n *Ensemble) generateGenesis() *genesis.Template { 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 { - handler, err := node.FullNodeHandler(f.FullNode, false) - require.NoError(t, err) - - srv, maddr := CreateRPCServer(t, handler) - - cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) - require.NoError(t, err) - t.Cleanup(stop) - f.ListenAddr, f.FullNode = maddr, cl - - return f -} - -func minerRpc(t *testing.T, m *TestMiner) *TestMiner { - handler, err := node.MinerHandler(m.StorageMiner, false) - require.NoError(t, err) - - srv, maddr := CreateRPCServer(t, handler) - - cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v0", nil) - require.NoError(t, err) - t.Cleanup(stop) - - m.ListenAddr, m.StorageMiner = maddr, cl - return m -} - -func LatestActorsAt(upgradeHeight abi.ChainEpoch) node.Option { - // Attention: Update this when introducing new actor versions or your tests will be sad - return NetworkUpgradeAt(network.Version13, upgradeHeight) -} - -func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { - fullSchedule := 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: 3, - Migration: stmgr.UpgradeActorsV4, - }, { - Network: network.Version13, - Height: 4, - Migration: stmgr.UpgradeActorsV5, - }} - - schedule := stmgr.UpgradeSchedule{} - for _, upgrade := range fullSchedule { - if upgrade.Network > version { - break - } - - schedule = append(schedule, upgrade) - } - - if upgradeHeight > 0 { - schedule[len(schedule)-1].Height = upgradeHeight - } - - return node.Override(new(stmgr.UpgradeSchedule), schedule) -} - -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/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go new file mode 100644 index 00000000000..724113bdcde --- /dev/null +++ b/itests/kit2/ensemble_opts.go @@ -0,0 +1,35 @@ +package kit2 + +import ( + "time" + + "github.com/filecoin-project/go-state-types/abi" +) + +type EnsembleOpt func(opts *ensembleOpts) error + +type ensembleOpts struct { + pastOffset time.Duration + proofType abi.RegisteredSealProof + mockProofs bool +} + +var DefaultEnsembleOpts = ensembleOpts{ + pastOffset: 10000 * time.Second, + proofType: abi.RegisteredSealProof_StackedDrg2KiBV1, +} + +func ProofType(proofType abi.RegisteredSealProof) EnsembleOpt { + return func(opts *ensembleOpts) error { + opts.proofType = proofType + return nil + } +} + +// MockProofs activates mock proofs for the entire ensemble. +func MockProofs() EnsembleOpt { + return func(opts *ensembleOpts) error { + opts.mockProofs = true + return nil + } +} diff --git a/itests/kit2/ensemble_presets.go b/itests/kit2/ensemble_presets.go new file mode 100644 index 00000000000..28a4b5d9224 --- /dev/null +++ b/itests/kit2/ensemble_presets.go @@ -0,0 +1,70 @@ +package kit2 + +import "testing" + +// EnsembleMinimal creates and starts an Ensemble with a single full node and a single miner. +// It does not interconnect nodes nor does it begin mining. +// +// This function supports passing both ensemble and node functional options. +// Functional options are applied to all nodes. +func EnsembleMinimal(t *testing.T, opts ...interface{}) (*TestFullNode, *TestMiner, *Ensemble) { + eopts, nopts := siftOptions(t, opts) + + var ( + full TestFullNode + miner TestMiner + ) + ens := NewEnsemble(t, eopts...).FullNode(&full, nopts...).Miner(&miner, &full, nopts...).Start() + return &full, &miner, ens +} + +// EnsembleTwoOne creates and starts an Ensemble with two full nodes and one miner. +// It does not interconnect nodes nor does it begin mining. +// +// This function supports passing both ensemble and node functional options. +// Functional options are applied to all nodes. +func EnsembleTwoOne(t *testing.T, opts ...interface{}) (*TestFullNode, *TestFullNode, *TestMiner, *Ensemble) { + eopts, nopts := siftOptions(t, opts) + + var ( + one, two TestFullNode + miner TestMiner + ) + ens := NewEnsemble(t, eopts...).FullNode(&one, nopts...).FullNode(&two, nopts...).Miner(&miner, &one, nopts...).Start() + return &one, &two, &miner, ens +} + +// EnsembleOneTwo creates and starts an Ensemble with one full node and two miners. +// It does not interconnect nodes nor does it begin mining. +// +// This function supports passing both ensemble and node functional options. +// Functional options are applied to all nodes. +func EnsembleOneTwo(t *testing.T, opts ...interface{}) (*TestFullNode, *TestMiner, *TestMiner, *Ensemble) { + eopts, nopts := siftOptions(t, opts) + + var ( + full TestFullNode + one, two TestMiner + ) + ens := NewEnsemble(t, eopts...). + FullNode(&full, nopts...). + Miner(&one, &full, nopts...). + Miner(&two, &full, nopts...). + Start() + + return &full, &one, &two, ens +} + +func siftOptions(t *testing.T, opts []interface{}) (eopts []EnsembleOpt, nopts []NodeOpt) { + for _, v := range opts { + switch o := v.(type) { + case EnsembleOpt: + eopts = append(eopts, o) + case NodeOpt: + nopts = append(nopts, o) + default: + t.Fatalf("invalid option type: %T", o) + } + } + return eopts, nopts +} diff --git a/itests/kit/files.go b/itests/kit2/files.go similarity index 82% rename from itests/kit/files.go rename to itests/kit2/files.go index d4e92fecfc4..1e1509858fe 100644 --- a/itests/kit/files.go +++ b/itests/kit2/files.go @@ -1,4 +1,4 @@ -package kit +package kit2 import ( "bytes" @@ -31,8 +31,9 @@ func CreateRandomFile(t *testing.T, rseed, size int) (path string) { return file.Name() } -// FilesEqual compares two files by blake2b hash equality. -func FilesEqual(t *testing.T, left, right string) bool { +// AssertFilesEqual compares two files by blake2b hash equality and +// fails the test if unequal. +func AssertFilesEqual(t *testing.T, left, right string) { // initialize hashes. leftH, rightH := blake2b.New256(), blake2b.New256() @@ -53,5 +54,5 @@ func FilesEqual(t *testing.T, left, right string) bool { // compute digests. leftD, rightD := leftH.Sum(nil), rightH.Sum(nil) - return bytes.Equal(leftD, rightD) + require.True(t, bytes.Equal(leftD, rightD)) } diff --git a/itests/kit2/funds.go b/itests/kit2/funds.go new file mode 100644 index 00000000000..da37ae2ba1b --- /dev/null +++ b/itests/kit2/funds.go @@ -0,0 +1,34 @@ +package kit2 + +import ( + "context" + "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" + "github.com/filecoin-project/lotus/chain/types" +) + +// SendFunds sends funds from the default wallet of the specified sender node +// 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) + require.NoError(t, err) + + msg := &types.Message{ + From: senderAddr, + To: recipient, + Value: amount, + } + + sm, err := sender.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) + + res, err := sender.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + require.Equal(t, 0, res.Receipt.ExitCode, "did not successfully send funds") +} diff --git a/itests/kit2/init.go b/itests/kit2/init.go new file mode 100644 index 00000000000..dfc5a13f201 --- /dev/null +++ b/itests/kit2/init.go @@ -0,0 +1,29 @@ +package kit2 + +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)) + + build.InsecurePoStValidation = true + + if err := os.Setenv("BELLMAN_NO_GPU", "1"); err != nil { + panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err)) + } + + if err := os.Setenv("LOTUS_DISABLE_WATCHDOG", "1"); err != nil { + panic(fmt.Sprintf("failed to set LOTUS_DISABLE_WATCHDOG env variable: %s", err)) + } +} diff --git a/itests/kit2/log.go b/itests/kit2/log.go new file mode 100644 index 00000000000..9b9a14d92bc --- /dev/null +++ b/itests/kit2/log.go @@ -0,0 +1,19 @@ +package kit2 + +import ( + "github.com/filecoin-project/lotus/lib/lotuslog" + logging "github.com/ipfs/go-log/v2" +) + +func QuietMiningLogs() { + lotuslog.SetupLogLevels() + + _ = logging.SetLogLevel("miner", "ERROR") + _ = logging.SetLogLevel("chainstore", "ERROR") + _ = logging.SetLogLevel("chain", "ERROR") + _ = logging.SetLogLevel("sub", "ERROR") + _ = logging.SetLogLevel("storageminer", "ERROR") + _ = logging.SetLogLevel("pubsub", "ERROR") + _ = logging.SetLogLevel("gen", "ERROR") + _ = logging.SetLogLevel("dht/RtRefreshManager", "ERROR") +} diff --git a/itests/kit/node_full.go b/itests/kit2/node_full.go similarity index 78% rename from itests/kit/node_full.go rename to itests/kit2/node_full.go index 0e991206331..b0b39b471ec 100644 --- a/itests/kit/node_full.go +++ b/itests/kit2/node_full.go @@ -1,4 +1,4 @@ -package kit +package kit2 import ( "context" @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" ) +// TestFullNode represents a full node enrolled in an Ensemble. type TestFullNode struct { v1api.FullNode @@ -21,9 +22,11 @@ type TestFullNode struct { ListenAddr multiaddr.Multiaddr DefaultKey *wallet.Key - options NodeOpts + options nodeOpts } +// CreateImportFile creates a random file with the specified seed and size, and +// imports it into the full node. func (f *TestFullNode) CreateImportFile(ctx context.Context, rseed int, size int) (res *api.ImportRes, path string) { path = CreateRandomFile(f.t, rseed, size) res, err := f.ClientImport(ctx, api.FileRef{Path: path}) diff --git a/itests/kit/node_miner.go b/itests/kit2/node_miner.go similarity index 95% rename from itests/kit/node_miner.go rename to itests/kit2/node_miner.go index 79da005ccfc..1cd65e20e7c 100644 --- a/itests/kit/node_miner.go +++ b/itests/kit2/node_miner.go @@ -1,4 +1,4 @@ -package kit +package kit2 import ( "context" @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/require" ) +// TestMiner represents a miner enrolled in an Ensemble. type TestMiner struct { api.StorageMiner @@ -42,12 +43,7 @@ type TestMiner struct { PrivKey libp2pcrypto.PrivKey } - options NodeOpts -} - -var MineNext = miner.MineReq{ - InjectNulls: 0, - Done: func(bool, abi.ChainEpoch, error) {}, + options nodeOpts } func (tm *TestMiner) PledgeSectors(ctx context.Context, n, existing int, blockNotif <-chan struct{}) { diff --git a/itests/kit2/node_opts.go b/itests/kit2/node_opts.go new file mode 100644 index 00000000000..59d5454df84 --- /dev/null +++ b/itests/kit2/node_opts.go @@ -0,0 +1,89 @@ +package kit2 + +import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/node" +) + +// DefaultPresealsPerBootstrapMiner is the number of preseals that every +// bootstrap miner has by default. It can be overridden through the +// PresealSectors option. +const DefaultPresealsPerBootstrapMiner = 2 + +// nodeOpts is an options accumulating struct, where functional options are +// merged into. +type nodeOpts struct { + balance abi.TokenAmount + lite bool + sectors int + rpc bool + ownerKey *wallet.Key + extraNodeOpts []node.Option +} + +// DefaultNodeOpts are the default options that will be applied to test nodes. +var DefaultNodeOpts = nodeOpts{ + balance: big.Mul(big.NewInt(100000000), types.NewInt(build.FilecoinPrecision)), + sectors: DefaultPresealsPerBootstrapMiner, +} + +// NodeOpt is a functional option for test nodes. +type NodeOpt func(opts *nodeOpts) error + +// OwnerBalance specifies the balance to be attributed to a miner's owner +// account. Only relevant 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 relevant 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 relevant when creating a miner. +func PresealSectors(sectors int) NodeOpt { + return func(opts *nodeOpts) error { + opts.sectors = sectors + return nil + } +} + +// ThroughRPC makes interactions with this node throughout the test flow through +// the JSON-RPC API. +func ThroughRPC() NodeOpt { + return func(opts *nodeOpts) error { + opts.rpc = true + return nil + } +} + +// OwnerAddr sets the owner address of a miner. Only relevant when creating +// a miner. +func OwnerAddr(wk *wallet.Key) NodeOpt { + return func(opts *nodeOpts) error { + opts.ownerKey = wk + return nil + } +} + +// ConstructorOpts are Lotus node constructor options that are passed as-is to +// the node. +func ConstructorOpts(extra ...node.Option) NodeOpt { + return func(opts *nodeOpts) error { + opts.extraNodeOpts = extra + return nil + } +} diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go new file mode 100644 index 00000000000..05d2c2287d6 --- /dev/null +++ b/itests/kit2/node_opts_nv.go @@ -0,0 +1,65 @@ +package kit2 + +import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/node" +) + +func LatestActorsAt(upgradeHeight abi.ChainEpoch) node.Option { + // Attention: Update this when introducing new actor versions or your tests will be sad + return NetworkUpgradeAt(network.Version13, upgradeHeight) +} + +func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { + fullSchedule := 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: 3, + Migration: stmgr.UpgradeActorsV4, + }, { + Network: network.Version13, + Height: 4, + Migration: stmgr.UpgradeActorsV5, + }} + + schedule := stmgr.UpgradeSchedule{} + for _, upgrade := range fullSchedule { + if upgrade.Network > version { + break + } + + schedule = append(schedule, upgrade) + } + + if upgradeHeight > 0 { + schedule[len(schedule)-1].Height = upgradeHeight + } + + return node.Override(new(stmgr.UpgradeSchedule), schedule) +} + +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/kit2/rpc.go b/itests/kit2/rpc.go new file mode 100644 index 00000000000..873b64257ad --- /dev/null +++ b/itests/kit2/rpc.go @@ -0,0 +1,53 @@ +package kit2 + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/node" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/stretchr/testify/require" +) + +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 { + handler, err := node.FullNodeHandler(f.FullNode, false) + require.NoError(t, err) + + srv, maddr := CreateRPCServer(t, handler) + + cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) + require.NoError(t, err) + t.Cleanup(stop) + f.ListenAddr, f.FullNode = maddr, cl + + return f +} + +func minerRpc(t *testing.T, m *TestMiner) *TestMiner { + handler, err := node.MinerHandler(m.StorageMiner, false) + require.NoError(t, err) + + srv, maddr := CreateRPCServer(t, handler) + + cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v0", nil) + require.NoError(t, err) + t.Cleanup(stop) + + m.ListenAddr, m.StorageMiner = maddr, cl + return m +} diff --git a/itests/multisig_test.go.no b/itests/multisig_test.go similarity index 100% rename from itests/multisig_test.go.no rename to itests/multisig_test.go diff --git a/itests/paych_api_test.go.no b/itests/paych_api_test.go similarity index 100% rename from itests/paych_api_test.go.no rename to itests/paych_api_test.go diff --git a/itests/paych_cli_test.go.no b/itests/paych_cli_test.go similarity index 100% rename from itests/paych_cli_test.go.no rename to itests/paych_cli_test.go diff --git a/itests/sdr_upgrade_test.go.no b/itests/sdr_upgrade_test.go similarity index 100% rename from itests/sdr_upgrade_test.go.no rename to itests/sdr_upgrade_test.go diff --git a/itests/sector_pledge_test.go.no b/itests/sector_pledge_test.go similarity index 100% rename from itests/sector_pledge_test.go.no rename to itests/sector_pledge_test.go diff --git a/itests/sector_terminate_test.go.no b/itests/sector_terminate_test.go similarity index 100% rename from itests/sector_terminate_test.go.no rename to itests/sector_terminate_test.go diff --git a/itests/tape_test.go.no b/itests/tape_test.go similarity index 100% rename from itests/tape_test.go.no rename to itests/tape_test.go diff --git a/itests/verifreg_test.go.no b/itests/verifreg_test.go similarity index 100% rename from itests/verifreg_test.go.no rename to itests/verifreg_test.go diff --git a/itests/wdpost_dispute_test.go.no b/itests/wdpost_dispute_test.go similarity index 100% rename from itests/wdpost_dispute_test.go.no rename to itests/wdpost_dispute_test.go diff --git a/itests/wdpost_test.go.no b/itests/wdpost_test.go similarity index 100% rename from itests/wdpost_test.go.no rename to itests/wdpost_test.go From 183814a8266989650563726cfe68166abce2c7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sun, 13 Jun 2021 23:43:22 +0100 Subject: [PATCH 13/72] finish migrating deals test. --- itests/api_test.go | 4 +- itests/ccupgrade_test.go | 1 - itests/deals_test.go | 102 +++++++++++-------------------------- itests/kit2/client.go | 107 --------------------------------------- 4 files changed, 32 insertions(+), 182 deletions(-) delete mode 100644 itests/kit2/client.go diff --git a/itests/api_test.go b/itests/api_test.go index a8abee92f9d..a4539444f56 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -26,11 +26,11 @@ func TestAPI(t *testing.T) { } type apiSuite struct { - opts []kit2.NodeOpt + opts []interface{} } // runAPITest is the entry point to API test suite -func runAPITest(t *testing.T, opts ...kit2.NodeOpt) { +func runAPITest(t *testing.T, opts ...interface{}) { ts := apiSuite{opts: opts} t.Run("version", ts.testVersion) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index f6ba878202f..28abac171a7 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -8,7 +8,6 @@ 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/deals_test.go b/itests/deals_test.go index b30e5ba699b..fed141cb150 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -352,75 +352,33 @@ func TestOfflineDealFlow(t *testing.T) { t.Run("fastretrieval", func(t *testing.T) { runTest(t, true) }) } -// -// func runSecondDealRetrievalTest(t *testing.T, b kit.APIBuilder, blocktime time.Duration) { -// ctx := context.Background() -// -// fulls, miners := b(t, kit.OneFull, kit.OneMiner) -// client, miner := fulls[0].FullNode.(*impl.FullNodeAPI), miners[0] -// -// kit.ConnectAndStartMining(t, blocktime, miner, client) -// -// dh := kit.NewDealHarness(t, client, miner) -// -// { -// data1 := make([]byte, 800) -// rand.New(rand.NewSource(int64(3))).Read(data1) -// r := bytes.NewReader(data1) -// -// fcid1, err := client.ClientImportLocal(ctx, r) -// if err != nil { -// t.Fatal(err) -// } -// -// data2 := make([]byte, 800) -// rand.New(rand.NewSource(int64(9))).Read(data2) -// r2 := bytes.NewReader(data2) -// -// fcid2, err := client.ClientImportLocal(ctx, r2) -// if err != nil { -// t.Fatal(err) -// } -// -// deal1 := dh.StartDeal(ctx, fcid1, true, 0) -// -// // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this -// time.Sleep(time.Second) -// dh.WaitDealSealed(ctx, deal1, true, false, nil) -// -// deal2 := dh.StartDeal(ctx, fcid2, true, 0) -// -// time.Sleep(time.Second) -// dh.WaitDealSealed(ctx, deal2, false, false, nil) -// -// // Retrieval -// info, err := client.ClientGetDealInfo(ctx, *deal2) -// require.NoError(t, err) -// -// rf, _ := miner.SectorsRefs(ctx) -// fmt.Printf("refs: %+v\n", rf) -// -// dh.PerformRetrieval(ctx, fcid2, &info.PieceCID, false, data2) -// } -// } -// -// func runZeroPricePerByteRetrievalDealFlow(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] -// -// kit.ConnectAndStartMining(t, blocktime, miner, client) -// -// dh := kit.NewDealHarness(t, client, miner) -// -// // Set price-per-byte to zero -// ask, err := miner.MarketGetRetrievalAsk(ctx) -// require.NoError(t, err) -// -// ask.PricePerByte = abi.NewTokenAmount(0) -// err = miner.MarketSetRetrievalAsk(ctx, ask) -// require.NoError(t, err) -// -// dh.MakeOnlineDeal(ctx, 6, false, false, startEpoch) -// } +func TestZeroPricePerByteRetrieval(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit2.QuietMiningLogs() + + var ( + blockTime = 10 * time.Millisecond + startEpoch = abi.ChainEpoch(2 << 12) + ) + + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx := context.Background() + + ask, err := miner.MarketGetRetrievalAsk(ctx) + require.NoError(t, err) + + ask.PricePerByte = abi.NewTokenAmount(0) + err = miner.MarketSetRetrievalAsk(ctx, ask) + require.NoError(t, err) + + dh := kit2.NewDealHarness(t, client, miner) + runConcurrentDeals(t, dh, fullDealCyclesOpts{ + n: 1, + startEpoch: startEpoch, + }) +} diff --git a/itests/kit2/client.go b/itests/kit2/client.go deleted file mode 100644 index 2777d8d2584..00000000000 --- a/itests/kit2/client.go +++ /dev/null @@ -1,107 +0,0 @@ -package kit2 - -import ( - "context" - "fmt" - "path/filepath" - "regexp" - "strings" - "testing" - "time" - - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/v2/actors/builtin" - "github.com/stretchr/testify/require" - lcli "github.com/urfave/cli/v2" -) - -// RunClientTest exercises some of the Client CLI commands -func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - // Create mock CLI - mockCLI := NewMockCLI(ctx, t, cmds) - clientCLI := mockCLI.Client(clientNode.ListenAddr) - - // Get the Miner address - addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) - require.NoError(t, err) - require.Len(t, addrs, 1) - - minerAddr := addrs[0] - fmt.Println("Miner:", minerAddr) - - // client query-ask - out := clientCLI.RunCmd("client", "query-ask", minerAddr.String()) - require.Regexp(t, regexp.MustCompile("Ask:"), out) - - // Create a deal (non-interactive) - // client deal --start-epoch= 1000000attofil - res, _ := clientNode.CreateImportFile(ctx, 1, 0) - - require.NoError(t, err) - startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) - dataCid := res.Root - price := "1000000attofil" - duration := fmt.Sprintf("%d", build.MinDealDuration) - out = clientCLI.RunCmd("client", "deal", startEpoch, dataCid.String(), minerAddr.String(), price, duration) - fmt.Println("client deal", out) - - // Create a deal (interactive) - // client deal - // - // (in days) - // - // "no" (verified Client) - // "yes" (confirm deal) - res, _ = clientNode.CreateImportFile(ctx, 2, 0) - require.NoError(t, err) - dataCid2 := res.Root - duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) - cmd := []string{"client", "deal"} - interactiveCmds := []string{ - dataCid2.String(), - duration, - minerAddr.String(), - "no", - "yes", - } - out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds) - fmt.Println("client deal:\n", out) - - // Wait for provider to start sealing deal - dealStatus := "" - for { - // client list-deals - out = clientCLI.RunCmd("client", "list-deals") - fmt.Println("list-deals:\n", out) - - lines := strings.Split(out, "\n") - require.GreaterOrEqual(t, len(lines), 2) - re := regexp.MustCompile(`\s+`) - parts := re.Split(lines[1], -1) - if len(parts) < 4 { - require.Fail(t, "bad list-deals output format") - } - dealStatus = parts[3] - fmt.Println(" Deal status:", dealStatus) - - st := CategorizeDealState(dealStatus) - require.NotEqual(t, TestDealStateFailed, st) - if st == TestDealStateComplete { - break - } - - time.Sleep(time.Second) - } - - // Retrieve the first file from the Miner - // client retrieve - tmpdir := t.TempDir() - path := filepath.Join(tmpdir, "outfile.dat") - out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) - fmt.Println("retrieve:\n", out) - require.Regexp(t, regexp.MustCompile("Success"), out) -} From 958b6b54a850424de36b8e664ac8e7f135e42743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sun, 13 Jun 2021 23:53:13 +0100 Subject: [PATCH 14/72] go mod tidy. --- go.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/go.mod b/go.mod index b34ca93220e..e22be541a1e 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07 github.com/coreos/go-systemd/v22 v22.1.0 - github.com/davecgh/go-spew v1.1.1 // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.2007.2 github.com/docker/go-units v0.4.0 From f1ec0d609403c11be6d8d6c3933af5d59f2ece4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 14 Jun 2021 00:10:37 +0100 Subject: [PATCH 15/72] fix lint. --- itests/deals_test.go | 1 + itests/kit2/deals.go | 31 ++++++++++++++----------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index fed141cb150..3a6d9c8682b 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -51,6 +51,7 @@ func TestDealCyclesConcurrent(t *testing.T) { cycles := []int{1, 2, 4, 8} for _, n := range cycles { + n := n ns := fmt.Sprintf("%d", n) t.Run(ns+"-fastretrieval-CAR", func(t *testing.T) { runTest(t, n, true, true) }) t.Run(ns+"-fastretrieval-NoCAR", func(t *testing.T) { runTest(t, n, true, false) }) diff --git a/itests/kit2/deals.go b/itests/kit2/deals.go index e2dc00d5258..2e015a9c721 100644 --- a/itests/kit2/deals.go +++ b/itests/kit2/deals.go @@ -1,9 +1,9 @@ package kit2 import ( - "bytes" "context" "io/ioutil" + "os" "testing" "time" @@ -128,7 +128,7 @@ loop: } } -// WaitDealSealed waits until the deal is published. +// WaitDealPublished waits until the deal is published. func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { subCtx, cancel := context.WithCancel(ctx) defer cancel() @@ -185,16 +185,16 @@ func (dh *DealHarness) PerformRetrieval(ctx context.Context, deal *cid.Cid, root require.NoError(dh.t, err) require.NotEmpty(dh.t, offers, "no offers") - tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "ret-car") + carFile, err := ioutil.TempFile(dh.t.TempDir(), "ret-car") require.NoError(dh.t, err) - defer tmpfile.Close() + defer carFile.Close() //nolint:errcheck caddr, err := dh.client.WalletDefaultAddress(ctx) require.NoError(dh.t, err) ref := &api.FileRef{ - Path: tmpfile.Name(), + Path: carFile.Name(), IsCAR: carExport, } @@ -205,19 +205,19 @@ func (dh *DealHarness) PerformRetrieval(ctx context.Context, deal *cid.Cid, root require.Emptyf(dh.t, update.Err, "retrieval failed: %s", update.Err) } - rdata, err := ioutil.ReadFile(tmpfile.Name()) - require.NoError(dh.t, err) - + ret := carFile.Name() if carExport { - rdata = dh.ExtractFileFromCAR(ctx, rdata) + actualFile := dh.ExtractFileFromCAR(ctx, carFile) + ret = actualFile.Name() + _ = actualFile.Close() //nolint:errcheck } - return tmpfile.Name() + return ret } -func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, rdata []byte) []byte { +func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, file *os.File) (out *os.File) { bserv := dstest.Bserv() - ch, err := car.LoadCar(bserv.Blockstore(), bytes.NewReader(rdata)) + ch, err := car.LoadCar(bserv.Blockstore(), file) require.NoError(dh.t, err) b, err := bserv.GetBlock(ctx, ch.Roots[0]) @@ -233,13 +233,10 @@ func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, rdata []byte) []b tmpfile, err := ioutil.TempFile(dh.t.TempDir(), "file-in-car") require.NoError(dh.t, err) - defer tmpfile.Close() + defer tmpfile.Close() //nolint:errcheck err = files.WriteTo(fil, tmpfile.Name()) require.NoError(dh.t, err) - rdata, err = ioutil.ReadFile(tmpfile.Name()) - require.NoError(dh.t, err) - - return rdata + return tmpfile } From ac67e466ec15b2fe71518e1f362975c2cc147db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 14 Jun 2021 00:13:15 +0100 Subject: [PATCH 16/72] fix test. --- itests/api_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itests/api_test.go b/itests/api_test.go index a4539444f56..f8567bd2aa7 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -87,11 +87,11 @@ func (ts *apiSuite) testConnectTwo(t *testing.T) { peers, err := one.NetPeers(ctx) require.NoError(t, err) - require.Lenf(t, peers, 1, "node one doesn't have 1 peer") + require.Lenf(t, peers, 2, "node one doesn't have 2 peers") peers, err = two.NetPeers(ctx) require.NoError(t, err) - require.Lenf(t, peers, 1, "node two doesn't have 1 peer") + require.Lenf(t, peers, 2, "node two doesn't have 2 peers") } func (ts *apiSuite) testSearchMsg(t *testing.T) { From d94a19ff65dbcb37a38ead4f527feaf2fea9d862 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 12:07:50 +0200 Subject: [PATCH 17/72] refactor: cli test with kit2 --- itests/cli_test.go | 13 ++-- itests/kit2/client.go | 146 +++++++++++++++++++++++++++++++++++++++++ itests/kit2/mockcli.go | 141 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 7 deletions(-) create mode 100644 itests/kit2/client.go create mode 100644 itests/kit2/mockcli.go diff --git a/itests/cli_test.go b/itests/cli_test.go index 10e2af15c8d..8436f189e65 100644 --- a/itests/cli_test.go +++ b/itests/cli_test.go @@ -1,22 +1,21 @@ package itests import ( - "context" "os" "testing" "time" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" ) // TestClient does a basic test to exercise the client CLI commands. func TestClient(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() - blocktime := 5 * time.Millisecond - ctx := context.Background() - clientNode, _ := kit.StartOneNodeOneMiner(ctx, t, blocktime) - kit.RunClientTest(t, cli.Commands, clientNode) + blockTime := 5 * time.Millisecond + client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + kit2.RunClientTest(t, cli.Commands, *client) } diff --git a/itests/kit2/client.go b/itests/kit2/client.go new file mode 100644 index 00000000000..247d208369b --- /dev/null +++ b/itests/kit2/client.go @@ -0,0 +1,146 @@ +package kit2 + +import ( + "context" + "fmt" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + "time" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/v2/actors/builtin" + "github.com/stretchr/testify/require" + lcli "github.com/urfave/cli/v2" +) + +// RunClientTest exercises some of the Client CLI commands +func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Create mock CLI + mockCLI := NewMockCLI(ctx, t, cmds) + clientCLI := mockCLI.Client(clientNode.ListenAddr) + + // Get the Miner address + addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) + require.NoError(t, err) + require.Len(t, addrs, 1) + + minerAddr := addrs[0] + fmt.Println("Miner:", minerAddr) + + // client query-ask + out := clientCLI.RunCmd("client", "query-ask", minerAddr.String()) + require.Regexp(t, regexp.MustCompile("Ask:"), out) + + // Create a deal (non-interactive) + // client deal --start-epoch= 1000000attofil + res, _, _, err := CreateImportFile(ctx, clientNode, 1, 0) + + require.NoError(t, err) + startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) + dataCid := res.Root + price := "1000000attofil" + duration := fmt.Sprintf("%d", build.MinDealDuration) + out = clientCLI.RunCmd("client", "deal", startEpoch, dataCid.String(), minerAddr.String(), price, duration) + fmt.Println("client deal", out) + + // Create a deal (interactive) + // client deal + // + // (in days) + // + // "no" (verified Client) + // "yes" (confirm deal) + res, _, _, err = CreateImportFile(ctx, clientNode, 2, 0) + require.NoError(t, err) + dataCid2 := res.Root + duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) + cmd := []string{"client", "deal"} + interactiveCmds := []string{ + dataCid2.String(), + duration, + minerAddr.String(), + "no", + "yes", + } + out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds) + fmt.Println("client deal:\n", out) + + // Wait for provider to start sealing deal + dealStatus := "" + for { + // client list-deals + out = clientCLI.RunCmd("client", "list-deals") + fmt.Println("list-deals:\n", out) + + lines := strings.Split(out, "\n") + require.GreaterOrEqual(t, len(lines), 2) + re := regexp.MustCompile(`\s+`) + parts := re.Split(lines[1], -1) + if len(parts) < 4 { + require.Fail(t, "bad list-deals output format") + } + dealStatus = parts[3] + fmt.Println(" Deal status:", dealStatus) + + st := CategorizeDealState(dealStatus) + require.NotEqual(t, TestDealStateFailed, st) + if st == TestDealStateComplete { + break + } + + time.Sleep(time.Second) + } + + // Retrieve the first file from the Miner + // client retrieve + tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client") + require.NoError(t, err) + path := filepath.Join(tmpdir, "outfile.dat") + out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) + fmt.Println("retrieve:\n", out) + require.Regexp(t, regexp.MustCompile("Success"), out) +} + +func CreateImportFile(ctx context.Context, client api.FullNode, rseed int, size int) (res *api.ImportRes, path string, data []byte, err error) { + data, path, err = createRandomFile(rseed, size) + if err != nil { + return nil, "", nil, err + } + + res, err = client.ClientImport(ctx, api.FileRef{Path: path}) + if err != nil { + return nil, "", nil, err + } + return res, path, data, nil +} + +func createRandomFile(rseed, size int) ([]byte, string, error) { + if size == 0 { + size = 1600 + } + data := make([]byte, size) + rand.New(rand.NewSource(int64(rseed))).Read(data) + + dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") + if err != nil { + return nil, "", err + } + + path := filepath.Join(dir, "sourcefile.dat") + err = ioutil.WriteFile(path, data, 0644) + if err != nil { + return nil, "", err + } + + return data, path, nil +} diff --git a/itests/kit2/mockcli.go b/itests/kit2/mockcli.go new file mode 100644 index 00000000000..592c9733379 --- /dev/null +++ b/itests/kit2/mockcli.go @@ -0,0 +1,141 @@ +package kit2 + +import ( + "bytes" + "context" + "flag" + "strings" + "testing" + + "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" + lcli "github.com/urfave/cli/v2" +) + +type MockCLI struct { + t *testing.T + cmds []*lcli.Command + cctx *lcli.Context + out *bytes.Buffer +} + +func NewMockCLI(ctx context.Context, t *testing.T, cmds []*lcli.Command) *MockCLI { + // Create a CLI App with an --api-url flag so that we can specify which node + // the command should be executed against + app := &lcli.App{ + Flags: []lcli.Flag{ + &lcli.StringFlag{ + Name: "api-url", + Hidden: true, + }, + }, + Commands: cmds, + } + + var out bytes.Buffer + app.Writer = &out + app.Setup() + + cctx := lcli.NewContext(app, &flag.FlagSet{}, nil) + cctx.Context = ctx + return &MockCLI{t: t, cmds: cmds, cctx: cctx, out: &out} +} + +func (c *MockCLI) Client(addr multiaddr.Multiaddr) *MockCLIClient { + return &MockCLIClient{t: c.t, cmds: c.cmds, addr: addr, cctx: c.cctx, out: c.out} +} + +// MockCLIClient runs commands against a particular node +type MockCLIClient struct { + t *testing.T + cmds []*lcli.Command + addr multiaddr.Multiaddr + cctx *lcli.Context + out *bytes.Buffer +} + +func (c *MockCLIClient) RunCmd(input ...string) string { + out, err := c.RunCmdRaw(input...) + require.NoError(c.t, err, "output:\n%s", out) + + return out +} + +// Given an input, find the corresponding command or sub-command. +// eg "paych add-funds" +func (c *MockCLIClient) cmdByNameSub(input []string) (*lcli.Command, []string) { + name := input[0] + for _, cmd := range c.cmds { + if cmd.Name == name { + return c.findSubcommand(cmd, input[1:]) + } + } + return nil, []string{} +} + +func (c *MockCLIClient) findSubcommand(cmd *lcli.Command, input []string) (*lcli.Command, []string) { + // If there are no sub-commands, return the current command + if len(cmd.Subcommands) == 0 { + return cmd, input + } + + // Check each sub-command for a match against the name + subName := input[0] + for _, subCmd := range cmd.Subcommands { + if subCmd.Name == subName { + // Found a match, recursively search for sub-commands + return c.findSubcommand(subCmd, input[1:]) + } + } + return nil, []string{} +} + +func (c *MockCLIClient) RunCmdRaw(input ...string) (string, error) { + cmd, input := c.cmdByNameSub(input) + if cmd == nil { + panic("Could not find command " + input[0] + " " + input[1]) + } + + // prepend --api-url= + apiFlag := "--api-url=" + c.addr.String() + input = append([]string{apiFlag}, input...) + + fs := c.flagSet(cmd) + err := fs.Parse(input) + require.NoError(c.t, err) + + err = cmd.Action(lcli.NewContext(c.cctx.App, fs, c.cctx)) + + // Get the output + str := strings.TrimSpace(c.out.String()) + c.out.Reset() + return str, err +} + +func (c *MockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { + // Apply app level flags (so we can process --api-url flag) + fs := &flag.FlagSet{} + for _, f := range c.cctx.App.Flags { + err := f.Apply(fs) + if err != nil { + c.t.Fatal(err) + } + } + // Apply command level flags + for _, f := range cmd.Flags { + err := f.Apply(fs) + if err != nil { + c.t.Fatal(err) + } + } + return fs +} + +func (c *MockCLIClient) RunInteractiveCmd(cmd []string, interactive []string) string { + c.toStdin(strings.Join(interactive, "\n") + "\n") + return c.RunCmd(cmd...) +} + +func (c *MockCLIClient) toStdin(s string) { + c.cctx.App.Metadata["stdin"] = bytes.NewBufferString(s) +} From 86cca7303d503e119e39c42cbb87a9392930dded Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 14:03:08 +0200 Subject: [PATCH 18/72] refactor: convert multisig tests to kit2 --- itests/multisig_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/itests/multisig_test.go b/itests/multisig_test.go index 4c513640d39..cc2b38c30e2 100644 --- a/itests/multisig_test.go +++ b/itests/multisig_test.go @@ -12,26 +12,26 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/stretchr/testify/require" ) // TestMultisig does a basic test to exercise the multisig CLI commands func TestMultisig(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() - blocktime := 5 * time.Millisecond - ctx := context.Background() - clientNode, _ := kit.StartOneNodeOneMiner(ctx, t, blocktime) + blockTime := 5 * time.Millisecond + client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + ens.InterconnectAll().BeginMining(blockTime) - runMultisigTests(t, clientNode) + runMultisigTests(t, *client) } -func runMultisigTests(t *testing.T, clientNode kit.TestFullNode) { +func runMultisigTests(t *testing.T, clientNode kit2.TestFullNode) { // Create mock CLI ctx := context.Background() - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) clientCLI := mockCLI.Client(clientNode.ListenAddr) // Create some wallets on the node to use for testing multisig @@ -42,7 +42,7 @@ func runMultisigTests(t *testing.T, clientNode kit.TestFullNode) { walletAddrs = append(walletAddrs, addr) - kit.SendFunds(ctx, t, clientNode, addr, types.NewInt(1e15)) + kit2.SendFunds(ctx, t, clientNode, addr, types.NewInt(1e15)) } // Create an msig with three of the addresses and threshold of two sigs From 7b00b1828b082939d50f9477c8868911bdeafe69 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 15:28:05 +0200 Subject: [PATCH 19/72] refactor: convert paych to kit2 --- itests/kit2/funds.go | 2 +- itests/paych_api_test.go | 54 ++++++++++++++++------------------------ 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/itests/kit2/funds.go b/itests/kit2/funds.go index da37ae2ba1b..fc4a6c29486 100644 --- a/itests/kit2/funds.go +++ b/itests/kit2/funds.go @@ -30,5 +30,5 @@ func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient res, err := sender.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) - require.Equal(t, 0, res.Receipt.ExitCode, "did not successfully send funds") + require.EqualValues(t, 0, res.Receipt.ExitCode, "did not successfully send funds") } diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go index 23fec855b48..900b3d092aa 100644 --- a/itests/paych_api_test.go +++ b/itests/paych_api_test.go @@ -8,7 +8,6 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/lotus/itests/kit" "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" @@ -24,36 +23,30 @@ import ( "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit2" ) func TestPaymentChannelsAPI(t *testing.T) { - kit.QuietMiningLogs() + kit2.QuietMiningLogs() ctx := context.Background() - n, sn := kit.MockMinerBuilder(t, kit.TwoFull, kit.OneMiner) - - paymentCreator := n[0] - paymentReceiver := n[1] - miner := sn[0] - - // get everyone connected - addrs, err := paymentCreator.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := paymentReceiver.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - // start mining blocks - bm := kit.NewBlockMiner(t, miner) - bm.MineBlocks(ctx, 5*time.Millisecond) - t.Cleanup(bm.Stop) + blockTime := 5 * time.Millisecond + + var ( + paymentCreator kit2.TestFullNode + paymentReceiver kit2.TestFullNode + miner kit2.TestMiner + ) + + //n, sn := kit2.MockMinerBuilder(t, kit2.TwoFull, kit2.OneMiner) + ens := kit2.NewEnsemble(t, kit2.MockProofs()). + FullNode(&paymentCreator). + FullNode(&paymentReceiver). + Miner(&miner, &paymentCreator). + Start(). + InterconnectAll() + bms := ens.BeginMining(blockTime, &miner) + bm := bms[0] // send some funds to register the receiver receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1) @@ -61,7 +54,7 @@ func TestPaymentChannelsAPI(t *testing.T) { t.Fatal(err) } - kit.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) + kit2.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) // setup the payment channel createrAddr, err := paymentCreator.WalletDefaultAddress(ctx) @@ -263,12 +256,9 @@ func TestPaymentChannelsAPI(t *testing.T) { if !delta.Equals(abi.NewTokenAmount(expectedRefund)) { t.Fatalf("did not send correct funds from creator: expected %d, got %d", expectedRefund, delta) } - - // shut down mining - bm.Stop() } -func waitForBlocks(ctx context.Context, t *testing.T, bm *kit.BlockMiner, paymentReceiver kit.TestFullNode, receiverAddr address.Address, count int) { +func waitForBlocks(ctx context.Context, t *testing.T, bm *kit2.BlockMiner, paymentReceiver kit2.TestFullNode, receiverAddr address.Address, count int) { // We need to add null blocks in batches, if we add too many the chain can't sync batchSize := 60 for i := 0; i < count; i += batchSize { @@ -297,7 +287,7 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *kit.BlockMiner, paymen } } -func waitForMessage(ctx context.Context, t *testing.T, paymentCreator kit.TestFullNode, msgCid cid.Cid, duration time.Duration, desc string) *api.MsgLookup { +func waitForMessage(ctx context.Context, t *testing.T, paymentCreator kit2.TestFullNode, msgCid cid.Cid, duration time.Duration, desc string) *api.MsgLookup { ctx, cancel := context.WithTimeout(ctx, duration) defer cancel() From d2c35db0c923737af5dfff438c2f0503345eb6b5 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 15:51:10 +0200 Subject: [PATCH 20/72] refactor: convert tape test to kit2 --- itests/tape_test.go | 52 ++++++++------------------------------------- 1 file changed, 9 insertions(+), 43 deletions(-) diff --git a/itests/tape_test.go b/itests/tape_test.go index 5c0cadc3f4e..6fb3def15cf 100644 --- a/itests/tape_test.go +++ b/itests/tape_test.go @@ -2,7 +2,6 @@ package itests import ( "context" - "fmt" "testing" "time" @@ -11,24 +10,23 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/stmgr" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/node" - "github.com/filecoin-project/lotus/node/impl" "github.com/stretchr/testify/require" ) func TestTapeFix(t *testing.T) { - kit.QuietMiningLogs() + kit2.QuietMiningLogs() var blocktime = 2 * time.Millisecond // The "before" case is disabled, because we need the builder to mock 32 GiB sectors to accurately repro this case // TODO: Make the mock sector size configurable and reenable this // t.Run("before", func(t *testing.T) { testTapeFix(t, b, blocktime, false) }) - t.Run("after", func(t *testing.T) { testTapeFix(t, kit.MockMinerBuilder, blocktime, true) }) + t.Run("after", func(t *testing.T) { testTapeFix(t, blocktime, true) }) } -func testTapeFix(t *testing.T, b kit.APIBuilder, blocktime time.Duration, after bool) { +func testTapeFix(t *testing.T, blocktime time.Duration, after bool) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -44,46 +42,14 @@ func testTapeFix(t *testing.T, b kit.APIBuilder, blocktime time.Duration, after }) } - n, sn := b(t, []kit.FullNodeOpts{{Opts: func(_ []kit.TestFullNode) node.Option { - return node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule) - }}}, kit.OneMiner) - - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - build.Clock.Sleep(time.Second) - - done := make(chan struct{}) - go func() { - defer close(done) - for ctx.Err() == nil { - build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, kit.MineNext); err != nil { - if ctx.Err() != nil { - // context was canceled, ignore the error. - return - } - t.Error(err) - } - } - }() - defer func() { - cancel() - <-done - }() + nopts := kit2.ConstructorOpts(node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)) + _, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), nopts) + ens.InterconnectAll().BeginMining(blocktime) sid, err := miner.PledgeSector(ctx) require.NoError(t, err) - fmt.Printf("All sectors is fsm\n") + t.Log("All sectors is fsm") // If before, we expect the precommit to fail successState := api.SectorState(sealing.CommitFailed) @@ -101,6 +67,6 @@ func testTapeFix(t *testing.T, b kit.APIBuilder, blocktime time.Duration, after } require.NotEqual(t, failureState, st.State) build.Clock.Sleep(100 * time.Millisecond) - fmt.Println("WaitSeal") + t.Log("WaitSeal") } } From eb5a263d747706722c96328ff3d4e9005d154f30 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 16:19:20 +0200 Subject: [PATCH 21/72] refactor: convert verifreg test to kit2 --- itests/verifreg_test.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/itests/verifreg_test.go b/itests/verifreg_test.go index b3555cc0634..180a194a6b2 100644 --- a/itests/verifreg_test.go +++ b/itests/verifreg_test.go @@ -6,25 +6,29 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/network" - "github.com/filecoin-project/lotus/itests/kit" + verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" lapi "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" - "github.com/filecoin-project/lotus/node/impl" - verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" - - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/node/impl" ) func TestVerifiedClientTopUp(t *testing.T) { + blockTime := 100 * time.Millisecond + test := func(nv network.Version, shouldWork bool) func(*testing.T) { return func(t *testing.T) { - nodes, miners := kit.MockMinerBuilder(t, []kit.FullNodeOpts{kit.FullNodeWithNetworkUpgradeAt(nv, -1)}, kit.OneMiner) - api := nodes[0].FullNode.(*impl.FullNodeAPI) + nopts := kit2.ConstructorOpts(kit2.NetworkUpgradeAt(nv, -1)) + + node, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), nopts) + ens.InterconnectAll().BeginMining(blockTime) + + api := node.FullNode.(*impl.FullNodeAPI) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -52,10 +56,6 @@ func TestVerifiedClientTopUp(t *testing.T) { Value: big.Zero(), } - bm := kit.NewBlockMiner(t, miners[0]) - bm.MineBlocks(ctx, 100*time.Millisecond) - t.Cleanup(bm.Stop) - sm, err := api.MpoolPushMessage(ctx, msg, nil) if err != nil { t.Fatal("AddVerifier failed: ", err) From 6fb31a34b37423861fac44fae65f9dee08553481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 14 Jun 2021 18:58:12 +0100 Subject: [PATCH 22/72] start mining way more in the past. --- itests/kit2/ensemble.go | 5 ++--- itests/kit2/ensemble_opts.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/itests/kit2/ensemble.go b/itests/kit2/ensemble.go index 5d12c83e127..751066de36c 100644 --- a/itests/kit2/ensemble.go +++ b/itests/kit2/ensemble.go @@ -114,8 +114,7 @@ type Ensemble struct { } } -// NewEnsemble instantiates a new blank Ensemble. This enables you to -// programmatically +// NewEnsemble instantiates a new blank Ensemble. func NewEnsemble(t *testing.T, opts ...EnsembleOpt) *Ensemble { options := DefaultEnsembleOpts for _, o := range opts { @@ -593,7 +592,7 @@ func (n *Ensemble) generateGenesis() *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 + Timestamp: uint64(time.Now().Unix() - int64(n.options.pastOffset.Seconds())), VerifregRootKey: gen.DefaultVerifregRootkeyActor, RemainderAccount: gen.DefaultRemainderAccountActor, } diff --git a/itests/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go index 724113bdcde..a5a8c733fbc 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit2/ensemble_opts.go @@ -15,7 +15,7 @@ type ensembleOpts struct { } var DefaultEnsembleOpts = ensembleOpts{ - pastOffset: 10000 * time.Second, + pastOffset: 100000 * time.Second, // time sufficiently in the past to trigger catch-up mining. proofType: abi.RegisteredSealProof_StackedDrg2KiBV1, } From 8a7dba11bd4bc2d05797cc0cd928196748b29508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 14 Jun 2021 18:58:40 +0100 Subject: [PATCH 23/72] add comment. --- itests/kit2/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itests/kit2/log.go b/itests/kit2/log.go index 9b9a14d92bc..f255d063955 100644 --- a/itests/kit2/log.go +++ b/itests/kit2/log.go @@ -8,7 +8,7 @@ import ( func QuietMiningLogs() { lotuslog.SetupLogLevels() - _ = logging.SetLogLevel("miner", "ERROR") + _ = logging.SetLogLevel("miner", "ERROR") // set this to INFO to watch mining happen. _ = logging.SetLogLevel("chainstore", "ERROR") _ = logging.SetLogLevel("chain", "ERROR") _ = logging.SetLogLevel("sub", "ERROR") From dae8be0881c24da0144b5c82c144d08226159637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 14 Jun 2021 18:59:15 +0100 Subject: [PATCH 24/72] migrate to require; use t.Log* instead of fmt.Print*. --- itests/paych_api_test.go | 160 ++++++++++++--------------------------- 1 file changed, 48 insertions(+), 112 deletions(-) diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go index 900b3d092aa..3639d7b7137 100644 --- a/itests/paych_api_test.go +++ b/itests/paych_api_test.go @@ -2,13 +2,13 @@ package itests import ( "context" - "fmt" "testing" "time" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" cbor "github.com/ipfs/go-ipld-cbor" @@ -50,36 +50,26 @@ func TestPaymentChannelsAPI(t *testing.T) { // send some funds to register the receiver receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) kit2.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) // setup the payment channel createrAddr, err := paymentCreator.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) channelAmt := int64(7000) channelInfo, err := paymentCreator.PaychGet(ctx, createrAddr, receiverAddr, abi.NewTokenAmount(channelAmt)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) channel, err := paymentCreator.PaychGetWaitReady(ctx, channelInfo.WaitSentinel) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // allocate three lanes var lanes []uint64 for i := 0; i < 3; i++ { lane, err := paymentCreator.PaychAllocateLane(ctx, channel) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) lanes = append(lanes, lane) } @@ -88,45 +78,28 @@ func TestPaymentChannelsAPI(t *testing.T) { // supersedes the voucher with a value of 1000 for _, lane := range lanes { vouch1, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(1000), lane) - if err != nil { - t.Fatal(err) - } - if vouch1.Voucher == nil { - t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouch1.Shortfall)) - } + require.NoError(t, err) + require.NotNil(t, vouch1.Voucher, "Not enough funds to create voucher: missing %d", vouch1.Shortfall) + vouch2, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(2000), lane) - if err != nil { - t.Fatal(err) - } - if vouch2.Voucher == nil { - t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouch2.Shortfall)) - } + require.NoError(t, err) + require.NotNil(t, vouch2.Voucher, "Not enough funds to create voucher: missing %d", vouch2.Shortfall) + delta1, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch1.Voucher, nil, abi.NewTokenAmount(1000)) - if err != nil { - t.Fatal(err) - } - if !delta1.Equals(abi.NewTokenAmount(1000)) { - t.Fatal("voucher didn't have the right amount") - } + require.NoError(t, err) + require.EqualValues(t, abi.NewTokenAmount(1000), delta1, "voucher didn't have the right amount") + delta2, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch2.Voucher, nil, abi.NewTokenAmount(1000)) - if err != nil { - t.Fatal(err) - } - if !delta2.Equals(abi.NewTokenAmount(1000)) { - t.Fatal("voucher didn't have the right amount") - } + require.NoError(t, err) + require.EqualValues(t, abi.NewTokenAmount(1000), delta2, "voucher didn't have the right amount") } // settle the payment channel settleMsgCid, err := paymentCreator.PaychSettle(ctx, channel) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) res := waitForMessage(ctx, t, paymentCreator, settleMsgCid, time.Second*10, "settle") - if res.Receipt.ExitCode != 0 { - t.Fatal("Unable to settle payment channel") - } + require.EqualValues(t, 0, res.Receipt.ExitCode, "Unable to settle payment channel") creatorStore := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(paymentCreator))) @@ -163,9 +136,7 @@ func TestPaymentChannelsAPI(t *testing.T) { }, int(build.MessageConfidence)+1, build.Finality, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key()) }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) select { case <-finished: @@ -175,75 +146,49 @@ func TestPaymentChannelsAPI(t *testing.T) { // Create a new voucher now that some vouchers have already been submitted vouchRes, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(1000), 3) - if err != nil { - t.Fatal(err) - } - if vouchRes.Voucher == nil { - t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouchRes.Shortfall)) - } + require.NoError(t, err) + require.NotNil(t, vouchRes.Voucher, "Not enough funds to create voucher: missing %d", vouchRes.Shortfall) + vdelta, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouchRes.Voucher, nil, abi.NewTokenAmount(1000)) - if err != nil { - t.Fatal(err) - } - if !vdelta.Equals(abi.NewTokenAmount(1000)) { - t.Fatal("voucher didn't have the right amount") - } + require.NoError(t, err) + require.EqualValues(t, abi.NewTokenAmount(1000), vdelta, "voucher didn't have the right amount") // Create a new voucher whose value would exceed the channel balance excessAmt := abi.NewTokenAmount(1000) vouchRes, err = paymentCreator.PaychVoucherCreate(ctx, channel, excessAmt, 4) - if err != nil { - t.Fatal(err) - } - if vouchRes.Voucher != nil { - t.Fatal("Expected not to be able to create voucher whose value would exceed channel balance") - } - if !vouchRes.Shortfall.Equals(excessAmt) { - t.Fatal(fmt.Errorf("Expected voucher shortfall of %d, got %d", excessAmt, vouchRes.Shortfall)) - } + require.NoError(t, err) + require.Nil(t, vouchRes.Voucher, "Expected not to be able to create voucher whose value would exceed channel balance") + require.EqualValues(t, excessAmt, vouchRes.Shortfall, "Expected voucher shortfall of %d, got %d", excessAmt, vouchRes.Shortfall) // Add a voucher whose value would exceed the channel balance vouch := &paych.SignedVoucher{ChannelAddr: channel, Amount: excessAmt, Lane: 4, Nonce: 1} vb, err := vouch.SigningBytes() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) + sig, err := paymentCreator.WalletSign(ctx, createrAddr, vb) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) + vouch.Signature = sig _, err = paymentReceiver.PaychVoucherAdd(ctx, channel, vouch, nil, abi.NewTokenAmount(1000)) - if err == nil { - t.Fatal(fmt.Errorf("Expected shortfall error of %d", excessAmt)) - } + require.Errorf(t, err, "Expected shortfall error of %d", excessAmt) // wait for the settlement period to pass before collecting waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, policy.PaychSettleDelay) creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // collect funds (from receiver, though either party can do it) collectMsg, err := paymentReceiver.PaychCollect(ctx, channel) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) + res, err = paymentReceiver.StateWaitMsg(ctx, collectMsg, 3, api.LookbackNoLimit, true) - if err != nil { - t.Fatal(err) - } - if res.Receipt.ExitCode != 0 { - t.Fatal("unable to collect on payment channel") - } + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode, "unable to collect on payment channel") // Finally, check the balance for the creator currentCreatorBalance, err := paymentCreator.WalletBalance(ctx, createrAddr) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // The highest nonce voucher that the creator sent on each lane is 2000 totalVouchers := int64(len(lanes) * 2000) @@ -253,9 +198,7 @@ func TestPaymentChannelsAPI(t *testing.T) { // channel amount - total voucher value expectedRefund := channelAmt - totalVouchers delta := big.Sub(currentCreatorBalance, creatorPreCollectBalance) - if !delta.Equals(abi.NewTokenAmount(expectedRefund)) { - t.Fatalf("did not send correct funds from creator: expected %d, got %d", expectedRefund, delta) - } + require.EqualValues(t, abi.NewTokenAmount(expectedRefund), delta, "did not send correct funds from creator: expected %d, got %d", expectedRefund, delta) } func waitForBlocks(ctx context.Context, t *testing.T, bm *kit2.BlockMiner, paymentReceiver kit2.TestFullNode, receiverAddr address.Address, count int) { @@ -276,14 +219,10 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *kit2.BlockMiner, payme From: receiverAddr, Value: types.NewInt(0), }, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = paymentReceiver.StateWaitMsg(ctx, m.Cid(), 1, api.LookbackNoLimit, true) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } } @@ -291,15 +230,12 @@ func waitForMessage(ctx context.Context, t *testing.T, paymentCreator kit2.TestF ctx, cancel := context.WithTimeout(ctx, duration) defer cancel() - fmt.Println("Waiting for", desc) + t.Log("Waiting for", desc) + res, err := paymentCreator.StateWaitMsg(ctx, msgCid, 1, api.LookbackNoLimit, true) - if err != nil { - fmt.Println("Error waiting for", desc, err) - t.Fatal(err) - } - if res.Receipt.ExitCode != 0 { - t.Fatalf("did not successfully send %s", desc) - } - fmt.Println("Confirmed", desc) + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode, "did not successfully send %s", desc) + + t.Log("Confirmed", desc) return res } From 0bb5fffd881b8dde2661870020bd453d25c90cc3 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 08:09:14 +0200 Subject: [PATCH 25/72] refactor: clean up code --- itests/paych_api_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go index 3639d7b7137..8fb4cde0c09 100644 --- a/itests/paych_api_test.go +++ b/itests/paych_api_test.go @@ -38,14 +38,13 @@ func TestPaymentChannelsAPI(t *testing.T) { miner kit2.TestMiner ) - //n, sn := kit2.MockMinerBuilder(t, kit2.TwoFull, kit2.OneMiner) ens := kit2.NewEnsemble(t, kit2.MockProofs()). FullNode(&paymentCreator). FullNode(&paymentReceiver). Miner(&miner, &paymentCreator). Start(). InterconnectAll() - bms := ens.BeginMining(blockTime, &miner) + bms := ens.BeginMining(blockTime) bm := bms[0] // send some funds to register the receiver From c27f3deaddbd954ada56a227fe61244633f2bc67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 14 Jun 2021 18:58:12 +0100 Subject: [PATCH 26/72] start mining way more in the past. --- itests/kit2/ensemble.go | 5 ++--- itests/kit2/ensemble_opts.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/itests/kit2/ensemble.go b/itests/kit2/ensemble.go index 5d12c83e127..751066de36c 100644 --- a/itests/kit2/ensemble.go +++ b/itests/kit2/ensemble.go @@ -114,8 +114,7 @@ type Ensemble struct { } } -// NewEnsemble instantiates a new blank Ensemble. This enables you to -// programmatically +// NewEnsemble instantiates a new blank Ensemble. func NewEnsemble(t *testing.T, opts ...EnsembleOpt) *Ensemble { options := DefaultEnsembleOpts for _, o := range opts { @@ -593,7 +592,7 @@ func (n *Ensemble) generateGenesis() *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 + Timestamp: uint64(time.Now().Unix() - int64(n.options.pastOffset.Seconds())), VerifregRootKey: gen.DefaultVerifregRootkeyActor, RemainderAccount: gen.DefaultRemainderAccountActor, } diff --git a/itests/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go index 724113bdcde..a5a8c733fbc 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit2/ensemble_opts.go @@ -15,7 +15,7 @@ type ensembleOpts struct { } var DefaultEnsembleOpts = ensembleOpts{ - pastOffset: 10000 * time.Second, + pastOffset: 100000 * time.Second, // time sufficiently in the past to trigger catch-up mining. proofType: abi.RegisteredSealProof_StackedDrg2KiBV1, } From 803a3df6b46ed7eceecdbd08e92fe71c02be1af4 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 11:50:40 +0200 Subject: [PATCH 27/72] refactor: ccupgrade test --- itests/ccupgrade_test.go | 85 +++++++++++++++++++------------------ itests/kit2/node_opts_nv.go | 12 ++++-- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index 28abac171a7..d90169b705e 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -3,62 +3,67 @@ package itests import ( "context" "fmt" - "sync/atomic" "testing" "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" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/node/impl" ) func TestCCUpgrade(t *testing.T) { - kit.QuietMiningLogs() + kit2.QuietMiningLogs() for _, height := range []abi.ChainEpoch{ - -1, // before - 162, // while sealing - 530, // after upgrade deal - 5000, // after + -1, // before + //162, // while sealing + //530, // after upgrade deal + //5000, // after } { height := height // make linters happy by copying t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) { - runTestCCUpgrade(t, kit.MockMinerBuilder, 5*time.Millisecond, height) + runTestCCUpgrade(t, height) }) } } -func runTestCCUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) { +func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { ctx := context.Background() - n, sn := b(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(upgradeHeight)}, kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - time.Sleep(time.Second) - - mine := int64(1) - done := make(chan struct{}) - go func() { - defer close(done) - for atomic.LoadInt64(&mine) == 1 { - time.Sleep(blocktime) - if err := sn[0].MineOne(ctx, kit.MineNext); err != nil { - t.Error(err) - } - } - }() + blockTime := 5 * time.Millisecond + + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.LatestActorsAt(upgradeHeight)) + ens.InterconnectAll().BeginMining(blockTime) + + //b := kit.MockMinerBuilder + //n, sn := b(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(upgradeHeight)}, kit.OneMiner) + //client := n[0].FullNode.(*impl.FullNodeAPI) + //miner := sn[0] + + //addrinfo, err := client.NetAddrsListen(ctx) + //if err != nil { + // t.Fatal(err) + //} + // + //if err := miner.NetConnect(ctx, addrinfo); err != nil { + // t.Fatal(err) + //} + //time.Sleep(time.Second) + // + //mine := int64(1) + //done := make(chan struct{}) + //go func() { + // defer close(done) + // for atomic.LoadInt64(&mine) == 1 { + // time.Sleep(blocktime) + // if err := sn[0].MineOne(ctx, kit.MineNext); err != nil { + // t.Error(err) + // } + // } + //}() maddr, err := miner.ActorAddress(ctx) if err != nil { @@ -68,7 +73,7 @@ func runTestCCUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Duration, u CC := abi.SectorNumber(kit.GenesisPreseals + 1) Upgraded := CC + 1 - kit.PledgeSectors(t, ctx, miner, 1, 0, nil) + miner.PledgeSectors(ctx, 1, 0, nil) sl, err := miner.SectorsList(ctx) if err != nil { @@ -92,9 +97,9 @@ func runTestCCUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Duration, u t.Fatal(err) } - dh := kit.NewDealHarness(t, client, miner) + dh := kit2.NewDealHarness(t, client, miner) - dh.MakeFullDeal(context.Background(), 6, false, false, 0) + dh.MakeOnlineDeal(context.Background(), 6, false, 0) // Validate upgrade @@ -123,10 +128,6 @@ func runTestCCUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Duration, u } t.Log("waiting for sector to expire") // wait one deadline per loop. - time.Sleep(time.Duration(dlInfo.WPoStChallengeWindow) * blocktime) + time.Sleep(time.Duration(dlInfo.WPoStChallengeWindow) * blockTime) } - - fmt.Println("shutting down mining") - atomic.AddInt64(&mine, -1) - <-done } diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go index 05d2c2287d6..606e3a13f20 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit2/node_opts_nv.go @@ -7,12 +7,12 @@ import ( "github.com/filecoin-project/lotus/node" ) -func LatestActorsAt(upgradeHeight abi.ChainEpoch) node.Option { +func LatestActorsAt(upgradeHeight abi.ChainEpoch) NodeOpt { // Attention: Update this when introducing new actor versions or your tests will be sad return NetworkUpgradeAt(network.Version13, upgradeHeight) } -func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { +func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) NodeOpt { fullSchedule := stmgr.UpgradeSchedule{{ // prepare for upgrade. Network: network.Version9, @@ -45,7 +45,13 @@ func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) nod schedule[len(schedule)-1].Height = upgradeHeight } - return node.Override(new(stmgr.UpgradeSchedule), schedule) + return func(opts *nodeOpts) error { + opts.extraNodeOpts = []node.Option{ + node.Override(new(stmgr.UpgradeSchedule), schedule), + } + return nil + } + //return node.Override(new(stmgr.UpgradeSchedule), schedule) } func SDRUpgradeAt(calico, persian abi.ChainEpoch) node.Option { From 4cd0964ab17dbed1f532e88f1115dbbb195e779a Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 08:27:02 +0200 Subject: [PATCH 28/72] refactor: replace if err with require --- itests/ccupgrade_test.go | 53 +++++++--------------------------------- 1 file changed, 9 insertions(+), 44 deletions(-) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index d90169b705e..bdd37f50307 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -19,10 +19,10 @@ func TestCCUpgrade(t *testing.T) { kit2.QuietMiningLogs() for _, height := range []abi.ChainEpoch{ - -1, // before - //162, // while sealing - //530, // after upgrade deal - //5000, // after + -1, // before + 162, // while sealing + 530, // after upgrade deal + 5000, // after } { height := height // make linters happy by copying t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) { @@ -38,33 +38,6 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.LatestActorsAt(upgradeHeight)) ens.InterconnectAll().BeginMining(blockTime) - //b := kit.MockMinerBuilder - //n, sn := b(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(upgradeHeight)}, kit.OneMiner) - //client := n[0].FullNode.(*impl.FullNodeAPI) - //miner := sn[0] - - //addrinfo, err := client.NetAddrsListen(ctx) - //if err != nil { - // t.Fatal(err) - //} - // - //if err := miner.NetConnect(ctx, addrinfo); err != nil { - // t.Fatal(err) - //} - //time.Sleep(time.Second) - // - //mine := int64(1) - //done := make(chan struct{}) - //go func() { - // defer close(done) - // for atomic.LoadInt64(&mine) == 1 { - // time.Sleep(blocktime) - // if err := sn[0].MineOne(ctx, kit.MineNext); err != nil { - // t.Error(err) - // } - // } - //}() - maddr, err := miner.ActorAddress(ctx) if err != nil { t.Fatal(err) @@ -76,16 +49,9 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { miner.PledgeSectors(ctx, 1, 0, nil) sl, err := miner.SectorsList(ctx) - if err != nil { - t.Fatal(err) - } - if len(sl) != 1 { - t.Fatal("expected 1 sector") - } - - if sl[0] != CC { - t.Fatal("bad") - } + require.NoError(t, err) + require.Len(t, sl, 1, "expected 1 sector") + require.Equal(t, CC, sl[0], "unexpected sector number") { si, err := client.StateSectorGetInfo(ctx, maddr, CC, types.EmptyTSK) @@ -93,9 +59,8 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { require.Less(t, 50000, int(si.Expiration)) } - if err := miner.SectorMarkForUpgrade(ctx, sl[0]); err != nil { - t.Fatal(err) - } + err = miner.SectorMarkForUpgrade(ctx, sl[0]) + require.NoError(t, err) dh := kit2.NewDealHarness(t, client, miner) From 2d5b798763626198d19282b35b30166269b61724 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 14 Jun 2021 12:07:50 +0200 Subject: [PATCH 29/72] refactor: cli test with kit2 --- itests/cli_test.go | 13 ++-- itests/kit2/client.go | 146 +++++++++++++++++++++++++++++++++++++++++ itests/kit2/mockcli.go | 141 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 7 deletions(-) create mode 100644 itests/kit2/client.go create mode 100644 itests/kit2/mockcli.go diff --git a/itests/cli_test.go b/itests/cli_test.go index 10e2af15c8d..8436f189e65 100644 --- a/itests/cli_test.go +++ b/itests/cli_test.go @@ -1,22 +1,21 @@ package itests import ( - "context" "os" "testing" "time" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" ) // TestClient does a basic test to exercise the client CLI commands. func TestClient(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() - blocktime := 5 * time.Millisecond - ctx := context.Background() - clientNode, _ := kit.StartOneNodeOneMiner(ctx, t, blocktime) - kit.RunClientTest(t, cli.Commands, clientNode) + blockTime := 5 * time.Millisecond + client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + kit2.RunClientTest(t, cli.Commands, *client) } diff --git a/itests/kit2/client.go b/itests/kit2/client.go new file mode 100644 index 00000000000..247d208369b --- /dev/null +++ b/itests/kit2/client.go @@ -0,0 +1,146 @@ +package kit2 + +import ( + "context" + "fmt" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + "time" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/v2/actors/builtin" + "github.com/stretchr/testify/require" + lcli "github.com/urfave/cli/v2" +) + +// RunClientTest exercises some of the Client CLI commands +func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Create mock CLI + mockCLI := NewMockCLI(ctx, t, cmds) + clientCLI := mockCLI.Client(clientNode.ListenAddr) + + // Get the Miner address + addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) + require.NoError(t, err) + require.Len(t, addrs, 1) + + minerAddr := addrs[0] + fmt.Println("Miner:", minerAddr) + + // client query-ask + out := clientCLI.RunCmd("client", "query-ask", minerAddr.String()) + require.Regexp(t, regexp.MustCompile("Ask:"), out) + + // Create a deal (non-interactive) + // client deal --start-epoch= 1000000attofil + res, _, _, err := CreateImportFile(ctx, clientNode, 1, 0) + + require.NoError(t, err) + startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) + dataCid := res.Root + price := "1000000attofil" + duration := fmt.Sprintf("%d", build.MinDealDuration) + out = clientCLI.RunCmd("client", "deal", startEpoch, dataCid.String(), minerAddr.String(), price, duration) + fmt.Println("client deal", out) + + // Create a deal (interactive) + // client deal + // + // (in days) + // + // "no" (verified Client) + // "yes" (confirm deal) + res, _, _, err = CreateImportFile(ctx, clientNode, 2, 0) + require.NoError(t, err) + dataCid2 := res.Root + duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) + cmd := []string{"client", "deal"} + interactiveCmds := []string{ + dataCid2.String(), + duration, + minerAddr.String(), + "no", + "yes", + } + out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds) + fmt.Println("client deal:\n", out) + + // Wait for provider to start sealing deal + dealStatus := "" + for { + // client list-deals + out = clientCLI.RunCmd("client", "list-deals") + fmt.Println("list-deals:\n", out) + + lines := strings.Split(out, "\n") + require.GreaterOrEqual(t, len(lines), 2) + re := regexp.MustCompile(`\s+`) + parts := re.Split(lines[1], -1) + if len(parts) < 4 { + require.Fail(t, "bad list-deals output format") + } + dealStatus = parts[3] + fmt.Println(" Deal status:", dealStatus) + + st := CategorizeDealState(dealStatus) + require.NotEqual(t, TestDealStateFailed, st) + if st == TestDealStateComplete { + break + } + + time.Sleep(time.Second) + } + + // Retrieve the first file from the Miner + // client retrieve + tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client") + require.NoError(t, err) + path := filepath.Join(tmpdir, "outfile.dat") + out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) + fmt.Println("retrieve:\n", out) + require.Regexp(t, regexp.MustCompile("Success"), out) +} + +func CreateImportFile(ctx context.Context, client api.FullNode, rseed int, size int) (res *api.ImportRes, path string, data []byte, err error) { + data, path, err = createRandomFile(rseed, size) + if err != nil { + return nil, "", nil, err + } + + res, err = client.ClientImport(ctx, api.FileRef{Path: path}) + if err != nil { + return nil, "", nil, err + } + return res, path, data, nil +} + +func createRandomFile(rseed, size int) ([]byte, string, error) { + if size == 0 { + size = 1600 + } + data := make([]byte, size) + rand.New(rand.NewSource(int64(rseed))).Read(data) + + dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") + if err != nil { + return nil, "", err + } + + path := filepath.Join(dir, "sourcefile.dat") + err = ioutil.WriteFile(path, data, 0644) + if err != nil { + return nil, "", err + } + + return data, path, nil +} diff --git a/itests/kit2/mockcli.go b/itests/kit2/mockcli.go new file mode 100644 index 00000000000..592c9733379 --- /dev/null +++ b/itests/kit2/mockcli.go @@ -0,0 +1,141 @@ +package kit2 + +import ( + "bytes" + "context" + "flag" + "strings" + "testing" + + "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" + lcli "github.com/urfave/cli/v2" +) + +type MockCLI struct { + t *testing.T + cmds []*lcli.Command + cctx *lcli.Context + out *bytes.Buffer +} + +func NewMockCLI(ctx context.Context, t *testing.T, cmds []*lcli.Command) *MockCLI { + // Create a CLI App with an --api-url flag so that we can specify which node + // the command should be executed against + app := &lcli.App{ + Flags: []lcli.Flag{ + &lcli.StringFlag{ + Name: "api-url", + Hidden: true, + }, + }, + Commands: cmds, + } + + var out bytes.Buffer + app.Writer = &out + app.Setup() + + cctx := lcli.NewContext(app, &flag.FlagSet{}, nil) + cctx.Context = ctx + return &MockCLI{t: t, cmds: cmds, cctx: cctx, out: &out} +} + +func (c *MockCLI) Client(addr multiaddr.Multiaddr) *MockCLIClient { + return &MockCLIClient{t: c.t, cmds: c.cmds, addr: addr, cctx: c.cctx, out: c.out} +} + +// MockCLIClient runs commands against a particular node +type MockCLIClient struct { + t *testing.T + cmds []*lcli.Command + addr multiaddr.Multiaddr + cctx *lcli.Context + out *bytes.Buffer +} + +func (c *MockCLIClient) RunCmd(input ...string) string { + out, err := c.RunCmdRaw(input...) + require.NoError(c.t, err, "output:\n%s", out) + + return out +} + +// Given an input, find the corresponding command or sub-command. +// eg "paych add-funds" +func (c *MockCLIClient) cmdByNameSub(input []string) (*lcli.Command, []string) { + name := input[0] + for _, cmd := range c.cmds { + if cmd.Name == name { + return c.findSubcommand(cmd, input[1:]) + } + } + return nil, []string{} +} + +func (c *MockCLIClient) findSubcommand(cmd *lcli.Command, input []string) (*lcli.Command, []string) { + // If there are no sub-commands, return the current command + if len(cmd.Subcommands) == 0 { + return cmd, input + } + + // Check each sub-command for a match against the name + subName := input[0] + for _, subCmd := range cmd.Subcommands { + if subCmd.Name == subName { + // Found a match, recursively search for sub-commands + return c.findSubcommand(subCmd, input[1:]) + } + } + return nil, []string{} +} + +func (c *MockCLIClient) RunCmdRaw(input ...string) (string, error) { + cmd, input := c.cmdByNameSub(input) + if cmd == nil { + panic("Could not find command " + input[0] + " " + input[1]) + } + + // prepend --api-url= + apiFlag := "--api-url=" + c.addr.String() + input = append([]string{apiFlag}, input...) + + fs := c.flagSet(cmd) + err := fs.Parse(input) + require.NoError(c.t, err) + + err = cmd.Action(lcli.NewContext(c.cctx.App, fs, c.cctx)) + + // Get the output + str := strings.TrimSpace(c.out.String()) + c.out.Reset() + return str, err +} + +func (c *MockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { + // Apply app level flags (so we can process --api-url flag) + fs := &flag.FlagSet{} + for _, f := range c.cctx.App.Flags { + err := f.Apply(fs) + if err != nil { + c.t.Fatal(err) + } + } + // Apply command level flags + for _, f := range cmd.Flags { + err := f.Apply(fs) + if err != nil { + c.t.Fatal(err) + } + } + return fs +} + +func (c *MockCLIClient) RunInteractiveCmd(cmd []string, interactive []string) string { + c.toStdin(strings.Join(interactive, "\n") + "\n") + return c.RunCmd(cmd...) +} + +func (c *MockCLIClient) toStdin(s string) { + c.cctx.App.Metadata["stdin"] = bytes.NewBufferString(s) +} From 16cad0e01a2a7e1d43c54214d7d8239bcb450a4f Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 11:46:32 +0200 Subject: [PATCH 30/72] refactor: convert gateway tests to kit2 --- itests/gateway_test.go | 104 +++++++++++++++++---------------------- itests/kit2/ensemble.go | 5 ++ itests/kit2/funds.go | 2 +- itests/kit2/node_opts.go | 14 ++++++ itests/multisig_test.go | 2 +- 5 files changed, 65 insertions(+), 62 deletions(-) diff --git a/itests/gateway_test.go b/itests/gateway_test.go index 7f1b70f2d32..20b0add6a9c 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -9,7 +9,6 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/chain/stmgr" "github.com/stretchr/testify/require" "golang.org/x/xerrors" @@ -21,10 +20,11 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/cli" "github.com/filecoin-project/lotus/gateway" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/node" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" @@ -46,7 +46,7 @@ func init() { // node that is connected through a gateway to a full API node func TestGatewayWalletMsig(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -180,7 +180,7 @@ func TestGatewayWalletMsig(t *testing.T) { // on a lite node that is connected through a gateway to a full API node func TestGatewayMsigCLI(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -193,7 +193,7 @@ func TestGatewayMsigCLI(t *testing.T) { func TestGatewayDealFlow(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -205,26 +205,27 @@ func TestGatewayDealFlow(t *testing.T) { // so that the deal starts sealing in time dealStartEpoch := abi.ChainEpoch(2 << 12) - dh := kit.NewDealHarness(t, nodes.lite, nodes.miner) - dh.MakeFullDeal(ctx, 6, false, false, dealStartEpoch) + dh := kit2.NewDealHarness(t, &nodes.lite, &nodes.miner) + dealCid, res, _ := dh.MakeOnlineDeal(ctx, 6, false, dealStartEpoch) + dh.PerformRetrieval(ctx, dealCid, res.Root, false) } func TestGatewayCLIDealFlow(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) defer nodes.closer() - kit.RunClientTest(t, cli.Commands, nodes.lite) + kit2.RunClientTest(t, cli.Commands, nodes.lite) } type testNodes struct { - lite kit.TestFullNode - full kit.TestFullNode - miner kit.TestMiner + lite kit2.TestFullNode + full kit2.TestFullNode + miner kit2.TestMiner closer jsonrpc.ClientCloser } @@ -261,66 +262,49 @@ func startNodes( ) *testNodes { var closer jsonrpc.ClientCloser - // Create one miner and two full nodes. + var ( + full kit2.TestFullNode + lite kit2.TestFullNode + miner kit2.TestMiner + ) + + // - Create one full node and one lite node // - Put a gateway server in front of full node 1 // - Start full node 2 in lite mode // - Connect lite node -> gateway server -> full node - opts := append( - // Full node - kit.OneFull, - // Lite node - kit.FullNodeOpts{ - Lite: true, - Opts: func(nodes []kit.TestFullNode) node.Option { - fullNode := nodes[0] - - // Create a gateway server in front of the full node - gwapi := gateway.NewNode(fullNode, lookbackCap, stateWaitLookbackLimit) - handler, err := gateway.Handler(gwapi) - require.NoError(t, err) - - srv, _ := kit.CreateRPCServer(t, handler) - - // Create a gateway client API that connects to the gateway server - var gapi api.Gateway - gapi, closer, err = client.NewGatewayRPCV1(ctx, "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) - require.NoError(t, err) - - // Provide the gateway API to dependency injection - return node.Override(new(api.Gateway), gapi) - }, - }, - ) - n, sn := kit.RPCMockMinerBuilder(t, opts, kit.OneMiner) - full := n[0] - lite := n[1] - miner := sn[0] + var liteOptBuilder kit2.OptBuilder + liteOptBuilder = func(nodes []*kit2.TestFullNode) node.Option { + fullNode := nodes[0] - // Get the listener address for the full node - fullAddr, err := full.NetAddrsListen(ctx) - require.NoError(t, err) + // Create a gateway server in front of the full node + gwapi := gateway.NewNode(fullNode, lookbackCap, stateWaitLookbackLimit) + handler, err := gateway.Handler(gwapi) + require.NoError(t, err) - // Connect the miner and the full node - err = miner.NetConnect(ctx, fullAddr) - require.NoError(t, err) + srv, _ := kit2.CreateRPCServer(t, handler) - // Connect the miner and the lite node (so that the lite node can send - // data to the miner) - liteAddr, err := lite.NetAddrsListen(ctx) - require.NoError(t, err) - err = miner.NetConnect(ctx, liteAddr) - require.NoError(t, err) + // Create a gateway client API that connects to the gateway server + var gapi api.Gateway + gapi, closer, err = client.NewGatewayRPCV1(ctx, "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) + require.NoError(t, err) + + // Provide the gateway API to dependency injection + return node.Override(new(api.Gateway), gapi) + } - // Start mining blocks - bm := kit.NewBlockMiner(t, miner) - bm.MineBlocks(ctx, blocktime) - t.Cleanup(bm.Stop) + kit2.NewEnsemble(t, kit2.MockProofs()). + FullNode(&full). + FullNode(&lite, kit2.LiteNode(), kit2.ThroughRPC(), kit2.AddOptBuilder(liteOptBuilder)). + Miner(&miner, &full). + Start(). + InterconnectAll(). + BeginMining(blocktime) return &testNodes{lite: lite, full: full, miner: miner, closer: closer} } -func sendFunds(ctx context.Context, fromNode kit.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { +func sendFunds(ctx context.Context, fromNode kit2.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { msg := &types.Message{ From: fromAddr, To: toAddr, diff --git a/itests/kit2/ensemble.go b/itests/kit2/ensemble.go index 5d12c83e127..d74649c2649 100644 --- a/itests/kit2/ensemble.go +++ b/itests/kit2/ensemble.go @@ -279,6 +279,11 @@ func (n *Ensemble) Start() *Ensemble { ) } + // Call option builders, passing active nodes as the parameter + for _, bopt := range full.options.optBuilders { + opts = append(opts, bopt(n.active.fullnodes)) + } + // Construct the full node. stop, err := node.New(ctx, opts...) diff --git a/itests/kit2/funds.go b/itests/kit2/funds.go index da37ae2ba1b..fc4a6c29486 100644 --- a/itests/kit2/funds.go +++ b/itests/kit2/funds.go @@ -30,5 +30,5 @@ func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient res, err := sender.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) - require.Equal(t, 0, res.Receipt.ExitCode, "did not successfully send funds") + require.EqualValues(t, 0, res.Receipt.ExitCode, "did not successfully send funds") } diff --git a/itests/kit2/node_opts.go b/itests/kit2/node_opts.go index 59d5454df84..bba78262a98 100644 --- a/itests/kit2/node_opts.go +++ b/itests/kit2/node_opts.go @@ -23,6 +23,7 @@ type nodeOpts struct { rpc bool ownerKey *wallet.Key extraNodeOpts []node.Option + optBuilders []OptBuilder } // DefaultNodeOpts are the default options that will be applied to test nodes. @@ -31,6 +32,10 @@ var DefaultNodeOpts = nodeOpts{ sectors: DefaultPresealsPerBootstrapMiner, } +// OptBuilder is used to create an option after some other node is already +// active. Takes all active nodes as a parameter. +type OptBuilder func(activeNodes []*TestFullNode) node.Option + // NodeOpt is a functional option for test nodes. type NodeOpt func(opts *nodeOpts) error @@ -87,3 +92,12 @@ func ConstructorOpts(extra ...node.Option) NodeOpt { return nil } } + +// AddOptBuilder adds an OptionBuilder to a node. It is used to add Lotus node +// constructor options after some nodes are already active. +func AddOptBuilder(optBuilder OptBuilder) NodeOpt { + return func(opts *nodeOpts) error { + opts.optBuilders = append(opts.optBuilders, optBuilder) + return nil + } +} diff --git a/itests/multisig_test.go b/itests/multisig_test.go index cc2b38c30e2..f5df0be1adb 100644 --- a/itests/multisig_test.go +++ b/itests/multisig_test.go @@ -22,7 +22,7 @@ func TestMultisig(t *testing.T) { kit2.QuietMiningLogs() blockTime := 5 * time.Millisecond - client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) runMultisigTests(t, *client) From 5ce482b817befc252830ea80acd35cf269b7b977 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 13:53:41 +0200 Subject: [PATCH 31/72] refactor: change network upgrade NodeOption to node.Option --- itests/ccupgrade_test.go | 3 ++- itests/kit2/node_opts_nv.go | 12 +++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index bdd37f50307..050e6fac1ae 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -35,7 +35,8 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { ctx := context.Background() blockTime := 5 * time.Millisecond - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.LatestActorsAt(upgradeHeight)) + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(upgradeHeight)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) ens.InterconnectAll().BeginMining(blockTime) maddr, err := miner.ActorAddress(ctx) diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go index 606e3a13f20..05d2c2287d6 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit2/node_opts_nv.go @@ -7,12 +7,12 @@ import ( "github.com/filecoin-project/lotus/node" ) -func LatestActorsAt(upgradeHeight abi.ChainEpoch) NodeOpt { +func LatestActorsAt(upgradeHeight abi.ChainEpoch) node.Option { // Attention: Update this when introducing new actor versions or your tests will be sad return NetworkUpgradeAt(network.Version13, upgradeHeight) } -func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) NodeOpt { +func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { fullSchedule := stmgr.UpgradeSchedule{{ // prepare for upgrade. Network: network.Version9, @@ -45,13 +45,7 @@ func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) Nod schedule[len(schedule)-1].Height = upgradeHeight } - return func(opts *nodeOpts) error { - opts.extraNodeOpts = []node.Option{ - node.Override(new(stmgr.UpgradeSchedule), schedule), - } - return nil - } - //return node.Override(new(stmgr.UpgradeSchedule), schedule) + return node.Override(new(stmgr.UpgradeSchedule), schedule) } func SDRUpgradeAt(calico, persian abi.ChainEpoch) node.Option { From 2267d15a0f5bb907e9039ab1ecc56b490fe3b6d6 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 14:37:03 +0200 Subject: [PATCH 32/72] refactor: update paych cli tests to use kit2 --- itests/kit2/funds.go | 2 +- itests/paych_cli_test.go | 87 ++++++++++++++++++++++++++-------------- 2 files changed, 59 insertions(+), 30 deletions(-) diff --git a/itests/kit2/funds.go b/itests/kit2/funds.go index da37ae2ba1b..fc4a6c29486 100644 --- a/itests/kit2/funds.go +++ b/itests/kit2/funds.go @@ -30,5 +30,5 @@ func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient res, err := sender.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) - require.Equal(t, 0, res.Receipt.ExitCode, "did not successfully send funds") + require.EqualValues(t, 0, res.Receipt.ExitCode, "did not successfully send funds") } diff --git a/itests/paych_cli_test.go b/itests/paych_cli_test.go index 373b6f43bfd..2450828d3ed 100644 --- a/itests/paych_cli_test.go +++ b/itests/paych_cli_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -37,18 +37,19 @@ func init() { // commands func TestPaymentChannelsBasic(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := kit.StartTwoNodesOneMiner(ctx, t, blocktime) - paymentCreator := nodes[0] - paymentReceiver := nodes[1] - creatorAddr := addrs[0] - receiverAddr := addrs[1] + + var ( + paymentCreator kit2.TestFullNode + paymentReceiver kit2.TestFullNode + ) + creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) @@ -70,12 +71,16 @@ func TestPaymentChannelsBasic(t *testing.T) { // creator: paych settle creatorCLI.RunCmd("paych", "settle", chAddr.String()) + t.Log("wait for chain to reach settle height") + // Wait for the chain to reach the settle height chState := getPaychState(ctx, t, paymentReceiver, chAddr) sa, err := chState.SettlingAt() require.NoError(t, err) waitForHeight(ctx, t, paymentReceiver, sa) + t.Log("settle height reached") + // receiver: paych collect receiverCLI.RunCmd("paych", "collect", chAddr.String()) } @@ -89,17 +94,18 @@ type voucherSpec struct { // TestPaymentChannelStatus tests the payment channel status CLI command func TestPaymentChannelStatus(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := kit.StartTwoNodesOneMiner(ctx, t, blocktime) - paymentCreator := nodes[0] - creatorAddr := addrs[0] - receiverAddr := addrs[1] + var ( + paymentCreator kit2.TestFullNode + paymentReceiver kit2.TestFullNode + ) + creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych status-by-from-to @@ -168,18 +174,18 @@ func TestPaymentChannelStatus(t *testing.T) { // channel voucher commands func TestPaymentChannelVouchers(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := kit.StartTwoNodesOneMiner(ctx, t, blocktime) - paymentCreator := nodes[0] - paymentReceiver := nodes[1] - creatorAddr := addrs[0] - receiverAddr := addrs[1] + var ( + paymentCreator kit2.TestFullNode + paymentReceiver kit2.TestFullNode + ) + creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) @@ -300,17 +306,18 @@ func TestPaymentChannelVouchers(t *testing.T) { // is greater than what's left in the channel, voucher create fails func TestPaymentChannelVoucherCreateShortfall(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit.QuietMiningLogs() + kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := kit.StartTwoNodesOneMiner(ctx, t, blocktime) - paymentCreator := nodes[0] - creatorAddr := addrs[0] - receiverAddr := addrs[1] + var ( + paymentCreator kit2.TestFullNode + paymentReceiver kit2.TestFullNode + ) + creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych add-funds @@ -378,7 +385,7 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) { } // waitForHeight waits for the node to reach the given chain epoch -func waitForHeight(ctx context.Context, t *testing.T, node kit.TestFullNode, height abi.ChainEpoch) { +func waitForHeight(ctx context.Context, t *testing.T, node kit2.TestFullNode, height abi.ChainEpoch) { atHeight := make(chan struct{}) chainEvents := events.NewEvents(ctx, node) err := chainEvents.ChainAt(func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error { @@ -396,7 +403,7 @@ func waitForHeight(ctx context.Context, t *testing.T, node kit.TestFullNode, hei } // getPaychState gets the state of the payment channel with the given address -func getPaychState(ctx context.Context, t *testing.T, node kit.TestFullNode, chAddr address.Address) paych.State { +func getPaychState(ctx context.Context, t *testing.T, node kit2.TestFullNode, chAddr address.Address) paych.State { act, err := node.StateGetActor(ctx, chAddr, types.EmptyTSK) require.NoError(t, err) @@ -406,3 +413,25 @@ func getPaychState(ctx context.Context, t *testing.T, node kit.TestFullNode, chA return chState } + +func startPaychCreatorReceiverMiner(ctx context.Context, t *testing.T, paymentCreator *kit2.TestFullNode, paymentReceiver *kit2.TestFullNode, blocktime time.Duration) (address.Address, address.Address) { + var miner kit2.TestMiner + opts := kit2.ThroughRPC() + kit2.NewEnsemble(t, kit2.MockProofs()). + FullNode(paymentCreator, opts). + FullNode(paymentReceiver, opts). + Miner(&miner, paymentCreator). + Start(). + InterconnectAll(). + BeginMining(blocktime) + + // Send some funds to the second node + receiverAddr, err := paymentReceiver.WalletDefaultAddress(ctx) + require.NoError(t, err) + kit2.SendFunds(ctx, t, *paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) + + // Get the first node's address + creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx) + require.NoError(t, err) + return creatorAddr, receiverAddr +} From cd53942525799a473d2845d110413a9d67d41cc4 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 15:38:09 +0200 Subject: [PATCH 33/72] refactor: batch deal test to use kit2 --- itests/batch_deal_test.go | 69 ++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/itests/batch_deal_test.go b/itests/batch_deal_test.go index 9676dffcce3..9cc4d7ac130 100644 --- a/itests/batch_deal_test.go +++ b/itests/batch_deal_test.go @@ -10,16 +10,15 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/markets/storageadapter" "github.com/filecoin-project/lotus/node" - "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/stretchr/testify/require" ) func TestBatchDealInput(t *testing.T) { - kit.QuietMiningLogs() + kit2.QuietMiningLogs() var ( blockTime = 10 * time.Millisecond @@ -32,50 +31,40 @@ func TestBatchDealInput(t *testing.T) { run := func(piece, deals, expectSectors int) func(t *testing.T) { return func(t *testing.T) { + ctx := context.Background() + publishPeriod := 10 * time.Second maxDealsPerMsg := uint64(deals) // Set max deals per publish deals message to maxDealsPerMsg - minerDef := []kit.StorageMiner{{ - Full: 0, - Opts: node.Options( - node.Override( - new(*storageadapter.DealPublisher), - storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ - Period: publishPeriod, - MaxDealsPerMsg: maxDealsPerMsg, - })), - node.Override(new(dtypes.GetSealingConfigFunc), func() (dtypes.GetSealingConfigFunc, error) { - return func() (sealiface.Config, error) { - return sealiface.Config{ - MaxWaitDealsSectors: 2, - MaxSealingSectors: 1, - MaxSealingSectorsForDeals: 3, - AlwaysKeepUnsealedCopy: true, - WaitDealsDelay: time.Hour, - }, nil + opts := kit2.ConstructorOpts(node.Options( + node.Override( + new(*storageadapter.DealPublisher), + storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ + Period: publishPeriod, + MaxDealsPerMsg: maxDealsPerMsg, + })), + node.Override(new(dtypes.GetSealingConfigFunc), func() (dtypes.GetSealingConfigFunc, error) { + return func() (sealiface.Config, error) { + return sealiface.Config{ + MaxWaitDealsSectors: 2, + MaxSealingSectors: 1, + MaxSealingSectorsForDeals: 3, + AlwaysKeepUnsealedCopy: true, + WaitDealsDelay: time.Hour, }, nil - }), - ), - Preseal: kit.PresealGenesis, - }} - - // Create a connect client and miner node - n, sn := kit.MockMinerBuilder(t, kit.OneFull, minerDef) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - blockMiner := kit.ConnectAndStartMining(t, blockTime, miner, client) - t.Cleanup(blockMiner.Stop) - - dh := kit.NewDealHarness(t, client, miner) - ctx := context.Background() + }, nil + }), + )) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blockTime) + dh := kit2.NewDealHarness(t, client, miner) err := miner.MarketSetAsk(ctx, big.Zero(), big.Zero(), 200, 128, 32<<30) require.NoError(t, err) checkNoPadding := func() { - sl, err := sn[0].SectorsList(ctx) + sl, err := miner.SectorsList(ctx) require.NoError(t, err) sort.Slice(sl, func(i, j int) bool { @@ -83,7 +72,7 @@ func TestBatchDealInput(t *testing.T) { }) for _, snum := range sl { - si, err := sn[0].SectorsStatus(ctx, snum, false) + si, err := miner.SectorsStatus(ctx, snum, false) require.NoError(t, err) // fmt.Printf("S %d: %+v %s\n", snum, si.Deals, si.State) @@ -98,7 +87,7 @@ func TestBatchDealInput(t *testing.T) { // Starts a deal and waits until it's published runDealTillSeal := func(rseed int) { - res, _, _, err := kit.CreateImportFile(ctx, client, rseed, piece) + res, _, _, err := kit2.CreateImportFile(ctx, client, rseed, piece) require.NoError(t, err) deal := dh.StartDeal(ctx, res.Root, false, dealStartEpoch) @@ -122,7 +111,7 @@ func TestBatchDealInput(t *testing.T) { checkNoPadding() - sl, err := sn[0].SectorsList(ctx) + sl, err := miner.SectorsList(ctx) require.NoError(t, err) require.Equal(t, len(sl), expectSectors) } From cd903bec5e05f236109a79342f9929d3de4f11d9 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 15 Jun 2021 17:24:57 +0200 Subject: [PATCH 34/72] refactor: sdr upgrade test to use kit2 --- itests/sdr_upgrade_test.go | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/itests/sdr_upgrade_test.go b/itests/sdr_upgrade_test.go index dfb4284b9f1..008c2ce612d 100644 --- a/itests/sdr_upgrade_test.go +++ b/itests/sdr_upgrade_test.go @@ -10,15 +10,14 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" bminer "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/lotus/node/impl" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSDRUpgrade(t *testing.T) { - kit.QuietMiningLogs() + kit2.QuietMiningLogs() // oldDelay := policy.GetPreCommitChallengeDelay() // policy.SetPreCommitChallengeDelay(5) @@ -31,18 +30,10 @@ func TestSDRUpgrade(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := kit.MockMinerBuilder(t, []kit.FullNodeOpts{kit.FullNodeWithSDRAt(500, 1000)}, kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] + opts := kit2.ConstructorOpts(kit2.SDRUpgradeAt(500, 1000)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll() - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } build.Clock.Sleep(time.Second) pledge := make(chan struct{}) @@ -53,7 +44,7 @@ func TestSDRUpgrade(t *testing.T) { round := 0 for atomic.LoadInt64(&mine) != 0 { build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) { + if err := miner.MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) { }}); err != nil { t.Error(err) @@ -88,7 +79,7 @@ func TestSDRUpgrade(t *testing.T) { }() // before. - kit.PledgeSectors(t, ctx, miner, 9, 0, pledge) + miner.PledgeSectors(ctx, 9, 0, pledge) s, err := miner.SectorsList(ctx) require.NoError(t, err) From 4ea73b408867c63d61dd072e5fffdefe863f4c6b Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Wed, 16 Jun 2021 14:42:28 +0200 Subject: [PATCH 35/72] refactor: use genesis preseals from kit2 --- itests/ccupgrade_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index 050e6fac1ae..2c35b425db5 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -6,7 +6,6 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/kit2" "github.com/stretchr/testify/require" @@ -44,7 +43,7 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { t.Fatal(err) } - CC := abi.SectorNumber(kit.GenesisPreseals + 1) + CC := abi.SectorNumber(kit2.DefaultPresealsPerBootstrapMiner + 1) Upgraded := CC + 1 miner.PledgeSectors(ctx, 1, 0, nil) From d2ff0cd88ece6e67f3f0671f5a894cb1e545010c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 16 Jun 2021 18:11:34 +0100 Subject: [PATCH 36/72] fix verifreg test; add VerifierRootKey() and Account() ensemble opts. --- itests/kit2/ensemble.go | 30 ++++++++-- itests/kit2/ensemble_opts.go | 36 +++++++++++- itests/kit2/node_opts_nv.go | 64 ++++++++++++++------ itests/verifreg_test.go | 109 ++++++++++++++++++----------------- 4 files changed, 162 insertions(+), 77 deletions(-) diff --git a/itests/kit2/ensemble.go b/itests/kit2/ensemble.go index 5d12c83e127..a66dac1e392 100644 --- a/itests/kit2/ensemble.go +++ b/itests/kit2/ensemble.go @@ -13,6 +13,7 @@ import ( "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/v1api" @@ -122,7 +123,19 @@ func NewEnsemble(t *testing.T, opts ...EnsembleOpt) *Ensemble { err := o(&options) require.NoError(t, err) } - return &Ensemble{t: t, options: &options} + + n := &Ensemble{t: t, options: &options} + + // add accounts from ensemble options to genesis. + for _, acc := range options.accounts { + n.genesis.accounts = append(n.genesis.accounts, genesis.Actor{ + Type: genesis.TAccount, + Balance: acc.initialBalance, + Meta: (&genesis.AccountMeta{Owner: acc.key.Address}).ActorMeta(), + }) + } + + return n } // FullNode enrolls a new full node. @@ -135,8 +148,7 @@ func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { 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. + // create a key+address, 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) @@ -589,12 +601,22 @@ func (n *Ensemble) BeginMining(blocktime time.Duration, miners ...*TestMiner) [] } func (n *Ensemble) generateGenesis() *genesis.Template { + var verifRoot = gen.DefaultVerifregRootkeyActor + if k := n.options.verifiedRoot.key; k != nil { + verifRoot = genesis.Actor{ + Type: genesis.TAccount, + Balance: n.options.verifiedRoot.initialBalance, + Meta: (&genesis.AccountMeta{Owner: k.Address}).ActorMeta(), + } + } + templ := &genesis.Template{ + NetworkVersion: network.Version0, 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, + VerifregRootKey: verifRoot, RemainderAccount: gen.DefaultRemainderAccountActor, } diff --git a/itests/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go index 724113bdcde..5e49976eceb 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit2/ensemble_opts.go @@ -4,14 +4,22 @@ import ( "time" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/wallet" ) type EnsembleOpt func(opts *ensembleOpts) error +type genesisAccount struct { + key *wallet.Key + initialBalance abi.TokenAmount +} + type ensembleOpts struct { - pastOffset time.Duration - proofType abi.RegisteredSealProof - mockProofs bool + pastOffset time.Duration + proofType abi.RegisteredSealProof + verifiedRoot genesisAccount + accounts []genesisAccount + mockProofs bool } var DefaultEnsembleOpts = ensembleOpts{ @@ -33,3 +41,25 @@ func MockProofs() EnsembleOpt { return nil } } + +// VerifierRootKey specifies the key to be enlisted as the verified clients +// registry root, as well as the initial balance to be attributed during +// genesis. +func VerifierRootKey(key *wallet.Key, balance abi.TokenAmount) EnsembleOpt { + return func(opts *ensembleOpts) error { + opts.verifiedRoot.key = key + opts.verifiedRoot.initialBalance = balance + return nil + } +} + +// Account sets up an account at genesis with the specified key and balance. +func Account(key *wallet.Key, balance abi.TokenAmount) EnsembleOpt { + return func(opts *ensembleOpts) error { + opts.accounts = append(opts.accounts, genesisAccount{ + key: key, + initialBalance: balance, + }) + return nil + } +} diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go index 05d2c2287d6..6f682bd3ad3 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit2/node_opts_nv.go @@ -1,36 +1,64 @@ package kit2 import ( + "context" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node" + "github.com/ipfs/go-cid" ) +// DefaultTestUpgradeSchedule +var DefaultTestUpgradeSchedule = stmgr.UpgradeSchedule{{ + Network: network.Version9, + Height: 1, + Migration: stmgr.UpgradeActorsV2, +}, { + Network: network.Version10, + Height: 2, + Migration: stmgr.UpgradeActorsV3, +}, { + Network: network.Version12, + Height: 3, + Migration: stmgr.UpgradeActorsV4, +}, { + Network: network.Version13, + Height: 4, + Migration: stmgr.UpgradeActorsV5, +}} + func LatestActorsAt(upgradeHeight abi.ChainEpoch) node.Option { // Attention: Update this when introducing new actor versions or your tests will be sad return NetworkUpgradeAt(network.Version13, upgradeHeight) } +// InstantaneousNetworkVersion starts the network instantaneously at the +// specified version in height 1. +func InstantaneousNetworkVersion(version network.Version) node.Option { + // composes all migration functions + var mf stmgr.MigrationFunc = func(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, oldState cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (newState cid.Cid, err error) { + var state = oldState + for _, u := range DefaultTestUpgradeSchedule { + if u.Network > version { + break + } + state, err = u.Migration(ctx, sm, cache, cb, state, height, ts) + if err != nil { + return cid.Undef, err + } + } + return state, nil + } + return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{ + {Network: version, Height: 1, Migration: mf}, + }) +} + func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { - fullSchedule := 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: 3, - Migration: stmgr.UpgradeActorsV4, - }, { - Network: network.Version13, - Height: 4, - Migration: stmgr.UpgradeActorsV5, - }} + fullSchedule := stmgr.UpgradeSchedule{} schedule := stmgr.UpgradeSchedule{} for _, upgrade := range fullSchedule { diff --git a/itests/verifreg_test.go b/itests/verifreg_test.go index 180a194a6b2..b1e3bcfa4e5 100644 --- a/itests/verifreg_test.go +++ b/itests/verifreg_test.go @@ -2,13 +2,17 @@ package itests import ( "context" + "fmt" "strings" "testing" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/wallet" verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" + "github.com/stretchr/testify/require" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" @@ -23,101 +27,102 @@ func TestVerifiedClientTopUp(t *testing.T) { test := func(nv network.Version, shouldWork bool) func(*testing.T) { return func(t *testing.T) { - nopts := kit2.ConstructorOpts(kit2.NetworkUpgradeAt(nv, -1)) + rootKey, err := wallet.GenerateKey(types.KTSecp256k1) + require.NoError(t, err) + + verifierKey, err := wallet.GenerateKey(types.KTSecp256k1) + require.NoError(t, err) + + verifiedClientKey, err := wallet.GenerateKey(types.KTBLS) + require.NoError(t, err) + + bal, err := types.ParseFIL("100fil") + require.NoError(t, err) + + node, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), + kit2.VerifierRootKey(rootKey, abi.NewTokenAmount(bal.Int64())), + kit2.Account(verifierKey, abi.NewTokenAmount(bal.Int64())), // assign some balance to the verifier so they can send an AddClient message. + kit2.ConstructorOpts(kit2.InstantaneousNetworkVersion(nv))) - node, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), nopts) ens.InterconnectAll().BeginMining(blockTime) api := node.FullNode.(*impl.FullNodeAPI) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - //Get VRH + // get VRH vrh, err := api.StateVerifiedRegistryRootKey(ctx, types.TipSetKey{}) - if err != nil { - t.Fatal(err) - } + fmt.Println(vrh.String()) + require.NoError(t, err) - //Add verifier - verifier, err := api.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } + // import the root key. + rootAddr, err := api.WalletImport(ctx, &rootKey.KeyInfo) + require.NoError(t, err) + + // import the verifier's key. + verifierAddr, err := api.WalletImport(ctx, &verifierKey.KeyInfo) + require.NoError(t, err) + + // import the verified client's key. + verifiedClientAddr, err := api.WalletImport(ctx, &verifiedClientKey.KeyInfo) + require.NoError(t, err) + + params, err := actors.SerializeParams(&verifreg4.AddVerifierParams{Address: verifierAddr, Allowance: big.NewInt(100000000000)}) + require.NoError(t, err) - params, err := actors.SerializeParams(&verifreg4.AddVerifierParams{Address: verifier, Allowance: big.NewInt(100000000000)}) - if err != nil { - t.Fatal(err) - } msg := &types.Message{ + From: rootAddr, To: verifreg.Address, - From: vrh, Method: verifreg.Methods.AddVerifier, Params: params, Value: big.Zero(), } sm, err := api.MpoolPushMessage(ctx, msg, nil) - if err != nil { - t.Fatal("AddVerifier failed: ", err) - } + require.NoError(t, err, "AddVerifier failed") + 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") - } + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode) - //Assign datacap to a client + // assign datacap to a client datacap := big.NewInt(10000) - clientAddress, err := api.WalletNew(ctx, types.KTBLS) - if err != nil { - t.Fatal(err) - } - params, err = actors.SerializeParams(&verifreg4.AddVerifiedClientParams{Address: clientAddress, Allowance: datacap}) - if err != nil { - t.Fatal(err) - } + params, err = actors.SerializeParams(&verifreg4.AddVerifiedClientParams{Address: verifiedClientAddr, Allowance: datacap}) + require.NoError(t, err) msg = &types.Message{ + From: verifierAddr, To: verifreg.Address, - From: verifier, Method: verifreg.Methods.AddVerifiedClient, Params: params, Value: big.Zero(), } sm, err = api.MpoolPushMessage(ctx, msg, nil) - if err != nil { - t.Fatal("AddVerifiedClient faield: ", err) - } + require.NoError(t, 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") - } + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode) + + // check datacap balance + dcap, err := api.StateVerifiedClientStatus(ctx, verifiedClientAddr, types.EmptyTSK) + require.NoError(t, err) - //check datacap balance - dcap, err := api.StateVerifiedClientStatus(ctx, clientAddress, types.EmptyTSK) - if err != nil { - t.Fatal(err) - } if !dcap.Equals(datacap) { t.Fatal("") } - //try to assign datacap to the same client should fail for actor v4 and below - params, err = actors.SerializeParams(&verifreg4.AddVerifiedClientParams{Address: clientAddress, Allowance: datacap}) + // try to assign datacap to the same client should fail for actor v4 and below + params, err = actors.SerializeParams(&verifreg4.AddVerifiedClientParams{Address: verifiedClientAddr, Allowance: datacap}) if err != nil { t.Fatal(err) } msg = &types.Message{ + From: verifierAddr, To: verifreg.Address, - From: verifier, Method: verifreg.Methods.AddVerifiedClient, Params: params, Value: big.Zero(), From 8ed753a712a1a6d1591ca58c9d45c8db6fa28c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 16 Jun 2021 18:16:59 +0100 Subject: [PATCH 37/72] rename RootVerifier option. --- itests/kit2/ensemble_opts.go | 7 +++---- itests/verifreg_test.go | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/itests/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go index df7fdf41b6a..c7edb99a6a7 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit2/ensemble_opts.go @@ -42,10 +42,9 @@ func MockProofs() EnsembleOpt { } } -// VerifierRootKey specifies the key to be enlisted as the verified clients -// registry root, as well as the initial balance to be attributed during -// genesis. -func VerifierRootKey(key *wallet.Key, balance abi.TokenAmount) EnsembleOpt { +// RootVerifier specifies the key to be enlisted as the verified registry root, +// as well as the initial balance to be attributed during genesis. +func RootVerifier(key *wallet.Key, balance abi.TokenAmount) EnsembleOpt { return func(opts *ensembleOpts) error { opts.verifiedRoot.key = key opts.verifiedRoot.initialBalance = balance diff --git a/itests/verifreg_test.go b/itests/verifreg_test.go index b1e3bcfa4e5..108da6ecfe3 100644 --- a/itests/verifreg_test.go +++ b/itests/verifreg_test.go @@ -40,7 +40,7 @@ func TestVerifiedClientTopUp(t *testing.T) { require.NoError(t, err) node, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), - kit2.VerifierRootKey(rootKey, abi.NewTokenAmount(bal.Int64())), + kit2.RootVerifier(rootKey, abi.NewTokenAmount(bal.Int64())), kit2.Account(verifierKey, abi.NewTokenAmount(bal.Int64())), // assign some balance to the verifier so they can send an AddClient message. kit2.ConstructorOpts(kit2.InstantaneousNetworkVersion(nv))) From 8f608dff45370a955472312f71ae4701a6acf45a Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Thu, 17 Jun 2021 09:37:35 +0200 Subject: [PATCH 38/72] refactor: sector pledge test to use kit2 --- itests/kit2/node_opts_nv.go | 4 +- itests/sector_pledge_test.go | 188 ++++++++--------------------------- 2 files changed, 43 insertions(+), 149 deletions(-) diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go index 6f682bd3ad3..39de9d9e27d 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit2/node_opts_nv.go @@ -58,10 +58,8 @@ func InstantaneousNetworkVersion(version network.Version) node.Option { } func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { - fullSchedule := stmgr.UpgradeSchedule{} - schedule := stmgr.UpgradeSchedule{} - for _, upgrade := range fullSchedule { + for _, upgrade := range DefaultTestUpgradeSchedule { if upgrade.Network > version { break } diff --git a/itests/sector_pledge_test.go b/itests/sector_pledge_test.go index e3d2a843cf8..62daa1add18 100644 --- a/itests/sector_pledge_test.go +++ b/itests/sector_pledge_test.go @@ -4,70 +4,40 @@ import ( "context" "fmt" "strings" - "sync/atomic" "testing" "time" + "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/stmgr" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/itests/kit" - bminer "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/lotus/node" - "github.com/filecoin-project/lotus/node/impl" - "github.com/stretchr/testify/require" + "github.com/filecoin-project/lotus/itests/kit2" ) func TestPledgeSectors(t *testing.T) { - kit.QuietMiningLogs() + kit2.QuietMiningLogs() + + blockTime := 50 * time.Millisecond - runTest := func(t *testing.T, b kit.APIBuilder, blocktime time.Duration, nSectors int) { + runTest := func(t *testing.T, nSectors int) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, kit.OneFull, kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - build.Clock.Sleep(time.Second) - - mine := int64(1) - done := make(chan struct{}) - go func() { - defer close(done) - for atomic.LoadInt64(&mine) != 0 { - build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) { - - }}); err != nil { - t.Error(err) - } - } - }() - - kit.PledgeSectors(t, ctx, miner, nSectors, 0, nil) + _, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + ens.InterconnectAll().BeginMining(blockTime) - atomic.StoreInt64(&mine, 0) - <-done + miner.PledgeSectors(ctx, nSectors, 0, nil) } t.Run("1", func(t *testing.T) { - runTest(t, kit.MockMinerBuilder, 50*time.Millisecond, 1) + runTest(t, 1) }) t.Run("100", func(t *testing.T) { - runTest(t, kit.MockMinerBuilder, 50*time.Millisecond, 100) + runTest(t, 100) }) t.Run("1000", func(t *testing.T) { @@ -75,52 +45,24 @@ func TestPledgeSectors(t *testing.T) { t.Skip("skipping test in short mode") } - runTest(t, kit.MockMinerBuilder, 50*time.Millisecond, 1000) + runTest(t, 1000) }) } func TestPledgeBatching(t *testing.T) { - runTest := func(t *testing.T, b kit.APIBuilder, blocktime time.Duration, nSectors int) { + blockTime := 50 * time.Millisecond + + runTest := func(t *testing.T, nSectors int) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1)}, kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blockTime) - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } + waitTillChainHeight(ctx, t, client, 10) - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - build.Clock.Sleep(time.Second) - - mine := int64(1) - done := make(chan struct{}) - go func() { - defer close(done) - for atomic.LoadInt64(&mine) != 0 { - build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) { - - }}); err != nil { - t.Error(err) - } - } - }() - - for { - h, err := client.ChainHead(ctx) - require.NoError(t, err) - if h.Height() > 10 { - break - } - } - - toCheck := kit.StartPledge(t, ctx, miner, nSectors, 0, nil) + toCheck := miner.StartPledge(ctx, nSectors, 0, nil) for len(toCheck) > 0 { states := map[api.SectorState]int{} @@ -157,80 +99,27 @@ func TestPledgeBatching(t *testing.T) { build.Clock.Sleep(100 * time.Millisecond) fmt.Printf("WaitSeal: %d %+v\n", len(toCheck), states) } - - atomic.StoreInt64(&mine, 0) - <-done } t.Run("100", func(t *testing.T) { - runTest(t, kit.MockMinerBuilder, 50*time.Millisecond, 100) + runTest(t, 100) }) } func TestPledgeBeforeNv13(t *testing.T) { - runTest := func(t *testing.T, b kit.APIBuilder, blocktime time.Duration, nSectors int) { + blocktime := 50 * time.Millisecond + + runTest := func(t *testing.T, nSectors int) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, []kit.FullNodeOpts{ - { - Opts: func(nodes []kit.TestFullNode) node.Option { - return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ - Network: network.Version9, - Height: 1, - Migration: stmgr.UpgradeActorsV2, - }, { - Network: network.Version10, - Height: 2, - Migration: stmgr.UpgradeActorsV3, - }, { - Network: network.Version12, - Height: 3, - Migration: stmgr.UpgradeActorsV4, - }, { - Network: network.Version13, - Height: 1000000000, - Migration: stmgr.UpgradeActorsV5, - }}) - }, - }, - }, kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(1000000000)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blocktime) - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - build.Clock.Sleep(time.Second) - - mine := int64(1) - done := make(chan struct{}) - go func() { - defer close(done) - for atomic.LoadInt64(&mine) != 0 { - build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) { - - }}); err != nil { - t.Error(err) - } - } - }() + waitTillChainHeight(ctx, t, client, 10) - for { - h, err := client.ChainHead(ctx) - require.NoError(t, err) - if h.Height() > 10 { - break - } - } - - toCheck := kit.StartPledge(t, ctx, miner, nSectors, 0, nil) + toCheck := miner.StartPledge(ctx, nSectors, 0, nil) for len(toCheck) > 0 { states := map[api.SectorState]int{} @@ -250,12 +139,19 @@ func TestPledgeBeforeNv13(t *testing.T) { build.Clock.Sleep(100 * time.Millisecond) fmt.Printf("WaitSeal: %d %+v\n", len(toCheck), states) } - - atomic.StoreInt64(&mine, 0) - <-done } t.Run("100-before-nv13", func(t *testing.T) { - runTest(t, kit.MockMinerBuilder, 50*time.Millisecond, 100) + runTest(t, 100) }) } + +func waitTillChainHeight(ctx context.Context, t *testing.T, node *kit2.TestFullNode, height int) { + for { + h, err := node.ChainHead(ctx) + require.NoError(t, err) + if h.Height() > abi.ChainEpoch(height) { + return + } + } +} From 6567887e6e409c7a304da2e3bb445c808681adce Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Thu, 17 Jun 2021 10:40:41 +0200 Subject: [PATCH 39/72] refactor: sector terminate test to kit2 --- itests/kit2/chain.go | 21 ++++++++ itests/kit2/ensemble_opts.go | 2 +- itests/sector_pledge_test.go | 16 +----- itests/sector_terminate_test.go | 86 +++++++-------------------------- 4 files changed, 42 insertions(+), 83 deletions(-) create mode 100644 itests/kit2/chain.go diff --git a/itests/kit2/chain.go b/itests/kit2/chain.go new file mode 100644 index 00000000000..9563bae9fca --- /dev/null +++ b/itests/kit2/chain.go @@ -0,0 +1,21 @@ +package kit2 + +import ( + "context" + "testing" + "time" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/stretchr/testify/require" +) + +func WaitTillChainHeight(ctx context.Context, t *testing.T, node *TestFullNode, blocktime time.Duration, height int) abi.ChainEpoch { + for { + h, err := node.ChainHead(ctx) + require.NoError(t, err) + if h.Height() > abi.ChainEpoch(height) { + return h.Height() + } + time.Sleep(blocktime) + } +} diff --git a/itests/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go index c7edb99a6a7..f8bc8153511 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit2/ensemble_opts.go @@ -23,7 +23,7 @@ type ensembleOpts struct { } var DefaultEnsembleOpts = ensembleOpts{ - pastOffset: 100000 * time.Second, // time sufficiently in the past to trigger catch-up mining. + pastOffset: 10000000 * time.Second, // time sufficiently in the past to trigger catch-up mining. proofType: abi.RegisteredSealProof_StackedDrg2KiBV1, } diff --git a/itests/sector_pledge_test.go b/itests/sector_pledge_test.go index 62daa1add18..73fd2204e5e 100644 --- a/itests/sector_pledge_test.go +++ b/itests/sector_pledge_test.go @@ -9,8 +9,6 @@ import ( "github.com/stretchr/testify/require" - "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" @@ -60,7 +58,7 @@ func TestPledgeBatching(t *testing.T) { client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) ens.InterconnectAll().BeginMining(blockTime) - waitTillChainHeight(ctx, t, client, 10) + kit2.WaitTillChainHeight(ctx, t, client, blockTime, 10) toCheck := miner.StartPledge(ctx, nSectors, 0, nil) @@ -117,7 +115,7 @@ func TestPledgeBeforeNv13(t *testing.T) { client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) - waitTillChainHeight(ctx, t, client, 10) + kit2.WaitTillChainHeight(ctx, t, client, blocktime, 10) toCheck := miner.StartPledge(ctx, nSectors, 0, nil) @@ -145,13 +143,3 @@ func TestPledgeBeforeNv13(t *testing.T) { runTest(t, 100) }) } - -func waitTillChainHeight(ctx context.Context, t *testing.T, node *kit2.TestFullNode, height int) { - for { - h, err := node.ChainHead(ctx) - require.NoError(t, err) - if h.Height() > abi.ChainEpoch(height) { - return - } - } -} diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go index b00337c7e91..d1852ec3997 100644 --- a/itests/sector_terminate_test.go +++ b/itests/sector_terminate_test.go @@ -2,18 +2,15 @@ package itests import ( "context" - "fmt" "os" "testing" "time" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/node/impl" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/stretchr/testify/require" ) @@ -22,7 +19,7 @@ func TestTerminate(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() const blocktime = 2 * time.Millisecond @@ -31,42 +28,9 @@ func TestTerminate(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := kit.MockMinerBuilder(t, - []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1)}, - []kit.StorageMiner{{Full: 0, Preseal: int(nSectors)}}, - ) - - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - build.Clock.Sleep(time.Second) - - done := make(chan struct{}) - go func() { - defer close(done) - for ctx.Err() == nil { - build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, kit.MineNext); err != nil { - if ctx.Err() != nil { - // context was canceled, ignore the error. - return - } - t.Error(err) - } - } - }() - defer func() { - cancel() - <-done - }() + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) require.NoError(t, err) @@ -79,11 +43,11 @@ func TestTerminate(t *testing.T) { require.Equal(t, p.MinerPower, p.TotalPower) require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*nSectors)) - fmt.Printf("Seal a sector\n") + t.Log("Seal a sector") - kit.PledgeSectors(t, ctx, miner, 1, 0, nil) + miner.PledgeSectors(ctx, 1, 0, nil) - fmt.Printf("wait for power\n") + t.Log("wait for power") { // Wait until proven. @@ -91,17 +55,10 @@ func TestTerminate(t *testing.T) { require.NoError(t, err) waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 - fmt.Printf("End for head.Height > %d\n", waitUntil) + t.Logf("End for head.Height > %d", waitUntil) - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) - - if head.Height() > waitUntil { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - } + height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) } nSectors++ @@ -111,7 +68,7 @@ func TestTerminate(t *testing.T) { require.Equal(t, p.MinerPower, p.TotalPower) require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*nSectors)) - fmt.Println("Terminate a sector") + t.Log("Terminate a sector") toTerminate := abi.SectorNumber(3) @@ -124,7 +81,7 @@ loop: si, err := miner.SectorsStatus(ctx, toTerminate, false) require.NoError(t, err) - fmt.Println("state: ", si.State, msgTriggerred) + t.Log("state: ", si.State, msgTriggerred) switch sealing.SectorState(si.State) { case sealing.Terminating: @@ -140,7 +97,7 @@ loop: require.NoError(t, err) if c != nil { msgTriggerred = true - fmt.Println("terminate message:", c) + t.Log("terminate message:", c) { p, err := miner.SectorTerminatePending(ctx) @@ -180,18 +137,11 @@ loop: di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) - if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - build.Clock.Sleep(blocktime) - } - require.NoError(t, err) - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2) + waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 + t.Logf("End for head.Height > %d", waitUntil) + height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) From e9325fecc5c9f914ffb81751a45021d49dbf7212 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Thu, 17 Jun 2021 11:57:16 +0200 Subject: [PATCH 40/72] refactor: wdpost test to kit2 --- itests/wdpost_test.go | 155 ++++++++++++------------------------------ 1 file changed, 45 insertions(+), 110 deletions(-) diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index f59465f051b..317a7a5293a 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -7,18 +7,18 @@ import ( "testing" "time" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/itests/kit" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/extern/sector-storage/mock" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-storage/storage" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/extern/sector-storage/mock" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/node/impl" ) @@ -27,7 +27,7 @@ func TestWindowedPost(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() var ( blocktime = 2 * time.Millisecond @@ -41,50 +41,20 @@ func TestWindowedPost(t *testing.T) { } { height := height // copy to satisfy lints t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) { - testWindowPostUpgrade(t, kit.MockMinerBuilder, blocktime, nSectors, height) + testWindowPostUpgrade(t, blocktime, nSectors, height) }) } } -func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Duration, nSectors int, upgradeHeight abi.ChainEpoch) { +func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, upgradeHeight abi.ChainEpoch) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(upgradeHeight)}, kit.OneMiner) - - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(upgradeHeight)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blocktime) - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - build.Clock.Sleep(time.Second) - - done := make(chan struct{}) - go func() { - defer close(done) - for ctx.Err() == nil { - build.Clock.Sleep(blocktime) - if err := sn[0].MineOne(ctx, kit.MineNext); err != nil { - if ctx.Err() != nil { - // context was canceled, ignore the error. - return - } - t.Error(err) - } - } - }() - defer func() { - cancel() - <-done - }() - - kit.PledgeSectors(t, ctx, miner, nSectors, 0, nil) + miner.PledgeSectors(ctx, nSectors, 0, nil) maddr, err := miner.ActorAddress(ctx) require.NoError(t, err) @@ -95,19 +65,12 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati mid, err := address.IDFromAddress(maddr) require.NoError(t, err) - fmt.Printf("Running one proving period\n") - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2) - - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) + t.Log("Running one proving period") + waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 + t.Logf("End for head.Height > %d", waitUntil) - if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - build.Clock.Sleep(blocktime) - } + height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) @@ -116,9 +79,9 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati require.NoError(t, err) require.Equal(t, p.MinerPower, p.TotalPower) - require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+kit.GenesisPreseals))) + require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+kit2.DefaultPresealsPerBootstrapMiner))) - fmt.Printf("Drop some sectors\n") + t.Log("Drop some sectors") // Drop 2 sectors from deadline 2 partition 0 (full partition / deadline) { @@ -162,7 +125,7 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati all, err := secs.All(2) require.NoError(t, err) - fmt.Println("the sectors", all) + t.Log("the sectors", all) s = storage.SectorRef{ ID: abi.SectorID{ @@ -178,20 +141,12 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - fmt.Printf("Go through another PP, wait for sectors to become faulty\n") - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2) + t.Log("Go through another PP, wait for sectors to become faulty") + waitUntil = di.PeriodStart + di.WPoStProvingPeriod + 2 + t.Logf("End for head.Height > %d", waitUntil) - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) - - if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - - build.Clock.Sleep(blocktime) - } + height = kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) @@ -199,9 +154,9 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati require.Equal(t, p.MinerPower, p.TotalPower) sectors := p.MinerPower.RawBytePower.Uint64() / uint64(ssz) - require.Equal(t, nSectors+kit.GenesisPreseals-3, int(sectors)) // -3 just removed sectors + require.Equal(t, nSectors+kit2.DefaultPresealsPerBootstrapMiner-3, int(sectors)) // -3 just removed sectors - fmt.Printf("Recover one sector\n") + t.Log("Recover one sector") err = miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(s, false) require.NoError(t, err) @@ -209,19 +164,11 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2) + waitUntil = di.PeriodStart + di.WPoStProvingPeriod + 2 + t.Logf("End for head.Height > %d", waitUntil) - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) - - if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - - build.Clock.Sleep(blocktime) - } + height = kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) @@ -229,11 +176,11 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati require.Equal(t, p.MinerPower, p.TotalPower) sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz) - require.Equal(t, nSectors+kit.GenesisPreseals-2, int(sectors)) // -2 not recovered sectors + require.Equal(t, nSectors+kit2.DefaultPresealsPerBootstrapMiner-2, int(sectors)) // -2 not recovered sectors // pledge a sector after recovery - kit.PledgeSectors(t, ctx, miner, 1, nSectors, nil) + miner.PledgeSectors(ctx, 1, nSectors, nil) { // Wait until proven. @@ -241,17 +188,10 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati require.NoError(t, err) waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 - fmt.Printf("End for head.Height > %d\n", waitUntil) + t.Logf("End for head.Height > %d\n", waitUntil) - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) - - if head.Height() > waitUntil { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - } + height = kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) } p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) @@ -260,7 +200,7 @@ func testWindowPostUpgrade(t *testing.T, b kit.APIBuilder, blocktime time.Durati require.Equal(t, p.MinerPower, p.TotalPower) sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz) - require.Equal(t, nSectors+kit.GenesisPreseals-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged + require.Equal(t, nSectors+kit2.DefaultPresealsPerBootstrapMiner-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged } func TestWindowPostBaseFeeNoBurn(t *testing.T) { @@ -268,7 +208,7 @@ func TestWindowPostBaseFeeNoBurn(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() var ( blocktime = 2 * time.Millisecond @@ -281,11 +221,8 @@ func TestWindowPostBaseFeeNoBurn(t *testing.T) { och := build.UpgradeClausHeight build.UpgradeClausHeight = 10 - n, sn := kit.MockMinerBuilder(t, kit.DefaultFullOpts(1), kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - bm := kit.ConnectAndStartMining(t, blocktime, miner, client) - t.Cleanup(bm.Stop) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) require.NoError(t, err) @@ -293,7 +230,7 @@ func TestWindowPostBaseFeeNoBurn(t *testing.T) { mi, err := client.StateMinerInfo(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - kit.PledgeSectors(t, ctx, miner, nSectors, 0, nil) + miner.PledgeSectors(ctx, nSectors, 0, nil) wact, err := client.StateGetActor(ctx, mi.Worker, types.EmptyTSK) require.NoError(t, err) en := wact.Nonce @@ -327,18 +264,16 @@ func TestWindowPostBaseFeeBurn(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() ctx, cancel := context.WithCancel(context.Background()) defer cancel() blocktime := 2 * time.Millisecond - n, sn := kit.MockMinerBuilder(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1)}, kit.OneMiner) - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - bm := kit.ConnectAndStartMining(t, blocktime, miner, client) - t.Cleanup(bm.Stop) + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) require.NoError(t, err) @@ -346,7 +281,7 @@ func TestWindowPostBaseFeeBurn(t *testing.T) { mi, err := client.StateMinerInfo(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - kit.PledgeSectors(t, ctx, miner, 10, 0, nil) + miner.PledgeSectors(ctx, 10, 0, nil) wact, err := client.StateGetActor(ctx, mi.Worker, types.EmptyTSK) require.NoError(t, err) en := wact.Nonce From 3de6beabe3fee146de2e06eb795f911b577a8417 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Thu, 17 Jun 2021 14:22:13 +0200 Subject: [PATCH 41/72] refactor: wdpost dispute test to use kit2 --- itests/wdpost_dispute_test.go | 140 +++++++++------------------------- 1 file changed, 37 insertions(+), 103 deletions(-) diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index 6c7302af3d0..8661fba00a9 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -2,7 +2,6 @@ package itests import ( "context" - "fmt" "os" "testing" "time" @@ -16,8 +15,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors" minerActor "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/node/impl" + "github.com/filecoin-project/lotus/itests/kit2" proof3 "github.com/filecoin-project/specs-actors/v3/actors/runtime/proof" "github.com/stretchr/testify/require" ) @@ -27,28 +25,29 @@ func TestWindowPostDispute(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() - b := kit.MockMinerBuilder blocktime := 2 * time.Millisecond ctx, cancel := context.WithCancel(context.Background()) defer cancel() + var ( + client kit2.TestFullNode + chainMiner kit2.TestMiner + evilMiner kit2.TestMiner + ) + // First, we configure two miners. After sealing, we're going to turn off the first miner so // it doesn't submit proofs. // // Then we're going to manually submit bad proofs. - n, sn := b(t, - []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1)}, - []kit.StorageMiner{ - {Full: 0, Preseal: kit.PresealGenesis}, - {Full: 0}, - }) - - client := n[0].FullNode.(*impl.FullNodeAPI) - chainMiner := sn[0] - evilMiner := sn[1] + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) + ens := kit2.NewEnsemble(t, kit2.MockProofs()). + FullNode(&client, opts). + Miner(&chainMiner, &client, opts). + Miner(&evilMiner, &client, opts, kit2.PresealSectors(0)). + Start() { addrinfo, err := client.NetAddrsListen(ctx) @@ -68,32 +67,13 @@ func TestWindowPostDispute(t *testing.T) { defaultFrom, err := client.WalletDefaultAddress(ctx) require.NoError(t, err) - build.Clock.Sleep(time.Second) - // Mine with the _second_ node (the good one). - done := make(chan struct{}) - go func() { - defer close(done) - for ctx.Err() == nil { - build.Clock.Sleep(blocktime) - if err := chainMiner.MineOne(ctx, kit.MineNext); err != nil { - if ctx.Err() != nil { - // context was canceled, ignore the error. - return - } - t.Error(err) - } - } - }() - defer func() { - cancel() - <-done - }() + ens.BeginMining(blocktime, &chainMiner) // Give the chain miner enough sectors to win every block. - kit.PledgeSectors(t, ctx, chainMiner, 10, 0, nil) + chainMiner.PledgeSectors(ctx, 10, 0, nil) // And the evil one 1 sector. No cookie for you. - kit.PledgeSectors(t, ctx, evilMiner, 1, 0, nil) + evilMiner.PledgeSectors(ctx, 1, 0, nil) // Let the evil miner's sectors gain power. evilMinerAddr, err := evilMiner.ActorAddress(ctx) @@ -102,19 +82,13 @@ func TestWindowPostDispute(t *testing.T) { di, err := client.StateMinerProvingDeadline(ctx, evilMinerAddr, types.EmptyTSK) require.NoError(t, err) - fmt.Printf("Running one proving period\n") - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod*2) + t.Logf("Running one proving period\n") - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) + waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 + t.Logf("End for head.Height > %d", waitUntil) - if head.Height() > di.PeriodStart+di.WPoStProvingPeriod*2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - build.Clock.Sleep(blocktime) - } + height := kit2.WaitTillChainHeight(ctx, t, &client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) p, err := client.StateMinerPower(ctx, evilMinerAddr, types.EmptyTSK) require.NoError(t, err) @@ -131,12 +105,12 @@ func TestWindowPostDispute(t *testing.T) { evilSectorLoc, err := client.StateSectorPartition(ctx, evilMinerAddr, evilSectorNo, types.EmptyTSK) require.NoError(t, err) - fmt.Println("evil miner stopping") + t.Log("evil miner stopping") // Now stop the evil miner, and start manually submitting bad proofs. require.NoError(t, evilMiner.Stop(ctx)) - fmt.Println("evil miner stopped") + t.Log("evil miner stopped") // Wait until we need to prove our sector. for { @@ -161,7 +135,7 @@ func TestWindowPostDispute(t *testing.T) { build.Clock.Sleep(blocktime) } - fmt.Println("accepted evil proof") + t.Log("accepted evil proof") // Make sure the evil node didn't lose any power. p, err = client.StateMinerPower(ctx, evilMinerAddr, types.EmptyTSK) @@ -188,7 +162,7 @@ func TestWindowPostDispute(t *testing.T) { sm, err := client.MpoolPushMessage(ctx, msg, nil) require.NoError(t, err) - fmt.Println("waiting dispute") + t.Log("waiting dispute") rec, err := client.StateWaitMsg(ctx, sm.Cid(), build.MessageConfidence, api.LookbackNoLimit, true) require.NoError(t, err) require.Zero(t, rec.Receipt.ExitCode, "dispute not accepted: %s", rec.Receipt.ExitCode.Error()) @@ -258,29 +232,16 @@ func TestWindowPostDisputeFails(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit.QuietMiningLogs() + kit2.QuietMiningLogs() - b := kit.MockMinerBuilder blocktime := 2 * time.Millisecond ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1)}, kit.OneMiner) - - client := n[0].FullNode.(*impl.FullNodeAPI) - miner := sn[0] - - { - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - } + opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) + client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + ens.InterconnectAll().BeginMining(blocktime) defaultFrom, err := client.WalletDefaultAddress(ctx) require.NoError(t, err) @@ -290,48 +251,21 @@ func TestWindowPostDisputeFails(t *testing.T) { build.Clock.Sleep(time.Second) - // Mine with the _second_ node (the good one). - done := make(chan struct{}) - go func() { - defer close(done) - for ctx.Err() == nil { - build.Clock.Sleep(blocktime) - if err := miner.MineOne(ctx, kit.MineNext); err != nil { - if ctx.Err() != nil { - // context was canceled, ignore the error. - return - } - t.Error(err) - } - } - }() - defer func() { - cancel() - <-done - }() - - kit.PledgeSectors(t, ctx, miner, 10, 0, nil) + miner.PledgeSectors(ctx, 10, 0, nil) di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - fmt.Printf("Running one proving period\n") - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod*2) - - for { - head, err := client.ChainHead(ctx) - require.NoError(t, err) + t.Log("Running one proving period") + waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 + t.Logf("End for head.Height > %d", waitUntil) - if head.Height() > di.PeriodStart+di.WPoStProvingPeriod*2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) - break - } - build.Clock.Sleep(blocktime) - } + height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) + t.Logf("Now head.Height = %d", height) ssz, err := miner.ActorSectorSize(ctx, maddr) require.NoError(t, err) - expectedPower := types.NewInt(uint64(ssz) * (kit.GenesisPreseals + 10)) + expectedPower := types.NewInt(uint64(ssz) * (kit2.DefaultPresealsPerBootstrapMiner + 10)) p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) From 7a9769b8078b4c3994ff23b95a91f0cd3c851bde Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Thu, 17 Jun 2021 14:58:35 +0200 Subject: [PATCH 42/72] refactor: deadline toggling test to kit2 --- itests/deadlines_test.go | 95 +++++++++++++++---------------------- itests/kit2/node_opts.go | 2 + itests/kit2/node_opts_nv.go | 4 +- 3 files changed, 42 insertions(+), 59 deletions(-) diff --git a/itests/deadlines_test.go b/itests/deadlines_test.go index 9551465a509..7b75eebbdb8 100644 --- a/itests/deadlines_test.go +++ b/itests/deadlines_test.go @@ -3,7 +3,6 @@ package itests import ( "bytes" "context" - "fmt" "os" "testing" "time" @@ -22,7 +21,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/node/impl" miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" "github.com/ipfs/go-cid" @@ -75,21 +74,26 @@ func TestDeadlineToggling(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := kit.MockMinerBuilder(t, []kit.FullNodeOpts{kit.FullNodeWithNetworkUpgradeAt(network.Version12, upgradeH)}, kit.OneMiner) - - client := n[0].FullNode.(*impl.FullNodeAPI) - minerA := sn[0] - - { - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := minerA.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - } + var ( + client kit2.TestFullNode + minerA kit2.TestMiner + minerB kit2.TestMiner + minerC kit2.TestMiner + minerD kit2.TestMiner + minerE kit2.TestMiner + ) + opts := []kit2.NodeOpt{kit2.ConstructorOpts(kit2.NetworkUpgradeAt(network.Version12, upgradeH))} + ens := kit2.NewEnsemble(t, kit2.MockProofs()). + FullNode(&client, opts...). + Miner(&minerA, &client, opts...). + Start(). + InterconnectAll() + ens.BeginMining(blocktime) + + opts = append(opts, kit2.OwnerAddr(client.DefaultKey)) + ens.Miner(&minerB, &client, opts...). + Miner(&minerC, &client, opts...). + Start() defaultFrom, err := client.WalletDefaultAddress(ctx) require.NoError(t, err) @@ -99,28 +103,6 @@ func TestDeadlineToggling(t *testing.T) { build.Clock.Sleep(time.Second) - done := make(chan struct{}) - go func() { - defer close(done) - for ctx.Err() == nil { - build.Clock.Sleep(blocktime) - if err := minerA.MineOne(ctx, kit.MineNext); err != nil { - if ctx.Err() != nil { - // context was canceled, ignore the error. - return - } - t.Error(err) - } - } - }() - defer func() { - cancel() - <-done - }() - - minerB := n[0].Stb(ctx, t, kit.TestSpt, defaultFrom) - minerC := n[0].Stb(ctx, t, kit.TestSpt, defaultFrom) - maddrB, err := minerB.ActorAddress(ctx) require.NoError(t, err) maddrC, err := minerC.ActorAddress(ctx) @@ -131,20 +113,20 @@ func TestDeadlineToggling(t *testing.T) { // pledge sectors on C, go through a PP, check for power { - kit.PledgeSectors(t, ctx, minerC, sectorsC, 0, nil) + minerC.PledgeSectors(ctx, sectorsC, 0, nil) di, err := client.StateMinerProvingDeadline(ctx, maddrC, types.EmptyTSK) require.NoError(t, err) - fmt.Printf("Running one proving period (miner C)\n") - fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod*2) + t.Log("Running one proving period (miner C)") + t.Logf("End for head.Height > %d", di.PeriodStart+di.WPoStProvingPeriod*2) for { head, err := client.ChainHead(ctx) require.NoError(t, err) if head.Height() > di.PeriodStart+provingPeriod*2 { - fmt.Printf("Now head.Height = %d\n", head.Height()) + t.Logf("Now head.Height = %d", head.Height()) break } build.Clock.Sleep(blocktime) @@ -165,7 +147,7 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) if head.Height() > upgradeH+provingPeriod { - fmt.Printf("Now head.Height = %d\n", head.Height()) + t.Logf("Now head.Height = %d", head.Height()) break } build.Clock.Sleep(blocktime) @@ -216,8 +198,9 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) require.GreaterOrEqual(t, nv, network.Version12) - minerD := n[0].Stb(ctx, t, kit.TestSpt, defaultFrom) - minerE := n[0].Stb(ctx, t, kit.TestSpt, defaultFrom) + ens.Miner(&minerD, &client, opts...). + Miner(&minerE, &client, opts...). + Start() maddrD, err := minerD.ActorAddress(ctx) require.NoError(t, err) @@ -225,7 +208,7 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) // first round of miner checks - checkMiner(maddrA, types.NewInt(uint64(ssz)*kit.GenesisPreseals), true, true, types.EmptyTSK) + checkMiner(maddrA, types.NewInt(uint64(ssz)*kit2.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) checkMiner(maddrC, types.NewInt(uint64(ssz)*sectorsC), true, true, types.EmptyTSK) checkMiner(maddrB, types.NewInt(0), false, false, types.EmptyTSK) @@ -233,10 +216,10 @@ func TestDeadlineToggling(t *testing.T) { checkMiner(maddrE, types.NewInt(0), false, false, types.EmptyTSK) // pledge sectors on minerB/minerD, stop post on minerC - kit.PledgeSectors(t, ctx, minerB, sectorsB, 0, nil) + minerB.PledgeSectors(ctx, sectorsB, 0, nil) checkMiner(maddrB, types.NewInt(0), true, true, types.EmptyTSK) - kit.PledgeSectors(t, ctx, minerD, sectorsD, 0, nil) + minerD.PledgeSectors(ctx, sectorsD, 0, nil) checkMiner(maddrD, types.NewInt(0), true, true, types.EmptyTSK) minerC.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).Fail() @@ -252,7 +235,7 @@ func TestDeadlineToggling(t *testing.T) { params := &miner.SectorPreCommitInfo{ Expiration: 2880 * 300, SectorNumber: 22, - SealProof: kit.TestSpt, + SealProof: kit2.TestSpt, SealedCID: cr, SealRandEpoch: head.Height() - 200, @@ -281,7 +264,7 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) if head.Height() > upgradeH+provingPeriod+(provingPeriod/2) { - fmt.Printf("Now head.Height = %d\n", head.Height()) + t.Logf("Now head.Height = %d", head.Height()) break } build.Clock.Sleep(blocktime) @@ -295,14 +278,14 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) if head.Height() > upgradeH+(provingPeriod*3) { - fmt.Printf("Now head.Height = %d\n", head.Height()) + t.Logf("Now head.Height = %d", head.Height()) break } build.Clock.Sleep(blocktime) } // second round of miner checks - checkMiner(maddrA, types.NewInt(uint64(ssz)*kit.GenesisPreseals), true, true, types.EmptyTSK) + checkMiner(maddrA, types.NewInt(uint64(ssz)*kit2.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) checkMiner(maddrC, types.NewInt(0), true, true, types.EmptyTSK) checkMiner(maddrB, types.NewInt(uint64(ssz)*sectorsB), true, true, types.EmptyTSK) checkMiner(maddrD, types.NewInt(uint64(ssz)*sectorsD), true, true, types.EmptyTSK) @@ -351,7 +334,7 @@ func TestDeadlineToggling(t *testing.T) { }, nil) require.NoError(t, err) - fmt.Println("sent termination message:", smsg.Cid()) + t.Log("sent termination message:", smsg.Cid()) r, err := client.StateWaitMsg(ctx, smsg.Cid(), 2, api.LookbackNoLimit, true) require.NoError(t, err) @@ -367,13 +350,13 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) if head.Height() > upgradeH+(provingPeriod*5) { - fmt.Printf("Now head.Height = %d\n", head.Height()) + t.Logf("Now head.Height = %d", head.Height()) break } build.Clock.Sleep(blocktime) } - checkMiner(maddrA, types.NewInt(uint64(ssz)*kit.GenesisPreseals), true, true, types.EmptyTSK) + checkMiner(maddrA, types.NewInt(uint64(ssz)*kit2.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) checkMiner(maddrC, types.NewInt(0), true, true, types.EmptyTSK) checkMiner(maddrB, types.NewInt(0), true, true, types.EmptyTSK) checkMiner(maddrD, types.NewInt(0), false, false, types.EmptyTSK) diff --git a/itests/kit2/node_opts.go b/itests/kit2/node_opts.go index 59d5454df84..39c6cb80938 100644 --- a/itests/kit2/node_opts.go +++ b/itests/kit2/node_opts.go @@ -14,6 +14,8 @@ import ( // PresealSectors option. const DefaultPresealsPerBootstrapMiner = 2 +const TestSpt = abi.RegisteredSealProof_StackedDrg2KiBV1_1 + // nodeOpts is an options accumulating struct, where functional options are // merged into. type nodeOpts struct { diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go index 6f682bd3ad3..39de9d9e27d 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit2/node_opts_nv.go @@ -58,10 +58,8 @@ func InstantaneousNetworkVersion(version network.Version) node.Option { } func NetworkUpgradeAt(version network.Version, upgradeHeight abi.ChainEpoch) node.Option { - fullSchedule := stmgr.UpgradeSchedule{} - schedule := stmgr.UpgradeSchedule{} - for _, upgrade := range fullSchedule { + for _, upgrade := range DefaultTestUpgradeSchedule { if upgrade.Network > version { break } From 9436be5ff03744609d0a28c5fdcecb497ba33ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 17 Jun 2021 21:58:29 +0100 Subject: [PATCH 43/72] introduce TestFullNode#WaitTillChain(predicate). --- itests/deals_test.go | 17 ++--------- itests/kit2/chain.go | 21 -------------- itests/kit2/node_full.go | 50 +++++++++++++++++++++++++++++++++ itests/sector_pledge_test.go | 4 +-- itests/sector_terminate_test.go | 8 +++--- 5 files changed, 58 insertions(+), 42 deletions(-) delete mode 100644 itests/kit2/chain.go diff --git a/itests/deals_test.go b/itests/deals_test.go index 3a6d9c8682b..af0ef68c470 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -239,23 +239,10 @@ func TestFirstDealEnablesMining(t *testing.T) { // once the provider has mined a block, thanks to the power acquired from the deal, // we pass the test. providerMined := make(chan struct{}) - heads, err := client.ChainNotify(ctx) - require.NoError(t, err) go func() { - for chg := range heads { - for _, c := range chg { - if c.Type != "apply" { - continue - } - for _, b := range c.Val.Blocks() { - if b.Miner == provider.ActorAddr { - close(providerMined) - return - } - } - } - } + _ = client.WaitTillChain(ctx, kit2.BlockMinedBy(provider.ActorAddr)) + close(providerMined) }() // now perform the deal. diff --git a/itests/kit2/chain.go b/itests/kit2/chain.go deleted file mode 100644 index 9563bae9fca..00000000000 --- a/itests/kit2/chain.go +++ /dev/null @@ -1,21 +0,0 @@ -package kit2 - -import ( - "context" - "testing" - "time" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/stretchr/testify/require" -) - -func WaitTillChainHeight(ctx context.Context, t *testing.T, node *TestFullNode, blocktime time.Duration, height int) abi.ChainEpoch { - for { - h, err := node.ChainHead(ctx) - require.NoError(t, err) - if h.Height() > abi.ChainEpoch(height) { - return h.Height() - } - time.Sleep(blocktime) - } -} diff --git a/itests/kit2/node_full.go b/itests/kit2/node_full.go index b0b39b471ec..3dadb4d8dff 100644 --- a/itests/kit2/node_full.go +++ b/itests/kit2/node_full.go @@ -4,8 +4,11 @@ import ( "context" "testing" + "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/api/v1api" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" @@ -33,3 +36,50 @@ func (f *TestFullNode) CreateImportFile(ctx context.Context, rseed int, size int require.NoError(f.t, err) return res, path } + +// WaitTillChain waits until a specified chain condition is met. It returns +// the first tipset where the condition is met. +func (f *TestFullNode) WaitTillChain(ctx context.Context, pred ChainPredicate) *types.TipSet { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + heads, err := f.ChainNotify(ctx) + require.NoError(f.t, err) + + for chg := range heads { + for _, c := range chg { + if c.Type != "apply" { + continue + } + if ts := c.Val; pred(ts) { + return ts + } + } + } + require.Fail(f.t, "chain condition not met") + return nil +} + +// ChainPredicate encapsulates a chain condition. +type ChainPredicate func(set *types.TipSet) bool + +// HeightAtLeast returns a ChainPredicate that is satisfied when the chain +// height is equal or higher to the target. +func HeightAtLeast(target abi.ChainEpoch) ChainPredicate { + return func(ts *types.TipSet) bool { + return ts.Height() >= target + } +} + +// BlockMinedBy returns a ChainPredicate that is satisfied when we observe the +// first block mined by the specified miner. +func BlockMinedBy(miner address.Address) ChainPredicate { + return func(ts *types.TipSet) bool { + for _, b := range ts.Blocks() { + if b.Miner == miner { + return true + } + } + return false + } +} diff --git a/itests/sector_pledge_test.go b/itests/sector_pledge_test.go index 73fd2204e5e..8e87f265827 100644 --- a/itests/sector_pledge_test.go +++ b/itests/sector_pledge_test.go @@ -58,7 +58,7 @@ func TestPledgeBatching(t *testing.T) { client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) ens.InterconnectAll().BeginMining(blockTime) - kit2.WaitTillChainHeight(ctx, t, client, blockTime, 10) + client.WaitTillChain(ctx, kit2.HeightAtLeast(10)) toCheck := miner.StartPledge(ctx, nSectors, 0, nil) @@ -115,7 +115,7 @@ func TestPledgeBeforeNv13(t *testing.T) { client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) - kit2.WaitTillChainHeight(ctx, t, client, blocktime, 10) + client.WaitTillChain(ctx, kit2.HeightAtLeast(10)) toCheck := miner.StartPledge(ctx, nSectors, 0, nil) diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go index d1852ec3997..faf12228c9e 100644 --- a/itests/sector_terminate_test.go +++ b/itests/sector_terminate_test.go @@ -57,8 +57,8 @@ func TestTerminate(t *testing.T) { waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) } nSectors++ @@ -140,8 +140,8 @@ loop: waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) From 2548c224c7a08ba5489644742921b6f73fb15aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 10:27:20 +0100 Subject: [PATCH 44/72] switch to TestFullNode#WaitTillChain. --- itests/wdpost_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index 317a7a5293a..83ddf34e548 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -69,8 +69,8 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) From e85af3cba7c9819526d6ce368e3dfc213c125bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 16:19:58 +0100 Subject: [PATCH 45/72] fix merge error. --- itests/wdpost_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index 83ddf34e548..608c377cabd 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -145,8 +145,8 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil = di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - height = kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts = client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) @@ -167,8 +167,8 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil = di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - height = kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts = client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) @@ -190,8 +190,8 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d\n", waitUntil) - height = kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) } p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) From 5548541e1a08c313c5e1d148ea739293329ced88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 18:10:42 +0100 Subject: [PATCH 46/72] fix default proof type to use for non-genesis miners. We need to instantiate non-genesis miners with a _concrete_ proof type. --- itests/deadlines_test.go | 8 ++------ itests/kit2/ensemble_opts.go | 4 ++-- itests/kit2/node_opts_nv.go | 1 - 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/itests/deadlines_test.go b/itests/deadlines_test.go index 7b75eebbdb8..3c8303ac021 100644 --- a/itests/deadlines_test.go +++ b/itests/deadlines_test.go @@ -26,7 +26,6 @@ import ( miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" - logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" ) @@ -57,11 +56,8 @@ func TestDeadlineToggling(t *testing.T) { if os.Getenv("LOTUS_TEST_DEADLINE_TOGGLING") != "1" { t.Skip("this takes a few minutes, set LOTUS_TEST_DEADLINE_TOGGLING=1 to run") } - _ = logging.SetLogLevel("miner", "ERROR") - _ = logging.SetLogLevel("chainstore", "ERROR") - _ = logging.SetLogLevel("chain", "ERROR") - _ = logging.SetLogLevel("sub", "ERROR") - _ = logging.SetLogLevel("storageminer", "FATAL") + + kit2.QuietMiningLogs() const sectorsC, sectorsD, sectorsB = 10, 9, 8 diff --git a/itests/kit2/ensemble_opts.go b/itests/kit2/ensemble_opts.go index f8bc8153511..8c6d66d9e13 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit2/ensemble_opts.go @@ -23,8 +23,8 @@ type ensembleOpts struct { } var DefaultEnsembleOpts = ensembleOpts{ - pastOffset: 10000000 * time.Second, // time sufficiently in the past to trigger catch-up mining. - proofType: abi.RegisteredSealProof_StackedDrg2KiBV1, + pastOffset: 10000000 * time.Second, // time sufficiently in the past to trigger catch-up mining. + proofType: abi.RegisteredSealProof_StackedDrg2KiBV1_1, // default _concrete_ proof type for non-genesis miners (notice the _1). } func ProofType(proofType abi.RegisteredSealProof) EnsembleOpt { diff --git a/itests/kit2/node_opts_nv.go b/itests/kit2/node_opts_nv.go index 39de9d9e27d..5ffd94f5ed9 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit2/node_opts_nv.go @@ -87,5 +87,4 @@ func SDRUpgradeAt(calico, persian abi.ChainEpoch) node.Option { Network: network.Version8, Height: persian, }}) - } From 3d8eb374bd05fed40e1845a25afa0440587b83a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 19:23:32 +0100 Subject: [PATCH 47/72] cleaner instantiation of lite and gateway nodes + general cleanup. --- itests/cli_test.go | 2 +- itests/gateway_test.go | 71 ++++++++++++++++++---------------------- itests/kit2/client.go | 2 +- itests/kit2/ensemble.go | 13 ++++---- itests/kit2/funds.go | 2 +- itests/multisig_test.go | 6 ++-- itests/paych_api_test.go | 2 +- itests/paych_cli_test.go | 2 +- 8 files changed, 45 insertions(+), 55 deletions(-) diff --git a/itests/cli_test.go b/itests/cli_test.go index 8436f189e65..5c9cf0f69c1 100644 --- a/itests/cli_test.go +++ b/itests/cli_test.go @@ -17,5 +17,5 @@ func TestClient(t *testing.T) { blockTime := 5 * time.Millisecond client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) - kit2.RunClientTest(t, cli.Commands, *client) + kit2.RunClientTest(t, cli.Commands, client) } diff --git a/itests/gateway_test.go b/itests/gateway_test.go index 20b0add6a9c..36df41d54f3 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "math" - "os" "testing" "time" @@ -45,7 +44,6 @@ func init() { // TestGatewayWalletMsig tests that API calls to wallet and msig can be made on a lite // node that is connected through a gateway to a full API node func TestGatewayWalletMsig(t *testing.T) { - _ = os.Setenv("BELLMAN_NO_GPU", "1") kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond @@ -111,7 +109,6 @@ func TestGatewayWalletMsig(t *testing.T) { if err != nil { return cid.Undef, err } - return lite.MpoolPush(ctx, sm) } @@ -179,7 +176,6 @@ func TestGatewayWalletMsig(t *testing.T) { // TestGatewayMsigCLI tests that msig CLI calls can be made // on a lite node that is connected through a gateway to a full API node func TestGatewayMsigCLI(t *testing.T) { - _ = os.Setenv("BELLMAN_NO_GPU", "1") kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond @@ -192,7 +188,6 @@ func TestGatewayMsigCLI(t *testing.T) { } func TestGatewayDealFlow(t *testing.T) { - _ = os.Setenv("BELLMAN_NO_GPU", "1") kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond @@ -200,18 +195,19 @@ func TestGatewayDealFlow(t *testing.T) { nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) defer nodes.closer() + time.Sleep(5 * time.Second) + // For these tests where the block time is artificially short, just use // a deal start epoch that is guaranteed to be far enough in the future // so that the deal starts sealing in time dealStartEpoch := abi.ChainEpoch(2 << 12) - dh := kit2.NewDealHarness(t, &nodes.lite, &nodes.miner) + dh := kit2.NewDealHarness(t, nodes.lite, nodes.miner) dealCid, res, _ := dh.MakeOnlineDeal(ctx, 6, false, dealStartEpoch) dh.PerformRetrieval(ctx, dealCid, res.Root, false) } func TestGatewayCLIDealFlow(t *testing.T) { - _ = os.Setenv("BELLMAN_NO_GPU", "1") kit2.QuietMiningLogs() blocktime := 5 * time.Millisecond @@ -223,9 +219,9 @@ func TestGatewayCLIDealFlow(t *testing.T) { } type testNodes struct { - lite kit2.TestFullNode - full kit2.TestFullNode - miner kit2.TestMiner + lite *kit2.TestFullNode + full *kit2.TestFullNode + miner *kit2.TestMiner closer jsonrpc.ClientCloser } @@ -242,8 +238,8 @@ func startNodesWithFunds( fullWalletAddr, err := nodes.full.WalletDefaultAddress(ctx) require.NoError(t, err) - // Create a wallet on the lite node - liteWalletAddr, err := nodes.lite.WalletNew(ctx, types.KTSecp256k1) + // Get the lite node default wallet address. + liteWalletAddr, err := nodes.lite.WalletDefaultAddress(ctx) require.NoError(t, err) // Send some funds from the full node to the lite node @@ -263,9 +259,9 @@ func startNodes( var closer jsonrpc.ClientCloser var ( - full kit2.TestFullNode + full *kit2.TestFullNode + miner *kit2.TestMiner lite kit2.TestFullNode - miner kit2.TestMiner ) // - Create one full node and one lite node @@ -273,38 +269,35 @@ func startNodes( // - Start full node 2 in lite mode // - Connect lite node -> gateway server -> full node - var liteOptBuilder kit2.OptBuilder - liteOptBuilder = func(nodes []*kit2.TestFullNode) node.Option { - fullNode := nodes[0] - - // Create a gateway server in front of the full node - gwapi := gateway.NewNode(fullNode, lookbackCap, stateWaitLookbackLimit) - handler, err := gateway.Handler(gwapi) - require.NoError(t, err) + // create the full node and the miner. + var ens *kit2.Ensemble + full, miner, ens = kit2.EnsembleMinimal(t, kit2.MockProofs()) + ens.InterconnectAll().BeginMining(blocktime) - srv, _ := kit2.CreateRPCServer(t, handler) + // Create a gateway server in front of the full node + gwapi := gateway.NewNode(full, lookbackCap, stateWaitLookbackLimit) + handler, err := gateway.Handler(gwapi) + require.NoError(t, err) - // Create a gateway client API that connects to the gateway server - var gapi api.Gateway - gapi, closer, err = client.NewGatewayRPCV1(ctx, "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) - require.NoError(t, err) + srv, _ := kit2.CreateRPCServer(t, handler) - // Provide the gateway API to dependency injection - return node.Override(new(api.Gateway), gapi) - } + // Create a gateway client API that connects to the gateway server + var gapi api.Gateway + gapi, closer, err = client.NewGatewayRPCV1(ctx, "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) + require.NoError(t, err) - kit2.NewEnsemble(t, kit2.MockProofs()). - FullNode(&full). - FullNode(&lite, kit2.LiteNode(), kit2.ThroughRPC(), kit2.AddOptBuilder(liteOptBuilder)). - Miner(&miner, &full). - Start(). - InterconnectAll(). - BeginMining(blocktime) + ens.FullNode(&lite, + kit2.LiteNode(), + kit2.ThroughRPC(), + kit2.ConstructorOpts( + node.Override(new(api.Gateway), gapi), + ), + ).Start().InterconnectAll() - return &testNodes{lite: lite, full: full, miner: miner, closer: closer} + return &testNodes{lite: &lite, full: full, miner: miner, closer: closer} } -func sendFunds(ctx context.Context, fromNode kit2.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { +func sendFunds(ctx context.Context, fromNode *kit2.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { msg := &types.Message{ From: fromAddr, To: toAddr, diff --git a/itests/kit2/client.go b/itests/kit2/client.go index 247d208369b..78a7034feca 100644 --- a/itests/kit2/client.go +++ b/itests/kit2/client.go @@ -21,7 +21,7 @@ import ( ) // RunClientTest exercises some of the Client CLI commands -func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) { +func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode *TestFullNode) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/itests/kit2/ensemble.go b/itests/kit2/ensemble.go index 67e6b859260..44580920f5c 100644 --- a/itests/kit2/ensemble.go +++ b/itests/kit2/ensemble.go @@ -145,13 +145,13 @@ func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { require.NoError(n.t, err) } - var key *wallet.Key - if !n.bootstrapped && !options.balance.IsZero() { - // create a key+address, 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) + key, err := wallet.GenerateKey(types.KTBLS) + require.NoError(n.t, err) + if !n.bootstrapped && !options.balance.IsZero() { + // if we still haven't forged genesis, create a key+address, and assign + // it some FIL; this will be set as the default wallet when the node is + // started. genacc := genesis.Actor{ Type: genesis.TAccount, Balance: options.balance, @@ -298,7 +298,6 @@ func (n *Ensemble) Start() *Ensemble { // 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) diff --git a/itests/kit2/funds.go b/itests/kit2/funds.go index fc4a6c29486..b2996335398 100644 --- a/itests/kit2/funds.go +++ b/itests/kit2/funds.go @@ -14,7 +14,7 @@ import ( // SendFunds sends funds from the default wallet of the specified sender node // to the recipient address. -func SendFunds(ctx context.Context, t *testing.T, sender TestFullNode, recipient address.Address, amount abi.TokenAmount) { +func SendFunds(ctx context.Context, t *testing.T, sender *TestFullNode, recipient address.Address, amount abi.TokenAmount) { senderAddr, err := sender.WalletDefaultAddress(ctx) require.NoError(t, err) diff --git a/itests/multisig_test.go b/itests/multisig_test.go index f5df0be1adb..9b1f5967389 100644 --- a/itests/multisig_test.go +++ b/itests/multisig_test.go @@ -3,7 +3,6 @@ package itests import ( "context" "fmt" - "os" "regexp" "strings" "testing" @@ -18,17 +17,16 @@ import ( // TestMultisig does a basic test to exercise the multisig CLI commands func TestMultisig(t *testing.T) { - _ = os.Setenv("BELLMAN_NO_GPU", "1") kit2.QuietMiningLogs() blockTime := 5 * time.Millisecond client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) - runMultisigTests(t, *client) + runMultisigTests(t, client) } -func runMultisigTests(t *testing.T, clientNode kit2.TestFullNode) { +func runMultisigTests(t *testing.T, clientNode *kit2.TestFullNode) { // Create mock CLI ctx := context.Background() mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go index 8fb4cde0c09..86a156790dd 100644 --- a/itests/paych_api_test.go +++ b/itests/paych_api_test.go @@ -51,7 +51,7 @@ func TestPaymentChannelsAPI(t *testing.T) { receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1) require.NoError(t, err) - kit2.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) + kit2.SendFunds(ctx, t, &paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) // setup the payment channel createrAddr, err := paymentCreator.WalletDefaultAddress(ctx) diff --git a/itests/paych_cli_test.go b/itests/paych_cli_test.go index 2450828d3ed..84ccee95abb 100644 --- a/itests/paych_cli_test.go +++ b/itests/paych_cli_test.go @@ -428,7 +428,7 @@ func startPaychCreatorReceiverMiner(ctx context.Context, t *testing.T, paymentCr // Send some funds to the second node receiverAddr, err := paymentReceiver.WalletDefaultAddress(ctx) require.NoError(t, err) - kit2.SendFunds(ctx, t, *paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) + kit2.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) // Get the first node's address creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx) From 718babd33a75154627c5f5851526ddb54029071c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 19:38:17 +0100 Subject: [PATCH 48/72] use miner owner address when posting proofs. --- itests/wdpost_dispute_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index 8661fba00a9..49b41c7e05c 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -87,8 +87,8 @@ func TestWindowPostDispute(t *testing.T) { waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 t.Logf("End for head.Height > %d", waitUntil) - height := kit2.WaitTillChainHeight(ctx, t, &client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) p, err := client.StateMinerPower(ctx, evilMinerAddr, types.EmptyTSK) require.NoError(t, err) @@ -122,7 +122,7 @@ func TestWindowPostDispute(t *testing.T) { build.Clock.Sleep(blocktime) } - err = submitBadProof(ctx, client, evilMinerAddr, di, evilSectorLoc.Deadline, evilSectorLoc.Partition) + err = submitBadProof(ctx, client, evilMiner.OwnerKey.Address, evilMinerAddr, di, evilSectorLoc.Deadline, evilSectorLoc.Partition) require.NoError(t, err, "evil proof not accepted") // Wait until after the proving period. @@ -220,7 +220,7 @@ func TestWindowPostDispute(t *testing.T) { } // Now try to be evil again - err = submitBadProof(ctx, client, evilMinerAddr, di, evilSectorLoc.Deadline, evilSectorLoc.Partition) + err = submitBadProof(ctx, client, evilMiner.OwnerKey.Address, evilMinerAddr, di, evilSectorLoc.Deadline, evilSectorLoc.Partition) require.Error(t, err) require.Contains(t, err.Error(), "message execution failed: exit 16, reason: window post failed: invalid PoSt") @@ -260,8 +260,8 @@ func TestWindowPostDisputeFails(t *testing.T) { waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 t.Logf("End for head.Height > %d", waitUntil) - height := kit2.WaitTillChainHeight(ctx, t, client, blocktime, int(waitUntil)) - t.Logf("Now head.Height = %d", height) + ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) ssz, err := miner.ActorSectorSize(ctx, maddr) require.NoError(t, err) @@ -327,7 +327,7 @@ waitForProof: func submitBadProof( ctx context.Context, - client api.FullNode, maddr address.Address, + client api.FullNode, owner address.Address, maddr address.Address, di *dline.Info, dlIdx, partIdx uint64, ) error { head, err := client.ChainHead(ctx) From a7d8d15c13f18e4c0a6d82bfd7d205741c4053fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 19:42:06 +0100 Subject: [PATCH 49/72] =?UTF-8?q?kill=20old=20kit=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- itests/kit/blockminer.go | 124 ------- itests/kit/client.go | 146 -------- itests/kit/deals.go | 312 ------------------ itests/kit/funds.go | 39 --- itests/kit/init.go | 32 -- itests/kit/log.go | 19 -- itests/kit/mockcli.go | 141 -------- itests/kit/net.go | 87 ----- itests/kit/node_builder.go | 658 ------------------------------------- itests/kit/nodes.go | 153 --------- itests/kit/pledge.go | 88 ----- 11 files changed, 1799 deletions(-) delete mode 100644 itests/kit/blockminer.go delete mode 100644 itests/kit/client.go delete mode 100644 itests/kit/deals.go delete mode 100644 itests/kit/funds.go delete mode 100644 itests/kit/init.go delete mode 100644 itests/kit/log.go delete mode 100644 itests/kit/mockcli.go delete mode 100644 itests/kit/net.go delete mode 100644 itests/kit/node_builder.go delete mode 100644 itests/kit/nodes.go delete mode 100644 itests/kit/pledge.go diff --git a/itests/kit/blockminer.go b/itests/kit/blockminer.go deleted file mode 100644 index 3b1f1fedfa7..00000000000 --- a/itests/kit/blockminer.go +++ /dev/null @@ -1,124 +0,0 @@ -package kit - -import ( - "context" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/miner" - "github.com/stretchr/testify/require" -) - -// BlockMiner is a utility that makes a test miner Mine blocks on a timer. -type BlockMiner struct { - t *testing.T - miner TestMiner - - nextNulls int64 - wg sync.WaitGroup - cancel context.CancelFunc -} - -func NewBlockMiner(t *testing.T, miner TestMiner) *BlockMiner { - return &BlockMiner{ - t: t, - miner: miner, - cancel: func() {}, - } -} - -func (bm *BlockMiner) MineBlocks(ctx context.Context, blocktime time.Duration) { - time.Sleep(time.Second) - - // wrap context in a cancellable context. - ctx, bm.cancel = context.WithCancel(ctx) - - bm.wg.Add(1) - go func() { - defer bm.wg.Done() - - for { - select { - case <-time.After(blocktime): - case <-ctx.Done(): - return - } - - nulls := atomic.SwapInt64(&bm.nextNulls, 0) - err := bm.miner.MineOne(ctx, miner.MineReq{ - InjectNulls: abi.ChainEpoch(nulls), - Done: func(bool, abi.ChainEpoch, error) {}, - }) - switch { - case err == nil: // wrap around - case ctx.Err() != nil: // context fired. - return - default: // log error - bm.t.Error(err) - } - } - }() -} - -// InjectNulls injects the specified amount of null rounds in the next -// mining rounds. -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)) { - for i := 0; i < 1000; i++ { - var ( - success bool - err error - epoch abi.ChainEpoch - wait = make(chan struct{}) - ) - - doneFn := func(win bool, ep abi.ChainEpoch, e error) { - success = win - err = e - epoch = ep - wait <- struct{}{} - } - - mineErr := bm.miner.MineOne(ctx, miner.MineReq{Done: doneFn}) - require.NoError(bm.t, mineErr) - <-wait - - require.NoError(bm.t, err) - - if success { - // Wait until it shows up on the given full nodes ChainHead - nloops := 50 - for i := 0; i < nloops; i++ { - ts, err := fn.ChainHead(ctx) - require.NoError(bm.t, err) - - if ts.Height() == epoch { - break - } - - require.NotEqual(bm.t, i, nloops-1, "block never managed to sync to node") - time.Sleep(time.Millisecond * 10) - } - - if cb != nil { - cb(epoch) - } - return - } - bm.t.Log("did not Mine block, trying again", i) - } - bm.t.Fatal("failed to Mine 1000 times in a row...") -} - -// Stop stops the block miner. -func (bm *BlockMiner) Stop() { - bm.t.Log("shutting down mining") - bm.cancel() - bm.wg.Wait() -} diff --git a/itests/kit/client.go b/itests/kit/client.go deleted file mode 100644 index 6b7d4626563..00000000000 --- a/itests/kit/client.go +++ /dev/null @@ -1,146 +0,0 @@ -package kit - -import ( - "context" - "fmt" - "io/ioutil" - "math/rand" - "os" - "path/filepath" - "regexp" - "strings" - "testing" - "time" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/v2/actors/builtin" - "github.com/stretchr/testify/require" - lcli "github.com/urfave/cli/v2" -) - -// RunClientTest exercises some of the Client CLI commands -func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - // Create mock CLI - mockCLI := NewMockCLI(ctx, t, cmds) - clientCLI := mockCLI.Client(clientNode.ListenAddr) - - // Get the Miner address - addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) - require.NoError(t, err) - require.Len(t, addrs, 1) - - minerAddr := addrs[0] - fmt.Println("Miner:", minerAddr) - - // client query-ask - out := clientCLI.RunCmd("client", "query-ask", minerAddr.String()) - require.Regexp(t, regexp.MustCompile("Ask:"), out) - - // Create a deal (non-interactive) - // client deal --start-epoch= 1000000attofil - res, _, _, err := CreateImportFile(ctx, clientNode, 1, 0) - - require.NoError(t, err) - startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12) - dataCid := res.Root - price := "1000000attofil" - duration := fmt.Sprintf("%d", build.MinDealDuration) - out = clientCLI.RunCmd("client", "deal", startEpoch, dataCid.String(), minerAddr.String(), price, duration) - fmt.Println("client deal", out) - - // Create a deal (interactive) - // client deal - // - // (in days) - // - // "no" (verified Client) - // "yes" (confirm deal) - res, _, _, err = CreateImportFile(ctx, clientNode, 2, 0) - require.NoError(t, err) - dataCid2 := res.Root - duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) - cmd := []string{"client", "deal"} - interactiveCmds := []string{ - dataCid2.String(), - duration, - minerAddr.String(), - "no", - "yes", - } - out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds) - fmt.Println("client deal:\n", out) - - // Wait for provider to start sealing deal - dealStatus := "" - for { - // client list-deals - out = clientCLI.RunCmd("client", "list-deals") - fmt.Println("list-deals:\n", out) - - lines := strings.Split(out, "\n") - require.GreaterOrEqual(t, len(lines), 2) - re := regexp.MustCompile(`\s+`) - parts := re.Split(lines[1], -1) - if len(parts) < 4 { - require.Fail(t, "bad list-deals output format") - } - dealStatus = parts[3] - fmt.Println(" Deal status:", dealStatus) - - st := CategorizeDealState(dealStatus) - require.NotEqual(t, TestDealStateFailed, st) - if st == TestDealStateComplete { - break - } - - time.Sleep(time.Second) - } - - // Retrieve the first file from the Miner - // client retrieve - tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client") - require.NoError(t, err) - path := filepath.Join(tmpdir, "outfile.dat") - out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) - fmt.Println("retrieve:\n", out) - require.Regexp(t, regexp.MustCompile("Success"), out) -} - -func CreateImportFile(ctx context.Context, client api.FullNode, rseed int, size int) (res *api.ImportRes, path string, data []byte, err error) { - data, path, err = createRandomFile(rseed, size) - if err != nil { - return nil, "", nil, err - } - - res, err = client.ClientImport(ctx, api.FileRef{Path: path}) - if err != nil { - return nil, "", nil, err - } - return res, path, data, nil -} - -func createRandomFile(rseed, size int) ([]byte, string, error) { - if size == 0 { - size = 1600 - } - data := make([]byte, size) - rand.New(rand.NewSource(int64(rseed))).Read(data) - - dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") - if err != nil { - return nil, "", err - } - - path := filepath.Join(dir, "sourcefile.dat") - err = ioutil.WriteFile(path, data, 0644) - if err != nil { - return nil, "", err - } - - return data, path, nil -} diff --git a/itests/kit/deals.go b/itests/kit/deals.go deleted file mode 100644 index c768eb87f3a..00000000000 --- a/itests/kit/deals.go +++ /dev/null @@ -1,312 +0,0 @@ -package kit - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - "time" - - "github.com/ipfs/go-cid" - files "github.com/ipfs/go-ipfs-files" - "github.com/ipld/go-car" - "github.com/stretchr/testify/require" - - "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/types" - sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/node/impl" - ipld "github.com/ipfs/go-ipld-format" - dag "github.com/ipfs/go-merkledag" - dstest "github.com/ipfs/go-merkledag/test" - unixfile "github.com/ipfs/go-unixfs/file" -) - -type DealHarness struct { - t *testing.T - client api.FullNode - miner TestMiner -} - -// NewDealHarness creates a test harness that contains testing utilities for deals. -func NewDealHarness(t *testing.T, client api.FullNode, miner TestMiner) *DealHarness { - return &DealHarness{ - t: t, - client: client, - miner: miner, - } -} - -func (dh *DealHarness) MakeFullDeal(ctx context.Context, rseed int, carExport, fastRet bool, startEpoch abi.ChainEpoch) { - res, _, data, err := CreateImportFile(ctx, dh.client, rseed, 0) - if err != nil { - dh.t.Fatal(err) - } - - fcid := res.Root - fmt.Println("FILE CID: ", fcid) - - deal := dh.StartDeal(ctx, fcid, fastRet, startEpoch) - - // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this - time.Sleep(time.Second) - dh.WaitDealSealed(ctx, deal, false, false, nil) - - // Retrieval - info, err := dh.client.ClientGetDealInfo(ctx, *deal) - require.NoError(dh.t, err) - - dh.TestRetrieval(ctx, fcid, &info.PieceCID, carExport, data) -} - -func (dh *DealHarness) StartDeal(ctx context.Context, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { - maddr, err := dh.miner.ActorAddress(ctx) - if err != nil { - dh.t.Fatal(err) - } - - addr, err := dh.client.WalletDefaultAddress(ctx) - if err != nil { - dh.t.Fatal(err) - } - deal, err := dh.client.ClientStartDeal(ctx, &api.StartDealParams{ - Data: &storagemarket.DataRef{ - TransferType: storagemarket.TTGraphsync, - Root: fcid, - }, - Wallet: addr, - Miner: maddr, - EpochPrice: types.NewInt(1000000), - DealStartEpoch: startEpoch, - MinBlocksDuration: uint64(build.MinDealDuration), - FastRetrieval: fastRet, - }) - if err != nil { - dh.t.Fatalf("%+v", err) - } - return deal -} - -func (dh *DealHarness) WaitDealSealed(ctx context.Context, deal *cid.Cid, noseal, noSealStart bool, cb func()) { -loop: - for { - di, err := dh.client.ClientGetDealInfo(ctx, *deal) - require.NoError(dh.t, err) - - switch di.State { - case storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing: - if noseal { - return - } - if !noSealStart { - dh.StartSealingWaiting(ctx) - } - case storagemarket.StorageDealProposalRejected: - dh.t.Fatal("deal rejected") - case storagemarket.StorageDealFailing: - dh.t.Fatal("deal failed") - case storagemarket.StorageDealError: - dh.t.Fatal("deal errored", di.Message) - case storagemarket.StorageDealActive: - fmt.Println("COMPLETE", di) - break loop - } - - mds, err := dh.miner.MarketListIncompleteDeals(ctx) - require.NoError(dh.t, err) - - var minerState storagemarket.StorageDealStatus - for _, md := range mds { - if md.DealID == di.DealID { - minerState = md.State - break - } - } - - fmt.Printf("Deal %d state: client:%s provider:%s\n", di.DealID, storagemarket.DealStates[di.State], storagemarket.DealStates[minerState]) - time.Sleep(time.Second / 2) - if cb != nil { - cb() - } - } -} - -func (dh *DealHarness) WaitDealPublished(ctx context.Context, deal *cid.Cid) { - subCtx, cancel := context.WithCancel(ctx) - defer cancel() - updates, err := dh.miner.MarketGetDealUpdates(subCtx) - if err != nil { - dh.t.Fatal(err) - } - for { - select { - case <-ctx.Done(): - dh.t.Fatal("context timeout") - case di := <-updates: - if deal.Equals(di.ProposalCid) { - switch di.State { - case storagemarket.StorageDealProposalRejected: - dh.t.Fatal("deal rejected") - case storagemarket.StorageDealFailing: - dh.t.Fatal("deal failed") - case storagemarket.StorageDealError: - dh.t.Fatal("deal errored", di.Message) - case storagemarket.StorageDealFinalizing, storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing, storagemarket.StorageDealActive: - fmt.Println("COMPLETE", di) - return - } - fmt.Println("Deal state: ", storagemarket.DealStates[di.State]) - } - } - } -} - -func (dh *DealHarness) StartSealingWaiting(ctx context.Context) { - snums, err := dh.miner.SectorsList(ctx) - require.NoError(dh.t, err) - - for _, snum := range snums { - si, err := dh.miner.SectorsStatus(ctx, snum, false) - require.NoError(dh.t, err) - - dh.t.Logf("Sector state: %s", si.State) - if si.State == api.SectorState(sealing.WaitDeals) { - require.NoError(dh.t, dh.miner.SectorStartSealing(ctx, snum)) - } - - flushSealingBatches(dh.t, ctx, dh.miner) - } -} - -func (dh *DealHarness) TestRetrieval(ctx context.Context, fcid cid.Cid, piece *cid.Cid, carExport bool, expect []byte) { - offers, err := dh.client.ClientFindData(ctx, fcid, piece) - if err != nil { - dh.t.Fatal(err) - } - - if len(offers) < 1 { - dh.t.Fatal("no offers") - } - - rpath, err := ioutil.TempDir("", "lotus-retrieve-test-") - if err != nil { - dh.t.Fatal(err) - } - defer os.RemoveAll(rpath) //nolint:errcheck - - caddr, err := dh.client.WalletDefaultAddress(ctx) - if err != nil { - dh.t.Fatal(err) - } - - ref := &api.FileRef{ - Path: filepath.Join(rpath, "ret"), - IsCAR: carExport, - } - updates, err := dh.client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref) - if err != nil { - dh.t.Fatal(err) - } - for update := range updates { - if update.Err != "" { - dh.t.Fatalf("retrieval failed: %s", update.Err) - } - } - - rdata, err := ioutil.ReadFile(filepath.Join(rpath, "ret")) - if err != nil { - dh.t.Fatal(err) - } - - if carExport { - rdata = dh.ExtractCarData(ctx, rdata, rpath) - } - - if !bytes.Equal(rdata, expect) { - dh.t.Fatal("wrong expect retrieved") - } -} - -func (dh *DealHarness) ExtractCarData(ctx context.Context, rdata []byte, rpath string) []byte { - bserv := dstest.Bserv() - ch, err := car.LoadCar(bserv.Blockstore(), bytes.NewReader(rdata)) - if err != nil { - dh.t.Fatal(err) - } - b, err := bserv.GetBlock(ctx, ch.Roots[0]) - if err != nil { - dh.t.Fatal(err) - } - nd, err := ipld.Decode(b) - if err != nil { - dh.t.Fatal(err) - } - dserv := dag.NewDAGService(bserv) - fil, err := unixfile.NewUnixfsFile(ctx, dserv, nd) - if err != nil { - dh.t.Fatal(err) - } - outPath := filepath.Join(rpath, "retLoadedCAR") - if err := files.WriteTo(fil, outPath); err != nil { - dh.t.Fatal(err) - } - rdata, err = ioutil.ReadFile(outPath) - if err != nil { - dh.t.Fatal(err) - } - return rdata -} - -type DealsScaffold struct { - Ctx context.Context - Client *impl.FullNodeAPI - Miner TestMiner - 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) - t.Cleanup(blockMiner.Stop) - return blockMiner -} - -type TestDealState int - -const ( - TestDealStateFailed = TestDealState(-1) - TestDealStateInProgress = TestDealState(0) - TestDealStateComplete = TestDealState(1) -) - -// CategorizeDealState categorizes deal states into one of three states: -// Complete, InProgress, Failed. -func CategorizeDealState(dealStatus string) TestDealState { - switch dealStatus { - case "StorageDealFailing", "StorageDealError": - return TestDealStateFailed - case "StorageDealStaged", "StorageDealAwaitingPreCommit", "StorageDealSealing", "StorageDealActive", "StorageDealExpired", "StorageDealSlashed": - return TestDealStateComplete - } - return TestDealStateInProgress -} diff --git a/itests/kit/funds.go b/itests/kit/funds.go deleted file mode 100644 index 4c739dc62c2..00000000000 --- a/itests/kit/funds.go +++ /dev/null @@ -1,39 +0,0 @@ -package kit - -import ( - "context" - "testing" - - "github.com/filecoin-project/go-state-types/abi" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/types" -) - -// SendFunds sends funds from the default wallet of the specified sender node -// 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) - } - - msg := &types.Message{ - From: senderAddr, - To: recipient, - Value: amount, - } - - sm, err := sender.MpoolPushMessage(ctx, msg, nil) - if err != nil { - t.Fatal(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") - } -} diff --git a/itests/kit/init.go b/itests/kit/init.go deleted file mode 100644 index 2f40ca0f048..00000000000 --- a/itests/kit/init.go +++ /dev/null @@ -1,32 +0,0 @@ -package kit - -import ( - "fmt" - "os" - "strings" - - "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() { - bin := os.Args[0] - if !strings.HasSuffix(bin, ".test") { - panic("package itests/kit must only be imported from tests") - } - - _ = 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/log.go b/itests/kit/log.go deleted file mode 100644 index 638e768d825..00000000000 --- a/itests/kit/log.go +++ /dev/null @@ -1,19 +0,0 @@ -package kit - -import ( - "github.com/filecoin-project/lotus/lib/lotuslog" - logging "github.com/ipfs/go-log/v2" -) - -func QuietMiningLogs() { - lotuslog.SetupLogLevels() - - _ = logging.SetLogLevel("miner", "ERROR") - _ = logging.SetLogLevel("chainstore", "ERROR") - _ = logging.SetLogLevel("chain", "ERROR") - _ = logging.SetLogLevel("sub", "ERROR") - _ = logging.SetLogLevel("storageminer", "ERROR") - _ = logging.SetLogLevel("pubsub", "ERROR") - _ = logging.SetLogLevel("gen", "ERROR") - _ = logging.SetLogLevel("dht/RtRefreshManager", "ERROR") -} diff --git a/itests/kit/mockcli.go b/itests/kit/mockcli.go deleted file mode 100644 index c0f21892033..00000000000 --- a/itests/kit/mockcli.go +++ /dev/null @@ -1,141 +0,0 @@ -package kit - -import ( - "bytes" - "context" - "flag" - "strings" - "testing" - - "github.com/multiformats/go-multiaddr" - "github.com/stretchr/testify/require" - lcli "github.com/urfave/cli/v2" -) - -type MockCLI struct { - t *testing.T - cmds []*lcli.Command - cctx *lcli.Context - out *bytes.Buffer -} - -func NewMockCLI(ctx context.Context, t *testing.T, cmds []*lcli.Command) *MockCLI { - // Create a CLI App with an --api-url flag so that we can specify which node - // the command should be executed against - app := &lcli.App{ - Flags: []lcli.Flag{ - &lcli.StringFlag{ - Name: "api-url", - Hidden: true, - }, - }, - Commands: cmds, - } - - var out bytes.Buffer - app.Writer = &out - app.Setup() - - cctx := lcli.NewContext(app, &flag.FlagSet{}, nil) - cctx.Context = ctx - return &MockCLI{t: t, cmds: cmds, cctx: cctx, out: &out} -} - -func (c *MockCLI) Client(addr multiaddr.Multiaddr) *MockCLIClient { - return &MockCLIClient{t: c.t, cmds: c.cmds, addr: addr, cctx: c.cctx, out: c.out} -} - -// MockCLIClient runs commands against a particular node -type MockCLIClient struct { - t *testing.T - cmds []*lcli.Command - addr multiaddr.Multiaddr - cctx *lcli.Context - out *bytes.Buffer -} - -func (c *MockCLIClient) RunCmd(input ...string) string { - out, err := c.RunCmdRaw(input...) - require.NoError(c.t, err, "output:\n%s", out) - - return out -} - -// Given an input, find the corresponding command or sub-command. -// eg "paych add-funds" -func (c *MockCLIClient) cmdByNameSub(input []string) (*lcli.Command, []string) { - name := input[0] - for _, cmd := range c.cmds { - if cmd.Name == name { - return c.findSubcommand(cmd, input[1:]) - } - } - return nil, []string{} -} - -func (c *MockCLIClient) findSubcommand(cmd *lcli.Command, input []string) (*lcli.Command, []string) { - // If there are no sub-commands, return the current command - if len(cmd.Subcommands) == 0 { - return cmd, input - } - - // Check each sub-command for a match against the name - subName := input[0] - for _, subCmd := range cmd.Subcommands { - if subCmd.Name == subName { - // Found a match, recursively search for sub-commands - return c.findSubcommand(subCmd, input[1:]) - } - } - return nil, []string{} -} - -func (c *MockCLIClient) RunCmdRaw(input ...string) (string, error) { - cmd, input := c.cmdByNameSub(input) - if cmd == nil { - panic("Could not find command " + input[0] + " " + input[1]) - } - - // prepend --api-url= - apiFlag := "--api-url=" + c.addr.String() - input = append([]string{apiFlag}, input...) - - fs := c.flagSet(cmd) - err := fs.Parse(input) - require.NoError(c.t, err) - - err = cmd.Action(lcli.NewContext(c.cctx.App, fs, c.cctx)) - - // Get the output - str := strings.TrimSpace(c.out.String()) - c.out.Reset() - return str, err -} - -func (c *MockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { - // Apply app level flags (so we can process --api-url flag) - fs := &flag.FlagSet{} - for _, f := range c.cctx.App.Flags { - err := f.Apply(fs) - if err != nil { - c.t.Fatal(err) - } - } - // Apply command level flags - for _, f := range cmd.Flags { - err := f.Apply(fs) - if err != nil { - c.t.Fatal(err) - } - } - return fs -} - -func (c *MockCLIClient) RunInteractiveCmd(cmd []string, interactive []string) string { - c.toStdin(strings.Join(interactive, "\n") + "\n") - return c.RunCmd(cmd...) -} - -func (c *MockCLIClient) toStdin(s string) { - c.cctx.App.Metadata["stdin"] = bytes.NewBufferString(s) -} diff --git a/itests/kit/net.go b/itests/kit/net.go deleted file mode 100644 index 54c72443f43..00000000000 --- a/itests/kit/net.go +++ /dev/null @@ -1,87 +0,0 @@ -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} -} diff --git a/itests/kit/node_builder.go b/itests/kit/node_builder.go deleted file mode 100644 index 3780a766900..00000000000 --- a/itests/kit/node_builder.go +++ /dev/null @@ -1,658 +0,0 @@ -package kit - -import ( - "bytes" - "context" - "crypto/rand" - "io/ioutil" - "net/http" - "net/http/httptest" - "sync" - "testing" - "time" - - "github.com/filecoin-project/go-state-types/network" - - "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) - } - - rkhKey, err := wallet.GenerateKey(types.KTSecp256k1) - if err != nil { - return nil, nil - } - - vrk := genesis.Actor{ - Type: genesis.TAccount, - Balance: big.Mul(big.Div(big.NewInt(int64(build.FilBase)), big.NewInt(100)), big.NewInt(int64(build.FilecoinPrecision))), - Meta: (&genesis.AccountMeta{Owner: rkhKey.Address}).ActorMeta(), - } - keys = append(keys, rkhKey) - - templ := &genesis.Template{ - NetworkVersion: network.Version0, - Accounts: genaccs, - Miners: genms, - NetworkName: "test", - Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past - VerifregRootKey: vrk, - 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()) - } - - if _, err := fulls[0].FullNode.WalletImport(ctx, &rkhKey.KeyInfo); err != nil { - t.Fatal(err) - } - - 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) - } - - rkhKey, err := wallet.GenerateKey(types.KTSecp256k1) - if err != nil { - return nil, nil - } - - vrk := genesis.Actor{ - Type: genesis.TAccount, - Balance: big.Mul(big.Div(big.NewInt(int64(build.FilBase)), big.NewInt(100)), big.NewInt(int64(build.FilecoinPrecision))), - Meta: (&genesis.AccountMeta{Owner: rkhKey.Address}).ActorMeta(), - } - keys = append(keys, rkhKey) - - templ := &genesis.Template{ - NetworkVersion: network.Version0, - Accounts: genaccs, - Miners: genms, - NetworkName: "test", - Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), - VerifregRootKey: vrk, - 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), - node.Override(new(ffiwrapper.Prover), mock.MockProver), - - // 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(*mock.SectorMgr), func() (*mock.SectorMgr, error) { - return mock.NewMockSectorMgr(nil), nil - }), - - node.Override(new(sectorstorage.SectorManager), node.From(new(*mock.SectorMgr))), - node.Override(new(sectorstorage.Unsealer), node.From(new(*mock.SectorMgr))), - node.Override(new(sectorstorage.PieceProvider), node.From(new(*mock.SectorMgr))), - - node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), - node.Override(new(ffiwrapper.Prover), mock.MockProver), - node.Unset(new(*sectorstorage.Manager)), - )) - } - - if _, err := fulls[0].FullNode.WalletImport(ctx, &rkhKey.KeyInfo); err != nil { - t.Fatal(err) - } - - 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(*mock.SectorMgr), func() (*mock.SectorMgr, error) { - return mock.NewMockSectorMgr(sectors), nil - }), - - node.Override(new(sectorstorage.SectorManager), node.From(new(*mock.SectorMgr))), - node.Override(new(sectorstorage.Unsealer), node.From(new(*mock.SectorMgr))), - node.Override(new(sectorstorage.PieceProvider), node.From(new(*mock.SectorMgr))), - - node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), - node.Override(new(ffiwrapper.Prover), mock.MockProver), - 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, false) - require.NoError(t, err) - - srv, maddr := CreateRPCServer(t, handler) - - var ret TestFullNode - cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+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, false) - require.NoError(t, err) - - srv, maddr := CreateRPCServer(t, handler) - - var ret TestMiner - cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+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/nodes.go b/itests/kit/nodes.go deleted file mode 100644 index d9b04166a50..00000000000 --- a/itests/kit/nodes.go +++ /dev/null @@ -1,153 +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 { - // Attention: Update this when introducing new actor versions or your tests will be sad - return FullNodeWithNetworkUpgradeAt(network.Version13, upgradeHeight) -} - -var FullNodeWithNetworkUpgradeAt = func(version network.Version, upgradeHeight abi.ChainEpoch) FullNodeOpts { - fullSchedule := 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: 3, - Migration: stmgr.UpgradeActorsV4, - }, { - Network: network.Version13, - Height: 4, - Migration: stmgr.UpgradeActorsV5, - }} - - schedule := stmgr.UpgradeSchedule{} - for _, upgrade := range fullSchedule { - if upgrade.Network > version { - break - } - - schedule = append(schedule, upgrade) - } - - if upgradeHeight > 0 { - schedule[len(schedule)-1].Height = upgradeHeight - } - - return FullNodeOpts{ - Opts: func(nodes []TestFullNode) node.Option { - return node.Override(new(stmgr.UpgradeSchedule), schedule) - }, - } -} - -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 254f87bac58..00000000000 --- a/itests/kit/pledge.go +++ /dev/null @@ -1,88 +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 - toCheck := StartPledge(t, ctx, miner, n, existing, blockNotif) - - for len(toCheck) > 0 { - flushSealingBatches(t, ctx, miner) - - states := map[api.SectorState]int{} - for n := range toCheck { - st, err := miner.SectorsStatus(ctx, n, false) - require.NoError(t, err) - states[st.State]++ - 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 %+v\n", len(toCheck), states) - } -} - -func flushSealingBatches(t *testing.T, ctx context.Context, miner TestMiner) { //nolint:golint - pcb, err := miner.SectorPreCommitFlush(ctx) - require.NoError(t, err) - if pcb != nil { - fmt.Printf("PRECOMMIT BATCH: %+v\n", pcb) - } - - cb, err := miner.SectorCommitFlush(ctx) - require.NoError(t, err) - if cb != nil { - fmt.Printf("COMMIT BATCH: %+v\n", cb) - } -} - -func StartPledge(t *testing.T, ctx context.Context, miner TestMiner, n, existing int, blockNotif <-chan struct{}) map[abi.SectorNumber]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{}{} - } - - return toCheck -} From 8a418bf9828f8f112396ca88d130f1e5be4e198b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 18 Jun 2021 19:45:29 +0100 Subject: [PATCH 50/72] rename {kit2=>kit}. --- itests/api_test.go | 22 +++++----- itests/batch_deal_test.go | 12 +++--- itests/ccupgrade_test.go | 17 ++++---- itests/cli_test.go | 8 ++-- itests/deadlines_test.go | 30 +++++++------- itests/deals_test.go | 52 ++++++++++++------------ itests/gateway_test.go | 40 +++++++++--------- itests/{kit2 => kit}/blockminer.go | 2 +- itests/{kit2 => kit}/client.go | 2 +- itests/{kit2 => kit}/deals.go | 2 +- itests/{kit2 => kit}/deals_state.go | 2 +- itests/{kit2 => kit}/ensemble.go | 2 +- itests/{kit2 => kit}/ensemble_opts.go | 2 +- itests/{kit2 => kit}/ensemble_presets.go | 2 +- itests/{kit2 => kit}/files.go | 2 +- itests/{kit2 => kit}/funds.go | 2 +- itests/{kit2 => kit}/init.go | 2 +- itests/{kit2 => kit}/log.go | 2 +- itests/{kit2 => kit}/mockcli.go | 2 +- itests/{kit2 => kit}/node_full.go | 2 +- itests/{kit2 => kit}/node_miner.go | 2 +- itests/{kit2 => kit}/node_opts.go | 2 +- itests/{kit2 => kit}/node_opts_nv.go | 2 +- itests/{kit2 => kit}/rpc.go | 2 +- itests/multisig_test.go | 12 +++--- itests/paych_api_test.go | 18 ++++---- itests/paych_cli_test.go | 48 +++++++++++----------- itests/sdr_upgrade_test.go | 8 ++-- itests/sector_pledge_test.go | 18 ++++---- itests/sector_terminate_test.go | 12 +++--- itests/tape_test.go | 8 ++-- itests/verifreg_test.go | 10 ++--- itests/wdpost_dispute_test.go | 28 ++++++------- itests/wdpost_test.go | 34 ++++++++-------- 34 files changed, 205 insertions(+), 206 deletions(-) rename itests/{kit2 => kit}/blockminer.go (99%) rename itests/{kit2 => kit}/client.go (99%) rename itests/{kit2 => kit}/deals.go (99%) rename itests/{kit2 => kit}/deals_state.go (98%) rename itests/{kit2 => kit}/ensemble.go (99%) rename itests/{kit2 => kit}/ensemble_opts.go (99%) rename itests/{kit2 => kit}/ensemble_presets.go (99%) rename itests/{kit2 => kit}/files.go (98%) rename itests/{kit2 => kit}/funds.go (98%) rename itests/{kit2 => kit}/init.go (98%) rename itests/{kit2 => kit}/log.go (97%) rename itests/{kit2 => kit}/mockcli.go (99%) rename itests/{kit2 => kit}/node_full.go (99%) rename itests/{kit2 => kit}/node_miner.go (99%) rename itests/{kit2 => kit}/node_opts.go (99%) rename itests/{kit2 => kit}/node_opts_nv.go (99%) rename itests/{kit2 => kit}/rpc.go (99%) diff --git a/itests/api_test.go b/itests/api_test.go index f8567bd2aa7..45c137a8d39 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -12,7 +12,7 @@ import ( 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/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/stretchr/testify/require" ) @@ -21,7 +21,7 @@ func TestAPI(t *testing.T) { runAPITest(t) }) t.Run("rpc", func(t *testing.T) { - runAPITest(t, kit2.ThroughRPC()) + runAPITest(t, kit.ThroughRPC()) }) } @@ -48,7 +48,7 @@ func (ts *apiSuite) testVersion(t *testing.T) { lapi.RunningNodeType = lapi.NodeUnknown }) - full, _, _ := kit2.EnsembleMinimal(t, ts.opts...) + full, _, _ := kit.EnsembleMinimal(t, ts.opts...) v, err := full.Version(context.Background()) require.NoError(t, err) @@ -61,7 +61,7 @@ func (ts *apiSuite) testVersion(t *testing.T) { func (ts *apiSuite) testID(t *testing.T) { ctx := context.Background() - full, _, _ := kit2.EnsembleMinimal(t, ts.opts...) + full, _, _ := kit.EnsembleMinimal(t, ts.opts...) id, err := full.ID(ctx) if err != nil { @@ -73,7 +73,7 @@ func (ts *apiSuite) testID(t *testing.T) { func (ts *apiSuite) testConnectTwo(t *testing.T) { ctx := context.Background() - one, two, _, ens := kit2.EnsembleTwoOne(t, ts.opts...) + one, two, _, ens := kit.EnsembleTwoOne(t, ts.opts...) p, err := one.NetPeers(ctx) require.NoError(t, err) @@ -97,7 +97,7 @@ func (ts *apiSuite) testConnectTwo(t *testing.T) { func (ts *apiSuite) testSearchMsg(t *testing.T) { ctx := context.Background() - full, _, ens := kit2.EnsembleMinimal(t, ts.opts...) + full, _, ens := kit.EnsembleMinimal(t, ts.opts...) senderAddr, err := full.WalletDefaultAddress(ctx) require.NoError(t, err) @@ -127,7 +127,7 @@ func (ts *apiSuite) testSearchMsg(t *testing.T) { func (ts *apiSuite) testMining(t *testing.T) { ctx := context.Background() - full, miner, _ := kit2.EnsembleMinimal(t, ts.opts...) + full, miner, _ := kit.EnsembleMinimal(t, ts.opts...) newHeads, err := full.ChainNotify(ctx) require.NoError(t, err) @@ -138,7 +138,7 @@ func (ts *apiSuite) testMining(t *testing.T) { require.NoError(t, err) require.Equal(t, int64(h1.Height()), int64(baseHeight)) - bm := kit2.NewBlockMiner(t, miner) + bm := kit.NewBlockMiner(t, miner) bm.MineUntilBlock(ctx, full, nil) require.NoError(t, err) @@ -170,7 +170,7 @@ func (ts *apiSuite) testMiningReal(t *testing.T) { func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { ctx := context.Background() - full, genesisMiner, ens := kit2.EnsembleMinimal(t, ts.opts...) + full, genesisMiner, ens := kit.EnsembleMinimal(t, ts.opts...) ens.BeginMining(4 * time.Millisecond) @@ -180,8 +180,8 @@ func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { _, err = full.StateMinerInfo(ctx, gaa, types.EmptyTSK) require.NoError(t, err) - var newMiner kit2.TestMiner - ens.Miner(&newMiner, full, kit2.OwnerAddr(full.DefaultKey)).Start() + var newMiner kit.TestMiner + ens.Miner(&newMiner, full, kit.OwnerAddr(full.DefaultKey)).Start() ta, err := newMiner.ActorAddress(ctx) require.NoError(t, err) diff --git a/itests/batch_deal_test.go b/itests/batch_deal_test.go index 9cc4d7ac130..300a44fa2f3 100644 --- a/itests/batch_deal_test.go +++ b/itests/batch_deal_test.go @@ -10,7 +10,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/markets/storageadapter" "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -18,7 +18,7 @@ import ( ) func TestBatchDealInput(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var ( blockTime = 10 * time.Millisecond @@ -37,7 +37,7 @@ func TestBatchDealInput(t *testing.T) { maxDealsPerMsg := uint64(deals) // Set max deals per publish deals message to maxDealsPerMsg - opts := kit2.ConstructorOpts(node.Options( + opts := kit.ConstructorOpts(node.Options( node.Override( new(*storageadapter.DealPublisher), storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ @@ -56,9 +56,9 @@ func TestBatchDealInput(t *testing.T) { }, nil }), )) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blockTime) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) err := miner.MarketSetAsk(ctx, big.Zero(), big.Zero(), 200, 128, 32<<30) require.NoError(t, err) @@ -87,7 +87,7 @@ func TestBatchDealInput(t *testing.T) { // Starts a deal and waits until it's published runDealTillSeal := func(rseed int) { - res, _, _, err := kit2.CreateImportFile(ctx, client, rseed, piece) + res, _, _, err := kit.CreateImportFile(ctx, client, rseed, piece) require.NoError(t, err) deal := dh.StartDeal(ctx, res.Root, false, dealStartEpoch) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index 2c35b425db5..e9961dc3a98 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -6,16 +6,15 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/itests/kit2" - "github.com/stretchr/testify/require" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit" + + "github.com/stretchr/testify/require" ) func TestCCUpgrade(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() for _, height := range []abi.ChainEpoch{ -1, // before @@ -34,8 +33,8 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { ctx := context.Background() blockTime := 5 * time.Millisecond - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(upgradeHeight)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(upgradeHeight)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blockTime) maddr, err := miner.ActorAddress(ctx) @@ -43,7 +42,7 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { t.Fatal(err) } - CC := abi.SectorNumber(kit2.DefaultPresealsPerBootstrapMiner + 1) + CC := abi.SectorNumber(kit.DefaultPresealsPerBootstrapMiner + 1) Upgraded := CC + 1 miner.PledgeSectors(ctx, 1, 0, nil) @@ -62,7 +61,7 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { err = miner.SectorMarkForUpgrade(ctx, sl[0]) require.NoError(t, err) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) dh.MakeOnlineDeal(context.Background(), 6, false, 0) diff --git a/itests/cli_test.go b/itests/cli_test.go index 5c9cf0f69c1..0bd1ec3b421 100644 --- a/itests/cli_test.go +++ b/itests/cli_test.go @@ -6,16 +6,16 @@ import ( "time" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" ) // TestClient does a basic test to exercise the client CLI commands. func TestClient(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blockTime := 5 * time.Millisecond - client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) - kit2.RunClientTest(t, cli.Commands, client) + kit.RunClientTest(t, cli.Commands, client) } diff --git a/itests/deadlines_test.go b/itests/deadlines_test.go index 3c8303ac021..00c737b7284 100644 --- a/itests/deadlines_test.go +++ b/itests/deadlines_test.go @@ -21,7 +21,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/node/impl" miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" "github.com/ipfs/go-cid" @@ -57,7 +57,7 @@ func TestDeadlineToggling(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_DEADLINE_TOGGLING=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() const sectorsC, sectorsD, sectorsB = 10, 9, 8 @@ -71,22 +71,22 @@ func TestDeadlineToggling(t *testing.T) { defer cancel() var ( - client kit2.TestFullNode - minerA kit2.TestMiner - minerB kit2.TestMiner - minerC kit2.TestMiner - minerD kit2.TestMiner - minerE kit2.TestMiner + client kit.TestFullNode + minerA kit.TestMiner + minerB kit.TestMiner + minerC kit.TestMiner + minerD kit.TestMiner + minerE kit.TestMiner ) - opts := []kit2.NodeOpt{kit2.ConstructorOpts(kit2.NetworkUpgradeAt(network.Version12, upgradeH))} - ens := kit2.NewEnsemble(t, kit2.MockProofs()). + opts := []kit.NodeOpt{kit.ConstructorOpts(kit.NetworkUpgradeAt(network.Version12, upgradeH))} + ens := kit.NewEnsemble(t, kit.MockProofs()). FullNode(&client, opts...). Miner(&minerA, &client, opts...). Start(). InterconnectAll() ens.BeginMining(blocktime) - opts = append(opts, kit2.OwnerAddr(client.DefaultKey)) + opts = append(opts, kit.OwnerAddr(client.DefaultKey)) ens.Miner(&minerB, &client, opts...). Miner(&minerC, &client, opts...). Start() @@ -204,7 +204,7 @@ func TestDeadlineToggling(t *testing.T) { require.NoError(t, err) // first round of miner checks - checkMiner(maddrA, types.NewInt(uint64(ssz)*kit2.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) + checkMiner(maddrA, types.NewInt(uint64(ssz)*kit.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) checkMiner(maddrC, types.NewInt(uint64(ssz)*sectorsC), true, true, types.EmptyTSK) checkMiner(maddrB, types.NewInt(0), false, false, types.EmptyTSK) @@ -231,7 +231,7 @@ func TestDeadlineToggling(t *testing.T) { params := &miner.SectorPreCommitInfo{ Expiration: 2880 * 300, SectorNumber: 22, - SealProof: kit2.TestSpt, + SealProof: kit.TestSpt, SealedCID: cr, SealRandEpoch: head.Height() - 200, @@ -281,7 +281,7 @@ func TestDeadlineToggling(t *testing.T) { } // second round of miner checks - checkMiner(maddrA, types.NewInt(uint64(ssz)*kit2.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) + checkMiner(maddrA, types.NewInt(uint64(ssz)*kit.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) checkMiner(maddrC, types.NewInt(0), true, true, types.EmptyTSK) checkMiner(maddrB, types.NewInt(uint64(ssz)*sectorsB), true, true, types.EmptyTSK) checkMiner(maddrD, types.NewInt(uint64(ssz)*sectorsD), true, true, types.EmptyTSK) @@ -352,7 +352,7 @@ func TestDeadlineToggling(t *testing.T) { build.Clock.Sleep(blocktime) } - checkMiner(maddrA, types.NewInt(uint64(ssz)*kit2.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) + checkMiner(maddrA, types.NewInt(uint64(ssz)*kit.DefaultPresealsPerBootstrapMiner), true, true, types.EmptyTSK) checkMiner(maddrC, types.NewInt(0), true, true, types.EmptyTSK) checkMiner(maddrB, types.NewInt(0), true, true, types.EmptyTSK) checkMiner(maddrD, types.NewInt(0), false, false, types.EmptyTSK) diff --git a/itests/deals_test.go b/itests/deals_test.go index af0ef68c470..3903968d44d 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -14,7 +14,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/markets/storageadapter" "github.com/filecoin-project/lotus/node" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" @@ -27,7 +27,7 @@ func TestDealCyclesConcurrent(t *testing.T) { t.Skip("skipping test in short mode") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blockTime := 10 * time.Millisecond @@ -37,9 +37,9 @@ func TestDealCyclesConcurrent(t *testing.T) { startEpoch := abi.ChainEpoch(2 << 12) runTest := func(t *testing.T, n int, fastRetrieval bool, carExport bool) { - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blockTime) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) runConcurrentDeals(t, dh, fullDealCyclesOpts{ n: n, @@ -67,7 +67,7 @@ type fullDealCyclesOpts struct { startEpoch abi.ChainEpoch } -func runConcurrentDeals(t *testing.T, dh *kit2.DealHarness, opts fullDealCyclesOpts) { +func runConcurrentDeals(t *testing.T, dh *kit.DealHarness, opts fullDealCyclesOpts) { errgrp, _ := errgroup.WithContext(context.Background()) for i := 0; i < opts.n; i++ { i := i @@ -81,7 +81,7 @@ func runConcurrentDeals(t *testing.T, dh *kit2.DealHarness, opts fullDealCyclesO }() deal, res, inPath := dh.MakeOnlineDeal(context.Background(), 5+i, opts.fastRetrieval, opts.startEpoch) outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, opts.carExport) - kit2.AssertFilesEqual(t, inPath, outPath) + kit.AssertFilesEqual(t, inPath, outPath) return nil }) } @@ -93,13 +93,13 @@ func TestDealsWithSealingAndRPC(t *testing.T) { t.Skip("skipping test in short mode") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var blockTime = 1 * time.Second - client, miner, ens := kit2.EnsembleMinimal(t, kit2.ThroughRPC()) // no mock proofs. + client, miner, ens := kit.EnsembleMinimal(t, kit.ThroughRPC()) // no mock proofs. ens.InterconnectAll().BeginMining(blockTime) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) t.Run("stdretrieval", func(t *testing.T) { runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1}) @@ -123,7 +123,7 @@ func TestPublishDealsBatching(t *testing.T) { startEpoch = abi.ChainEpoch(2 << 12) ) - kit2.QuietMiningLogs() + kit.QuietMiningLogs() opts := node.Override(new(*storageadapter.DealPublisher), storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ @@ -132,10 +132,10 @@ func TestPublishDealsBatching(t *testing.T) { }), ) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ConstructorOpts(opts)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ConstructorOpts(opts)) ens.InterconnectAll().BeginMining(10 * time.Millisecond) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) // Starts a deal and waits until it's published runDealTillPublish := func(rseed int) { @@ -210,23 +210,23 @@ func TestFirstDealEnablesMining(t *testing.T) { t.Skip("skipping test in short mode") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var ( - client kit2.TestFullNode - genMiner kit2.TestMiner // bootstrap - provider kit2.TestMiner // no sectors, will need to create one + client kit.TestFullNode + genMiner kit.TestMiner // bootstrap + provider kit.TestMiner // no sectors, will need to create one ) - ens := kit2.NewEnsemble(t, kit2.MockProofs()) + ens := kit.NewEnsemble(t, kit.MockProofs()) ens.FullNode(&client) ens.Miner(&genMiner, &client) - ens.Miner(&provider, &client, kit2.PresealSectors(0)) + ens.Miner(&provider, &client, kit.PresealSectors(0)) ens.Start().InterconnectAll().BeginMining(50 * time.Millisecond) ctx := context.Background() - dh := kit2.NewDealHarness(t, &client, &provider) + dh := kit.NewDealHarness(t, &client, &provider) ref, _ := client.CreateImportFile(ctx, 5, 0) @@ -241,7 +241,7 @@ func TestFirstDealEnablesMining(t *testing.T) { providerMined := make(chan struct{}) go func() { - _ = client.WaitTillChain(ctx, kit2.BlockMinedBy(provider.ActorAddr)) + _ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) close(providerMined) }() @@ -266,10 +266,10 @@ func TestOfflineDealFlow(t *testing.T) { runTest := func(t *testing.T, fastRet bool) { ctx := context.Background() - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blocktime) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) // Create a random file and import on the client. res, inFile := client.CreateImportFile(ctx, 1, 0) @@ -333,7 +333,7 @@ func TestOfflineDealFlow(t *testing.T) { // Retrieve the deal outFile := dh.PerformRetrieval(ctx, proposalCid, rootCid, false) - kit2.AssertFilesEqual(t, inFile, outFile) + kit.AssertFilesEqual(t, inFile, outFile) } t.Run("stdretrieval", func(t *testing.T) { runTest(t, false) }) @@ -345,14 +345,14 @@ func TestZeroPricePerByteRetrieval(t *testing.T) { t.Skip("skipping test in short mode") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var ( blockTime = 10 * time.Millisecond startEpoch = abi.ChainEpoch(2 << 12) ) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blockTime) ctx := context.Background() @@ -364,7 +364,7 @@ func TestZeroPricePerByteRetrieval(t *testing.T) { err = miner.MarketSetRetrievalAsk(ctx, ask) require.NoError(t, err) - dh := kit2.NewDealHarness(t, client, miner) + dh := kit.NewDealHarness(t, client, miner) runConcurrentDeals(t, dh, fullDealCyclesOpts{ n: 1, startEpoch: startEpoch, diff --git a/itests/gateway_test.go b/itests/gateway_test.go index 36df41d54f3..dfbe5bed578 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/filecoin-project/lotus/itests/kit" "github.com/stretchr/testify/require" "golang.org/x/xerrors" @@ -23,7 +24,6 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/cli" "github.com/filecoin-project/lotus/gateway" - "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/node" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" @@ -44,7 +44,7 @@ func init() { // TestGatewayWalletMsig tests that API calls to wallet and msig can be made on a lite // node that is connected through a gateway to a full API node func TestGatewayWalletMsig(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -176,7 +176,7 @@ func TestGatewayWalletMsig(t *testing.T) { // TestGatewayMsigCLI tests that msig CLI calls can be made // on a lite node that is connected through a gateway to a full API node func TestGatewayMsigCLI(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -188,7 +188,7 @@ func TestGatewayMsigCLI(t *testing.T) { } func TestGatewayDealFlow(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -202,26 +202,26 @@ func TestGatewayDealFlow(t *testing.T) { // so that the deal starts sealing in time dealStartEpoch := abi.ChainEpoch(2 << 12) - dh := kit2.NewDealHarness(t, nodes.lite, nodes.miner) + dh := kit.NewDealHarness(t, nodes.lite, nodes.miner) dealCid, res, _ := dh.MakeOnlineDeal(ctx, 6, false, dealStartEpoch) dh.PerformRetrieval(ctx, dealCid, res.Root, false) } func TestGatewayCLIDealFlow(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) defer nodes.closer() - kit2.RunClientTest(t, cli.Commands, nodes.lite) + kit.RunClientTest(t, cli.Commands, nodes.lite) } type testNodes struct { - lite *kit2.TestFullNode - full *kit2.TestFullNode - miner *kit2.TestMiner + lite *kit.TestFullNode + full *kit.TestFullNode + miner *kit.TestMiner closer jsonrpc.ClientCloser } @@ -259,9 +259,9 @@ func startNodes( var closer jsonrpc.ClientCloser var ( - full *kit2.TestFullNode - miner *kit2.TestMiner - lite kit2.TestFullNode + full *kit.TestFullNode + miner *kit.TestMiner + lite kit.TestFullNode ) // - Create one full node and one lite node @@ -270,8 +270,8 @@ func startNodes( // - Connect lite node -> gateway server -> full node // create the full node and the miner. - var ens *kit2.Ensemble - full, miner, ens = kit2.EnsembleMinimal(t, kit2.MockProofs()) + var ens *kit.Ensemble + full, miner, ens = kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blocktime) // Create a gateway server in front of the full node @@ -279,7 +279,7 @@ func startNodes( handler, err := gateway.Handler(gwapi) require.NoError(t, err) - srv, _ := kit2.CreateRPCServer(t, handler) + srv, _ := kit.CreateRPCServer(t, handler) // Create a gateway client API that connects to the gateway server var gapi api.Gateway @@ -287,9 +287,9 @@ func startNodes( require.NoError(t, err) ens.FullNode(&lite, - kit2.LiteNode(), - kit2.ThroughRPC(), - kit2.ConstructorOpts( + kit.LiteNode(), + kit.ThroughRPC(), + kit.ConstructorOpts( node.Override(new(api.Gateway), gapi), ), ).Start().InterconnectAll() @@ -297,7 +297,7 @@ func startNodes( return &testNodes{lite: &lite, full: full, miner: miner, closer: closer} } -func sendFunds(ctx context.Context, fromNode *kit2.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { +func sendFunds(ctx context.Context, fromNode *kit.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { msg := &types.Message{ From: fromAddr, To: toAddr, diff --git a/itests/kit2/blockminer.go b/itests/kit/blockminer.go similarity index 99% rename from itests/kit2/blockminer.go rename to itests/kit/blockminer.go index 04d425dd623..2c9bd47c6cf 100644 --- a/itests/kit2/blockminer.go +++ b/itests/kit/blockminer.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/client.go b/itests/kit/client.go similarity index 99% rename from itests/kit2/client.go rename to itests/kit/client.go index 78a7034feca..3a16f520407 100644 --- a/itests/kit2/client.go +++ b/itests/kit/client.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/deals.go b/itests/kit/deals.go similarity index 99% rename from itests/kit2/deals.go rename to itests/kit/deals.go index 2e015a9c721..98e6efee23b 100644 --- a/itests/kit2/deals.go +++ b/itests/kit/deals.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/deals_state.go b/itests/kit/deals_state.go similarity index 98% rename from itests/kit2/deals_state.go rename to itests/kit/deals_state.go index be3a9e4db5b..617a6d28e8d 100644 --- a/itests/kit2/deals_state.go +++ b/itests/kit/deals_state.go @@ -1,4 +1,4 @@ -package kit2 +package kit type TestDealState int diff --git a/itests/kit2/ensemble.go b/itests/kit/ensemble.go similarity index 99% rename from itests/kit2/ensemble.go rename to itests/kit/ensemble.go index 44580920f5c..1accdbd61ca 100644 --- a/itests/kit2/ensemble.go +++ b/itests/kit/ensemble.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "bytes" diff --git a/itests/kit2/ensemble_opts.go b/itests/kit/ensemble_opts.go similarity index 99% rename from itests/kit2/ensemble_opts.go rename to itests/kit/ensemble_opts.go index 8c6d66d9e13..9233aadd8d4 100644 --- a/itests/kit2/ensemble_opts.go +++ b/itests/kit/ensemble_opts.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "time" diff --git a/itests/kit2/ensemble_presets.go b/itests/kit/ensemble_presets.go similarity index 99% rename from itests/kit2/ensemble_presets.go rename to itests/kit/ensemble_presets.go index 28a4b5d9224..7cae12a6885 100644 --- a/itests/kit2/ensemble_presets.go +++ b/itests/kit/ensemble_presets.go @@ -1,4 +1,4 @@ -package kit2 +package kit import "testing" diff --git a/itests/kit2/files.go b/itests/kit/files.go similarity index 98% rename from itests/kit2/files.go rename to itests/kit/files.go index 1e1509858fe..48592b51835 100644 --- a/itests/kit2/files.go +++ b/itests/kit/files.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "bytes" diff --git a/itests/kit2/funds.go b/itests/kit/funds.go similarity index 98% rename from itests/kit2/funds.go rename to itests/kit/funds.go index b2996335398..417cf9ce1b1 100644 --- a/itests/kit2/funds.go +++ b/itests/kit/funds.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/init.go b/itests/kit/init.go similarity index 98% rename from itests/kit2/init.go rename to itests/kit/init.go index dfc5a13f201..8df4922b864 100644 --- a/itests/kit2/init.go +++ b/itests/kit/init.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "fmt" diff --git a/itests/kit2/log.go b/itests/kit/log.go similarity index 97% rename from itests/kit2/log.go rename to itests/kit/log.go index f255d063955..3dce3af9d0c 100644 --- a/itests/kit2/log.go +++ b/itests/kit/log.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "github.com/filecoin-project/lotus/lib/lotuslog" diff --git a/itests/kit2/mockcli.go b/itests/kit/mockcli.go similarity index 99% rename from itests/kit2/mockcli.go rename to itests/kit/mockcli.go index 592c9733379..c0f21892033 100644 --- a/itests/kit2/mockcli.go +++ b/itests/kit/mockcli.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "bytes" diff --git a/itests/kit2/node_full.go b/itests/kit/node_full.go similarity index 99% rename from itests/kit2/node_full.go rename to itests/kit/node_full.go index 3dadb4d8dff..83586e1881e 100644 --- a/itests/kit2/node_full.go +++ b/itests/kit/node_full.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/node_miner.go b/itests/kit/node_miner.go similarity index 99% rename from itests/kit2/node_miner.go rename to itests/kit/node_miner.go index 1cd65e20e7c..d3f0d2e3c9d 100644 --- a/itests/kit2/node_miner.go +++ b/itests/kit/node_miner.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/node_opts.go b/itests/kit/node_opts.go similarity index 99% rename from itests/kit2/node_opts.go rename to itests/kit/node_opts.go index b2dacd3cc23..c36ca3e2651 100644 --- a/itests/kit2/node_opts.go +++ b/itests/kit/node_opts.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "github.com/filecoin-project/go-state-types/abi" diff --git a/itests/kit2/node_opts_nv.go b/itests/kit/node_opts_nv.go similarity index 99% rename from itests/kit2/node_opts_nv.go rename to itests/kit/node_opts_nv.go index 5ffd94f5ed9..d4c84b4f157 100644 --- a/itests/kit2/node_opts_nv.go +++ b/itests/kit/node_opts_nv.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/kit2/rpc.go b/itests/kit/rpc.go similarity index 99% rename from itests/kit2/rpc.go rename to itests/kit/rpc.go index 873b64257ad..dab45df0773 100644 --- a/itests/kit2/rpc.go +++ b/itests/kit/rpc.go @@ -1,4 +1,4 @@ -package kit2 +package kit import ( "context" diff --git a/itests/multisig_test.go b/itests/multisig_test.go index 9b1f5967389..0afdf5f0a59 100644 --- a/itests/multisig_test.go +++ b/itests/multisig_test.go @@ -11,25 +11,25 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/stretchr/testify/require" ) // TestMultisig does a basic test to exercise the multisig CLI commands func TestMultisig(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blockTime := 5 * time.Millisecond - client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) runMultisigTests(t, client) } -func runMultisigTests(t *testing.T, clientNode *kit2.TestFullNode) { +func runMultisigTests(t *testing.T, clientNode *kit.TestFullNode) { // Create mock CLI ctx := context.Background() - mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) clientCLI := mockCLI.Client(clientNode.ListenAddr) // Create some wallets on the node to use for testing multisig @@ -40,7 +40,7 @@ func runMultisigTests(t *testing.T, clientNode *kit2.TestFullNode) { walletAddrs = append(walletAddrs, addr) - kit2.SendFunds(ctx, t, clientNode, addr, types.NewInt(1e15)) + kit.SendFunds(ctx, t, clientNode, addr, types.NewInt(1e15)) } // Create an msig with three of the addresses and threshold of two sigs diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go index 86a156790dd..668eb14aab5 100644 --- a/itests/paych_api_test.go +++ b/itests/paych_api_test.go @@ -7,6 +7,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/itests/kit" "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" @@ -23,22 +24,21 @@ import ( "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit2" ) func TestPaymentChannelsAPI(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() ctx := context.Background() blockTime := 5 * time.Millisecond var ( - paymentCreator kit2.TestFullNode - paymentReceiver kit2.TestFullNode - miner kit2.TestMiner + paymentCreator kit.TestFullNode + paymentReceiver kit.TestFullNode + miner kit.TestMiner ) - ens := kit2.NewEnsemble(t, kit2.MockProofs()). + ens := kit.NewEnsemble(t, kit.MockProofs()). FullNode(&paymentCreator). FullNode(&paymentReceiver). Miner(&miner, &paymentCreator). @@ -51,7 +51,7 @@ func TestPaymentChannelsAPI(t *testing.T) { receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1) require.NoError(t, err) - kit2.SendFunds(ctx, t, &paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) + kit.SendFunds(ctx, t, &paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) // setup the payment channel createrAddr, err := paymentCreator.WalletDefaultAddress(ctx) @@ -200,7 +200,7 @@ func TestPaymentChannelsAPI(t *testing.T) { require.EqualValues(t, abi.NewTokenAmount(expectedRefund), delta, "did not send correct funds from creator: expected %d, got %d", expectedRefund, delta) } -func waitForBlocks(ctx context.Context, t *testing.T, bm *kit2.BlockMiner, paymentReceiver kit2.TestFullNode, receiverAddr address.Address, count int) { +func waitForBlocks(ctx context.Context, t *testing.T, bm *kit.BlockMiner, paymentReceiver kit.TestFullNode, receiverAddr address.Address, count int) { // We need to add null blocks in batches, if we add too many the chain can't sync batchSize := 60 for i := 0; i < count; i += batchSize { @@ -225,7 +225,7 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *kit2.BlockMiner, payme } } -func waitForMessage(ctx context.Context, t *testing.T, paymentCreator kit2.TestFullNode, msgCid cid.Cid, duration time.Duration, desc string) *api.MsgLookup { +func waitForMessage(ctx context.Context, t *testing.T, paymentCreator kit.TestFullNode, msgCid cid.Cid, duration time.Duration, desc string) *api.MsgLookup { ctx, cancel := context.WithTimeout(ctx, duration) defer cancel() diff --git a/itests/paych_cli_test.go b/itests/paych_cli_test.go index 84ccee95abb..8a069044973 100644 --- a/itests/paych_cli_test.go +++ b/itests/paych_cli_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -37,19 +37,19 @@ func init() { // commands func TestPaymentChannelsBasic(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() var ( - paymentCreator kit2.TestFullNode - paymentReceiver kit2.TestFullNode + paymentCreator kit.TestFullNode + paymentReceiver kit.TestFullNode ) creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) @@ -94,18 +94,18 @@ type voucherSpec struct { // TestPaymentChannelStatus tests the payment channel status CLI command func TestPaymentChannelStatus(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() var ( - paymentCreator kit2.TestFullNode - paymentReceiver kit2.TestFullNode + paymentCreator kit.TestFullNode + paymentReceiver kit.TestFullNode ) creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych status-by-from-to @@ -174,18 +174,18 @@ func TestPaymentChannelStatus(t *testing.T) { // channel voucher commands func TestPaymentChannelVouchers(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() var ( - paymentCreator kit2.TestFullNode - paymentReceiver kit2.TestFullNode + paymentCreator kit.TestFullNode + paymentReceiver kit.TestFullNode ) creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) @@ -306,18 +306,18 @@ func TestPaymentChannelVouchers(t *testing.T) { // is greater than what's left in the channel, voucher create fails func TestPaymentChannelVoucherCreateShortfall(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() var ( - paymentCreator kit2.TestFullNode - paymentReceiver kit2.TestFullNode + paymentCreator kit.TestFullNode + paymentReceiver kit.TestFullNode ) creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit2.NewMockCLI(ctx, t, cli.Commands) + mockCLI := kit.NewMockCLI(ctx, t, cli.Commands) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych add-funds @@ -385,7 +385,7 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) { } // waitForHeight waits for the node to reach the given chain epoch -func waitForHeight(ctx context.Context, t *testing.T, node kit2.TestFullNode, height abi.ChainEpoch) { +func waitForHeight(ctx context.Context, t *testing.T, node kit.TestFullNode, height abi.ChainEpoch) { atHeight := make(chan struct{}) chainEvents := events.NewEvents(ctx, node) err := chainEvents.ChainAt(func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error { @@ -403,7 +403,7 @@ func waitForHeight(ctx context.Context, t *testing.T, node kit2.TestFullNode, he } // getPaychState gets the state of the payment channel with the given address -func getPaychState(ctx context.Context, t *testing.T, node kit2.TestFullNode, chAddr address.Address) paych.State { +func getPaychState(ctx context.Context, t *testing.T, node kit.TestFullNode, chAddr address.Address) paych.State { act, err := node.StateGetActor(ctx, chAddr, types.EmptyTSK) require.NoError(t, err) @@ -414,10 +414,10 @@ func getPaychState(ctx context.Context, t *testing.T, node kit2.TestFullNode, ch return chState } -func startPaychCreatorReceiverMiner(ctx context.Context, t *testing.T, paymentCreator *kit2.TestFullNode, paymentReceiver *kit2.TestFullNode, blocktime time.Duration) (address.Address, address.Address) { - var miner kit2.TestMiner - opts := kit2.ThroughRPC() - kit2.NewEnsemble(t, kit2.MockProofs()). +func startPaychCreatorReceiverMiner(ctx context.Context, t *testing.T, paymentCreator *kit.TestFullNode, paymentReceiver *kit.TestFullNode, blocktime time.Duration) (address.Address, address.Address) { + var miner kit.TestMiner + opts := kit.ThroughRPC() + kit.NewEnsemble(t, kit.MockProofs()). FullNode(paymentCreator, opts). FullNode(paymentReceiver, opts). Miner(&miner, paymentCreator). @@ -428,7 +428,7 @@ func startPaychCreatorReceiverMiner(ctx context.Context, t *testing.T, paymentCr // Send some funds to the second node receiverAddr, err := paymentReceiver.WalletDefaultAddress(ctx) require.NoError(t, err) - kit2.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) + kit.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) // Get the first node's address creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx) diff --git a/itests/sdr_upgrade_test.go b/itests/sdr_upgrade_test.go index 008c2ce612d..3aa685b0933 100644 --- a/itests/sdr_upgrade_test.go +++ b/itests/sdr_upgrade_test.go @@ -10,14 +10,14 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" bminer "github.com/filecoin-project/lotus/miner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSDRUpgrade(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() // oldDelay := policy.GetPreCommitChallengeDelay() // policy.SetPreCommitChallengeDelay(5) @@ -30,8 +30,8 @@ func TestSDRUpgrade(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - opts := kit2.ConstructorOpts(kit2.SDRUpgradeAt(500, 1000)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.SDRUpgradeAt(500, 1000)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll() build.Clock.Sleep(time.Second) diff --git a/itests/sector_pledge_test.go b/itests/sector_pledge_test.go index 8e87f265827..d911dcb68c4 100644 --- a/itests/sector_pledge_test.go +++ b/itests/sector_pledge_test.go @@ -7,16 +7,16 @@ import ( "testing" "time" + "github.com/filecoin-project/lotus/itests/kit" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/itests/kit2" ) func TestPledgeSectors(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blockTime := 50 * time.Millisecond @@ -24,7 +24,7 @@ func TestPledgeSectors(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + _, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blockTime) miner.PledgeSectors(ctx, nSectors, 0, nil) @@ -54,11 +54,11 @@ func TestPledgeBatching(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(-1)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blockTime) - client.WaitTillChain(ctx, kit2.HeightAtLeast(10)) + client.WaitTillChain(ctx, kit.HeightAtLeast(10)) toCheck := miner.StartPledge(ctx, nSectors, 0, nil) @@ -111,11 +111,11 @@ func TestPledgeBeforeNv13(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(1000000000)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(1000000000)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) - client.WaitTillChain(ctx, kit2.HeightAtLeast(10)) + client.WaitTillChain(ctx, kit.HeightAtLeast(10)) toCheck := miner.StartPledge(ctx, nSectors, 0, nil) diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go index faf12228c9e..94d438437c5 100644 --- a/itests/sector_terminate_test.go +++ b/itests/sector_terminate_test.go @@ -10,7 +10,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/stretchr/testify/require" ) @@ -19,7 +19,7 @@ func TestTerminate(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() const blocktime = 2 * time.Millisecond @@ -28,8 +28,8 @@ func TestTerminate(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(-1)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) @@ -57,7 +57,7 @@ func TestTerminate(t *testing.T) { waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) } @@ -140,7 +140,7 @@ loop: waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) diff --git a/itests/tape_test.go b/itests/tape_test.go index 6fb3def15cf..08970152fce 100644 --- a/itests/tape_test.go +++ b/itests/tape_test.go @@ -10,13 +10,13 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/stmgr" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/node" "github.com/stretchr/testify/require" ) func TestTapeFix(t *testing.T) { - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var blocktime = 2 * time.Millisecond @@ -42,8 +42,8 @@ func testTapeFix(t *testing.T, blocktime time.Duration, after bool) { }) } - nopts := kit2.ConstructorOpts(node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)) - _, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), nopts) + nopts := kit.ConstructorOpts(node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)) + _, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), nopts) ens.InterconnectAll().BeginMining(blocktime) sid, err := miner.PledgeSector(ctx) diff --git a/itests/verifreg_test.go b/itests/verifreg_test.go index 108da6ecfe3..28a72263e57 100644 --- a/itests/verifreg_test.go +++ b/itests/verifreg_test.go @@ -11,6 +11,7 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/itests/kit" verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" "github.com/stretchr/testify/require" @@ -18,7 +19,6 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit2" "github.com/filecoin-project/lotus/node/impl" ) @@ -39,10 +39,10 @@ func TestVerifiedClientTopUp(t *testing.T) { bal, err := types.ParseFIL("100fil") require.NoError(t, err) - node, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), - kit2.RootVerifier(rootKey, abi.NewTokenAmount(bal.Int64())), - kit2.Account(verifierKey, abi.NewTokenAmount(bal.Int64())), // assign some balance to the verifier so they can send an AddClient message. - kit2.ConstructorOpts(kit2.InstantaneousNetworkVersion(nv))) + node, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), + kit.RootVerifier(rootKey, abi.NewTokenAmount(bal.Int64())), + kit.Account(verifierKey, abi.NewTokenAmount(bal.Int64())), // assign some balance to the verifier so they can send an AddClient message. + kit.ConstructorOpts(kit.InstantaneousNetworkVersion(nv))) ens.InterconnectAll().BeginMining(blockTime) diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index 49b41c7e05c..742972fc654 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -15,7 +15,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors" minerActor "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" proof3 "github.com/filecoin-project/specs-actors/v3/actors/runtime/proof" "github.com/stretchr/testify/require" ) @@ -25,7 +25,7 @@ func TestWindowPostDispute(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 2 * time.Millisecond @@ -33,20 +33,20 @@ func TestWindowPostDispute(t *testing.T) { defer cancel() var ( - client kit2.TestFullNode - chainMiner kit2.TestMiner - evilMiner kit2.TestMiner + client kit.TestFullNode + chainMiner kit.TestMiner + evilMiner kit.TestMiner ) // First, we configure two miners. After sealing, we're going to turn off the first miner so // it doesn't submit proofs. // // Then we're going to manually submit bad proofs. - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) - ens := kit2.NewEnsemble(t, kit2.MockProofs()). + opts := kit.ConstructorOpts(kit.LatestActorsAt(-1)) + ens := kit.NewEnsemble(t, kit.MockProofs()). FullNode(&client, opts). Miner(&chainMiner, &client, opts). - Miner(&evilMiner, &client, opts, kit2.PresealSectors(0)). + Miner(&evilMiner, &client, opts, kit.PresealSectors(0)). Start() { @@ -87,7 +87,7 @@ func TestWindowPostDispute(t *testing.T) { waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 t.Logf("End for head.Height > %d", waitUntil) - ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) p, err := client.StateMinerPower(ctx, evilMinerAddr, types.EmptyTSK) @@ -232,15 +232,15 @@ func TestWindowPostDisputeFails(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() blocktime := 2 * time.Millisecond ctx, cancel := context.WithCancel(context.Background()) defer cancel() - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(-1)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) defaultFrom, err := client.WalletDefaultAddress(ctx) @@ -260,12 +260,12 @@ func TestWindowPostDisputeFails(t *testing.T) { waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 t.Logf("End for head.Height > %d", waitUntil) - ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) ssz, err := miner.ActorSectorSize(ctx, maddr) require.NoError(t, err) - expectedPower := types.NewInt(uint64(ssz) * (kit2.DefaultPresealsPerBootstrapMiner + 10)) + expectedPower := types.NewInt(uint64(ssz) * (kit.DefaultPresealsPerBootstrapMiner + 10)) p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index 608c377cabd..8a4b8ec239f 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -18,7 +18,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/lotus/itests/kit2" + "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/node/impl" ) @@ -27,7 +27,7 @@ func TestWindowedPost(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var ( blocktime = 2 * time.Millisecond @@ -50,8 +50,8 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, ctx, cancel := context.WithCancel(context.Background()) defer cancel() - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(upgradeHeight)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(upgradeHeight)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) miner.PledgeSectors(ctx, nSectors, 0, nil) @@ -69,7 +69,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) @@ -79,7 +79,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, require.NoError(t, err) require.Equal(t, p.MinerPower, p.TotalPower) - require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+kit2.DefaultPresealsPerBootstrapMiner))) + require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+kit.DefaultPresealsPerBootstrapMiner))) t.Log("Drop some sectors") @@ -145,7 +145,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil = di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - ts = client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts = client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) @@ -154,7 +154,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, require.Equal(t, p.MinerPower, p.TotalPower) sectors := p.MinerPower.RawBytePower.Uint64() / uint64(ssz) - require.Equal(t, nSectors+kit2.DefaultPresealsPerBootstrapMiner-3, int(sectors)) // -3 just removed sectors + require.Equal(t, nSectors+kit.DefaultPresealsPerBootstrapMiner-3, int(sectors)) // -3 just removed sectors t.Log("Recover one sector") @@ -167,7 +167,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil = di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d", waitUntil) - ts = client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts = client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) @@ -176,7 +176,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, require.Equal(t, p.MinerPower, p.TotalPower) sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz) - require.Equal(t, nSectors+kit2.DefaultPresealsPerBootstrapMiner-2, int(sectors)) // -2 not recovered sectors + require.Equal(t, nSectors+kit.DefaultPresealsPerBootstrapMiner-2, int(sectors)) // -2 not recovered sectors // pledge a sector after recovery @@ -190,7 +190,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 t.Logf("End for head.Height > %d\n", waitUntil) - ts := client.WaitTillChain(ctx, kit2.HeightAtLeast(waitUntil)) + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) } @@ -200,7 +200,7 @@ func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, require.Equal(t, p.MinerPower, p.TotalPower) sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz) - require.Equal(t, nSectors+kit2.DefaultPresealsPerBootstrapMiner-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged + require.Equal(t, nSectors+kit.DefaultPresealsPerBootstrapMiner-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged } func TestWindowPostBaseFeeNoBurn(t *testing.T) { @@ -208,7 +208,7 @@ func TestWindowPostBaseFeeNoBurn(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() var ( blocktime = 2 * time.Millisecond @@ -221,7 +221,7 @@ func TestWindowPostBaseFeeNoBurn(t *testing.T) { och := build.UpgradeClausHeight build.UpgradeClausHeight = 10 - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs()) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) @@ -264,15 +264,15 @@ func TestWindowPostBaseFeeBurn(t *testing.T) { t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") } - kit2.QuietMiningLogs() + kit.QuietMiningLogs() ctx, cancel := context.WithCancel(context.Background()) defer cancel() blocktime := 2 * time.Millisecond - opts := kit2.ConstructorOpts(kit2.LatestActorsAt(-1)) - client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts) + opts := kit.ConstructorOpts(kit.LatestActorsAt(-1)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) From 7ee184e965d3dce7dc9790487102ada932f3e4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 11:56:10 +0100 Subject: [PATCH 51/72] fix lotus-storage-miner tests. --- cmd/lotus-storage-miner/actor_test.go | 62 +++++-------------------- cmd/lotus-storage-miner/allinfo_test.go | 24 +++------- 2 files changed, 18 insertions(+), 68 deletions(-) diff --git a/cmd/lotus-storage-miner/actor_test.go b/cmd/lotus-storage-miner/actor_test.go index 7f36812bc01..073a8305988 100644 --- a/cmd/lotus-storage-miner/actor_test.go +++ b/cmd/lotus-storage-miner/actor_test.go @@ -10,14 +10,13 @@ import ( "testing" "time" - logging "github.com/ipfs/go-log/v2" + "github.com/filecoin-project/go-state-types/network" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/itests/kit" @@ -32,36 +31,21 @@ func TestWorkerKeyChange(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _ = logging.SetLogLevel("*", "INFO") - - policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) - policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) - policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) - kit.QuietMiningLogs() blocktime := 1 * time.Millisecond - - clients, miners := kit.MockMinerBuilder(t, - []kit.FullNodeOpts{kit.FullNodeWithLatestActorsAt(-1), kit.FullNodeWithLatestActorsAt(-1)}, - kit.OneMiner) - - client1 := clients[0] - client2 := clients[1] - - // Connect the nodes. - addrinfo, err := client1.NetAddrsListen(ctx) - require.NoError(t, err) - err = client2.NetConnect(ctx, addrinfo) - require.NoError(t, err) + client1, client2, miner, ens := kit.EnsembleTwoOne(t, kit.MockProofs(), + kit.ConstructorOpts(kit.InstantaneousNetworkVersion(network.Version13)), + ) + ens.InterconnectAll().BeginMining(blocktime) output := bytes.NewBuffer(nil) run := func(cmd *cli.Command, args ...string) error { app := cli.NewApp() app.Metadata = map[string]interface{}{ "repoType": repo.StorageMiner, - "testnode-full": clients[0], - "testnode-storage": miners[0], + "testnode-full": client1, + "testnode-storage": miner, } app.Writer = output api.RunningNodeType = api.NodeMiner @@ -78,9 +62,6 @@ func TestWorkerKeyChange(t *testing.T) { return cmd.Action(cctx) } - // start mining - kit.ConnectAndStartMining(t, blocktime, miners[0], client1, client2) - newKey, err := client1.WalletNew(ctx, types.KTBLS) require.NoError(t, err) @@ -105,14 +86,8 @@ func TestWorkerKeyChange(t *testing.T) { require.Error(t, run(actorConfirmChangeWorker, "--really-do-it", newKey.String())) output.Reset() - for { - head, err := client1.ChainHead(ctx) - require.NoError(t, err) - if head.Height() >= abi.ChainEpoch(targetEpoch) { - break - } - build.Clock.Sleep(10 * blocktime) - } + client1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(targetEpoch))) + require.NoError(t, run(actorConfirmChangeWorker, "--really-do-it", newKey.String())) output.Reset() @@ -121,23 +96,8 @@ func TestWorkerKeyChange(t *testing.T) { // Wait for finality (worker key switch). targetHeight := head.Height() + policy.ChainFinality - for { - head, err := client1.ChainHead(ctx) - require.NoError(t, err) - if head.Height() >= targetHeight { - break - } - build.Clock.Sleep(10 * blocktime) - } + client1.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight)) // Make sure the other node can catch up. - for i := 0; i < 20; i++ { - head, err := client2.ChainHead(ctx) - require.NoError(t, err) - if head.Height() >= targetHeight { - return - } - build.Clock.Sleep(10 * blocktime) - } - t.Fatal("failed to reach target epoch on the second miner") + client2.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight)) } diff --git a/cmd/lotus-storage-miner/allinfo_test.go b/cmd/lotus-storage-miner/allinfo_test.go index cbe65524e11..f65c10bd8cc 100644 --- a/cmd/lotus-storage-miner/allinfo_test.go +++ b/cmd/lotus-storage-miner/allinfo_test.go @@ -7,13 +7,9 @@ import ( "time" "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/node/impl" - logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/node/repo" @@ -24,12 +20,6 @@ func TestMinerAllInfo(t *testing.T) { t.Skip("skipping test in short mode") } - _ = logging.SetLogLevel("*", "INFO") - - policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) - policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) - policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) - _test = true kit.QuietMiningLogs() @@ -40,16 +30,15 @@ func TestMinerAllInfo(t *testing.T) { policy.SetPreCommitChallengeDelay(oldDelay) }) - n, sn := kit.Builder(t, kit.OneFull, kit.OneMiner) - client, miner := n[0].FullNode, sn[0] - kit.ConnectAndStartMining(t, time.Second, miner, client.(*impl.FullNodeAPI)) + client, miner, ens := kit.EnsembleMinimal(t) + ens.InterconnectAll().BeginMining(time.Second) run := func(t *testing.T) { app := cli.NewApp() app.Metadata = map[string]interface{}{ "repoType": repo.StorageMiner, - "testnode-full": n[0], - "testnode-storage": sn[0], + "testnode-full": client, + "testnode-storage": miner, } api.RunningNodeType = api.NodeMiner @@ -61,7 +50,8 @@ func TestMinerAllInfo(t *testing.T) { t.Run("pre-info-all", run) dh := kit.NewDealHarness(t, client, miner) - dh.MakeFullDeal(context.Background(), 6, false, false, 0) - + deal, res, inPath := dh.MakeOnlineDeal(context.Background(), 6, false, 0) + outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, false) + kit.AssertFilesEqual(t, inPath, outPath) t.Run("post-info-all", run) } From d1b291de5ef7476c395f1f49a0e78b8f0dd1a9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 13:24:25 +0100 Subject: [PATCH 52/72] fix proof types. --- itests/api_test.go | 11 ++++++++--- itests/kit/ensemble.go | 2 +- itests/kit/ensemble_opts.go | 11 +---------- itests/kit/node_opts.go | 14 ++++++++------ 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/itests/api_test.go b/itests/api_test.go index 45c137a8d39..5487a2c3879 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -7,6 +7,7 @@ import ( "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" lapi "github.com/filecoin-project/lotus/api" @@ -170,9 +171,10 @@ func (ts *apiSuite) testMiningReal(t *testing.T) { func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { ctx := context.Background() - full, genesisMiner, ens := kit.EnsembleMinimal(t, ts.opts...) + full, genesisMiner, ens := kit.EnsembleMinimal(t, append(ts.opts, kit.MockProofs())...) + ens.InterconnectAll().BeginMining(4 * time.Millisecond) - ens.BeginMining(4 * time.Millisecond) + time.Sleep(1 * time.Second) gaa, err := genesisMiner.ActorAddress(ctx) require.NoError(t, err) @@ -181,7 +183,10 @@ func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { require.NoError(t, err) var newMiner kit.TestMiner - ens.Miner(&newMiner, full, kit.OwnerAddr(full.DefaultKey)).Start() + ens.Miner(&newMiner, full, + kit.OwnerAddr(full.DefaultKey), + kit.ProofType(abi.RegisteredSealProof_StackedDrg2KiBV1), // we're using v0 actors with old proofs. + ).Start().InterconnectAll() ta, err := newMiner.ActorAddress(ctx) require.NoError(t, err) diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 1accdbd61ca..9861bcd7e5c 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -337,7 +337,7 @@ func (n *Ensemble) Start() *Ensemble { params, aerr := actors.SerializeParams(&power2.CreateMinerParams{ Owner: m.OwnerKey.Address, Worker: m.OwnerKey.Address, - SealProofType: n.options.proofType, + SealProofType: m.options.proofType, Peer: abi.PeerID(m.Libp2p.PeerID), }) require.NoError(n.t, aerr) diff --git a/itests/kit/ensemble_opts.go b/itests/kit/ensemble_opts.go index 9233aadd8d4..440362ed142 100644 --- a/itests/kit/ensemble_opts.go +++ b/itests/kit/ensemble_opts.go @@ -16,22 +16,13 @@ type genesisAccount struct { type ensembleOpts struct { pastOffset time.Duration - proofType abi.RegisteredSealProof verifiedRoot genesisAccount accounts []genesisAccount mockProofs bool } var DefaultEnsembleOpts = ensembleOpts{ - pastOffset: 10000000 * time.Second, // time sufficiently in the past to trigger catch-up mining. - proofType: abi.RegisteredSealProof_StackedDrg2KiBV1_1, // default _concrete_ proof type for non-genesis miners (notice the _1). -} - -func ProofType(proofType abi.RegisteredSealProof) EnsembleOpt { - return func(opts *ensembleOpts) error { - opts.proofType = proofType - return nil - } + pastOffset: 10000000 * time.Second, // time sufficiently in the past to trigger catch-up mining. } // MockProofs activates mock proofs for the entire ensemble. diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index c36ca3e2651..ae99f3f2912 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -26,12 +26,14 @@ type nodeOpts struct { ownerKey *wallet.Key extraNodeOpts []node.Option optBuilders []OptBuilder + proofType abi.RegisteredSealProof } // DefaultNodeOpts are the default options that will be applied to test nodes. var DefaultNodeOpts = nodeOpts{ - balance: big.Mul(big.NewInt(100000000), types.NewInt(build.FilecoinPrecision)), - sectors: DefaultPresealsPerBootstrapMiner, + balance: big.Mul(big.NewInt(100000000), types.NewInt(build.FilecoinPrecision)), + sectors: DefaultPresealsPerBootstrapMiner, + proofType: abi.RegisteredSealProof_StackedDrg2KiBV1_1, // default _concrete_ proof type for non-genesis miners (notice the _1) for new actors versions. } // OptBuilder is used to create an option after some other node is already @@ -95,11 +97,11 @@ func ConstructorOpts(extra ...node.Option) NodeOpt { } } -// AddOptBuilder adds an OptionBuilder to a node. It is used to add Lotus node -// constructor options after some nodes are already active. -func AddOptBuilder(optBuilder OptBuilder) NodeOpt { +// ProofType sets the proof type for this node. If you're using new actor +// versions, this should be a _1 proof type. +func ProofType(proofType abi.RegisteredSealProof) NodeOpt { return func(opts *nodeOpts) error { - opts.optBuilders = append(opts.optBuilders, optBuilder) + opts.proofType = proofType return nil } } From 0879ac496f7daa01e42b037d36f0b9687532be2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 18:21:10 +0100 Subject: [PATCH 53/72] uncomment lines in TestDealCyclesConcurrent. --- itests/deals_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index 3f3c853aaab..96b81be1f6c 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -38,7 +38,7 @@ func TestDealCyclesConcurrent(t *testing.T) { startEpoch := abi.ChainEpoch(2 << 12) runTest := func(t *testing.T, n int, fastRetrieval bool, carExport bool) { - client, miner, ens := kit.EnsembleMinimal(t) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blockTime) dh := kit.NewDealHarness(t, client, miner) @@ -54,9 +54,9 @@ func TestDealCyclesConcurrent(t *testing.T) { for _, n := range cycles { n := n ns := fmt.Sprintf("%d", n) - //t.Run(ns+"-fastretrieval-CAR", func(t *testing.T) { runTest(t, n, true, true) }) - //t.Run(ns+"-fastretrieval-NoCAR", func(t *testing.T) { runTest(t, n, true, false) }) - //t.Run(ns+"-stdretrieval-CAR", func(t *testing.T) { runTest(t, n, true, false) }) + t.Run(ns+"-fastretrieval-CAR", func(t *testing.T) { runTest(t, n, true, true) }) + t.Run(ns+"-fastretrieval-NoCAR", func(t *testing.T) { runTest(t, n, true, false) }) + t.Run(ns+"-stdretrieval-CAR", func(t *testing.T) { runTest(t, n, true, false) }) t.Run(ns+"-stdretrieval-NoCAR", func(t *testing.T) { runTest(t, n, false, false) }) } } From 00fa3878d445e6cee86a42703444b5ce39885103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 18:22:08 +0100 Subject: [PATCH 54/72] remove debug statement. --- itests/kit/node_miner.go | 1 - 1 file changed, 1 deletion(-) diff --git a/itests/kit/node_miner.go b/itests/kit/node_miner.go index ec38c4303f8..d3f0d2e3c9d 100644 --- a/itests/kit/node_miner.go +++ b/itests/kit/node_miner.go @@ -107,7 +107,6 @@ func (tm *TestMiner) StartPledge(ctx context.Context, n, existing int, blockNoti } func (tm *TestMiner) FlushSealingBatches(ctx context.Context) { - fmt.Println("FLUSH SEALING BATCHES***************") pcb, err := tm.StorageMiner.SectorPreCommitFlush(ctx) require.NoError(tm.t, err) if pcb != nil { From 70929a99e6dfdf5bfa2376e44739c21da44d1886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 18:24:39 +0100 Subject: [PATCH 55/72] speed up test. --- itests/deals_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index 96b81be1f6c..f35f10e2a25 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -123,7 +123,7 @@ func TestDealsWithSealingAndRPC(t *testing.T) { func TestQuotePriceForUnsealedRetrieval(t *testing.T) { var ( ctx = context.Background() - blocktime = time.Second + blocktime = 10 * time.Millisecond ) kit.QuietMiningLogs() From c22e10c4a4dc5a21867718c1ddb8fabbcc708fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 18:29:25 +0100 Subject: [PATCH 56/72] use mock proofs in TestQuotePriceForUnsealedRetrieval. --- itests/deals_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index f35f10e2a25..e7cadc173d9 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -128,7 +128,7 @@ func TestQuotePriceForUnsealedRetrieval(t *testing.T) { kit.QuietMiningLogs() - client, miner, ens := kit.EnsembleMinimal(t) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) ens.InterconnectAll().BeginMining(blocktime) var ( From 4fcd0b7acaf0437a0d52a713273ae3dfef74bc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 21:20:45 +0100 Subject: [PATCH 57/72] disable resource filtering on scheduler. --- itests/deals_test.go | 2 +- itests/kit/ensemble.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index e7cadc173d9..f35f10e2a25 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -128,7 +128,7 @@ func TestQuotePriceForUnsealedRetrieval(t *testing.T) { kit.QuietMiningLogs() - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + client, miner, ens := kit.EnsembleMinimal(t) ens.InterconnectAll().BeginMining(blocktime) var ( diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 0955be11b8a..62b35a26911 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -444,10 +444,10 @@ func (n *Ensemble) Start() *Ensemble { // disable resource filtering so that local worker gets assigned tasks // regardless of system pressure. - node.Override(new(*sectorstorage.SealerConfig), func() *sectorstorage.SealerConfig { + node.Override(new(sectorstorage.SealerConfig), func() sectorstorage.SealerConfig { scfg := config.DefaultStorageMiner() scfg.Storage.ResourceFiltering = sectorstorage.ResourceFilteringDisabled - return &scfg.Storage + return scfg.Storage }), } From e438ef99f8c168799e056caac3c1292cab22f322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 21:25:55 +0100 Subject: [PATCH 58/72] fix merge error in window post dispute tests. --- itests/deals_test.go | 1 + itests/wdpost_dispute_test.go | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index f35f10e2a25..ab7f05d3e01 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -50,6 +50,7 @@ func TestDealCyclesConcurrent(t *testing.T) { }) } + // TOOD: add 2, 4, 8, more when this graphsync issue is fixed: https://github.com/ipfs/go-graphsync/issues/175# cycles := []int{1} for _, n := range cycles { n := n diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index 742972fc654..bf1a01e6073 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -335,11 +335,6 @@ func submitBadProof( return err } - from, err := client.WalletDefaultAddress(ctx) - if err != nil { - return err - } - minerInfo, err := client.StateMinerInfo(ctx, maddr, head.Key()) if err != nil { return err @@ -374,7 +369,7 @@ func submitBadProof( Method: minerActor.Methods.SubmitWindowedPoSt, Params: enc, Value: types.NewInt(0), - From: from, + From: owner, } sm, err := client.MpoolPushMessage(ctx, msg, nil) if err != nil { From 502e104e6aa5f964d33eeffc57400a83605601b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 21:35:39 +0100 Subject: [PATCH 59/72] typo. --- itests/deals_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index ab7f05d3e01..d4da44c435b 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -50,7 +50,7 @@ func TestDealCyclesConcurrent(t *testing.T) { }) } - // TOOD: add 2, 4, 8, more when this graphsync issue is fixed: https://github.com/ipfs/go-graphsync/issues/175# + // TODO: add 2, 4, 8, more when this graphsync issue is fixed: https://github.com/ipfs/go-graphsync/issues/175# cycles := []int{1} for _, n := range cycles { n := n From 0e2d06fc398069562adb81421a190a9fd8ad931d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 23:10:17 +0100 Subject: [PATCH 60/72] switch to http API. --- itests/kit/ensemble.go | 2 +- itests/kit/rpc.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 62b35a26911..136eef0a5e7 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -439,7 +439,7 @@ func (n *Ensemble) Start() *Ensemble { node.MockHost(n.mn), - node.Override(new(v1api.FullNode), m.FullNode), + node.Override(new(v1api.FullNode), m.FullNode.FullNode), node.Override(new(*lotusminer.Miner), lotusminer.NewTestMiner(mineBlock, m.ActorAddr)), // disable resource filtering so that local worker gets assigned tasks diff --git a/itests/kit/rpc.go b/itests/kit/rpc.go index dab45df0773..3269d2bea94 100644 --- a/itests/kit/rpc.go +++ b/itests/kit/rpc.go @@ -30,7 +30,7 @@ func fullRpc(t *testing.T, f *TestFullNode) *TestFullNode { srv, maddr := CreateRPCServer(t, handler) - cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) + cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "http://"+srv.Listener.Addr().String()+"/rpc/v1", nil) require.NoError(t, err) t.Cleanup(stop) f.ListenAddr, f.FullNode = maddr, cl @@ -44,7 +44,7 @@ func minerRpc(t *testing.T, m *TestMiner) *TestMiner { srv, maddr := CreateRPCServer(t, handler) - cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v0", nil) + cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "http://"+srv.Listener.Addr().String()+"/rpc/v0", nil) require.NoError(t, err) t.Cleanup(stop) From bb032b526c740cb86e70eccffbdda75a6aa8ca27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 21 Jun 2021 23:24:59 +0100 Subject: [PATCH 61/72] switch back to ws API. --- itests/kit/rpc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itests/kit/rpc.go b/itests/kit/rpc.go index 3269d2bea94..dab45df0773 100644 --- a/itests/kit/rpc.go +++ b/itests/kit/rpc.go @@ -30,7 +30,7 @@ func fullRpc(t *testing.T, f *TestFullNode) *TestFullNode { srv, maddr := CreateRPCServer(t, handler) - cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "http://"+srv.Listener.Addr().String()+"/rpc/v1", nil) + cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) require.NoError(t, err) t.Cleanup(stop) f.ListenAddr, f.FullNode = maddr, cl @@ -44,7 +44,7 @@ func minerRpc(t *testing.T, m *TestMiner) *TestMiner { srv, maddr := CreateRPCServer(t, handler) - cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "http://"+srv.Listener.Addr().String()+"/rpc/v0", nil) + cl, stop, err := client.NewStorageMinerRPCV0(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v0", nil) require.NoError(t, err) t.Cleanup(stop) From da789939b198c2391d1ca946406d52f43daac37c Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 22 Jun 2021 14:33:44 +0200 Subject: [PATCH 62/72] fix: bump blocktime of TestQuotePriceForUnsealedRetrieval to 1 second --- itests/deals_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itests/deals_test.go b/itests/deals_test.go index d4da44c435b..ad9d7d63ccf 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -124,7 +124,7 @@ func TestDealsWithSealingAndRPC(t *testing.T) { func TestQuotePriceForUnsealedRetrieval(t *testing.T) { var ( ctx = context.Background() - blocktime = 10 * time.Millisecond + blocktime = time.Second ) kit.QuietMiningLogs() From 2a58f830c08d60efecbc7ef7c6e262571b7cd8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 22 Jun 2021 16:34:30 +0100 Subject: [PATCH 63/72] fix sector_terminate_test.go flakiness. --- itests/sector_terminate_test.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go index 94d438437c5..1ce55be10bd 100644 --- a/itests/sector_terminate_test.go +++ b/itests/sector_terminate_test.go @@ -21,15 +21,14 @@ func TestTerminate(t *testing.T) { kit.QuietMiningLogs() - const blocktime = 2 * time.Millisecond - - nSectors := uint64(2) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + var ( + blocktime = 2 * time.Millisecond + nSectors = 2 + ctx = context.Background() + ) opts := kit.ConstructorOpts(kit.LatestActorsAt(-1)) - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), opts) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.PresealSectors(nSectors), opts) ens.InterconnectAll().BeginMining(blocktime) maddr, err := miner.ActorAddress(ctx) @@ -41,7 +40,7 @@ func TestTerminate(t *testing.T) { p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) require.Equal(t, p.MinerPower, p.TotalPower) - require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*nSectors)) + require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors))) t.Log("Seal a sector") @@ -54,7 +53,7 @@ func TestTerminate(t *testing.T) { di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 + waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 20 // 20 is some slack for the proof to be submitted + applied t.Logf("End for head.Height > %d", waitUntil) ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) @@ -66,7 +65,7 @@ func TestTerminate(t *testing.T) { p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) require.Equal(t, p.MinerPower, p.TotalPower) - require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*nSectors)) + require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors))) t.Log("Terminate a sector") @@ -113,11 +112,14 @@ loop: time.Sleep(100 * time.Millisecond) } + // need to wait for message to be mined and applied. + time.Sleep(5 * time.Second) + // check power decreased p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) require.NoError(t, err) require.Equal(t, p.MinerPower, p.TotalPower) - require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*(nSectors-1))) + require.Equal(t, types.NewInt(uint64(ssz)*uint64(nSectors-1)), p.MinerPower.RawBytePower) // check in terminated set { @@ -138,7 +140,7 @@ loop: di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 + waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 20 // slack like above t.Logf("End for head.Height > %d", waitUntil) ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) t.Logf("Now head.Height = %d", ts.Height()) @@ -147,5 +149,5 @@ loop: require.NoError(t, err) require.Equal(t, p.MinerPower, p.TotalPower) - require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*(nSectors-1))) + require.Equal(t, types.NewInt(uint64(ssz)*uint64(nSectors-1)), p.MinerPower.RawBytePower) } From 71a7270c9891088c20e80af08278e57692ceea89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 22 Jun 2021 16:34:41 +0100 Subject: [PATCH 64/72] cleanup gateway RPC. --- itests/gateway_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/itests/gateway_test.go b/itests/gateway_test.go index e2329bf778a..0f73befa5f9 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -288,6 +288,7 @@ func startNodes( var gapi api.Gateway gapi, closer, err = client.NewGatewayRPCV1(ctx, "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) require.NoError(t, err) + t.Cleanup(closer) ens.FullNode(&lite, kit.LiteNode(), From 098eb6bfff4729824bea385bd9da4d2f8f10a7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 22 Jun 2021 16:35:58 +0100 Subject: [PATCH 65/72] try using bg context on constructor. --- itests/kit/ensemble.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 136eef0a5e7..2e04c37c844 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -245,8 +245,7 @@ func (n *Ensemble) Miner(miner *TestMiner, full *TestFullNode, opts ...NodeOpt) // Start starts all enrolled nodes. func (n *Ensemble) Start() *Ensemble { - ctx, cancel := context.WithCancel(context.Background()) - n.t.Cleanup(cancel) + ctx := context.Background() var gtempl *genesis.Template if !n.bootstrapped { From 9b2efd5ace6b0c3d7bccb8ea1c93644e0096d422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 22 Jun 2021 17:07:14 +0100 Subject: [PATCH 66/72] try to deflake window post itests. --- itests/wdpost_dispute_test.go | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index bf1a01e6073..24b831df35c 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -49,26 +49,11 @@ func TestWindowPostDispute(t *testing.T) { Miner(&evilMiner, &client, opts, kit.PresealSectors(0)). Start() - { - addrinfo, err := client.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := chainMiner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - - if err := evilMiner.NetConnect(ctx, addrinfo); err != nil { - t.Fatal(err) - } - } - defaultFrom, err := client.WalletDefaultAddress(ctx) require.NoError(t, err) // Mine with the _second_ node (the good one). - ens.BeginMining(blocktime, &chainMiner) + ens.InterconnectAll().BeginMining(blocktime, &chainMiner) // Give the chain miner enough sectors to win every block. chainMiner.PledgeSectors(ctx, 10, 0, nil) @@ -84,7 +69,7 @@ func TestWindowPostDispute(t *testing.T) { t.Logf("Running one proving period\n") - waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 + waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 + 1 t.Logf("End for head.Height > %d", waitUntil) ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) @@ -257,7 +242,7 @@ func TestWindowPostDisputeFails(t *testing.T) { require.NoError(t, err) t.Log("Running one proving period") - waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 + waitUntil := di.PeriodStart + di.WPoStProvingPeriod*2 + 1 t.Logf("End for head.Height > %d", waitUntil) ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) From 120dd149793a7baf314c78d80bf7f50994ff610a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 22 Jun 2021 17:18:07 +0100 Subject: [PATCH 67/72] avoid double close. --- itests/gateway_test.go | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/itests/gateway_test.go b/itests/gateway_test.go index 0f73befa5f9..6d30bb46e36 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -19,7 +19,6 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" - "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/cli" @@ -35,12 +34,6 @@ const ( maxStateWaitLookbackLimit = stmgr.LookbackNoLimit ) -func init() { - policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) - policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) - policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) -} - // TestGatewayWalletMsig tests that API calls to wallet and msig can be made on a lite // node that is connected through a gateway to a full API node func TestGatewayWalletMsig(t *testing.T) { @@ -49,7 +42,6 @@ func TestGatewayWalletMsig(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) - defer nodes.closer() lite := nodes.lite full := nodes.full @@ -181,7 +173,6 @@ func TestGatewayMsigCLI(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) - defer nodes.closer() lite := nodes.lite runMultisigTests(t, lite) @@ -193,7 +184,6 @@ func TestGatewayDealFlow(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) - defer nodes.closer() time.Sleep(5 * time.Second) @@ -216,16 +206,14 @@ func TestGatewayCLIDealFlow(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) - defer nodes.closer() kit.RunClientTest(t, cli.Commands, nodes.lite) } type testNodes struct { - lite *kit.TestFullNode - full *kit.TestFullNode - miner *kit.TestMiner - closer jsonrpc.ClientCloser + lite *kit.TestFullNode + full *kit.TestFullNode + miner *kit.TestMiner } func startNodesWithFunds( @@ -298,7 +286,7 @@ func startNodes( ), ).Start().InterconnectAll() - return &testNodes{lite: &lite, full: full, miner: miner, closer: closer} + return &testNodes{lite: &lite, full: full, miner: miner} } func sendFunds(ctx context.Context, fromNode *kit.TestFullNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { From 2e9e1c2330b9dcb3eca7fdd6682aab6a8db98176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 22 Jun 2021 18:15:38 +0100 Subject: [PATCH 68/72] avoid double BlockMiner instantiation. --- itests/kit/ensemble.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 2e04c37c844..788aa40c0d6 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -109,6 +109,7 @@ type Ensemble struct { active struct { fullnodes []*TestFullNode miners []*TestMiner + bms map[*TestMiner]*BlockMiner } genesis struct { miners []genesis.Miner @@ -125,6 +126,7 @@ func NewEnsemble(t *testing.T, opts ...EnsembleOpt) *Ensemble { } n := &Ensemble{t: t, options: &options} + n.active.bms = make(map[*TestMiner]*BlockMiner) // add accounts from ensemble options to genesis. for _, acc := range options.accounts { @@ -597,7 +599,14 @@ func (n *Ensemble) BeginMining(blocktime time.Duration, miners ...*TestMiner) [] var bms []*BlockMiner if len(miners) == 0 { - miners = n.active.miners + // no miners have been provided explicitly, instantiate block miners + // for all active miners that aren't still mining. + for _, m := range n.active.miners { + if _, ok := n.active.bms[m]; ok { + continue // skip, already have a block miner + } + miners = append(miners, m) + } } for _, m := range miners { @@ -606,6 +615,8 @@ func (n *Ensemble) BeginMining(blocktime time.Duration, miners ...*TestMiner) [] n.t.Cleanup(bm.Stop) bms = append(bms, bm) + + n.active.bms[m] = bm } return bms From 779626ceec9beec82c15f17118bd388b22134f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 23 Jun 2021 18:05:20 +0100 Subject: [PATCH 69/72] fix circleci. --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index f4f9b421d44..133fb4d9607 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -440,6 +440,7 @@ jobs: paths: - appimage + gofmt: executor: golang steps: From 9b3188d110bf85148d0bbe26549c589f303b3ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 23 Jun 2021 18:13:29 +0100 Subject: [PATCH 70/72] split deals tests. --- .circleci/config.yml | 25 ++ itests/deals_concurrent_test.go | 49 ++++ itests/deals_offline_test.go | 101 ++++++++ itests/deals_power_test.go | 61 +++++ itests/deals_pricing_test.go | 131 ++++++++++ itests/deals_publish_test.go | 108 ++++++++ itests/deals_test.go | 441 +------------------------------- itests/kit/deals.go | 43 +++- 8 files changed, 517 insertions(+), 442 deletions(-) create mode 100644 itests/deals_concurrent_test.go create mode 100644 itests/deals_offline_test.go create mode 100644 itests/deals_power_test.go create mode 100644 itests/deals_pricing_test.go create mode 100644 itests/deals_publish_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 133fb4d9607..9a6f377f1fb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -771,6 +771,31 @@ workflows: suite: itest-deadlines target: "./itests/deadlines_test.go" + - test: + name: test-itest-deals_concurrent + suite: itest-deals_concurrent + target: "./itests/deals_concurrent_test.go" + + - test: + name: test-itest-deals_offline + suite: itest-deals_offline + target: "./itests/deals_offline_test.go" + + - test: + name: test-itest-deals_power + suite: itest-deals_power + target: "./itests/deals_power_test.go" + + - test: + name: test-itest-deals_pricing + suite: itest-deals_pricing + target: "./itests/deals_pricing_test.go" + + - test: + name: test-itest-deals_publish + suite: itest-deals_publish + target: "./itests/deals_publish_test.go" + - test: name: test-itest-deals suite: itest-deals diff --git a/itests/deals_concurrent_test.go b/itests/deals_concurrent_test.go new file mode 100644 index 00000000000..33a8218dd5c --- /dev/null +++ b/itests/deals_concurrent_test.go @@ -0,0 +1,49 @@ +package itests + +import ( + "fmt" + "testing" + "time" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/itests/kit" +) + +func TestDealCyclesConcurrent(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit.QuietMiningLogs() + + blockTime := 10 * time.Millisecond + + // For these tests where the block time is artificially short, just use + // a deal start epoch that is guaranteed to be far enough in the future + // so that the deal starts sealing in time + startEpoch := abi.ChainEpoch(2 << 12) + + runTest := func(t *testing.T, n int, fastRetrieval bool, carExport bool) { + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(blockTime) + dh := kit.NewDealHarness(t, client, miner) + + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{ + N: n, + FastRetrieval: fastRetrieval, + CarExport: carExport, + StartEpoch: startEpoch, + }) + } + + // TODO: add 2, 4, 8, more when this graphsync issue is fixed: https://github.com/ipfs/go-graphsync/issues/175# + cycles := []int{1} + for _, n := range cycles { + n := n + ns := fmt.Sprintf("%d", n) + t.Run(ns+"-fastretrieval-CAR", func(t *testing.T) { runTest(t, n, true, true) }) + t.Run(ns+"-fastretrieval-NoCAR", func(t *testing.T) { runTest(t, n, true, false) }) + t.Run(ns+"-stdretrieval-CAR", func(t *testing.T) { runTest(t, n, true, false) }) + t.Run(ns+"-stdretrieval-NoCAR", func(t *testing.T) { runTest(t, n, false, false) }) + } +} diff --git a/itests/deals_offline_test.go b/itests/deals_offline_test.go new file mode 100644 index 00000000000..c3f19048b73 --- /dev/null +++ b/itests/deals_offline_test.go @@ -0,0 +1,101 @@ +package itests + +import ( + "context" + "path/filepath" + "testing" + "time" + + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" + "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/stretchr/testify/require" +) + +func TestOfflineDealFlow(t *testing.T) { + blocktime := 10 * time.Millisecond + + // For these tests where the block time is artificially short, just use + // a deal start epoch that is guaranteed to be far enough in the future + // so that the deal starts sealing in time + startEpoch := abi.ChainEpoch(2 << 12) + + runTest := func(t *testing.T, fastRet bool) { + ctx := context.Background() + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(blocktime) + + dh := kit.NewDealHarness(t, client, miner) + + // Create a random file and import on the client. + res, inFile := client.CreateImportFile(ctx, 1, 0) + + // Get the piece size and commP + rootCid := res.Root + pieceInfo, err := client.ClientDealPieceCID(ctx, rootCid) + require.NoError(t, err) + t.Log("FILE CID:", rootCid) + + // Create a storage deal with the miner + maddr, err := miner.ActorAddress(ctx) + require.NoError(t, err) + + addr, err := client.WalletDefaultAddress(ctx) + require.NoError(t, err) + + // Manual storage deal (offline deal) + dataRef := &storagemarket.DataRef{ + TransferType: storagemarket.TTManual, + Root: rootCid, + PieceCid: &pieceInfo.PieceCID, + PieceSize: pieceInfo.PieceSize.Unpadded(), + } + + proposalCid, err := client.ClientStartDeal(ctx, &api.StartDealParams{ + Data: dataRef, + Wallet: addr, + Miner: maddr, + EpochPrice: types.NewInt(1000000), + DealStartEpoch: startEpoch, + MinBlocksDuration: uint64(build.MinDealDuration), + FastRetrieval: fastRet, + }) + require.NoError(t, err) + + // Wait for the deal to reach StorageDealCheckForAcceptance on the client + cd, err := client.ClientGetDealInfo(ctx, *proposalCid) + require.NoError(t, err) + require.Eventually(t, func() bool { + cd, _ := client.ClientGetDealInfo(ctx, *proposalCid) + return cd.State == storagemarket.StorageDealCheckForAcceptance + }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) + + // Create a CAR file from the raw file + carFileDir := t.TempDir() + carFilePath := filepath.Join(carFileDir, "out.car") + err = client.ClientGenCar(ctx, api.FileRef{Path: inFile}, carFilePath) + require.NoError(t, err) + + // Import the CAR file on the miner - this is the equivalent to + // transferring the file across the wire in a normal (non-offline) deal + err = miner.DealsImportData(ctx, *proposalCid, carFilePath) + require.NoError(t, err) + + // Wait for the deal to be published + dh.WaitDealPublished(ctx, proposalCid) + + t.Logf("deal published, retrieving") + + // Retrieve the deal + outFile := dh.PerformRetrieval(ctx, proposalCid, rootCid, false) + + kit.AssertFilesEqual(t, inFile, outFile) + + } + + t.Run("stdretrieval", func(t *testing.T) { runTest(t, false) }) + t.Run("fastretrieval", func(t *testing.T) { runTest(t, true) }) +} diff --git a/itests/deals_power_test.go b/itests/deals_power_test.go new file mode 100644 index 00000000000..ebf1895e3fc --- /dev/null +++ b/itests/deals_power_test.go @@ -0,0 +1,61 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/filecoin-project/lotus/itests/kit" +) + +func TestFirstDealEnablesMining(t *testing.T) { + // test making a deal with a fresh miner, and see if it starts to mine. + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit.QuietMiningLogs() + + var ( + client kit.TestFullNode + genMiner kit.TestMiner // bootstrap + provider kit.TestMiner // no sectors, will need to create one + ) + + ens := kit.NewEnsemble(t, kit.MockProofs()) + ens.FullNode(&client) + ens.Miner(&genMiner, &client) + ens.Miner(&provider, &client, kit.PresealSectors(0)) + ens.Start().InterconnectAll().BeginMining(50 * time.Millisecond) + + ctx := context.Background() + + dh := kit.NewDealHarness(t, &client, &provider) + + ref, _ := client.CreateImportFile(ctx, 5, 0) + + t.Log("FILE CID:", ref.Root) + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // start a goroutine to monitor head changes from the client + // once the provider has mined a block, thanks to the power acquired from the deal, + // we pass the test. + providerMined := make(chan struct{}) + + go func() { + _ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) + close(providerMined) + }() + + // now perform the deal. + deal := dh.StartDeal(ctx, ref.Root, false, 0) + + // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this + time.Sleep(time.Second) + + dh.WaitDealSealed(ctx, deal, false, false, nil) + + <-providerMined +} diff --git a/itests/deals_pricing_test.go b/itests/deals_pricing_test.go new file mode 100644 index 00000000000..357abec1ed9 --- /dev/null +++ b/itests/deals_pricing_test.go @@ -0,0 +1,131 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/extern/sector-storage/storiface" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/stretchr/testify/require" +) + +func TestQuotePriceForUnsealedRetrieval(t *testing.T) { + var ( + ctx = context.Background() + blocktime = time.Second + ) + + kit.QuietMiningLogs() + + client, miner, ens := kit.EnsembleMinimal(t) + ens.InterconnectAll().BeginMining(blocktime) + + var ( + ppb = int64(1) + unsealPrice = int64(77) + ) + + // Set unsealed price to non-zero + ask, err := miner.MarketGetRetrievalAsk(ctx) + require.NoError(t, err) + ask.PricePerByte = abi.NewTokenAmount(ppb) + ask.UnsealPrice = abi.NewTokenAmount(unsealPrice) + err = miner.MarketSetRetrievalAsk(ctx, ask) + require.NoError(t, err) + + dh := kit.NewDealHarness(t, client, miner) + + deal1, res1, _ := dh.MakeOnlineDeal(ctx, kit.MakeFullDealParams{Rseed: 6}) + + // one more storage deal for the same data + _, res2, _ := dh.MakeOnlineDeal(ctx, kit.MakeFullDealParams{Rseed: 6}) + require.Equal(t, res1.Root, res2.Root) + + // Retrieval + dealInfo, err := client.ClientGetDealInfo(ctx, *deal1) + require.NoError(t, err) + + // fetch quote -> zero for unsealed price since unsealed file already exists. + offers, err := client.ClientFindData(ctx, res1.Root, &dealInfo.PieceCID) + require.NoError(t, err) + require.Len(t, offers, 2) + require.Equal(t, offers[0], offers[1]) + require.Equal(t, uint64(0), offers[0].UnsealPrice.Uint64()) + require.Equal(t, dealInfo.Size*uint64(ppb), offers[0].MinPrice.Uint64()) + + // remove ONLY one unsealed file + ss, err := miner.StorageList(context.Background()) + require.NoError(t, err) + _, err = miner.SectorsList(ctx) + require.NoError(t, err) + +iLoop: + for storeID, sd := range ss { + for _, sector := range sd { + err := miner.StorageDropSector(ctx, storeID, sector.SectorID, storiface.FTUnsealed) + require.NoError(t, err) + break iLoop // remove ONLY one + } + } + + // get retrieval quote -> zero for unsealed price as unsealed file exists. + offers, err = client.ClientFindData(ctx, res1.Root, &dealInfo.PieceCID) + require.NoError(t, err) + require.Len(t, offers, 2) + require.Equal(t, offers[0], offers[1]) + require.Equal(t, uint64(0), offers[0].UnsealPrice.Uint64()) + require.Equal(t, dealInfo.Size*uint64(ppb), offers[0].MinPrice.Uint64()) + + // remove the other unsealed file as well + ss, err = miner.StorageList(context.Background()) + require.NoError(t, err) + _, err = miner.SectorsList(ctx) + require.NoError(t, err) + for storeID, sd := range ss { + for _, sector := range sd { + require.NoError(t, miner.StorageDropSector(ctx, storeID, sector.SectorID, storiface.FTUnsealed)) + } + } + + // fetch quote -> non-zero for unseal price as we no more unsealed files. + offers, err = client.ClientFindData(ctx, res1.Root, &dealInfo.PieceCID) + require.NoError(t, err) + require.Len(t, offers, 2) + require.Equal(t, offers[0], offers[1]) + require.Equal(t, uint64(unsealPrice), offers[0].UnsealPrice.Uint64()) + total := (dealInfo.Size * uint64(ppb)) + uint64(unsealPrice) + require.Equal(t, total, offers[0].MinPrice.Uint64()) +} + +func TestZeroPricePerByteRetrieval(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + + kit.QuietMiningLogs() + + var ( + blockTime = 10 * time.Millisecond + startEpoch = abi.ChainEpoch(2 << 12) + ) + + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx := context.Background() + + ask, err := miner.MarketGetRetrievalAsk(ctx) + require.NoError(t, err) + + ask.PricePerByte = abi.NewTokenAmount(0) + err = miner.MarketSetRetrievalAsk(ctx, ask) + require.NoError(t, err) + + dh := kit.NewDealHarness(t, client, miner) + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{ + N: 1, + StartEpoch: startEpoch, + }) +} diff --git a/itests/deals_publish_test.go b/itests/deals_publish_test.go new file mode 100644 index 00000000000..16f84038bbb --- /dev/null +++ b/itests/deals_publish_test.go @@ -0,0 +1,108 @@ +package itests + +import ( + "bytes" + "context" + "testing" + "time" + + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/markets/storageadapter" + "github.com/filecoin-project/lotus/node" + market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" + "github.com/stretchr/testify/require" +) + +func TestPublishDealsBatching(t *testing.T) { + var ( + ctx = context.Background() + publishPeriod = 10 * time.Second + maxDealsPerMsg = uint64(2) // Set max deals per publish deals message to 2 + startEpoch = abi.ChainEpoch(2 << 12) + ) + + kit.QuietMiningLogs() + + opts := node.Override(new(*storageadapter.DealPublisher), + storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ + Period: publishPeriod, + MaxDealsPerMsg: maxDealsPerMsg, + }), + ) + + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ConstructorOpts(opts)) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + dh := kit.NewDealHarness(t, client, miner) + + // Starts a deal and waits until it's published + runDealTillPublish := func(rseed int) { + res, _ := client.CreateImportFile(ctx, rseed, 0) + + upds, err := client.ClientGetDealUpdates(ctx) + require.NoError(t, err) + + dh.StartDeal(ctx, res.Root, false, startEpoch) + + // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this + time.Sleep(time.Second) + + done := make(chan struct{}) + go func() { + for upd := range upds { + if upd.DataRef.Root == res.Root && upd.State == storagemarket.StorageDealAwaitingPreCommit { + done <- struct{}{} + } + } + }() + <-done + } + + // Run three deals in parallel + done := make(chan struct{}, maxDealsPerMsg+1) + for rseed := 1; rseed <= 3; rseed++ { + rseed := rseed + go func() { + runDealTillPublish(rseed) + done <- struct{}{} + }() + } + + // Wait for two of the deals to be published + for i := 0; i < int(maxDealsPerMsg); i++ { + <-done + } + + // Expect a single PublishStorageDeals message that includes the first two deals + msgCids, err := client.StateListMessages(ctx, &api.MessageMatch{To: market.Address}, types.EmptyTSK, 1) + require.NoError(t, err) + count := 0 + for _, msgCid := range msgCids { + msg, err := client.ChainGetMessage(ctx, msgCid) + require.NoError(t, err) + + if msg.Method == market.Methods.PublishStorageDeals { + count++ + var pubDealsParams market2.PublishStorageDealsParams + err = pubDealsParams.UnmarshalCBOR(bytes.NewReader(msg.Params)) + require.NoError(t, err) + require.Len(t, pubDealsParams.Deals, int(maxDealsPerMsg)) + } + } + require.Equal(t, 1, count) + + // The third deal should be published once the publish period expires. + // Allow a little padding as it takes a moment for the state change to + // be noticed by the client. + padding := 10 * time.Second + select { + case <-time.After(publishPeriod + padding): + require.Fail(t, "Expected 3rd deal to be published once publish period elapsed") + case <-done: // Success + } +} diff --git a/itests/deals_test.go b/itests/deals_test.go index ad9d7d63ccf..f8389bbd622 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -1,99 +1,12 @@ package itests import ( - "bytes" - "context" - "fmt" - "path/filepath" "testing" "time" - "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors/builtin/market" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/extern/sector-storage/storiface" "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/markets/storageadapter" - "github.com/filecoin-project/lotus/node" - market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" - "github.com/stretchr/testify/require" - "golang.org/x/sync/errgroup" ) -func TestDealCyclesConcurrent(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode") - } - - kit.QuietMiningLogs() - - blockTime := 10 * time.Millisecond - - // For these tests where the block time is artificially short, just use - // a deal start epoch that is guaranteed to be far enough in the future - // so that the deal starts sealing in time - startEpoch := abi.ChainEpoch(2 << 12) - - runTest := func(t *testing.T, n int, fastRetrieval bool, carExport bool) { - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) - ens.InterconnectAll().BeginMining(blockTime) - dh := kit.NewDealHarness(t, client, miner) - - runConcurrentDeals(t, dh, fullDealCyclesOpts{ - n: n, - fastRetrieval: fastRetrieval, - carExport: carExport, - startEpoch: startEpoch, - }) - } - - // TODO: add 2, 4, 8, more when this graphsync issue is fixed: https://github.com/ipfs/go-graphsync/issues/175# - cycles := []int{1} - for _, n := range cycles { - n := n - ns := fmt.Sprintf("%d", n) - t.Run(ns+"-fastretrieval-CAR", func(t *testing.T) { runTest(t, n, true, true) }) - t.Run(ns+"-fastretrieval-NoCAR", func(t *testing.T) { runTest(t, n, true, false) }) - t.Run(ns+"-stdretrieval-CAR", func(t *testing.T) { runTest(t, n, true, false) }) - t.Run(ns+"-stdretrieval-NoCAR", func(t *testing.T) { runTest(t, n, false, false) }) - } -} - -type fullDealCyclesOpts struct { - n int - fastRetrieval bool - carExport bool - startEpoch abi.ChainEpoch -} - -func runConcurrentDeals(t *testing.T, dh *kit.DealHarness, opts fullDealCyclesOpts) { - errgrp, _ := errgroup.WithContext(context.Background()) - for i := 0; i < opts.n; i++ { - i := i - errgrp.Go(func() (err error) { - defer func() { - // This is necessary because golang can't deal with test - // failures being reported from children goroutines ¯\_(ツ)_/¯ - if r := recover(); r != nil { - err = fmt.Errorf("deal failed: %s", r) - } - }() - deal, res, inPath := dh.MakeOnlineDeal(context.Background(), kit.MakeFullDealParams{ - Rseed: 5 + i, - FastRet: opts.fastRetrieval, - StartEpoch: opts.startEpoch, - }) - outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, opts.carExport) - kit.AssertFilesEqual(t, inPath, outPath) - return nil - }) - } - require.NoError(t, errgrp.Wait()) -} - func TestDealsWithSealingAndRPC(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") @@ -108,361 +21,15 @@ func TestDealsWithSealingAndRPC(t *testing.T) { dh := kit.NewDealHarness(t, client, miner) t.Run("stdretrieval", func(t *testing.T) { - runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1}) + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1}) }) t.Run("fastretrieval", func(t *testing.T) { - runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1, fastRetrieval: true}) + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1, FastRetrieval: true}) }) t.Run("fastretrieval-twodeals-sequential", func(t *testing.T) { - runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1, fastRetrieval: true}) - runConcurrentDeals(t, dh, fullDealCyclesOpts{n: 1, fastRetrieval: true}) - }) -} - -func TestQuotePriceForUnsealedRetrieval(t *testing.T) { - var ( - ctx = context.Background() - blocktime = time.Second - ) - - kit.QuietMiningLogs() - - client, miner, ens := kit.EnsembleMinimal(t) - ens.InterconnectAll().BeginMining(blocktime) - - var ( - ppb = int64(1) - unsealPrice = int64(77) - ) - - // Set unsealed price to non-zero - ask, err := miner.MarketGetRetrievalAsk(ctx) - require.NoError(t, err) - ask.PricePerByte = abi.NewTokenAmount(ppb) - ask.UnsealPrice = abi.NewTokenAmount(unsealPrice) - err = miner.MarketSetRetrievalAsk(ctx, ask) - require.NoError(t, err) - - dh := kit.NewDealHarness(t, client, miner) - - deal1, res1, _ := dh.MakeOnlineDeal(ctx, kit.MakeFullDealParams{Rseed: 6}) - - // one more storage deal for the same data - _, res2, _ := dh.MakeOnlineDeal(ctx, kit.MakeFullDealParams{Rseed: 6}) - require.Equal(t, res1.Root, res2.Root) - - // Retrieval - dealInfo, err := client.ClientGetDealInfo(ctx, *deal1) - require.NoError(t, err) - - // fetch quote -> zero for unsealed price since unsealed file already exists. - offers, err := client.ClientFindData(ctx, res1.Root, &dealInfo.PieceCID) - require.NoError(t, err) - require.Len(t, offers, 2) - require.Equal(t, offers[0], offers[1]) - require.Equal(t, uint64(0), offers[0].UnsealPrice.Uint64()) - require.Equal(t, dealInfo.Size*uint64(ppb), offers[0].MinPrice.Uint64()) - - // remove ONLY one unsealed file - ss, err := miner.StorageList(context.Background()) - require.NoError(t, err) - _, err = miner.SectorsList(ctx) - require.NoError(t, err) - -iLoop: - for storeID, sd := range ss { - for _, sector := range sd { - err := miner.StorageDropSector(ctx, storeID, sector.SectorID, storiface.FTUnsealed) - require.NoError(t, err) - break iLoop // remove ONLY one - } - } - - // get retrieval quote -> zero for unsealed price as unsealed file exists. - offers, err = client.ClientFindData(ctx, res1.Root, &dealInfo.PieceCID) - require.NoError(t, err) - require.Len(t, offers, 2) - require.Equal(t, offers[0], offers[1]) - require.Equal(t, uint64(0), offers[0].UnsealPrice.Uint64()) - require.Equal(t, dealInfo.Size*uint64(ppb), offers[0].MinPrice.Uint64()) - - // remove the other unsealed file as well - ss, err = miner.StorageList(context.Background()) - require.NoError(t, err) - _, err = miner.SectorsList(ctx) - require.NoError(t, err) - for storeID, sd := range ss { - for _, sector := range sd { - require.NoError(t, miner.StorageDropSector(ctx, storeID, sector.SectorID, storiface.FTUnsealed)) - } - } - - // fetch quote -> non-zero for unseal price as we no more unsealed files. - offers, err = client.ClientFindData(ctx, res1.Root, &dealInfo.PieceCID) - require.NoError(t, err) - require.Len(t, offers, 2) - require.Equal(t, offers[0], offers[1]) - require.Equal(t, uint64(unsealPrice), offers[0].UnsealPrice.Uint64()) - total := (dealInfo.Size * uint64(ppb)) + uint64(unsealPrice) - require.Equal(t, total, offers[0].MinPrice.Uint64()) - -} - -func TestPublishDealsBatching(t *testing.T) { - var ( - ctx = context.Background() - publishPeriod = 10 * time.Second - maxDealsPerMsg = uint64(2) // Set max deals per publish deals message to 2 - startEpoch = abi.ChainEpoch(2 << 12) - ) - - kit.QuietMiningLogs() - - opts := node.Override(new(*storageadapter.DealPublisher), - storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{ - Period: publishPeriod, - MaxDealsPerMsg: maxDealsPerMsg, - }), - ) - - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ConstructorOpts(opts)) - ens.InterconnectAll().BeginMining(10 * time.Millisecond) - - dh := kit.NewDealHarness(t, client, miner) - - // Starts a deal and waits until it's published - runDealTillPublish := func(rseed int) { - res, _ := client.CreateImportFile(ctx, rseed, 0) - - upds, err := client.ClientGetDealUpdates(ctx) - require.NoError(t, err) - - dh.StartDeal(ctx, res.Root, false, startEpoch) - - // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this - time.Sleep(time.Second) - - done := make(chan struct{}) - go func() { - for upd := range upds { - if upd.DataRef.Root == res.Root && upd.State == storagemarket.StorageDealAwaitingPreCommit { - done <- struct{}{} - } - } - }() - <-done - } - - // Run three deals in parallel - done := make(chan struct{}, maxDealsPerMsg+1) - for rseed := 1; rseed <= 3; rseed++ { - rseed := rseed - go func() { - runDealTillPublish(rseed) - done <- struct{}{} - }() - } - - // Wait for two of the deals to be published - for i := 0; i < int(maxDealsPerMsg); i++ { - <-done - } - - // Expect a single PublishStorageDeals message that includes the first two deals - msgCids, err := client.StateListMessages(ctx, &api.MessageMatch{To: market.Address}, types.EmptyTSK, 1) - require.NoError(t, err) - count := 0 - for _, msgCid := range msgCids { - msg, err := client.ChainGetMessage(ctx, msgCid) - require.NoError(t, err) - - if msg.Method == market.Methods.PublishStorageDeals { - count++ - var pubDealsParams market2.PublishStorageDealsParams - err = pubDealsParams.UnmarshalCBOR(bytes.NewReader(msg.Params)) - require.NoError(t, err) - require.Len(t, pubDealsParams.Deals, int(maxDealsPerMsg)) - } - } - require.Equal(t, 1, count) - - // The third deal should be published once the publish period expires. - // Allow a little padding as it takes a moment for the state change to - // be noticed by the client. - padding := 10 * time.Second - select { - case <-time.After(publishPeriod + padding): - require.Fail(t, "Expected 3rd deal to be published once publish period elapsed") - case <-done: // Success - } -} - -func TestFirstDealEnablesMining(t *testing.T) { - // test making a deal with a fresh miner, and see if it starts to mine. - if testing.Short() { - t.Skip("skipping test in short mode") - } - - kit.QuietMiningLogs() - - var ( - client kit.TestFullNode - genMiner kit.TestMiner // bootstrap - provider kit.TestMiner // no sectors, will need to create one - ) - - ens := kit.NewEnsemble(t, kit.MockProofs()) - ens.FullNode(&client) - ens.Miner(&genMiner, &client) - ens.Miner(&provider, &client, kit.PresealSectors(0)) - ens.Start().InterconnectAll().BeginMining(50 * time.Millisecond) - - ctx := context.Background() - - dh := kit.NewDealHarness(t, &client, &provider) - - ref, _ := client.CreateImportFile(ctx, 5, 0) - - t.Log("FILE CID:", ref.Root) - - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // start a goroutine to monitor head changes from the client - // once the provider has mined a block, thanks to the power acquired from the deal, - // we pass the test. - providerMined := make(chan struct{}) - - go func() { - _ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) - close(providerMined) - }() - - // now perform the deal. - deal := dh.StartDeal(ctx, ref.Root, false, 0) - - // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this - time.Sleep(time.Second) - - dh.WaitDealSealed(ctx, deal, false, false, nil) - - <-providerMined -} - -func TestOfflineDealFlow(t *testing.T) { - blocktime := 10 * time.Millisecond - - // For these tests where the block time is artificially short, just use - // a deal start epoch that is guaranteed to be far enough in the future - // so that the deal starts sealing in time - startEpoch := abi.ChainEpoch(2 << 12) - - runTest := func(t *testing.T, fastRet bool) { - ctx := context.Background() - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) - ens.InterconnectAll().BeginMining(blocktime) - - dh := kit.NewDealHarness(t, client, miner) - - // Create a random file and import on the client. - res, inFile := client.CreateImportFile(ctx, 1, 0) - - // Get the piece size and commP - rootCid := res.Root - pieceInfo, err := client.ClientDealPieceCID(ctx, rootCid) - require.NoError(t, err) - t.Log("FILE CID:", rootCid) - - // Create a storage deal with the miner - maddr, err := miner.ActorAddress(ctx) - require.NoError(t, err) - - addr, err := client.WalletDefaultAddress(ctx) - require.NoError(t, err) - - // Manual storage deal (offline deal) - dataRef := &storagemarket.DataRef{ - TransferType: storagemarket.TTManual, - Root: rootCid, - PieceCid: &pieceInfo.PieceCID, - PieceSize: pieceInfo.PieceSize.Unpadded(), - } - - proposalCid, err := client.ClientStartDeal(ctx, &api.StartDealParams{ - Data: dataRef, - Wallet: addr, - Miner: maddr, - EpochPrice: types.NewInt(1000000), - DealStartEpoch: startEpoch, - MinBlocksDuration: uint64(build.MinDealDuration), - FastRetrieval: fastRet, - }) - require.NoError(t, err) - - // Wait for the deal to reach StorageDealCheckForAcceptance on the client - cd, err := client.ClientGetDealInfo(ctx, *proposalCid) - require.NoError(t, err) - require.Eventually(t, func() bool { - cd, _ := client.ClientGetDealInfo(ctx, *proposalCid) - return cd.State == storagemarket.StorageDealCheckForAcceptance - }, 30*time.Second, 1*time.Second, "actual deal status is %s", storagemarket.DealStates[cd.State]) - - // Create a CAR file from the raw file - carFileDir := t.TempDir() - carFilePath := filepath.Join(carFileDir, "out.car") - err = client.ClientGenCar(ctx, api.FileRef{Path: inFile}, carFilePath) - require.NoError(t, err) - - // Import the CAR file on the miner - this is the equivalent to - // transferring the file across the wire in a normal (non-offline) deal - err = miner.DealsImportData(ctx, *proposalCid, carFilePath) - require.NoError(t, err) - - // Wait for the deal to be published - dh.WaitDealPublished(ctx, proposalCid) - - t.Logf("deal published, retrieving") - - // Retrieve the deal - outFile := dh.PerformRetrieval(ctx, proposalCid, rootCid, false) - - kit.AssertFilesEqual(t, inFile, outFile) - - } - - t.Run("stdretrieval", func(t *testing.T) { runTest(t, false) }) - t.Run("fastretrieval", func(t *testing.T) { runTest(t, true) }) -} - -func TestZeroPricePerByteRetrieval(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode") - } - - kit.QuietMiningLogs() - - var ( - blockTime = 10 * time.Millisecond - startEpoch = abi.ChainEpoch(2 << 12) - ) - - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs()) - ens.InterconnectAll().BeginMining(blockTime) - - ctx := context.Background() - - ask, err := miner.MarketGetRetrievalAsk(ctx) - require.NoError(t, err) - - ask.PricePerByte = abi.NewTokenAmount(0) - err = miner.MarketSetRetrievalAsk(ctx, ask) - require.NoError(t, err) - - dh := kit.NewDealHarness(t, client, miner) - runConcurrentDeals(t, dh, fullDealCyclesOpts{ - n: 1, - startEpoch: startEpoch, + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1, FastRetrieval: true}) + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1, FastRetrieval: true}) }) } diff --git a/itests/kit/deals.go b/itests/kit/deals.go index bf986a5e7ce..aa2ee8a072d 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -2,26 +2,27 @@ package kit import ( "context" + "fmt" "io/ioutil" "os" "testing" "time" - "github.com/ipfs/go-cid" - files "github.com/ipfs/go-ipfs-files" - "github.com/ipld/go-car" - "github.com/stretchr/testify/require" - "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + "github.com/ipfs/go-cid" + files "github.com/ipfs/go-ipfs-files" ipld "github.com/ipfs/go-ipld-format" dag "github.com/ipfs/go-merkledag" dstest "github.com/ipfs/go-merkledag/test" unixfile "github.com/ipfs/go-unixfs/file" + "github.com/ipld/go-car" + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" ) type DealHarness struct { @@ -246,3 +247,35 @@ func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, file *os.File) (o return tmpfile } + +type RunConcurrentDealsOpts struct { + N int + FastRetrieval bool + CarExport bool + StartEpoch abi.ChainEpoch +} + +func (dh *DealHarness) RunConcurrentDeals(opts RunConcurrentDealsOpts) { + errgrp, _ := errgroup.WithContext(context.Background()) + for i := 0; i < opts.N; i++ { + i := i + errgrp.Go(func() (err error) { + defer func() { + // This is necessary because golang can't deal with test + // failures being reported from children goroutines ¯\_(ツ)_/¯ + if r := recover(); r != nil { + err = fmt.Errorf("deal failed: %s", r) + } + }() + deal, res, inPath := dh.MakeOnlineDeal(context.Background(), MakeFullDealParams{ + Rseed: 5 + i, + FastRet: opts.FastRetrieval, + StartEpoch: opts.StartEpoch, + }) + outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, opts.CarExport) + AssertFilesEqual(dh.t, inPath, outPath) + return nil + }) + } + require.NoError(dh.t, errgrp.Wait()) +} From 58f348cb7f0265198d19fa463af9b41968c749c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 23 Jun 2021 19:14:27 +0100 Subject: [PATCH 71/72] add ability to suspend deal-making until CE is stable. --- itests/ccupgrade_test.go | 5 ++++- itests/kit/deals.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index 71bb4c06571..eac2523bf6e 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -62,7 +62,10 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { require.NoError(t, err) dh := kit.NewDealHarness(t, client, miner) - deal, res, inPath := dh.MakeOnlineDeal(ctx, kit.MakeFullDealParams{Rseed: 6}) + deal, res, inPath := dh.MakeOnlineDeal(ctx, kit.MakeFullDealParams{ + Rseed: 6, + SuspendUntilCryptoeconStable: true, + }) outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, false) kit.AssertFilesEqual(t, inPath, outPath) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index aa2ee8a072d..8d90a032bd3 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -35,6 +35,30 @@ type MakeFullDealParams struct { Rseed int FastRet bool StartEpoch abi.ChainEpoch + + // SuspendUntilCryptoeconStable suspends deal-making, until cryptoecon + // parameters are stabilised. This affects projected collateral, and tests + // will fail in network version 13 and higher if deals are started too soon + // after network birth. + // + // The reason is that the formula for collateral calculation takes + // circulating supply into account: + // + // [portion of power this deal will be] * [~1% of tokens]. + // + // In the first epochs after genesis, the total circulating supply is + // changing dramatically in percentual terms. Therefore, if the deal is + // proposed too soon, by the time it gets published on chain, the quoted + // provider collateral will no longer be valid. + // + // The observation is that deals fail with: + // + // GasEstimateMessageGas error: estimating gas used: message execution + // failed: exit 16, reason: Provider collateral out of bounds. (RetCode=16) + // + // Enabling this will suspend deal-making until the network has reached a + // height of 150. + SuspendUntilCryptoeconStable bool } // NewDealHarness creates a test harness that contains testing utilities for deals. @@ -56,6 +80,12 @@ func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, params MakeFullDealPa dh.t.Logf("FILE CID: %s", res.Root) + if params.SuspendUntilCryptoeconStable { + dh.t.Logf("deal-making suspending until cryptecon parameters have stabilised") + ts := dh.client.WaitTillChain(ctx, HeightAtLeast(150)) + dh.t.Logf("deal-making continuing; current height is %d", ts.Height()) + } + deal = dh.StartDeal(ctx, res.Root, params.FastRet, params.StartEpoch) // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this From 6a48fbbc118493b238f889d1e06bc600e4c4753a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 23 Jun 2021 19:21:42 +0100 Subject: [PATCH 72/72] increase suspension threshold to 300. --- itests/kit/deals.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 8d90a032bd3..d9129b76a86 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -57,7 +57,7 @@ type MakeFullDealParams struct { // failed: exit 16, reason: Provider collateral out of bounds. (RetCode=16) // // Enabling this will suspend deal-making until the network has reached a - // height of 150. + // height of 300. SuspendUntilCryptoeconStable bool } @@ -82,7 +82,7 @@ func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, params MakeFullDealPa if params.SuspendUntilCryptoeconStable { dh.t.Logf("deal-making suspending until cryptecon parameters have stabilised") - ts := dh.client.WaitTillChain(ctx, HeightAtLeast(150)) + ts := dh.client.WaitTillChain(ctx, HeightAtLeast(300)) dh.t.Logf("deal-making continuing; current height is %d", ts.Height()) }