diff --git a/bridge/Dockerfile b/bridge/Dockerfile index 7593f846..9dbd47ff 100644 --- a/bridge/Dockerfile +++ b/bridge/Dockerfile @@ -5,7 +5,7 @@ WORKDIR /app ADD . . -RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg \ - go build -o /guardiand github.com/certusone/wormhole/bridge/cmd/guardiand +RUN --mount=type=cache,target=/root/.cache --mount=type=cache,target=/go \ + go build -mod=readonly -o /guardiand github.com/certusone/wormhole/bridge/cmd/guardiand ENTRYPOINT /guardiand diff --git a/bridge/cmd/guardiand/guardiankey.go b/bridge/cmd/guardiand/guardiankey.go new file mode 100644 index 00000000..36e54566 --- /dev/null +++ b/bridge/cmd/guardiand/guardiankey.go @@ -0,0 +1,49 @@ +package main + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "encoding/binary" + "fmt" + "os" + "strconv" + "strings" +) + +// getDevnetIndex returns the current host's devnet index (i.e. 0 for guardian-0). +func getDevnetIndex() (int, error) { + hostname, err := os.Hostname() + if err != nil { + panic(err) + } + + h := strings.Split(hostname, "-") + + if h[0] != "guardian" { + return 0, fmt.Errorf("hostname %s does not appear to be a devnet host", hostname) + } + + i, err := strconv.Atoi(h[1]) + if err != nil { + return 0, fmt.Errorf("invalid devnet index %s in hostname %s", h[1], hostname) + } + + return i, nil +} + +// deterministicKeyByIndex generates a deterministic address from a given index. +func deterministicKeyByIndex(c elliptic.Curve, idx uint64) (*ecdsa.PrivateKey) { + buf := make([]byte, 200) + binary.LittleEndian.PutUint64(buf, idx) + + worstRNG := bytes.NewBuffer(buf) + + key, err := ecdsa.GenerateKey(c, bytes.NewReader(worstRNG.Bytes())) + if err != nil { + panic(err) + } + + return key +} + diff --git a/bridge/cmd/guardiand/main.go b/bridge/cmd/guardiand/main.go index c0abe830..d2cc1602 100644 --- a/bridge/cmd/guardiand/main.go +++ b/bridge/cmd/guardiand/main.go @@ -2,12 +2,14 @@ package main import ( "context" + "crypto/ecdsa" "encoding/hex" "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" @@ -29,6 +31,8 @@ var ( 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") ) var ( @@ -54,8 +58,8 @@ func main() { panic(err) } - // Our root logger. - logger := ipfslog.Logger(fmt.Sprintf("%s-%s", "wormhole", hostname)) + // Our root logger. Convert directly to a regular Zap logger. + logger := ipfslog.Logger(fmt.Sprintf("%s-%s", "wormhole", hostname)).Desugar() // Override the default go-log config, which uses a magic environment variable. ipfslog.SetAllLoggers(lvl) @@ -73,6 +77,25 @@ func main() { ethContractAddr := eth_common.HexToAddress(*ethContract) + // Guardian key initialization + 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())) + // Node's main lifecycle context. rootCtx, rootCtxCancel = context.WithCancel(context.Background()) defer rootCtxCancel() @@ -81,7 +104,7 @@ func main() { ec := make(chan *common.ChainLock) // Run supervisor. - supervisor.New(rootCtx, logger.Desugar(), func(ctx context.Context) error { + supervisor.New(rootCtx, logger, func(ctx context.Context) error { if err := supervisor.Run(ctx, "p2p", p2p); err != nil { return err } diff --git a/bridge/cmd/guardiand/nodekey.go b/bridge/cmd/guardiand/nodekey.go index d8d2cbf3..a7e71e83 100644 --- a/bridge/cmd/guardiand/nodekey.go +++ b/bridge/cmd/guardiand/nodekey.go @@ -48,16 +48,14 @@ func getOrCreateNodeKey(logger *zap.Logger, path string) (crypto.PrivKey, error) return priv, nil } -// FIXME: this hardcodes the private key if we're guardian-0. -// Proper fix is to add a debug mode and fetch the remote peer ID, -// or add a special bootstrap pod. -func bootstrapNodePrivateKeyHack() crypto.PrivKey { - hostname, err := os.Hostname() +// deterministicNodeKey returns a non-nil value if we have a deterministic key on file for the current host. +func deterministicNodeKey() crypto.PrivKey { + idx, err := getDevnetIndex() if err != nil { panic(err) } - if hostname == "guardian-0" { + if idx == 0 { // node ID: 12D3KooWQ1sV2kowPY1iJX1hJcVTysZjKv3sfULTGwhdpUGGZ1VF b, err := base64.StdEncoding.DecodeString("CAESQGlv6OJOMXrZZVTCC0cgCv7goXr6QaSVMZIndOIXKNh80vYnG+EutVlZK20Nx9cLkUG5ymKB\n88LXi/vPBwP8zfY=") if err != nil { diff --git a/bridge/cmd/guardiand/p2p.go b/bridge/cmd/guardiand/p2p.go index 2b002ad6..6b67a1f5 100644 --- a/bridge/cmd/guardiand/p2p.go +++ b/bridge/cmd/guardiand/p2p.go @@ -18,6 +18,7 @@ import ( libp2pquic "github.com/libp2p/go-libp2p-quic-transport" swarm "github.com/libp2p/go-libp2p-swarm" libp2ptls "github.com/libp2p/go-libp2p-tls" + "github.com/libp2p/go-libp2p-core/crypto" "github.com/multiformats/go-multiaddr" "go.uber.org/zap" "google.golang.org/protobuf/proto" @@ -29,16 +30,26 @@ import ( func p2p(ctx context.Context) (re error) { logger := supervisor.Logger(ctx) - priv := bootstrapNodePrivateKeyHack() - + var priv crypto.PrivKey var err error - if priv == nil { - priv, err = getOrCreateNodeKey(logger, *nodeKeyPath) - if err != nil { - panic(err) + + if *unsafeDevMode { + priv = deterministicNodeKey() + + var err error + if priv == nil { + priv, err = getOrCreateNodeKey(logger, *nodeKeyPath) + if err != nil { + return fmt.Errorf("failed to load node key: %w", err) + } + } else { + logger.Info("devnet: loaded hardcoded node key") } } else { - logger.Info("HACK: loaded hardcoded guardian-0 node key") + priv, err = getOrCreateNodeKey(logger, *nodeKeyPath) + if err != nil { + return fmt.Errorf("failed to load node key: %w", err) + } } var idht *dht.IpfsDHT diff --git a/bridge/go.sum b/bridge/go.sum index de074421..7174f158 100644 --- a/bridge/go.sum +++ b/bridge/go.sum @@ -300,8 +300,6 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leoluk/go-libp2p-connmgr v0.0.0-20200817112351-3d0c029185f1 h1:ApGN0fTah3pRuSgHeFSeLJZGknMYlI3oKDqwmgXbEY8= -github.com/leoluk/go-libp2p-connmgr v0.0.0-20200817112351-3d0c029185f1/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= @@ -343,6 +341,8 @@ github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCy github.com/libp2p/go-libp2p-circuit v0.2.3/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= github.com/libp2p/go-libp2p-circuit v0.3.1 h1:69ENDoGnNN45BNDnBd+8SXSetDuw0eJFcGmOvvtOgBw= github.com/libp2p/go-libp2p-circuit v0.3.1/go.mod h1:8RMIlivu1+RxhebipJwFDA45DasLx+kkrp4IlJj53F4= +github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= +github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= diff --git a/devnet/bridge.yaml b/devnet/bridge.yaml index 5aada6ba..241ca4d9 100644 --- a/devnet/bridge.yaml +++ b/devnet/bridge.yaml @@ -33,7 +33,7 @@ spec: labels: app: guardian spec: - terminationGracePeriodSeconds: 1 + terminationGracePeriodSeconds: 0 containers: - name: guardiand image: guardiand-image @@ -48,7 +48,8 @@ spec: - -ethContract - 0xCfEB869F69431e42cdB54A4F4f105C19C080A601 - -ethConfirmations - - '1' + - '2' + - -unsafeDevMode ports: - containerPort: 8999 name: p2p