// Copyright 2016 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.google.trillian.proto";
option java_outer_classname = "TrillianMapApiProto";
option go_package = "github.com/google/trillian";

package trillian;

import "trillian.proto";
import "google/api/annotations.proto";

// MapLeaf represents the data behind Map leaves.
message MapLeaf {
  // index is the location of this leaf.
  // All indexes for a given Map must contain a constant number of bits.
  // These are not numeric indices. Note that this is typically derived using a
  // hash and thus the length of all indices in the map will match the number
  // of bits in the hash function.
  bytes index = 1;
  // leaf_hash is the tree hash of leaf_value.  This does not need to be set
  // on SetMapLeavesRequest; the server will fill it in.
  // For an empty leaf (len(leaf_value)==0), there may be two possible values
  // for this hash:
  //  - If the leaf has never been set, it counts as an empty subtree and
  //    a nil value is used.
  //  - If the leaf has been explicitly set to a zero-length entry, it no
  //    longer counts as empty and the value of hasher.HashLeaf(index, nil)
  //    will be used.
  bytes leaf_hash = 2;
  // leaf_value is the data the tree commits to.
  bytes leaf_value = 3;
  // extra_data holds related contextual data, but is not covered by any hash.
  bytes extra_data = 4;
}

message MapLeaves {
  repeated MapLeaf leaves = 1;
}

message MapLeafInclusion {
  MapLeaf leaf = 1;
  // inclusion holds the inclusion proof for this leaf in the map root. It
  // holds one entry for each level of the tree; combining each of these in
  // turn with the leaf's hash (according to the tree's hash strategy)
  // reproduces the root hash.  A nil entry for a particular level indicates
  // that the node in question has an empty subtree beneath it (and so its
  // associated hash value is hasher.HashEmpty(index, height) rather than
  // hasher.HashChildren(l_hash, r_hash)).
  repeated bytes inclusion = 2;
}

message GetMapLeavesRequest {
  int64 map_id = 1;
  repeated bytes index = 2;
  reserved 3;  // was 'revision'
}

message GetMapLeafRequest {
  int64 map_id = 1;
  bytes index = 2;
}

message GetMapLeafByRevisionRequest {
  int64 map_id = 1;
  bytes index = 2;
  int64 revision = 3;
}

// This message replaces the current implementation of GetMapLeavesRequest
// with the difference that revision must be >=0.
message GetMapLeavesByRevisionRequest {
  int64 map_id = 1;
  // index(es) to query.  It is an error to request the same index more than once.
  repeated bytes index = 2;
  // revision >= 0.
  int64 revision = 3;
}

message GetMapLeafResponse {
  MapLeafInclusion map_leaf_inclusion = 1;
  SignedMapRoot map_root = 2;
} 


message GetMapLeavesResponse {
  repeated MapLeafInclusion map_leaf_inclusion = 2;
  SignedMapRoot map_root = 3;
}

// GetLastInRangeByRevisionRequest specifies a range in the map at a revision.
// The range is defined as the entire subtree below a particular point in the 
// Merkle tree. Another way of saying this is that the range matches all leaves
// that share a common prefix of `prefix_bits` with `prefix`.
message GetLastInRangeByRevisionRequest {
  int64 map_id = 1;
  int64 revision = 2;
  bytes prefix = 3;
  // prefix_bits is the number of bits to include, starting from the left, or
  // most significant bit (MSB).
  int32 prefix_bits = 4;
}

message SetMapLeavesRequest {
  int64 map_id = 1;
  // The leaves being set must have unique Index values within the request.
  repeated MapLeaf leaves = 2;
  reserved 3;  // was MapperMetadata (removed, replaced by metadata).
  // Metadata that the Map should associate with the new Map root after
  // incorporating the leaf changes.  The metadata will be reflected in the
  // Map Root returned in the map's SetLeaves response.
  // Map personalities should use metadata to persist any state needed later
  // to continue mapping from an external data source.
  reserved 4;
  bytes metadata = 5;
  // The map revision to associate the leaves with. The request will fail if
  // this revision already exists, does not match the current write revision, or
  // is not positive. Note that revision = 0 is reserved for the empty tree.
  int64 revision = 6;
}

message SetMapLeavesResponse {
  SignedMapRoot map_root = 2;
}

