Skip to content

Commit

Permalink
feat: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
joanestebanr committed Feb 10, 2025
1 parent 73b5449 commit cf64a3a
Show file tree
Hide file tree
Showing 8 changed files with 972 additions and 28 deletions.
63 changes: 63 additions & 0 deletions aggsender/agggsender_signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package aggsender

import (
"context"
"fmt"

kms "cloud.google.com/go/kms/apiv1"
aggkitcommon "github.com/agglayer/aggkit/common"
"github.com/agglayer/aggkit/log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/pascaldekloe/etherkeyms"
)

type funcSignHash = func(context.Context, common.Hash) ([]byte, error)

func newSigner(logger *log.Logger, cfg Config) (funcSignHash, common.Address, error) {
var signer funcSignHash
var err error
var publicKey common.Address
if cfg.KMSKeyName != "" {
logger.Debugf("using KMS key: %s", cfg.KMSKeyName)
signer, publicKey, err = useKMSAuth(cfg)
if err != nil {
return nil, common.Address{}, fmt.Errorf("error using KMS: %w", err)
}
} else {
log.Debugf("using local private key: %s", cfg.AggsenderPrivateKey.Path)
signer, publicKey, err = useLocalAuth(cfg)
if err != nil {
return nil, common.Address{}, fmt.Errorf("error using local key: %w", err)
}
}
return signer, publicKey, nil
}

func useKMSAuth(config Config) (funcSignHash, common.Address, error) {
ctx, cancel := context.WithTimeout(context.Background(), config.KMSConnectionTimeout.Duration)
defer cancel()

client, err := kms.NewKeyManagementClient(ctx)
if err != nil {
return nil, common.Address{}, fmt.Errorf("failed to create kms client: %w", err)
}

mk, err := etherkeyms.NewManagedKey(ctx, client, config.KMSKeyName)
if err != nil {
return nil, common.Address{}, fmt.Errorf("failed to create managed key: %w", err)
}
return mk.SignHash, mk.EthereumAddr, nil

}

func useLocalAuth(config Config) (funcSignHash, common.Address, error) {
privateKey, err := aggkitcommon.NewKeyFromKeystore(config.AggsenderPrivateKey)
if err != nil {
return nil, common.Address{}, err
}
addr := crypto.PubkeyToAddress(privateKey.PublicKey)
return func(ctx context.Context, hash common.Hash) ([]byte, error) {
return crypto.Sign(hash.Bytes(), privateKey)
}, addr, nil
}
18 changes: 8 additions & 10 deletions aggsender/aggsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package aggsender

