diff --git a/cmd/cartesi-rollups-node/machinehash.go b/cmd/cartesi-rollups-node/machinehash.go new file mode 100644 index 000000000..14bf6fe7d --- /dev/null +++ b/cmd/cartesi-rollups-node/machinehash.go @@ -0,0 +1,74 @@ +// (c) Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 (see LICENSE) + +package main + +import ( + "fmt" + "os" + "path" + + "github.com/cartesi/rollups-node/pkg/contracts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" +) + +const HASH_SIZE = 32 + +// Validates if the hash from the Cartesi Machine at machineDir matches the template hash onchain. +// It returns an error if it doesn't. +func validateMachineHash( + machineDir string, + applicationAddress string, + ethereumNodeAddr string, +) error { + offchainHash, err := getHash(machineDir) + if err != nil { + return err + } + onchainHash, err := getTemplateHash(applicationAddress, ethereumNodeAddr) + if err != nil { + return err + } + if offchainHash != onchainHash { + return fmt.Errorf( + "cartesi machine hash mismatch: expected %v but got %v", + onchainHash, + offchainHash, + ) + } + return nil +} + +// Reads the Cartesi Machine hash from machineDir. Returns the hash as +// a hex string or an error +func getHash(machineDir string) (string, error) { + path := path.Join(machineDir, "hash") + hash, err := os.ReadFile(path) + if err != nil { + return "", err + } else if len(hash) != HASH_SIZE { + return "", fmt.Errorf("Malformed hash: expected %v bytes, read %v", HASH_SIZE, len(hash)) + } + return common.Bytes2Hex(hash), nil +} + +// TODO: documentation +func getTemplateHash(applicationAddress string, ethereumNodeAddr string) (string, error) { + client, err := ethclient.Dial(ethereumNodeAddr) + if err != nil { + return "", err + } + cartesiApplication, err := contracts.NewCartesiDAppCaller( + common.HexToAddress(applicationAddress), + client, + ) + if err != nil { + return "", err + } + hash, err := cartesiApplication.GetTemplateHash(nil) + if err != nil { + return "", err + } + return common.Bytes2Hex(hash[:]), nil +} diff --git a/cmd/cartesi-rollups-node/main.go b/cmd/cartesi-rollups-node/main.go index b9b7cab68..4e7009ccd 100644 --- a/cmd/cartesi-rollups-node/main.go +++ b/cmd/cartesi-rollups-node/main.go @@ -20,6 +20,16 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() + if !config.GetCartesiFeatureDisableMachineHashCheck() { + if err := validateMachineHash( + config.GetCartesiSnapshotDir(), + config.GetCartesiContractsApplicationAddress(), + config.GetCartesiBlockchainHttpEndpoint(), + ); err != nil { + config.ErrorLogger.Fatal(err) + } + } + sunodoValidatorEnabled := config.GetCartesiExperimentalSunodoValidatorEnabled() if !sunodoValidatorEnabled { // add Redis first