message WriteMapLeavesRequest {
  int64 map_id = 1;
  // The leaves being set must have unique Index values within the request.
  repeated MapLeaf leaves = 2;
  // Metadata that the Map should associate with the new Map root after
  // incorporating the leaf changes.  The metadata will be reflected in the
  // Map Root published for this revision.
  // Map personalities should use metadata to persist any state needed later
  // to continue mapping from an external data source.
  bytes metadata = 3;
  // The map revision to associate the leaves with. The request will fail if
  // this revision already exists, does not match the current write revision, or
  // is not positive. Note that revision = 0 is reserved for the empty tree.
  int64 expect_revision = 4;
}

message WriteMapLeavesResponse {
  // The map revision that the leaves will be published at.
  // This may be accompanied by a proof that the write request has been included
  // in an input log in the future.
  int64 revision = 1;
}

message GetSignedMapRootRequest {
  int64 map_id = 1;
}

message GetSignedMapRootByRevisionRequest {
  int64 map_id = 1;
  int64 revision = 2;
}

message GetSignedMapRootResponse {
  SignedMapRoot map_root = 2;
}

message InitMapRequest {
  int64 map_id = 1;
}

message InitMapResponse {
  SignedMapRoot created = 1;
}

// TrillianMap defines a service which provides access to a Verifiable Map as
// defined in the Verifiable Data Structures paper.
service TrillianMap {
  // GetLeaves returns an inclusion proof for each index requested.
  // For indexes that do not exist, the inclusion proof will use nil for the
  // empty leaf value.
  rpc GetLeaf(GetMapLeafRequest) returns (GetMapLeafResponse) {}
  rpc GetLeafByRevision(GetMapLeafByRevisionRequest) returns (GetMapLeafResponse) {}
  rpc GetLeaves(GetMapLeavesRequest) returns (GetMapLeavesResponse) {}
  rpc GetLeavesByRevision(GetMapLeavesByRevisionRequest) returns (GetMapLeavesResponse) {}
  // Deprecated: this should only be used by writers, which should migrate
  // to TrillianMapWrite#GetLeavesByRevision
  rpc GetLeavesByRevisionNoProof(GetMapLeavesByRevisionRequest) returns (MapLeaves) {
    option deprecated = true;
  }
  // GetLastInRangeByRevision returns the last leaf in a requested range.
  rpc GetLastInRangeByRevision(GetLastInRangeByRevisionRequest) returns (MapLeaf) {
    option (google.api.http) = {
      get: "/v1beta1/maps/{map_id}/roots/{revision}/leaves:last_in_range"
    };
  }
  // Deprecated: this should only be used by writers, which should migrate
  // to TrillianMapWrite#WriteLeaves
  rpc SetLeaves(SetMapLeavesRequest) returns (SetMapLeavesResponse) {
    option deprecated = true;
  }
  rpc GetSignedMapRoot(GetSignedMapRootRequest)
      returns (GetSignedMapRootResponse) {
    option (google.api.http) = {
      get: "/v1beta1/maps/{map_id}/roots:latest"
    };
  }
  rpc GetSignedMapRootByRevision(GetSignedMapRootByRevisionRequest)
      returns (GetSignedMapRootResponse) {
    option (google.api.http) = {
      get: "/v1beta1/maps/{map_id}/roots/{revision}"
    };
  }
  rpc InitMap(InitMapRequest) returns (InitMapResponse) {
    option (google.api.http) = {
      post: "/v1beta1/maps/{map_id}:init"
    };
  }
}

// TrillianMapWrite defines a service to allow writes against a Verifiable Map
// that will be readable via the TrillianMap service. The write API does not
// expose any Merkle Tree properties. This allows key/value writes to be
// decoupled from the Merkle Tree synthesis and publishing.
service TrillianMapWrite {
  // GetLeavesByRevision returns the requested map leaves without inclusion proofs.
  // This API is designed for internal use where verification is not needed.
  rpc GetLeavesByRevision(GetMapLeavesByRevisionRequest) returns (MapLeaves) {}
  // WriteLeaves sets the values for the provided leaves, and returns the new map
  // revision if successful.
  rpc WriteLeaves(WriteMapLeavesRequest) returns (WriteMapLeavesResponse) {}
}
