Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BCI-2953] Initial Aptos keystore #13564

Merged
merged 65 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
04aa1ed
chain type to include aptos
yongkangchia Jun 12, 2024
fb33e75
aptos key ed25519 implementation
yongkangchia Jun 13, 2024
bf0d6cd
add aptos to keystore master
yongkangchia Jun 13, 2024
794f319
added exports for keys
yongkangchia Jun 13, 2024
176ee2e
removed sdk dependency
yongkangchia Jun 14, 2024
12c35d5
updated go mod
yongkangchia Jun 14, 2024
0bc9679
Added tests for account sdk deps
yongkangchia Jun 14, 2024
1aafd02
added aptos keystore
yongkangchia Jun 14, 2024
d0f516a
added interface assertion to solana
yongkangchia Jun 14, 2024
684d3a6
added aptos keyring
yongkangchia Jun 14, 2024
3cc7061
added aptos keystore mocks
yongkangchia Jun 15, 2024
faf6717
added aptos key controller & router
yongkangchia Jun 15, 2024
53e5391
Added aptos keys command
yongkangchia Jun 15, 2024
cea7964
added aptos keystore e2e tests
yongkangchia Jun 15, 2024
360a792
Added Aptos network ORM test for key
yongkangchia Jun 17, 2024
a3db03d
Added aptos ocr2 keys support
yongkangchia Jun 17, 2024
cb34e55
Revert "Added Aptos network ORM test for key"
yongkangchia Jun 17, 2024
e66b7d8
Added Aptos export functionality
yongkangchia Jun 17, 2024
f438e06
Modified Aptos Accounts for key rotation
yongkangchia Jun 17, 2024
038017f
added aptos keystore to orm validation
yongkangchia Jun 17, 2024
87bcc83
Addded Change logs
yongkangchia Jun 17, 2024
56d2f07
Updated keys implementation to remove address
yongkangchia Jun 17, 2024
56bf81b
Revert "updated go mod"
yongkangchia Jun 17, 2024
1ff903d
Update changeset
yongkangchia Jun 18, 2024
d81f7a4
Updated GraphQL to include Aptos
yongkangchia Jun 18, 2024
ce41adc
Linting fixes
yongkangchia Jun 18, 2024
76a3b82
added aptos configs for keystore
yongkangchia Jun 19, 2024
a4599a5
Changed Aptos config to RawConfig
yongkangchia Jun 19, 2024
ae9bfb2
Added Mock file for general config
yongkangchia Jun 19, 2024
bee29ec
using *bool type for aptos enabled
yongkangchia Jun 19, 2024
df8ecfa
added debug for error
yongkangchia Jun 19, 2024
7e2940c
Fixed tests + added ORM
yongkangchia Jun 19, 2024
37d7f67
Added Test Scripts
yongkangchia Jun 19, 2024
053d843
Updated type of raw config
yongkangchia Jun 20, 2024
71431cf
update all packages go mod tidy
yongkangchia Jun 20, 2024
7f5228a
update all packages go mod
yongkangchia Jun 20, 2024
af9b808
Update core/services/chainlink/config.go
yongkangchia Jun 20, 2024
c0b1203
Removed Address in key
yongkangchia Jun 24, 2024
52984ad
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 25, 2024
26d66da
Fixed merge conflicts
yongkangchia Jun 25, 2024
5484ddb
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 25, 2024
fe40501
nit changes based on reviews
yongkangchia Jun 26, 2024
22f72df
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 26, 2024
e840f5d
Added typecast check for keyring
yongkangchia Jun 27, 2024
3ad8c9e
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 27, 2024
eace378
Added config type cast check
yongkangchia Jun 27, 2024
b2af408
make generate update version
yongkangchia Jun 28, 2024
1fd2ca6
update validation method
yongkangchia Jun 28, 2024
4ae0848
update config validation
yongkangchia Jun 28, 2024
badba0e
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 28, 2024
b0beb7a
Removed Pointer type for RawConfig
yongkangchia Jun 28, 2024
8e9d51e
Updated Validate with better error message
yongkangchia Jun 28, 2024
c2ebf42
Added Error config
yongkangchia Jun 28, 2024
4adc736
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 28, 2024
f704847
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 28, 2024
9247f70
Update struct of RawConfig
yongkangchia Jun 29, 2024
4090a87
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jun 29, 2024
05d87de
removed uncessary config validation
yongkangchia Jul 1, 2024
6903844
Added missing starknet keystore tests
yongkangchia Jul 1, 2024
2ca056b
added styling feedback
yongkangchia Jul 1, 2024
62712ba
Update core/services/keystore/keys/aptoskey/account.go
yongkangchia Jul 1, 2024
202519a
Removed empty array table for config
yongkangchia Jul 1, 2024
4e92975
fixed lint
yongkangchia Jul 1, 2024
af142e5
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jul 1, 2024
ab26fc0
Merge branch 'develop' into BCI-2953-Aptos-Keystore
yongkangchia Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/real-fireants-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

