Skip to content

Commit 0effcb9

Browse files
committed
fix: generate new privateKey for transporter owner to avoid keyRegistrar conflicts
1 parent 222dc16 commit 0effcb9

File tree

4 files changed

+89
-24
lines changed

4 files changed

+89
-24
lines changed

config/contexts/migrations/v0.1.1-v0.1.2.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,24 @@ import (
1010

1111
func Migration_0_1_1_to_0_1_2(user, old, new *yaml.Node) (*yaml.Node, error) {
1212
// Update fork block heights to match ponos project
13-
engine := migration.PatchEngine{}
13+
engine := migration.PatchEngine{
14+
Old: old,
15+
New: new,
16+
User: user,
17+
Rules: []migration.PatchRule{
18+
// Remove transporter keys
19+
{
20+
Path: []string{"context", "transporter", "private_key"},
21+
Condition: migration.Always{},
22+
Remove: true,
23+
},
24+
{
25+
Path: []string{"context", "transporter", "bls_private_key"},
26+
Condition: migration.Always{},
27+
Remove: true,
28+
},
29+
},
30+
}
1431
if err := engine.Apply(); err != nil {
1532
return nil, err
1633
}

config/contexts/v0.1.2.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ context:
2424
# Stake Root Transporter configuration
2525
transporter:
2626
schedule: "0 */2 * * *"
27-
private_key: "0x5f8e6420b9cb0c940e3d3f8b99177980785906d16fb3571f70d7a05ecf5f2172"
28-
bls_private_key: "0x5f8e6420b9cb0c940e3d3f8b99177980785906d16fb3571f70d7a05ecf5f2172"
2927
active_stake_roots: []
3028
# All key material (BLS and ECDSA) within this file should be used for local testing ONLY
3129
# ECDSA keys used are from Anvil's private key set

pkg/commands/transporter.go

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/Layr-Labs/devkit-cli/pkg/common/iface"
1717
"github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/ICrossChainRegistry"
1818
"github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IOperatorTableUpdater"
19+
"github.com/tyler-smith/go-bip39"
1920
"github.com/urfave/cli/v2"
2021
"gopkg.in/yaml.v3"
2122

@@ -166,10 +167,8 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
166167
return fmt.Errorf("context '%s' not found in configuration", contextName)
167168
}
168169

169-
// Debug logging to check what's loaded
170-
logger.Info("Transporter config loaded - Private key present: %v, BLS key present: %v",
171-
envCtx.Transporter.PrivateKey != "",
172-
envCtx.Transporter.BlsPrivateKey != "")
170+
// Extract devnet mnemonic
171+
mnemonic := envCtx.Mnemonic
173172

174173
// Get the values from env/config
175174
crossChainRegistryAddress := ethcommon.HexToAddress(envCtx.EigenLayer.L1.CrossChainRegistry)
@@ -223,12 +222,46 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
223222
return fmt.Errorf("failed to get l1 chain for ID %d: %v", l1Config.ChainID, err)
224223
}
225224

