161 lines
4.1 KiB
Go
161 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ecdsa"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
|
|
eth_common "github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/certusone/wormhole/bridge/pkg/common"
|
|
"github.com/certusone/wormhole/bridge/pkg/ethereum"
|
|
"github.com/certusone/wormhole/bridge/pkg/supervisor"
|
|
|
|
ipfslog "github.com/ipfs/go-log/v2"
|
|
)
|
|
|
|
var (
|
|
p2pNetworkID = flag.String("network", "/wormhole/dev", "P2P network identifier")
|
|
p2pPort = flag.Uint("port", 8999, "P2P UDP listener port")
|
|
p2pBootstrap = flag.String("bootstrap", "", "P2P bootstrap peers (comma-separated)")
|
|
|
|
nodeKeyPath = flag.String("nodeKey", "", "Path to node key (will be generated if it doesn't exist)")
|
|
|
|
ethRPC = flag.String("ethRPC", "", "Ethereum RPC URL")
|
|
ethContract = flag.String("ethContract", "", "Ethereum bridge contract address")
|
|
ethConfirmations = flag.Uint64("ethConfirmations", 15, "Ethereum confirmation count requirement")
|
|
|
|
logLevel = flag.String("loglevel", "info", "Logging level (debug, info, warn, error, dpanic, panic, fatal)")
|
|
|
|
unsafeDevMode = flag.Bool("unsafeDevMode", false, "Launch node in unsafe, deterministic devnet mode")
|
|
|
|
nodeName = flag.String("nodeName", "", "Node name to announce in gossip heartbeats (default: hostname)")
|
|
)
|
|
|
|
var (
|
|
rootCtx context.Context
|
|
rootCtxCancel context.CancelFunc
|
|
)
|
|
|
|
func rootLoggerName() string {
|
|
if *unsafeDevMode {
|
|
// FIXME: add hostname to root logger for cleaner console output in multi-node development.
|
|
// The proper way is to change the output format to include the hostname.
|
|
hostname, err := os.Hostname()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return fmt.Sprintf("%s-%s", "wormhole", hostname)
|
|
} else {
|
|
return "wormhole"
|
|
}
|
|
}
|
|
|
|
func loadGuardianKey(logger *zap.Logger) *ecdsa.PrivateKey {
|
|
var gk *ecdsa.PrivateKey
|
|
|
|
if *unsafeDevMode {
|
|
// Figure out our devnet index
|
|
idx, err := getDevnetIndex()
|
|
if err != nil {
|
|
logger.Fatal("Failed to parse hostname - are we running in devnet?")
|
|
}
|
|
|
|
// Generate guardian key
|
|
gk = deterministicKeyByIndex(crypto.S256(), uint64(idx))
|
|
} else {
|
|
panic("not implemented") // TODO
|
|
}
|
|
|
|
logger.Info("Loaded guardian key", zap.String(
|
|
"address", crypto.PubkeyToAddress(gk.PublicKey).String()))
|
|
|
|
return gk
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
// Set up logging. The go-log zap wrapper that libp2p uses is compatible with our
|
|
// usage of zap in supervisor, which is nice.
|
|
lvl, err := ipfslog.LevelFromString(*logLevel)
|
|
if err != nil {
|
|
fmt.Println("Invalid log level")
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Our root logger. Convert directly to a regular Zap logger.
|
|
logger := ipfslog.Logger(rootLoggerName()).Desugar()
|
|
|
|
// Override the default go-log config, which uses a magic environment variable.
|
|
ipfslog.SetAllLoggers(lvl)
|
|
|
|
// Mute chatty subsystems.
|
|
if err := ipfslog.SetLogLevel("swarm2", "error"); err != nil {
|
|
panic(err)
|
|
} // connection errors
|
|
|
|
// Verify flags
|
|
if *nodeKeyPath == "" {
|
|
logger.Fatal("Please specify -nodeKey")
|
|
}
|
|
if *ethRPC == "" {
|
|
logger.Fatal("Please specify -ethRPC")
|
|
}
|
|
if *nodeName == "" {
|
|
hostname, err := os.Hostname()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
*nodeName = hostname
|
|
}
|
|
|
|
ethContractAddr := eth_common.HexToAddress(*ethContract)
|
|
|
|
// Guardian key
|
|
gk := loadGuardianKey(logger)
|
|
|
|
// Node's main lifecycle context.
|
|
rootCtx, rootCtxCancel = context.WithCancel(context.Background())
|
|
defer rootCtxCancel()
|
|
|
|
// Ethereum lock event channel
|
|
ec := make(chan *common.ChainLock)
|
|
|
|
// Run supervisor.
|
|
supervisor.New(rootCtx, logger, func(ctx context.Context) error {
|
|
if err := supervisor.Run(ctx, "p2p", p2p); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := supervisor.Run(ctx, "eth",
|
|
ethereum.NewEthBridgeWatcher(*ethRPC, ethContractAddr, *ethConfirmations, ec).Run); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := supervisor.Run(ctx, "lockups", ethLockupProcessor(ec, gk)); err != nil {
|
|
return err
|
|
}
|
|
|
|
logger.Info("Started internal services")
|
|
supervisor.Signal(ctx, supervisor.SignalHealthy)
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil
|
|
}
|
|
})
|
|
|
|
select {
|
|
case <-rootCtx.Done():
|
|
logger.Info("root context cancelled, exiting...")
|
|
// TODO: wait for things to shut down gracefully
|
|
}
|
|
}
|
|
|