Skip to content

Enable Cubist Signer integration #3965

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

Open
wants to merge 51 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
dd5176e
Add comments to signer-config setup
richardpringle Feb 17, 2025
ed0c5f8
Extend siging configuration to include RPC
richardpringle Feb 14, 2025
dd99c36
Add default behaviour to switch
richardpringle Feb 19, 2025
9f61b1c
Add timeout to signer instantiation
richardpringle Feb 19, 2025
f106e92
Make rpc-signer client handle the connection
richardpringle Feb 20, 2025
de574a4
Fix linter error
richardpringle Feb 21, 2025
a7e895a
Close the connection on any error
richardpringle Feb 21, 2025
15a53f0
Remove special character from error message
richardpringle Mar 12, 2025
cc11cac
Use Go casing conventions in json config
richardpringle Mar 12, 2025
eeb3644
Fix default signing config behaviour
richardpringle Mar 12, 2025
47e37fa
Cleanup type-check in config-test
richardpringle Mar 13, 2025
505c7fb
Simply variable name for url
richardpringle Mar 13, 2025
0d66c3a
Only use public config api in test
richardpringle Mar 13, 2025
f8837e8
Add test for default config signer with multiple inits
richardpringle Mar 13, 2025
97ffb21
Merge remote-tracking branch 'origin/master' into signers-config-wip
richardpringle Mar 14, 2025
7327d0f
Merge remote-tracking branch 'origin/master' into signers-config-wip
richardpringle Mar 18, 2025
bb56fd5
Bubble up cleanup function
richardpringle Mar 18, 2025
0b22c0a
Merge remote-tracking branch 'origin/master' into signers-config-wip
richardpringle Mar 24, 2025
d3e2677
Merge remote-tracking branch 'origin/master' into signers-config-wip
richardpringle Mar 24, 2025
193ccd4
Merge remote-tracking branch 'origin/master' into signers-config-wip
richardpringle Mar 28, 2025
bd77f88
Simplify default signer creation code
richardpringle Mar 28, 2025
5bc1bc0
Cleanup signer creation when key path is set
richardpringle Mar 28, 2025
64f1a1d
Remove redundant word in error message
richardpringle Mar 28, 2025
b55f05d
Fix config test name
richardpringle Mar 28, 2025
e85e815
Small rpc-signer-client cleanup refactor
richardpringle Mar 28, 2025
c8b3714
Fix the min-connect-timeout for grpc signer
richardpringle Mar 28, 2025
c46209e
Merge branch 'master' into signers-config-wip
geoff-vball May 5, 2025
8a4cb7c
Merge branch 'master' into signers-config-wip
geoff-vball May 13, 2025
99c3a48
Reconfigure signer setup
geoff-vball May 15, 2025
e23e982
Merge branch 'master' into signers-config-wip
geoff-vball May 15, 2025
e408079
Refactor config
geoff-vball May 15, 2025
c34b691
Reduce diff
geoff-vball May 15, 2025
446b34f
Merge branch 'master' into signers-config-wip
geoff-vball May 27, 2025
de822f3
Fix tests
geoff-vball May 27, 2025
80ed485
lint
geoff-vball May 27, 2025
a6d8add
Add logging to signer creation
geoff-vball May 27, 2025
649447d
Merge branch 'master' into signers-config-wip
geoff-vball May 27, 2025
d79916b
Fix ordering
geoff-vball May 27, 2025
14c5525
Lint
geoff-vball May 27, 2025
fac9f79
Merge branch 'master' into signers-config-wip
geoff-vball May 28, 2025
8fa5525
Remove json tags from fields that are not user supplied
geoff-vball May 28, 2025
0c15985
Remove stray comment
geoff-vball May 29, 2025
15db2ad
Merge branch 'master' into signers-config-wip
geoff-vball Jun 3, 2025
58cc0c1
Update utils/crypto/bls/signer/rpcsigner/client.go
geoff-vball Jun 17, 2025
f92d3be
Review fixes
geoff-vball Jun 17, 2025
270d59a
Merge branch 'signers-config-wip' of github.com:ava-labs/avalanche-go…
geoff-vball Jun 17, 2025
60526b1
Move signer to node package
geoff-vball Jun 17, 2025
9791ff8
Merge branch 'master' into signers-config-wip
geoff-vball Jun 17, 2025
ba4977a
Add missing files
geoff-vball Jun 18, 2025
3283340
Wrap error
geoff-vball Jun 24, 2025
d6512c2
Lint
geoff-vball Jun 24, 2025
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
272 changes: 91 additions & 181 deletions config/config.go