#changed Added Aptos Keystore to Core. This includes Aptos Key which uses ED25519, Keystore, Relevant tests
1 change: 1 addition & 0 deletions core/cmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ func NewApp(s *Shell) *cli.App {
keysCommand("Cosmos", NewCosmosKeysClient(s)),
keysCommand("Solana", NewSolanaKeysClient(s)),
keysCommand("StarkNet", NewStarkNetKeysClient(s)),
keysCommand("Aptos", NewAptosKeysClient(s)),
keysCommand("DKGSign", NewDKGSignKeysClient(s)),
keysCommand("DKGEncrypt", NewDKGEncryptKeysClient(s)),

Expand Down
57 changes: 57 additions & 0 deletions core/cmd/aptos_keys_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cmd

import (
"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey"
"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)

type AptosKeyPresenter struct {
JAID
presenters.AptosKeyResource
}

// RenderTable implements TableRenderer
func (p AptosKeyPresenter) RenderTable(rt RendererTable) error {
headers := []string{"ID", "Aptos Public Key"}
rows := [][]string{p.ToRow()}

if _, err := rt.Write([]byte("🔑 Aptos Keys\n")); err != nil {
return err
}
renderList(headers, rows, rt.Writer)

return utils.JustError(rt.Write([]byte("\n")))
}

func (p *AptosKeyPresenter) ToRow() []string {
row := []string{
p.ID,
p.PubKey,
}

return row
}

type AptosKeyPresenters []AptosKeyPresenter

// RenderTable implements TableRenderer
func (ps AptosKeyPresenters) RenderTable(rt RendererTable) error {
headers := []string{"ID", "Aptos Public Key"}
rows := [][]string{}

for _, p := range ps {
rows = append(rows, p.ToRow())
}

if _, err := rt.Write([]byte("🔑 Aptos Keys\n")); err != nil {
return err
}
renderList(headers, rows, rt.Writer)

return utils.JustError(rt.Write([]byte("\n")))
}

func NewAptosKeysClient(s *Shell) KeysClient {
return newKeysClient[aptoskey.Key, AptosKeyPresenter, AptosKeyPresenters]("Aptos", s)
}
175 changes: 175 additions & 0 deletions core/cmd/aptos_keys_commands_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package cmd_test

import (
"bytes"
"context"
"flag"
"fmt"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"

"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink/v2/core/cmd"
"github.com/smartcontractkit/chainlink/v2/core/internal/cltest"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey"
"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)

func TestAptosKeyPresenter_RenderTable(t *testing.T) {
t.Parallel()

var (
id = "1"
pubKey = "somepubkey"
buffer = bytes.NewBufferString("")
r = cmd.RendererTable{Writer: buffer}
)

p := cmd.AptosKeyPresenter{
JAID: cmd.JAID{ID: id},
AptosKeyResource: presenters.AptosKeyResource{
JAID: presenters.NewJAID(id),
PubKey: pubKey,
},
}

// Render a single resource
require.NoError(t, p.RenderTable(r))

output := buffer.String()
assert.Contains(t, output, id)
assert.Contains(t, output, pubKey)

// Render many resources
buffer.Reset()
ps := cmd.AptosKeyPresenters{p}
require.NoError(t, ps.RenderTable(r))

output = buffer.String()
assert.Contains(t, output, id)
assert.Contains(t, output, pubKey)
}

func TestShell_AptosKeys(t *testing.T) {
app := startNewApplicationV2(t, nil)
ks := app.GetKeyStore().Aptos()
cleanup := func() {
ctx := context.Background()
keys, err := ks.GetAll()
require.NoError(t, err)
for _, key := range keys {
require.NoError(t, utils.JustError(ks.Delete(ctx, key.ID())))
}
requireAptosKeyCount(t, app, 0)
}

t.Run("ListAptosKeys", func(tt *testing.T) {
defer cleanup()
ctx := testutils.Context(t)
client, r := app.NewShellAndRenderer()
key, err := app.GetKeyStore().Aptos().Create(ctx)
require.NoError(t, err)
requireAptosKeyCount(t, app, 1)
assert.Nil(t, cmd.NewAptosKeysClient(client).ListKeys(cltest.EmptyCLIContext()))
require.Equal(t, 1, len(r.Renders))
keys := *r.Renders[0].(*cmd.AptosKeyPresenters)
assert.True(t, key.PublicKeyStr() == keys[0].PubKey)
})

t.Run("CreateAptosKey", func(tt *testing.T) {
defer cleanup()
client, _ := app.NewShellAndRenderer()
require.NoError(t, cmd.NewAptosKeysClient(client).CreateKey(nilContext))
keys, err := app.GetKeyStore().Aptos().GetAll()
require.NoError(t, err)
require.Len(t, keys, 1)
})

t.Run("DeleteAptosKey", func(tt *testing.T) {
defer cleanup()
ctx := testutils.Context(t)
client, _ := app.NewShellAndRenderer()
key, err := app.GetKeyStore().Aptos().Create(ctx)
require.NoError(t, err)
requireAptosKeyCount(t, app, 1)
set := flag.NewFlagSet("test", 0)
flagSetApplyFromAction(cmd.NewAptosKeysClient(client).DeleteKey, set, "aptos")

require.NoError(tt, set.Set("yes", "true"))

strID := key.ID()
err = set.Parse([]string{strID})
require.NoError(t, err)
c := cli.NewContext(nil, set, nil)
err = cmd.NewAptosKeysClient(client).DeleteKey(c)
require.NoError(t, err)
requireAptosKeyCount(t, app, 0)
})

t.Run("ImportExportAptosKey", func(tt *testing.T) {
defer cleanup()
defer deleteKeyExportFile(t)
ctx := testutils.Context(t)
client, _ := app.NewShellAndRenderer()

_, err := app.GetKeyStore().Aptos().Create(ctx)
require.NoError(t, err)

keys := requireAptosKeyCount(t, app, 1)
key := keys[0]
keyName := keyNameForTest(t)

// Export test invalid id
set := flag.NewFlagSet("test Aptos export", 0)
flagSetApplyFromAction(cmd.NewAptosKeysClient(client).ExportKey, set, "aptos")

require.NoError(tt, set.Parse([]string{"0"}))
require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt"))
require.NoError(tt, set.Set("output", keyName))

c := cli.NewContext(nil, set, nil)
err = cmd.NewAptosKeysClient(client).ExportKey(c)
require.Error(t, err, "Error exporting")
require.Error(t, utils.JustError(os.Stat(keyName)))

// Export test
set = flag.NewFlagSet("test Aptos export", 0)
flagSetApplyFromAction(cmd.NewAptosKeysClient(client).ExportKey, set, "aptos")

require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())}))
require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt"))
require.NoError(tt, set.Set("output", keyName))

c = cli.NewContext(nil, set, nil)

require.NoError(t, cmd.NewAptosKeysClient(client).ExportKey(c))
require.NoError(t, utils.JustError(os.Stat(keyName)))

require.NoError(t, utils.JustError(app.GetKeyStore().Aptos().Delete(ctx, key.ID())))
requireAptosKeyCount(t, app, 0)

set = flag.NewFlagSet("test Aptos import", 0)
flagSetApplyFromAction(cmd.NewAptosKeysClient(client).ImportKey, set, "aptos")

require.NoError(tt, set.Parse([]string{keyName}))
require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt"))
c = cli.NewContext(nil, set, nil)
require.NoError(t, cmd.NewAptosKeysClient(client).ImportKey(c))

requireAptosKeyCount(t, app, 1)
})
}

