2020-07-01 16:29:09 +00:00
|
|
|
package testkit
|
2020-06-30 22:02:01 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/rand"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2020-07-09 13:57:18 +00:00
|
|
|
"time"
|
2020-06-30 22:02:01 +00:00
|
|
|
|
2020-07-07 12:58:09 +00:00
|
|
|
"contrib.go.opencensus.io/exporter/prometheus"
|
2020-06-30 22:02:01 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
|
|
|
"github.com/filecoin-project/go-jsonrpc"
|
|
|
|
"github.com/filecoin-project/go-jsonrpc/auth"
|
|
|
|
"github.com/filecoin-project/go-storedcounter"
|
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
|
|
"github.com/filecoin-project/lotus/api/apistruct"
|
|
|
|
"github.com/filecoin-project/lotus/build"
|
|
|
|
"github.com/filecoin-project/lotus/chain/actors"
|
|
|
|
genesis_chain "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"
|
|
|
|
"github.com/filecoin-project/lotus/miner"
|
|
|
|
"github.com/filecoin-project/lotus/node"
|
|
|
|
"github.com/filecoin-project/lotus/node/impl"
|
|
|
|
"github.com/filecoin-project/lotus/node/modules"
|
|
|
|
"github.com/filecoin-project/lotus/node/repo"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
|
|
"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/crypto"
|
2020-07-01 16:29:09 +00:00
|
|
|
"github.com/gorilla/mux"
|
2020-06-30 22:02:01 +00:00
|
|
|
"github.com/ipfs/go-datastore"
|
2020-07-01 16:29:09 +00:00
|
|
|
libp2pcrypto "github.com/libp2p/go-libp2p-core/crypto"
|
2020-06-30 22:02:01 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
|
|
"github.com/testground/sdk-go/sync"
|
|
|
|
)
|
|
|
|
|
2020-07-09 13:57:18 +00:00
|
|
|
const (
|
|
|
|
sealDelay = 30 * time.Second
|
|
|
|
)
|
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
type LotusMiner struct {
|
|
|
|
*LotusNode
|
2020-06-30 22:02:01 +00:00
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
t *TestEnvironment
|
2020-06-30 22:02:01 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
func PrepareMiner(t *TestEnvironment) (*LotusMiner, error) {
|
2020-06-30 22:02:01 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), PrepareNodeTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
pubsubTracer, err := GetPubsubTracerMaddr(ctx, t)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
drandOpt, err := GetRandomBeaconOpts(ctx, t)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// first create a wallet
|
|
|
|
walletKey, err := wallet.GenerateKey(crypto.SigTypeBLS)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// publish the account ID/balance
|
2020-07-07 21:02:29 +00:00
|
|
|
balance := t.FloatParam("balance")
|
2020-06-30 22:02:01 +00:00
|
|
|
balanceMsg := &InitialBalanceMsg{Addr: walletKey.Address, Balance: balance}
|
2020-07-01 16:29:09 +00:00
|
|
|
t.SyncClient.Publish(ctx, BalanceTopic, balanceMsg)
|
2020-06-30 22:02:01 +00:00
|
|
|
|
|
|
|
// create and publish the preseal commitment
|
2020-07-01 16:29:09 +00:00
|
|
|
priv, _, err := libp2pcrypto.GenerateEd25519Key(rand.Reader)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
minerID, err := peer.IDFromPrivateKey(priv)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// pick unique sequence number for each miner, no matter in which group they are
|
2020-07-01 16:29:09 +00:00
|
|
|
seq := t.SyncClient.MustSignalAndWait(ctx, StateMinerPickSeqNum, t.IntParam("miners"))
|
2020-06-30 22:02:01 +00:00
|
|
|
|
|
|
|
minerAddr, err := address.NewIDAddress(genesis_chain.MinerStart + uint64(seq-1))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
presealDir, err := ioutil.TempDir("", "preseal")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
sectors := t.IntParam("sectors")
|
2020-07-03 18:57:57 +00:00
|
|
|
genMiner, _, err := seed.PreSeal(minerAddr, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, sectors, presealDir, []byte("TODO: randomize this"), &walletKey.KeyInfo, false)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
genMiner.PeerId = minerID
|
|
|
|
|
|
|
|
t.RecordMessage("Miner Info: Owner: %s Worker: %s", genMiner.Owner, genMiner.Worker)
|
|
|
|
|
|
|
|
presealMsg := &PresealMsg{Miner: *genMiner, Seqno: seq}
|
2020-07-01 16:29:09 +00:00
|
|
|
t.SyncClient.Publish(ctx, PresealTopic, presealMsg)
|
2020-06-30 22:02:01 +00:00
|
|
|
|
|
|
|
// then collect the genesis block and bootstrapper address
|
2020-07-01 16:29:09 +00:00
|
|
|
genesisMsg, err := WaitForGenesis(t, ctx)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// prepare the repo
|
|
|
|
minerRepo := repo.NewMemory(nil)
|
|
|
|
|
|
|
|
lr, err := minerRepo.Lock(repo.StorageMiner)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ks, err := lr.KeyStore()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
kbytes, err := priv.Bytes()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ks.Put("libp2p-host", types.KeyInfo{
|
|
|
|
Type: "libp2p-host",
|
|
|
|
PrivateKey: kbytes,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ds, err := lr.Datastore("/metadata")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ds.Put(datastore.NewKey("miner-address"), minerAddr.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nic := storedcounter.New(ds, datastore.NewKey(modules.StorageCounterDSPrefix))
|
|
|
|
for i := 0; i < (sectors + 1); i++ {
|
|
|
|
_, err = nic.Next()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = lr.Close()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
minerIP := t.NetClient.MustGetDataNetworkIP().String()
|
|
|
|
|
|
|
|
// create the node
|
|
|
|
// we need both a full node _and_ and storage miner node
|
2020-07-01 16:29:09 +00:00
|
|
|
n := &LotusNode{}
|
2020-06-30 22:02:01 +00:00
|
|
|
|
|
|
|
nodeRepo := repo.NewMemory(nil)
|
|
|
|
|
|
|
|
stop1, err := node.New(context.Background(),
|
2020-07-01 16:29:09 +00:00
|
|
|
node.FullAPI(&n.FullApi),
|
2020-06-30 22:02:01 +00:00
|
|
|
node.Online(),
|
|
|
|
node.Repo(nodeRepo),
|
|
|
|
withGenesis(genesisMsg.Genesis),
|
2020-07-06 14:47:17 +00:00
|
|
|
withApiEndpoint(fmt.Sprintf("/ip4/0.0.0.0/tcp/%s", t.PortNumber("node_rpc", "0"))),
|
2020-06-30 22:02:01 +00:00
|
|
|
withListenAddress(minerIP),
|
|
|
|
withBootstrapper(genesisMsg.Bootstrapper),
|
|
|
|
withPubsubConfig(false, pubsubTracer),
|
|
|
|
drandOpt,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the wallet
|
|
|
|
err = n.setWallet(ctx, walletKey)
|
|
|
|
if err != nil {
|
|
|
|
stop1(context.TODO())
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
minerOpts := []node.Option{
|
2020-07-01 16:29:09 +00:00
|
|
|
node.StorageMiner(&n.MinerApi),
|
2020-06-30 22:02:01 +00:00
|
|
|
node.Online(),
|
|
|
|
node.Repo(minerRepo),
|
2020-07-01 16:29:09 +00:00
|
|
|
node.Override(new(api.FullNode), n.FullApi),
|
2020-07-06 14:47:17 +00:00
|
|
|
withApiEndpoint(fmt.Sprintf("/ip4/0.0.0.0/tcp/%s", t.PortNumber("miner_rpc", "0"))),
|
2020-06-30 22:02:01 +00:00
|
|
|
withMinerListenAddress(minerIP),
|
|
|
|
}
|
|
|
|
|
|
|
|
if t.StringParam("mining_mode") != "natural" {
|
2020-07-06 11:45:26 +00:00
|
|
|
mineBlock := make(chan func(bool, error))
|
2020-06-30 22:02:01 +00:00
|
|
|
minerOpts = append(minerOpts,
|
|
|
|
node.Override(new(*miner.Miner), miner.NewTestMiner(mineBlock, minerAddr)))
|
2020-07-07 12:58:09 +00:00
|
|
|
|
2020-07-06 11:45:26 +00:00
|
|
|
n.MineOne = func(ctx context.Context, cb func(bool, error)) error {
|
2020-06-30 22:02:01 +00:00
|
|
|
select {
|
|
|
|
case mineBlock <- cb:
|
|
|
|
return nil
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stop2, err := node.New(context.Background(), minerOpts...)
|
|
|
|
if err != nil {
|
|
|
|
stop1(context.TODO())
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-01 16:29:09 +00:00
|
|
|
n.StopFn = func(ctx context.Context) error {
|
2020-06-30 22:02:01 +00:00
|
|
|
// TODO use a multierror for this
|
|
|
|
err2 := stop2(ctx)
|
|
|
|
err1 := stop1(ctx)
|
|
|
|
if err2 != nil {
|
|
|
|
return err2
|
|
|
|
}
|
|
|
|
return err1
|
|
|
|
}
|
|
|
|
|
|
|
|
registerAndExportMetrics(minerAddr.String())
|
|
|
|
|
2020-07-03 13:38:19 +00:00
|
|
|
// collect stats based on Travis' scripts
|
2020-07-03 18:06:10 +00:00
|
|
|
if t.InitContext.GroupSeq == 1 {
|
2020-07-06 16:24:11 +00:00
|
|
|
go collectStats(t, ctx, n.FullApi)
|
2020-07-03 18:06:10 +00:00
|
|
|
}
|
2020-07-03 13:38:19 +00:00
|
|
|
|
2020-07-07 12:58:09 +00:00
|
|
|
// Start listening on the full node.
|
|
|
|
fullNodeNetAddrs, err := n.FullApi.NetAddrsListen(ctx)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2020-07-07 12:58:09 +00:00
|
|
|
// err = n.MinerApi.NetConnect(ctx, fullNodeNetAddrs)
|
|
|
|
// if err != nil {
|
|
|
|
// panic(err)
|
|
|
|
// }
|
2020-06-30 22:02:01 +00:00
|
|
|
|
2020-07-09 13:57:18 +00:00
|
|
|
// set seal delay to lower value than 1 hour
|
|
|
|
err = n.MinerApi.SectorSetSealDelay(ctx, sealDelay)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-17 12:28:52 +00:00
|
|
|
// set expected seal duration to 1 minute
|
|
|
|
err = n.MinerApi.SectorSetExpectedSealDuration(ctx, 1*time.Minute)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-09 13:57:18 +00:00
|
|
|
// print out the admin auth token
|
|
|
|
token, err := n.MinerApi.AuthNew(ctx, apistruct.AllPermissions)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
t.RecordMessage("Auth token: %s", string(token))
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
// add local storage for presealed sectors
|
2020-07-01 16:29:09 +00:00
|
|
|
err = n.MinerApi.StorageAddLocal(ctx, presealDir)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
2020-07-01 16:29:09 +00:00
|
|
|
n.StopFn(context.TODO())
|
2020-06-30 22:02:01 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the miner PeerID
|
|
|
|
minerIDEncoded, err := actors.SerializeParams(&saminer.ChangePeerIDParams{NewID: abi.PeerID(minerID)})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
changeMinerID := &types.Message{
|
|
|
|
To: minerAddr,
|
|
|
|
From: genMiner.Worker,
|
|
|
|
Method: builtin.MethodsMiner.ChangePeerID,
|
|
|
|
Params: minerIDEncoded,
|
|
|
|
Value: types.NewInt(0),
|
|
|
|
GasPrice: types.NewInt(0),
|
|
|
|
GasLimit: 1000000,
|
|
|
|
}
|
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
_, err = n.FullApi.MpoolPushMessage(ctx, changeMinerID)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
2020-07-01 16:29:09 +00:00
|
|
|
n.StopFn(context.TODO())
|
2020-06-30 22:02:01 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
t.RecordMessage("publish our address to the miners addr topic")
|
2020-07-07 12:58:09 +00:00
|
|
|
minerActor, err := n.MinerApi.ActorAddress(ctx)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-07 12:58:09 +00:00
|
|
|
|
|
|
|
minerNetAddrs, err := n.MinerApi.NetAddrsListen(ctx)
|
2020-06-30 22:02:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-07 12:58:09 +00:00
|
|
|
|
|
|
|
t.SyncClient.MustPublish(ctx, MinersAddrsTopic, MinerAddressesMsg{
|
|
|
|
FullNetAddrs: fullNodeNetAddrs,
|
|
|
|
MinerNetAddrs: minerNetAddrs,
|
|
|
|
MinerActorAddr: minerActor,
|
|
|
|
})
|
2020-06-30 22:02:01 +00:00
|
|
|
|
2020-07-02 21:49:59 +00:00
|
|
|
t.RecordMessage("connecting to all other miners")
|
|
|
|
|
2020-07-07 12:58:09 +00:00
|
|
|
// densely connect the miner's full nodes.
|
2020-07-02 21:49:59 +00:00
|
|
|
minerCh := make(chan *MinerAddressesMsg, 16)
|
|
|
|
sctx, cancel := context.WithCancel(ctx)
|
|
|
|
defer cancel()
|
|
|
|
t.SyncClient.MustSubscribe(sctx, MinersAddrsTopic, minerCh)
|
|
|
|
for i := 0; i < t.IntParam("miners"); i++ {
|
2020-07-07 12:58:09 +00:00
|
|
|
m := <-minerCh
|
|
|
|
if m.MinerActorAddr == minerActor {
|
|
|
|
// once I find myself, I stop connecting to others, to avoid a simopen problem.
|
|
|
|
break
|
2020-07-02 21:49:59 +00:00
|
|
|
}
|
2020-07-07 12:58:09 +00:00
|
|
|
err := n.FullApi.NetConnect(ctx, m.FullNetAddrs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to connect to miner %s on: %v", m.MinerActorAddr, m.FullNetAddrs)
|
|
|
|
}
|
|
|
|
t.RecordMessage("connected to full node of miner %s on %v", m.MinerActorAddr, m.FullNetAddrs)
|
|
|
|
|
2020-07-02 21:49:59 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
t.RecordMessage("waiting for all nodes to be ready")
|
2020-07-01 16:29:09 +00:00
|
|
|
t.SyncClient.MustSignalAndWait(ctx, StateReady, t.TestInstanceCount)
|
|
|
|
|
|
|
|
m := &LotusMiner{n, t}
|
|
|
|
|
2020-07-06 14:47:17 +00:00
|
|
|
err = startFullNodeAPIServer(t, nodeRepo, n.FullApi)
|
2020-07-01 16:54:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-06 14:47:17 +00:00
|
|
|
err = startStorageMinerAPIServer(t, minerRepo, n.MinerApi)
|
2020-07-01 16:29:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return m, err
|
|
|
|
}
|
2020-06-30 22:02:01 +00:00
|
|
|
|
2020-07-01 16:29:09 +00:00
|
|
|
func (m *LotusMiner) RunDefault() error {
|
|
|
|
var (
|
|
|
|
t = m.t
|
|
|
|
clients = t.IntParam("clients")
|
|
|
|
miners = t.IntParam("miners")
|
|
|
|
)
|
|
|
|
|
|
|
|
t.RecordMessage("running miner")
|
2020-07-01 18:36:46 +00:00
|
|
|
t.RecordMessage("block delay: %v", build.BlockDelaySecs)
|
|
|
|
t.D().Gauge("miner.block-delay").Update(float64(build.BlockDelaySecs))
|
2020-07-01 16:29:09 +00:00
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
myActorAddr, err := m.MinerApi.ActorAddress(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// mine / stop mining
|
|
|
|
mine := true
|
|
|
|
done := make(chan struct{})
|
|
|
|
|
|
|
|
if m.MineOne != nil {
|
|
|
|
go func() {
|
|
|
|
defer t.RecordMessage("shutting down mining")
|
|
|
|
defer close(done)
|
|
|
|
|
|
|
|
var i int
|
|
|
|
for i = 0; mine; i++ {
|
|
|
|
// synchronize all miners to mine the next block
|
|
|
|
t.RecordMessage("synchronizing all miners to mine next block [%d]", i)
|
|
|
|
stateMineNext := sync.State(fmt.Sprintf("mine-block-%d", i))
|
|
|
|
t.SyncClient.MustSignalAndWait(ctx, stateMineNext, miners)
|
|
|
|
|
2020-07-03 21:40:43 +00:00
|
|
|
ch := make(chan error)
|
2020-07-06 20:10:53 +00:00
|
|
|
const maxRetries = 100
|
|
|
|
success := false
|
|
|
|
for retries := 0; retries < maxRetries; retries++ {
|
2020-07-03 21:40:43 +00:00
|
|
|
err := m.MineOne(ctx, func(mined bool, err error) {
|
|
|
|
if mined {
|
|
|
|
t.D().Counter(fmt.Sprintf("block.mine,miner=%s", myActorAddr)).Inc(1)
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
})
|
2020-07-06 11:45:26 +00:00
|
|
|
if err != nil {
|
2020-07-03 21:40:43 +00:00
|
|
|
panic(err)
|
2020-07-06 11:45:26 +00:00
|
|
|
}
|
2020-07-03 21:40:43 +00:00
|
|
|
|
|
|
|
miningErr := <-ch
|
|
|
|
if miningErr == nil {
|
2020-07-06 20:10:53 +00:00
|
|
|
success = true
|
2020-07-03 21:40:43 +00:00
|
|
|
break
|
2020-07-01 16:29:09 +00:00
|
|
|
}
|
2020-07-03 21:40:43 +00:00
|
|
|
t.D().Counter("block.mine.err").Inc(1)
|
2020-07-06 20:10:53 +00:00
|
|
|
t.RecordMessage("retrying block [%d] after %d attempts due to mining error: %s",
|
|
|
|
i, retries, miningErr)
|
|
|
|
}
|
|
|
|
if !success {
|
|
|
|
panic(fmt.Errorf("failed to mine block %d after %d retries", i, maxRetries))
|
2020-07-01 16:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// signal the last block to make sure no miners are left stuck waiting for the next block signal
|
|
|
|
// while the others have stopped
|
|
|
|
stateMineLast := sync.State(fmt.Sprintf("mine-block-%d", i))
|
|
|
|
t.SyncClient.MustSignalEntry(ctx, stateMineLast)
|
|
|
|
}()
|
|
|
|
} else {
|
|
|
|
close(done)
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait for a signal from all clients to stop mining
|
|
|
|
err = <-t.SyncClient.MustBarrier(ctx, StateStopMining, clients).C
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
mine = false
|
|
|
|
<-done
|
|
|
|
|
|
|
|
t.SyncClient.MustSignalAndWait(ctx, StateDone, t.TestInstanceCount)
|
|
|
|
return nil
|
2020-06-30 22:02:01 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 14:47:17 +00:00
|
|
|
func startStorageMinerAPIServer(t *TestEnvironment, repo *repo.MemRepo, minerApi api.StorageMiner) error {
|
2020-06-30 22:02:01 +00:00
|
|
|
mux := mux.NewRouter()
|
|
|
|
|
|
|
|
rpcServer := jsonrpc.NewServer()
|
2020-07-09 13:57:18 +00:00
|
|
|
rpcServer.Register("Filecoin", minerApi)
|
2020-06-30 22:02:01 +00:00
|
|
|
|
|
|
|
mux.Handle("/rpc/v0", rpcServer)
|
|
|
|
mux.PathPrefix("/remote").HandlerFunc(minerApi.(*impl.StorageMinerAPI).ServeRemote)
|
|
|
|
mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof
|
|
|
|
|
2020-07-07 12:58:09 +00:00
|
|
|
exporter, err := prometheus.NewExporter(prometheus.Options{
|
|
|
|
Namespace: "lotus",
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
mux.Handle("/debug/metrics", exporter)
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
ah := &auth.Handler{
|
2020-07-09 13:57:18 +00:00
|
|
|
Verify: func(ctx context.Context, token string) ([]auth.Permission, error) {
|
|
|
|
return apistruct.AllPermissions, nil
|
|
|
|
},
|
|
|
|
Next: mux.ServeHTTP,
|
2020-06-30 22:02:01 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 14:47:17 +00:00
|
|
|
endpoint, err := repo.APIEndpoint()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("no API endpoint in repo: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:02:01 +00:00
|
|
|
srv := &http.Server{Handler: ah}
|
|
|
|
|
2020-07-06 14:47:17 +00:00
|
|
|
listenAddr, err := startServer(endpoint, srv)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to start storage miner API endpoint: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.RecordMessage("started storage miner API server at %s", listenAddr)
|
|
|
|
return nil
|
2020-06-30 22:02:01 +00:00
|
|
|
}
|