diff options
| author | Fuwn <[email protected]> | 2026-02-26 15:41:45 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-26 15:41:45 -0800 |
| commit | fec9114caaa7d274e524793d5eb0cf2ef2c5af11 (patch) | |
| tree | 0897394ccdfaf6633e1a4ca8eb02bff49bb93c00 /internal/state | |
| parent | feat: add read-only PLC API compatibility endpoints (diff) | |
| download | plutia-test-fec9114caaa7d274e524793d5eb0cf2ef2c5af11.tar.xz plutia-test-fec9114caaa7d274e524793d5eb0cf2ef2c5af11.zip | |
feat: Apply Iku formatting
Diffstat (limited to 'internal/state')
| -rw-r--r-- | internal/state/engine.go | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/internal/state/engine.go b/internal/state/engine.go index 4ecdaca..0f5caad 100644 --- a/internal/state/engine.go +++ b/internal/state/engine.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "time" - "github.com/Fuwn/plutia/internal/config" "github.com/Fuwn/plutia/internal/storage" "github.com/Fuwn/plutia/internal/types" @@ -21,41 +20,55 @@ func New(store storage.Store, mode string) *Engine { 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 } @@ -64,12 +77,16 @@ func ComputeNextState(op types.ParsedOperation, existing *types.StateV1) (types. 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, @@ -79,9 +96,11 @@ func ComputeNextState(op types.ParsedOperation, existing *types.StateV1) (types. 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 } @@ -89,31 +108,39 @@ 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{ { @@ -123,6 +150,7 @@ func materializeDIDDocument(did string, payload map[string]any) ([]byte, error) }, } } + if signingKey, ok := payload["signingKey"].(string); ok && signingKey != "" { doc["verificationMethod"] = []map[string]any{ { @@ -134,10 +162,13 @@ func materializeDIDDocument(did string, payload map[string]any) ([]byte, error) } 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) } @@ -148,9 +179,11 @@ func extractRotationKeys(payload map[string]any) []string { if v == "" { return } + if _, ok := seen[v]; ok { return } + seen[v] = struct{}{} keys = append(keys, v) } @@ -162,11 +195,14 @@ func extractRotationKeys(payload map[string]any) []string { } } } + if recovery, ok := payload["recoveryKey"].(string); ok { add(recovery) } + if signing, ok := payload["signingKey"].(string); ok { add(signing) } + return keys } |