func requireAptosKeyCount(t *testing.T, app chainlink.Application, length int) []aptoskey.Key {
t.Helper()
keys, err := app.GetKeyStore().Aptos().GetAll()
require.NoError(t, err)
require.Len(t, keys, length)
return keys
}
1 change: 1 addition & 0 deletions core/config/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type AppConfig interface {
CosmosEnabled() bool
SolanaEnabled() bool
StarkNetEnabled() bool
AptosEnabled() bool

Validate() error
ValidateDB() error
Expand Down
2 changes: 2 additions & 0 deletions core/internal/cltest/cltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey"
Expand Down Expand Up @@ -126,6 +127,7 @@ var (
DefaultP2PKey = p2pkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed))
DefaultSolanaKey = solkey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed))
DefaultStarkNetKey = starkkey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed))
DefaultAptosKey = aptoskey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed))
DefaultVRFKey = vrfkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed))
DefaultDKGSignKey = dkgsignkey.MustNewXXXTestingOnly(big.NewInt(KeyBigIntSeed))
DefaultDKGEncryptKey = dkgencryptkey.MustNewXXXTestingOnly(big.NewInt(KeyBigIntSeed))
Expand Down
26 changes: 26 additions & 0 deletions core/services/chainlink/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,32 @@ type Config struct {
Solana solcfg.TOMLConfigs `toml:",omitempty"`

Starknet stkcfg.TOMLConfigs `toml:",omitempty"`

Aptos RawConfigs `toml:",omitempty"`
}

