aboutsummaryrefslogtreecommitdiff
path: root/internal/state
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-26 14:46:02 -0800
committerFuwn <[email protected]>2026-02-26 14:48:52 -0800
commit0099d621e97b6048971fadb5c71918cc9f2b5a09 (patch)
treea38ba31585200bacd61f453ef7158de7f0aaf7a3 /internal/state
parentInitial commit (diff)
downloadplutia-test-0099d621e97b6048971fadb5c71918cc9f2b5a09.tar.xz
plutia-test-0099d621e97b6048971fadb5c71918cc9f2b5a09.zip
feat: initial Plutia release — verifiable high-performance PLC mirror (mirror + resolver modes)
Diffstat (limited to 'internal/state')
-rw-r--r--internal/state/engine.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/internal/state/engine.go b/internal/state/engine.go
new file mode 100644
index 0000000..4ecdaca
--- /dev/null
+++ b/internal/state/engine.go
@@ -0,0 +1,172 @@
+package state
+
+import (
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/Fuwn/plutia/internal/config"
+ "github.com/Fuwn/plutia/internal/storage"
+ "github.com/Fuwn/plutia/internal/types"
+)
+
+type Engine struct {
+ store storage.Store
+ mode string
+}
+
+func New(store storage.Store, mode string) *Engine {
+ return &Engine{store: store, mode: mode}
+}
+
+func (e *Engine) Apply(op types.ParsedOperation, blockRef *types.BlockRefV1) error {
+ existing, ok, err := e.store.GetState(op.DID)
+ if err != nil {
+ return fmt.Errorf("load state: %w", err)
+ }
+ var prior *types.StateV1
+ if ok {
+ prior = &existing
+ }
+ next, err := ComputeNextState(op, prior)
+ if err != nil {
+ return err
+ }
+ if pebbleStore, ok := e.store.(*storage.PebbleStore); ok {
+ includeOpRef := e.mode == config.ModeMirror && blockRef != nil
+ if err := pebbleStore.ApplyOperationBatch(next, blockRef, includeOpRef); err != nil {
+ return fmt.Errorf("apply operation batch: %w", err)
+ }
+ return nil
+ }
+ if err := e.store.PutState(next); err != nil {
+ return fmt.Errorf("put state: %w", err)
+ }
+ if err := e.store.SetChainHead(op.DID, op.Sequence); err != nil {
+ return fmt.Errorf("set chain head: %w", err)
+ }
+ if err := e.store.AddDIDSequence(op.DID, op.Sequence); err != nil {
+ return fmt.Errorf("append did sequence: %w", err)
+ }
+ if e.mode == config.ModeMirror && blockRef != nil {
+ if err := e.store.PutOpSeqRef(op.Sequence, *blockRef); err != nil {
+ return fmt.Errorf("put opseq ref: %w", err)
+ }
+ }
+ if err := e.store.SetGlobalSeq(op.Sequence); err != nil {
+ return fmt.Errorf("set global seq: %w", err)
+ }
+ return nil
+}
+
+func ComputeNextState(op types.ParsedOperation, existing *types.StateV1) (types.StateV1, error) {
+ if existing != nil && op.Sequence <= existing.LatestOpSeq {
+ if existing.ChainTipHash == op.CID {
+ return *existing, nil
+ }
+ return types.StateV1{}, fmt.Errorf("non-monotonic sequence for %s: got %d <= %d", op.DID, op.Sequence, existing.LatestOpSeq)
+ }
+ doc, err := materializeDIDDocument(op.DID, op.Payload)
+ if err != nil {
+ return types.StateV1{}, err
+ }
+ next := types.StateV1{
+ Version: 1,
+ DID: op.DID,
+ DIDDocument: doc,
+ ChainTipHash: op.CID,
+ LatestOpSeq: op.Sequence,
+ UpdatedAt: time.Now().UTC(),
+ }
+ next.RotationKeys = extractRotationKeys(op.Payload)
+ if len(next.RotationKeys) == 0 && existing != nil {
+ next.RotationKeys = append([]string(nil), existing.RotationKeys...)
+ }
+ return next, nil
+}
+
+func materializeDIDDocument(did string, payload map[string]any) ([]byte, error) {
+ for _, k := range []string{"did_document", "didDoc", "document", "didDocument"} {
+ if v, ok := payload[k]; ok {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return nil, fmt.Errorf("marshal did document field %s: %w", k, err)
+ }
+ return types.CanonicalizeJSON(b)
+ }
+ }
+ if v, ok := payload["alsoKnownAs"]; ok {
+ doc := map[string]any{
+ "id": did,
+ "alsoKnownAs": v,
+ }
+ b, err := json.Marshal(doc)
+ if err != nil {
+ return nil, fmt.Errorf("marshal derived did document: %w", err)
+ }
+ return types.CanonicalizeJSON(b)
+ }
+
+ doc := map[string]any{"id": did}
+ if typ, _ := payload["type"].(string); typ == "plc_tombstone" || typ == "tombstone" {
+ doc["deactivated"] = true
+ }
+ if handle, ok := payload["handle"].(string); ok && handle != "" {
+ doc["alsoKnownAs"] = []string{"at://" + handle}
+ }
+ if serviceEndpoint, ok := payload["service"].(string); ok && serviceEndpoint != "" {
+ doc["service"] = []map[string]any{
+ {
+ "id": "#atproto_pds",
+ "type": "AtprotoPersonalDataServer",
+ "serviceEndpoint": serviceEndpoint,
+ },
+ }
+ }
+ if signingKey, ok := payload["signingKey"].(string); ok && signingKey != "" {
+ doc["verificationMethod"] = []map[string]any{
+ {
+ "id": "#atproto",
+ "type": "Multikey",
+ "controller": did,
+ "publicKeyMultibase": signingKey,
+ },
+ }
+ doc["authentication"] = []string{"#atproto"}
+ }
+ b, err := json.Marshal(doc)
+ if err != nil {
+ return nil, fmt.Errorf("marshal synthesized did document: %w", err)
+ }
+ return types.CanonicalizeJSON(b)
+}
+
+func extractRotationKeys(payload map[string]any) []string {
+ keys := make([]string, 0, 4)
+ seen := map[string]struct{}{}
+ add := func(v string) {
+ if v == "" {
+ return
+ }
+ if _, ok := seen[v]; ok {
+ return
+ }
+ seen[v] = struct{}{}
+ keys = append(keys, v)
+ }
+
+ if arr, ok := payload["rotationKeys"].([]any); ok {
+ for _, v := range arr {
+ if s, ok := v.(string); ok {
+ add(s)
+ }
+ }
+ }
+ if recovery, ok := payload["recoveryKey"].(string); ok {
+ add(recovery)
+ }
+ if signing, ok := payload["signingKey"].(string); ok {
+ add(signing)
+ }
+ return keys
+}