From 8201498bb0f475c2777ede6fa6dbd5bb1633cdab Mon Sep 17 00:00:00 2001 From: Victor Yves Crispim Date: Fri, 8 Mar 2024 15:54:11 -0300 Subject: [PATCH 1/2] feat: change CARTESI_BLOCKCHAIN_ID to uint64 This change is meant to comply with the Ethereum JSON-RPC API specification --- CHANGELOG.md | 6 ++++++ docs/config.md | 2 +- internal/config/config.go | 6 ++++++ internal/config/generate/Config.toml | 2 +- internal/config/get.go | 4 ++-- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index beeaacfac..d4d68347c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +## Changed + +- Changed CARTESI_BLOCKCHAIN_ID type from int to uint64 + ## [1.3.0] 2024-02-09 ### Added diff --git a/docs/config.md b/docs/config.md index 80d986e81..8d2c6b3c7 100644 --- a/docs/config.md +++ b/docs/config.md @@ -78,7 +78,7 @@ HTTP endpoint for the blockchain RPC provider. An unique identifier representing a blockchain network. -* **Type:** `int` +* **Type:** `uint64` ## `CARTESI_BLOCKCHAIN_IS_LEGACY` diff --git a/internal/config/config.go b/internal/config/config.go index 717cedd51..815b0019c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -30,6 +30,11 @@ func toInt64FromString(s string) (int64, error) { return strconv.ParseInt(s, 10, 64) } +func toUint64FromString(s string) (uint64, error) { + value, err := strconv.ParseUint(s, 10, 64) + return value, err +} + func toStringFromString(s string) (string, error) { return s, nil } @@ -42,6 +47,7 @@ func toDurationFromSeconds(s string) (time.Duration, error) { var ( toBool = strconv.ParseBool toInt = strconv.Atoi + toUint64 = toUint64FromString toInt64 = toInt64FromString toString = toStringFromString toDuration = toDurationFromSeconds diff --git a/internal/config/generate/Config.toml b/internal/config/generate/Config.toml index 5901676b5..908e872fa 100644 --- a/internal/config/generate/Config.toml +++ b/internal/config/generate/Config.toml @@ -60,7 +60,7 @@ At the end of each epoch, the node will send claims to the blockchain.""" # [blockchain.CARTESI_BLOCKCHAIN_ID] -go-type = "int" +go-type = "uint64" description = """ An unique identifier representing a blockchain network.""" diff --git a/internal/config/get.go b/internal/config/get.go index f3ce1a792..593e1ecb5 100644 --- a/internal/config/get.go +++ b/internal/config/get.go @@ -54,8 +54,8 @@ func GetCartesiBlockchainHttpEndpoint() string { return v } -func GetCartesiBlockchainId() int { - v := get("CARTESI_BLOCKCHAIN_ID", "", false, false, toInt) +func GetCartesiBlockchainId() uint64 { + v := get("CARTESI_BLOCKCHAIN_ID", "", false, false, toUint64) return v } From 5580389c9cf5c16579f1ebeb63e79332f5e3dfaf Mon Sep 17 00:00:00 2001 From: Victor Yves Crispim Date: Thu, 7 Mar 2024 16:17:28 -0300 Subject: [PATCH 2/2] feat: validate chain id --- CHANGELOG.md | 4 ++ cmd/cartesi-rollups-node/chainid.go | 46 +++++++++++++++++++++++ cmd/cartesi-rollups-node/chainid_test.go | 48 ++++++++++++++++++++++++ cmd/cartesi-rollups-node/main.go | 8 ++++ 4 files changed, 106 insertions(+) create mode 100644 cmd/cartesi-rollups-node/chainid.go create mode 100644 cmd/cartesi-rollups-node/chainid_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index d4d68347c..e41f824b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added verification to ensure CARTESI_BLOCKCHAIN_ID matches the id returned from the Ethereum node + ## Changed - Changed CARTESI_BLOCKCHAIN_ID type from int to uint64 diff --git a/cmd/cartesi-rollups-node/chainid.go b/cmd/cartesi-rollups-node/chainid.go new file mode 100644 index 000000000..f7f7d7507 --- /dev/null +++ b/cmd/cartesi-rollups-node/chainid.go @@ -0,0 +1,46 @@ +// (c) Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 (see LICENSE) + +package main + +import ( + "context" + "fmt" + "time" + + "github.com/cartesi/rollups-node/internal/config" + "github.com/ethereum/go-ethereum/ethclient" +) + +const defaultTimeout = 3 * time.Second + +// 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(ctx context.Context, chainId uint64, ethereumNodeAddr string) error { + remoteChainId, err := getChainId(ctx, 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(ctx context.Context, ethereumNodeAddr string) (uint64, error) { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + + client, err := ethclient.Dial(ethereumNodeAddr) + if err != nil { + return 0, fmt.Errorf("Failed to create RPC client: %v", err) + } + chainId, err := client.ChainID(ctx) + if err != nil { + return 0, fmt.Errorf("Failed to get chain id: %v", err) + } + return chainId.Uint64(), nil +} diff --git a/cmd/cartesi-rollups-node/chainid_test.go b/cmd/cartesi-rollups-node/chainid_test.go new file mode 100644 index 000000000..f8e5dede3 --- /dev/null +++ b/cmd/cartesi-rollups-node/chainid_test.go @@ -0,0 +1,48 @@ +// (c) Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 (see LICENSE) + +package main + +import ( + "context" + "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 := uint64(11111) + + err := validateChainId(context.Background(), 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 := uint64(31337) + + err := validateChainId(context.Background(), localChainId, ts.URL) + + s.Nil(err) +} diff --git a/cmd/cartesi-rollups-node/main.go b/cmd/cartesi-rollups-node/main.go index b9b7cab68..c8ef42e36 100644 --- a/cmd/cartesi-rollups-node/main.go +++ b/cmd/cartesi-rollups-node/main.go @@ -20,6 +20,14 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() + if err := validateChainId( + ctx, + config.GetCartesiBlockchainId(), + config.GetCartesiBlockchainHttpEndpoint(), + ); err != nil { + config.ErrorLogger.Fatal(err) + } + sunodoValidatorEnabled := config.GetCartesiExperimentalSunodoValidatorEnabled() if !sunodoValidatorEnabled { // add Redis first