kill old kit 🎉
This commit is contained in:
parent
a8bf7e7bad
commit
a7d8d15c13
@ -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()
|
||||
}
|
@ -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 <Miner addr>
|
||||
out := clientCLI.RunCmd("client", "query-ask", minerAddr.String())
|
||||
require.Regexp(t, regexp.MustCompile("Ask:"), out)
|
||||
|
||||
// Create a deal (non-interactive)
|
||||
// client deal --start-epoch=<start epoch> <cid> <Miner addr> 1000000attofil <duration>
|
||||
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
|
||||
// <cid>
|
||||
// <duration> (in days)
|
||||
// <miner addr>
|
||||
// "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 <cid> <file path>
|
||||
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
|
||||
}
|
@ -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
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
}
|
@ -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")
|
||||
}
|
@ -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=<node api listener address>
|
||||
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)
|
||||
}
|
@ -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}
|
||||
}
|
@ -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
|
||||
}
|
@ -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) {},
|
||||
}
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user