package hostexec import ( "bytes" "context" "errors" "os" "github.com/carlosframework/platform/internal/rootparticipation" "github.com/carlosframework/platform/internal/rootstate" ) func ReadRoot(ctx context.Context, store rootstate.Store, clock Clock, q ExecutionRequest, serving bool) (ExecutionRecord, error) { var r ExecutionRecord if store == nil || clock == nil { return r, ErrState } if _, err := store.Read("update.json"); !errors.Is(err, os.ErrNotExist) { return r, ErrLost } ledger := rootparticipation.Ledger{State: store} census, err := ledger.Census() if err != nil || census.NeverEnrolled { return r, errors.Join(err, ErrState) } raw, err := store.Read(q.Host + ".json") if serving { if errors.Is(err, os.ErrNotExist) { return r, nil } if err != nil { return r, err } if rootparticipation.Decode(raw, &r) != nil || r.Schema != 1 || !r.Request.Valid() || r.Token == "" || r.Replay == nil || r.Request.Host != q.Host || r.Status != "settled" || r.Authority.Migration != census.Migration || r.Authority.Box != census.Box || r.Authority.Enrollment != census.Enrollment { return r, ErrLost } return r, nil } if err != nil { return r, err } if rootparticipation.Decode(raw, &r) != nil || r.Schema != 1 || !r.Request.Valid() || !sameExecution(q, r) || r.Status != "active" || r.Authority.ParticipationOnly || r.Authority.Installation == "" || r.Authority.Migration != census.Migration || r.Authority.Box != census.Box || r.Authority.Enrollment != census.Enrollment || r.Token == "" { return r, ErrLost } boot, err := BootID() if err != nil || r.Peer.KernelBootID != boot { return r, ErrLost } _, now, err := clock.Now() if err != nil || now >= r.SafeUntil { return r, ErrLost } if err = ControllerAlive(ctx, r.Peer); err != nil { return r, err } if err := ctx.Err(); err != nil { return r, err } alive, err := rootstate.LiveHeld(store, q.Host+".live") if err != nil || !alive { return r, errors.Join(ErrLost, err) } again, err := store.Read(q.Host + ".json") if err != nil || !bytes.Equal(raw, again) { return r, ErrLost } _, now, err = clock.Now() if err != nil || now >= r.SafeUntil { return r, ErrLost } return r, nil }