Skip to content

Commit cc9dbc1

Browse files
committed
fix helpers
1 parent 35bbbcb commit cc9dbc1

2 files changed

Lines changed: 98 additions & 33 deletions

File tree

execution/evm/test/execution_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import (
2121

2222
const (
2323
CHAIN_ID = "1234"
24-
GENESIS_HASH = "0x2b8bbb1ea1e04f9c9809b4b278a8687806edc061a356c7dbc491930d8e922503"
25-
GENESIS_STATEROOT = "0x05e9954443da80d86f2104e56ffdfd98fe21988730684360104865b3dc8191b4"
24+
GENESIS_HASH = "0x6699a4ef6e7b76499c6cd68443455a3584e505b1da43cf82e6efaef41f5e1d8a"
25+
GENESIS_STATEROOT = "0x0373244015ce5fa583ed6e575b7a22c39a542233a62d2bd47c37fd1a2b035366"
2626
TEST_PRIVATE_KEY = "cece4f25ac74deb1468965160c7185e07dff413f23fcadb611b05ca37ab0a52e"
2727
TEST_TO_ADDRESS = "0x944fDcD1c868E3cC566C78023CcB38A32cDA836E"
2828
)

execution/evm/test/test_helpers.go

Lines changed: 96 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package test
55
import (
66
"context"
77
"encoding/hex"
8+
"encoding/json"
89
"fmt"
910
mathrand "math/rand"
1011
"net/http"
@@ -79,51 +80,115 @@ func SetupTestRethNode(t testing.TB, client types.TastoraDockerClient, networkID
7980
// waitForRethContainer waits for the Reth container to be ready by polling the provided endpoints with JWT authentication.
8081
func waitForRethContainer(t testing.TB, jwtSecret, ethURL, engineURL string) error {
8182
t.Helper()
82-
client := &http.Client{Timeout: 100 * time.Millisecond}
83+
84+
secret, err := decodeSecret(jwtSecret)
85+
if err != nil {
86+
return err
87+
}
88+
authToken, err := getAuthToken(secret)
89+
if err != nil {
90+
return err
91+
}
92+
93+
client := &http.Client{Timeout: 500 * time.Millisecond}
8394
timer := time.NewTimer(30 * time.Second)
8495
defer timer.Stop()
96+
var lastErr error
8597
for {
8698
select {
8799
case <-timer.C:
100+
if lastErr != nil {
101+
return fmt.Errorf("timeout waiting for reth container to be ready: %w", lastErr)
102+
}
88103
return fmt.Errorf("timeout waiting for reth container to be ready")
89104
default:
90-
rpcReq := strings.NewReader(`{"jsonrpc":"2.0","method":"net_version","params":[],"id":1}`)
91-
resp, err := client.Post(ethURL, "application/json", rpcReq)
105+
genesisHash, err := getGenesisHash(client, ethURL)
106+
if err == nil {
107+
err = waitForEngineForkchoice(client, engineURL, authToken, genesisHash)
108+
}
92109
if err == nil {
93-
if err := resp.Body.Close(); err != nil {
94-
return fmt.Errorf("failed to close response body: %w", err)
95-
}
96-
if resp.StatusCode == http.StatusOK {
97-
req, err := http.NewRequest("POST", engineURL, strings.NewReader(`{"jsonrpc":"2.0","method":"engine_getClientVersionV1","params":[],"id":1}`))
98-
if err != nil {
99-
return err
100-
}
101-
req.Header.Set("Content-Type", "application/json")
102-
secret, err := decodeSecret(jwtSecret)
103-
if err != nil {
104-
return err
105-
}
106-
authToken, err := getAuthToken(secret)
107-
if err != nil {
108-
return err
109-
}
110-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken))
111-
resp, err := client.Do(req)
112-
if err == nil {
113-
if err := resp.Body.Close(); err != nil {
114-
return fmt.Errorf("failed to close response body: %w", err)
115-
}
116-
if resp.StatusCode == http.StatusOK {
117-
return nil
118-
}
119-
}
120-
}
110+
return nil
121111
}
112+
lastErr = err
122113
time.Sleep(100 * time.Millisecond)
123114
}
124115
}
125116
}
126117

118+
type jsonRPCError struct {
119+
Code int `json:"code"`
120+
Message string `json:"message"`
121+
}
122+
123+
func getGenesisHash(client *http.Client, ethURL string) (string, error) {
124+
rpcReq := strings.NewReader(`{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0",false],"id":1}`)
125+
resp, err := client.Post(ethURL, "application/json", rpcReq)
126+
if err != nil {
127+
return "", err
128+
}
129+
defer func() { _ = resp.Body.Close() }()
130+
131+
if resp.StatusCode != http.StatusOK {
132+
return "", fmt.Errorf("eth endpoint returned status %d", resp.StatusCode)
133+
}
134+
135+
var rpcResp struct {
136+
Result struct {
137+
Hash string `json:"hash"`
138+
} `json:"result"`
139+
Error *jsonRPCError `json:"error,omitempty"`
140+
}
141+
if err := json.NewDecoder(resp.Body).Decode(&rpcResp); err != nil {
142+
return "", fmt.Errorf("decode genesis block response: %w", err)
143+
}
144+
if rpcResp.Error != nil {
145+
return "", fmt.Errorf("eth_getBlockByNumber failed: %s", rpcResp.Error.Message)
146+
}
147+
if rpcResp.Result.Hash == "" {
148+
return "", fmt.Errorf("eth_getBlockByNumber returned empty genesis hash")
149+
}
150+
return rpcResp.Result.Hash, nil
151+
}
152+
153+
func waitForEngineForkchoice(client *http.Client, engineURL, authToken, genesisHash string) error {
154+
body := fmt.Sprintf(`{"jsonrpc":"2.0","method":"engine_forkchoiceUpdatedV3","params":[{"headBlockHash":%q,"safeBlockHash":%q,"finalizedBlockHash":%q},null],"id":1}`, genesisHash, genesisHash, genesisHash)
155+
req, err := http.NewRequest("POST", engineURL, strings.NewReader(body))
156+
if err != nil {
157+
return err
158+
}
159+
req.Header.Set("Content-Type", "application/json")
160+
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken))
161+
162+
resp, err := client.Do(req)
163+
if err != nil {
164+
return err
165+
}
166+
defer func() { _ = resp.Body.Close() }()
167+
168+
if resp.StatusCode != http.StatusOK {
169+
return fmt.Errorf("engine endpoint returned status %d", resp.StatusCode)
170+
}
171+
172+
var rpcResp struct {
173+
Result struct {
174+
PayloadStatus struct {
175+
Status string `json:"status"`
176+
} `json:"payloadStatus"`
177+
} `json:"result"`
178+
Error *jsonRPCError `json:"error,omitempty"`
179+
}
180+
if err := json.NewDecoder(resp.Body).Decode(&rpcResp); err != nil {
181+
return fmt.Errorf("decode engine forkchoice response: %w", err)
182+
}
183+
if rpcResp.Error != nil {
184+
return fmt.Errorf("engine_forkchoiceUpdatedV3 failed: %s", rpcResp.Error.Message)
185+
}
186+
if rpcResp.Result.PayloadStatus.Status != "VALID" {
187+
return fmt.Errorf("engine forkchoice status %s", rpcResp.Result.PayloadStatus.Status)
188+
}
189+
return nil
190+
}
191+
127192
// decodeSecret decodes a hex-encoded JWT secret string into a byte slice.
128193
func decodeSecret(jwtSecret string) ([]byte, error) {
129194
secret, err := hex.DecodeString(strings.TrimPrefix(jwtSecret, "0x"))

0 commit comments

Comments
 (0)