2019-09-17 12:36:17 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2019-10-22 17:18:06 +00:00
|
|
|
"path/filepath"
|
2019-09-17 12:36:17 +00:00
|
|
|
"sync/atomic"
|
|
|
|
"time"
|
2019-10-22 17:18:06 +00:00
|
|
|
|
|
|
|
"golang.org/x/xerrors"
|
2019-11-27 14:18:51 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/lotus/build"
|
|
|
|
"github.com/filecoin-project/lotus/chain/address"
|
|
|
|
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
2019-09-17 12:36:17 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (api *api) Spawn() (nodeInfo, error) {
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "lotus-")
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:18:51 +00:00
|
|
|
params := []string{"daemon", "--bootstrap=false"}
|
2019-09-17 12:36:17 +00:00
|
|
|
genParam := "--genesis=" + api.genesis
|
2019-11-27 14:18:51 +00:00
|
|
|
|
2019-09-17 12:36:17 +00:00
|
|
|
id := atomic.AddInt32(&api.cmds, 1)
|
|
|
|
if id == 1 {
|
2019-11-27 14:18:51 +00:00
|
|
|
// preseal
|
|
|
|
|
|
|
|
genMiner, err := address.NewIDAddress(101)
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
2019-11-29 03:38:18 +00:00
|
|
|
sbroot := filepath.Join(dir, "preseal")
|
|
|
|
genm, err := seed.PreSeal(genMiner, build.SectorSizes[0], 1, sbroot, []byte("8"))
|
2019-11-27 14:18:51 +00:00
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, xerrors.Errorf("preseal failed: %w", err)
|
|
|
|
}
|
2019-11-29 03:38:18 +00:00
|
|
|
|
|
|
|
if err := seed.WriteGenesisMiner(genMiner, sbroot, genm); err != nil {
|
|
|
|
return nodeInfo{}, xerrors.Errorf("failed to write genminer info: %w", err)
|
|
|
|
}
|
2019-11-27 14:18:51 +00:00
|
|
|
params = append(params, "--genesis-presealed-sectors="+filepath.Join(dir, "preseal", "pre-seal-t0101.json"))
|
|
|
|
|
2019-09-17 12:36:17 +00:00
|
|
|
// make genesis
|
|
|
|
genf, err := ioutil.TempFile(os.TempDir(), "lotus-genesis-")
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
api.genesis = genf.Name()
|
|
|
|
genParam = "--lotus-make-random-genesis=" + api.genesis
|
|
|
|
|
|
|
|
if err := genf.Close(); err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
mux := newWsMux()
|
2019-11-12 21:42:26 +00:00
|
|
|
confStr := fmt.Sprintf("[API]\nListenAddress = \"/ip4/127.0.0.1/tcp/%d/http\"\n", 2500+id)
|
2019-10-22 17:18:06 +00:00
|
|
|
|
|
|
|
err = ioutil.WriteFile(filepath.Join(dir, "config.toml"), []byte(confStr), 0700)
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:18:51 +00:00
|
|
|
cmd := exec.Command("./lotus", append(params, genParam)...)
|
2019-09-17 12:36:17 +00:00
|
|
|
|
|
|
|
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw)
|
|
|
|
cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw)
|
2019-11-04 16:47:08 +00:00
|
|
|
cmd.Env = append(os.Environ(), "LOTUS_PATH="+dir)
|
2019-09-17 12:36:17 +00:00
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
info := nodeInfo{
|
|
|
|
Repo: dir,
|
|
|
|
ID: id,
|
|
|
|
ApiPort: 2500 + id,
|
|
|
|
State: NodeRunning,
|
|
|
|
}
|
|
|
|
|
|
|
|
api.runningLk.Lock()
|
|
|
|
api.running[id] = &runningNode{
|
|
|
|
cmd: cmd,
|
|
|
|
meta: info,
|
|
|
|
|
|
|
|
mux: mux,
|
|
|
|
stop: func() {
|
|
|
|
cmd.Process.Signal(os.Interrupt)
|
|
|
|
cmd.Process.Wait()
|
|
|
|
|
|
|
|
api.runningLk.Lock()
|
|
|
|
api.running[id].meta.State = NodeStopped
|
|
|
|
api.runningLk.Unlock()
|
|
|
|
|
|
|
|
//logfile.Close()
|
|
|
|
//errlogfile.Close()
|
|
|
|
|
|
|
|
//close(mux.stop)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
api.runningLk.Unlock()
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
|
|
|
|
|
|
|
return info, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "lotus-storage-")
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
initArgs := []string{"init"}
|
|
|
|
if fullNodeRepo == api.running[1].meta.Repo {
|
2019-11-27 14:18:51 +00:00
|
|
|
initArgs = []string{"init", "--actor=t0101", "--genesis-miner", "--pre-sealed-sectors=" + filepath.Join(fullNodeRepo, "preseal")}
|
2019-09-17 12:36:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
id := atomic.AddInt32(&api.cmds, 1)
|
|
|
|
cmd := exec.Command("./lotus-storage-miner", initArgs...)
|
|
|
|
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
|
|
|
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
2019-11-04 16:47:08 +00:00
|
|
|
cmd.Env = append(os.Environ(), "LOTUS_STORAGE_PATH="+dir, "LOTUS_PATH="+fullNodeRepo)
|
2019-09-17 12:36:17 +00:00
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 300)
|
|
|
|
|
|
|
|
mux := newWsMux()
|
|
|
|
|
|
|
|
cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id))
|
|
|
|
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw)
|
|
|
|
cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw)
|
2019-11-04 16:47:08 +00:00
|
|
|
cmd.Env = append(os.Environ(), "LOTUS_STORAGE_PATH="+dir, "LOTUS_PATH="+fullNodeRepo)
|
2019-09-17 12:36:17 +00:00
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
info := nodeInfo{
|
|
|
|
Repo: dir,
|
|
|
|
ID: id,
|
|
|
|
ApiPort: 2500 + id,
|
|
|
|
State: NodeRunning,
|
|
|
|
|
|
|
|
FullNode: fullNodeRepo,
|
|
|
|
Storage: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
api.runningLk.Lock()
|
|
|
|
api.running[id] = &runningNode{
|
|
|
|
cmd: cmd,
|
|
|
|
meta: info,
|
|
|
|
|
|
|
|
mux: mux,
|
|
|
|
stop: func() {
|
|
|
|
cmd.Process.Signal(os.Interrupt)
|
|
|
|
cmd.Process.Wait()
|
|
|
|
|
|
|
|
api.runningLk.Lock()
|
|
|
|
api.running[id].meta.State = NodeStopped
|
|
|
|
api.runningLk.Unlock()
|
|
|
|
|
|
|
|
//logfile.Close()
|
|
|
|
//errlogfile.Close()
|
|
|
|
|
|
|
|
//close(mux.stop)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
api.runningLk.Unlock()
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
|
|
|
|
|
|
|
return info, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *api) RestartNode(id int32) (nodeInfo, error) {
|
|
|
|
api.runningLk.Lock()
|
|
|
|
defer api.runningLk.Unlock()
|
|
|
|
nd, ok := api.running[id]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
return nodeInfo{}, xerrors.New("node not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
if nd.meta.State != NodeStopped {
|
|
|
|
return nodeInfo{}, xerrors.New("node not stopped")
|
|
|
|
}
|
|
|
|
|
|
|
|
var cmd *exec.Cmd
|
|
|
|
if nd.meta.Storage {
|
|
|
|
cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id))
|
|
|
|
} else {
|
|
|
|
cmd = exec.Command("./lotus", "daemon", "--api", fmt.Sprintf("%d", 2500+id))
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.Stderr = nd.cmd.Stderr // recycle old vars
|
|
|
|
cmd.Stdout = nd.cmd.Stdout
|
|
|
|
cmd.Env = nd.cmd.Env
|
|
|
|
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
return nodeInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nd.cmd = cmd
|
|
|
|
|
|
|
|
nd.stop = func() {
|
|
|
|
cmd.Process.Signal(os.Interrupt)
|
|
|
|
cmd.Process.Wait()
|
|
|
|
|
|
|
|
api.runningLk.Lock()
|
|
|
|
api.running[id].meta.State = NodeStopped
|
|
|
|
api.runningLk.Unlock()
|
|
|
|
|
|
|
|
//logfile.Close()
|
|
|
|
//errlogfile.Close()
|
|
|
|
|
|
|
|
//close(mux.stop)
|
|
|
|
}
|
|
|
|
|
|
|
|
nd.meta.State = NodeRunning
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
|
|
|
|
|
|
|
return nd.meta, nil
|
|
|
|
}
|