// Copyright 2018-2021 Cargill Incorporated
//
// 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";

// Represents a splinter node on the splinter network
message SplinterNode {
    // unique id of a splinter node
    string node_id = 1;

    // The endpoints the splinter node is available on
    repeated string endpoints = 2;

    // The public key that must be used for identification if authorization is
    // set to challenge. This does not need to be set if using Trust.
    bytes public_key = 3;
}

message SplinterService {
    message Argument {
        string key = 1;
        string value = 2;
    }

    string service_id = 1;
    string service_type = 2;
    repeated string allowed_nodes = 3;
    repeated Argument arguments = 4;
}

message Circuit {
    enum AuthorizationType {
        UNSET_AUTHORIZATION_TYPE = 0;
        // Connections are trusted, and no authorization is done
        TRUST_AUTHORIZATION = 1;
        // Connections must prove their identity by signing bytes and providing
        // their public key
        CHALLENGE_AUTHORIZATION = 2;
    }

    enum PersistenceType {
        UNSET_PERSISTENCE_TYPE = 0;

        // The circuit does not have a preference for if the connection is
        // persisted
        ANY_PERSISTENCE = 1;
    }

    enum DurabilityType {
        UNSET_DURABILITY_TYPE = 0;

        // The message will be dropped if the connection is not available
        NO_DURABILITY = 1;
    }

    enum RouteType {
        UNSET_ROUTE_TYPE = 0;

        // The circuit can use any route to deliver the message
        ANY_ROUTE = 1;
    }

    enum CircuitStatus {
        UNSET_CIRCUIT_STATUS = 0;

        ACTIVE = 1;

        // The circuit has been disbanded and no longer has networking
        // capabilities
        DISBANDED = 2;

        // The circuit has been abandoned and may be removed from storage
        ABANDONED = 3;
    }

    // The unique circuit name
    string circuit_id = 1;

    // The list of services (service ids) that are allowed to connect to the
    // circuit
    repeated SplinterService roster = 2;

    // The SplinterNodes that are a part of the circuit
    repeated SplinterNode members = 3;

    // Circuit specific authorization type
    AuthorizationType authorization_type = 4;

    // Whether the circuit connections need to be persisted
    PersistenceType persistence = 5;

    // Whether the connection must be durable
    DurabilityType durability = 6;

    // Routes a message is allowed to take from one service to another
    RouteType routes = 7;

    // The circuit management type indicates the application authorization
    // handler that will handle this circuit's change proposals.
    string circuit_management_type  = 8;

    // Opaque bytes that can be used by applications
    bytes application_metadata = 9;

    // Human-readable comments about the circuit
    string comments = 10;

    // Human-readable display name for the circuit
    string display_name = 11;

    // The schema version of the circuit
    int32 circuit_version = 12;

    // The status of the circuit
    CircuitStatus circuit_status = 13;
}

// Contains the vote counts for a given proposal.
message CircuitProposal {
    enum ProposalType {
        UNSET_PROPOSAL_TYPE = 0;
        CREATE = 1;
        UPDATE_ROSTER = 2;
        ADD_NODE = 3;
        REMOVE_NODE = 4;
        DISBAND = 5;
    }

    // An individual vote record
    message VoteRecord {
        // The public key of the voter
        bytes public_key = 1;

        // The voter's actual vote
        CircuitProposalVote.Vote vote = 2;

        // the node the vote came from
        string voter_node_id = 3;
    }

    // What is being changed
    ProposalType proposal_type = 1;

    // The id of the circuit being proposed/updated
    string circuit_id = 2;

    // The sha256 hash of the final state of the new circuit definition in
    // bytes
    string circuit_hash = 3;

    // The new circuit state created by the proposal
    Circuit circuit_proposal = 4;

    // List of votes
    repeated VoteRecord votes = 5;

    // The public key that the request originated from a vote does not need to
    // come from the node this public key is associated with
    bytes requester = 6;

    // the node the requester created the proposal for
    string requester_node_id = 7;
}

// Contains all the circuit proposals up for a vote.
message CircuitProposalList {
    repeated CircuitProposal candidates = 1;
}

///
/// Messages

message CircuitManagementPayload {
     enum Action {
         ACTION_UNSET = 0;
         CIRCUIT_PROPOSAL_VOTE = 1;
         CIRCUIT_CREATE_REQUEST = 2;
         CIRCUIT_UPDATE_ROSTER_REQUEST = 3;
         CIRCUIT_UPDATE_ADD_NODE = 4;
         CIRCUIT_UPDATE_REMOVE_NODE = 5;
         CIRCUIT_UPDATE_APPLICATION_METADATA_REQUEST = 6;
         CIRCUIT_JOIN_REQUEST = 7;
         CIRCUIT_DISBAND_REQUEST = 8;
         CIRCUIT_PURGE_REQUEST = 9;
         CIRCUIT_ABANDON = 10;
         PROPOSAL_REMOVE_REQUEST = 11;
    }

    message Header {
         Action action = 1;

         // Public key of agent submitting the payload
         bytes requester = 2;

         // A hash of the circuit management payload action in bytes
         bytes payload_sha512 = 3;

         // the node the requester is submitting the payload for
         string requester_node_id = 4;
    }

    // Serialized header
    bytes header = 1;

    // The signature derived from signing the header included in this request
    bytes signature = 2;

    CircuitProposalVote circuit_proposal_vote = 3;
    CircuitCreateRequest circuit_create_request = 4;
    CircuitUpdateRosterRequest  circuit_update_roster_request = 5;
    CircuitUpdateAddNodeRequest circuit_update_add_node = 6;
    CircuitUpdateRemoveNodeRequest circuit_update_remove_node = 7;
    CircuitUpdateApplicationMetadataRequest
        circuit_update_application_metadata_request = 8;
    CircuitJoinRequest circuit_join_request = 9;
    CircuitDisbandRequest circuit_disband_request = 10;
    CircuitPurgeRequest circuit_purge_request = 11;
    CircuitAbandon circuit_abandon = 12;
    ProposalRemoveRequest proposal_remove_request = 13;
}

