Skip to content

Commit

Permalink
Node: Add support for Movement
Browse files Browse the repository at this point in the history
  • Loading branch information
bruce-riley committed Jan 23, 2025
1 parent 1dfeafd commit 655a43a
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 133 deletions.
1 change: 1 addition & 0 deletions node/cmd/guardiand/adminnodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func runListNodes(cmd *cobra.Command, args []string) {
{"Sei", vaa.ChainIDSei},
{"Scroll", vaa.ChainIDScroll},
{"Mantle", vaa.ChainIDMantle},
{"Movement", vaa.ChainIDMovement},
{"Blast", vaa.ChainIDBlast},
{"XLayer", vaa.ChainIDXLayer},
{"Linea", vaa.ChainIDLinea},
Expand Down
24 changes: 24 additions & 0 deletions node/cmd/guardiand/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ var (
aptosAccount *string
aptosHandle *string

movementRPC *string
movementAccount *string
movementHandle *string

suiRPC *string
suiMoveEventType *string

Expand Down Expand Up @@ -377,6 +381,10 @@ func init() {
aptosAccount = NodeCmd.Flags().String("aptosAccount", "", "aptos account")
aptosHandle = NodeCmd.Flags().String("aptosHandle", "", "aptos handle")

movementRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "movementRPC", "Movement RPC URL", "", []string{"http", "https"})
movementAccount = NodeCmd.Flags().String("movementAccount", "", "movement account")
movementHandle = NodeCmd.Flags().String("movementHandle", "", "movement handle")

suiRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "suiRPC", "Sui RPC URL", "http://sui:9000", []string{"http", "https"})
suiMoveEventType = NodeCmd.Flags().String("suiMoveEventType", "", "Sui move event type for publish_message")

Expand Down Expand Up @@ -887,6 +895,10 @@ func runNode(cmd *cobra.Command, args []string) {
logger.Fatal("Either --aptosAccount, --aptosRPC and --aptosHandle must all be set or all unset")
}

if !argsConsistent([]string{*movementAccount, *movementRPC, *movementHandle}) {
logger.Fatal("Either --movementAccount, --movementRPC and --movementHandle must all be set or all unset")
}

if !argsConsistent([]string{*suiRPC, *suiMoveEventType}) {
logger.Fatal("Either --suiRPC and --suiMoveEventType must all be set or all unset")
}
Expand Down Expand Up @@ -962,6 +974,7 @@ func runNode(cmd *cobra.Command, args []string) {
rpcMap["mantleRPC"] = *mantleRPC
rpcMap["monadRPC"] = *monadRPC
rpcMap["moonbeamRPC"] = *moonbeamRPC
rpcMap["movementRPC"] = *movementRPC
rpcMap["nearRPC"] = *nearRPC
rpcMap["oasisRPC"] = *oasisRPC
rpcMap["optimismRPC"] = *optimismRPC
Expand Down Expand Up @@ -1571,6 +1584,17 @@ func runNode(cmd *cobra.Command, args []string) {
watcherConfigs = append(watcherConfigs, wc)
}

if shouldStart(movementRPC) {
wc := &aptos.WatcherConfig{
NetworkID: "movement",
ChainID: vaa.ChainIDMovement,
Rpc: *movementRPC,
Account: *movementAccount,
Handle: *movementHandle,
}
watcherConfigs = append(watcherConfigs, wc)
}

if shouldStart(suiRPC) {
wc := &sui.WatcherConfig{
NetworkID: "sui",
Expand Down
218 changes: 111 additions & 107 deletions node/pkg/proto/publicrpc/v1/publicrpc.pb.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion node/pkg/watchers/aptos/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ func (wc *WatcherConfig) Create(
_ chan<- *common.GuardianSet,
env common.Environment,
) (interfaces.L1Finalizer, supervisor.Runnable, error) {
return nil, NewWatcher(wc.Rpc, wc.Account, wc.Handle, msgC, obsvReqC).Run, nil
return nil, NewWatcher(wc.ChainID, wc.NetworkID, wc.Rpc, wc.Account, wc.Handle, msgC, obsvReqC).Run, nil
}
62 changes: 37 additions & 25 deletions node/pkg/watchers/aptos/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
"github.com/certusone/wormhole/node/pkg/readiness"
"github.com/certusone/wormhole/node/pkg/supervisor"
"github.com/certusone/wormhole/node/pkg/watchers"
eth_common "github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
Expand All @@ -25,6 +26,9 @@ import (
type (
// Watcher is responsible for looking over Aptos blockchain and reporting new transactions to the wormhole contract
Watcher struct {
chainID vaa.ChainID
networkID string

aptosRPC string
aptosAccount string
aptosHandle string
Expand All @@ -36,57 +40,65 @@ type (
)

var (
aptosMessagesConfirmed = promauto.NewCounter(
aptosMessagesConfirmed = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "wormhole_aptos_observations_confirmed_total",
Help: "Total number of verified Aptos observations found",
})
currentAptosHeight = promauto.NewGauge(
Help: "Total number of verified observations found for the chain",
}, []string{"chain_name"})
currentAptosHeight = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "wormhole_aptos_current_height",
Help: "Current Aptos block height",
})
Help: "Current block height for the chain",
}, []string{"chain_name"})
)

// NewWatcher creates a new Aptos appid watcher
func NewWatcher(
chainID vaa.ChainID,
networkID watchers.NetworkID,
aptosRPC string,
aptosAccount string,
aptosHandle string,
msgC chan<- *common.MessagePublication,
obsvReqC <-chan *gossipv1.ObservationRequest,
) *Watcher {
return &Watcher{
chainID: chainID,
networkID: string(networkID),
aptosRPC: aptosRPC,
aptosAccount: aptosAccount,
aptosHandle: aptosHandle,
msgC: msgC,
obsvReqC: obsvReqC,
readinessSync: common.MustConvertChainIdToReadinessSyncing(vaa.ChainIDAptos),
readinessSync: common.MustConvertChainIdToReadinessSyncing(chainID),
}
}

func (e *Watcher) Run(ctx context.Context) error {
p2p.DefaultRegistry.SetNetworkStats(vaa.ChainIDAptos, &gossipv1.Heartbeat_Network{
p2p.DefaultRegistry.SetNetworkStats(e.chainID, &gossipv1.Heartbeat_Network{
ContractAddress: e.aptosAccount,
})

logger := supervisor.Logger(ctx)

logger.Info("Starting watcher",
zap.String("watcher_name", "aptos"),
zap.String("aptosRPC", e.aptosRPC),
zap.String("aptosAccount", e.aptosAccount),
zap.String("aptosHandle", e.aptosHandle),
zap.String("watcher_name", e.networkID),
zap.String("rpc", e.aptosRPC),
zap.String("account", e.aptosAccount),
zap.String("handle", e.aptosHandle),
)

logger.Info("Aptos watcher connecting to RPC node ", zap.String("url", e.aptosRPC))

// SECURITY: the API guarantees that we only get the events from the right
// contract
var eventsEndpoint = fmt.Sprintf(`%s/v1/accounts/%s/events/%s/event`, e.aptosRPC, e.aptosAccount, e.aptosHandle)
var aptosHealth = fmt.Sprintf(`%s/v1`, e.aptosRPC)

logger.Info("watcher connecting to RPC node ",
zap.String("url", e.aptosRPC),
zap.String("eventsQuery", eventsEndpoint),
zap.String("healthQuery", aptosHealth),
)

// the events have sequence numbers associated with them in the aptos API
// (NOTE: this is not the same as the wormhole sequence id). The event
// endpoint is paginated, so we use this variable to keep track of which
Expand All @@ -103,7 +115,7 @@ func (e *Watcher) Run(ctx context.Context) error {
case <-ctx.Done():
return ctx.Err()
case r := <-e.obsvReqC:
if vaa.ChainID(r.ChainId) != vaa.ChainIDAptos {
if vaa.ChainID(r.ChainId) != e.chainID {
panic("invalid chain ID")
}

Expand All @@ -117,13 +129,13 @@ func (e *Watcher) Run(ctx context.Context) error {
body, err := e.retrievePayload(s)
if err != nil {
logger.Error("retrievePayload", zap.Error(err))
p2p.DefaultRegistry.AddErrorCount(vaa.ChainIDAptos, 1)
p2p.DefaultRegistry.AddErrorCount(e.chainID, 1)
continue
}

if !gjson.Valid(string(body)) {
logger.Error("InvalidJson: " + string(body))
p2p.DefaultRegistry.AddErrorCount(vaa.ChainIDAptos, 1)
p2p.DefaultRegistry.AddErrorCount(e.chainID, 1)
break

}
Expand Down Expand Up @@ -165,7 +177,7 @@ func (e *Watcher) Run(ctx context.Context) error {
eventsJson, err := e.retrievePayload(s)
if err != nil {
logger.Error("retrievePayload", zap.Error(err))
p2p.DefaultRegistry.AddErrorCount(vaa.ChainIDAptos, 1)
p2p.DefaultRegistry.AddErrorCount(e.chainID, 1)
continue
}

Expand All @@ -178,7 +190,7 @@ func (e *Watcher) Run(ctx context.Context) error {

if !gjson.Valid(string(eventsJson)) {
logger.Error("InvalidJson: " + string(eventsJson))
p2p.DefaultRegistry.AddErrorCount(vaa.ChainIDAptos, 1)
p2p.DefaultRegistry.AddErrorCount(e.chainID, 1)
continue

}
Expand Down Expand Up @@ -207,13 +219,13 @@ func (e *Watcher) Run(ctx context.Context) error {
health, err := e.retrievePayload(aptosHealth)
if err != nil {
logger.Error("health", zap.Error(err))
p2p.DefaultRegistry.AddErrorCount(vaa.ChainIDAptos, 1)
p2p.DefaultRegistry.AddErrorCount(e.chainID, 1)
continue
}

if !gjson.Valid(string(health)) {
logger.Error("Invalid JSON in health response: " + string(health))
p2p.DefaultRegistry.AddErrorCount(vaa.ChainIDAptos, 1)
p2p.DefaultRegistry.AddErrorCount(e.chainID, 1)
continue

}
Expand All @@ -226,8 +238,8 @@ func (e *Watcher) Run(ctx context.Context) error {
blockHeight := pHealth.Get("block_height")

if blockHeight.Exists() {
currentAptosHeight.Set(float64(blockHeight.Uint()))
p2p.DefaultRegistry.SetNetworkStats(vaa.ChainIDAptos, &gossipv1.Heartbeat_Network{
currentAptosHeight.WithLabelValues(e.networkID).Set(float64(blockHeight.Uint()))
p2p.DefaultRegistry.SetNetworkStats(e.chainID, &gossipv1.Heartbeat_Network{
Height: int64(blockHeight.Uint()),
ContractAddress: e.aptosAccount,
})
Expand Down Expand Up @@ -309,14 +321,14 @@ func (e *Watcher) observeData(logger *zap.Logger, data gjson.Result, nativeSeq u
Timestamp: time.Unix(int64(ts.Uint()), 0),
Nonce: uint32(nonce.Uint()), // uint32
Sequence: sequence.Uint(),
EmitterChain: vaa.ChainIDAptos,
EmitterChain: e.chainID,
EmitterAddress: a,
Payload: pl,
ConsistencyLevel: uint8(consistencyLevel.Uint()),
IsReobservation: isReobservation,
}

aptosMessagesConfirmed.Inc()
aptosMessagesConfirmed.WithLabelValues(e.networkID).Inc()

logger.Info("message observed",
zap.String("txHash", observation.TxIDString()),
Expand Down
1 change: 1 addition & 0 deletions proto/publicrpc/v1/publicrpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ enum ChainID {
CHAIN_ID_UNICHAIN = 44;
CHAIN_ID_WORLDCHAIN = 45;
CHAIN_ID_INK = 46;
CHAIN_ID_MOVEMENT = 49;
CHAIN_ID_WORMCHAIN = 3104;
CHAIN_ID_COSMOSHUB = 4000;
CHAIN_ID_EVMOS = 4001;
Expand Down
1 change: 1 addition & 0 deletions sdk/testnet_consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var knownTestnetTokenbridgeEmitters = map[vaa.ChainID]string{
vaa.ChainIDSei: "9328673cb5de3fd99974cefbbd90fea033f4c59a572abfd7e1a4eebcc5d18157",
vaa.ChainIDScroll: "00000000000000000000000022427d90B7dA3fA4642F7025A854c7254E4e45BF",
vaa.ChainIDMantle: "00000000000000000000000075Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D",
vaa.ChainIDMovement: "0000000000000000000000000000000000000000000000000000000000000002",
vaa.ChainIDBlast: "000000000000000000000000430855B4D43b8AEB9D2B9869B74d58dda79C0dB2",
vaa.ChainIDXLayer: "000000000000000000000000dA91a06299BBF302091B053c6B9EF86Eff0f930D",
vaa.ChainIDLinea: "000000000000000000000000C7A204bDBFe983FCD8d8E61D02b475D4073fF97e",
Expand Down
7 changes: 7 additions & 0 deletions sdk/vaa/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ func (c ChainID) String() string {
return "hyperevm"
case ChainIDMonad:
return "monad"
case ChainIDMovement:
return "movement"
case ChainIDCosmoshub:
return "cosmoshub"
case ChainIDEvmos:
Expand Down Expand Up @@ -350,6 +352,8 @@ func ChainIDFromString(s string) (ChainID, error) {
return ChainIDHyperEVM, nil
case "monad":
return ChainIDMonad, nil
case "movement":
return ChainIDMovement, nil
case "cosmoshub":
return ChainIDCosmoshub, nil
case "seievm":
Expand Down Expand Up @@ -435,6 +439,7 @@ func GetAllNetworkIDs() []ChainID {
ChainIDInk,
ChainIDHyperEVM,
ChainIDMonad,
ChainIDMovement,
ChainIDWormchain,
ChainIDCosmoshub,
ChainIDEvmos,
Expand Down Expand Up @@ -545,6 +550,8 @@ const (
ChainIDHyperEVM ChainID = 47
// ChainIDMonad is the ChainID of Monad
ChainIDMonad ChainID = 48
// ChainIDMovement is the ChainID of Movement
ChainIDMovement ChainID = 49
//ChainIDWormchain is the ChainID of Wormchain
ChainIDWormchain ChainID = 3104
// ChainIDCosmoshub is the ChainID of Cosmoshub
Expand Down
3 changes: 3 additions & 0 deletions sdk/vaa/structs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func TestChainIDFromString(t *testing.T) {
{input: "ink", output: ChainIDInk},
{input: "hyperevm", output: ChainIDHyperEVM},
{input: "monad", output: ChainIDMonad},
{input: "movement", output: ChainIDMovement},
{input: "seievm", output: ChainIDSeiEVM},
{input: "wormchain", output: ChainIDWormchain},
{input: "cosmoshub", output: ChainIDCosmoshub},
Expand Down Expand Up @@ -133,6 +134,7 @@ func TestChainIDFromString(t *testing.T) {
{input: "Ink", output: ChainIDInk},
{input: "HyperEVM", output: ChainIDHyperEVM},
{input: "Monad", output: ChainIDMonad},
{input: "Movement", output: ChainIDMovement},
{input: "SeiEVM", output: ChainIDSeiEVM},
{input: "Wormchain", output: ChainIDWormchain},
{input: "Cosmoshub", output: ChainIDCosmoshub},
Expand Down Expand Up @@ -335,6 +337,7 @@ func TestChainId_String(t *testing.T) {
{input: 45, output: "worldchain"},
{input: 46, output: "ink"},
{input: 47, output: "hyperevm"},
{input: 49, output: "movement"},
{input: 3104, output: "wormchain"},
{input: 4000, output: "cosmoshub"},
{input: 4001, output: "evmos"},
Expand Down

0 comments on commit 655a43a

Please sign in to comment.