diff --git a/admin/admin.go b/admin/admin.go index 4cd5cf043..da9934b55 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -7,8 +7,9 @@ import ( "net/http" "sync" + "github.com/ethereum-optimism/supersim/config" "github.com/ethereum/go-ethereum/log" - + "github.com/ethereum/go-ethereum/rpc" "github.com/gin-gonic/gin" ) @@ -19,15 +20,24 @@ type AdminServer struct { cancel context.CancelFunc wg sync.WaitGroup + rpcServer *rpc.Server + networkConfig *config.NetworkConfig + port uint64 } -func NewAdminServer(log log.Logger, port uint64) *AdminServer { - return &AdminServer{log: log, port: port} +type RPCMethods struct { + Log log.Logger + NetworkConfig *config.NetworkConfig +} + +func NewAdminServer(log log.Logger, port uint64, networkConfig *config.NetworkConfig) *AdminServer { + return &AdminServer{log: log, port: port, networkConfig: networkConfig} } func (s *AdminServer) Start(ctx context.Context) error { - router := setupRouter() + router := s.setupRouter() + s.srv = &http.Server{Handler: router} listener, err := net.Listen("tcp", fmt.Sprintf(":%d", s.port)) @@ -73,13 +83,69 @@ func (s *AdminServer) Endpoint() string { return fmt.Sprintf("http://127.0.0.1:%d", s.port) } -func setupRouter() *gin.Engine { +func (s *AdminServer) ConfigAsString() string { + return fmt.Sprintf("Admin Server: %s\n\n", s.Endpoint()) +} + +func filterByChainID(chains []config.ChainConfig, chainId uint64) *config.ChainConfig { + for _, chain := range chains { + if chain.ChainID == chainId { + return &chain + } + } + return nil +} + +func (s *AdminServer) setupRouter() *gin.Engine { gin.SetMode(gin.ReleaseMode) router := gin.New() router.Use(gin.Recovery()) + rpcServer := rpc.NewServer() + rpcMethods := &RPCMethods{ + Log: s.log, + NetworkConfig: s.networkConfig, + } + + if err := rpcServer.RegisterName("admin", rpcMethods); err != nil { + s.log.Error("failed to register RPC methods:", "error", err) + return nil + } + router.GET("/ready", func(c *gin.Context) { c.String(http.StatusOK, "OK") }) + + router.POST("/", gin.WrapH(rpcServer)) + return router } + +func (m *RPCMethods) GetConfig(args *struct{}) *config.NetworkConfig { + + m.Log.Debug("admin_getConfig") + return m.NetworkConfig +} + +func (m *RPCMethods) GetL1Addresses(args *uint64) *map[string]string { + chain := filterByChainID(m.NetworkConfig.L2Configs, *args) + if chain == nil { + m.Log.Error("chain not found", "chainID", *args) + return nil + } + + reply := map[string]string{ + "AddressManager": chain.L2Config.L1Addresses.AddressManager.String(), + "L1CrossDomainMessengerProxy": chain.L2Config.L1Addresses.L1CrossDomainMessengerProxy.String(), + "L1ERC721BridgeProxy": chain.L2Config.L1Addresses.L1ERC721BridgeProxy.String(), + "L1StandardBridgeProxy": chain.L2Config.L1Addresses.L1StandardBridgeProxy.String(), + "L2OutputOracleProxy": chain.L2Config.L1Addresses.L2OutputOracleProxy.String(), + "OptimismMintableERC20FactoryProxy": chain.L2Config.L1Addresses.OptimismMintableERC20FactoryProxy.String(), + "OptimismPortalProxy": chain.L2Config.L1Addresses.OptimismPortalProxy.String(), + "SystemConfigProxy": chain.L2Config.L1Addresses.SystemConfigProxy.String(), + "ProxyAdmin": chain.L2Config.L1Addresses.ProxyAdmin.String(), + "SuperchainConfig": chain.L2Config.L1Addresses.SuperchainConfig.String(), + } + m.Log.Debug("admin_getL2Addresses") + return &reply +} diff --git a/admin/admin_test.go b/admin/admin_test.go index 2360d2595..e426b6067 100644 --- a/admin/admin_test.go +++ b/admin/admin_test.go @@ -9,15 +9,20 @@ import ( "time" "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum-optimism/supersim/config" + "github.com/ethereum-optimism/supersim/testutils" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestAdminServerBasicFunctionality(t *testing.T) { + networkConfig := config.GetDefaultNetworkConfig(uint64(time.Now().Unix()), "") testlog := testlog.Logger(t, log.LevelInfo) ctx, cancel := context.WithCancel(context.Background()) - adminServer := NewAdminServer(testlog, 0) + adminServer := NewAdminServer(testlog, 0, &networkConfig) t.Cleanup(func() { cancel() }) require.NoError(t, adminServer.Start(ctx)) @@ -43,3 +48,49 @@ func TestAdminServerBasicFunctionality(t *testing.T) { } require.Error(t, err) } + +func TestGetL1AddressesRPC(t *testing.T) { + networkConfig := config.GetDefaultNetworkConfig(uint64(time.Now().Unix()), "") + testlog := testlog.Logger(t, log.LevelInfo) + + ctx, cancel := context.WithCancel(context.Background()) + adminServer := NewAdminServer(testlog, 0, &networkConfig) + t.Cleanup(func() { cancel() }) + + require.NoError(t, adminServer.Start(ctx)) + + waitErr := testutils.WaitForWithTimeout(context.Background(), 500*time.Millisecond, 10*time.Second, func() (bool, error) { + // Dial the RPC server + client, err := rpc.Dial(adminServer.Endpoint()) + require.NoError(t, err) + + var addresses map[string]string + chainID := uint64(902) + err = client.CallContext(context.Background(), &addresses, "admin_getL1Addresses", chainID) + + require.NoError(t, err) + + expectedAddresses := map[string]string{ + "AddressManager": "0x90D0B458313d3A207ccc688370eE76B75200EadA", + "L1CrossDomainMessengerProxy": "0xeCA0f912b4bd255f3851951caE5775CC9400aA3B", + "L1ERC721BridgeProxy": "0xdC0917C61A4CD589B29b6464257d564C0abeBB2a", + "L1StandardBridgeProxy": "0x67B2aB287a32bB9ACe84F6a5A30A62597b10AdE9", + "L2OutputOracleProxy": "0x0000000000000000000000000000000000000000", + "OptimismMintableERC20FactoryProxy": "0xd4E933aa1f37A755135d7623488a383f8208CC7c", + "OptimismPortalProxy": "0x35e67BC631C327b60C6A39Cff6b03a8adBB19c2D", + "ProxyAdmin": "0x0000000000000000000000000000000000000000", + "SuperchainConfig": "0x0000000000000000000000000000000000000000", + "SystemConfigProxy": "0xFb295Aa436F23BE2Bd17678Adf1232bdec02FED1", + } + + for key, expectedValue := range expectedAddresses { + if addresses[key] != expectedValue { + return false, nil + } + } + + return true, nil + }) + + assert.NoError(t, waitErr) +} diff --git a/supersim.go b/supersim.go index 0eeb2e194..5abf52a68 100644 --- a/supersim.go +++ b/supersim.go @@ -65,7 +65,8 @@ func NewSupersim(log log.Logger, envPrefix string, closeApp context.CancelCauseF return nil, fmt.Errorf("failed to create orchestrator") } - adminServer := admin.NewAdminServer(log, cliConfig.AdminPort) + adminServer := admin.NewAdminServer(log, cliConfig.AdminPort, &networkConfig) + return &Supersim{log, cliConfig, &networkConfig, o, adminServer}, nil } @@ -108,7 +109,7 @@ func (s *Supersim) ConfigAsString() string { fmt.Fprintln(&b, "Supersim Config") fmt.Fprintln(&b, "-----------------------") - fmt.Fprintf(&b, "Admin Server: %s\n\n", s.adminServer.Endpoint()) + fmt.Fprintf(&b, s.adminServer.ConfigAsString()) fmt.Fprintln(&b, "Chain Configuration") fmt.Fprintln(&b, "-----------------------")