syntax = "proto3";

package execution;

import "types/types.proto";

option go_package = "./execution;execution";

enum ValidationStatus {
    Success = 0;      // State transition simulation is successful.
    InvalidChain = 1; // State transition simulation is Unsuccessful.
    TooFarAway = 2;   // Chain hash is too far away from current chain head and unfeasible to validate.
    MissingSegment = 3; // Chain segments are missing.
}

message ForkChoiceReceipt {
    bool success = 1; // Forkchoice is either successful or unsuccessful.
    types.H256 latestValidHash = 2; // Return latest valid hash in case of halt of execution.
}

// Result we receive after validation
message ValidationReceipt {
    ValidationStatus validationStatus = 1;
    types.H256 latestValidHash = 2;
    optional types.H256 missingHash = 3; // The missing hash, in case we receive MissingSegment so that we can reverse download it.
};

message IsCanonicalResponse {
    bool canonical = 1; // Whether hash is canonical or not.
}

// Header is an header for execution
message Header {
  types.H256 parentHash = 1;
  types.H160 coinbase = 2;
  types.H256 stateRoot = 3;
  types.H256 receiptRoot = 4;
  types.H2048 logsBloom = 5;
  types.H256 mixDigest = 6;
  uint64 blockNumber = 7;
  uint64 gasLimit = 8;
  uint64 gasUsed = 9;
  uint64 timestamp = 10;
  uint64 nonce = 11;
  bytes extraData = 12;
  types.H256 difficulty = 13;
  types.H256 blockHash = 14; // We keep this so that we can validate it
  types.H256 ommerHash = 15;
  types.H256 transactionHash = 16;
  optional types.H256 baseFeePerGas = 17;
  optional types.H256 withdrawalHash = 18;
}

// Body is a block body for execution
message BlockBody {
  types.H256 blockHash = 1;
  uint64 blockNumber = 2;
  // Raw transactions in byte format.
  repeated bytes transactions = 3;
  repeated Header uncles = 4;
  repeated types.Withdrawal withdrawals = 5;
}

message GetHeaderResponse {
    optional Header header = 1;
}

message GetBodyResponse {
    optional BlockBody body = 1;
}

message GetHeaderHashNumberResponse {
    optional uint64 blockNumber = 1; // null if not found.
}

message GetSegmentRequest {
    // Get headers/body by number or hash, invalid if none set.
    optional uint64 blockNumber = 1;
    optional types.H256 blockHash = 2;
}

message InsertHeadersRequest {
    repeated Header headers = 1;
}

message InsertBodiesRequest {
    repeated BlockBody bodies = 1;
}

message EmptyMessage {}

service Execution {
    // Chain Putters.
    rpc InsertHeaders(InsertHeadersRequest) returns(EmptyMessage);
    rpc InsertBodies(InsertBodiesRequest) returns(EmptyMessage);
    // Chain Validation and ForkChoice.
    rpc ValidateChain(types.H256) returns(ValidationReceipt);
    rpc UpdateForkChoice(types.H256) returns(ForkChoiceReceipt);
    rpc AssembleBlock(EmptyMessage) returns(types.ExecutionPayload); // Builds on top of current head.
    // Chain Getters.
    rpc GetHeader(GetSegmentRequest) returns(GetHeaderResponse);
    rpc GetBody(GetSegmentRequest) returns(GetBodyResponse);
    rpc IsCanonicalHash(types.H256) returns(IsCanonicalResponse);
    rpc GetHeaderHashNumber(types.H256) returns(GetHeaderHashNumberResponse);
}