2020-06-24 10:52:23 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2020-06-29 12:57:55 +00:00
|
|
|
"net/http"
|
2020-06-26 14:30:44 +00:00
|
|
|
"os"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2020-06-24 10:52:23 +00:00
|
|
|
"time"
|
2020-06-29 17:25:52 +00:00
|
|
|
|
2020-06-29 17:11:53 +00:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
2020-06-24 10:52:23 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
|
|
"github.com/filecoin-project/lotus/build"
|
2020-06-25 14:55:44 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/beacon"
|
2020-06-24 10:52:23 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/wallet"
|
2020-06-30 16:02:02 +00:00
|
|
|
"github.com/filecoin-project/lotus/metrics"
|
2020-06-24 10:52:23 +00:00
|
|
|
"github.com/filecoin-project/lotus/node"
|
|
|
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
|
|
|
modtest "github.com/filecoin-project/lotus/node/modules/testing"
|
|
|
|
"github.com/filecoin-project/lotus/node/repo"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
|
|
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
2020-06-25 10:33:52 +00:00
|
|
|
"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"
|
2020-06-30 16:02:02 +00:00
|
|
|
influxdb "github.com/kpacha/opencensus-influxdb"
|
|
|
|
|
2020-06-25 10:33:52 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
2020-06-29 12:57:55 +00:00
|
|
|
manet "github.com/multiformats/go-multiaddr-net"
|
2020-06-25 10:33:52 +00:00
|
|
|
"github.com/testground/sdk-go/run"
|
|
|
|
"github.com/testground/sdk-go/runtime"
|
2020-06-30 16:02:02 +00:00
|
|
|
"go.opencensus.io/stats"
|
|
|
|
"go.opencensus.io/stats/view"
|
2020-06-24 10:52:23 +00:00
|
|
|
)
|
|
|
|
|
2020-06-25 10:33:52 +00:00
|
|
|
func init() {
|
2020-06-26 13:24:01 +00:00
|
|
|
logging.SetLogLevel("*", "ERROR")
|
2020-06-25 10:33:52 +00:00
|
|
|
|
|
|
|
os.Setenv("BELLMAN_NO_GPU", "1")
|
|
|
|
|
|
|
|
build.InsecurePoStValidation = true
|
|
|
|
build.DisableBuiltinAssets = true
|
|
|
|
|
|
|
|
power.ConsensusMinerMinPower = big.NewInt(2048)
|
|
|
|
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
|
|
|
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
|
|
|
}
|
|
|
|
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
var PrepareNodeTimeout = time.Minute
|
2020-06-24 10:52:23 +00:00
|
|
|
|
|
|
|
type TestEnvironment struct {
|
|
|
|
*runtime.RunEnv
|
|
|
|
*run.InitContext
|
|
|
|
}
|
|
|
|
|
2020-06-25 14:55:44 +00:00
|
|
|
// workaround for default params being wrapped in quote chars
|
|
|
|
func (t *TestEnvironment) StringParam(name string) string {
|
|
|
|
return strings.Trim(t.RunEnv.StringParam(name), "\"")
|
|
|
|
}
|
|
|
|
|
2020-06-24 17:39:06 +00:00
|
|
|
func (t *TestEnvironment) DurationParam(name string) time.Duration {
|
2020-06-25 14:55:44 +00:00
|
|
|
d, err := time.ParseDuration(t.StringParam(name))
|
2020-06-24 17:39:06 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("invalid duration value for param '%s': %w", name, err))
|
|
|
|
}
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
2020-06-29 23:18:12 +00:00
|
|
|
func (t *TestEnvironment) DebugSpew(format string, args ...interface{}) {
|
2020-06-29 17:11:53 +00:00
|
|
|
t.RecordMessage(spew.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
2020-06-24 10:52:23 +00:00
|
|
|
type Node struct {
|
|
|
|
fullApi api.FullNode
|
|
|
|
minerApi api.StorageMiner
|
|
|
|
stop node.StopFunc
|
2020-06-24 13:29:27 +00:00
|
|
|
MineOne func(context.Context, func(bool)) error
|
2020-06-24 10:52:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) setWallet(ctx context.Context, walletKey *wallet.Key) error {
|
|
|
|
_, err := n.fullApi.WalletImport(ctx, &walletKey.KeyInfo)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = n.fullApi.WalletSetDefault(ctx, walletKey.Address)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-24 11:10:35 +00:00
|
|
|
func waitForBalances(t *TestEnvironment, ctx context.Context, nodes int) ([]*InitialBalanceMsg, error) {
|
|
|
|
ch := make(chan *InitialBalanceMsg)
|
|
|
|
sub := t.SyncClient.MustSubscribe(ctx, balanceTopic, ch)
|
|
|
|
|
|
|
|
balances := make([]*InitialBalanceMsg, 0, nodes)
|
|
|
|
for i := 0; i < nodes; i++ {
|
|
|
|
select {
|
|
|
|
case m := <-ch:
|
|
|
|
balances = append(balances, m)
|
|
|
|
case err := <-sub.Done():
|
|
|
|
return nil, fmt.Errorf("got error while waiting for balances: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return balances, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func collectPreseals(t *TestEnvironment, ctx context.Context, miners int) ([]*PresealMsg, error) {
|
|
|
|
ch := make(chan *PresealMsg)
|
|
|
|
sub := t.SyncClient.MustSubscribe(ctx, presealTopic, ch)
|
|
|
|
|
|
|
|
preseals := make([]*PresealMsg, 0, miners)
|
|
|
|
for i := 0; i < miners; i++ {
|
|
|
|
select {
|
|
|
|
case m := <-ch:
|
|
|
|
preseals = append(preseals, m)
|
|
|
|
case err := <-sub.Done():
|
|
|
|
return nil, fmt.Errorf("got error while waiting for preseals: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-26 14:30:44 +00:00
|
|
|
sort.Slice(preseals, func(i, j int) bool {
|
|
|
|
return preseals[i].Seqno < preseals[j].Seqno
|
|
|
|
})
|
|
|
|
|
2020-06-24 11:10:35 +00:00
|
|
|
return preseals, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func waitForGenesis(t *TestEnvironment, ctx context.Context) (*GenesisMsg, error) {
|
|
|
|
genesisCh := make(chan *GenesisMsg)
|
|
|
|
sub := t.SyncClient.MustSubscribe(ctx, genesisTopic, genesisCh)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case genesisMsg := <-genesisCh:
|
|
|
|
return genesisMsg, nil
|
|
|
|
case err := <-sub.Done():
|
|
|
|
return nil, fmt.Errorf("error while waiting for genesis msg: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2020-06-25 11:10:00 +00:00
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
func collectMinerAddrs(t *TestEnvironment, ctx context.Context, miners int) ([]MinerAddressesMsg, error) {
|
|
|
|
ch := make(chan MinerAddressesMsg)
|
2020-06-25 11:10:00 +00:00
|
|
|
sub := t.SyncClient.MustSubscribe(ctx, minersAddrsTopic, ch)
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
addrs := make([]MinerAddressesMsg, 0, miners)
|
2020-06-25 11:10:00 +00:00
|
|
|
for i := 0; i < miners; i++ {
|
|
|
|
select {
|
|
|
|
case a := <-ch:
|
|
|
|
addrs = append(addrs, a)
|
|
|
|
case err := <-sub.Done():
|
|
|
|
return nil, fmt.Errorf("got error while waiting for miners addrs: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return addrs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func collectClientAddrs(t *TestEnvironment, ctx context.Context, clients int) ([]peer.AddrInfo, error) {
|
|
|
|
ch := make(chan peer.AddrInfo)
|
|
|
|
sub := t.SyncClient.MustSubscribe(ctx, clientsAddrsTopic, ch)
|
|
|
|
|
|
|
|
addrs := make([]peer.AddrInfo, 0, clients)
|
|
|
|
for i := 0; i < clients; i++ {
|
|
|
|
select {
|
|
|
|
case a := <-ch:
|
|
|
|
addrs = append(addrs, a)
|
|
|
|
case err := <-sub.Done():
|
|
|
|
return nil, fmt.Errorf("got error while waiting for clients addrs: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return addrs, nil
|
|
|
|
}
|
2020-06-24 14:41:57 +00:00
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
func getPubsubTracerMaddr(ctx context.Context, t *TestEnvironment) (string, error) {
|
2020-06-26 08:58:56 +00:00
|
|
|
if !t.BooleanParam("enable_pubsub_tracer") {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ch := make(chan *PubsubTracerMsg)
|
|
|
|
sub := t.SyncClient.MustSubscribe(ctx, pubsubTracerTopic, ch)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case m := <-ch:
|
2020-06-30 22:02:01 +00:00
|
|
|
return m.Multiaddr, nil
|
2020-06-26 08:58:56 +00:00
|
|
|
case err := <-sub.Done():
|
2020-06-26 11:06:45 +00:00
|
|
|
return "", fmt.Errorf("got error while waiting for pubsub tracer config: %w", err)
|
2020-06-26 08:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
func getDrandOpts(ctx context.Context, t *TestEnvironment) (node.Option, error) {
|
2020-06-25 14:55:44 +00:00
|
|
|
beaconType := t.StringParam("random_beacon_type")
|
|
|
|
switch beaconType {
|
|
|
|
case "external-drand":
|
2020-06-24 14:41:57 +00:00
|
|
|
noop := func(settings *node.Settings) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return noop, nil
|
2020-06-25 14:55:44 +00:00
|
|
|
|
|
|
|
case "local-drand":
|
|
|
|
cfg, err := waitForDrandConfig(ctx, t.SyncClient)
|
|
|
|
if err != nil {
|
|
|
|
t.RecordMessage("error getting drand config: %w", err)
|
|
|
|
return nil, err
|
2020-06-26 08:58:56 +00:00
|
|
|
|
2020-06-25 14:55:44 +00:00
|
|
|
}
|
2020-06-29 17:11:53 +00:00
|
|
|
t.DebugSpew("setting drand config: %v", cfg)
|
2020-06-25 14:55:44 +00:00
|
|
|
return node.Options(
|
|
|
|
node.Override(new(dtypes.DrandConfig), cfg.Config),
|
|
|
|
node.Override(new(dtypes.DrandBootstrap), cfg.GossipBootstrap),
|
|
|
|
), nil
|
|
|
|
|
|
|
|
case "mock":
|
2020-06-25 15:56:12 +00:00
|
|
|
return node.Options(
|
|
|
|
node.Override(new(beacon.RandomBeacon), modtest.RandomBeacon),
|
|
|
|
node.Override(new(dtypes.DrandConfig), dtypes.DrandConfig{
|
|
|
|
ChainInfoJSON: "{\"Hash\":\"wtf\"}",
|
|
|
|
}),
|
|
|
|
node.Override(new(dtypes.DrandBootstrap), dtypes.DrandBootstrap{}),
|
|
|
|
), nil
|
2020-06-25 14:55:44 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unknown random_beacon_type: %s", beaconType)
|
2020-06-24 14:41:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-30 11:50:46 +00:00
|
|
|
|
2020-06-30 15:53:27 +00:00
|
|
|
func startServer(repo *repo.MemRepo, srv *http.Server) error {
|
|
|
|
endpoint, err := repo.APIEndpoint()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
lst, err := manet.Listen(endpoint)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not listen: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
_ = srv.Serve(manet.NetListener(lst))
|
|
|
|
}()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-06-30 16:02:02 +00:00
|
|
|
|
|
|
|
func registerAndExportMetrics(instanceName string) {
|
|
|
|
// Register all Lotus metric views
|
|
|
|
err := view.Register(metrics.DefaultViews...)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the metric to one so it is published to the exporter
|
|
|
|
stats.Record(context.Background(), metrics.LotusInfo.M(1))
|
|
|
|
|
|
|
|
// Register our custom exporter to opencensus
|
|
|
|
e, err := influxdb.NewExporter(context.Background(), influxdb.Options{
|
|
|
|
Database: "testground",
|
|
|
|
Address: os.Getenv("INFLUXDB_URL"),
|
|
|
|
Username: "",
|
|
|
|
Password: "",
|
|
|
|
InstanceName: instanceName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
view.RegisterExporter(e)
|
|
|
|
view.SetReportingPeriod(5 * time.Second)
|
|
|
|
}
|