diff --git a/src/device-state-access.h b/src/device-state-access.h
index 8f89cbe2e..51d5633a9 100644
--- a/src/device-state-access.h
+++ b/src/device-state-access.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef DEVICE_STATE_ACCESS
-#define DEVICE_STATE_ACCESS
+#ifndef DEVICE_STATE_ACCESS_H
+#define DEVICE_STATE_ACCESS_H
/// \file
/// \brief Virtual state access implementation
@@ -158,4 +158,4 @@ class device_state_access : public i_device_state_access {
} // namespace cartesi
-#endif
+#endif // DEVICE_STATE_ACCESS_H
diff --git a/src/i-device-state-access.h b/src/i-device-state-access.h
index 1065c7825..075d2bc46 100644
--- a/src/i-device-state-access.h
+++ b/src/i-device-state-access.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef I_DEVICE_STATE_ACCESS
-#define I_DEVICE_STATE_ACCESS
+#ifndef I_DEVICE_STATE_ACCESS_H
+#define I_DEVICE_STATE_ACCESS_H
#include
@@ -231,4 +231,4 @@ class i_device_state_access {
} // namespace cartesi
-#endif
+#endif // I_DEVICE_STATE_ACCESS_H
diff --git a/src/i-virtual-machine.h b/src/i-virtual-machine.h
index db4cd7abc..e3202ac03 100644
--- a/src/i-virtual-machine.h
+++ b/src/i-virtual-machine.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef I_VIRTUAL_MACHINE
-#define I_VIRTUAL_MACHINE
+#ifndef I_VIRTUAL_MACHINE_H
+#define I_VIRTUAL_MACHINE_H
#include
#include
@@ -290,4 +290,4 @@ class i_virtual_machine {
} // namespace cartesi
-#endif
+#endif // I_VIRTUAL_MACHINE_H
diff --git a/src/jsonrpc-fork-result.h b/src/jsonrpc-fork-result.h
index d42ec64a1..26a5ba73c 100644
--- a/src/jsonrpc-fork-result.h
+++ b/src/jsonrpc-fork-result.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef JSONRPC_FORK_RESULT
-#define JSONRPC_FORK_RESULT
+#ifndef JSONRPC_FORK_RESULT_H
+#define JSONRPC_FORK_RESULT_H
namespace cartesi {
@@ -26,4 +26,4 @@ struct fork_result final {
} // namespace cartesi
-#endif // JSONRPC_FORK_RESULT
+#endif // JSONRPC_FORK_RESULT_H
diff --git a/src/jsonrpc-machine-c-api.h b/src/jsonrpc-machine-c-api.h
index abfbf43ef..9ae8312c3 100644
--- a/src/jsonrpc-machine-c-api.h
+++ b/src/jsonrpc-machine-c-api.h
@@ -122,12 +122,6 @@ CM_API cm_error cm_jsonrpc_get_server_version(const cm_machine *m, const char **
/// This function makes it the leader of its own program group.
CM_API cm_error cm_jsonrpc_emancipate_server(cm_machine *m);
-/// \brief Asks server to delay next request by a given amount of time.
-/// \param m Pointer to a valid JSONRPC remote machine object.
-/// \param ms Number of milliseconds to delay next request.
-/// \returns 0 for success, non zero code for error.
-CM_API cm_error cm_jsonrpc_delay_next_request(cm_machine *m, uint64_t ms);
-
// -----------------------------------------------------------------------------
// Client API functions
// -----------------------------------------------------------------------------
@@ -167,6 +161,16 @@ CM_API cm_error cm_jsonrpc_get_cleanup_call(cm_machine *m, cm_jsonrpc_cleanup_ca
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_jsonrpc_get_server_address(cm_machine *m, const char **address);
+// -----------------------------------------------------------------------------
+// Debugging and testing
+// -----------------------------------------------------------------------------
+
+/// \brief Asks server to delay next request by a given amount of time.
+/// \param m Pointer to a valid JSONRPC remote machine object.
+/// \param ms Number of milliseconds to delay next request.
+/// \returns 0 for success, non zero code for error.
+CM_API cm_error cm_jsonrpc_delay_next_request(cm_machine *m, uint64_t ms);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/jsonrpc-remote-machine.cpp b/src/jsonrpc-remote-machine.cpp
index 4977a6105..f97a2d76c 100644
--- a/src/jsonrpc-remote-machine.cpp
+++ b/src/jsonrpc-remote-machine.cpp
@@ -62,6 +62,7 @@
#include "interpret.h"
#include "json-util.h"
#include "jsonrpc-discover.h"
+#include "jsonrpc-version.h"
#include "machine-config.h"
#include "machine-merkle-tree.h"
#include "machine-runtime-config.h"
@@ -106,17 +107,6 @@ std::ostream &operator<<(std::ostream &out, log_prefix prefix) {
using namespace std::string_literals;
using json = nlohmann::json;
-/// \brief Server semantic version major
-static constexpr uint32_t server_version_major = 0;
-/// \brief Server semantic version minor
-static constexpr uint32_t server_version_minor = 5;
-/// \brief Server semantic version patch
-static constexpr uint32_t server_version_patch = 0;
-/// \brief Server semantic version pre_release
-static constexpr const char *server_version_pre_release = "";
-/// \brief Server semantic version build
-static constexpr const char *server_version_build = "";
-
/// \brief Installs a signal handler
template
static void install_signal_handler(int signum, HANDLER handler) {
@@ -723,11 +713,11 @@ static json jsonrpc_get_version_handler(const json &j, const std::shared_ptr.
+//
+
+#ifndef JSONRPC_VERSION_H
+#define JSONRPC_VERSION_H
+
+#include
+
+namespace cartesi {
+
+constexpr uint32_t JSONRPC_VERSION_MAJOR = 0;
+constexpr uint32_t JSONRPC_VERSION_MINOR = 5;
+constexpr uint32_t JSONRPC_VERSION_PATCH = 0;
+constexpr const char *JSONRPC_VERSION_PRE_RELEASE = "";
+constexpr const char *JSONRPC_VERSION_BUILD = "";
+
+} // namespace cartesi
+
+#endif // JSONRPC_VERSION_H
diff --git a/src/jsonrpc-virtual-machine.cpp b/src/jsonrpc-virtual-machine.cpp
index aa4b01b7e..66122c30e 100644
--- a/src/jsonrpc-virtual-machine.cpp
+++ b/src/jsonrpc-virtual-machine.cpp
@@ -47,6 +47,7 @@
#include "interpret.h"
#include "json-util.h"
#include "json.hpp"
+#include "jsonrpc-version.h"
#include "machine-config.h"
#include "machine-memory-range-descr.h"
#include "machine-merkle-tree.h"
@@ -330,9 +331,23 @@ const std::string &jsonrpc_virtual_machine::get_server_address() const {
return m_address;
}
+static inline std::string semver_to_string(uint32_t major, uint32_t minor) {
+ return std::to_string(major) + "." + std::to_string(minor);
+}
+
+void jsonrpc_virtual_machine::check_server_version() const {
+ const auto server_version = get_server_version();
+ if (server_version.major != JSONRPC_VERSION_MAJOR || server_version.minor != JSONRPC_VERSION_MINOR) {
+ throw std::runtime_error{"expected server version "s +
+ semver_to_string(JSONRPC_VERSION_MAJOR, JSONRPC_VERSION_MINOR) + " (got "s +
+ semver_to_string(server_version.major, server_version.minor) + ")"s};
+ }
+}
+
jsonrpc_virtual_machine::jsonrpc_virtual_machine(std::string address) : m_address(std::move(address)) {
// Install handler to ignore SIGPIPE lest we crash when a server closes a connection
os_disable_sigpipe();
+ check_server_version();
}
static boost::asio::ip::tcp::endpoint address_to_endpoint(const std::string &address) {
@@ -450,6 +465,7 @@ jsonrpc_virtual_machine::jsonrpc_virtual_machine(const std::string &address, for
spawned.address = m_address;
// Install handler to ignore SIGPIPE lest we crash when a server closes a connection
os_disable_sigpipe();
+ check_server_version();
} catch (...) {
if (restore_sigprocmask) {
sigprocmask(SIG_SETMASK, &omask, nullptr);
diff --git a/src/jsonrpc-virtual-machine.h b/src/jsonrpc-virtual-machine.h
index ddfbd2295..8afd3ff45 100644
--- a/src/jsonrpc-virtual-machine.h
+++ b/src/jsonrpc-virtual-machine.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef JSONRPC_VIRTUAL_MACHINE
-#define JSONRPC_VIRTUAL_MACHINE
+#ifndef JSONRPC_VIRTUAL_MACHINE_H
+#define JSONRPC_VIRTUAL_MACHINE_H
#include
#include
@@ -136,6 +136,8 @@ class jsonrpc_virtual_machine final : public i_virtual_machine {
const hash_type &root_hash_before, const access_log &log, const hash_type &root_hash_after) const override;
bool do_is_jsonrpc_virtual_machine() const override;
+ void check_server_version() const;
+
mutable boost::asio::io_context m_ioc{1}; // The io_context is required for all I/O
mutable boost::beast::tcp_stream m_stream{m_ioc}; // TCP stream for keep alive connections
cleanup_call m_call{cleanup_call::nothing};
@@ -145,4 +147,4 @@ class jsonrpc_virtual_machine final : public i_virtual_machine {
} // namespace cartesi
-#endif
+#endif // JSONRPC_VIRTUAL_MACHINE_H
diff --git a/src/virtual-machine.h b/src/virtual-machine.h
index d7c6e82fa..b1e36ed5a 100644
--- a/src/virtual-machine.h
+++ b/src/virtual-machine.h
@@ -14,8 +14,8 @@
// with this program (see COPYING). If not, see .
//
-#ifndef VIRTUAL_MACHINE
-#define VIRTUAL_MACHINE
+#ifndef VIRTUAL_MACHINE_H
+#define VIRTUAL_MACHINE_H
#include
#include
@@ -92,4 +92,4 @@ class virtual_machine : public i_virtual_machine {
} // namespace cartesi
-#endif
+#endif // VIRTUAL_MACHINE_H
diff --git a/tests/lua/machine-test.lua b/tests/lua/machine-test.lua
index 0426fe790..1dbe35756 100755
--- a/tests/lua/machine-test.lua
+++ b/tests/lua/machine-test.lua
@@ -388,8 +388,8 @@ do_test("register values should match", function(machine)
end)
if machine_type ~= "local" then
- print("\n\n check remote get_machine")
- do_test("get_machine should get reference to working machine", function(machine)
+ print("\n\n checking remote-machine-specific functionality")
+ do_test("connect should get give access to working machine", function(machine)
local machine_2 = jsonrpc.connect_server(machine:get_server_address())
assert(machine:get_root_hash() == machine_2:get_root_hash())
machine_2:destroy()
@@ -400,6 +400,52 @@ if machine_type ~= "local" then
assert(err:match("no machine"))
end)
+ do_test("timeout mechanism should be respected", function(machine)
+ -- default timeout is -1 (meaning wait indefinitely)
+ local old_tm = machine:get_timeout()
+ assert(old_tm == -1)
+ -- set timeout to 100ms
+ machine:set_timeout(100)
+ -- make sure it stuck
+ assert(machine:get_timeout() == 100)
+ -- ask server to delay response by 1000ms
+ machine:delay_next_request(1000)
+ -- next call should fail with timeout
+ local ret, err = pcall(function()
+ machine:get_root_hash()
+ end)
+ assert(ret == false)
+ assert(err:match("jsonrpc error: timeout"))
+ machine:set_timeout(old_tm)
+ end)
+
+ do_test("cleanup call should be respected", function(machine)
+ -- all machines returned by build_machine are configured to shutdown server
+ assert(machine:get_cleanup_call() == jsonrpc.SHUTDOWN)
+ local address
+ do
+ -- fork server, get address of new server, make sure fork holds a
+ -- machine, and set cleanup to destroy it on close
+ local m2 = machine:fork_server()
+ address = m2:get_server_address()
+ assert(not m2:is_empty())
+ m2:set_cleanup_call(jsonrpc.DESTROY)
+ end
+ do
+ -- connect to server again, make sure it does not have a machine
+ -- anymore, and set cleanup to shut it down on close
+ local m2 = jsonrpc.connect_server(address)
+ assert(m2:is_empty())
+ m2:set_cleanup_call(jsonrpc.SHUTDOWN)
+ end
+ -- now there should be no server at that address
+ local ret, err = pcall(function()
+ jsonrpc.connect_server(address)
+ end)
+ assert(ret == false)
+ assert(err:match("jsonrpc error: post error contacting " .. address))
+ end)
+
do_test("jsonrpc connection error 49 after rapid successive requests ", function(machine)
-- On a Mac, this loop will break with EADDRNOTAVAIL(49)
-- Setting up the SO_LINGER to 0 fixed this issue