Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

manifest: cluster hash mismatch error #2414

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 45 additions & 17 deletions cluster/manifest/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,75 @@
package manifest

import (
"bytes"
"encoding/hex"
"encoding/json"
"os"

"google.golang.org/protobuf/proto"

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/app/z"
"github.com/obolnetwork/charon/cluster"
manifestpb "github.com/obolnetwork/charon/cluster/manifestpb/v1"
)

// Load loads a cluster from disk and returns true if cluster was loaded from a legacy lock file.
// It supports reading from both cluster manifest and legacy lock files.
// If both files are provided, it first reads the manifest file before reading the legacy lock file.
// Load loads a cluster from disk by reading both the cluster manifest and legacy lock files.
// If both files are loaded successfully and the cluster hashes from the manifest and legacy lock files match,
// the cluster read from the manifest file is returned. Otherwise, an error is returned indicating a mismatch
// between the cluster hashes. If loading from the manifest file succeeds, the cluster read from the manifest file
// is returned. Otherwise, the cluster read from the legacy lock file is returned.
func Load(manifestFile, legacyLockFile string, lockCallback func(cluster.Lock) error) (*manifestpb.Cluster, error) {
b, err := os.ReadFile(manifestFile)
if err == nil {
manifest := new(manifestpb.Cluster)
if err := proto.Unmarshal(b, manifest); err != nil {
return nil, errors.Wrap(err, "unmarshal cluster manifest")
manifestCluster, err1 := loadClusterManifest(manifestFile)
legacyCluster, err2 := loadLegacyLock(legacyLockFile, lockCallback)

switch {
case err1 == nil && err2 == nil:
// Both files loaded successfully, check if cluster hashes match
if !bytes.Equal(manifestCluster.InitialMutationHash, legacyCluster.InitialMutationHash) {
return nil, errors.New("manifest and legacy cluster hashes don't match",
z.Str("manifest_hash", hex.EncodeToString(manifestCluster.InitialMutationHash)),
z.Str("legacy_hash", hex.EncodeToString(legacyCluster.InitialMutationHash)))
}

return manifest, nil
return manifestCluster, nil
case err1 == nil:
// Cluster manifest loaded successfully
return manifestCluster, nil
case err2 == nil:
// Legacy cluster lock loaded successfully
return legacyCluster, nil
default:
// None of the files were loaded successfully, so return an error
return nil, errors.New("couldn't load cluster either from manifest or legacy lock file", z.Err(err1), z.Err(err2))
}
}

b, err = os.ReadFile(legacyLockFile)
// loadClusterManifest loads a cluster from disk using the provided manifest file.
func loadClusterManifest(manifestFile string) (*manifestpb.Cluster, error) {
b, err := os.ReadFile(manifestFile)
if err != nil {
return nil, errors.Wrap(err, "read legacy lock file")
return nil, errors.Wrap(err, "read manifest file")
}

m, err := loadLegacyLock(b, lockCallback)
if err != nil {
return nil, errors.Wrap(err, "load legacy lock")
manifest := new(manifestpb.Cluster)
xenowits marked this conversation as resolved.
Show resolved Hide resolved
if err = proto.Unmarshal(b, manifest); err != nil {
return nil, errors.Wrap(err, "unmarshal cluster manifest")
}

return m, nil
return manifest, nil
}

func loadLegacyLock(input []byte, lockCallback func(cluster.Lock) error) (*manifestpb.Cluster, error) {
// loadLegacyLock loads a cluster from disk using the provided legacy lock file.
func loadLegacyLock(legacyLockFile string, lockCallback func(cluster.Lock) error) (*manifestpb.Cluster, error) {
b, err := os.ReadFile(legacyLockFile)
if err != nil {
return nil, errors.Wrap(err, "read legacy lock file")
}

var lock cluster.Lock

if err := json.Unmarshal(input, &lock); err != nil {
if err := json.Unmarshal(b, &lock); err != nil {
return nil, errors.Wrap(err, "unmarshal legacy lock")
}

Expand Down
8 changes: 7 additions & 1 deletion cluster/manifest/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestLoad(t *testing.T) {
}{
{
name: "no file",
errorMsg: "read legacy lock",
errorMsg: "couldn't load cluster either from manifest or legacy lock file",
},
{
name: "only manifest",
Expand All @@ -69,6 +69,12 @@ func TestLoad(t *testing.T) {
manifestFile: manifestFile,
legacyLockFile: legacyLockFile,
},
{
name: "mismatching cluster hashes",
manifestFile: manifestFile,
legacyLockFile: "testdata/lock2.json",
errorMsg: "manifest and legacy cluster hashes don't match",
},
}

for _, tt := range tests {
Expand Down