feat: payment channel CLI tests
This commit is contained in:
parent
2d73b04f7d
commit
043b63d8d8
56
api/test/blockminer.go
Normal file
56
api/test/blockminer.go
Normal file
@ -0,0 +1,56 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
)
|
||||
|
||||
type BlockMiner struct {
|
||||
ctx context.Context
|
||||
t *testing.T
|
||||
miner TestStorageNode
|
||||
blocktime time.Duration
|
||||
mine int64
|
||||
nulls int64
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewBlockMiner(ctx context.Context, t *testing.T, miner TestStorageNode, blocktime time.Duration) *BlockMiner {
|
||||
return &BlockMiner{
|
||||
ctx: ctx,
|
||||
t: t,
|
||||
miner: miner,
|
||||
blocktime: blocktime,
|
||||
mine: int64(1),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (bm *BlockMiner) MineBlocks() {
|
||||
time.Sleep(time.Second)
|
||||
go func() {
|
||||
defer close(bm.done)
|
||||
for atomic.LoadInt64(&bm.mine) == 1 {
|
||||
time.Sleep(bm.blocktime)
|
||||
nulls := atomic.SwapInt64(&bm.nulls, 0)
|
||||
if err := bm.miner.MineOne(bm.ctx, miner.MineReq{
|
||||
InjectNulls: abi.ChainEpoch(nulls),
|
||||
Done: func(bool, error) {},
|
||||
}); err != nil {
|
||||
bm.t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (bm *BlockMiner) Stop() {
|
||||
atomic.AddInt64(&bm.mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-bm.done
|
||||
}
|
@ -20,7 +20,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
@ -47,7 +47,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -84,7 +84,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -148,7 +148,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -203,7 +203,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
@ -24,7 +24,7 @@ var log = logging.Logger("apitest")
|
||||
|
||||
func (ts *testSuite) testMining(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@ -55,7 +55,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
|
@ -23,14 +23,13 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
)
|
||||
|
||||
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 2, oneMiner)
|
||||
n, sn := b(t, 2, OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
@ -51,8 +50,8 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
}
|
||||
|
||||
// start mining blocks
|
||||
bm := newBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.mineBlocks()
|
||||
bm := NewBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.MineBlocks()
|
||||
|
||||
// send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
@ -60,7 +59,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
||||
SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
||||
|
||||
// setup the payment channel
|
||||
createrAddr, err := paymentCreator.WalletDefaultAddress(ctx)
|
||||
@ -201,10 +200,10 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
}
|
||||
|
||||
// shut down mining
|
||||
bm.stop()
|
||||
bm.Stop()
|
||||
}
|
||||
|
||||
func waitForBlocks(ctx context.Context, t *testing.T, bm *blockMiner, paymentReceiver TestNode, receiverAddr address.Address, count int) {
|
||||
func waitForBlocks(ctx context.Context, t *testing.T, bm *BlockMiner, paymentReceiver TestNode, 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 {
|
||||
@ -249,73 +248,3 @@ func waitForMessage(ctx context.Context, t *testing.T, paymentCreator TestNode,
|
||||
fmt.Println("Confirmed", desc)
|
||||
return res
|
||||
}
|
||||
|
||||
type blockMiner struct {
|
||||
ctx context.Context
|
||||
t *testing.T
|
||||
miner TestStorageNode
|
||||
blocktime time.Duration
|
||||
mine int64
|
||||
nulls int64
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func newBlockMiner(ctx context.Context, t *testing.T, miner TestStorageNode, blocktime time.Duration) *blockMiner {
|
||||
return &blockMiner{
|
||||
ctx: ctx,
|
||||
t: t,
|
||||
miner: miner,
|
||||
blocktime: blocktime,
|
||||
mine: int64(1),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (bm *blockMiner) mineBlocks() {
|
||||
time.Sleep(time.Second)
|
||||
go func() {
|
||||
defer close(bm.done)
|
||||
for atomic.LoadInt64(&bm.mine) == 1 {
|
||||
time.Sleep(bm.blocktime)
|
||||
nulls := atomic.SwapInt64(&bm.nulls, 0)
|
||||
if err := bm.miner.MineOne(bm.ctx, miner.MineReq{
|
||||
InjectNulls: abi.ChainEpoch(nulls),
|
||||
Done: func(bool, error) {},
|
||||
}); err != nil {
|
||||
bm.t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (bm *blockMiner) stop() {
|
||||
atomic.AddInt64(&bm.mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-bm.done
|
||||
}
|
||||
|
||||
func sendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.Address, amount abi.TokenAmount) {
|
||||
|
||||
senderAddr, err := sender.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
From: senderAddr,
|
||||
To: addr,
|
||||
Value: amount,
|
||||
}
|
||||
|
||||
sm, err := sender.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := sender.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("did not successfully send money")
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -14,10 +16,16 @@ import (
|
||||
|
||||
type TestNode struct {
|
||||
api.FullNode
|
||||
// ListenAddr is the address on which an API server is listening, if an
|
||||
// API server is created for this Node
|
||||
ListenAddr multiaddr.Multiaddr
|
||||
}
|
||||
|
||||
type TestStorageNode struct {
|
||||
api.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
|
||||
}
|
||||
@ -54,11 +62,11 @@ func TestApis(t *testing.T, b APIBuilder) {
|
||||
t.Run("testMiningReal", ts.testMiningReal)
|
||||
}
|
||||
|
||||
var oneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
|
||||
func (ts *testSuite) testVersion(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
@ -70,7 +78,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testID(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, oneMiner)
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
id, err := api.ID(ctx)
|
||||
@ -82,7 +90,7 @@ func (ts *testSuite) testID(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testConnectTwo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 2, oneMiner)
|
||||
apis, _ := ts.makeNodes(t, 2, OneMiner)
|
||||
|
||||
p, err := apis[0].NetPeers(ctx)
|
||||
if err != nil {
|
||||
|
36
api/test/util.go
Normal file
36
api/test/util.go
Normal file
@ -0,0 +1,36 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func SendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.Address, amount abi.TokenAmount) {
|
||||
senderAddr, err := sender.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
From: senderAddr,
|
||||
To: addr,
|
||||
Value: amount,
|
||||
}
|
||||
|
||||
sm, err := sender.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := sender.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("did not successfully send money")
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@ -113,7 +113,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
27
cli/cmd.go
27
cli/cmd.go
@ -67,6 +67,19 @@ func (a APIInfo) AuthHeader() http.Header {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The flag passed on the command line with the listen address of the API
|
||||
// server (only used by the tests)
|
||||
func flagForAPI(t repo.RepoType) string {
|
||||
switch t {
|
||||
case repo.FullNode:
|
||||
return "api"
|
||||
case repo.StorageMiner:
|
||||
return "miner-api"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown repo type: %v", t))
|
||||
}
|
||||
}
|
||||
|
||||
func flagForRepo(t repo.RepoType) string {
|
||||
switch t {
|
||||
case repo.FullNode:
|
||||
@ -102,6 +115,20 @@ func envForRepoDeprecation(t repo.RepoType) string {
|
||||
}
|
||||
|
||||
func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
// Check if there was a flag passed with the listen address of the API
|
||||
// server (only used by the tests)
|
||||
apiFlag := flagForAPI(t)
|
||||
if ctx.IsSet(apiFlag) {
|
||||
strma := ctx.String(apiFlag)
|
||||
strma = strings.TrimSpace(strma)
|
||||
|
||||
apima, err := multiaddr.NewMultiaddr(strma)
|
||||
if err != nil {
|
||||
return APIInfo{}, err
|
||||
}
|
||||
return APIInfo{Addr: apima}, nil
|
||||
}
|
||||
|
||||
envKey := envForRepo(t)
|
||||
env, ok := os.LookupEnv(envKey)
|
||||
if !ok {
|
||||
|
25
cli/paych.go
25
cli/paych.go
@ -5,9 +5,8 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
@ -71,7 +70,7 @@ var paychGetCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(chAddr)
|
||||
fmt.Fprintln(cctx.App.Writer, chAddr)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -94,7 +93,7 @@ var paychListCmd = &cli.Command{
|
||||
}
|
||||
|
||||
for _, v := range chs {
|
||||
fmt.Println(v.String())
|
||||
fmt.Fprintln(cctx.App.Writer, v.String())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@ -135,7 +134,7 @@ var paychSettleCmd = &cli.Command{
|
||||
return fmt.Errorf("settle message execution failed (exit code %d)", mwait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
fmt.Printf("Settled channel %s\n", ch)
|
||||
fmt.Fprintf(cctx.App.Writer, "Settled channel %s\n", ch)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -175,7 +174,7 @@ var paychCloseCmd = &cli.Command{
|
||||
return fmt.Errorf("collect message execution failed (exit code %d)", mwait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
fmt.Printf("Collected funds for channel %s\n", ch)
|
||||
fmt.Fprintf(cctx.App.Writer, "Collected funds for channel %s\n", ch)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -239,7 +238,7 @@ var paychVoucherCreateCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(enc)
|
||||
fmt.Fprintln(cctx.App.Writer, enc)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -275,7 +274,7 @@ var paychVoucherCheckCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("voucher is valid")
|
||||
fmt.Fprintln(cctx.App.Writer, "voucher is valid")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -356,9 +355,9 @@ var paychVoucherListCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Lane %d, Nonce %d: %s; %s\n", v.Lane, v.Nonce, v.Amount.String(), enc)
|
||||
fmt.Fprintf(cctx.App.Writer, "Lane %d, Nonce %d: %s; %s\n", v.Lane, v.Nonce, v.Amount.String(), enc)
|
||||
} else {
|
||||
fmt.Printf("Lane %d, Nonce %d: %s\n", v.Lane, v.Nonce, v.Amount.String())
|
||||
fmt.Fprintf(cctx.App.Writer, "Lane %d, Nonce %d: %s\n", v.Lane, v.Nonce, v.Amount.String())
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,8 +414,8 @@ var paychVoucherBestSpendableCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(enc)
|
||||
fmt.Printf("Amount: %s\n", best.Amount)
|
||||
fmt.Fprintln(cctx.App.Writer, enc)
|
||||
fmt.Fprintf(cctx.App.Writer, "Amount: %s\n", best.Amount)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -462,7 +461,7 @@ var paychVoucherSubmitCmd = &cli.Command{
|
||||
return fmt.Errorf("message execution failed (exit code %d)", mwait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
fmt.Println("channel updated successfully")
|
||||
fmt.Fprintln(cctx.App.Writer, "channel updated successfully")
|
||||
|
||||
return nil
|
||||
},
|
||||
|
228
cli/paych_test.go
Normal file
228
cli/paych_test.go
Normal file
@ -0,0 +1,228 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/apibstore"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/test"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
builder "github.com/filecoin-project/lotus/node/test"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
}
|
||||
|
||||
// TestPaymentChannels does a basic test to exercise the payment channel CLI
|
||||
// commands
|
||||
func TestPaymentChannels(t *testing.T) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
blocktime := 5 * time.Millisecond
|
||||
ctx := context.Background()
|
||||
n, sn := builder.RPCMockSbBuilder(t, 2, test.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 := test.NewBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.MineBlocks()
|
||||
|
||||
// Send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
test.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
||||
|
||||
// Get the creator's address
|
||||
creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create mock CLI
|
||||
mockCLI := newMockCLI(t)
|
||||
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
||||
receiverCLI := mockCLI.client(paymentReceiver.ListenAddr)
|
||||
|
||||
// creator: paych get <creator> <receiver> <amount>
|
||||
channelAmt := "100000"
|
||||
cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt}
|
||||
chstr := creatorCLI.runCmd(paychGetCmd, cmd)
|
||||
|
||||
chAddr, err := address.NewFromString(chstr)
|
||||
require.NoError(t, err)
|
||||
|
||||
// creator: paych voucher create <channel> <amount>
|
||||
voucherAmt := 100
|
||||
vamt := strconv.Itoa(voucherAmt)
|
||||
cmd = []string{chAddr.String(), vamt}
|
||||
voucher := creatorCLI.runCmd(paychVoucherCreateCmd, cmd)
|
||||
|
||||
// receiver: paych voucher add <channel> <voucher>
|
||||
cmd = []string{chAddr.String(), voucher}
|
||||
receiverCLI.runCmd(paychVoucherAddCmd, cmd)
|
||||
|
||||
// creator: paych settle <channel>
|
||||
cmd = []string{chAddr.String()}
|
||||
creatorCLI.runCmd(paychSettleCmd, cmd)
|
||||
|
||||
// Wait for the chain to reach the settle height
|
||||
chState := getPaychState(ctx, t, paymentReceiver, chAddr)
|
||||
waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt)
|
||||
|
||||
// receiver: paych collect <channel>
|
||||
cmd = []string{chAddr.String()}
|
||||
receiverCLI.runCmd(paychCloseCmd, cmd)
|
||||
}
|
||||
|
||||
type mockCLI struct {
|
||||
t *testing.T
|
||||
cctx *cli.Context
|
||||
out *bytes.Buffer
|
||||
}
|
||||
|
||||
func newMockCLI(t *testing.T) *mockCLI {
|
||||
// Create a CLI App with an --api flag so that we can specify which node
|
||||
// the command should be executed against
|
||||
app := cli.NewApp()
|
||||
app.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "api",
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
var out bytes.Buffer
|
||||
app.Writer = &out
|
||||
app.Setup()
|
||||
|
||||
cctx := cli.NewContext(app, &flag.FlagSet{}, nil)
|
||||
return &mockCLI{t: t, cctx: cctx, out: &out}
|
||||
}
|
||||
|
||||
func (c *mockCLI) client(addr multiaddr.Multiaddr) *mockCLIClient {
|
||||
return &mockCLIClient{t: c.t, addr: addr, cctx: c.cctx, out: c.out}
|
||||
}
|
||||
|
||||
// mockCLIClient runs commands against a particular node
|
||||
type mockCLIClient struct {
|
||||
t *testing.T
|
||||
addr multiaddr.Multiaddr
|
||||
cctx *cli.Context
|
||||
out *bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
||||
// prepend --api=<node api listener address>
|
||||
apiFlag := "--api=" + c.addr.String()
|
||||
input = append([]string{apiFlag}, input...)
|
||||
|
||||
fs := c.flagSet(cmd)
|
||||
err := fs.Parse(input)
|
||||
require.NoError(c.t, err)
|
||||
|
||||
err = cmd.Action(cli.NewContext(c.cctx.App, fs, c.cctx))
|
||||
require.NoError(c.t, err)
|
||||
|
||||
// Get the output
|
||||
str := strings.TrimSpace(c.out.String())
|
||||
c.out.Reset()
|
||||
return str
|
||||
}
|
||||
|
||||
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
|
||||
// Apply app level flags (so we can process --api 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
|
||||
}
|
||||
|
||||
// waitForHeight waits for the node to reach the given chain epoch
|
||||
func waitForHeight(ctx context.Context, t *testing.T, node test.TestNode, 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 {
|
||||
close(atHeight)
|
||||
return nil
|
||||
}, nil, 1, height)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-atHeight:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
|
||||
// getPaychState gets the state of the payment channel with the given address
|
||||
func getPaychState(ctx context.Context, t *testing.T, node test.TestNode, chAddr address.Address) paych.State {
|
||||
act, err := node.StateGetActor(ctx, chAddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
store := cbor.NewCborStore(apibstore.NewAPIBlockstore(node))
|
||||
var chState paych.State
|
||||
err = store.Get(ctx, act.Head, &chState)
|
||||
require.NoError(t, err)
|
||||
|
||||
return chState
|
||||
}
|
@ -1,55 +1,21 @@
|
||||
package node_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
builder "github.com/filecoin-project/lotus/node/test"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
"github.com/filecoin-project/lotus/storage/mockstorage"
|
||||
|
||||
"github.com/filecoin-project/go-storedcounter"
|
||||
"github.com/ipfs/go-datastore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"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/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
"github.com/filecoin-project/lotus/api/test"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||
"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"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
modtest "github.com/filecoin-project/lotus/node/modules/testing"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -62,435 +28,12 @@ func init() {
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
}
|
||||
|
||||
func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, act address.Address, pk crypto.PrivKey, tnd test.TestNode, mn mocknet.Mocknet, opts node.Option) test.TestStorageNode {
|
||||
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("/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 < test.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(&saminer.ChangePeerIDParams{NewID: abi.PeerID(peerid)})
|
||||
require.NoError(t, err)
|
||||
|
||||
msg := &types.Message{
|
||||
To: act,
|
||||
From: waddr,
|
||||
Method: builtin.MethodsMiner.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 miner.MineReq)
|
||||
// TODO: use stop
|
||||
_, err = node.New(ctx,
|
||||
node.StorageMiner(&minerapi),
|
||||
node.Online(),
|
||||
node.Repo(r),
|
||||
node.Test(),
|
||||
|
||||
node.MockHost(mn),
|
||||
|
||||
node.Override(new(api.FullNode), tnd),
|
||||
node.Override(new(*miner.Miner), miner.NewTestMiner(mineBlock, act)),
|
||||
|
||||
opts,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to construct node: %v", err)
|
||||
}
|
||||
|
||||
/*// 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 miner.MineReq) error {
|
||||
select {
|
||||
case mineBlock <- req:
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne}
|
||||
}
|
||||
|
||||
func builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
ctx := context.Background()
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, 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
|
||||
var maddrs []address.Address
|
||||
var genaccs []genesis.Actor
|
||||
var 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, test.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(400_000_000), 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,
|
||||
Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past
|
||||
VerifregRootKey: gen.DefaultVerifregRootkeyActor,
|
||||
}
|
||||
|
||||
// END PRESEAL SECTION
|
||||
|
||||
for i := 0; i < nFull; i++ {
|
||||
var genesis node.Option
|
||||
if i == 0 {
|
||||
genesis = node.Override(new(modules.Genesis), modtest.MakeGenesisMem(&genbuf, *templ))
|
||||
} else {
|
||||
genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes()))
|
||||
}
|
||||
|
||||
var err error
|
||||
// TODO: Don't ignore stop
|
||||
_, err = node.New(ctx,
|
||||
node.FullAPI(&fulls[i].FullNode),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
node.MockHost(mn),
|
||||
node.Test(),
|
||||
|
||||
genesis,
|
||||
)
|
||||
if 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
|
||||
|
||||
storers[i] = testStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options())
|
||||
if err := storers[i].StorageAddLocal(ctx, presealDirs[i]); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
/*
|
||||
sma := storers[i].StorageMiner.(*impl.StorageMinerAPI)
|
||||
|
||||
psd := presealDirs[i]
|
||||
*/
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(storers) > 0 {
|
||||
// Mine 2 blocks to setup some CE stuff in some actors
|
||||
var wait sync.Mutex
|
||||
wait.Lock()
|
||||
|
||||
storers[0].MineOne(ctx, miner.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
storers[0].MineOne(ctx, miner.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
ctx := context.Background()
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, 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
|
||||
var genaccs []genesis.Actor
|
||||
var maddrs []address.Address
|
||||
var presealDirs []string
|
||||
var keys []*wallet.Key
|
||||
var pidKeys []crypto.PrivKey
|
||||
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)
|
||||
}
|
||||
|
||||
preseals := storage[i].Preseal
|
||||
if preseals == test.PresealGenesis {
|
||||
preseals = test.GenesisPreseals
|
||||
}
|
||||
|
||||
genm, k, err := mockstorage.PreSeal(2048, 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(400_000_000_000), types.NewInt(build.FilecoinPrecision)),
|
||||
Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(),
|
||||
})
|
||||
|
||||
keys = append(keys, wk)
|
||||
pidKeys = append(pidKeys, pk)
|
||||
presealDirs = append(presealDirs, tdir)
|
||||
maddrs = append(maddrs, maddr)
|
||||
genms = append(genms, *genm)
|
||||
}
|
||||
templ := &genesis.Template{
|
||||
Accounts: genaccs,
|
||||
Miners: genms,
|
||||
Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000),
|
||||
VerifregRootKey: gen.DefaultVerifregRootkeyActor,
|
||||
}
|
||||
|
||||
// END PRESEAL SECTION
|
||||
|
||||
for i := 0; i < nFull; i++ {
|
||||
var genesis node.Option
|
||||
if i == 0 {
|
||||
genesis = node.Override(new(modules.Genesis), modtest.MakeGenesisMem(&genbuf, *templ))
|
||||
} else {
|
||||
genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes()))
|
||||
}
|
||||
|
||||
var err error
|
||||
// TODO: Don't ignore stop
|
||||
_, err = node.New(ctx,
|
||||
node.FullAPI(&fulls[i].FullNode),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
node.MockHost(mn),
|
||||
node.Test(),
|
||||
|
||||
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
|
||||
|
||||
genesis,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", 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,
|
||||
}
|
||||
}
|
||||
|
||||
storers[i] = testStorageNode(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(build.DefaultSectorSize(), sectors), nil
|
||||
}),
|
||||
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
|
||||
node.Unset(new(*sectorstorage.Manager)),
|
||||
))
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(storers) > 0 {
|
||||
// Mine 2 blocks to setup some CE stuff in some actors
|
||||
var wait sync.Mutex
|
||||
wait.Lock()
|
||||
|
||||
storers[0].MineOne(ctx, miner.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
storers[0].MineOne(ctx, miner.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func TestAPI(t *testing.T) {
|
||||
test.TestApis(t, builder)
|
||||
}
|
||||
|
||||
func rpcBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
fullApis, storaApis := builder(t, nFull, storage)
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, len(storage))
|
||||
|
||||
for i, a := range fullApis {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", a)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
var err error
|
||||
fulls[i].FullNode, _, err = client.NewFullNodeRPC("ws://"+testServ.Listener.Addr().String(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, a := range storaApis {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", a)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
var err error
|
||||
storers[i].StorageMiner, _, err = client.NewStorageMinerRPC("ws://"+testServ.Listener.Addr().String(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
storers[i].MineOne = a.MineOne
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
test.TestApis(t, builder.Builder)
|
||||
}
|
||||
|
||||
func TestAPIRPC(t *testing.T) {
|
||||
test.TestApis(t, rpcBuilder)
|
||||
test.TestApis(t, builder.RPCBuilder)
|
||||
}
|
||||
|
||||
func TestAPIDealFlow(t *testing.T) {
|
||||
@ -501,16 +44,16 @@ func TestAPIDealFlow(t *testing.T) {
|
||||
logging.SetLogLevel("storageminer", "ERROR")
|
||||
|
||||
t.Run("TestDealFlow", func(t *testing.T) {
|
||||
test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, false, false)
|
||||
test.TestDealFlow(t, builder.MockSbBuilder, 10*time.Millisecond, false, false)
|
||||
})
|
||||
t.Run("WithExportedCAR", func(t *testing.T) {
|
||||
test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, true, false)
|
||||
test.TestDealFlow(t, builder.MockSbBuilder, 10*time.Millisecond, true, false)
|
||||
})
|
||||
t.Run("TestDoubleDealFlow", func(t *testing.T) {
|
||||
test.TestDoubleDealFlow(t, mockSbBuilder, 10*time.Millisecond)
|
||||
test.TestDoubleDealFlow(t, builder.MockSbBuilder, 10*time.Millisecond)
|
||||
})
|
||||
t.Run("TestFastRetrievalDealFlow", func(t *testing.T) {
|
||||
test.TestFastRetrievalDealFlow(t, mockSbBuilder, 10*time.Millisecond)
|
||||
test.TestFastRetrievalDealFlow(t, builder.MockSbBuilder, 10*time.Millisecond)
|
||||
})
|
||||
}
|
||||
|
||||
@ -528,15 +71,15 @@ func TestAPIDealFlowReal(t *testing.T) {
|
||||
saminer.PreCommitChallengeDelay = 5
|
||||
|
||||
t.Run("basic", func(t *testing.T) {
|
||||
test.TestDealFlow(t, builder, time.Second, false, false)
|
||||
test.TestDealFlow(t, builder.Builder, time.Second, false, false)
|
||||
})
|
||||
|
||||
t.Run("fast-retrieval", func(t *testing.T) {
|
||||
test.TestDealFlow(t, builder, time.Second, false, true)
|
||||
test.TestDealFlow(t, builder.Builder, time.Second, false, true)
|
||||
})
|
||||
|
||||
t.Run("retrieval-second", func(t *testing.T) {
|
||||
test.TestSenondDealRetrieval(t, builder, time.Second)
|
||||
test.TestSenondDealRetrieval(t, builder.Builder, time.Second)
|
||||
})
|
||||
}
|
||||
|
||||
@ -547,7 +90,7 @@ func TestDealMining(t *testing.T) {
|
||||
logging.SetLogLevel("sub", "ERROR")
|
||||
logging.SetLogLevel("storageminer", "ERROR")
|
||||
|
||||
test.TestDealMining(t, mockSbBuilder, 50*time.Millisecond, false)
|
||||
test.TestDealMining(t, builder.MockSbBuilder, 50*time.Millisecond, false)
|
||||
}
|
||||
|
||||
func TestPledgeSectors(t *testing.T) {
|
||||
@ -558,11 +101,11 @@ func TestPledgeSectors(t *testing.T) {
|
||||
logging.SetLogLevel("storageminer", "ERROR")
|
||||
|
||||
t.Run("1", func(t *testing.T) {
|
||||
test.TestPledgeSector(t, mockSbBuilder, 50*time.Millisecond, 1)
|
||||
test.TestPledgeSector(t, builder.MockSbBuilder, 50*time.Millisecond, 1)
|
||||
})
|
||||
|
||||
t.Run("100", func(t *testing.T) {
|
||||
test.TestPledgeSector(t, mockSbBuilder, 50*time.Millisecond, 100)
|
||||
test.TestPledgeSector(t, builder.MockSbBuilder, 50*time.Millisecond, 100)
|
||||
})
|
||||
|
||||
t.Run("1000", func(t *testing.T) {
|
||||
@ -570,7 +113,7 @@ func TestPledgeSectors(t *testing.T) {
|
||||
t.Skip("skipping test in short mode")
|
||||
}
|
||||
|
||||
test.TestPledgeSector(t, mockSbBuilder, 50*time.Millisecond, 1000)
|
||||
test.TestPledgeSector(t, builder.MockSbBuilder, 50*time.Millisecond, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
@ -585,7 +128,7 @@ func TestWindowedPost(t *testing.T) {
|
||||
logging.SetLogLevel("sub", "ERROR")
|
||||
logging.SetLogLevel("storageminer", "ERROR")
|
||||
|
||||
test.TestWindowPost(t, mockSbBuilder, 2*time.Millisecond, 10)
|
||||
test.TestWindowPost(t, builder.MockSbBuilder, 2*time.Millisecond, 10)
|
||||
}
|
||||
|
||||
func TestCCUpgrade(t *testing.T) {
|
||||
@ -595,7 +138,7 @@ func TestCCUpgrade(t *testing.T) {
|
||||
logging.SetLogLevel("sub", "ERROR")
|
||||
logging.SetLogLevel("storageminer", "ERROR")
|
||||
|
||||
test.TestCCUpgrade(t, mockSbBuilder, 5*time.Millisecond)
|
||||
test.TestCCUpgrade(t, builder.MockSbBuilder, 5*time.Millisecond)
|
||||
}
|
||||
|
||||
func TestPaymentChannels(t *testing.T) {
|
||||
@ -606,5 +149,5 @@ func TestPaymentChannels(t *testing.T) {
|
||||
logging.SetLogLevel("pubsub", "ERROR")
|
||||
logging.SetLogLevel("storageminer", "ERROR")
|
||||
|
||||
test.TestPaymentChannels(t, mockSbBuilder, 5*time.Millisecond)
|
||||
test.TestPaymentChannels(t, builder.MockSbBuilder, 5*time.Millisecond)
|
||||
}
|
||||
|
498
node/test/builder.go
Normal file
498
node/test/builder.go
Normal file
@ -0,0 +1,498 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"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/test"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||
"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"
|
||||
miner2 "github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
testing2 "github.com/filecoin-project/lotus/node/modules/testing"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/lotus/storage/mockstorage"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"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"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Address, act address.Address, pk crypto.PrivKey, tnd test.TestNode, mn mocknet.Mocknet, opts node.Option) test.TestStorageNode {
|
||||
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("/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 < test.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(&miner.ChangePeerIDParams{NewID: abi.PeerID(peerid)})
|
||||
require.NoError(t, err)
|
||||
|
||||
msg := &types.Message{
|
||||
To: act,
|
||||
From: waddr,
|
||||
Method: builtin.MethodsMiner.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 miner2.MineReq)
|
||||
// TODO: use stop
|
||||
_, err = node.New(ctx,
|
||||
node.StorageMiner(&minerapi),
|
||||
node.Online(),
|
||||
node.Repo(r),
|
||||
node.Test(),
|
||||
|
||||
node.MockHost(mn),
|
||||
|
||||
node.Override(new(api.FullNode), tnd),
|
||||
node.Override(new(*miner2.Miner), miner2.NewTestMiner(mineBlock, act)),
|
||||
|
||||
opts,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to construct node: %v", err)
|
||||
}
|
||||
|
||||
/*// 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 miner2.MineReq) error {
|
||||
select {
|
||||
case mineBlock <- req:
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne}
|
||||
}
|
||||
|
||||
func Builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
ctx := context.Background()
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, 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
|
||||
var maddrs []address.Address
|
||||
var genaccs []genesis.Actor
|
||||
var 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, test.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,
|
||||
Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past
|
||||
VerifregRootKey: gen.DefaultVerifregRootkeyActor,
|
||||
}
|
||||
|
||||
// END PRESEAL SECTION
|
||||
|
||||
for i := 0; i < nFull; 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()))
|
||||
}
|
||||
|
||||
var err error
|
||||
// TODO: Don't ignore stop
|
||||
_, err = node.New(ctx,
|
||||
node.FullAPI(&fulls[i].FullNode),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
node.MockHost(mn),
|
||||
node.Test(),
|
||||
|
||||
genesis,
|
||||
)
|
||||
if 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
|
||||
|
||||
storers[i] = CreateTestStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options())
|
||||
if err := storers[i].StorageAddLocal(ctx, presealDirs[i]); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
/*
|
||||
sma := storers[i].StorageMiner.(*impl.StorageMinerAPI)
|
||||
|
||||
psd := presealDirs[i]
|
||||
*/
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(storers) > 0 {
|
||||
// Mine 2 blocks to setup some CE stuff in some actors
|
||||
var wait sync.Mutex
|
||||
wait.Lock()
|
||||
|
||||
_ = storers[0].MineOne(ctx, miner2.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
_ = storers[0].MineOne(ctx, miner2.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
ctx := context.Background()
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, 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
|
||||
var genaccs []genesis.Actor
|
||||
var maddrs []address.Address
|
||||
var keys []*wallet.Key
|
||||
var 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 == test.PresealGenesis {
|
||||
preseals = test.GenesisPreseals
|
||||
}
|
||||
|
||||
genm, k, err := mockstorage.PreSeal(2048, 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(400000000000), 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,
|
||||
Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000),
|
||||
VerifregRootKey: gen.DefaultVerifregRootkeyActor,
|
||||
}
|
||||
|
||||
// END PRESEAL SECTION
|
||||
|
||||
for i := 0; i < nFull; 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()))
|
||||
}
|
||||
|
||||
var err error
|
||||
// TODO: Don't ignore stop
|
||||
_, err = node.New(ctx,
|
||||
node.FullAPI(&fulls[i].FullNode),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
node.MockHost(mn),
|
||||
node.Test(),
|
||||
|
||||
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
|
||||
|
||||
genesis,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", 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,
|
||||
}
|
||||
}
|
||||
|
||||
storers[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(build.DefaultSectorSize(), sectors), nil
|
||||
}),
|
||||
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
|
||||
node.Unset(new(*sectorstorage.Manager)),
|
||||
))
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(storers) > 0 {
|
||||
// Mine 2 blocks to setup some CE stuff in some actors
|
||||
var wait sync.Mutex
|
||||
wait.Lock()
|
||||
|
||||
_ = storers[0].MineOne(ctx, miner2.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
_ = storers[0].MineOne(ctx, miner2.MineReq{Done: func(bool, error) {
|
||||
wait.Unlock()
|
||||
}})
|
||||
wait.Lock()
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func RPCBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return rpcWithBuilder(t, Builder, nFull, storage)
|
||||
}
|
||||
|
||||
func RPCMockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
return rpcWithBuilder(t, MockSbBuilder, nFull, storage)
|
||||
}
|
||||
|
||||
func rpcWithBuilder(t *testing.T, b test.APIBuilder, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||
fullApis, storaApis := b(t, nFull, storage)
|
||||
fulls := make([]test.TestNode, nFull)
|
||||
storers := make([]test.TestStorageNode, len(storage))
|
||||
|
||||
for i, a := range fullApis {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", a)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
addr := testServ.Listener.Addr()
|
||||
listenAddr := "ws://" + addr.String()
|
||||
var err error
|
||||
fulls[i].FullNode, _, err = client.NewFullNodeRPC(listenAddr, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ma, err := parseWSSMultiAddr(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fulls[i].ListenAddr = ma
|
||||
}
|
||||
|
||||
for i, a := range storaApis {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", a)
|
||||
testServ := httptest.NewServer(rpcServer) // todo: close
|
||||
|
||||
addr := testServ.Listener.Addr()
|
||||
listenAddr := "ws://" + addr.String()
|
||||
var err error
|
||||
storers[i].StorageMiner, _, err = client.NewStorageMinerRPC(listenAddr, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ma, err := parseWSSMultiAddr(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
storers[i].ListenAddr = ma
|
||||
storers[i].MineOne = a.MineOne
|
||||
}
|
||||
|
||||
return fulls, storers
|
||||
}
|
||||
|
||||
func parseWSSMultiAddr(addr net.Addr) (multiaddr.Multiaddr, error) {
|
||||
host, port, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ma, err := multiaddr.NewMultiaddr("/ip4/" + host + "/" + addr.Network() + "/" + port + "/wss")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ma, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user