Devnet 3; Builtin bootstrap; NAT Port Map

This commit is contained in:
Łukasz Magiera 2019-10-09 05:16:35 +02:00
parent ed78894d20
commit 752654ab03
14 changed files with 290 additions and 85 deletions

30
build/bootstrap.go Normal file
View File

@ -0,0 +1,30 @@
package build
import (
"context"
"github.com/filecoin-project/go-lotus/lib/addrutil"
"os"
"strings"
rice "github.com/GeertJohan/go.rice"
"github.com/libp2p/go-libp2p-core/peer"
)
func BuiltinBootstrap() ([]peer.AddrInfo, error) {
var out []peer.AddrInfo
b := rice.MustFindBox("bootstrap")
err := b.Walk("", func(path string, info os.FileInfo, err error) error {
if !strings.HasSuffix(path, ".pi") {
return nil
}
spi := b.MustString(path)
if spi == "" {
return nil
}
pi, err := addrutil.ParseAddresses(context.TODO(), strings.Split(strings.TrimSpace(spi), "\n"))
out = append(out, pi...)
return err
})
return out, err
}

0
build/bootstrap/.gitkeep Normal file
View File

View File

@ -0,0 +1 @@
/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWK3mKvkdtNj7Bm9cJVufpiSnwQdkimuq5A69ZxFLxRvF1

1
build/bootstrap/root.pi Normal file
View File

@ -0,0 +1 @@
/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWChZgMm5bmFF8ESr1QYonR8mPHaLkTzBafZ7iWnpWTtQX

Binary file not shown.

View File

@ -1,15 +1,11 @@
package cli
import (
"context"
"fmt"
"sync"
"time"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-lotus/lib/addrutil"
)
var netCmd = &cli.Command{
@ -80,7 +76,7 @@ var netConnect = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
pis, err := parseAddresses(ctx, cctx.Args().Slice())
pis, err := addrutil.ParseAddresses(ctx, cctx.Args().Slice())
if err != nil {
return err
}
@ -120,80 +116,3 @@ var netId = &cli.Command{
return nil
},
}
// parseAddresses is a function that takes in a slice of string peer addresses
// (multiaddr + peerid) and returns a slice of properly constructed peers
func parseAddresses(ctx context.Context, addrs []string) ([]peer.AddrInfo, error) {
// resolve addresses
maddrs, err := resolveAddresses(ctx, addrs)
if err != nil {
return nil, err
}
return peer.AddrInfosFromP2pAddrs(maddrs...)
}
const (
dnsResolveTimeout = 10 * time.Second
)
// resolveAddresses resolves addresses parallelly
func resolveAddresses(ctx context.Context, addrs []string) ([]ma.Multiaddr, error) {
ctx, cancel := context.WithTimeout(ctx, dnsResolveTimeout)
defer cancel()
var maddrs []ma.Multiaddr
var wg sync.WaitGroup
resolveErrC := make(chan error, len(addrs))
maddrC := make(chan ma.Multiaddr)
for _, addr := range addrs {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
// check whether address ends in `ipfs/Qm...`
if _, last := ma.SplitLast(maddr); last.Protocol().Code == ma.P_IPFS {
maddrs = append(maddrs, maddr)
continue
}
wg.Add(1)
go func(maddr ma.Multiaddr) {
defer wg.Done()
raddrs, err := madns.Resolve(ctx, maddr)
if err != nil {
resolveErrC <- err
return
}
// filter out addresses that still doesn't end in `ipfs/Qm...`
found := 0
for _, raddr := range raddrs {
if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_IPFS {
maddrC <- raddr
found++
}
}
if found == 0 {
resolveErrC <- fmt.Errorf("found no ipfs peers at %s", maddr)
}
}(maddr)
}
go func() {
wg.Wait()
close(maddrC)
}()
for maddr := range maddrC {
maddrs = append(maddrs, maddr)
}
select {
case err := <-resolveErrC:
return nil, err
default:
}
return maddrs, nil
}

View File

