Skip to content

Commit ace5074

Browse files
committed
Implement frax DA changes
1 parent 6638905 commit ace5074

File tree

25 files changed

+444
-85
lines changed

25 files changed

+444
-85
lines changed

.github/CODEOWNERS

Lines changed: 0 additions & 39 deletions
This file was deleted.

.github/dependabot.yml

Lines changed: 0 additions & 14 deletions
This file was deleted.

.github/workflows/release.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Release docker image
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
service:
7+
description: Service to release
8+
required: true
9+
type: choice
10+
options:
11+
- op-node
12+
- op-batcher
13+
- op-proposer
14+
- op-bootnode
15+
version:
16+
description: Service version to publish (will be the docker tag)
17+
required: true
18+
19+
jobs:
20+
build-and-push-image:
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
packages: write
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
- name: Set up Docker Buildx
29+
uses: docker/setup-buildx-action@v3
30+
- name: Log in to the Container registry
31+
uses: docker/login-action@v3
32+
with:
33+
registry: ghcr.io
34+
username: ${{ github.actor }}
35+
password: ${{ secrets.GITHUB_TOKEN }}
36+
- name: Build and push
37+
uses: docker/bake-action@v5
38+
env:
39+
REGISTRY: ghcr.io
40+
REPOSITORY: fraxfinance/fraxtal
41+
PLATFORMS: linux/amd64,linux/arm64
42+
GIT_COMMIT: ${{ github.sha }}
43+
GIT_VERSION: ${{ inputs.version }}
44+
IMAGE_TAGS: ${{ inputs.version }}
45+
with:
46+
push: true
47+
set: |
48+
*.cache-from=type=gha
49+
*.cache-to=type=gha,mode=max
50+
targets: ${{ inputs.service }}

docker-bake.hcl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ target "op-node" {
9292
}
9393
target = "op-node-target"
9494
platforms = split(",", PLATFORMS)
95-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-node:${tag}"]
95+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-node:${tag}"]
9696
}
9797

9898
target "op-batcher" {
@@ -105,7 +105,7 @@ target "op-batcher" {
105105
}
106106
target = "op-batcher-target"
107107
platforms = split(",", PLATFORMS)
108-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-batcher:${tag}"]
108+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-batcher:${tag}"]
109109
}
110110

111111
target "op-proposer" {
@@ -118,7 +118,7 @@ target "op-proposer" {
118118
}
119119
target = "op-proposer-target"
120120
platforms = split(",", PLATFORMS)
121-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-proposer:${tag}"]
121+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-proposer:${tag}"]
122122
}
123123

124124
target "op-challenger" {
@@ -132,7 +132,7 @@ target "op-challenger" {
132132
}
133133
target = "op-challenger-target"
134134
platforms = split(",", PLATFORMS)
135-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-challenger:${tag}"]
135+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-challenger:${tag}"]
136136
}
137137

138138
target "op-dispute-mon" {
@@ -145,7 +145,7 @@ target "op-dispute-mon" {
145145
}
146146
target = "op-dispute-mon-target"
147147
platforms = split(",", PLATFORMS)
148-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-dispute-mon:${tag}"]
148+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-dispute-mon:${tag}"]
149149
}
150150

151151
target "op-conductor" {
@@ -158,7 +158,7 @@ target "op-conductor" {
158158
}
159159
target = "op-conductor-target"
160160
platforms = split(",", PLATFORMS)
161-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-conductor:${tag}"]
161+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-conductor:${tag}"]
162162
}
163163

164164
target "da-server" {
@@ -170,7 +170,7 @@ target "da-server" {
170170
}
171171
target = "da-server-target"
172172
platforms = split(",", PLATFORMS)
173-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/da-server:${tag}"]
173+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-da-server:${tag}"]
174174
}
175175

176176
target "op-program" {
@@ -183,7 +183,7 @@ target "op-program" {
183183
}
184184
target = "op-program-target"
185185
platforms = split(",", PLATFORMS)
186-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-program:${tag}"]
186+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-program:${tag}"]
187187
}
188188

189189
target "op-supervisor" {
@@ -196,7 +196,7 @@ target "op-supervisor" {
196196
}
197197
target = "op-supervisor-target"
198198
platforms = split(",", PLATFORMS)
199-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-supervisor:${tag}"]
199+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-op-supervisor:${tag}"]
200200
}
201201

202202
target "cannon" {
@@ -209,7 +209,7 @@ target "cannon" {
209209
}
210210
target = "cannon-target"
211211
platforms = split(",", PLATFORMS)
212-
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/cannon:${tag}"]
212+
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}-cannon:${tag}"]
213213
}
214214

215215
target "proofs-tools" {

frax-da/cli.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package fraxda
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
7+
"github.com/urfave/cli/v2"
8+
9+
opservice "github.com/ethereum-optimism/optimism/op-service"
10+
)
11+
12+
const (
13+
DaRpcFlagName = "da.rpc"
14+
)
15+
16+
var (
17+
defaultDaRpc = "https://da-rpc.mainnet.frax.com"
18+
)
19+
20+
func CLIFlags(envPrefix string) []cli.Flag {
21+
return []cli.Flag{
22+
&cli.StringFlag{
23+
Name: DaRpcFlagName,
24+
Usage: "DA endpoint",
25+
Value: defaultDaRpc,
26+
EnvVars: opservice.PrefixEnvVar(envPrefix, "DA_RPC"),
27+
},
28+
}
29+
}
30+
31+
type Config struct {
32+
DaRpc string
33+
}
34+
35+
func (c Config) Check() error {
36+
if c.DaRpc == "" {
37+
c.DaRpc = defaultDaRpc
38+
}
39+
40+
if _, err := url.Parse(c.DaRpc); err != nil {
41+
return fmt.Errorf("invalid da rpc url: %w", err)
42+
}
43+
44+
return nil
45+
}
46+
47+
type CLIConfig struct {
48+
DaRpc string
49+
}
50+
51+
func (c CLIConfig) Check() error {
52+
if c.DaRpc == "" {
53+
c.DaRpc = defaultDaRpc
54+
}
55+
56+
if _, err := url.Parse(c.DaRpc); err != nil {
57+
return fmt.Errorf("invalid da rpc url: %w", err)
58+
}
59+
60+
return nil
61+
}
62+
63+
func NewCLIConfig() CLIConfig {
64+
return CLIConfig{
65+
DaRpc: defaultDaRpc,
66+
}
67+
}
68+
69+
func ReadCLIConfig(ctx *cli.Context) CLIConfig {
70+
return CLIConfig{
71+
DaRpc: ctx.String(DaRpcFlagName),
72+
}
73+
}

