lotus/node/node_test.go

476 lines
12 KiB
Go
Raw Normal View History

2019-07-10 13:06:04 +00:00
package node_test
2019-07-09 16:27:07 +00:00
import (
2019-07-24 23:23:06 +00:00
"bytes"
2019-07-09 16:27:07 +00:00
"context"
2019-10-03 00:02:06 +00:00
"crypto/rand"
"io/ioutil"
2019-07-09 16:36:40 +00:00
"net/http/httptest"
2019-07-09 16:27:07 +00:00
"testing"
"time"
2019-07-09 16:27:07 +00:00
"github.com/filecoin-project/lotus/lib/lotuslog"
"github.com/filecoin-project/lotus/storage/mockstorage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
2020-03-05 22:27:30 +00:00
"github.com/filecoin-project/go-fil-markets/storedcounter"
2019-09-23 15:27:30 +00:00
"github.com/ipfs/go-datastore"
logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p-core/crypto"
2019-09-23 15:27:30 +00:00
"github.com/libp2p/go-libp2p-core/peer"
2019-07-24 23:25:14 +00:00
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
2019-09-23 15:27:30 +00:00
"github.com/stretchr/testify/require"
2019-07-10 17:28:49 +00:00
2020-02-23 15:50:36 +00:00
"github.com/filecoin-project/go-address"
"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"
2020-02-23 15:50:36 +00:00
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
"github.com/filecoin-project/lotus/api/test"
2020-02-23 15:50:36 +00:00
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
2020-02-23 15:50:36 +00:00
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
"github.com/filecoin-project/lotus/chain/types"
2020-02-23 15:50:36 +00:00
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
2020-02-23 15:50:36 +00:00
genesis "github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/lib/jsonrpc"
"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"
sectorstorage "github.com/filecoin-project/sector-storage"
2020-03-27 23:00:21 +00:00
"github.com/filecoin-project/sector-storage/mock"
2019-07-09 16:27:07 +00:00
)
2019-11-30 22:22:26 +00:00
func init() {
2019-12-02 12:51:16 +00:00
_ = logging.SetLogLevel("*", "INFO")
2019-12-03 01:41:31 +00:00
2020-02-27 23:14:15 +00:00
build.SectorSizes = []abi.SectorSize{2048}
power.ConsensusMinerMinPower = big.NewInt(2048)
2019-11-30 22:22:26 +00:00
}
2020-01-14 02:04:33 +00:00
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 {
2019-09-23 15:27:30 +00:00
r := repo.NewMemory(nil)
2019-11-12 17:59:38 +00:00
lr, err := r.Lock(repo.StorageMiner)
2019-09-23 15:27:30 +00:00
require.NoError(t, err)
2019-10-03 00:02:06 +00:00
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,
})
2019-09-23 15:27:30 +00:00
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)
2020-03-06 07:30:20 +00:00
nic := storedcounter.New(ds, datastore.NewKey("/storage/nextid"))
for i := 0; i < nPreseal; i++ {
nic.Next()
}
2020-03-18 01:08:11 +00:00
nic.Next()
2020-03-06 07:30:20 +00:00
2019-09-23 15:27:30 +00:00
err = lr.Close()
require.NoError(t, err)
2019-10-03 00:02:06 +00:00
peerid, err := peer.IDFromPrivateKey(pk)
2019-09-23 15:27:30 +00:00
require.NoError(t, err)
2020-02-23 07:49:15 +00:00
enc, err := actors.SerializeParams(&saminer.ChangePeerIDParams{NewID: peerid})
2019-09-23 15:27:30 +00:00
require.NoError(t, err)
msg := &types.Message{
To: act,
From: waddr,
2020-02-23 07:49:15 +00:00
Method: builtin.MethodsMiner.ChangePeerID,
2019-09-23 15:27:30 +00:00
Params: enc,
Value: types.NewInt(0),
GasPrice: types.NewInt(0),
2020-03-18 20:45:37 +00:00
GasLimit: 1000000,
2019-09-23 15:27:30 +00:00
}
_, err = tnd.MpoolPushMessage(ctx, msg)
require.NoError(t, err)
// start node
var minerapi api.StorageMiner
2019-11-30 23:17:50 +00:00
mineBlock := make(chan struct{})
2019-09-23 15:27:30 +00:00
// TODO: use stop
_, err = node.New(ctx,
node.StorageMiner(&minerapi),
node.Online(),
node.Repo(r),
2019-10-23 11:02:00 +00:00
node.Test(),
2019-09-23 15:27:30 +00:00
node.MockHost(mn),
2019-09-23 15:27:30 +00:00
node.Override(new(api.FullNode), tnd),
2019-11-30 23:17:50 +00:00
node.Override(new(*miner.Miner), miner.NewTestMiner(mineBlock, act)),
2020-01-14 02:04:33 +00:00
opts,
2019-09-23 15:27:30 +00:00
)
if err != nil {
t.Fatalf("failed to construct node: %v", err)
}
2019-09-23 15:27:30 +00:00
/*// Bootstrap with full node
remoteAddrs, err := tnd.NetAddrsListen(ctx)
require.NoError(t, err)
err = minerapi.NetConnect(ctx, remoteAddrs)
require.NoError(t, err)*/
2019-11-30 23:17:50 +00:00
mineOne := func(ctx context.Context) error {
select {
case mineBlock <- struct{}{}:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
2019-09-23 15:27:30 +00:00
2019-12-02 12:51:16 +00:00
return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne}
2019-09-23 15:27:30 +00:00
}
func builder(t *testing.T, nFull int, storage []int) ([]test.TestNode, []test.TestStorageNode) {
2019-07-09 16:27:07 +00:00
ctx := context.Background()
mn := mocknet.New(ctx)
2019-09-23 15:27:30 +00:00
fulls := make([]test.TestNode, nFull)
storers := make([]test.TestStorageNode, len(storage))
2019-07-09 16:27:07 +00:00
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
require.NoError(t, err)
minerPid, err := peer.IDFromPrivateKey(pk)
require.NoError(t, err)
2019-07-24 23:23:06 +00:00
var genbuf bytes.Buffer
2019-11-30 04:43:53 +00:00
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
2020-02-23 07:49:15 +00:00
var genms []genesis.Miner
var maddrs []address.Address
2020-02-23 20:32:14 +00:00
var genaccs []genesis.Actor
var keys []*wallet.Key
2019-11-30 23:17:50 +00:00
var presealDirs []string
for i := 0; i < len(storage); i++ {
2020-02-23 15:50:36 +00:00
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)
}
2020-03-06 07:30:20 +00:00
genm, k, err := seed.PreSeal(maddr, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, nPreseal, tdir, []byte("make genesis mem random"), nil)
if err != nil {
t.Fatal(err)
}
2020-02-23 20:32:14 +00:00
genm.PeerId = minerPid
wk, err := wallet.NewKey(*k)
if err != nil {
return nil, nil
}
2019-11-30 23:17:50 +00:00
2020-02-23 20:32:14 +00:00
genaccs = append(genaccs, genesis.Actor{
Type: genesis.TAccount,
Balance: big.NewInt(40000000000),
Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(),
})
keys = append(keys, wk)
2019-11-30 23:17:50 +00:00
presealDirs = append(presealDirs, tdir)
2020-02-23 07:49:15 +00:00
maddrs = append(maddrs, maddr)
genms = append(genms, *genm)
}
templ := &genesis.Template{
2020-04-14 03:05:19 +00:00
Accounts: genaccs,
Miners: genms,
2020-04-17 23:13:02 +00:00
Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past
}
// END PRESEAL SECTION
2019-09-23 15:27:30 +00:00
for i := 0; i < nFull; i++ {
2019-07-24 23:23:06 +00:00
var genesis node.Option
if i == 0 {
2020-02-23 07:49:15 +00:00
genesis = node.Override(new(modules.Genesis), modtest.MakeGenesisMem(&genbuf, *templ))
2019-07-24 23:23:06 +00:00
} else {
genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes()))
}
2019-07-09 16:27:07 +00:00
var err error
2019-09-17 14:45:09 +00:00
// TODO: Don't ignore stop
_, err = node.New(ctx,
2019-09-23 15:27:30 +00:00
node.FullAPI(&fulls[i].FullNode),
2019-07-10 13:06:04 +00:00
node.Online(),
node.Repo(repo.NewMemory(nil)),
2019-07-29 19:34:34 +00:00
node.MockHost(mn),
2019-10-23 11:02:00 +00:00
node.Test(),
2019-07-24 23:23:06 +00:00
genesis,
2019-07-09 16:27:07 +00:00
)
if err != nil {
t.Fatal(err)
}
2019-09-23 15:27:30 +00:00
}
for i, full := range storage {
// TODO: support non-bootstrap miners
if i != 0 {
t.Fatal("only one storage node supported")
}
if full != 0 {
t.Fatal("storage nodes only supported on the first full node")
}
f := fulls[full]
2020-02-23 20:32:14 +00:00
if _, err := f.FullNode.WalletImport(ctx, &keys[i].KeyInfo); err != nil {
t.Fatal(err)
2020-02-23 20:32:14 +00:00
}
if err := f.FullNode.WalletSetDefault(ctx, keys[i].Address); err != nil {
t.Fatal(err)
2020-02-23 20:32:14 +00:00
}
2019-09-23 15:27:30 +00:00
2020-02-23 07:49:15 +00:00
genMiner := maddrs[i]
wa := genms[i].Worker
2019-09-23 15:27:30 +00:00
2020-01-14 02:04:33 +00:00
storers[i] = testStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options())
if err := storers[i].StorageAddLocal(ctx, presealDirs[i]); err != nil {
2020-03-18 01:08:11 +00:00
t.Fatalf("%+v", err)
2019-11-30 23:17:50 +00:00
}
/*
sma := storers[i].StorageMiner.(*impl.StorageMinerAPI)
2019-11-30 23:17:50 +00:00
psd := presealDirs[i]
*/
2019-07-09 16:27:07 +00:00
}
2019-07-09 17:03:36 +00:00
if err := mn.LinkAll(); err != nil {
t.Fatal(err)
}
2019-09-23 15:27:30 +00:00
return fulls, storers
2019-07-09 16:27:07 +00:00
}
2020-03-06 07:30:20 +00:00
const nPreseal = 2
2020-01-13 20:47:27 +00:00
func mockSbBuilder(t *testing.T, nFull int, storage []int) ([]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
2020-02-23 07:49:15 +00:00
var genms []genesis.Miner
2020-02-23 15:50:36 +00:00
var genaccs []genesis.Actor
2020-02-23 07:49:15 +00:00
var maddrs []address.Address
2020-01-13 20:47:27 +00:00
var presealDirs []string
2020-02-23 15:50:36 +00:00
var keys []*wallet.Key
2020-01-13 20:47:27 +00:00
for i := 0; i < len(storage); i++ {
2020-02-23 15:50:36 +00:00
maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i))
2020-01-13 20:47:27 +00:00
if err != nil {
t.Fatal(err)
}
tdir, err := ioutil.TempDir("", "preseal-memgen")
if err != nil {
t.Fatal(err)
}
genm, k, err := mockstorage.PreSeal(2048, maddr, nPreseal)
2020-01-13 20:47:27 +00:00
if err != nil {
t.Fatal(err)
}
2020-02-23 15:50:36 +00:00
genm.PeerId = minerPid
wk, err := wallet.NewKey(*k)
if err != nil {
return nil, nil
}
2020-01-13 20:47:27 +00:00
2020-02-23 15:50:36 +00:00
genaccs = append(genaccs, genesis.Actor{
Type: genesis.TAccount,
Balance: big.NewInt(40000000000),
Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(),
})
keys = append(keys, wk)
2020-01-13 20:47:27 +00:00
presealDirs = append(presealDirs, tdir)
2020-02-23 07:49:15 +00:00
maddrs = append(maddrs, maddr)
genms = append(genms, *genm)
}
templ := &genesis.Template{
2020-04-14 03:05:19 +00:00
Accounts: genaccs,
Miners: genms,
2020-04-17 23:13:02 +00:00
Timestamp: uint64(time.Now().Unix() - 10000),
2020-01-13 20:47:27 +00:00
}
// END PRESEAL SECTION
for i := 0; i < nFull; i++ {
var genesis node.Option
if i == 0 {
2020-02-23 07:49:15 +00:00
genesis = node.Override(new(modules.Genesis), modtest.MakeGenesisMem(&genbuf, *templ))
2020-01-13 20:47:27 +00:00
} 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(),
2020-03-26 02:50:56 +00:00
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
2020-01-13 20:47:27 +00:00
genesis,
)
if err != nil {
2020-02-23 15:50:36 +00:00
t.Fatalf("%+v", err)
2020-01-13 20:47:27 +00:00
}
}
for i, full := range storage {
// TODO: support non-bootstrap miners
if i != 0 {
t.Fatal("only one storage node supported")
}
if full != 0 {
t.Fatal("storage nodes only supported on the first full node")
}
f := fulls[full]
2020-02-23 15:50:36 +00:00
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
}
2020-01-13 20:47:27 +00:00
2020-02-23 07:49:15 +00:00
genMiner := maddrs[i]
wa := genms[i].Worker
2020-01-13 20:47:27 +00:00
2020-01-14 02:04:33 +00:00
storers[i] = testStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options(
2020-03-23 11:40:02 +00:00
node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) {
return mock.NewMockSectorMgr(5, build.SectorSizes[0]), nil
}),
2020-04-17 23:01:11 +00:00
node.Override(new(ffiwrapper.Verifier), mock.MockVerifier),
2020-03-23 11:40:02 +00:00
node.Unset(new(*sectorstorage.Manager)),
2020-01-14 02:04:33 +00:00
))
2020-01-13 20:47:27 +00:00
}
if err := mn.LinkAll(); err != nil {
t.Fatal(err)
}
return fulls, storers
}
2019-07-09 16:27:07 +00:00
func TestAPI(t *testing.T) {
test.TestApis(t, builder)
}
2019-07-09 16:36:40 +00:00
2019-09-23 15:27:30 +00:00
func rpcBuilder(t *testing.T, nFull int, storage []int) ([]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
2019-07-09 16:36:40 +00:00
2019-09-23 15:27:30 +00:00
var err error
2019-10-04 16:02:25 +00:00
fulls[i].FullNode, _, err = client.NewFullNodeRPC("ws://"+testServ.Listener.Addr().String(), nil)
2019-09-23 15:27:30 +00:00
if err != nil {
t.Fatal(err)
}
}
2019-07-09 16:36:40 +00:00
2019-09-23 15:27:30 +00:00
for i, a := range storaApis {
2019-07-09 16:36:40 +00:00
rpcServer := jsonrpc.NewServer()
rpcServer.Register("Filecoin", a)
testServ := httptest.NewServer(rpcServer) // todo: close
2019-07-15 16:28:00 +00:00
var err error
2019-10-04 16:02:25 +00:00
storers[i].StorageMiner, _, err = client.NewStorageMinerRPC("ws://"+testServ.Listener.Addr().String(), nil)
2019-07-15 16:28:00 +00:00
if err != nil {
t.Fatal(err)
}
2019-11-30 23:17:50 +00:00
storers[i].MineOne = a.MineOne
2019-07-09 16:36:40 +00:00
}
2019-09-23 15:27:30 +00:00
return fulls, storers
2019-07-09 16:36:40 +00:00
}
func TestAPIRPC(t *testing.T) {
test.TestApis(t, rpcBuilder)
}
func TestAPIDealFlow(t *testing.T) {
2020-01-21 16:05:10 +00:00
logging.SetLogLevel("miner", "ERROR")
2020-03-06 07:30:20 +00:00
logging.SetLogLevel("chainstore", "ERROR")
2020-01-21 16:05:10 +00:00
logging.SetLogLevel("chain", "ERROR")
logging.SetLogLevel("sub", "ERROR")
logging.SetLogLevel("storageminer", "ERROR")
test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, false)
t.Run("WithExportedCAR", func(t *testing.T) {
test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, true)
})
2020-01-14 02:04:33 +00:00
}
func TestAPIDealFlowReal(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
lotuslog.SetupLogLevels()
2020-03-06 07:30:20 +00:00
logging.SetLogLevel("miner", "ERROR")
logging.SetLogLevel("chainstore", "ERROR")
logging.SetLogLevel("chain", "ERROR")
logging.SetLogLevel("sub", "ERROR")
logging.SetLogLevel("storageminer", "ERROR")
test.TestDealFlow(t, builder, time.Second, false)
}