226-
// Check if private key is empty
227-
if envCtx.Transporter.PrivateKey == "" {
228-
return fmt.Errorf("transporter private key is empty. Please check config/contexts/devnet.yaml")
225+
// Pull privateKey from random mnemonic to use as transporter owner
226+
entropy, err := bip39.NewEntropy(256)
227+
if err != nil {
228+
return fmt.Errorf("entropy generation failed: %w", err)
229+
}
230+
randomMnemonic, err := bip39.NewMnemonic(entropy)
231+
if err != nil {
232+
return fmt.Errorf("mnemonic generation failed: %w", err)
233+
}
234+
privateKey, err := devnet.GetPrivateKeyFromMnemonic(randomMnemonic, "", 0)
235+
if err != nil {
236+
return fmt.Errorf("failed to parse private key: %w", err)
237+
}
238+
239+
// Convert ecdsaPrivateKey to hex
240+
privateKeyHex := fmt.Sprintf("0x%x", privateKey.D.Bytes())
241+
publicKeyHex := crypto.PubkeyToAddress(privateKey.PublicKey)
242+
243+
// Connect to an ethClient to fund transporter owner
244+
l1EthClient, err := ethclient.Dial(l1RpcUrl)
245+
if err != nil {
246+
return fmt.Errorf("failed to connect to L1 RPC: %w", err)
247+
}
248+
l2EthClient, err := ethclient.Dial(l2RpcUrl)
249+
if err != nil {
250+
return fmt.Errorf("failed to connect to L2 RPC: %w", err)
229251
}
230252

231-
txSign, err := txSigner.NewPrivateKeySigner(envCtx.Transporter.PrivateKey)
253+
// Fund transporter owner on both L1 and L2
254+
err = devnet.FundIfNeeded(l1EthClient, publicKeyHex, mnemonic)
255+
if err != nil {
256+
return fmt.Errorf("failed to fund %s", publicKeyHex)
257+
}
258+
err = devnet.FundIfNeeded(l2EthClient, publicKeyHex, mnemonic)
259+
if err != nil {
260+
return fmt.Errorf("failed to fund %s", publicKeyHex)
261+
}
262+
263+
// Create signer for transporter owner
264+
txSign, err := txSigner.NewPrivateKeySigner(privateKeyHex)
232265
if err != nil {
233266
return fmt.Errorf("failed to create private key signer: %v", err)
234267
}
@@ -265,13 +298,8 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
265298
return fmt.Errorf("failed to calculate stake table root: %v", err)
266299
}
267300

268-
// Check if BLS private key is empty
269-
if envCtx.Transporter.BlsPrivateKey == "" {
270-
return fmt.Errorf("transporter BLS private key is empty. Please check config/contexts/devnet.yaml")
271-
}
272-
273301
scheme := bn254.NewScheme()
274-
genericPk, err := scheme.NewPrivateKeyFromHexString(envCtx.Transporter.BlsPrivateKey)
302+
genericPk, err := scheme.NewPrivateKeyFromHexString(privateKeyHex)
275303
if err != nil {
276304
return fmt.Errorf("failed to create BLS private key: %v", err)
277305
}
@@ -288,7 +316,7 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
288316
// On initial devnet Transport we take ownership of contracts and configure generator to use context keys
289317
if contextName == devnet.DEVNET_CONTEXT && initialRun {
290318
// Transfer ownership to our context configured PrivateKey
291-
transferOwnership(logger, l1Config.RPCURL, crossChainRegistryAddress, envCtx.Transporter.PrivateKey)
319+
transferOwnership(logger, l1Config.RPCURL, crossChainRegistryAddress, privateKeyHex)
292320

293321
// Construct registry caller
294322
ccRegistryCaller, err := ICrossChainRegistry.NewICrossChainRegistryCaller(crossChainRegistryAddress, l1Client.RPCClient)
@@ -320,7 +348,7 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
320348
if chainId.Uint64() == uint64(l2ChainId) {
321349
rpcURL = l2Config.RPCURL
322350
}
323-
transferOwnership(logger, rpcURL, tableUpdaterAddr, envCtx.Transporter.PrivateKey)
351+
transferOwnership(logger, rpcURL, tableUpdaterAddr, privateKeyHex)
324352

325353
// Read the current generator (avs,id) from OperatorTableUpdater
326354
gen, err := getGenerator(cCtx.Context, logger, cm, chainId, tableUpdaterAddr)
@@ -343,7 +371,7 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
343371

344372
// Construct contractCaller with KeyRegistrar
345373
contractCaller, err := common.NewContractCaller(
346-
envCtx.Transporter.PrivateKey,
374+
privateKeyHex,
347375
big.NewInt(int64(l1ChainId)),
348376
client,
349377
ethcommon.HexToAddress(""),
@@ -360,7 +388,7 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
360388
}
361389

362390
// Derive BN254 keys from the hex string (no keystore files needed)
363-
blsHex := strings.TrimPrefix(envCtx.Transporter.BlsPrivateKey, "0x")
391+
blsHex := strings.TrimPrefix(privateKeyHex, "0x")
364392

365393
// Extract key details
366394
scheme := bn254.NewScheme()
@@ -394,7 +422,7 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
394422
}
395423

