// Copyright 2021 Cartesi Pte. Ltd. // 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"; import "versioning.proto"; import "cartesi-machine.proto"; package CartesiServerManager; // The version implemented by an instance of the Cartesi Server Manager can be obtained with a call to GetVersion. // Each Cartesi Server Manager controls a variety of independent Sessions (see StartSession). // The current list of Sessions can be obtained with a call to GetStatus. // Each Session controls a single Cartesi Machine through a connection to a Cartesi Machine Server that the // Server Manager itself spanws for the session. // The Cartesi Machine is specified in the StartSession request, either by config or by directory. // Each Session is divided into Epochs. // The list of past Epochs (and the current Epoch) for a Session can be obtained with a call to GetSessionStatus. // Within each Epoch, the state of the associated machine is advanced by individual inputs (see AdvanceState). // The processing of each input, when successful, may produce a number of Vouchers (i.e., collateral effects // actionable in the blockchain) and a variety of Notices (which describe any relevant changes to the internal // state of applications running inside the Cartesi Machine). // The current Epoch can be closed (and the next Epoch started) with a call to FinishEpoch. // This is a synchronous call that can only be issued after all inputs in the active epoch have been processed. // The entire state of the machine can be stored to disk (and later recovered) when the Epoch is finished. // An input can be skipped for a variety of reasons (see CompletionStatus). // Whether successfully processed or skipped, the machine can produce a variety of Reports (i.e., diagnostics, logs etc) // Input processing is assynchronous: the reslut of all processed inputs for processing can be // obtained with a call to GetEpochStatus. // Information about an Epoch is retained until its Session is terminated (see EndSession). // (Note that machines stored to disk are always retained.) // When an input is skipped, for whatever reason, the state of the Cartesi Machine is reverted to what it was // before the input was given to the machine: i.e., from the prespective of the machine, it never happened. // Certain error conditions may cause a Session to become unusable. // An unusable Session is said to be "tainted". // All further operations in a tainted Session (other than EndSession) will fail. // The underlying reason can be obtained with a call to GetSessionStatus. // Between inputs, the state of the machine can be inspected with a query (see InspectState). // Processing of a query can produce a variety of Reports. // Processing of a query can be aborted for a variety of reasons (see CompletionStatus). // After the query is processed, the state of the Cartesi Machine is reverted to what it was before the query was given // to the machine: i.e., from the perspective of the machine, it never happened. // State inspection is synchronous: the query is processed as soon as the current input is done (if any) and all // produced Reports are immediately returned. // A Cartesi Machine used with the Cartesi Server Manager must define 5 memory ranges, in addition to however // many flash drives the application it runs might require. // Each memory range must have a power-of-two length, and must start at a multiple of its size. // The first two are the rx buffer and tx buffer memory ranges. // The rx buffer is used by the Cartesi Server Manager to send the input and query payloads into the Cartesi // Machine. // The tx buffer is used by the Cartesi Machine to send Vouchers, Notices, and Reports to the Cartesi Server // Manager. // Each input to AdvanceState, in addition to the payload, require some metadata. // This is sent into the Cartesi Machine by means of the input metadata memory range. // The last two remaining memory ranges are the voucher hashes and notice hashes memory ranges. // These contain array of hashes, respectively of each voucher and notice produced while processing an input. // Whenever an input is processed, the Cartesi Server Manager collects from the Cartesi Machine a Merkle proof // that the voucher hashes and notice hashes memory ranges are part of the Cartesi Machine State. // Likewise, each voucher and notice accompanies a proof that its hash is part of, respectively, the voucher hashe // memory range and notice hashes memory range. // Finally, the Cartesi Server Manager also maintains two additional Merkle trees, respectively containing as // leaves the Merkle tree root hash of the voucher hashes memory range and the notice hashes memory range. service ServerManager { rpc GetVersion(CartesiMachine.Void) returns (Versioning.GetVersionResponse) {} rpc StartSession (StartSessionRequest) returns (StartSessionResponse) {} rpc AdvanceState (AdvanceStateRequest) returns (CartesiMachine.Void) {} rpc GetStatus (CartesiMachine.Void) returns (GetStatusResponse) {} rpc GetSessionStatus (GetSessionStatusRequest) returns (GetSessionStatusResponse) {} rpc GetEpochStatus (GetEpochStatusRequest) returns (GetEpochStatusResponse) {} rpc InspectState (InspectStateRequest) returns (InspectStateResponse) {} rpc FinishEpoch (FinishEpochRequest) returns (CartesiMachine.Void) {} rpc EndSession (EndSessionRequest) returns (CartesiMachine.Void) {} } message StartSessionResponse { CartesiMachine.MachineConfig config = 1; // Configuration of instantiated machine } message GetStatusResponse { repeated string session_id = 1; // List of available sessions } // Deadlines for a variety of machine server tasks // (All deadlines are in milliseconds) message DeadlineConfig { uint64 checkin = 1; // Deadline for receiving checkin from spawned machine server uint64 update_merkle_tree = 2; // Deadline for updating a Merkle tree uint64 advance_state = 3; // Deadline for advancing the state uint64 advance_state_increment = 4; // Deadline for each increment when advancing state uint64 inspect_state = 5; // Deadline for inspecting state uint64 inspect_state_increment = 6; // Deadline for each increment when inspecting state uint64 machine = 7; // Deadling for instantiating a machine uint64 store = 8; // Deadling for storing a machine uint64 fast = 9; // Deadling for quick machine server tasks } // Cycle limits for a variety of machine server tasks message CyclesConfig { uint64 max_advance_state = 1; // Maximum number of cycles that processing the input in an AdvanceState can take uint64 advance_state_increment = 2; // Number of cycles in each increment to processing an input uint64 max_inspect_state = 3; // Maximum number of cycles that processing the query in an InspectState can take uint64 inspect_state_increment = 4; // Number of cycles in each increment to processing a query } message StartSessionRequest { string session_id = 1; // Id of session to start string machine_directory = 2; // Machine to instantiate for session uint64 active_epoch_index = 3; // Active epoch for the newly instantiated machine CyclesConfig server_cycles = 5; // Cycle limit for server tasks DeadlineConfig server_deadline = 6; // Time limit for server tasks CartesiMachine.MachineRuntimeConfig runtime = 7; // Machine runtime parameters } // Information about why the session became invalid message TaintStatus { int32 error_code = 1; // Error code associated to tainting of session string error_message = 2; // Descriptive error message } message GetSessionStatusRequest { string session_id = 1; // Id of session to describe } message GetSessionStatusResponse { string session_id = 1; // Id of session being described uint64 active_epoch_index = 2; // Currently active epoch in session repeated uint64 epoch_index = 3; // List of epochs the session holds TaintStatus taint_status = 4; // If session is tainted, an error code and message giving the cause } message EndSessionRequest { string session_id = 1; // Session to end. } message Address { bytes data = 1; // 20-byte address } message InputMetadata { Address msg_sender = 1; // 20-byte address of sender uint64 block_number = 2; // Block number when input was posted uint64 timestamp = 3; // Time stamp of block (Unix?) uint64 epoch_index = 4; // Epoch index in session uint64 input_index = 5; // Input index in epoch } message AdvanceStateRequest { string session_id = 1; uint64 active_epoch_index = 2; // To double-check the desired epoch is the active one uint64 current_input_index = 3; // To double-check the current input in the active epoch is the expected one InputMetadata input_metadata = 4; // Information sent via the input metadata memory range bytes input_payload = 5; // Payload sent via the rx buffer memory range } message GetEpochStatusRequest { string session_id = 1; // Session to which epoch belongs uint64 epoch_index = 2; // Index of epoch to describe. May refer to an old epoch that is still cached by the session } // Reason why input was skipped enum CompletionStatus { ACCEPTED = 0; CYCLE_LIMIT_EXCEEDED = 1; REJECTED_BY_MACHINE = 2; MACHINE_HALTED = 3; TIME_LIMIT_EXCEEDED = 4; } message InputResult { CartesiMachine.MerkleTreeProof voucher_hashes_in_machine = 1; // Merkle proof that the voucher hashes memory range is part of the Cartesi Machine State repeated Voucher vouchers = 2; // List of vouchers produced when processing the input CartesiMachine.MerkleTreeProof notice_hashes_in_machine = 3; // Merkle proof that the notice hashes memory range is part of the Cartesi Machine State repeated Notice notices = 4; // List of notices produced when processing the input } // For an ACTIVE epoch or a FINISHED epoch with pending inputs, the voucher_hashes_in_epoch and notice_hashes_in_epoch // proofs are incremental. I.e., the voucher and notice Merkle trees assume that future voucher and notice // keccak hashes are zero in producing the proofs. // For FINISHED epochs without pending inputs, each proof is recomputed to take into account the voucher and notice keccaks that came afterwards in the epoch. message ProcessedInput { uint64 input_index = 1; // Index of input in epoch CartesiMachine.Hash most_recent_machine_hash = 2; // State hash of Cartesi Machine after processing input (might be the same as previous if the input was rejected and the machine reverted CartesiMachine.MerkleTreeProof voucher_hashes_in_epoch = 3; // Merkle proof that the voucher hashes memory range is in the epoch CartesiMachine.MerkleTreeProof notice_hashes_in_epoch = 4; // Merkle proof that the notice hashes memory range is in the epoch repeated Report reports = 5; // Reports produced during input or query processing oneof processed_oneof { InputResult result = 6; // Result of processing input... CompletionStatus skip_reason = 7; // ...or reason input was skipped }; } enum EpochState { ACTIVE = 0; // Epoch is still accepting inputs FINISHED = 1; // Epoch has been buried under the next active epoch but is perhaps still processing pending inputs } message GetEpochStatusResponse { string session_id = 1; // Session to which epoch belong uint64 epoch_index = 2; // Index of epoch being described EpochState state = 3; // State epoch is currently in CartesiMachine.Hash most_recent_machine_hash = 4; // Most recent machine hash in epoch CartesiMachine.Hash most_recent_vouchers_epoch_root_hash = 5; // Most recent root hash for Merkle tree of voucher hashes memory ranges CartesiMachine.Hash most_recent_notices_epoch_root_hash = 6; // Most recent root hash for Merkle tree of notice hashes memory ranges repeated ProcessedInput processed_inputs = 7; // List of inputs already processed uint64 pending_input_count = 8; // Number of inputs pending processing TaintStatus taint_status = 9; // If session is tainted, an error code and message giving the cause } message Notice { CartesiMachine.Hash keccak = 1; // Keccak hash of notice payload bytes payload = 2; // Notice payload CartesiMachine.MerkleTreeProof keccak_in_notice_hashes = 3; // Proof that keccak is in notice hashes memory range } message Voucher { CartesiMachine.Hash keccak = 1; // Keccak hash of voucher Address address = 2; // 20-byte address bytes payload = 3; // Voucher payload CartesiMachine.MerkleTreeProof keccak_in_voucher_hashes = 4; // Proof that keccak is in voucher hashes memory range } message Report { bytes payload = 1; // Report payload } message InspectStateRequest { string session_id = 1; // Session to inspect uint64 active_epoch_index = 2; // To double-check the desired epoch is the active one bytes query_payload = 3; // Query payload } message InspectStateResponse { string session_id = 1; // Id of session being described uint64 active_epoch_index = 2; // Epoch that was inspected uint64 current_input_index = 3; // Current input index before/after state was inspected CompletionStatus status = 4; // Whether inspection completed or not (and why not) repeated Report reports = 5; // Reports produced while processing the query } message FinishEpochRequest { string session_id = 1; // Id of session containing epoch to finish uint64 active_epoch_index = 2; // To double-check epoch index is correct uint64 processed_input_count = 3; // To double-check all inputs sent have been processed string storage_directory = 4; // Directory to store machine state (do not store if empty string) }