diff options
Diffstat (limited to 'internal/checkpoint/checkpoint_test.go')
| -rw-r--r-- | internal/checkpoint/checkpoint_test.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/internal/checkpoint/checkpoint_test.go b/internal/checkpoint/checkpoint_test.go new file mode 100644 index 0000000..9ca9b2a --- /dev/null +++ b/internal/checkpoint/checkpoint_test.go @@ -0,0 +1,105 @@ +package checkpoint + +import ( + "crypto/ed25519" + "crypto/rand" + "encoding/base64" + "os" + "path/filepath" + "testing" + + "github.com/Fuwn/plutia/internal/storage" + "github.com/Fuwn/plutia/internal/types" +) + +func TestBuildAndStoreCheckpoint(t *testing.T) { + tmp := t.TempDir() + store, err := storage.OpenPebble(tmp) + if err != nil { + t.Fatalf("open pebble: %v", err) + } + defer store.Close() + + pub, priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatalf("generate key: %v", err) + } + keyPath := filepath.Join(tmp, "mirror.key") + if err := os.WriteFile(keyPath, []byte(base64.RawURLEncoding.EncodeToString(priv)), 0o600); err != nil { + t.Fatalf("write key: %v", err) + } + + mgr := NewManager(store, tmp, keyPath) + states := []types.StateV1{ + {Version: 1, DID: "did:plc:a", ChainTipHash: "tip-a"}, + {Version: 1, DID: "did:plc:b", ChainTipHash: "tip-b"}, + } + cp, err := mgr.BuildAndStore(42, states, []string{"abc", "def"}) + if err != nil { + t.Fatalf("build checkpoint: %v", err) + } + if cp.Signature == "" || cp.CheckpointHash == "" { + t.Fatalf("expected signed checkpoint") + } + payload, err := marshalCheckpointPayload(cp) + if err != nil { + t.Fatalf("marshal payload: %v", err) + } + rawSig, err := base64.RawURLEncoding.DecodeString(cp.Signature) + if err != nil { + t.Fatalf("decode signature: %v", err) + } + if !ed25519.Verify(pub, payload, rawSig) { + t.Fatalf("signature verification failed") + } + + stored, ok, err := store.GetCheckpoint(cp.Sequence) + if err != nil || !ok { + t.Fatalf("stored checkpoint missing: ok=%v err=%v", ok, err) + } + if stored.CheckpointHash != cp.CheckpointHash { + t.Fatalf("checkpoint hash mismatch") + } +} + +func TestCheckpointRootStability(t *testing.T) { + tmp := t.TempDir() + store, err := storage.OpenPebble(tmp) + if err != nil { + t.Fatalf("open pebble: %v", err) + } + defer store.Close() + + if err := store.PutState(types.StateV1{Version: 1, DID: "did:plc:b", ChainTipHash: "tip-b"}); err != nil { + t.Fatalf("put state b: %v", err) + } + if err := store.PutState(types.StateV1{Version: 1, DID: "did:plc:a", ChainTipHash: "tip-a"}); err != nil { + t.Fatalf("put state a: %v", err) + } + + _, priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatalf("generate key: %v", err) + } + keyPath := filepath.Join(tmp, "mirror.key") + if err := os.WriteFile(keyPath, []byte(base64.RawURLEncoding.EncodeToString(priv)), 0o600); err != nil { + t.Fatalf("write key: %v", err) + } + + mgr := NewManager(store, tmp, keyPath) + cp1, err := mgr.BuildAndStoreFromStore(100, []string{"abc"}) + if err != nil { + t.Fatalf("build checkpoint 1: %v", err) + } + cp2, err := mgr.BuildAndStoreFromStore(200, []string{"abc"}) + if err != nil { + t.Fatalf("build checkpoint 2: %v", err) + } + + if cp1.DIDMerkleRoot != cp2.DIDMerkleRoot { + t.Fatalf("did root changed for identical state: %s vs %s", cp1.DIDMerkleRoot, cp2.DIDMerkleRoot) + } + if cp1.BlockMerkleRoot != cp2.BlockMerkleRoot { + t.Fatalf("block root changed for identical block set: %s vs %s", cp1.BlockMerkleRoot, cp2.BlockMerkleRoot) + } +} |