syntax = "proto3";

package soma.rpc;

import "soma/rpc/transaction.proto";

message SystemState {
  // Core epoch information
  optional uint64 epoch = 1;
  optional uint64 epoch_start_timestamp_ms = 2;

  // The protocol version
  optional uint64 protocol_version = 3;
  
  // System parameters
  optional SystemParameters parameters = 4;
  
  // Validator set
  optional ValidatorSet validators = 5;
  
  // Report records
  map<string, ReporterSet> validator_report_records = 6;
  
  // Emission pool
  optional EmissionPool emission_pool = 7;

  // Target state (difficulty thresholds, EMAs, reward per target)
  optional TargetState target_state = 12;

  // Model registry
  optional ModelRegistry model_registry = 11;

  // Submission report records (target_id hex -> reporter addresses)
  map<string, ReporterSet> submission_report_records = 13;

  // Safe mode fields
  optional bool safe_mode = 14;
  optional uint64 safe_mode_accumulated_fees = 15;
  optional uint64 safe_mode_accumulated_emissions = 16;
}

message ReporterSet {
  repeated string reporters = 1;
}

message SystemParameters {
  optional uint64 epoch_duration_ms = 1;
  optional uint64 validator_reward_allocation_bps = 2;

  // Model parameters
  optional uint64 model_min_stake = 3;
  optional uint64 model_architecture_version = 4;
  optional uint64 model_reveal_slash_rate_bps = 5;
  optional uint64 model_tally_slash_rate_bps = 6;

  // Fee parameters
  optional uint64 target_epoch_fee_collection = 7;
  optional uint64 base_fee = 8;
  optional uint64 write_object_fee = 9;
  optional uint64 value_fee_bps = 10;
  optional uint64 min_value_fee_bps = 11;
  optional uint64 max_value_fee_bps = 12;
  optional uint64 fee_adjustment_rate_bps = 13;

  // Target/Mining parameters
  optional uint64 target_models_per_target = 14;
  optional uint64 target_embedding_dim = 15;
  optional float target_initial_distance_threshold = 16;
  optional uint64 target_reward_allocation_bps = 17;
  optional uint64 target_hit_rate_target_bps = 18;
  optional uint64 target_hit_rate_ema_decay_bps = 19;
  optional uint64 target_difficulty_adjustment_rate_bps = 20;
  optional float target_max_distance_threshold = 21;
  optional float target_min_distance_threshold = 22;
  optional uint64 target_initial_targets_per_epoch = 23;

  // Reward distribution parameters
  optional uint64 target_miner_reward_share_bps = 24;
  optional uint64 target_model_reward_share_bps = 25;
  optional uint64 target_claimer_incentive_bps = 26;

  // Submission parameters
  optional uint64 submission_bond_per_byte = 27;

  // Challenge parameters
  optional uint64 challenger_bond_per_byte = 28;
  // challenge_distance_epsilon removed - using Burn's Tolerance::permissive() instead

  // Data size limit
  optional uint64 max_submission_data_size = 30;
}

message EmissionPool {
  optional uint64 balance = 1;
  optional uint64 emission_per_epoch = 2;
}

message ValidatorSet {
  optional uint64 total_stake = 1;
  repeated Validator validators = 2;
  repeated Validator pending_validators = 3;
  repeated uint32 pending_removals = 4;
  map<string, string> staking_pool_mappings = 5; // pool_id -> validator_address
  map<string, Validator> inactive_validators = 6; // pool_id -> validator
  map<string, uint64> at_risk_validators = 7; // address -> epochs_at_risk
}

message Validator {
  optional string soma_address = 1;
  optional bytes protocol_pubkey = 2;
  optional bytes network_pubkey = 3;
  optional bytes worker_pubkey = 4;
  optional string net_address = 5;
  optional string p2p_address = 6;
  optional string primary_address = 7;
  optional string proxy_address = 19;  // HTTP proxy address for serving data/model downloads

  optional uint64 voting_power = 8;
  optional uint64 commission_rate = 9;
  optional uint64 next_epoch_stake = 10;
  optional uint64 next_epoch_commission_rate = 11;

  optional StakingPool staking_pool = 12;

  // Next epoch metadata (only if set)
  optional bytes next_epoch_protocol_pubkey = 13;
  optional bytes next_epoch_network_pubkey = 14;
  optional bytes next_epoch_worker_pubkey = 15;
  optional string next_epoch_net_address = 16;
  optional string next_epoch_p2p_address = 17;
  optional string next_epoch_primary_address = 18;
  optional string next_epoch_proxy_address = 20;  // HTTP proxy address for next epoch
}

message StakingPool {
  optional string id = 1;
  optional uint64 activation_epoch = 2;
  optional uint64 deactivation_epoch = 3;
  optional uint64 soma_balance = 4;
  optional uint64 rewards_pool = 5;
  optional uint64 pool_token_balance = 6;
  map<uint64, PoolTokenExchangeRate> exchange_rates = 7;
  optional uint64 pending_stake = 8;
  optional uint64 pending_total_soma_withdraw = 9;
  optional uint64 pending_pool_token_withdraw = 10;
}

