Skip to content

Scilla Server API

Vaivaswatha N edited this page Feb 16, 2020 · 7 revisions

Scilla-server API description

Introduction

With performance profiling experiments showing that the launch overhead of scilla-runner is about 25-30ms and given chain calls involve multiple executions of scilla-runner, there is a significant overhead to smart-contract execution in just process launch. To avoid this overhead, a persistent (continuously running) Scilla server process (called scilla-server) that accepts contract execution requests and executes the contract, providing output within the server process itself, is introduced. This ensures that the launch overhead is removed since the server is launched only once when the node boots up.

Server API

The server is a JSON-RPC server, providing two methos run and check. The server will serve only one request at a time and is going to be single threaded.

Both method take a single parameter named argv, which will be a JSON array of strings. This parameter will hold all the arguments to be provided for this Scilla execution. The arguments will be identical to the command line arguments of the scilla-runner executable.

Note: we use a single parameter JSON-RPC method, and not have the scilla-runner arguments directly as part of the method arguments because jsonrpccpp does not support optional arguments (https://github.com/cinemast/libjson-rpc-cpp/issues/32)

Example:

./bin/scilla-runner -init tests/runner/helloWorld/init.json -istate tests/runner/helloWorld/state_1.json -o output_1.json -imessage tests/runner/helloWorld/message_1.json -iblockchain tests/runner/helloWorld/blockchain_1.json -i tests/contracts/helloWorld.scilla -libdir src/stdlib “-gaslimit 800

Can be passed via the “scilla-runner” JSON-RPC method as:

{
  "jsonrpc": "2.0", 
  "method": "run", 
  “id” : 3, 
  "params": 
  {
    "argv” : [“-init”, “tests/runner/helloWorld/init.json”, “-istate”, “tests/runner/helloWorld/state_1.json”, “-o”, “output_1.json”, “-imessage”, “tests/runner/helloWorld/message_1.json”, “-iblockchain”, “tests/runner/helloWorld/blockchain_1.json”, “-i”, “tests/contracts/helloWorld.scilla”, “-libdir”, “src/stdlib”, “-gaslimit”, “800”]
  }
}

Return value:

On success

Conforming to the JSON-RPC standard, the response object's result field will be set. This value will again be a JSON, and will be identical to today’s output JSON emitted by scilla-runner/ scilla-checker. The -jsonerrors argument currently passed to the runner / checker is implicitly assumed.

On failure:

Partially conforming to the JSON-RPC standard (see Sec 5.1: Error object), the response-object's error field will be set. However, the message section of this error will not be "limited to a concise single sentence" as specified by the standard. It can either be a string or a JSON object itself. The client will need to handle both cases. In the case that the message is a JSON object, it will be identical to the error JSON emitted by scilla-checker / scilla-runner.

The case of the error's message section being just a string occurs only when an incorrect -argv (i.e., command line parameters through JSON-RPC) is passed. The error returned will be a command line parsing error and will not be a JSON, same as what the runners output today.

Demo C++ client

With bin/scilla-server from the Scilla repo running, client.exe built by the below code can be run as follows to mimic scilla-runner and scilla-checker.

client.exe check tests/contracts/wallet_2.scilla -libdir src/stdlib -gaslimit 10000

client.exe run  -init tests/runner/wallet_2/init.json -i tests/contracts/wallet_2.scilla -libdir src/stdlib -o /tmp/output.json -galimit 8000 -imessage tests/runner/wallet_2/message_7.json -iblockchain tests/runner/wallet_2/blockchain_7.json -istate tests/runner/wallet_2/state_7.json
Makefile
CFLAGS=-ggdb3 -Wall -std=c++14
LDFLAGS=-ljsoncpp -ljsonrpccpp-client -ljsonrpccpp-common

client.exe : client.cpp
        g++ ${CFLAGS} client.cpp -o client.exe ${LDFLAGS}
client.cpp
#include <iostream>
#include <string.h>
#include <jsonrpccpp/client.h>
#include <jsonrpccpp/client/connectors/unixdomainsocketclient.h>

const char *SCILLA_SERVER_PATH = "/tmp/scilla-server.sock";
int main(int argc, char *argv[])
{
  if (argc < 2 || !strcmp(argv[1], "-h") ||
      !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help"))
  {
    std::cerr << "Usage: " << argv[0] << " run|check ARGV...\n";
    return EXIT_FAILURE;
  }

  std::string method = argv[1];
  Json::Value params;
  Json::Value &server_argv = params["argv"];
  for (int i = 2; i < argc; i++) {
    server_argv.append(argv[i]);
  }

  jsonrpc::UnixDomainSocketClient c(SCILLA_SERVER_PATH);
  jsonrpc::Client client(c);

  try {
    Json::Value result = client.CallMethod(method, params);
    // The result is a string that contains a JSON.
    auto result_json_string = result.asString();
#if 1
    std::cout << result_json_string;
#else
    Json::Value scilla_output;
    // To do any kind of processing on the result, it must be parsed.
    if (!JSONUtils::GetInstance().convertStrtoJson(
          result_json_string, scilla_output))
    {
      std::cerr << "Error parsing Scilla output JSON\n";
      return EXIT_FAILURE;
    }
    std::cout << scilla_output.toStyledString();
#endif
    
  } catch (jsonrpc::JsonRpcException &e) {
    // if all the arguments were passed correctly to the server,
    // e.GetMessage() will be a (parseable) JSON string. Otherwise
    // it will be just an error message string describing the command
    // line usage. For this demo client, we just print whatever it is.
    std::cerr << e.GetMessage() << "\n";
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}