Commit 9f24084f authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Support file: URLs to download prestates from. (#12441)

* op-challenger: Introduce --prestates-url to specify prestates source for all game types at once.

* op-challenger: Add required config validation for asterisc kona.

Allow specify both prestate and prestates url to allow overriding. Prestate takes priority.

* op-challenger: Introduce vm-flag to make default with overrides pattern easier.

* op-challenger: Add vm type info to override flags.

* op-challenger: Support file: URLs to download prestates from.

Makes it possible to support multiple prestates without needing a HTTP server.
parent cb9e6675
...@@ -69,20 +69,11 @@ func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.H ...@@ -69,20 +69,11 @@ func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.H
return fmt.Errorf("error creating prestate dir: %w", err) return fmt.Errorf("error creating prestate dir: %w", err)
} }
prestateUrl := m.baseUrl.JoinPath(hash.Hex() + fileType) prestateUrl := m.baseUrl.JoinPath(hash.Hex() + fileType)
tCtx, cancel := context.WithTimeout(ctx, time.Minute) in, err := m.fetch(ctx, prestateUrl)
defer cancel()
req, err := http.NewRequestWithContext(tCtx, "GET", prestateUrl.String(), nil)
if err != nil {
return fmt.Errorf("failed to create prestate request: %w", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch prestate from %v: %w", prestateUrl, err) return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("%w from url %v: status %v", ErrPrestateUnavailable, prestateUrl, resp.StatusCode)
} }
defer in.Close()
tmpFile := dest + ".tmp" + fileType // Preserve the file type extension so state decoding is applied correctly tmpFile := dest + ".tmp" + fileType // Preserve the file type extension so state decoding is applied correctly
out, err := ioutil.NewAtomicWriter(tmpFile, 0o644) out, err := ioutil.NewAtomicWriter(tmpFile, 0o644)
if err != nil { if err != nil {
...@@ -92,7 +83,7 @@ func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.H ...@@ -92,7 +83,7 @@ func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.H
// If errors occur, try to clean up without renaming the file into its final destination as Close() would do // If errors occur, try to clean up without renaming the file into its final destination as Close() would do
_ = out.Abort() _ = out.Abort()
}() }()
if _, err := io.Copy(out, resp.Body); err != nil { if _, err := io.Copy(out, in); err != nil {
return fmt.Errorf("failed to write file %v: %w", dest, err) return fmt.Errorf("failed to write file %v: %w", dest, err)
} }
if err := out.Close(); err != nil { if err := out.Close(); err != nil {
...@@ -110,3 +101,29 @@ func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.H ...@@ -110,3 +101,29 @@ func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.H
} }
return nil return nil
} }
func (m *MultiPrestateProvider) fetch(ctx context.Context, prestateUrl *url.URL) (io.ReadCloser, error) {
if prestateUrl.Scheme == "file" {
path := prestateUrl.Path
in, err := os.OpenFile(path, os.O_RDONLY, 0o644)
if errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("%w unavailable from path %v", ErrPrestateUnavailable, path)
}
return in, err
}
tCtx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
req, err := http.NewRequestWithContext(tCtx, "GET", prestateUrl.String(), nil)
if err != nil {
return nil, fmt.Errorf("failed to create prestate request: %w", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to fetch prestate from %v: %w", prestateUrl, err)
}
if resp.StatusCode != http.StatusOK {
_ = resp.Body.Close() // Not returning the body so make a best effort to close it now.
return nil, fmt.Errorf("%w from url %v: status %v", ErrPrestateUnavailable, prestateUrl, resp.StatusCode)
}
return resp.Body, nil
}
...@@ -18,7 +18,7 @@ import ( ...@@ -18,7 +18,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestDownloadPrestate(t *testing.T) { func TestDownloadPrestateHTTP(t *testing.T) {
for _, ext := range supportedFileTypes { for _, ext := range supportedFileTypes {
t.Run(ext, func(t *testing.T) { t.Run(ext, func(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()
...@@ -38,6 +38,28 @@ func TestDownloadPrestate(t *testing.T) { ...@@ -38,6 +38,28 @@ func TestDownloadPrestate(t *testing.T) {
} }
} }
func TestDownloadPrestateFile(t *testing.T) {
for _, ext := range supportedFileTypes {
t.Run(ext, func(t *testing.T) {
sourceDir := t.TempDir()
dir := t.TempDir()
hash := common.Hash{0xaa}
sourcePath := filepath.Join(sourceDir, hash.Hex()+ext)
expectedContent := "/" + hash.Hex() + ext
require.NoError(t, os.WriteFile(sourcePath, []byte(expectedContent), 0600))
provider := NewMultiPrestateProvider(parseURL(t, "file:"+sourceDir), dir, &stubStateConverter{hash: hash})
path, err := provider.PrestatePath(context.Background(), hash)
require.NoError(t, err)
in, err := os.Open(path)
require.NoError(t, err)
defer in.Close()
content, err := io.ReadAll(in)
require.NoError(t, err)
require.Equal(t, expectedContent, string(content))
})
}
}
func TestCreateDirectory(t *testing.T) { func TestCreateDirectory(t *testing.T) {
for _, ext := range supportedFileTypes { for _, ext := range supportedFileTypes {
t.Run(ext, func(t *testing.T) { t.Run(ext, func(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