message CircuitProposalVote {
    enum Vote {
        UNSET_VOTE = 0;
        ACCEPT = 1;
        REJECT = 2;
    }

    // The id of the circuit being updated
    string circuit_id = 1;
    // The sha256 hash of the final state of the new circuit definition in
    // bytes
    string circuit_hash = 2;
    Vote vote = 3;
}

// This message will be submitted to a splinter node by an administrator that
// wishes to add a new Circuit to the network
message CircuitCreateRequest {
   Circuit circuit = 1;
}

// This message will be submitted to a splinter node by an administrator that
// wishes to modify a circuit's roster of services.
message CircuitUpdateRosterRequest {
    // The unique circuit id
    string circuit_id = 1;

    // The list of services that should be added to the circuit
    repeated SplinterService add_services= 2;

    // The list of services that should be removed from the circuit
    repeated SplinterService remove_services= 3;
}

// This message will be submitted to a splinter node by an administrator that
// wishes to add a splinter node to the circuit
message CircuitUpdateAddNodeRequest {
    // The unique circuit id
    string circuit_id = 1;

    // The node that should be added to the circuit
    SplinterNode node= 2;
}

// This message will be submitted to a splinter node by an administrator that
// wishes to remove a splinter node to the circuit
message CircuitUpdateRemoveNodeRequest {
    // The unique circuit name
    string circuit_id = 1;

    // The node that should be removed from the circuit
    string node_id= 2;
}

message CircuitUpdateApplicationMetadataRequest {
    // The unique circuit name
    string circuit_id = 1;

    // the new application metadata that should be stored in the circuit
    bytes application_metedata = 2;
}

// This message is used to notify the new node of the circuit definition, as
// well as ask for confirmation that they wish to join the node.
message CircuitJoinRequest {
    Circuit circuit = 1;
}

message CircuitDisbandRequest {
    // The unique circuit name
    string circuit_id = 1;
}

message CircuitPurgeRequest {
    // The unique circuit id of the inactive circuit to be purged
    string circuit_id = 1;
}

message CircuitAbandon {
    // The unique circuit name
    string circuit_id = 1;
}

message ProposalRemoveRequest {
    // The unique circuit name
    string circuit_id = 1;
}

message AdminMessage {
    enum Type {
        UNSET = 0;
        CONSENSUS_MESSAGE = 1;
        PROPOSED_CIRCUIT = 2;
        MEMBER_READY = 3;
        ABANDONED_CIRCUIT = 4;
        REMOVED_PROPOSAL = 5;

        SERVICE_PROTOCOL_VERSION_REQUEST = 100;
        SERVICE_PROTOCOL_VERSION_RESPONSE = 101;
    }

    Type message_type = 1;

    bytes consensus_message = 2;
    ProposedCircuit proposed_circuit = 3;
    MemberReady member_ready = 4;
    AbandonedCircuit abandoned_circuit = 5;
    RemovedProposal removed_proposal = 6;

    // Messages to agree on protocol version
    ServiceProtocolVersionRequest protocol_request = 100;
    ServiceProtocolVersionResponse protocol_response = 101;
}

message ProposedCircuit {
    // the payload that needs to be sent to all members of a circuit
    CircuitManagementPayload circuit_payload = 1;

    // the hash of the expected circuit proposal that is generated by the
    // included request
    bytes expected_hash = 2;

    bytes required_verifiers = 3;
}

message MemberReady {
    string circuit_id = 1;
    string member_node_id = 2;
}

message AbandonedCircuit {
    // the circuit being abandoned
    string circuit_id = 1;
    string member_node_id = 2;
}

message RemovedProposal {
    // the proposal being removed
    string circuit_id = 1;
}

// This message is sent to a connection AdminService to agree upon protocol
// version.
//
// The sending service will provide the min and max protocol versions they
// support.
message ServiceProtocolVersionRequest {
    uint32 protocol_min = 1;
    uint32 protocol_max = 2;
}

// This message is a response ServiceProtocolVersionRequest. It contains the
// protocol version that the responder can support. If no matching protocol can
// be supported 0 is returned.
message ServiceProtocolVersionResponse {
    uint32 protocol = 1;
}