message PoolTokenExchangeRate {
  optional uint64 soma_amount = 1;
  optional uint64 pool_token_amount = 2;
}

// A registered model in the mining system.
// Status derived from fields (same pattern as validators):
//   Committed: weights_manifest absent, staking_pool.deactivation_epoch absent
//   Active:    weights_manifest present, staking_pool.deactivation_epoch absent
//   Inactive:  staking_pool.deactivation_epoch present
message Model {
  optional string owner = 1;                              // SomaAddress hex
  optional uint64 architecture_version = 2;
  optional bytes weights_url_commitment = 3;              // 32-byte digest
  optional bytes weights_commitment = 4;                  // 32-byte digest
  optional uint64 commit_epoch = 5;
  optional ModelWeightsManifest weights_manifest = 6;     // absent while committed
  repeated float embedding = 7;                           // Model embedding for KNN selection (f32 values)
  optional StakingPool staking_pool = 8;
  optional uint64 commission_rate = 9;
  optional uint64 next_epoch_commission_rate = 10;
  optional PendingModelUpdate pending_update = 11;        // absent if no update in flight
}

// Registry of all models in the mining system.
message ModelRegistry {
  map<string, Model> active_models = 1;              // ModelId (ObjectID hex) -> Model
  map<string, Model> pending_models = 2;             // ModelId (ObjectID hex) -> Model
  map<string, string> staking_pool_mappings = 3;     // pool ObjectID hex -> ModelId hex
  map<string, Model> inactive_models = 4;            // ModelId (ObjectID hex) -> Model
  optional uint64 total_model_stake = 5;
  map<string, ReporterSet> model_report_records = 6; // ModelId hex -> reporter addresses
}

// Target state coordination (stored in SystemState).
// Tracks difficulty thresholds and statistics for target generation.
message TargetState {
  // Current distance threshold for new targets (f32 cosine distance)
  optional float distance_threshold = 1;

  // Count of targets generated this epoch
  optional uint64 targets_generated_this_epoch = 2;

  // Count of successful hits this epoch
  optional uint64 hits_this_epoch = 3;

  // EMA of hit rate across epochs (bps, 0-10000)
  // 0 indicates bootstrap mode (no data yet)
  optional uint64 hit_rate_ema_bps = 4;

  // Reward per target for current epoch (in shannons)
  optional uint64 reward_per_target = 5;
}

// A target in the Soma mining competition.
// Targets are shared objects that miners compete to fill.
message Target {
  // Target ID (ObjectID hex)
  optional string id = 1;

  // Center embedding point (f32 values)
  repeated float embedding = 2;

  // Models assigned to this target (ModelId hex strings)
  repeated string model_ids = 3;

  // Distance threshold (f32 cosine distance)
  optional float distance_threshold = 4;

  // Pre-allocated reward amount (in shannons)
  optional uint64 reward_pool = 5;

  // Epoch in which this target was generated
  optional uint64 generation_epoch = 6;

  // Status: "open", "filled", or "claimed"
  optional string status = 7;

  // Fill epoch (only present if status is "filled")
  optional uint64 fill_epoch = 8;

  // Miner address who filled (only present if filled)
  optional string miner = 9;

  // Model used by the miner (only present if filled)
  optional string winning_model_id = 10;

  // Model owner address at fill time (only present if filled)
  optional string winning_model_owner = 11;

  // Bond amount held (in shannons, only present if filled)
  optional uint64 bond_amount = 12;
}

// A data submission to a target.
message Submission {
  // Miner address
  optional string miner = 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 this submission
  optional string model_id = 4;

  // Embedding vector (f32 values)
  repeated float embedding = 5;

  // Distance score reported by submitter (f32 cosine distance)
  optional float distance_score = 6;

  // Bond amount locked (in shannons)
  optional uint64 bond_amount = 7;

  // Epoch when submission was made
  optional uint64 submit_epoch = 9;
}

// A challenge against a filled target's submission.
message Challenge {
  // Challenge ID (ObjectID hex)
  optional string id = 1;

  // Target being challenged (TargetId hex)
  optional string target_id = 2;

  // Address of the challenger
  optional string challenger = 3;

  // Bond locked by challenger (in shannons)
  optional uint64 challenger_bond = 4;

  // Epoch when challenge was initiated
  optional uint64 challenge_epoch = 5;

  // Status: "pending" or "resolved"
  optional string status = 6;

  // Verdict (only if resolved): "challenger_won" or "challenger_lost"
  // Simplified: reports indicate "challenger is wrong". If 2f+1 report, challenger loses.
  optional string verdict = 7;

  // Win reason is no longer used in simplified design (field kept for backwards compatibility)
  optional string win_reason = 8;

  // Distance threshold of target (f32 cosine distance)
  optional float distance_threshold = 9;

  // Claimed distance score by miner (f32 cosine distance)
  optional float winning_distance_score = 10;

  // Winning model ID used by miner
  optional string winning_model_id = 11;
}

