Skip to content

Commit

Permalink
Aptos LOOP setup (#14076)
Browse files Browse the repository at this point in the history
* Wire up init necessary for an Aptos LOOP

* Fix typings, make sure SetFrom doesn't blank out RawConfig

* Add missing initialization code for Aptos

* keystore: Aptos should use blake2b since blake2s is unavailable

Blake2b costs about a third of SHA2/SHA3/keccak256

https://aptos.dev/en/build/smart-contracts/cryptography

* keystore: Fix aptoskey public key encoding

* keystore: Remove aptoskey/account.go, completely unused

* aptoskey: Add support for address derivation

* keystore: aptos: Test implementation against vectors generated by the CLI

* keystore: aptos: Remove 0x prefix from public key

* keystore: cosmos: Remove duplicate nil check

* operator_ui: Increase install timeout

Really painful on slower internet connections

* keystore: aptos: Update report hashing format
  • Loading branch information
archseer authored Aug 16, 2024
1 parent 08194be commit 69a0090
Show file tree
Hide file tree
Showing 18 changed files with 219 additions and 238 deletions.
7 changes: 7 additions & 0 deletions core/cmd/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G
}
initOps = append(initOps, chainlink.InitStarknet(ctx, relayerFactory, starkCfg))
}
if cfg.AptosEnabled() {
aptosCfg := chainlink.AptosFactoryConfig{
Keystore: keyStore.Aptos(),
TOMLConfigs: cfg.AptosConfigs(),
}
initOps = append(initOps, chainlink.InitAptos(ctx, relayerFactory, aptosCfg))
}

relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions core/cmd/shell_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,9 @@ func (s *Shell) runNode(c *cli.Context) error {
if s.Config.StarkNetEnabled() {
enabledChains = append(enabledChains, chaintype.StarkNet)
}
if s.Config.AptosEnabled() {
enabledChains = append(enabledChains, chaintype.Aptos)
}
err2 := app.GetKeyStore().OCR2().EnsureKeys(rootCtx, enabledChains...)
if err2 != nil {
return errors.Wrap(err2, "failed to ensure ocr key")
Expand Down Expand Up @@ -464,6 +467,12 @@ func (s *Shell) runNode(c *cli.Context) error {
return errors.Wrap(err2, "failed to ensure starknet key")
}
}
if s.Config.AptosEnabled() {
err2 := app.GetKeyStore().Aptos().EnsureKey(rootCtx)
if err2 != nil {
return errors.Wrap(err2, "failed to ensure aptos key")
}
}

err2 := app.GetKeyStore().CSA().EnsureKey(rootCtx)
if err2 != nil {
Expand Down
7 changes: 7 additions & 0 deletions core/internal/cltest/cltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,13 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn
}
initOps = append(initOps, chainlink.InitStarknet(testCtx, relayerFactory, starkCfg))
}
if cfg.AptosEnabled() {
aptosCfg := chainlink.AptosFactoryConfig{
Keystore: keyStore.Aptos(),
TOMLConfigs: cfg.AptosConfigs(),
}
initOps = append(initOps, chainlink.InitAptos(testCtx, relayerFactory, aptosCfg))
}

relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
if err != nil {
Expand Down
24 changes: 21 additions & 3 deletions core/services/chainlink/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,13 @@ type RawConfig map[string]any
// ValidateConfig returns an error if the Config is not valid for use, as-is.
func (c *RawConfig) ValidateConfig() (err error) {
if v, ok := (*c)["Enabled"]; ok {
if _, ok := v.(*bool); !ok {
err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Enabled", Value: v, Msg: "expected *bool"})
if _, ok := v.(bool); !ok {
err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Enabled", Value: v, Msg: "expected bool"})
}
}
if v, ok := (*c)["ChainID"]; ok {
if _, ok := v.(string); !ok {
err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainID", Value: v, Msg: "expected string"})
}
}
return err
Expand All @@ -67,7 +72,17 @@ func (c *RawConfig) IsEnabled() bool {
return false
}

return (*c)["Enabled"] == nil || *(*c)["Enabled"].(*bool)
enabled, ok := (*c)["Enabled"].(bool)
return ok && enabled
}

func (c *RawConfig) ChainID() string {
if c == nil {
return ""
}

chainID, _ := (*c)["ChainID"].(string)
return chainID
}

// TOMLString returns a TOML encoded string.
Expand Down Expand Up @@ -170,6 +185,9 @@ func (c *Config) SetFrom(f *Config) (err error) {
err = multierr.Append(err, commonconfig.NamedMultiErrorList(err4, "Starknet"))
}

// the plugin should handle it's own defaults and merging
c.Aptos = f.Aptos

_, err = commonconfig.MultiErrorList(err)

return err
Expand Down
4 changes: 4 additions & 0 deletions core/services/chainlink/config_general.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ func (g *generalConfig) StarknetConfigs() starknet.TOMLConfigs {
return g.c.Starknet
}

func (g *generalConfig) AptosConfigs() RawConfigs {
return g.c.Aptos
}

func (g *generalConfig) Validate() error {
return g.validate(g.secrets.Validate)
}
Expand Down
2 changes: 1 addition & 1 deletion core/services/chainlink/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ func TestConfig_Validate(t *testing.T) {
- 1: 2 errors:
- ChainID: missing: required for all chains
- Nodes: missing: must have at least one node
- Aptos.0.Enabled: invalid value (1): expected *bool`},
- Aptos.0.Enabled: invalid value (1): expected bool`},
} {
t.Run(tt.name, func(t *testing.T) {
var c Config
Expand Down
49 changes: 49 additions & 0 deletions core/services/chainlink/mocks/general_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions core/services/chainlink/relayer_chain_interoperators.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,23 @@ func InitStarknet(ctx context.Context, factory RelayerFactory, config StarkNetFa
}
}

// InitAptos is a option for instantiating Aptos relayers
func InitAptos(ctx context.Context, factory RelayerFactory, config AptosFactoryConfig) CoreRelayerChainInitFunc {
return func(op *CoreRelayerChainInteroperators) (err error) {
relayers, err := factory.NewAptos(config.Keystore, config.TOMLConfigs)
if err != nil {
return fmt.Errorf("failed to setup aptos relayer: %w", err)
}

for id, relayer := range relayers {
op.srvs = append(op.srvs, relayer)
op.loopRelayers[id] = relayer
}

return nil
}
}

// Get a [loop.Relayer] by id
func (rs *CoreRelayerChainInteroperators) Get(id types.RelayID) (loop.Relayer, error) {
rs.mu.Lock()
Expand Down
70 changes: 66 additions & 4 deletions core/services/chainlink/relayer_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
pkgstarknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink"
starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain"
"github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config"
starkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
coreconfig "github.com/smartcontractkit/chainlink/v2/core/config"
"github.com/smartcontractkit/chainlink/v2/core/config/env"
Expand Down Expand Up @@ -171,12 +171,12 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solcfg.TOMLConf

type StarkNetFactoryConfig struct {
Keystore keystore.StarkNet
config.TOMLConfigs
starkcfg.TOMLConfigs
}

// TODO BCF-2606 consider consolidating the driving logic with that of NewSolana above via generics
// perhaps when we implement a Cosmos LOOP
func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOMLConfigs) (map[types.RelayID]loop.Relayer, error) {
func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starkcfg.TOMLConfigs) (map[types.RelayID]loop.Relayer, error) {
starknetRelayers := make(map[types.RelayID]loop.Relayer)

var (
Expand Down Expand Up @@ -205,7 +205,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML
if cmdName := env.StarknetPlugin.Cmd.Get(); cmdName != "" {
// setup the starknet relayer to be a LOOP
cfgTOML, err := toml.Marshal(struct {
Starknet config.TOMLConfig
Starknet starkcfg.TOMLConfig
}{Starknet: *chainCfg})
if err != nil {
return nil, fmt.Errorf("failed to marshal StarkNet configs: %w", err)
Expand Down Expand Up @@ -301,3 +301,65 @@ func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[types.RelayI
}
return relayers, nil
}

type AptosFactoryConfig struct {
Keystore keystore.Aptos
TOMLConfigs RawConfigs
}

func (r *RelayerFactory) NewAptos(ks keystore.Aptos, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) {
plugin := env.NewPlugin("aptos")
loopKs := &keystore.AptosLooppSigner{Aptos: ks}
return r.NewLOOPRelayer("Aptos", corerelay.NetworkAptos, plugin, loopKs, chainCfgs)
}

func (r *RelayerFactory) NewLOOPRelayer(name string, network string, plugin env.Plugin, ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) {
relayers := make(map[types.RelayID]loop.Relayer)
lggr := r.Logger.Named(name)

unique := make(map[string]struct{})
// create one relayer per chain id
for _, chainCfg := range chainCfgs {
relayID := types.RelayID{Network: network, ChainID: chainCfg.ChainID()}
if _, alreadyExists := unique[relayID.Name()]; alreadyExists {
return nil, fmt.Errorf("duplicate chain definitions for %s", relayID.Name())
}
unique[relayID.Name()] = struct{}{}

// skip disabled chains from further processing
if !chainCfg.IsEnabled() {
lggr.Warnw("Skipping disabled chain", "id", relayID.ChainID)
continue
}

lggr2 := lggr.Named(relayID.ChainID)

cmdName := plugin.Cmd.Get()
if cmdName == "" {
return nil, fmt.Errorf("plugin not defined: %s", "")
}

// setup the relayer as a LOOP
cfgTOML, err := toml.Marshal(chainCfg)
if err != nil {
return nil, fmt.Errorf("failed to marshal configs: %w", err)
}

envVars, err := plugins.ParseEnvFile(plugin.Env.Get())
if err != nil {
return nil, fmt.Errorf("failed to parse env file: %w", err)
}
cmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{
ID: relayID.Name(),
Cmd: cmdName,
Env: envVars,
})
if err != nil {
return nil, fmt.Errorf("failed to create LOOP command: %w", err)
}
// the relayer service has a delicate keystore dependency. the value that is passed to NewRelayerService must
// be compatible with instantiating a starknet transaction manager KeystoreAdapter within the LOOPp executable.
relayers[relayID] = loop.NewRelayerService(lggr2, r.GRPCOpts, cmdFn, string(cfgTOML), ks, r.CapabilitiesRegistry)
}
return relayers, nil
}
1 change: 1 addition & 0 deletions core/services/chainlink/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type GeneralConfig interface {
CosmosConfigs() coscfg.TOMLConfigs
SolanaConfigs() solcfg.TOMLConfigs
StarknetConfigs() stkcfg.TOMLConfigs
AptosConfigs() RawConfigs
// ConfigTOML returns both the user provided and effective configuration as TOML.
ConfigTOML() (user, effective string)
}
72 changes: 0 additions & 72 deletions core/services/keystore/keys/aptoskey/account.go

This file was deleted.

Loading

0 comments on commit 69a0090

Please sign in to comment.