// RawConfigs is a list of RawConfig.
type RawConfigs []RawConfig

// RawConfig is the config used for chains that are not embedded.
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"})
}
}
return err
}

func (c *RawConfig) IsEnabled() bool {
if c == nil {
return false
}

return (*c)["Enabled"] == nil || *(*c)["Enabled"].(*bool)
}

// TOMLString returns a TOML encoded string.
Expand Down
9 changes: 9 additions & 0 deletions core/services/chainlink/config_general.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,15 @@ func (g *generalConfig) StarkNetEnabled() bool {
return false
}

func (g *generalConfig) AptosEnabled() bool {
for _, c := range g.c.Aptos {
if c.IsEnabled() {
return true
}
}
return false
}

func (g *generalConfig) WebServer() config.WebServer {
return &webServerConfig{c: g.c.WebServer, s: g.secrets.WebServer, rootDir: g.RootDir}
}
Expand Down
5 changes: 3 additions & 2 deletions core/services/chainlink/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,7 @@ func TestConfig_Validate(t *testing.T) {
toml string
exp string
}{
{name: "invalid", toml: invalidTOML, exp: `invalid configuration: 7 errors:
{name: "invalid", toml: invalidTOML, exp: `invalid configuration: 8 errors:
- P2P.V2.Enabled: invalid value (false): P2P required for OCR or OCR2. Please enable P2P or disable OCR/OCR2.
- Database.Lock.LeaseRefreshInterval: invalid value (6s): must be less than or equal to half of LeaseDuration (10s)
- WebServer: 8 errors:
Expand Down Expand Up @@ -1357,7 +1357,8 @@ func TestConfig_Validate(t *testing.T) {
- 0.ChainID: missing: required for all chains
- 1: 2 errors:
- ChainID: missing: required for all chains
- Nodes: missing: must have at least one node`},
- Nodes: missing: must have at least one node
- Aptos.0.Enabled: invalid value (1): expected *bool`},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is formatted this way due to one test

Now:     - Aptos.0.Enabled: invalid value (1): expected *bool

With more tests:
                                +       - Aptos.0: 2 errors:
                                +                       - Enabled: invalid value (1): expected *bool
                                +                       - test: invalid value (1): this is a test

} {
t.Run(tt.name, func(t *testing.T) {
var c Config
Expand Down
18 changes: 18 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.

3 changes: 3 additions & 0 deletions core/services/chainlink/testdata/config-invalid.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ APIKey = 'key'

[[Starknet]]

[[Aptos]]
Enabled = 1

[OCR2]
Enabled = true

Expand Down
12 changes: 12 additions & 0 deletions core/services/job/job_orm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,18 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) {
require.NoError(t, err)
})

t.Run(("test Aptos key validation"), func(t *testing.T) {
ctx := testutils.Context(t)
jb.OCR2OracleSpec.Relay = relay.NetworkAptos
err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key")
require.EqualError(t, err, "no Aptos key matching: \"bad key\"")

aptosKey, err := keyStore.Aptos().Create(ctx)
require.NoError(t, err)
err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, aptosKey.ID())
require.NoError(t, err)
})

t.Run("test Mercury ETH key validation", func(t *testing.T) {
ctx := testutils.Context(t)
jb.OCR2OracleSpec.PluginType = types.Mercury
Expand Down
Loading
Loading