frax-da/client.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package fraxda
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"net/http"
10+
"net/url"
11+
"time"
12+
13+
"github.com/multiformats/go-multibase"
14+
)
15+
16+
type DAClient struct {
17+
baseUrl *url.URL
18+
httpClient *http.Client
19+
}
20+
21+
func NewDAClient(rpc string) (*DAClient, error) {
22+
baseUrl, err := url.Parse(rpc)
23+
if err != nil {
24+
return nil, fmt.Errorf("unable to parse DA endpoint: %s", err)
25+
}
26+
27+
httpClient := &http.Client{
28+
Timeout: 30 * time.Second,
29+
}
30+
31+
return &DAClient{
32+
baseUrl: baseUrl,
33+
httpClient: httpClient,
34+
}, nil
35+
}
36+
37+
func (c DAClient) Read(ctx context.Context, id []byte) ([]byte, error) {
38+
ipfsCID, err := multibase.Encode(multibase.Base32, id)
39+
if err != nil {
40+
return nil, fmt.Errorf("unable to decode CID: %w", err)
41+
}
42+
43+
fetchUrl := c.baseUrl.ResolveReference(&url.URL{Path: fmt.Sprintf("/v1/blobs/%s", ipfsCID)})
44+
request, err := http.NewRequestWithContext(ctx, "GET", fetchUrl.String(), nil)
45+
if err != nil {
46+
return nil, fmt.Errorf("unable to create request to fetch data from DA: %w", err)
47+
}
48+
resp, err := c.httpClient.Do(request)
49+
50+
if err != nil {
51+
return nil, fmt.Errorf("unable to fetch DA data: %w", err)
52+
}
53+
if resp.StatusCode != 200 {
54+
return nil, fmt.Errorf("unable to fetch DA data, got status code %d", resp.StatusCode)
55+
}
56+
57+
body, err := io.ReadAll(resp.Body)
58+
if err != nil {
59+
return nil, fmt.Errorf("unable to read DA data fetch response: %w", err)
60+
}
61+
62+
return body, nil
63+
}
64+
65+
func (c DAClient) ReadCelestia(ctx context.Context, hexString string) ([]byte, error) {
66+
fetchUrl := c.baseUrl.ResolveReference(&url.URL{Path: fmt.Sprintf("/v1/blobs/celestia-%s", hexString)})
67+
request, err := http.NewRequestWithContext(ctx, "GET", fetchUrl.String(), nil)
68+
if err != nil {
69+
return nil, fmt.Errorf("unable to create request to fetch celestia data from DA: %w", err)
70+
}
71+
resp, err := c.httpClient.Do(request)
72+
73+
if err != nil {
74+
return nil, fmt.Errorf("unable to fetch DA celestia data: %w", err)
75+
}
76+
if resp.StatusCode != 200 {
77+
return nil, fmt.Errorf("unable to fetch DA celestia data, got status code %d", resp.StatusCode)
78+
}
79+
80+
body, err := io.ReadAll(resp.Body)
81+
if err != nil {
82+
return nil, fmt.Errorf("unable to read DA celestia data fetch response: %w", err)
83+
}
84+
85+
return body, nil
86+
}
87+
88+
func (c DAClient) Write(ctx context.Context, data []byte) ([]byte, error) {
89+
submitUrl := c.baseUrl.ResolveReference(&url.URL{Path: "/v1/blobs"})
90+
91+
request, err := http.NewRequestWithContext(ctx, "POST", submitUrl.String(), bytes.NewBuffer(data))
92+
if err != nil {
93+
return nil, fmt.Errorf("unable to create request to submit data to DA: %w", err)
94+
}
95+
96+
resp, err := c.httpClient.Do(request)
97+
98+
if err != nil {
99+
return nil, fmt.Errorf("unable to submit data to DA: %w", err)
100+
}
101+
if resp.StatusCode > 299 {
102+
return nil, fmt.Errorf("unable to submit data to DA, got status code %d", resp.StatusCode)
103+
}
104+
105+
body, err := io.ReadAll(resp.Body)
106+
if err != nil {
107+
return nil, fmt.Errorf("unable to read DA data submit response: %w", err)
108+
}
109+
110+
var respDto daSubmitResponse
111+
err = json.Unmarshal(body, &respDto)
112+
if err != nil {
113+
return nil, fmt.Errorf("unable to parse DA data submit response json: %w", err)
114+
}
115+
116+
if respDto.ID == "" {
117+
return nil, fmt.Errorf("DA data submit response returned empty ID")
118+
}
119+
120+
_, ipfsCID, err := multibase.Decode(respDto.ID)
121+
if err != nil {
122+
return nil, fmt.Errorf("DA data submit response returned invalid multibase encoded value: %w", err)
123+
}
124+
125+
return ipfsCID, nil
126+
}

0 commit comments

Comments
 (0)