import (
"context"
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/agglayer/aggkit/aggsender/types"
"github.com/agglayer/aggkit/bridgesync"
aggkitcommon "github.com/agglayer/aggkit/common"

"github.com/agglayer/aggkit/l1infotreesync"
"github.com/agglayer/aggkit/log"
"github.com/agglayer/aggkit/tree"
Expand Down Expand Up @@ -51,7 +51,8 @@ type AggSender struct {

cfg Config

sequencerKey *ecdsa.PrivateKey
signer funcSignHash
signerAddr common.Address

status types.AggsenderStatus
rateLimiter RateLimiter
Expand All @@ -74,11 +75,8 @@ func New(
if err != nil {
return nil, err
}
signer, signerAddr, err := newSigner(logger, cfg)

sequencerPrivateKey, err := aggkitcommon.NewKeyFromKeystore(cfg.AggsenderPrivateKey)
if err != nil {
return nil, err
}
rateLimit := aggkitcommon.NewRateLimit(cfg.MaxSubmitCertificateRate)

logger.Infof("Aggsender Config: %s.", cfg.String())
Expand All @@ -90,7 +88,8 @@ func New(
l2Syncer: l2Syncer,
aggLayerClient: aggLayerClient,
l1infoTreeSyncer: l1InfoTreeSyncer,
sequencerKey: sequencerPrivateKey,
signer: signer,
signerAddr: signerAddr,
epochNotifier: epochNotifier,
status: types.AggsenderStatus{Status: types.StatusNone},
rateLimiter: rateLimit,
Expand Down Expand Up @@ -699,14 +698,13 @@ func (a *AggSender) getImportedBridgeExits(
// signCertificate signs a certificate with the sequencer key
func (a *AggSender) signCertificate(certificate *agglayer.Certificate) (*agglayer.SignedCertificate, error) {
hashToSign := certificate.HashToSign()

sig, err := crypto.Sign(hashToSign.Bytes(), a.sequencerKey)
sig, err := a.signer(context.Background(), hashToSign)
if err != nil {
return nil, err
}

a.log.Infof("Signed certificate. sequencer address: %s. New local exit root: %s Hash signed: %s",
crypto.PubkeyToAddress(a.sequencerKey.PublicKey).String(),
a.signerAddr.String(),
common.BytesToHash(certificate.NewLocalExitRoot[:]).String(),
hashToSign.String(),
)
Expand Down
27 changes: 15 additions & 12 deletions aggsender/aggsender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,6 @@ func TestSendCertificate(t *testing.T) {

type testCfg struct {
name string
sequencerKey *ecdsa.PrivateKey
shouldSendCertificate []interface{}
getLastSentCertificate []interface{}
lastL2BlockProcessed []interface{}
Expand All @@ -1003,11 +1002,14 @@ func TestSendCertificate(t *testing.T) {
setupTest := func(cfg testCfg) (*AggSender, *mocks.AggSenderStorage, *mocks.L2BridgeSyncer,
*agglayer.AgglayerClientMock, *mocks.L1InfoTreeSyncer) {
var (
signer = func(_ context.Context, hash common.Hash) ([]byte, error) {
return crypto.Sign(hash.Bytes(), privateKey)
}
aggsender = &AggSender{
log: log.WithFields("aggsender", 1),
cfg: Config{MaxRetriesStoreCertificate: 1},
sequencerKey: cfg.sequencerKey,
rateLimiter: aggkitcommon.NewRateLimit(aggkitcommon.RateLimitConfig{}),
log: log.WithFields("aggsender", 1),
cfg: Config{MaxRetriesStoreCertificate: 1},
signer: signer,
rateLimiter: aggkitcommon.NewRateLimit(aggkitcommon.RateLimitConfig{}),
}
mockStorage *mocks.AggSenderStorage
mockL2Syncer *mocks.L2BridgeSyncer
Expand Down Expand Up @@ -1293,7 +1295,6 @@ func TestSendCertificate(t *testing.T) {
getExitRootByIndex: []interface{}{treeTypes.Root{}, nil},
originNetwork: []interface{}{uint32(1), nil},
sendCertificate: []interface{}{common.Hash{}, errors.New("error sending certificate")},
sequencerKey: privateKey,
expectedError: "error sending certificate",
},
{
Expand Down Expand Up @@ -1322,7 +1323,6 @@ func TestSendCertificate(t *testing.T) {
originNetwork: []interface{}{uint32(1), nil},
sendCertificate: []interface{}{common.Hash{}, nil},
saveLastSentCertificate: []interface{}{errors.New("error saving last sent certificate in db")},
sequencerKey: privateKey,
expectedError: "error saving last sent certificate in db",
},
{
Expand Down Expand Up @@ -1351,7 +1351,6 @@ func TestSendCertificate(t *testing.T) {
originNetwork: []interface{}{uint32(1), nil},
sendCertificate: []interface{}{common.Hash{}, nil},
saveLastSentCertificate: []interface{}{nil},
sequencerKey: privateKey,
},
}

Expand Down Expand Up @@ -1697,14 +1696,16 @@ func TestSendCertificate_NoClaims(t *testing.T) {
mockL2Syncer := mocks.NewL2BridgeSyncer(t)
mockAggLayerClient := agglayer.NewAgglayerClientMock(t)
mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncer(t)

signer := func(_ context.Context, hash common.Hash) ([]byte, error) {
return crypto.Sign(hash.Bytes(), privateKey)
}
aggSender := &AggSender{
log: log.WithFields("aggsender-test", "no claims test"),
storage: mockStorage,
l2Syncer: mockL2Syncer,
aggLayerClient: mockAggLayerClient,
l1infoTreeSyncer: mockL1InfoTreeSyncer,
sequencerKey: privateKey,
signer: signer,
cfg: Config{},
rateLimiter: aggkitcommon.NewRateLimit(aggkitcommon.RateLimitConfig{}),
}
Expand Down Expand Up @@ -2218,7 +2219,9 @@ func newAggsenderTestData(t *testing.T, creationFlags testDataFlags) *aggsenderT
}
privKey, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
require.NoError(t, err)

signer := func(_ context.Context, hash common.Hash) ([]byte, error) {
return crypto.Sign(hash.Bytes(), privKey)
}
ctx := context.TODO()
sut := &AggSender{
log: logger,
Expand All @@ -2230,7 +2233,7 @@ func newAggsenderTestData(t *testing.T, creationFlags testDataFlags) *aggsenderT
MaxCertSize: 1024 * 1024,
},
rateLimiter: aggkitcommon.NewRateLimit(aggkitcommon.RateLimitConfig{}),
sequencerKey: privKey,
signer: signer,
epochNotifier: epochNotifierMock,
}
testCerts := []aggsendertypes.CertificateInfo{
Expand Down
5 changes: 5 additions & 0 deletions aggsender/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ type Config struct {
StoragePath string `mapstructure:"StoragePath"`
// AggLayerURL is the URL of the AggLayer
AggLayerURL string `mapstructure:"AggLayerURL"`
// KMSKeyName is the name of the KMS key used to encrypt the private key
KMSKeyName string `mapstructure:"KMSKeyName"`
// KMSConnectionTimeout is the timeout for the KMS connection
KMSConnectionTimeout types.Duration `mapstructure:"KMSConnectionTimeout"`

// AggsenderPrivateKey is the private key which is used to sign certificates
AggsenderPrivateKey types.KeystoreFileConfig `mapstructure:"AggsenderPrivateKey"`
// URLRPCL2 is the URL of the L2 RPC node
Expand Down
8 changes: 8 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ var (
FieldNamePattern: "L2Config.polygonBridgeAddr",
Reason: bridgeAddrSetOnWrongSection,
},
{
FieldNamePattern: "SequencerPrivateKeyPath",
Reason: "SequencerPrivateKeyPath is deprecated, use AggSender.AggsenderPrivateKey.Path instead, or AggSender.KMSKeyName",
},
{
FieldNamePattern: "SequencerPrivateKeyPassword",
Reason: "SequencerPrivateKeyPassword is deprecated, use AggSender.AggsenderPrivateKey.Password instead",
},
}
)

Expand Down
6 changes: 3 additions & 3 deletions config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ ContractVersions = "elderberry"
IsValidiumMode = false
L2Coinbase = "0xfa3b44587990f97ba8b6ba7e230a5f0e95d14b3d"
SequencerPrivateKeyPath = "/app/sequencer.keystore"
SequencerPrivateKeyPassword = "test"
WitnessURL = "http://localhost:8123"
# Who send Proof to L1? AggLayer addr, or aggregator addr?
Expand Down Expand Up @@ -208,7 +206,9 @@ GlobalExitRootManagerAddr = "{{L1Config.polygonZkEVMGlobalExitRootAddress}}"
[AggSender]
StoragePath = "{{PathRWData}}/aggsender.sqlite"
AggLayerURL = "{{AggLayerURL}}"
AggsenderPrivateKey = {Path = "{{SequencerPrivateKeyPath}}", Password = "{{SequencerPrivateKeyPassword}}"}
KMSKeyName = ""
KMSConnectionTimeout = "30s"
AggsenderPrivateKey = {Path = "/app/sequencer.keystore", Password = "test"}
URLRPCL2="{{L2URL}}"
BlockFinality = "LatestBlock"
EpochNotificationPercentage = 50
Expand Down
22 changes: 21 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/agglayer/aggkit
go 1.22.4

require (
cloud.google.com/go/kms v1.20.5
github.com/0xPolygon/cdk-contracts-tooling v0.0.2-0.20241225094934-1d381f5703ef
github.com/0xPolygon/cdk-rpc v0.0.0-20241004114257-6c3cb6eebfb6
github.com/0xPolygon/zkevm-ethtx-manager v0.2.4
Expand All @@ -17,6 +18,7 @@ require (
github.com/knadh/koanf/v2 v2.1.2
github.com/mattn/go-sqlite3 v1.14.24
github.com/mitchellh/mapstructure v1.5.0
github.com/pascaldekloe/etherkeyms v1.1.0
github.com/pelletier/go-toml/v2 v2.2.3
github.com/rubenv/sql-migrate v1.7.1
github.com/russross/meddler v1.0.1
Expand All @@ -35,6 +37,12 @@ require (
)

require (
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/auth v0.13.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.2.2 // indirect
cloud.google.com/go/longrunning v0.6.2 // indirect
github.com/0xPolygonHermez/zkevm-synchronizer-l1 v1.0.6 // indirect
github.com/DataDog/zstd v1.5.6 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
Expand Down Expand Up @@ -64,6 +72,7 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/getsentry/sentry-go v0.28.1 // indirect
Expand All @@ -77,7 +86,10 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/go-bexpr v0.1.10 // indirect
github.com/hashicorp/hcl v1.0.1-0.20180906183839-65a6292f0157 // indirect
Expand Down Expand Up @@ -136,12 +148,20 @@ require (
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/time v0.8.0 // indirect
google.golang.org/api v0.214.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/grpc v1.67.3 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
Loading

0 comments on commit cf64a3a

Please sign in to comment.