Commit 6fa5e378 authored by Yann Hodique's avatar Yann Hodique Committed by GitHub

feat(kurtosis-devnet): output L1 addresses (#13601)

Dump a few potentially interesting addresses as part of the L1 manifest.
In particular, superchain addresses.

Implementation addresses are provided as well, as they might come in
handy for debugging purposes.

Output now looks like:
...
  "l1": {
    "name": "Ethereum",
    "nodes": [
      {
        "cl": "http://127.0.0.1:50973",
        "el": "http://127.0.0.1:50965"
      }
    ],
    "addresses": {
      "delayedWETHImpl": "0x6cc791cd89220c47952885782156e5e8f2833063",
      "disputeGameFactoryImpl": "0x256fa44786f5b9aa47f13639b97a52cbbb8d3b6e",
      "l1CrossDomainMessengerImpl": "0xe70dae11d895c2e508e7d1c0c91dd0f3e4e971c3",
      "l1ERC721BridgeImpl": "0x5a0242103310c7992773430e790c142b7e94ef3a",
      "l1StandardBridgeImpl": "0x8eb57e8ca6e1e3216b4293cc37d621a43c17ec40",
      "mipsSingleton": "0xb5322da185af39b53f8d3cbf40636eb3f1b527f2",
      "opcm": "0xf0f6e276962a776112511c4ea74ad12b4e44cd6b",
      "optimismMintableERC20FactoryImpl": "0x5f554a3eabcc8e2055040d563ef4910e8bacff8d",
      "optimismPortalImpl": "0x9d1da1fef40e2b5f44ed193bd88f1d3ee4a31cc5",
      "preimageOracleSingleton": "0x31502454e4b07ab6f35216fd734aafd816a06110",
      "protocolVersionsImpl": "0xba337ce3e690fdd01b1a830404e8caaae22a0638",
      "protocolVersionsProxy": "0xf2749e312b43529cb35a91e355919a376bd22ce3",
      "proxyAdmin": "0xed3b4bf7e17e47dac37d7bb913196e192dcaf748",
      "superchainConfigImpl": "0xcf99c17529cc22c39551547e323ed9dda6841734",
      "superchainConfigProxy": "0x329cf899464ba580bf047f4b886db342c602f579",
      "systemConfigImpl": "0x5d58414e85fc12d343eb3445dd7417c483d939a9"
    }
  },
...
parent c7a6819a
......@@ -171,11 +171,15 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En
// Find L1 endpoint
finder := NewServiceFinder(inspectResult.UserServices)
if nodes, endpoints := finder.FindL1Endpoints(); len(nodes) > 0 {
env.L1 = &Chain{
chain := &Chain{
Name: "Ethereum",
Services: endpoints,
Nodes: nodes,
}
if deployerState.State != nil {
chain.Addresses = deployerState.State.Addresses
}
env.L1 = chain
}
// Find L2 endpoints
......@@ -190,8 +194,10 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En
}
// Add contract addresses if available
if addresses, ok := deployerState.State[chainSpec.NetworkID]; ok {
chain.Addresses = addresses
if deployerState.State != nil && deployerState.State.Deployments != nil {
if addresses, ok := deployerState.State.Deployments[chainSpec.NetworkID]; ok {
chain.Addresses = addresses
}
}
env.L2 = append(env.L2, chain)
......
......@@ -25,24 +25,31 @@ type DeploymentAddresses map[string]string
// DeploymentStateAddresses maps chain IDs to their contract addresses
type DeploymentStateAddresses map[string]DeploymentAddresses
type DeployerState struct {
Deployments DeploymentStateAddresses `json:"l2s"`
Addresses DeploymentAddresses `json:"superchain"`
}
// StateFile represents the structure of the state.json file
type StateFile struct {
OpChainDeployments []map[string]interface{} `json:"opChainDeployments"`
OpChainDeployments []map[string]interface{} `json:"opChainDeployments"`
SuperChainDeployment map[string]interface{} `json:"superchainDeployment"`
ImplementationsDeployment map[string]interface{} `json:"implementationsDeployment"`
}
// Wallet represents a wallet with optional private key and name
type Wallet struct {
Address string
PrivateKey string
Name string
Address string `json:"address"`
PrivateKey string `json:"private_key"`
Name string `json:"name"`
}
// WalletList holds a list of wallets
type WalletList []*Wallet
type DeployerData struct {
Wallets WalletList
State DeploymentStateAddresses
Wallets WalletList `json:"wallets"`
State *DeployerState `json:"state"`
}
type Deployer struct {
......@@ -176,13 +183,27 @@ func hexToDecimal(hex string) (string, error) {
}
// parseStateFile parses the state.json file and extracts addresses
func parseStateFile(r io.Reader) (DeploymentStateAddresses, error) {
func parseStateFile(r io.Reader) (*DeployerState, error) {
var state StateFile
if err := json.NewDecoder(r).Decode(&state); err != nil {
return nil, fmt.Errorf("failed to decode state file: %w", err)
}
result := make(DeploymentStateAddresses)
result := &DeployerState{
Deployments: make(DeploymentStateAddresses),
Addresses: make(DeploymentAddresses),
}
mapDeployment := func(deployment map[string]interface{}) DeploymentAddresses {
addrSuffix := "Address"
addresses := make(DeploymentAddresses)
for key, value := range deployment {
if strings.HasSuffix(key, addrSuffix) {
addresses[strings.TrimSuffix(key, addrSuffix)] = value.(string)
}
}
return addresses
}
for _, deployment := range state.OpChainDeployments {
// Get the chain ID
......@@ -201,21 +222,19 @@ func parseStateFile(r io.Reader) (DeploymentStateAddresses, error) {
continue
}
addresses := make(DeploymentAddresses)
// Look for address fields in the deployment map
for key, value := range deployment {
if strings.HasSuffix(key, "Address") {
key = strings.TrimSuffix(key, "Address")
addresses[key] = value.(string)
}
}
addresses := mapDeployment(deployment)
if len(addresses) > 0 {
result[id] = addresses
result.Deployments[id] = addresses
}
}
result.Addresses = mapDeployment(state.ImplementationsDeployment)
// merge the superchain and implementations addresses
for key, value := range mapDeployment(state.SuperChainDeployment) {
result.Addresses[key] = value
}
return result, nil
}
......
......@@ -25,12 +25,21 @@ func TestParseStateFile(t *testing.T) {
"someOtherField": 123,
"L2OutputOracleAddress": "0xghi"
}
]
],
"superchainDeployment": {
"SuperchainConfigAddress": "0x111",
"ProtocolVersionsAddress": "0x222"
},
"implementationsDeployment": {
"L1CrossDomainMessengerProxyAddress": "0x333",
"L1StandardBridgeProxyAddress": "0x444"
}
}`
result, err := parseStateFile(strings.NewReader(stateJSON))
require.NoError(t, err, "Failed to parse state file")
// Test chain deployments
tests := []struct {
chainID string
expected DeploymentAddresses
......@@ -54,7 +63,7 @@ func TestParseStateFile(t *testing.T) {
}
for _, tt := range tests {
chain, ok := result[tt.chainID]
chain, ok := result.Deployments[tt.chainID]
require.True(t, ok, "Chain %s not found in result", tt.chainID)
for key, expected := range tt.expected {
......@@ -62,6 +71,20 @@ func TestParseStateFile(t *testing.T) {
require.Equal(t, expected, actual, "Chain %s, %s: expected %s, got %s", tt.chainID, key, expected, actual)
}
}
// Test superchain and implementations addresses
expectedAddresses := DeploymentAddresses{
"SuperchainConfig": "0x111",
"ProtocolVersions": "0x222",
"L1CrossDomainMessengerProxy": "0x333",
"L1StandardBridgeProxy": "0x444",
}
for key, expected := range expectedAddresses {
actual, ok := result.Addresses[key]
require.True(t, ok, "Address %s not found in result", key)
require.Equal(t, expected, actual, "Address %s: expected %s, got %s", key, expected, actual)
}
}
func TestParseStateFileErrors(t *testing.T) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment