syntax = "proto3";

package quilibrium.node.clock.pb;

option go_package = "source.quilibrium.com/quilibrium/monorepo/node/protobufs";

import "channel.proto";
import "keys.proto";

// Represents a clock frame for a given filter. Clock frames are the primary
// sequencing mechanism upon which the network derives consensus. As the master
// pulse clock, this provides deterministic but random leader election. At the
// data pulse clock level, this provides the same, within a quorum for data
// sequencers.
message ClockFrame {
  // The filter is used as a domain separator for input, but in the context of
  // verifiable delay functions, is simply prepended to the input field as input
  // for the VDF.
  bytes filter = 1;
  // A strictly monotonically-increasing frame number. Used for culling old
  // frames past a configurable cutoff point.
  uint64 frame_number = 2;
  // The self-reported timestamp from the proof publisher, encoded as an int64
  // of the Unix epoch in milliseconds. Should be good until
  // 292278994-08-17 07:12:55.807, at which point, this is someone else's
  // problem. Timestamps are imperfect, but smoothed in a rolling window to
  // ensure a network and quorum-stable difficulty adjustment. Anomalies are
  // bounded such that a timestamp beyond ten times the average issuance rate
  // is discarded in preference to the runner up electees, unless there is
  // simply no alternative available (for example, if a network outage occurred
  // from an upgrade or bug).
  int64 timestamp = 3;
  // The difficulty level used for the frame. Difficulty is calculated based on
  // the previous 60 timestamps correlated with difficulties, such that the
  // interval smooths out to align to the type-defined rate. This is expected to
  // increase subtly with clock speed and future hardware implementations, but
  // due to incentive alignment associated with data proofs, not fastest clock
  // in the west, should be gradual.
  uint32 difficulty = 4;
  // The selector value of the previous frame's output, produced as a Poseidon
  // hash of the output.
  bytes parent_selector = 5;
  // The input data used for the VDF proof. For the master pulse clock, this is
  // the concatenation of the filter, frame number, difficulty, previous frame's
  // output, and the rolled state proof commitment input. For the data pulse
  // clocks, this is the concatenation of the filter, frame number, timestamp,
  // difficulty, issuer address, previous frame's output, along with data
  // mutation and availability proofs. Elements that are also in the fields of
  // the clock frame are not included in this field due to redundancy. For the
  // ceremony phase, this is a singular clock fusing master and data pulses.
  bytes input = 6;
  // The output data from the VDF, serialized as bytes. For Wesolowski, this is
  // an encoding of the 258 byte Y value concatenated with the 258 byte proof
  // value.
  bytes output = 7;
  // Any aggregate proofs to be rolled into the committed clock frame.
  repeated quilibrium.node.channel.pb.InclusionAggregateProof aggregate_proofs = 8;
  // The signature of the proof issuer.
  oneof public_key_signature {
    quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 9;
  }
}

message ClockFrameParentSelectors {
  uint64 frame_number = 1;
  bytes parent_selector = 2;
}

// Represents a request for a range of clock frames. Used to stay synchronized
// to the latest state.
message ClockFramesRequest {
  // The filter is used as a domain separator for input to the frames.
  bytes filter = 1;
  // The earliest frame in the range requested.
  uint64 from_frame_number = 2;
  // The latest frame in the range requested, if provided. Capped to a maximum
  // size of 128 frames.
  uint64 to_frame_number = 3;
  // The optional parent selector. If provided, will perform a check to confirm
  // continuity, otherwise, will rewind the sync head to the beginning.
  bytes parent_selector = 4;
  // The optional range selectors. If provided, will perform a check against
  // them to optimize the provided deltas.
  repeated ClockFrameParentSelectors range_parent_selectors = 5;
}

message ClockFramesPreflight {
  repeated ClockFrameParentSelectors range_parent_selectors = 1;
}

// Represents a response for a range of clock frames. Used to stay synchronized
// to the latest state.
message ClockFramesResponse {
  // The filter is used as a domain separator for input to the frames.
  bytes filter = 1;
  // The earliest frame in the range response. Paginated to a maximum size of
  // 128 frames per response.
  uint64 from_frame_number = 2;
  // The latest frame in the range response.
  uint64 to_frame_number = 3;
  // The set of clock frames within the provided range.
  repeated ClockFrame clock_frames = 4;
}