diff --git a/anvil/anvil.go b/anvil/anvil.go index 84ffb5ad..1e415c4e 100644 --- a/anvil/anvil.go +++ b/anvil/anvil.go @@ -8,9 +8,7 @@ import ( "os" "os/exec" "sync/atomic" - "time" - "github.com/ethereum-optimism/supersim/utils" "github.com/ethereum/go-ethereum/log" ) @@ -58,13 +56,13 @@ func (a *Anvil) Start(ctx context.Context) error { tempFile, err := os.CreateTemp("", "genesis-*.json") if err != nil { - return fmt.Errorf("Error creating temporary genesis file: %v", err) + return fmt.Errorf("error creating temporary genesis file: %v", err) } defer os.Remove(tempFile.Name()) _, err = tempFile.Write(a.cfg.Genesis) if err != nil { - return fmt.Errorf("Error writing to genesis file: %v", err) + return fmt.Errorf("error writing to genesis file: %v", err) } // Prep args @@ -72,7 +70,7 @@ func (a *Anvil) Start(ctx context.Context) error { "--host", host, "--chain-id", fmt.Sprintf("%d", a.cfg.ChainId), "--port", fmt.Sprintf("%d", a.cfg.Port), - "--init", fmt.Sprintf("%s", tempFile.Name()), + "--init", tempFile.Name(), } a.cmd = exec.CommandContext(a.resourceCtx, "anvil", args...) @@ -109,10 +107,6 @@ func (a *Anvil) Start(ctx context.Context) error { return fmt.Errorf("failed to start anvil: %w", err) } - if _, err := utils.WaitForAnvilClientToBeReady(fmt.Sprintf("http://%s:%d", host, a.cfg.Port), 5*time.Second); err != nil { - return fmt.Errorf("failed to start anvil: %w", err) - } - go func() { if err := a.cmd.Wait(); err != nil { anvilLog.Error("anvil terminated with an error", "error", err) @@ -122,6 +116,22 @@ func (a *Anvil) Start(ctx context.Context) error { a.stoppedCh <- struct{}{} }() + // go func() { + // _, err := utils.WaitForAnvilClientToBeReady(fmt.Sprintf("http://localhost:%d", a.cfg.Port), 10*time.Second) + + // fmt.Println("waiting for anvil client done") + + // if err != nil { + // anvilLog.Error("timed out connecting to RPC server", "error", err) + // return + // } + + // if a.ready.CompareAndSwap(false, true) { + // a.readyCh <- struct{}{} + // } + + // }() + return nil } @@ -141,3 +151,7 @@ func (a *Anvil) Stop() error { func (a *Anvil) Stopped() bool { return a.stopped.Load() } + +func (a *Anvil) Endpoint() string { + return fmt.Sprintf("http://%s:%d", host, a.cfg.Port) +} diff --git a/supersim.go b/supersim.go index b816fa3f..65412bd6 100644 --- a/supersim.go +++ b/supersim.go @@ -3,11 +3,16 @@ package supersim import ( _ "embed" "fmt" + "time" + + "sync" "context" "github.com/ethereum-optimism/supersim/anvil" + "github.com/ethereum-optimism/supersim/utils" + "github.com/ethereum/go-ethereum/log" ) @@ -41,8 +46,8 @@ func NewSupersim(log log.Logger, config *Config) *Supersim { l1Chain := anvil.New(log, &config.l1Chain) l2Chains := make(map[uint64]*anvil.Anvil) - for _, l2Chain := range config.l2Chains { - l2Chains[l2Chain.ChainId] = anvil.New(log, &l2Chain) + for _, l2ChainConfig := range config.l2Chains { + l2Chains[l2ChainConfig.ChainId] = anvil.New(log, &l2ChainConfig) } return &Supersim{log, l1Chain, l2Chains} @@ -55,12 +60,26 @@ func (s *Supersim) Start(ctx context.Context) error { return fmt.Errorf("l1 chain failed to start: %w", err) } + var wg sync.WaitGroup + waitForAnvil := func(anvil *anvil.Anvil) { + defer wg.Done() + wg.Add(1) + utils.WaitForAnvilEndpointToBeReady(anvil.Endpoint(), 10*time.Second) + } + + go waitForAnvil(s.l1Chain) + for _, l2Chain := range s.l2Chains { if err := l2Chain.Start(ctx); err != nil { return fmt.Errorf("l2 chain failed to start: %w", err) } + go waitForAnvil(l2Chain) } + wg.Wait() + + print("Anvils are ready") + return nil } diff --git a/supersim_test.go b/supersim_test.go index cb23c123..ec5b4b83 100644 --- a/supersim_test.go +++ b/supersim_test.go @@ -10,6 +10,8 @@ import ( oplog "github.com/ethereum-optimism/optimism/op-service/log" "github.com/ethereum-optimism/supersim/utils" + + "github.com/ethereum/go-ethereum/rpc" ) const ( @@ -27,7 +29,14 @@ func TestGenesisState(t *testing.T) { defer supersim.Stop(context.Background()) for _, l2ChainConfig := range DefaultConfig.l2Chains { - client, err := utils.WaitForAnvilClientToBeReady(fmt.Sprintf("http://127.0.0.1:%d", l2ChainConfig.Port), anvilClientTimeout) + rpcUrl := fmt.Sprintf("http://127.0.0.1:%d", l2ChainConfig.Port) + client, clientCreateErr := rpc.Dial(rpcUrl) + + if clientCreateErr != nil { + t.Fatalf("Failed to create client: %v", clientCreateErr) + } + + err := utils.WaitForAnvilClientToBeReady(client, anvilClientTimeout) if err != nil { t.Fatalf("Failed to connect to RPC server: %v", err) } diff --git a/utils/rpc.go b/utils/rpc.go index de7e3cf9..96c4aa25 100644 --- a/utils/rpc.go +++ b/utils/rpc.go @@ -3,13 +3,27 @@ package utils import ( "context" "fmt" - "net/http" + "strings" "time" "github.com/ethereum/go-ethereum/rpc" ) -func WaitForAnvilClientToBeReady(rpcUrl string, timeout time.Duration) (*rpc.Client, error) { +func WaitForAnvilEndpointToBeReady(endpoint string, timeout time.Duration) error { + client, clientCreateErr := rpc.Dial(endpoint) + if clientCreateErr != nil { + return fmt.Errorf("failed to create client: %v", clientCreateErr) + } + + err := WaitForAnvilClientToBeReady(client, timeout) + if err != nil { + return fmt.Errorf("failed to connect to RPC server: %v", err) + } + + return nil +} + +func WaitForAnvilClientToBeReady(client *rpc.Client, timeout time.Duration) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() @@ -19,22 +33,21 @@ func WaitForAnvilClientToBeReady(rpcUrl string, timeout time.Duration) (*rpc.Cli for { select { case <-ctx.Done(): - return nil, fmt.Errorf("timed out waiting for response from %s", rpcUrl) + return fmt.Errorf("timed out waiting for response from client") case <-ticker.C: - _, err := http.Get(rpcUrl) + var result string + callErr := client.Call(&result, "web3_clientVersion") - if err != nil { - fmt.Printf("Error making request: %v\n", err) + if callErr != nil { + fmt.Printf("error calling web3_clientVersion: %v\n", callErr) continue } - client, err := rpc.Dial(rpcUrl) - if err != nil { - fmt.Printf("Error creating rpc client: %v\n", err) - continue + if strings.HasPrefix(result, "anvil") { + return nil } - return client, nil + return fmt.Errorf("unexpected client version: %s", result) } } }