Large diffs are not rendered by default.

103 changes: 23 additions & 80 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,23 @@
package config

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net"
"os"
"path/filepath"
"testing"

"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"

"github.com/ava-labs/avalanchego/chains"
"github.com/ava-labs/avalanchego/config/node"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/proto/pb/signer"
"github.com/ava-labs/avalanchego/snow/consensus/snowball"
"github.com/ava-labs/avalanchego/subnets"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/crypto/bls/signer/localsigner"
"github.com/ava-labs/avalanchego/utils/crypto/bls/signer/rpcsigner"
"github.com/ava-labs/avalanchego/utils/perms"
)

Expand Down Expand Up @@ -557,63 +551,34 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) {
}
}

type signerServer struct {
signer.UnimplementedSignerServer
}

func (*signerServer) PublicKey(context.Context, *signer.PublicKeyRequest) (*signer.PublicKeyResponse, error) {
// for tests to pass, this must be the base64 encoding of a 32 byte public key
// but it does not need to be associated with any private key
bytes, err := base64.StdEncoding.DecodeString("j8Ndzc1I6EYWYUWAdhcwpQ1I2xX/i4fdwgJIaxbHlf9yQKMT0jlReiiLYsydgaS1")
if err != nil {
return nil, err
}

return &signer.PublicKeyResponse{
PublicKey: bytes,
}, nil
}

