-
Notifications
You must be signed in to change notification settings - Fork 77
Scilla Server API
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.
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”]
}
}
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.
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.
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;
}