396424
// EOA/operator address you want to register for this OperatorSet
397-
opEOA := mustKey(logger, envCtx.Transporter.PrivateKey)
425+
opEOA := mustKey(logger, privateKeyHex)
398426
operatorAddress := crypto.PubkeyToAddress(opEOA.PublicKey)
399427

400428
// Build the message hash per registrar rules and sign with BLS private key
@@ -444,7 +472,7 @@ func Transport(cCtx *cli.Context, initialRun bool) error {
444472
certificateVerifierAddr := readBN254CertificateVerifier(cCtx.Context, logger, rpcURL, tableUpdaterAddr)
445473

446474
// Update generator using the transporter BLS key
447-
if err := updateGeneratorFromContext(cCtx.Context, logger, cm, chainId, tableUpdaterAddr, certificateVerifierAddr, txSign, envCtx.Transporter.BlsPrivateKey, gen); err != nil {
475+
if err := updateGeneratorFromContext(cCtx.Context, logger, cm, chainId, tableUpdaterAddr, certificateVerifierAddr, txSign, privateKeyHex, gen); err != nil {
448476
return fmt.Errorf("updateGenerator chain %d at %s: %w", chainId.Uint64(), tableUpdaterAddr.Hex(), err)
449477
}
450478
}

test/integration/migration/avs_context_0_1_1_to_0_1_2_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"gopkg.in/yaml.v3"
99
)
1010

11-
// assumes testNode(t, yamlStr) helper exists in this package like in your other test
1211
func TestMigration_0_1_1_to_0_1_2(t *testing.T) {
1312
oldYAML := `
1413
version: 0.1.1
@@ -29,6 +28,11 @@ context:
2928
block: 31408197
3029
url: ""
3130
block_time: 3
31+
transporter:
32+
schedule: "0 */2 * * *"
33+
private_key: "0x5f8e6420b9cb0c940e3d3f8b99177980785906d16fb3571f70d7a05ecf5f2172"
34+
bls_private_key: "0x5f8e6420b9cb0c940e3d3f8b99177980785906d16fb3571f70d7a05ecf5f2172"
35+
active_stake_roots: []
3236
`
3337

3438
userNode := testNode(t, oldYAML)
@@ -115,6 +119,24 @@ context:
115119
}
116120
})
117121

122+
t.Run("transporter keys removed", func(t *testing.T) {
123+
priv := migration.ResolveNode(migrated, []string{"context", "transporter", "private_key"})
124+
if priv != nil {
125+
t.Errorf("expected context.transporter.private_key to be removed, got %v", priv)
126+
}
127+
bls := migration.ResolveNode(migrated, []string{"context", "transporter", "bls_private_key"})
128+
if bls != nil {
129+
t.Errorf("expected context.transporter.bls_private_key to be removed, got %v", bls)
130+
}
131+
})
132+
133+
t.Run("transporter other fields preserved", func(t *testing.T) {
134+
scheduleNode := migration.ResolveNode(migrated, []string{"context", "transporter", "schedule"})
135+
if scheduleNode == nil || scheduleNode.Value != "0 */2 * * *" {
136+
t.Errorf("expected context.transporter.schedule preserved, got %v", scheduleNode)
137+
}
138+
})
139+
118140
t.Run("other fields preserved", func(t *testing.T) {
119141
nameNode := migration.ResolveNode(migrated, []string{"context", "name"})
120142
if nameNode == nil || nameNode.Value != "devnet" {

0 commit comments

Comments
 (0)