diff --git a/devnet-sdk/descriptors/deployment.go b/devnet-sdk/descriptors/deployment.go index 4b27e967ad9a5..5f664e6ca2e35 100644 --- a/devnet-sdk/descriptors/deployment.go +++ b/devnet-sdk/descriptors/deployment.go @@ -31,16 +31,21 @@ type Node struct { // AddressMap is a map of address names to their corresponding addresses type AddressMap map[string]types.Address -// Chain represents a chain (L1 or L2) in a devnet. type Chain struct { Name string `json:"name"` ID string `json:"id,omitempty"` Services ServiceMap `json:"services,omitempty"` Nodes []Node `json:"nodes"` - Addresses AddressMap `json:"addresses,omitempty"` Wallets WalletMap `json:"wallets,omitempty"` JWT string `json:"jwt,omitempty"` Config *params.ChainConfig `json:"config,omitempty"` + Addresses AddressMap `json:"addresses,omitempty"` +} + +type L2Chain struct { + Chain + L1Addresses AddressMap `json:"l1_addresses,omitempty"` + L1Wallets WalletMap `json:"l1_wallets,omitempty"` } // Wallet represents a wallet with an address and optional private key. @@ -54,9 +59,9 @@ type WalletMap map[string]Wallet // DevnetEnvironment exposes the relevant information to interact with a devnet. type DevnetEnvironment struct { - Name string `json:"name"` - L1 *Chain `json:"l1"` - L2 []*Chain `json:"l2"` + Name string `json:"name"` + L1 *Chain `json:"l1"` + L2 []*L2Chain `json:"l2"` Features []string `json:"features,omitempty"` } diff --git a/devnet-sdk/shell/env/devnet.go b/devnet-sdk/shell/env/devnet.go index 2e0ac6005c19d..ade54e56369d3 100644 --- a/devnet-sdk/shell/env/devnet.go +++ b/devnet-sdk/shell/env/devnet.go @@ -67,7 +67,7 @@ func (d *DevnetEnv) GetChain(chainName string) (*ChainConfig, error) { } else { for _, l2Chain := range d.Config.L2 { if l2Chain.Name == chainName { - chain = l2Chain + chain = &l2Chain.Chain break } } diff --git a/devnet-sdk/shell/env/env_test.go b/devnet-sdk/shell/env/env_test.go index 0be7890319d0a..8c651ee7b227e 100644 --- a/devnet-sdk/shell/env/env_test.go +++ b/devnet-sdk/shell/env/env_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/ethereum-optimism/optimism/devnet-sdk/descriptors" - "github.com/ethereum-optimism/optimism/devnet-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -109,25 +108,42 @@ func TestGetChain(t *testing.T) { }, }, JWT: "0x1234", + Addresses: descriptors.AddressMap{ + "deployer": common.HexToAddress("0x1234567890123456789012345678901234567890"), + }, }, - L2: []*descriptors.Chain{ + L2: []*descriptors.L2Chain{ { - Name: "op", - Nodes: []descriptors.Node{ - { - Services: descriptors.ServiceMap{ - "el": { - Endpoints: descriptors.EndpointMap{ - "rpc": { - Host: "localhost", - Port: 9545, + Chain: descriptors.Chain{ + Name: "op", + Nodes: []descriptors.Node{ + { + Services: descriptors.ServiceMap{ + "el": { + Endpoints: descriptors.EndpointMap{ + "rpc": { + Host: "localhost", + Port: 9545, + }, }, }, }, }, }, + JWT: "0x5678", + Addresses: descriptors.AddressMap{ + "deployer": common.HexToAddress("0x2345678901234567890123456789012345678901"), + }, + }, + L1Addresses: descriptors.AddressMap{ + "deployer": common.HexToAddress("0x2345678901234567890123456789012345678901"), + }, + L1Wallets: descriptors.WalletMap{ + "deployer": descriptors.Wallet{ + Address: common.HexToAddress("0x2345678901234567890123456789012345678901"), + PrivateKey: "0x2345678901234567890123456789012345678901", + }, }, - JWT: "0x5678", }, }, }, @@ -176,7 +192,7 @@ func TestChainConfig(t *testing.T) { }, }, JWT: "0x1234", - Addresses: map[string]types.Address{ + Addresses: descriptors.AddressMap{ "deployer": common.HexToAddress("0x1234567890123456789012345678901234567890"), }, }, diff --git a/devnet-sdk/shell/env/kt_native_fetch_test.go b/devnet-sdk/shell/env/kt_native_fetch_test.go index 7bc85d5415d38..f2b83a856c9f4 100644 --- a/devnet-sdk/shell/env/kt_native_fetch_test.go +++ b/devnet-sdk/shell/env/kt_native_fetch_test.go @@ -149,7 +149,7 @@ func TestFetchKurtosisNativeDataSuccess(t *testing.T) { envSpec := &spec.EnclaveSpec{} env := &kurtosis.KurtosisEnvironment{ DevnetEnvironment: descriptors.DevnetEnvironment{ - L2: make([]*descriptors.Chain, 0, 1), + L2: make([]*descriptors.L2Chain, 0, 1), Features: envSpec.Features, }, } diff --git a/devnet-sdk/system/chain.go b/devnet-sdk/system/chain.go index 30ae169a280a5..3ff64f10b65ab 100644 --- a/devnet-sdk/system/chain.go +++ b/devnet-sdk/system/chain.go @@ -29,7 +29,8 @@ type opBlock interface { var ( // This will make sure that we implement the Chain interface - _ Chain = (*chain)(nil) + _ Chain = (*chain)(nil) + _ L2Chain = (*l2Chain)(nil) // Make sure we're using op-geth in place of go-ethereum. // If you're wondering why this fails at compile time, @@ -119,13 +120,13 @@ func (m *clientManager) GethClient(rpcURL string) (*ethclient.Client, error) { type chain struct { id string rpcUrl string - users map[string]Wallet + wallets WalletMap clients *clientManager registry interfaces.ContractsRegistry mu sync.Mutex node Node chainConfig *params.ChainConfig - addresses descriptors.AddressMap + addresses AddressMap } func (c *chain) Node() Node { @@ -140,20 +141,6 @@ func (c *chain) GethClient() (*ethclient.Client, error) { return c.clients.GethClient(c.rpcUrl) } -func newChain(chainID string, rpcUrl string, users map[string]Wallet, chainConfig *params.ChainConfig, addresses descriptors.AddressMap) *chain { - clients := newClientManager() - chain := &chain{ - id: chainID, - rpcUrl: rpcUrl, - users: users, - clients: clients, - node: newNode(rpcUrl, clients), - chainConfig: chainConfig, - addresses: addresses, - } - return chain -} - func (c *chain) ContractsRegistry() interfaces.ContractsRegistry { c.mu.Lock() defer c.mu.Unlock() @@ -178,14 +165,8 @@ func (c *chain) RPCURL() string { // error. // Typically this will be one of the pre-funded wallets associated with // the deployed system. -func (c *chain) Wallets(ctx context.Context) ([]Wallet, error) { - wallets := []Wallet{} - - for _, user := range c.users { - wallets = append(wallets, user) - } - - return wallets, nil +func (c *chain) Wallets() WalletMap { + return c.wallets } func (c *chain) ID() types.ChainID { @@ -233,18 +214,48 @@ func (c *chain) Config() (*params.ChainConfig, error) { return c.chainConfig, nil } -func (c *chain) Addresses() descriptors.AddressMap { +func newChainFromDescriptor(d *descriptors.Chain) (Chain, error) { + // TODO: handle incorrect descriptors better. We could panic here. + firstNodeRPC := d.Nodes[0].Services["el"].Endpoints["rpc"] + rpcURL := fmt.Sprintf("http://%s:%d", firstNodeRPC.Host, firstNodeRPC.Port) + + c := newChain(d.ID, rpcURL, nil, d.Config, AddressMap(d.Addresses)) // Create chain first + + wallets, err := newWalletMapFromDescriptorWalletMap(d.Wallets, c) + if err != nil { + return nil, err + } + c.wallets = wallets + + return c, nil +} + +func newChain(chainID string, rpcUrl string, wallets WalletMap, chainConfig *params.ChainConfig, addresses AddressMap) *chain { + clients := newClientManager() + chain := &chain{ + id: chainID, + rpcUrl: rpcUrl, + wallets: wallets, + clients: clients, + node: newNode(rpcUrl, clients), + chainConfig: chainConfig, + addresses: addresses, + } + return chain +} + +func (c *chain) Addresses() AddressMap { return c.addresses } -func chainFromDescriptor(d *descriptors.Chain) (Chain, error) { +func newL2ChainFromDescriptor(d *descriptors.L2Chain) (L2Chain, error) { // TODO: handle incorrect descriptors better. We could panic here. firstNodeRPC := d.Nodes[0].Services["el"].Endpoints["rpc"] rpcURL := fmt.Sprintf("http://%s:%d", firstNodeRPC.Host, firstNodeRPC.Port) - c := newChain(d.ID, rpcURL, nil, d.Config, d.Addresses) // Create chain first + c := newL2Chain(d.ID, rpcURL, nil, nil, d.Config, AddressMap(d.L1Addresses), AddressMap(d.Addresses)) // Create chain first - users := make(map[string]Wallet) + wallets := make(WalletMap) for key, w := range d.Wallets { // TODO: The assumption that the wallet will necessarily be used on chain `d` may // be problematic if the L2 admin wallets are to be used to sign L1 transactions. @@ -253,9 +264,32 @@ func chainFromDescriptor(d *descriptors.Chain) (Chain, error) { if err != nil { return nil, fmt.Errorf("failed to create wallet: %w", err) } - users[key] = k + wallets[key] = k } - c.users = users // Set users after creation + c.wallets = wallets // Set wallets after creation return c, nil } + +func newL2Chain(chainID string, rpcUrl string, l1Wallets WalletMap, l2Wallets WalletMap, chainConfig *params.ChainConfig, l1Addresses AddressMap, l2Addresses AddressMap) *l2Chain { + chain := &l2Chain{ + chain: newChain(chainID, rpcUrl, l2Wallets, chainConfig, l2Addresses), + l1Addresses: l1Addresses, + l1Wallets: l1Wallets, + } + return chain +} + +type l2Chain struct { + *chain + l1Addresses AddressMap + l1Wallets WalletMap +} + +func (c *l2Chain) L1Addresses() AddressMap { + return c.l1Addresses +} + +func (c *l2Chain) L1Wallets() WalletMap { + return c.l1Wallets +} diff --git a/devnet-sdk/system/chain_test.go b/devnet-sdk/system/chain_test.go index 775b331ba1a10..3500e507b8c7d 100644 --- a/devnet-sdk/system/chain_test.go +++ b/devnet-sdk/system/chain_test.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestClientManager(t *testing.T) { @@ -68,9 +67,64 @@ func TestChainFromDescriptor(t *testing.T) { Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), }, }, + Addresses: descriptors.AddressMap{ + "user1": common.HexToAddress("0x1234567890123456789012345678901234567890"), + }, } - chain, err := chainFromDescriptor(descriptor) + chain, err := newChainFromDescriptor(descriptor) + assert.Nil(t, err) + assert.NotNil(t, chain) + lowLevelChain, ok := chain.(LowLevelChain) + assert.True(t, ok) + assert.Equal(t, "http://localhost:8545", lowLevelChain.RPCURL()) + + // Compare the underlying big.Int values + chainID := chain.ID() + expectedID := big.NewInt(1) + assert.Equal(t, 0, expectedID.Cmp(chainID)) +} + +func TestL2ChainFromDescriptor(t *testing.T) { + descriptor := &descriptors.L2Chain{ + Chain: descriptors.Chain{ + ID: "1", + Nodes: []descriptors.Node{ + { + Services: descriptors.ServiceMap{ + "el": descriptors.Service{ + Endpoints: descriptors.EndpointMap{ + "rpc": descriptors.PortInfo{ + Host: "localhost", + Port: 8545, + }, + }, + }, + }, + }, + }, + Wallets: descriptors.WalletMap{ + "user1": descriptors.Wallet{ + PrivateKey: "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), + }, + }, + Addresses: descriptors.AddressMap{ + "user2": common.HexToAddress("0x1234567890123456789012345678901234567891"), + }, + }, + L1Addresses: descriptors.AddressMap{ + "user1": common.HexToAddress("0x1234567890123456789012345678901234567890"), + }, + L1Wallets: descriptors.WalletMap{ + "user1": descriptors.Wallet{ + PrivateKey: "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), + }, + }, + } + + chain, err := newL2ChainFromDescriptor(descriptor) assert.Nil(t, err) assert.NotNil(t, chain) lowLevelChain, ok := chain.(LowLevelChain) @@ -84,19 +138,17 @@ func TestChainFromDescriptor(t *testing.T) { } func TestChainWallet(t *testing.T) { - ctx := context.Background() testAddr := common.HexToAddress("0x1234567890123456789012345678901234567890") wallet, err := newWallet("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", testAddr, nil) assert.Nil(t, err) - chain := newChain("1", "http://localhost:8545", map[string]Wallet{ + l1Chain := newChain("1", "http://localhost:8545", WalletMap{ "user1": wallet}, nil, map[string]common.Address{}) t.Run("finds wallet meeting constraints", func(t *testing.T) { constraint := &addressConstraint{addr: testAddr} - wallets, err := chain.Wallets(ctx) - require.NoError(t, err) + wallets := l1Chain.Wallets() for _, w := range wallets { if constraint.CheckWallet(w) { @@ -111,8 +163,7 @@ func TestChainWallet(t *testing.T) { t.Run("returns error when no wallet meets constraints", func(t *testing.T) { wrongAddr := common.HexToAddress("0x0987654321098765432109876543210987654321") constraint := &addressConstraint{addr: wrongAddr} - wallets, err := chain.Wallets(ctx) - require.NoError(t, err) + wallets := l1Chain.Wallets() for _, w := range wallets { if constraint.CheckWallet(w) { diff --git a/devnet-sdk/system/interfaces.go b/devnet-sdk/system/interfaces.go index 61a6d12234985..febe5c8440c94 100644 --- a/devnet-sdk/system/interfaces.go +++ b/devnet-sdk/system/interfaces.go @@ -18,39 +18,37 @@ import ( "github.com/ethereum/go-ethereum/params" ) -type genSystem[T Chain] interface { +type genSystem[T Chain, U L2Chain] interface { Identifier() string L1() T - L2s() []T + L2s() []U } // System represents a complete Optimism system with L1 and L2 chains -type System = genSystem[Chain] +type System = genSystem[Chain, L2Chain] -type LowLevelSystem = genSystem[LowLevelChain] +type LowLevelSystem = genSystem[LowLevelChain, LowLevelL2Chain] // Chain represents an Ethereum chain (L1 or L2) type Chain interface { ID() types.ChainID - // If an instance of an implementation this interface represents an L1 chain, - // then then the wallets returned should be either validator wallets or test wallets, - // both useful in the context of sending transactions on the L1. - // - // If an instance of an implementation of this interface represents an L2 chain, - // then the wallets returned should be a combination of: - // 1. L2 admin wallets: wallets with admin priviledges for administrating an - // L2's bridge contracts, etc on L1. Despite inclusion on the L2 wallet list, these wallets - // are not useful for sending transactions on the L2 and do not control any L2 balance. - // 2. L2 test wallets: wallets controlling balance on the L2 for purposes of - // testing. The balance on these wallets will originate unbacked L2 ETH from - // the L2 genesis definition which cannot be withdrawn without maybe "stealing" - // the backing from other deposits. - Wallets(ctx context.Context) ([]Wallet, error) ContractsRegistry() interfaces.ContractsRegistry SupportsEIP(ctx context.Context, eip uint64) bool Node() Node Config() (*params.ChainConfig, error) - Addresses() descriptors.AddressMap + + // The wallets and addresses below are for use on the chain that the instance represents. + // If the instance also implements L2Chain, then the wallets and addresses below are still for the L2. + Wallets() WalletMap + Addresses() AddressMap +} + +type L2Chain interface { + Chain + + // The wallets and addresses below are for use on the L1 chain that this L2Chain instance settles to. + L1Addresses() AddressMap + L1Wallets() WalletMap } type Node interface { @@ -60,7 +58,6 @@ type Node interface { BlockByNumber(ctx context.Context, number *big.Int) (eth.BlockInfo, error) } -// LowLevelChain is a Chain that gives direct access to the low level RPC client. type LowLevelChain interface { Chain RPCURL() string @@ -68,6 +65,14 @@ type LowLevelChain interface { GethClient() (*ethclient.Client, error) } +type LowLevelL2Chain interface { + L2Chain + LowLevelChain +} + +type WalletMap map[string]Wallet +type AddressMap descriptors.AddressMap + // Wallet represents a chain wallet. // In particular it can process transactions. type Wallet interface { @@ -130,7 +135,7 @@ type InteropSystem interface { // InteropSet provides access to L2 chains in an interop environment type InteropSet interface { - L2s() []Chain + L2s() []L2Chain } // Supervisor provides access to the query interface of the supervisor diff --git a/devnet-sdk/system/system.go b/devnet-sdk/system/system.go index 90e94209f931d..a831a58d3f3f0 100644 --- a/devnet-sdk/system/system.go +++ b/devnet-sdk/system/system.go @@ -15,7 +15,7 @@ import ( type system struct { identifier string l1 Chain - l2s []Chain + l2s []L2Chain } // system implements System @@ -38,7 +38,7 @@ func (s *system) L1() Chain { return s.l1 } -func (s *system) L2s() []Chain { +func (s *system) L2s() []L2Chain { return s.l2s } @@ -46,30 +46,24 @@ func (s *system) Identifier() string { return s.identifier } -func (s *system) addChains(chains ...*descriptors.Chain) error { - for _, chainDesc := range chains { - if chainDesc.Name == "Ethereum" { - l1, err := chainFromDescriptor(chainDesc) - if err != nil { - return fmt.Errorf("failed to add L1 chain: %w", err) - } - s.l1 = l1 - } else { - l2, err := chainFromDescriptor(chainDesc) - if err != nil { - return fmt.Errorf("failed to add L2 chain: %w", err) - } - s.l2s = append(s.l2s, l2) - } +func systemFromDevnet(dn descriptors.DevnetEnvironment, identifier string) (System, error) { + l1, err := newChainFromDescriptor(dn.L1) + if err != nil { + return nil, fmt.Errorf("failed to add L1 chain: %w", err) } - return nil -} -func systemFromDevnet(dn descriptors.DevnetEnvironment, identifier string) (System, error) { - sys := &system{identifier: identifier} + l2s := make([]L2Chain, len(dn.L2)) + for i, l2 := range dn.L2 { + l2s[i], err = newL2ChainFromDescriptor(l2) + if err != nil { + return nil, fmt.Errorf("failed to add L2 chain: %w", err) + } + } - if err := sys.addChains(append(dn.L2, dn.L1)...); err != nil { - return nil, err + sys := &system{ + identifier: identifier, + l1: l1, + l2s: l2s, } if slices.Contains(dn.Features, "interop") { @@ -81,6 +75,7 @@ func systemFromDevnet(dn descriptors.DevnetEnvironment, identifier string) (Syst supervisorRPC: fmt.Sprintf("http://%s:%d", supervisorRPC.Host, supervisorRPC.Port), }, nil } + return sys, nil } diff --git a/devnet-sdk/system/system_test.go b/devnet-sdk/system/system_test.go index 29fe3931b5582..ea95a43534b5a 100644 --- a/devnet-sdk/system/system_test.go +++ b/devnet-sdk/system/system_test.go @@ -1,7 +1,6 @@ package system import ( - "context" "encoding/json" "os" "path/filepath" @@ -41,29 +40,48 @@ func TestNewSystemFromEnv(t *testing.T) { PrivateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", }, }, + Addresses: descriptors.AddressMap{ + "defaultl1": common.HexToAddress("0x123"), + }, }, - L2: []*descriptors.Chain{{ - ID: "2", - Nodes: []descriptors.Node{{ - Services: map[string]descriptors.Service{ - "el": { - Name: "geth", - Endpoints: descriptors.EndpointMap{ - "rpc": descriptors.PortInfo{ - Host: "localhost", - Port: 8546, + L2: []*descriptors.L2Chain{ + { + Chain: descriptors.Chain{ + ID: "2", + Nodes: []descriptors.Node{{ + Services: map[string]descriptors.Service{ + "el": { + Name: "geth", + Endpoints: descriptors.EndpointMap{ + "rpc": descriptors.PortInfo{ + Host: "localhost", + Port: 8546, + }, + }, }, }, + }}, + Wallets: descriptors.WalletMap{ + "default": descriptors.Wallet{ + Address: common.HexToAddress("0x123"), + PrivateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + }, + }, + Addresses: descriptors.AddressMap{ + "defaultl2": common.HexToAddress("0x456"), }, }, - }}, - Wallets: descriptors.WalletMap{ - "default": descriptors.Wallet{ - Address: common.HexToAddress("0x123"), - PrivateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + L1Addresses: descriptors.AddressMap{ + "defaultl1": common.HexToAddress("0x123"), + }, + L1Wallets: descriptors.WalletMap{ + "default": descriptors.Wallet{ + Address: common.HexToAddress("0x123"), + PrivateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + }, }, }, - }}, + }, Features: []string{}, } @@ -111,14 +129,27 @@ func TestSystemFromDevnet(t *testing.T) { Wallets: descriptors.WalletMap{ "default": testWallet, }, + Addresses: descriptors.AddressMap{ + "defaultl1": common.HexToAddress("0x123"), + }, }, - L2: []*descriptors.Chain{{ - ID: "2", - Nodes: []descriptors.Node{testNode}, - Wallets: descriptors.WalletMap{ - "default": testWallet, + L2: []*descriptors.L2Chain{ + { + Chain: descriptors.Chain{ + ID: "2", + Nodes: []descriptors.Node{testNode}, + Wallets: descriptors.WalletMap{ + "default": testWallet, + }, + }, + L1Addresses: descriptors.AddressMap{ + "defaultl1": common.HexToAddress("0x123"), + }, + L1Wallets: descriptors.WalletMap{ + "default": testWallet, + }, }, - }}, + }, }, wantErr: false, isInterop: false, @@ -132,14 +163,26 @@ func TestSystemFromDevnet(t *testing.T) { Wallets: descriptors.WalletMap{ "default": testWallet, }, - }, - L2: []*descriptors.Chain{{ - ID: "2", - Nodes: []descriptors.Node{testNode}, - Wallets: descriptors.WalletMap{ - "default": testWallet, + Addresses: descriptors.AddressMap{ + "defaultl1": common.HexToAddress("0x123"), }, - }}, + }, + L2: []*descriptors.L2Chain{ + { + Chain: descriptors.Chain{ + ID: "2", + Nodes: []descriptors.Node{testNode}, + Wallets: descriptors.WalletMap{ + "default": testWallet, + }, + }, + L1Addresses: descriptors.AddressMap{ + "defaultl1": common.HexToAddress("0x123"), + }, + L1Wallets: descriptors.WalletMap{ + "default": testWallet, + }, + }}, Features: []string{"interop"}, }, wantErr: false, @@ -209,12 +252,11 @@ func TestChainUser(t *testing.T) { testWallet, err := newWallet("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", common.HexToAddress("0x123"), chain) assert.Nil(t, err) - chain.users = map[string]Wallet{ + chain.wallets = WalletMap{ "l2Faucet": testWallet, } - ctx := context.Background() - wallets, err := chain.Wallets(ctx) + wallets := chain.Wallets() require.NoError(t, err) for _, w := range wallets { diff --git a/devnet-sdk/system/txbuilder_test.go b/devnet-sdk/system/txbuilder_test.go index cd21e32f17b96..62064b4ee0629 100644 --- a/devnet-sdk/system/txbuilder_test.go +++ b/devnet-sdk/system/txbuilder_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/bindings" - "github.com/ethereum-optimism/optimism/devnet-sdk/descriptors" "github.com/ethereum-optimism/optimism/devnet-sdk/interfaces" "github.com/ethereum-optimism/optimism/devnet-sdk/types" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -121,17 +120,17 @@ func (m *mockChain) Client() (*sources.EthClient, error) { return args.Get(0).(*sources.EthClient), nil } -func (m *mockChain) Wallets(ctx context.Context) ([]Wallet, error) { - return nil, nil +func (m *mockChain) Wallets() WalletMap { + return nil } func (m *mockChain) Config() (*params.ChainConfig, error) { return nil, fmt.Errorf("not implemented for mock chain") } -func (m *mockChain) Addresses() descriptors.AddressMap { +func (m *mockChain) Addresses() AddressMap { args := m.Called() - return args.Get(0).(descriptors.AddressMap) + return args.Get(0).(AddressMap) } type mockNode struct { diff --git a/devnet-sdk/system/wallet.go b/devnet-sdk/system/wallet.go index 1a70faa6186c8..b34a5eb10ee43 100644 --- a/devnet-sdk/system/wallet.go +++ b/devnet-sdk/system/wallet.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/bindings" "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/constants" + "github.com/ethereum-optimism/optimism/devnet-sdk/descriptors" "github.com/ethereum-optimism/optimism/devnet-sdk/types" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-service/sources" @@ -38,7 +39,19 @@ type wallet struct { chain internalChain } -func newWallet(pk string, addr types.Address, chain *chain) (*wallet, error) { +func newWalletMapFromDescriptorWalletMap(descriptorWalletMap descriptors.WalletMap, chain internalChain) (WalletMap, error) { + result := WalletMap{} + for k, v := range descriptorWalletMap { + wallet, err := newWallet(v.PrivateKey, v.Address, chain) + if err != nil { + return nil, err + } + result[k] = wallet + } + return result, nil +} + +func newWallet(pk string, addr types.Address, chain internalChain) (*wallet, error) { privateKey, err := privateKeyFromString(pk) if err != nil { return nil, fmt.Errorf("failed to convert private from string: %w", err) diff --git a/devnet-sdk/testing/systest/testing_test.go b/devnet-sdk/testing/systest/testing_test.go index 86e8418a15366..ecd4804ee9ea9 100644 --- a/devnet-sdk/testing/systest/testing_test.go +++ b/devnet-sdk/testing/systest/testing_test.go @@ -7,7 +7,6 @@ import ( "os" "testing" - "github.com/ethereum-optimism/optimism/devnet-sdk/descriptors" "github.com/ethereum-optimism/optimism/devnet-sdk/interfaces" "github.com/ethereum-optimism/optimism/devnet-sdk/shell/env" "github.com/ethereum-optimism/optimism/devnet-sdk/system" @@ -23,7 +22,8 @@ import ( ) var ( - _ system.Chain = (*mockChain)(nil) + _ system.Chain = (*mockChain)(nil) + _ system.L2Chain = (*mockL2Chain)(nil) ) // mockTB implements a minimal testing.TB for testing @@ -90,8 +90,8 @@ func (m *mockChain) Client() (*sources.EthClient, error) { return ni func (m *mockChain) GethClient() (*ethclient.Client, error) { return nil, nil } func (m *mockChain) ID() types.ChainID { return types.ChainID(big.NewInt(1)) } func (m *mockChain) ContractsRegistry() interfaces.ContractsRegistry { return nil } -func (m *mockChain) Wallets(ctx context.Context) ([]system.Wallet, error) { - return nil, nil +func (m *mockChain) Wallets() system.WalletMap { + return nil } func (m *mockChain) GasPrice(ctx context.Context) (*big.Int, error) { return big.NewInt(1), nil @@ -108,22 +108,34 @@ func (m *mockChain) SupportsEIP(ctx context.Context, eip uint64) bool { func (m *mockChain) Config() (*params.ChainConfig, error) { return nil, fmt.Errorf("not implemented on mockChain") } -func (m *mockChain) Addresses() descriptors.AddressMap { - return descriptors.AddressMap{} +func (m *mockChain) Addresses() system.AddressMap { + return system.AddressMap{} +} + +// mockL2Chain implements a minimal system.L2Chain for testing +type mockL2Chain struct { + mockChain +} + +func (m *mockL2Chain) L1Addresses() system.AddressMap { + return system.AddressMap{} +} +func (m *mockL2Chain) L1Wallets() system.WalletMap { + return system.WalletMap{} } // mockSystem implements a minimal system.System for testing type mockSystem struct{} -func (m *mockSystem) Identifier() string { return "mock" } -func (m *mockSystem) L1() system.Chain { return &mockChain{} } -func (m *mockSystem) L2s() []system.Chain { return []system.Chain{&mockChain{}} } -func (m *mockSystem) Close() error { return nil } +func (m *mockSystem) Identifier() string { return "mock" } +func (m *mockSystem) L1() system.Chain { return &mockChain{} } +func (m *mockSystem) L2s() []system.L2Chain { return []system.L2Chain{&mockL2Chain{}} } +func (m *mockSystem) Close() error { return nil } // mockInteropSet implements a minimal system.InteropSet for testing type mockInteropSet struct{} -func (m *mockInteropSet) L2s() []system.Chain { return []system.Chain{&mockChain{}} } +func (m *mockInteropSet) L2s() []system.L2Chain { return []system.L2Chain{&mockL2Chain{}} } // mockSupervisor implements the system.Supervisor interface for testing type mockSupervisor struct{} diff --git a/devnet-sdk/testing/testlib/validators/lowlevel.go b/devnet-sdk/testing/testlib/validators/lowlevel.go index 29e99f0d12758..4a1bdaf88c726 100644 --- a/devnet-sdk/testing/testlib/validators/lowlevel.go +++ b/devnet-sdk/testing/testlib/validators/lowlevel.go @@ -13,7 +13,7 @@ type LowLevelSystemGetter = func(context.Context) system.LowLevelSystem type lowLevelSystemWrapper struct { identifier string l1 system.LowLevelChain - l2 []system.LowLevelChain + l2 []system.LowLevelL2Chain } var _ system.LowLevelSystem = (*lowLevelSystemWrapper)(nil) @@ -26,7 +26,7 @@ func (l *lowLevelSystemWrapper) L1() system.LowLevelChain { return l.l1 } -func (l *lowLevelSystemWrapper) L2s() []system.LowLevelChain { +func (l *lowLevelSystemWrapper) L2s() []system.LowLevelL2Chain { return l.l2 } @@ -42,7 +42,7 @@ func lowLevelSystemValidator(sysMarker interface{}) systest.PreconditionValidato } for idx, l2 := range sys.L2s() { - if l2, ok := l2.(system.LowLevelChain); ok { + if l2, ok := l2.(system.LowLevelL2Chain); ok { lowLevelSys.l2 = append(lowLevelSys.l2, l2) } else { return nil, fmt.Errorf("L2 chain %d is not a low level chain", idx) diff --git a/devnet-sdk/testing/testlib/validators/validators_test.go b/devnet-sdk/testing/testlib/validators/validators_test.go index fca524c436a72..5bcfa2a840e49 100644 --- a/devnet-sdk/testing/testlib/validators/validators_test.go +++ b/devnet-sdk/testing/testlib/validators/validators_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/bindings" - "github.com/ethereum-optimism/optimism/devnet-sdk/descriptors" "github.com/ethereum-optimism/optimism/devnet-sdk/interfaces" "github.com/ethereum-optimism/optimism/devnet-sdk/system" "github.com/ethereum-optimism/optimism/devnet-sdk/testing/systest" @@ -40,20 +39,24 @@ func TestValidators(t *testing.T) { // We create a system that has a low-level L1 chain and at least one wallet systestSystem := &mockSystem{ l1: &mockChain{}, - l2s: []system.Chain{ - &mockChain{ - wallets: []system.Wallet{ - &mockWallet{ - balance: types.NewBalance(big.NewInt(2)), + l2s: []system.L2Chain{ + &mockL2Chain{ + mockChain: mockChain{ + wallets: system.WalletMap{ + "user1": &mockWallet{ + address: types.Address(common.HexToAddress("0x1")), + balance: types.NewBalance(big.NewInt(2)), + }, + "user2": &mockWallet{ + address: types.Address(common.HexToAddress("0x2")), + balance: types.NewBalance(big.NewInt(11)), + }, }, - &mockWallet{ - balance: types.NewBalance(big.NewInt(11)), + config: ¶ms.ChainConfig{ + Optimism: ¶ms.OptimismConfig{}, + IsthmusTime: Uint64Ptr(0), }, }, - config: ¶ms.ChainConfig{ - Optimism: ¶ms.OptimismConfig{}, - IsthmusTime: Uint64Ptr(0), - }, }, }, } @@ -101,11 +104,13 @@ func TestValidators(t *testing.T) { t.Run("test AcquireL2WithFork - fork active", func(t *testing.T) { // Create a system with the Isthmus fork active systestSystem := &mockSystem{ - l2s: []system.Chain{ - &mockChain{ - config: ¶ms.ChainConfig{ - Optimism: ¶ms.OptimismConfig{}, - IsthmusTime: Uint64Ptr(50), + l2s: []system.L2Chain{ + &mockL2Chain{ + mockChain: mockChain{ + config: ¶ms.ChainConfig{ + Optimism: ¶ms.OptimismConfig{}, + IsthmusTime: Uint64Ptr(50), + }, }, }, }, @@ -130,11 +135,13 @@ func TestValidators(t *testing.T) { t.Run("test AcquireL2WithFork - fork not active", func(t *testing.T) { // Create a system where the Isthmus fork is not yet active systestSystem := &mockSystem{ - l2s: []system.Chain{ - &mockChain{ - config: ¶ms.ChainConfig{ - Optimism: ¶ms.OptimismConfig{}, - IsthmusTime: Uint64Ptr(150), + l2s: []system.L2Chain{ + &mockL2Chain{ + mockChain: mockChain{ + config: ¶ms.ChainConfig{ + Optimism: ¶ms.OptimismConfig{}, + IsthmusTime: Uint64Ptr(150), + }, }, }, }, @@ -153,11 +160,13 @@ func TestValidators(t *testing.T) { t.Run("test AcquireRequiresNotL2Fork - fork not active", func(t *testing.T) { // Create a system where the Isthmus fork is not yet active systestSystem := &mockSystem{ - l2s: []system.Chain{ - &mockChain{ - config: ¶ms.ChainConfig{ - Optimism: ¶ms.OptimismConfig{}, - IsthmusTime: Uint64Ptr(150), // Activates after current timestamp + l2s: []system.L2Chain{ + &mockL2Chain{ + mockChain: mockChain{ + config: ¶ms.ChainConfig{ + Optimism: ¶ms.OptimismConfig{}, + IsthmusTime: Uint64Ptr(150), // Activates after current timestamp + }, }, }, }, @@ -182,11 +191,13 @@ func TestValidators(t *testing.T) { t.Run("test AcquireRequiresNotL2Fork - fork active", func(t *testing.T) { // Create a system with the Isthmus fork active systestSystem := &mockSystem{ - l2s: []system.Chain{ - &mockChain{ - config: ¶ms.ChainConfig{ - Optimism: ¶ms.OptimismConfig{}, - IsthmusTime: Uint64Ptr(50), + l2s: []system.L2Chain{ + &mockL2Chain{ + mockChain: mockChain{ + config: ¶ms.ChainConfig{ + Optimism: ¶ms.OptimismConfig{}, + IsthmusTime: Uint64Ptr(50), + }, }, }, }, @@ -205,7 +216,7 @@ func TestValidators(t *testing.T) { t.Run("chain index out of range", func(t *testing.T) { // Create a system with no L2 chains systestSystem := &mockSystem{ - l2s: []system.Chain{}, + l2s: []system.L2Chain{}, } // Try to get chain config for an invalid chain index @@ -221,7 +232,7 @@ func TestValidators(t *testing.T) { type mockSystem struct { l1 system.Chain - l2s []system.Chain + l2s []system.L2Chain } func (sys *mockSystem) Identifier() string { @@ -232,12 +243,12 @@ func (sys *mockSystem) L1() system.Chain { return sys.l1 } -func (sys *mockSystem) L2s() []system.Chain { +func (sys *mockSystem) L2s() []system.L2Chain { return sys.l2s } type mockChain struct { - wallets []system.Wallet + wallets system.WalletMap config *params.ChainConfig } @@ -246,8 +257,8 @@ func (m *mockChain) Client() (*sources.EthClient, error) { return ni func (m *mockChain) GethClient() (*ethclient.Client, error) { return nil, nil } func (m *mockChain) ID() types.ChainID { return types.ChainID(big.NewInt(1)) } func (m *mockChain) ContractsRegistry() interfaces.ContractsRegistry { return nil } -func (m *mockChain) Wallets(ctx context.Context) ([]system.Wallet, error) { - return m.wallets, nil +func (m *mockChain) Wallets() system.WalletMap { + return m.wallets } func (m *mockChain) GasPrice(ctx context.Context) (*big.Int, error) { return big.NewInt(1), nil @@ -271,8 +282,20 @@ func (m *mockChain) Node() system.Node { return newMockNode(m.config) } -func (m *mockChain) Addresses() descriptors.AddressMap { - return descriptors.AddressMap{} +func (m *mockChain) Addresses() system.AddressMap { + return system.AddressMap{} +} + +type mockL2Chain struct { + mockChain + l1Wallets system.WalletMap +} + +func (m *mockL2Chain) L1Addresses() system.AddressMap { + return system.AddressMap{} +} +func (m *mockL2Chain) L1Wallets() system.WalletMap { + return m.l1Wallets } type mockNode struct { @@ -350,8 +373,10 @@ func (m mockWallet) Transactor() *bind.TransactOpts { } var ( - _ system.Chain = (*mockChain)(nil) - _ system.LowLevelChain = (*mockChain)(nil) - _ system.System = (*mockSystem)(nil) - _ system.Wallet = (*mockWallet)(nil) + _ system.Chain = (*mockChain)(nil) + _ system.LowLevelChain = (*mockChain)(nil) + _ system.L2Chain = (*mockL2Chain)(nil) + _ system.LowLevelL2Chain = (*mockL2Chain)(nil) + _ system.System = (*mockSystem)(nil) + _ system.Wallet = (*mockWallet)(nil) ) diff --git a/devnet-sdk/testing/testlib/validators/wallet.go b/devnet-sdk/testing/testlib/validators/wallet.go index b8065831126ba..ff1be570fd528 100644 --- a/devnet-sdk/testing/testlib/validators/wallet.go +++ b/devnet-sdk/testing/testlib/validators/wallet.go @@ -15,10 +15,7 @@ type WalletGetter = func(context.Context) system.Wallet func walletFundsValidator(chain system.Chain, minFunds types.Balance, userMarker interface{}) systest.PreconditionValidator { constraint := constraints.WithBalance(minFunds) return func(t systest.T, sys system.System) (context.Context, error) { - wallets, err := chain.Wallets(t.Context()) - if err != nil { - return nil, err - } + wallets := chain.Wallets() for _, wallet := range wallets { if constraint.CheckWallet(wallet) { diff --git a/kurtosis-devnet/pkg/kurtosis/kurtosis.go b/kurtosis-devnet/pkg/kurtosis/kurtosis.go index a47a08e8f7779..dcbf7b1167378 100644 --- a/kurtosis-devnet/pkg/kurtosis/kurtosis.go +++ b/kurtosis-devnet/pkg/kurtosis/kurtosis.go @@ -151,7 +151,7 @@ func (d *KurtosisDeployer) GetEnvironmentInfo(ctx context.Context, spec *spec.En } // Get contract addresses - deployerState, err := d.enclaveObserver.EnclaveObserve(ctx, d.enclave) + deployerData, err := d.enclaveObserver.EnclaveObserve(ctx, d.enclave) if err != nil { return nil, fmt.Errorf("failed to parse deployer state: %w", err) } @@ -164,7 +164,7 @@ func (d *KurtosisDeployer) GetEnvironmentInfo(ctx context.Context, spec *spec.En env := &KurtosisEnvironment{ DevnetEnvironment: descriptors.DevnetEnvironment{ - L2: make([]*descriptors.Chain, 0, len(spec.Chains)), + L2: make([]*descriptors.L2Chain, 0, len(spec.Chains)), Features: spec.Features, }, } @@ -177,15 +177,17 @@ func (d *KurtosisDeployer) GetEnvironmentInfo(ctx context.Context, spec *spec.En finder := NewServiceFinder(inspectResult.UserServices, WithL2Networks(networks)) if nodes, services := finder.FindL1Services(); len(nodes) > 0 { chain := &descriptors.Chain{ - ID: deployerState.L1ChainID, - Name: "Ethereum", - Services: services, - Nodes: nodes, - JWT: jwtData.L1JWT, + ID: deployerData.L1ChainID, + Name: "Ethereum", + Services: services, + Nodes: nodes, + JWT: jwtData.L1JWT, + Addresses: descriptors.AddressMap(deployerData.State.Addresses), + Wallets: d.getWallets(deployerData.L1ValidatorWallets), } - if deployerState.State != nil { - chain.Addresses = descriptors.AddressMap(deployerState.State.Addresses) - chain.Wallets = d.getWallets(deployerState.L1ValidatorWallets) + if deployerData.State != nil { + chain.Addresses = descriptors.AddressMap(deployerData.State.Addresses) + chain.Wallets = d.getWallets(deployerData.L1ValidatorWallets) } env.L1 = chain } @@ -194,20 +196,24 @@ func (d *KurtosisDeployer) GetEnvironmentInfo(ctx context.Context, spec *spec.En for _, chainSpec := range spec.Chains { nodes, services := finder.FindL2Services(chainSpec.Name) - chain := &descriptors.Chain{ - Name: chainSpec.Name, - ID: chainSpec.NetworkID, - Services: services, - Nodes: nodes, - JWT: jwtData.L2JWT, + chain := &descriptors.L2Chain{ + Chain: descriptors.Chain{ + Name: chainSpec.Name, + ID: chainSpec.NetworkID, + Services: services, + Nodes: nodes, + JWT: jwtData.L2JWT, + }, } // Add contract addresses if available - if deployerState.State != nil && deployerState.State.Deployments != nil { - if deployment, ok := deployerState.State.Deployments[chainSpec.NetworkID]; ok { - chain.Addresses = descriptors.AddressMap(deployment.Addresses) + if deployerData.State != nil && deployerData.State.Deployments != nil { + if deployment, ok := deployerData.State.Deployments[chainSpec.NetworkID]; ok { + chain.L1Addresses = descriptors.AddressMap(deployment.L1Addresses) + chain.Addresses = descriptors.AddressMap(deployment.L2Addresses) chain.Config = deployment.Config - chain.Wallets = d.getWallets(append(deployment.L2Wallets, deployment.L1Wallets...)) + chain.Wallets = d.getWallets(deployment.L2Wallets) + chain.L1Wallets = d.getWallets(deployment.L1Wallets) } } diff --git a/kurtosis-devnet/pkg/kurtosis/kurtosis_test.go b/kurtosis-devnet/pkg/kurtosis/kurtosis_test.go index 8ecbcf063f7c9..765e028fbbd66 100644 --- a/kurtosis-devnet/pkg/kurtosis/kurtosis_test.go +++ b/kurtosis-devnet/pkg/kurtosis/kurtosis_test.go @@ -236,13 +236,12 @@ func TestGetEnvironmentInfo(t *testing.T) { "rpc": {Port: 52645}, } - testWallets := deployer.WalletList{ - { - Name: "test-wallet", - Address: common.HexToAddress("0x123"), - PrivateKey: "0xabc", - }, + testWallet := &deployer.Wallet{ + Name: "test-wallet", + Address: common.HexToAddress("0x123"), + PrivateKey: "0xabc", } + testWallets := deployer.WalletList{testWallet} testJWTs := &jwt.Data{ L1JWT: "test-l1-jwt", @@ -272,11 +271,20 @@ func TestGetEnvironmentInfo(t *testing.T) { name: "successful environment info with JWT", spec: testSpec, inspect: &inspect.InspectData{UserServices: testServices}, - deploy: &deployer.DeployerData{L1ValidatorWallets: testWallets}, - jwt: testJWTs, + deploy: &deployer.DeployerData{ + L1ValidatorWallets: testWallets, + State: &deployer.DeployerState{ + Addresses: deployer.DeploymentAddresses{ + "0x123": common.HexToAddress("0x123"), + }, + }, + L1ChainID: "1234", + }, + jwt: testJWTs, want: &KurtosisEnvironment{ DevnetEnvironment: descriptors.DevnetEnvironment{ L1: &descriptors.Chain{ + ID: "1234", Name: "Ethereum", Services: make(descriptors.ServiceMap), Nodes: []descriptors.Node{ @@ -285,13 +293,24 @@ func TestGetEnvironmentInfo(t *testing.T) { }, }, JWT: testJWTs.L1JWT, + Addresses: descriptors.AddressMap{ + "0x123": common.HexToAddress("0x123"), + }, + Wallets: descriptors.WalletMap{ + testWallet.Name: { + Address: testWallet.Address, + PrivateKey: testWallet.PrivateKey, + }, + }, }, - L2: []*descriptors.Chain{ + L2: []*descriptors.L2Chain{ { - Name: "op-kurtosis", - ID: "1234", - Services: make(descriptors.ServiceMap), - JWT: testJWTs.L2JWT, + Chain: descriptors.Chain{ + Name: "op-kurtosis", + ID: "1234", + Services: make(descriptors.ServiceMap), + JWT: testJWTs.L2JWT, + }, }, }, }, diff --git a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go index 0b8055abf9324..fdc4bbeba923e 100644 --- a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go +++ b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -37,10 +38,11 @@ type DeploymentAddresses map[string]types.Address type DeploymentStateAddresses map[string]DeploymentAddresses type DeploymentState struct { - Addresses DeploymentAddresses `json:"addresses"` - L1Wallets WalletList `json:"l1_wallets"` - L2Wallets WalletList `json:"l2_wallets"` - Config *params.ChainConfig `json:"chain_config"` + L1Addresses DeploymentAddresses `json:"l1_addresses"` + L2Addresses DeploymentAddresses `json:"l2_addresses"` + L1Wallets WalletList `json:"l1_wallets"` + L2Wallets WalletList `json:"l2_wallets"` + Config *params.ChainConfig `json:"chain_config"` } type DeployerState struct { @@ -64,6 +66,7 @@ type Wallet struct { // WalletList holds a list of wallets type WalletList []*Wallet +type WalletMap map[string]*Wallet type DeployerData struct { L1ValidatorWallets WalletList `json:"wallets"` @@ -157,16 +160,22 @@ func parseWalletsFile(r io.Reader) (map[string]WalletList, error) { for id, chain := range rawData { // Create a map to store wallets by name - walletMap := make(map[string]Wallet) + walletMap := make(WalletMap) hasAddress := make(map[string]bool) // First pass: collect addresses for key, value := range chain { if strings.HasSuffix(key, "Address") { name := strings.TrimSuffix(key, "Address") - wallet := walletMap[name] - wallet.Address = common.HexToAddress(value) - wallet.Name = name + wallet, ok := walletMap[name] + if !ok || wallet == nil { + wallet = &Wallet{ + Name: name, + Address: common.HexToAddress(value), + } + } else { + log.Warn("duplicate wallet name key in wallets file", "name", name) + } walletMap[name] = wallet hasAddress[name] = true } @@ -188,7 +197,7 @@ func parseWalletsFile(r io.Reader) (map[string]WalletList, error) { wl := make(WalletList, 0, len(walletMap)) for name, wallet := range walletMap { if hasAddress[name] { - wl = append(wl, &wallet) + wl = append(wl, wallet) } } @@ -253,13 +262,23 @@ func parseStateFile(r io.Reader) (*DeployerState, error) { continue } - addresses := mapDeployment(deployment) + l1Addresses := mapDeployment(deployment) - if len(addresses) > 0 { - result.Deployments[id] = DeploymentState{ - Addresses: addresses, + // op-deployer currently does not categorize L2 addresses + // so we need to map them manually. + // TODO: Update op-deployer to sort rollup contracts by category + l2Addresses := make(DeploymentAddresses) + for _, addressName := range []string{"optimismMintableERC20FactoryProxy"} { + if addr, ok := l1Addresses[addressName]; ok { + l2Addresses[addressName] = addr + delete(l1Addresses, addressName) } } + + result.Deployments[id] = DeploymentState{ + L1Addresses: l1Addresses, + L2Addresses: l2Addresses, + } } result.Addresses = mapDeployment(state.ImplementationsDeployment) diff --git a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go index d125a19a098c9..ea03525e913be 100644 --- a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go +++ b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go @@ -67,7 +67,8 @@ func TestParseStateFile(t *testing.T) { require.True(t, ok, "Chain %s not found in result", tt.chainID) for key, expected := range tt.expected { - actual := chain.Addresses[key] + actual := chain.L1Addresses[key] + // TODO: add L2 addresses require.Equal(t, expected, actual, "Chain %s, %s: expected %s, got %s", tt.chainID, key, expected, actual) } } diff --git a/op-acceptance-tests/tests/interop/interop_smoke_test.go b/op-acceptance-tests/tests/interop/interop_smoke_test.go index 97fecc088026f..86a02e6f9dc4d 100644 --- a/op-acceptance-tests/tests/interop/interop_smoke_test.go +++ b/op-acceptance-tests/tests/interop/interop_smoke_test.go @@ -90,11 +90,17 @@ func TestSmokeTestFailure(t *testing.T) { addr: mockAddr, bal: sdktypes.NewBalance(big.NewInt(1000000)), } - mockChain := newMockFailingChain( + mockL1Chain := newMockFailingL1Chain( sdktypes.ChainID(big.NewInt(1234)), - []system.Wallet{mockWallet}, + system.WalletMap{ + "user1": mockWallet, + }, ) - mockSys := &mockFailingSystem{chain: mockChain} + mockL2Chain := newMockFailingL2Chain( + sdktypes.ChainID(big.NewInt(1234)), + system.WalletMap{"user1": mockWallet}, + ) + mockSys := &mockFailingSystem{l1Chain: mockL1Chain, l2Chain: mockL2Chain} // Run the smoke test logic and capture failures getter := func(ctx context.Context) system.Wallet { diff --git a/op-acceptance-tests/tests/interop/mocks_test.go b/op-acceptance-tests/tests/interop/mocks_test.go index c5d6cdb9d077a..b8480722a4ac3 100644 --- a/op-acceptance-tests/tests/interop/mocks_test.go +++ b/op-acceptance-tests/tests/interop/mocks_test.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/bindings" "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/registry/empty" - "github.com/ethereum-optimism/optimism/devnet-sdk/descriptors" "github.com/ethereum-optimism/optimism/devnet-sdk/interfaces" "github.com/ethereum-optimism/optimism/devnet-sdk/system" "github.com/ethereum-optimism/optimism/devnet-sdk/testing/systest" @@ -138,12 +137,12 @@ func (r *mockContractsRegistry) SuperchainWETH(address types.Address) (interface type mockFailingChain struct { id types.ChainID reg interfaces.ContractsRegistry - wallets []system.Wallet + wallets system.WalletMap } var _ system.Chain = (*mockFailingChain)(nil) -func newMockFailingChain(id types.ChainID, wallets []system.Wallet) *mockFailingChain { +func newMockFailingL1Chain(id types.ChainID, wallets system.WalletMap) *mockFailingChain { return &mockFailingChain{ id: id, reg: &mockContractsRegistry{}, @@ -155,8 +154,8 @@ func (m *mockFailingChain) Node() system.Node { return nil } func (m *mockFailingChain) RPCURL() string { return "mock://failing" } func (m *mockFailingChain) Client() (*ethclient.Client, error) { return ethclient.Dial(m.RPCURL()) } func (m *mockFailingChain) ID() types.ChainID { return m.id } -func (m *mockFailingChain) Wallets(ctx context.Context) ([]system.Wallet, error) { - return m.wallets, nil +func (m *mockFailingChain) Wallets() system.WalletMap { + return m.wallets } func (m *mockFailingChain) ContractsRegistry() interfaces.ContractsRegistry { return m.reg } func (m *mockFailingChain) GasPrice(ctx context.Context) (*big.Int, error) { @@ -174,13 +173,38 @@ func (m *mockFailingChain) SupportsEIP(ctx context.Context, eip uint64) bool { func (m *mockFailingChain) Config() (*params.ChainConfig, error) { return nil, fmt.Errorf("not implemented") } -func (m *mockFailingChain) Addresses() descriptors.AddressMap { +func (m *mockFailingChain) Addresses() system.AddressMap { return map[string]common.Address{} } +// mockFailingChain implements system.Chain with a failing SendETH +type mockFailingL2Chain struct { + mockFailingChain +} + +var _ system.L2Chain = (*mockFailingL2Chain)(nil) + +func newMockFailingL2Chain(id types.ChainID, wallets system.WalletMap) *mockFailingL2Chain { + return &mockFailingL2Chain{ + mockFailingChain: mockFailingChain{ + id: id, + reg: &mockContractsRegistry{}, + wallets: wallets, + }, + } +} + +func (m *mockFailingL2Chain) L1Addresses() system.AddressMap { + return map[string]common.Address{} +} +func (m *mockFailingL2Chain) L1Wallets() system.WalletMap { + return map[string]system.Wallet{} +} + // mockFailingSystem implements system.System type mockFailingSystem struct { - chain system.Chain + l1Chain system.Chain + l2Chain system.L2Chain } func (m *mockFailingSystem) Identifier() string { @@ -188,11 +212,11 @@ func (m *mockFailingSystem) Identifier() string { } func (m *mockFailingSystem) L1() system.Chain { - return nil // We don't need L1 for this test + return m.l1Chain } -func (m *mockFailingSystem) L2s() []system.Chain { - return []system.Chain{m.chain} +func (m *mockFailingSystem) L2s() []system.L2Chain { + return []system.L2Chain{m.l2Chain} } func (m *mockFailingSystem) Close() error {