@ -40,6 +40,10 @@ var DaemonCmd = &cli.Command{
Name: "genesis",
Usage: "genesis file to use for first node run",
},
&cli.BoolFlag{
Name: "bootstrap",
Value: true,
},
},
Action: func(cctx *cli.Context) error {
ctx := context.Background()
@ -95,7 +99,32 @@ var DaemonCmd = &cli.Command{
return err
}
go func() {
if !cctx.Bool("bootstrap") {
return
}
err := bootstrap(ctx, api)
if err != nil {
log.Error("Bootstrap failed: ", err)
}
}()
// TODO: properly parse api endpoint (or make it a URL)
return serveRPC(api, stop, "127.0.0.1:"+cctx.String("api"))
},
}
func bootstrap(ctx context.Context, api api.FullNode) error {
pis, err := build.BuiltinBootstrap()
if err != nil {
return err
}
for _, pi := range pis {
if err := api.NetConnect(ctx, pi); err != nil {
return err
}
}
return nil
}

89
lib/addrutil/parse.go Normal file
View File

@ -0,0 +1,89 @@
package addrutil
import (
"context"
"fmt"
"sync"
"time"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
)
// parseAddresses is a function that takes in a slice of string peer addresses
// (multiaddr + peerid) and returns a slice of properly constructed peers
func ParseAddresses(ctx context.Context, addrs []string) ([]peer.AddrInfo, error) {
// resolve addresses
maddrs, err := resolveAddresses(ctx, addrs)
if err != nil {
return nil, err
}
return peer.AddrInfosFromP2pAddrs(maddrs...)
}
const (
dnsResolveTimeout = 10 * time.Second
)
// resolveAddresses resolves addresses parallelly
func resolveAddresses(ctx context.Context, addrs []string) ([]ma.Multiaddr, error) {
ctx, cancel := context.WithTimeout(ctx, dnsResolveTimeout)
defer cancel()
var maddrs []ma.Multiaddr
var wg sync.WaitGroup
resolveErrC := make(chan error, len(addrs))
maddrC := make(chan ma.Multiaddr)
for _, addr := range addrs {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
// check whether address ends in `ipfs/Qm...`
if _, last := ma.SplitLast(maddr); last.Protocol().Code == ma.P_IPFS {
maddrs = append(maddrs, maddr)
continue
}
wg.Add(1)
go func(maddr ma.Multiaddr) {
defer wg.Done()
raddrs, err := madns.Resolve(ctx, maddr)
if err != nil {
resolveErrC <- err
return
}
// filter out addresses that still doesn't end in `ipfs/Qm...`
found := 0
for _, raddr := range raddrs {
if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_IPFS {
maddrC <- raddr
found++
}
}
if found == 0 {
resolveErrC <- fmt.Errorf("found no ipfs peers at %s", maddr)
}
}(maddr)
}
go func() {
wg.Wait()
close(maddrC)
}()
for maddr := range maddrC {
maddrs = append(maddrs, maddr)
}
select {
case err := <-resolveErrC:
return nil, err
default:
}
return maddrs, nil
}

View File

@ -171,7 +171,7 @@ func libp2p() Option {
Override(BaseRoutingKey, lp2p.BaseRouting),
Override(new(routing.Routing), lp2p.Routing),
//Override(NatPortMapKey, lp2p.NatPortMap), //TODO: reenable when closing logic is actually there
Override(NatPortMapKey, lp2p.NatPortMap),
Override(ConnectionManagerKey, lp2p.ConnectionManager(50, 200, 20*time.Second)),
Override(new(*pubsub.PubSub), lp2p.GossipSub()),

2
scripts/bootstrap.toml Normal file
View File

@ -0,0 +1,2 @@
[Libp2p]
ListenAddresses = ["/ip4/0.0.0.0/tcp/1347"]

9
scripts/daemon.service Normal file
View File

@ -0,0 +1,9 @@
[Unit]
Description=Lotus Daemon
After=network.target
[Service]
ExecStart=/usr/local/bin/lotus daemon
[Install]
WantedBy=multiuser.target

110
scripts/deploy-devnet.sh Executable file
View File

@ -0,0 +1,110 @@
#!/usr/bin/env bash
############
## Settings
GENESIS_HOST=root@147.75.80.29
BOOTSTRAPPERS=( root@147.75.80.17 )
############
log() {
echo -e "\e[33m$1\e[39m"
}
rm -f build/bootstrap/*.pi
log '> Generating genesis'
make
GENPATH=$(mktemp -d)
log 'staring temp daemon'
./lotus --repo="${GENPATH}" daemon --lotus-make-random-genesis="${GENPATH}/devnet.car" &
GDPID=$!
sleep 3
log 'Extracting genesis miner prvate key'
ADDR=$(./lotus --repo="${GENPATH}" wallet list)
./lotus --repo="${GENPATH}" wallet export "$ADDR" > "${GENPATH}/wallet.key"
kill "$GDPID"
wait
log '> Creating genesis binary'
cp "${GENPATH}/devnet.car" build/genesis/devnet.car
rm -f build/bootstrap/*.pi
make
log '> Deploying and starting genesis miner'
ssh $GENESIS_HOST 'systemctl stop lotus-daemon' &
ssh $GENESIS_HOST 'systemctl stop lotus-storage-miner' &
wait
ssh $GENESIS_HOST 'rm -rf .lotus' &
ssh $GENESIS_HOST 'rm -rf .lotusstorage' &
scp -C lotus "${GENESIS_HOST}":/usr/local/bin/lotus &
scp -C lotus-storage-miner "${GENESIS_HOST}":/usr/local/bin/lotus-storage-miner &
wait
log 'Initializing genesis miner repo'
ssh $GENESIS_HOST 'systemctl start lotus-daemon'
scp scripts/bootstrap.toml "${GENESIS_HOST}:.lotus/config.toml" &
ssh < "${GENPATH}/wallet.key" $GENESIS_HOST '/usr/local/bin/lotus wallet import' &
wait
ssh $GENESIS_HOST 'systemctl restart lotus-daemon'
log 'Starting genesis mining'
ssh $GENESIS_HOST '/usr/local/bin/lotus-storage-miner init --genesis-miner --actor=t0101'
ssh $GENESIS_HOST 'systemctl start lotus-storage-miner'
log 'Getting genesis addr info'
ssh $GENESIS_HOST './lotus net listen' | grep -v '/10' | grep -v '/127' > build/bootstrap/root.pi
log '> Creating bootstrap binaries'
make
for host in "${BOOTSTRAPPERS[@]}"
do
log "> Deploying bootstrap node $host"
log "Stopping lotus daemon"
ssh "$host" 'systemctl stop lotus-daemon' &
ssh "$host" 'systemctl stop lotus-storage-miner' &
wait
ssh "$host" 'rm -rf .lotus' &
ssh "$host" 'rm -rf .lotusstorage' &
scp -C lotus "${host}":/usr/local/bin/lotus &
scp -C lotus-storage-miner "${host}":/usr/local/bin/lotus-storage-miner &
wait
log 'Initializing repo'
ssh "$host" 'systemctl start lotus-daemon'
scp scripts/bootstrap.toml "${host}:.lotus/config.toml"
ssh "$host" 'systemctl restart lotus-daemon'
log 'Extracting addr info'
ssh "$host" './lotus net listen' | grep -v '/10' | grep -v '/127' >> build/bootstrap/bootstrappers.pi
done

6
scripts/setup-host.sh Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
HOST=$1
scp scripts/daemon.service "${HOST}:/etc/systemd/system/lotus-daemon.service"
scp scripts/sminer.service "${HOST}:/etc/systemd/system/lotus-storage-miner.service"

9
scripts/sminer.service Normal file
View File

@ -0,0 +1,9 @@
[Unit]
Description=Lotus Storage Miner
After=network.target
[Service]
ExecStart=/usr/local/bin/lotus-storage-miner run
[Install]
WantedBy=multiuser.target