syntax = "proto3";

package soma.rpc;

import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "soma/rpc/object.proto";
import "soma/rpc/object_reference.proto";

// A transaction.
message Transaction {

  // The digest of this Transaction.
  optional string digest = 1;

  optional TransactionKind kind = 2;
  optional string sender = 3;
  repeated ObjectReference gas_payment = 4;
}

// Transaction type.
message TransactionKind {
  oneof kind {
    // Transaction used to initialize the chain state.
    //
    // Only valid if in the genesis checkpoint (0) and if this is the very first transaction ever
    // executed on the chain.
    GenesisTransaction genesis = 1;

    // Consensus commit update.
    ConsensusCommitPrologue consensus_commit_prologue = 2;

    // System transaction used to end an epoch..
    ChangeEpoch change_epoch = 3;

    AddValidator add_validator = 4;

    RemoveValidator remove_validator = 5;

    ReportValidator report_validator = 6;

    UndoReportValidator undo_report_validator = 7;

    UpdateValidatorMetadata update_validator_metadata = 8;

    SetCommissionRate set_commission_rate = 9;

    TransferCoin transfer_coin = 10;

    PayCoins pay_coins = 11;

    TransferObjects transfer_objects = 12;

    AddStake add_stake = 13;

    WithdrawStake withdraw_stake = 14;

    // Model transactions
    CommitModel commit_model = 15;
    RevealModel reveal_model = 16;
    CommitModelUpdate commit_model_update = 17;
    RevealModelUpdate reveal_model_update = 18;
    AddStakeToModel add_stake_to_model = 19;
    SetModelCommissionRate set_model_commission_rate = 20;
    DeactivateModel deactivate_model = 21;
    ReportModel report_model = 22;
    UndoReportModel undo_report_model = 23;

    // Submission transactions
    SubmitData submit_data = 24;
    ClaimRewards claim_rewards = 25;
    ReportSubmission report_submission = 28;
    UndoReportSubmission undo_report_submission = 29;

    // Challenge transactions
    InitiateChallenge initiate_challenge = 26;
    // Field 27 was ResolveAudit (removed)
    ReportChallenge report_challenge = 30;
    UndoReportChallenge undo_report_challenge = 31;
    ClaimChallengeBond claim_challenge_bond = 32;
  }
}

message AddValidator {
  optional bytes pubkey_bytes = 1;
  optional bytes network_pubkey_bytes = 2;
  optional bytes worker_pubkey_bytes = 3;
  optional bytes net_address = 4;
  optional bytes p2p_address = 5;
  optional bytes primary_address = 6;
  optional bytes proxy_address = 7;
}

message RemoveValidator {
  optional bytes pubkey_bytes = 1;
}

message ReportValidator {
  optional string reportee = 1;
}

message UndoReportValidator {
  optional string reportee = 1;
}

message UpdateValidatorMetadata {
  optional bytes next_epoch_network_address = 1;
  optional bytes next_epoch_p2p_address = 2;
  optional bytes next_epoch_primary_address = 3;
  optional bytes next_epoch_proxy_address = 4;
  optional bytes next_epoch_protocol_pubkey = 5;
  optional bytes next_epoch_worker_pubkey = 6;
  optional bytes next_epoch_network_pubkey = 7;
}

message SetCommissionRate {
  optional uint64 new_rate = 1;
}

message TransferCoin {
  optional ObjectReference coin = 1;
  optional uint64 amount = 2;
  optional string recipient = 3;
}

message PayCoins {
  repeated ObjectReference coins = 1;
  repeated uint64 amounts = 2;
  repeated string recipients = 3;
}

message TransferObjects {
  repeated ObjectReference objects = 1;
  optional string recipient = 2;
}

message AddStake {
  optional string address = 1;
  optional ObjectReference coin_ref = 2;
  optional uint64 amount = 3;
}


message WithdrawStake {
  optional ObjectReference staked_soma = 1;
}

message Metadata {
  oneof version {
    MetadataV1 v1 = 1;
  }
}

message MetadataV1 {
  optional bytes checksum = 1;  // 32-byte digest
  optional uint64 size = 2;      // Size in bytes
}

message Manifest {
  oneof version {
    ManifestV1 v1 = 1;
  }
}

message ManifestV1 {
  optional string url = 1;
  optional Metadata metadata = 2;
}

// Model weights manifest: URL + metadata + decryption key.
// Used by RevealModel and RevealModelUpdate transactions, and by Model in system state.
message ModelWeightsManifest {
  optional Manifest manifest = 1;
  optional bytes decryption_key = 2;     // 32-byte AES-256 key
}

// Pending update to an active model's weights (commit phase).
message PendingModelUpdate {
  optional bytes weights_url_commitment = 1;  // 32-byte digest
  optional bytes weights_commitment = 2;      // 32-byte digest
  optional uint64 commit_epoch = 3;
}

// Model transaction messages

