syntax = "proto3";

package sync;

import "google/protobuf/empty.proto";

option go_package = "github.com/ava-labs/avalanchego/proto/pb/sync";

// Request represents a request for information during syncing.
message Request {
  oneof message {
    SyncGetRangeProofRequest range_proof_request = 1;
    SyncGetChangeProofRequest change_proof_request = 2;
  }
}

// The interface required by an x/sync/SyncManager for syncing.
// Note this service definition only exists for use in tests.
// A database shouldn't expose this over the internet, as it
// allows for reading/writing to the database.
service DB {
  rpc GetMerkleRoot(google.protobuf.Empty) returns (GetMerkleRootResponse);

  rpc GetProof(GetProofRequest) returns (GetProofResponse);

  rpc GetChangeProof(GetChangeProofRequest) returns (GetChangeProofResponse);
  rpc VerifyChangeProof(VerifyChangeProofRequest) returns (VerifyChangeProofResponse);
  rpc CommitChangeProof(CommitChangeProofRequest) returns (google.protobuf.Empty);

  rpc GetRangeProof(GetRangeProofRequest) returns (GetRangeProofResponse);
  rpc CommitRangeProof(CommitRangeProofRequest) returns (google.protobuf.Empty);
}

message GetMerkleRootResponse {
  bytes root_hash = 1;
}

message GetProofRequest {
  bytes key = 1;
}

message GetProofResponse {
  Proof proof = 1;
}

message Proof {
  bytes key = 1;
  MaybeBytes value = 2;
  repeated ProofNode proof = 3;
}

// For use in sync client, which has a restriction on the size of
// the response. GetChangeProof in the DB service doesn't.
message SyncGetChangeProofRequest {
  bytes start_root_hash = 1;
  bytes end_root_hash = 2;
  MaybeBytes start_key = 3;
  MaybeBytes end_key = 4;
  uint32 key_limit = 5;
  uint32 bytes_limit = 6;
}

message SyncGetChangeProofResponse {
  oneof response {
    ChangeProof change_proof = 1;
    RangeProof range_proof = 2;
  }
}

message GetChangeProofRequest {
  bytes start_root_hash = 1;
  bytes end_root_hash = 2;
  MaybeBytes start_key = 3;
  MaybeBytes end_key = 4;
  uint32 key_limit = 5;
}

message GetChangeProofResponse {
  oneof response {
    ChangeProof change_proof = 1;
    // True iff server errored with merkledb.ErrInsufficientHistory.
    bool root_not_present = 2;
  }
}

message VerifyChangeProofRequest {
  ChangeProof proof = 1;
  MaybeBytes start_key = 2;
  MaybeBytes end_key = 3;
  bytes expected_root_hash = 4;
}

message VerifyChangeProofResponse {
  // If empty, there was no error.
  string error = 1;
}

message CommitChangeProofRequest {
  ChangeProof proof = 1;
}

// For use in sync client, which has a restriction on the size of
// the response. GetRangeProof in the DB service doesn't.
message SyncGetRangeProofRequest {
  bytes root_hash = 1;
  MaybeBytes start_key = 2;
  MaybeBytes end_key = 3;
  uint32 key_limit = 4;
  uint32 bytes_limit = 5;
}

message GetRangeProofRequest {
  bytes root_hash = 1;
  MaybeBytes start_key = 2;
  MaybeBytes end_key = 3;
  uint32 key_limit = 4;
}

message GetRangeProofResponse {
  RangeProof proof = 1;
}

message CommitRangeProofRequest {
  MaybeBytes start_key = 1;
  RangeProof range_proof = 2;
}

message ChangeProof {
  repeated ProofNode start_proof = 1;
  repeated ProofNode end_proof = 2;
  repeated KeyChange key_changes = 3;
}

message RangeProof {
  repeated ProofNode start = 1;
  repeated ProofNode end = 2;
  repeated KeyValue key_values = 3;
}

message ProofNode {
  SerializedPath key = 1;
  MaybeBytes value_or_hash = 2;
  map<uint32, bytes> children = 3;
}

message KeyChange {
  bytes key = 1;
  MaybeBytes value = 2;
}

message SerializedPath {
  uint64 nibble_length = 1;
  bytes value = 2;
}

message MaybeBytes {
  bytes value = 1;
  // If false, this is None.
  // Otherwise this is Some.
  bool is_nothing = 2;
}

message KeyValue {
  bytes key = 1;
  bytes value = 2;
}