func TestGetStakingSigner(t *testing.T) {
testKey := "HLimS3vRibTMk9lZD4b+Z+GLuSBShvgbsu0WTLt2Kd4="
rpcServer := grpc.NewServer()
defer rpcServer.GracefulStop()

signer.RegisterSignerServer(rpcServer, &signerServer{})

listener, err := net.Listen("tcp", "[::1]:0")
require.NoError(t, err)

go func() {
require.NoError(t, rpcServer.Serve(listener))
}()

type config map[string]any
type cfg map[string]any
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we don't need this type alias


tests := []struct {
name string
viperKeys string
config config
expectedSignerType bls.Signer
expectedErr error
name string
viperKeys string
config cfg
expectedSignerConfigType interface{}
expectedErr error
}{
{
name: "default-signer",
expectedSignerType: &localsigner.LocalSigner{},
name: "default-signer",
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remove the kebab-casing in these test names? Plain strings work fine and there's no reason to format it this way IMO

expectedSignerConfigType: node.SignerPathConfig{},
},
{
name: "ephemeral-signer",
config: config{StakingEphemeralSignerEnabledKey: true},
expectedSignerType: &localsigner.LocalSigner{},
name: "ephemeral-signer",
config: cfg{StakingEphemeralSignerEnabledKey: true},
expectedSignerConfigType: node.EphemeralSignerConfig{},
},
{
name: "content-key",
config: config{StakingSignerKeyContentKey: testKey},
expectedSignerType: &localsigner.LocalSigner{},
name: "content-key",
config: cfg{StakingSignerKeyContentKey: testKey},
expectedSignerConfigType: node.ContentKeyConfig{},
},
{
name: "file-key",
config: config{
config: cfg{
StakingSignerKeyPathKey: func() string {
filePath := filepath.Join(t.TempDir(), "signer.key")
bytes, err := base64.StdEncoding.DecodeString(testKey)
Expand All @@ -622,16 +587,16 @@ func TestGetStakingSigner(t *testing.T) {
return filePath
}(),
},
expectedSignerType: &localsigner.LocalSigner{},
expectedSignerConfigType: node.SignerPathConfig{},
},
{
name: "rpc-signer",
config: config{StakingRPCSignerKey: listener.Addr().String()},
expectedSignerType: &rpcsigner.Client{},
name: "rpc-signer",
config: cfg{StakingRPCSignerKey: "localhost"},
expectedSignerConfigType: node.RPCSignerConfig{},
},
{
name: "multiple-configurations-set",
config: config{
config: cfg{
StakingEphemeralSignerEnabledKey: true,
StakingSignerKeyContentKey: testKey,
},
Expand All @@ -651,36 +616,14 @@ func TestGetStakingSigner(t *testing.T) {
v.Set(key, value)
}

config, cleanup, err := GetNodeConfig(context.Background(), v)
defer func() {
if err == nil {
_ = cleanup()
}
}()
config, err := GetNodeConfig(v)

require.ErrorIs(err, tt.expectedErr)
require.IsType(tt.expectedSignerType, config.StakingSigningKey)
require.IsType(tt.expectedSignerConfigType, config.StakingSignerConfig)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just do an check on the expected config instead of just a type check?

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 was slightly annoying because of the way temp dirs work in the test suite. Let me know if you think it's better or worse.

})
}
}

func TestDefaultConfigInitializationUsesExistingDefaultKey(t *testing.T) {
t.Setenv("HOME", t.TempDir())

require := require.New(t)
v := setupViperFlags()

config1, cleanup1, err := GetNodeConfig(context.Background(), v)
defer func() { _ = cleanup1() }()
require.NoError(err)

config2, cleanup2, err := GetNodeConfig(context.Background(), v)
defer func() { _ = cleanup2() }()
require.NoError(err)

require.Equal(config1.StakingSigningKey.PublicKey(), config2.StakingSigningKey.PublicKey())
}

// setups config json file and writes content
func setupConfigJSON(t *testing.T, rootPath string, value string) string {
configFilePath := filepath.Join(rootPath, "config.json")
Expand Down
26 changes: 19 additions & 7 deletions config/node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/ava-labs/avalanchego/subnets"
"github.com/ava-labs/avalanchego/trace"
"github.com/ava-labs/avalanchego/upgrade"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/profiler"
"github.com/ava-labs/avalanchego/utils/set"
Expand Down Expand Up @@ -76,13 +75,26 @@ type StakingConfig struct {
SybilProtectionEnabled bool `json:"sybilProtectionEnabled"`
PartialSyncPrimaryNetwork bool `json:"partialSyncPrimaryNetwork"`
StakingTLSCert tls.Certificate `json:"-"`
StakingSigningKey bls.Signer `json:"-"`
SybilProtectionDisabledWeight uint64 `json:"sybilProtectionDisabledWeight"`
// not accessed but used for logging
StakingKeyPath string `json:"stakingKeyPath"`
StakingCertPath string `json:"stakingCertPath"`
StakingSignerPath string `json:"stakingSignerPath"`
StakingSignerRPC string `json:"stakingSignerRPC"`
StakingTLSKeyPath string `json:"stakingTLSKeyPath"`
StakingTLSCertPath string `json:"stakingTLSCertPath"`

StakingSignerConfig interface{} `json:"stakingSignerConfig"`
}

type EphemeralSignerConfig struct{}

type ContentKeyConfig struct {
SignerKeyRawContent string `json:"signerKeyRawContent"`
}

type SignerPathConfig struct {
SignerPathIsSet bool `json:"signerPathIsSet"`
SigningKeyPath string `json:"signingKeyPath"`
}

type RPCSignerConfig struct {
StakingSignerRPC string `json:"stakingSignerRPC"`
}

type StateSyncConfig struct {
Expand Down
12 changes: 1 addition & 11 deletions main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"time"

"github.com/spf13/pflag"
"golang.org/x/term"
Expand Down Expand Up @@ -53,9 +51,7 @@ func main() {
os.Exit(0)
}

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
nodeConfig, cleanup, err := config.GetNodeConfig(ctx, v)
cancel()
nodeConfig, err := config.GetNodeConfig(v)
if err != nil {
fmt.Printf("couldn't load node config: %s\n", err)
os.Exit(1)
Expand All @@ -68,15 +64,9 @@ func main() {
nodeApp, err := app.New(nodeConfig)
if err != nil {
fmt.Printf("couldn't start node: %s\n", err)
if err := cleanup(); err != nil {
fmt.Printf("error cleaning up: %s\n", err)
}
os.Exit(1)
}

exitCode := app.Run(nodeApp)
if err := cleanup(); err != nil {
fmt.Printf("error cleaning up: %s\n", err)
}
os.Exit(exitCode)
}
27 changes: 21 additions & 6 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import (
"github.com/ava-labs/avalanchego/vms/rpcchainvm/runtime"

databasefactory "github.com/ava-labs/avalanchego/database/factory"
blssigner "github.com/ava-labs/avalanchego/utils/crypto/bls/signer"
avmconfig "github.com/ava-labs/avalanchego/vms/avm/config"
platformconfig "github.com/ava-labs/avalanchego/vms/platformvm/config"
coreth "github.com/ava-labs/coreth/plugin/evm"
Expand Down Expand Up @@ -134,7 +135,12 @@ func New(
Config: config,
}

pop, err := signer.NewProofOfPossession(n.Config.StakingSigningKey)
n.StakingSigner, err = blssigner.GetStakingSigner(config.StakingSignerConfig)
if err != nil {
return nil, fmt.Errorf("problem initializing staking signer: %w", err)
}

pop, err := signer.NewProofOfPossession(n.StakingSigner)
if err != nil {
return nil, fmt.Errorf("problem creating proof of possession: %w", err)
}
Expand Down Expand Up @@ -284,6 +290,7 @@ type Node struct {

StakingTLSSigner crypto.Signer
StakingTLSCert *staking.Certificate
StakingSigner bls.Signer

// Storage for this node
DB database.Database
Expand Down Expand Up @@ -571,7 +578,7 @@ func (n *Node) initNetworking(reg prometheus.Registerer) error {
err := n.vdrs.AddStaker(
constants.PrimaryNetworkID,
n.ID,
n.Config.StakingSigningKey.PublicKey(),
n.StakingSigner.PublicKey(),
dummyTxID,
n.Config.SybilProtectionDisabledWeight,
)
Expand Down Expand Up @@ -610,7 +617,7 @@ func (n *Node) initNetworking(reg prometheus.Registerer) error {
n.Config.NetworkConfig.Beacons = n.bootstrappers
n.Config.NetworkConfig.TLSConfig = tlsConfig
n.Config.NetworkConfig.TLSKey = tlsKey
n.Config.NetworkConfig.BLSKey = n.Config.StakingSigningKey
n.Config.NetworkConfig.BLSKey = n.StakingSigner
n.Config.NetworkConfig.TrackedSubnets = n.Config.TrackedSubnets
n.Config.NetworkConfig.UptimeCalculator = n.uptimeCalculator
n.Config.NetworkConfig.UptimeRequirement = n.Config.UptimeRequirement
Expand Down Expand Up @@ -1100,7 +1107,7 @@ func (n *Node) initChainManager(avaxAssetID ids.ID) error {
SybilProtectionEnabled: n.Config.SybilProtectionEnabled,
StakingTLSSigner: n.StakingTLSSigner,
StakingTLSCert: n.StakingTLSCert,
StakingBLSKey: n.Config.StakingSigningKey,
StakingBLSKey: n.StakingSigner,
Log: n.Log,
LogFactory: n.LogFactory,
VMManager: n.VMManager,
Expand Down Expand Up @@ -1344,7 +1351,7 @@ func (n *Node) initInfoAPI() error {

n.Log.Info("initializing info API")

pop, err := signer.NewProofOfPossession(n.Config.StakingSigningKey)
pop, err := signer.NewProofOfPossession(n.StakingSigner)
if err != nil {
return fmt.Errorf("problem creating proof of possession: %w", err)
}
Expand Down Expand Up @@ -1455,7 +1462,7 @@ func (n *Node) initHealthAPI() error {
return "validator doesn't have a BLS key", nil
}

nodePK := n.Config.StakingSigningKey.PublicKey()
nodePK := n.StakingSigner.PublicKey()
if nodePK.Equals(vdrPK) {
return "node has the correct BLS key", nil
}
Expand Down Expand Up @@ -1650,6 +1657,14 @@ func (n *Node) shutdown() {
time.Sleep(n.Config.ShutdownWait)
}

if n.StakingSigner != nil {
if err := n.StakingSigner.Shutdown(); err != nil {
n.Log.Debug(
"error during staking signer shutdown",
zap.Error(err),
)
}
}
if n.resourceManager != nil {
n.resourceManager.Shutdown()
}
Expand Down
1 change: 1 addition & 0 deletions utils/crypto/bls/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ type Signer interface {
PublicKey() *PublicKey
Sign(msg []byte) (*Signature, error)
SignProofOfPossession(msg []byte) (*Signature, error)
Shutdown() error
}
5 changes: 5 additions & 0 deletions utils/crypto/bls/signer/localsigner/localsigner.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,8 @@ func (s *LocalSigner) Sign(msg []byte) (*bls.Signature, error) {
func (s *LocalSigner) SignProofOfPossession(msg []byte) (*bls.Signature, error) {
return new(bls.Signature).Sign(s.sk, msg, bls.CiphersuiteProofOfPossession.Bytes()), nil
}

// Sign [msg] to prove the ownership
func (*LocalSigner) Shutdown() error {
return nil
}
Loading