message CommitModel {
  optional string model_id = 1;
  optional bytes weights_url_commitment = 2;
  optional bytes weights_commitment = 3;
  optional uint64 architecture_version = 4;
  optional uint64 stake_amount = 5;
  optional uint64 commission_rate = 6;
  optional string staking_pool_id = 7;
}

message RevealModel {
  optional string model_id = 1;
  optional ModelWeightsManifest weights_manifest = 2;
  // Model embedding for stake-weighted KNN target selection (f32 values)
  repeated float embedding = 3;
}

message CommitModelUpdate {
  optional string model_id = 1;
  optional bytes weights_url_commitment = 2;
  optional bytes weights_commitment = 3;
}

message RevealModelUpdate {
  optional string model_id = 1;
  optional ModelWeightsManifest weights_manifest = 2;
  // Updated model embedding for stake-weighted KNN target selection (f32 values)
  repeated float embedding = 3;
}

message AddStakeToModel {
  optional string model_id = 1;
  optional ObjectReference coin_ref = 2;
  optional uint64 amount = 3;
}

message SetModelCommissionRate {
  optional string model_id = 1;
  optional uint64 new_rate = 2;
}

message DeactivateModel {
  optional string model_id = 1;
}

message ReportModel {
  optional string model_id = 1;
}

message UndoReportModel {
  optional string model_id = 1;
}

// Report a submission as fraudulent (validators only)
message ReportSubmission {
  optional string target_id = 1;
  // Optional challenger to attribute fraud to (for tally-based bond distribution)
  optional string challenger = 2;
}

// Undo a previous submission report
message UndoReportSubmission {
  optional string target_id = 1;
}


// System transaction used to change the epoch.
message ChangeEpoch {
  // The next (to become) epoch ID.
  optional uint64 epoch = 1;

  // Unix timestamp when epoch started.
  optional google.protobuf.Timestamp epoch_start_timestamp = 2;

  // The protocol version in effect in the new epoch.
  optional uint64 protocol_version = 3;

  // The total amount of fees charged during the epoch.
  optional uint64 fees = 4;

  /// Epoch randomness
  optional bytes epoch_randomness = 5;
}


// The genesis transaction.
message GenesisTransaction {
  // Set of genesis objects.
  repeated Object objects = 1;
}

// Consensus commit prologue system transaction.
message ConsensusCommitPrologue {
  // Epoch of the commit prologue transaction.
  optional uint64 epoch = 1;

  // Consensus round of the commit.
  optional uint64 round = 2;

  // The sub DAG index of the consensus commit. This field is populated if there
  // are multiple consensus commits per round.
  optional uint64 sub_dag_index = 3;

  // Unix timestamp from consensus.
  optional google.protobuf.Timestamp commit_timestamp = 4;

  // Digest of consensus output.
  optional string consensus_commit_digest = 5;

  // Digest of any additional state computed by the consensus handler.
  // Used to detect forking bugs as early as possible.
  optional string additional_state_digest = 6;
}

// Submit data to a target in the mining competition.
message SubmitData {
  // Target ID (ObjectID hex string)
  optional string target_id = 1;

  // Commitment to raw data: hash(data_bytes), 32-byte digest
  optional bytes data_commitment = 2;

  // Manifest for submitted data
  optional SubmissionManifest data_manifest = 3;

  // Model ID used for submission (must be in target's model_ids)
  optional string model_id = 4;

  // Pre-computed embedding (f32 values)
  repeated float embedding = 5;

  // Distance score (f32 cosine distance, lower is better)
  optional float distance_score = 6;

  // Bond coin reference
  optional ObjectReference bond_coin = 7;
}

// Claim rewards from a filled or expired target.
message ClaimRewards {
  // Target ID (ObjectID hex string)
  optional string target_id = 1;
}

// Manifest for submitted data (URL + metadata).
message SubmissionManifest {
  optional Manifest manifest = 1;
}

// Initiate a challenge against a filled target.
message InitiateChallenge {
  // Target ID (ObjectID hex string) to challenge
  optional string target_id = 1;

  // Type of challenge (e.g., "data_unavailable", "model_unavailable", "data_fraud", "score_fraud")
  optional string challenge_type = 2;

  // For ModelUnavailable challenges: the model ID that is unavailable
  optional string model_id = 3;

  // Bond coin reference
  optional ObjectReference bond_coin = 4;
}

// Report a challenge (validators only).
// Reports indicate "the challenger is wrong" (i.e., the submission is valid).
// If 2f+1 validators report, the challenger loses their bond.
message ReportChallenge {
  // Challenge ID (ObjectID hex string)
  optional string challenge_id = 1;
}

// Undo a previous challenge report.
message UndoReportChallenge {
  // Challenge ID (ObjectID hex string)
  optional string challenge_id = 1;
}

// Claim the challenger's bond after challenge window closes.
// Distributes bond based on tally-based report quorum.
message ClaimChallengeBond {
  // Challenge ID (ObjectID hex string)
  optional string challenge_id = 1;
}
