Skip to content

Commit

Permalink
feat: validate chain id
Browse files Browse the repository at this point in the history
  • Loading branch information
torives committed Mar 8, 2024
1 parent 1910694 commit 49b1d6c
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 0 deletions.
73 changes: 73 additions & 0 deletions cmd/cartesi-rollups-node/chainid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

package main

import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"

"github.com/cartesi/rollups-node/internal/config"
)

// Checks if the chain id from the configuration matches the chain id reported
// by the Ethereum node. If they don't, it returns an error.
func validateChainId(chainId uint, ethereumNodeAddr string) error {
remoteChainId, err := getChainId(ethereumNodeAddr)
if err != nil {
config.ErrorLogger.Printf("Couldn't validate chainId: %v\n", err)
} else if chainId != remoteChainId {
return fmt.Errorf(
"chainId mismatch. Expected %v but Ethereum node returned %v",
chainId,
remoteChainId,
)
}
return nil
}

func getChainId(ethereumNodeAddr string) (uint, error) {
// create and send the request
requestBody := strings.NewReader(`{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":67}`)
resp, err := http.Post(ethereumNodeAddr, "application/json", requestBody)
if err != nil {
return 0, err
}
defer resp.Body.Close()

// parse the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, err
}
var chainIdResponse *GetChainIdResponse
err = json.Unmarshal(body, &chainIdResponse)
if err != nil {
return 0, fmt.Errorf("Failed to parse response: %v", err)
}

// handle the response
if chainIdResponse.Error != nil {
return 0, fmt.Errorf("Failed to get chainId: %v", chainIdResponse.Error.Message)
}
chainId, err := strconv.ParseUint(chainIdResponse.Result[2:], 16, 64)
if err != nil {
return 0, fmt.Errorf("Failed to parse chainId: %v", err)
}
return uint(chainId), nil
}

type GetChainIdResponse struct {
// The chainId encoded as a hex string prefixed with "0x"
Result string `json:"result"`
Error *GetChainIdError `json:"error"`
}

type GetChainIdError struct {
Code int `json:"code"`
Message string `json:"message"`
}
47 changes: 47 additions & 0 deletions cmd/cartesi-rollups-node/chainid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

package main

import (
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/suite"
)

type ValidateChainIdSuite struct {
suite.Suite
}

func TestValidateChainId(t *testing.T) {
suite.Run(t, new(ValidateChainIdSuite))
}

func (s *ValidateChainIdSuite) TestItFailsIfChainIdsDoNotMatch() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `{"jsonrpc":"2.0","id":67,"result":"0x7a69"}`)
}))
defer ts.Close()
localChainId := uint(11111)

err := validateChainId(localChainId, ts.URL)

s.NotNil(err)
}

func (s *ValidateChainIdSuite) TestItReturnsNilIfChainIdsMatch() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `{"jsonrpc":"2.0","id":67,"result":"0x7a69"}`)
}))
defer ts.Close()
localChainId := uint(31337)

err := validateChainId(localChainId, ts.URL)

s.Nil(err)
}
7 changes: 7 additions & 0 deletions cmd/cartesi-rollups-node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ func main() {
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()

if err := validateChainId(
config.GetCartesiBlockchainId(),
config.GetCartesiBlockchainHttpEndpoint(),
); err != nil {
config.ErrorLogger.Fatal(err)
}

sunodoValidatorEnabled := config.GetCartesiExperimentalSunodoValidatorEnabled()
if !sunodoValidatorEnabled {
// add Redis first
Expand Down

0 comments on commit 49b1d6c

Please sign in to comment.