From e432378fbb5bf740ceceabf908933c20c3bd19a0 Mon Sep 17 00:00:00 2001 From: tbjump Date: Wed, 24 May 2023 19:59:05 +0000 Subject: [PATCH] node: move adminrpc from guardiand into own package --- node/cmd/guardiand/adminverify.go | 63 +---- node/cmd/guardiand/node.go | 43 ++- .../guardiand => pkg/adminrpc}/adminserver.go | 255 +++++++----------- .../adminrpc}/adminserver_test.go | 2 +- node/pkg/node/adminServiceRunnable.go | 104 +++++++ 5 files changed, 248 insertions(+), 219 deletions(-) rename node/{cmd/guardiand => pkg/adminrpc}/adminserver.go (80%) rename node/{cmd/guardiand => pkg/adminrpc}/adminserver_test.go (99%) create mode 100644 node/pkg/node/adminServiceRunnable.go diff --git a/node/cmd/guardiand/adminverify.go b/node/cmd/guardiand/adminverify.go index 595090f4c..ca1188d82 100644 --- a/node/cmd/guardiand/adminverify.go +++ b/node/cmd/guardiand/adminverify.go @@ -1,20 +1,14 @@ package guardiand import ( - "encoding/hex" - "fmt" "log" "os" - "time" - "github.com/wormhole-foundation/wormhole/sdk/vaa" - - "github.com/davecgh/go-spew/spew" "github.com/spf13/cobra" "google.golang.org/protobuf/encoding/prototext" + "github.com/certusone/wormhole/node/pkg/adminrpc" nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1" - "github.com/status-im/keycard-go/hexutils" ) var AdminClientGovernanceVAAVerifyCmd = &cobra.Command{ @@ -26,68 +20,15 @@ var AdminClientGovernanceVAAVerifyCmd = &cobra.Command{ func runGovernanceVAAVerify(cmd *cobra.Command, args []string) { path := args[0] - b, err := os.ReadFile(path) if err != nil { log.Fatalf("failed to read file: %v", err) } - var req nodev1.InjectGovernanceVAARequest err = prototext.Unmarshal(b, &req) if err != nil { log.Fatalf("failed to deserialize: %v", err) } - timestamp := time.Unix(int64(req.Timestamp), 0) - - for _, message := range req.Messages { - var ( - v *vaa.VAA - ) - switch payload := message.Payload.(type) { - case *nodev1.GovernanceMessage_GuardianSet: - v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_ContractUpgrade: - v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_BridgeRegisterChain: - v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_BridgeContractUpgrade: - v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_AccountantModifyBalance: - v, err = accountantModifyBalance(payload.AccountantModifyBalance, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_WormchainStoreCode: - v, err = wormchainStoreCode(payload.WormchainStoreCode, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_WormchainInstantiateContract: - v, err = wormchainInstantiateContract(payload.WormchainInstantiateContract, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_WormchainMigrateContract: - v, err = wormchainMigrateContract(payload.WormchainMigrateContract, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_CircleIntegrationUpdateWormholeFinality: - v, err = circleIntegrationUpdateWormholeFinality(payload.CircleIntegrationUpdateWormholeFinality, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_CircleIntegrationRegisterEmitterAndDomain: - v, err = circleIntegrationRegisterEmitterAndDomain(payload.CircleIntegrationRegisterEmitterAndDomain, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_CircleIntegrationUpgradeContractImplementation: - v, err = circleIntegrationUpgradeContractImplementation(payload.CircleIntegrationUpgradeContractImplementation, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_IbcReceiverUpdateChannelChain: - v, err = ibcReceiverUpdateChannelChain(payload.IbcReceiverUpdateChannelChain, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - default: - panic(fmt.Sprintf("unsupported VAA type: %T", payload)) - } - if err != nil { - log.Fatalf("invalid update: %v", err) - } - - digest := v.SigningDigest().Bytes() - if err != nil { - panic(err) - } - - b, err := v.Marshal() - if err != nil { - panic(err) - } - - log.Printf("Serialized: %v", hex.EncodeToString(b)) - - log.Printf("VAA with digest %s: %+v", hexutils.BytesToHex(digest), spew.Sdump(v)) - } + adminrpc.VerifyReq(&req) } diff --git a/node/cmd/guardiand/node.go b/node/cmd/guardiand/node.go index d9af8319d..9dee98c17 100644 --- a/node/cmd/guardiand/node.go +++ b/node/cmd/guardiand/node.go @@ -42,6 +42,7 @@ import ( "github.com/certusone/wormhole/node/pkg/common" "github.com/certusone/wormhole/node/pkg/devnet" "github.com/certusone/wormhole/node/pkg/governor" + "github.com/certusone/wormhole/node/pkg/node" "github.com/certusone/wormhole/node/pkg/p2p" "github.com/certusone/wormhole/node/pkg/processor" gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1" @@ -1556,7 +1557,47 @@ func runNode(cmd *cobra.Command, args []string) { return err } - adminService, err := adminServiceRunnable(logger, *adminSocketPath, injectWriteC, signedInWriteC, obsvReqSendWriteC, db, gst, gov, gk, ethRPC, ethContract, *testnetMode) + rpcMap := make(map[string]string) + rpcMap["acalaRPC"] = *acalaRPC + rpcMap["algorandIndexerRPC"] = *algorandIndexerRPC + rpcMap["algorandAlgodRPC"] = *algorandAlgodRPC + rpcMap["aptosRPC"] = *aptosRPC + rpcMap["arbitrumRPC"] = *arbitrumRPC + rpcMap["auroraRPC"] = *auroraRPC + rpcMap["avalancheRPC"] = *avalancheRPC + rpcMap["baseRPC"] = *baseRPC + rpcMap["bscRPC"] = *bscRPC + rpcMap["celoRPC"] = *celoRPC + rpcMap["ethRPC"] = *ethRPC + rpcMap["fantomRPC"] = *fantomRPC + rpcMap["ibcLCD"] = *ibcLCD + rpcMap["ibcWS"] = *ibcWS + rpcMap["karuraRPC"] = *karuraRPC + rpcMap["klaytnRPC"] = *klaytnRPC + rpcMap["moonbeamRPC"] = *moonbeamRPC + rpcMap["nearRPC"] = *nearRPC + rpcMap["neonRPC"] = *neonRPC + rpcMap["oasisRPC"] = *oasisRPC + rpcMap["optimismRPC"] = *optimismRPC + rpcMap["polygonRPC"] = *polygonRPC + rpcMap["pythnetRPC"] = *pythnetRPC + rpcMap["pythnetWS"] = *pythnetWS + rpcMap["sei"] = "IBC" + if env == common.TestNet { + rpcMap["sepoliaRPC"] = *sepoliaRPC + } + rpcMap["solanaRPC"] = *solanaRPC + rpcMap["suiRPC"] = *suiRPC + rpcMap["terraWS"] = *terraWS + rpcMap["terraLCD"] = *terraLCD + rpcMap["terra2WS"] = *terra2WS + rpcMap["terra2LCD"] = *terra2LCD + rpcMap["wormchainWS"] = *wormchainWS + rpcMap["wormchainLCD"] = *wormchainLCD + rpcMap["xplaWS"] = *xplaWS + rpcMap["xplaLCD"] = *xplaLCD + + adminService, err := node.AdminServiceRunnable(logger, *adminSocketPath, injectWriteC, signedInWriteC, obsvReqSendWriteC, db, gst, gov, gk, ethRPC, ethContract, rpcMap) if err != nil { logger.Fatal("failed to create admin service socket", zap.Error(err)) } diff --git a/node/cmd/guardiand/adminserver.go b/node/pkg/adminrpc/adminserver.go similarity index 80% rename from node/cmd/guardiand/adminserver.go rename to node/pkg/adminrpc/adminserver.go index b79de2754..4cd1a2f41 100644 --- a/node/cmd/guardiand/adminserver.go +++ b/node/pkg/adminrpc/adminserver.go @@ -1,4 +1,4 @@ -package guardiand +package adminrpc import ( "bytes" @@ -9,25 +9,22 @@ import ( "encoding/json" "errors" "fmt" + "log" "math" "math/big" "math/rand" - "net" "net/http" - "os" "sync" "time" "github.com/certusone/wormhole/node/pkg/watchers/evm/connectors" - ethcrypto "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" + "github.com/status-im/keycard-go/hexutils" "golang.org/x/exp/slices" "github.com/certusone/wormhole/node/pkg/db" "github.com/certusone/wormhole/node/pkg/governor" gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1" - publicrpcv1 "github.com/certusone/wormhole/node/pkg/proto/publicrpc/v1" - "github.com/certusone/wormhole/node/pkg/publicrpc" ethcommon "github.com/ethereum/go-ethereum/common" "go.uber.org/zap" "google.golang.org/grpc/codes" @@ -35,7 +32,7 @@ import ( "github.com/certusone/wormhole/node/pkg/common" nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1" - "github.com/certusone/wormhole/node/pkg/supervisor" + "github.com/davecgh/go-spew/spew" "github.com/wormhole-foundation/wormhole/sdk/vaa" ) @@ -51,7 +48,34 @@ type nodePrivilegedService struct { gsCache sync.Map gk *ecdsa.PrivateKey guardianAddress ethcommon.Address - testnetMode bool + rpcMap map[string]string +} + +func NewPrivService( + db *db.Database, + injectC chan<- *vaa.VAA, + obsvReqSendC chan<- *gossipv1.ObservationRequest, + logger *zap.Logger, + signedInC chan<- *gossipv1.SignedVAAWithQuorum, + governor *governor.ChainGovernor, + evmConnector connectors.Connector, + gk *ecdsa.PrivateKey, + guardianAddress ethcommon.Address, + rpcMap map[string]string, + +) *nodePrivilegedService { + return &nodePrivilegedService{ + db: db, + injectC: injectC, + obsvReqSendC: obsvReqSendC, + logger: logger, + signedInC: signedInC, + governor: governor, + evmConnector: evmConnector, + gk: gk, + guardianAddress: guardianAddress, + rpcMap: rpcMap, + } } // adminGuardianSetUpdateToVAA converts a nodev1.GuardianSetUpdate message to its canonical VAA representation. @@ -392,6 +416,44 @@ func ibcReceiverUpdateChannelChain( return v, nil } +func govMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, timestamp time.Time) (*vaa.VAA, error) { + var ( + v *vaa.VAA + err error + ) + + switch payload := message.Payload.(type) { + case *nodev1.GovernanceMessage_GuardianSet: + v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_ContractUpgrade: + v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_BridgeRegisterChain: + v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_BridgeContractUpgrade: + v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_AccountantModifyBalance: + v, err = accountantModifyBalance(payload.AccountantModifyBalance, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_WormchainStoreCode: + v, err = wormchainStoreCode(payload.WormchainStoreCode, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_WormchainInstantiateContract: + v, err = wormchainInstantiateContract(payload.WormchainInstantiateContract, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_WormchainMigrateContract: + v, err = wormchainMigrateContract(payload.WormchainMigrateContract, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_CircleIntegrationUpdateWormholeFinality: + v, err = circleIntegrationUpdateWormholeFinality(payload.CircleIntegrationUpdateWormholeFinality, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_CircleIntegrationRegisterEmitterAndDomain: + v, err = circleIntegrationRegisterEmitterAndDomain(payload.CircleIntegrationRegisterEmitterAndDomain, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_CircleIntegrationUpgradeContractImplementation: + v, err = circleIntegrationUpgradeContractImplementation(payload.CircleIntegrationUpgradeContractImplementation, timestamp, currentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_IbcReceiverUpdateChannelChain: + v, err = ibcReceiverUpdateChannelChain(payload.IbcReceiverUpdateChannelChain, timestamp, currentSetIndex, message.Nonce, message.Sequence) + default: + panic(fmt.Sprintf("unsupported VAA type: %T", payload)) + } + + return v, err +} + func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *nodev1.InjectGovernanceVAARequest) (*nodev1.InjectGovernanceVAAResponse, error) { s.logger.Info("governance VAA injected via admin socket", zap.String("request", req.String())) @@ -405,34 +467,8 @@ func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *no digests := make([][]byte, len(req.Messages)) for i, message := range req.Messages { - switch payload := message.Payload.(type) { - case *nodev1.GovernanceMessage_GuardianSet: - v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_ContractUpgrade: - v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_BridgeRegisterChain: - v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_BridgeContractUpgrade: - v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_AccountantModifyBalance: - v, err = accountantModifyBalance(payload.AccountantModifyBalance, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_WormchainStoreCode: - v, err = wormchainStoreCode(payload.WormchainStoreCode, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_WormchainInstantiateContract: - v, err = wormchainInstantiateContract(payload.WormchainInstantiateContract, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_WormchainMigrateContract: - v, err = wormchainMigrateContract(payload.WormchainMigrateContract, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_CircleIntegrationUpdateWormholeFinality: - v, err = circleIntegrationUpdateWormholeFinality(payload.CircleIntegrationUpdateWormholeFinality, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_CircleIntegrationRegisterEmitterAndDomain: - v, err = circleIntegrationRegisterEmitterAndDomain(payload.CircleIntegrationRegisterEmitterAndDomain, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_CircleIntegrationUpgradeContractImplementation: - v, err = circleIntegrationUpgradeContractImplementation(payload.CircleIntegrationUpgradeContractImplementation, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - case *nodev1.GovernanceMessage_IbcReceiverUpdateChannelChain: - v, err = ibcReceiverUpdateChannelChain(payload.IbcReceiverUpdateChannelChain, timestamp, req.CurrentSetIndex, message.Nonce, message.Sequence) - default: - panic(fmt.Sprintf("unsupported VAA type: %T", payload)) - } + v, err = govMsgToVaa(message, req.CurrentSetIndex, timestamp) + if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } @@ -591,84 +627,6 @@ func (s *nodePrivilegedService) FindMissingMessages(ctx context.Context, req *no }, nil } -func adminServiceRunnable( - logger *zap.Logger, - socketPath string, - injectC chan<- *vaa.VAA, - signedInC chan<- *gossipv1.SignedVAAWithQuorum, - obsvReqSendC chan<- *gossipv1.ObservationRequest, - db *db.Database, - gst *common.GuardianSetState, - gov *governor.ChainGovernor, - gk *ecdsa.PrivateKey, - ethRpc *string, - ethContract *string, - testnetMode bool, -) (supervisor.Runnable, error) { - // Delete existing UNIX socket, if present. - fi, err := os.Stat(socketPath) - if err == nil { - fmode := fi.Mode() - if fmode&os.ModeType == os.ModeSocket { - err = os.Remove(socketPath) - if err != nil { - return nil, fmt.Errorf("failed to remove existing socket at %s: %w", socketPath, err) - } - } else { - return nil, fmt.Errorf("%s is not a UNIX socket", socketPath) - } - } - - // Create a new UNIX socket and listen to it. - - // The socket is created with the default umask. We set a restrictive umask in setRestrictiveUmask - // to ensure that any files we create are only readable by the user - this is much harder to mess up. - // The umask avoids a race condition between file creation and chmod. - - laddr, err := net.ResolveUnixAddr("unix", socketPath) - if err != nil { - return nil, fmt.Errorf("invalid listen address: %v", err) - } - l, err := net.ListenUnix("unix", laddr) - if err != nil { - return nil, fmt.Errorf("failed to listen on %s: %w", socketPath, err) - } - - logger.Info("admin server listening on", zap.String("path", socketPath)) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - var evmConnector connectors.Connector - if ethRPC != nil && ethContract != nil { - contract := ethcommon.HexToAddress(*ethContract) - evmConnector, err = connectors.NewEthereumConnector(ctx, "eth", *ethRpc, contract, logger) - if err != nil { - return nil, fmt.Errorf("failed to connecto to ethereum") - } - } - - nodeService := &nodePrivilegedService{ - db: db, - injectC: injectC, - obsvReqSendC: obsvReqSendC, - logger: logger.Named("adminservice"), - signedInC: signedInC, - governor: gov, - gk: gk, - guardianAddress: ethcrypto.PubkeyToAddress(gk.PublicKey), - evmConnector: evmConnector, - testnetMode: testnetMode, - } - - publicrpcService := publicrpc.NewPublicrpcServer(logger, db, gst, gov) - - grpcServer := common.NewInstrumentedGRPCServer(logger, common.GrpcLogDetailMinimal) - nodev1.RegisterNodePrivilegedServiceServer(grpcServer, nodeService) - publicrpcv1.RegisterPublicRPCServiceServer(grpcServer, publicrpcService) - return supervisor.GRPCServer(grpcServer, l, false), nil -} - func (s *nodePrivilegedService) SendObservationRequest(ctx context.Context, req *nodev1.SendObservationRequestRequest) (*nodev1.SendObservationRequestResponse, error) { if err := common.PostObservationRequest(s.obsvReqSendC, req.ObservationRequest); err != nil { return nil, err @@ -891,48 +849,33 @@ func (s *nodePrivilegedService) SignExistingVAA(ctx context.Context, req *nodev1 } func (s *nodePrivilegedService) DumpRPCs(ctx context.Context, req *nodev1.DumpRPCsRequest) (*nodev1.DumpRPCsResponse, error) { - rpcMap := make(map[string]string) - - rpcMap["acalaRPC"] = *acalaRPC - rpcMap["algorandIndexerRPC"] = *algorandIndexerRPC - rpcMap["algorandAlgodRPC"] = *algorandAlgodRPC - rpcMap["aptosRPC"] = *aptosRPC - rpcMap["arbitrumRPC"] = *arbitrumRPC - rpcMap["auroraRPC"] = *auroraRPC - rpcMap["avalancheRPC"] = *avalancheRPC - rpcMap["baseRPC"] = *baseRPC - rpcMap["bscRPC"] = *bscRPC - rpcMap["celoRPC"] = *celoRPC - rpcMap["ethRPC"] = *ethRPC - rpcMap["fantomRPC"] = *fantomRPC - rpcMap["ibcLCD"] = *ibcLCD - rpcMap["ibcWS"] = *ibcWS - rpcMap["karuraRPC"] = *karuraRPC - rpcMap["klaytnRPC"] = *klaytnRPC - rpcMap["moonbeamRPC"] = *moonbeamRPC - rpcMap["nearRPC"] = *nearRPC - rpcMap["neonRPC"] = *neonRPC - rpcMap["oasisRPC"] = *oasisRPC - rpcMap["optimismRPC"] = *optimismRPC - rpcMap["polygonRPC"] = *polygonRPC - rpcMap["pythnetRPC"] = *pythnetRPC - rpcMap["pythnetWS"] = *pythnetWS - rpcMap["sei"] = "IBC" - if s.testnetMode { - rpcMap["sepoliaRPC"] = *sepoliaRPC - } - rpcMap["solanaRPC"] = *solanaRPC - rpcMap["suiRPC"] = *suiRPC - rpcMap["terraWS"] = *terraWS - rpcMap["terraLCD"] = *terraLCD - rpcMap["terra2WS"] = *terra2WS - rpcMap["terra2LCD"] = *terra2LCD - rpcMap["wormchainWS"] = *wormchainWS - rpcMap["wormchainLCD"] = *wormchainLCD - rpcMap["xplaWS"] = *xplaWS - rpcMap["xplaLCD"] = *xplaLCD - return &nodev1.DumpRPCsResponse{ - Response: rpcMap, + Response: s.rpcMap, }, nil } + +func VerifyReq(req *nodev1.InjectGovernanceVAARequest) { + timestamp := time.Unix(int64(req.Timestamp), 0) + + for _, message := range req.Messages { + v, err := govMsgToVaa(message, req.CurrentSetIndex, timestamp) + + if err != nil { + log.Fatalf("invalid update: %v", err) + } + + digest := v.SigningDigest().Bytes() + if err != nil { + panic(err) + } + + b, err := v.Marshal() + if err != nil { + panic(err) + } + + log.Printf("Serialized: %v", hex.EncodeToString(b)) + + log.Printf("VAA with digest %s: %+v", hexutils.BytesToHex(digest), spew.Sdump(v)) + } +} diff --git a/node/cmd/guardiand/adminserver_test.go b/node/pkg/adminrpc/adminserver_test.go similarity index 99% rename from node/cmd/guardiand/adminserver_test.go rename to node/pkg/adminrpc/adminserver_test.go index 73dfd6c75..fa6dcd597 100644 --- a/node/cmd/guardiand/adminserver_test.go +++ b/node/pkg/adminrpc/adminserver_test.go @@ -1,5 +1,5 @@ //nolint:unparam -package guardiand +package adminrpc import ( "context" diff --git a/node/pkg/node/adminServiceRunnable.go b/node/pkg/node/adminServiceRunnable.go new file mode 100644 index 000000000..d7ab00f25 --- /dev/null +++ b/node/pkg/node/adminServiceRunnable.go @@ -0,0 +1,104 @@ +package node + +import ( + "context" + "crypto/ecdsa" + "fmt" + "net" + "os" + "time" + + "github.com/certusone/wormhole/node/pkg/adminrpc" + "github.com/certusone/wormhole/node/pkg/common" + "github.com/certusone/wormhole/node/pkg/db" + "github.com/certusone/wormhole/node/pkg/governor" + gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1" + nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1" + publicrpcv1 "github.com/certusone/wormhole/node/pkg/proto/publicrpc/v1" + "github.com/certusone/wormhole/node/pkg/publicrpc" + "github.com/certusone/wormhole/node/pkg/supervisor" + "github.com/certusone/wormhole/node/pkg/watchers/evm/connectors" + "github.com/wormhole-foundation/wormhole/sdk/vaa" + "go.uber.org/zap" + + ethcommon "github.com/ethereum/go-ethereum/common" + ethcrypto "github.com/ethereum/go-ethereum/crypto" +) + +func AdminServiceRunnable( + logger *zap.Logger, + socketPath string, + injectC chan<- *vaa.VAA, + signedInC chan<- *gossipv1.SignedVAAWithQuorum, + obsvReqSendC chan<- *gossipv1.ObservationRequest, + db *db.Database, + gst *common.GuardianSetState, + gov *governor.ChainGovernor, + gk *ecdsa.PrivateKey, + ethRpc *string, + ethContract *string, + rpcMap map[string]string, +) (supervisor.Runnable, error) { + // Delete existing UNIX socket, if present. + fi, err := os.Stat(socketPath) + if err == nil { + fmode := fi.Mode() + if fmode&os.ModeType == os.ModeSocket { + err = os.Remove(socketPath) + if err != nil { + return nil, fmt.Errorf("failed to remove existing socket at %s: %w", socketPath, err) + } + } else { + return nil, fmt.Errorf("%s is not a UNIX socket", socketPath) + } + } + + // Create a new UNIX socket and listen to it. + + // The socket is created with the default umask. We set a restrictive umask in setRestrictiveUmask + // to ensure that any files we create are only readable by the user - this is much harder to mess up. + // The umask avoids a race condition between file creation and chmod. + + laddr, err := net.ResolveUnixAddr("unix", socketPath) + if err != nil { + return nil, fmt.Errorf("invalid listen address: %v", err) + } + l, err := net.ListenUnix("unix", laddr) + if err != nil { + return nil, fmt.Errorf("failed to listen on %s: %w", socketPath, err) + } + + logger.Info("admin server listening on", zap.String("path", socketPath)) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + + var evmConnector connectors.Connector + if ethRpc != nil && ethContract != nil { + contract := ethcommon.HexToAddress(*ethContract) + evmConnector, err = connectors.NewEthereumConnector(ctx, "eth", *ethRpc, contract, logger) + if err != nil { + return nil, fmt.Errorf("failed to connecto to ethereum") + } + } + + nodeService := adminrpc.NewPrivService( + db, + injectC, + obsvReqSendC, + logger.Named("adminservice"), + signedInC, + gov, + evmConnector, + gk, + ethcrypto.PubkeyToAddress(gk.PublicKey), + rpcMap, + ) + + publicrpcService := publicrpc.NewPublicrpcServer(logger, db, gst, gov) + + grpcServer := common.NewInstrumentedGRPCServer(logger, common.GrpcLogDetailMinimal) + nodev1.RegisterNodePrivilegedServiceServer(grpcServer, nodeService) + publicrpcv1.RegisterPublicRPCServiceServer(grpcServer, publicrpcService) + return supervisor.GRPCServer(grpcServer, l, false), nil +}