зеркало из https://github.com/microsoft/CCF.git
Remove jsonrpc leftovers (#1388)
This commit is contained in:
Родитель
b9d442786c
Коммит
2b6e358e62
|
@ -22,7 +22,7 @@ def wait_for_global_commit(client, seqno, view, timeout=3):
|
|||
assert (
|
||||
r.status == http.HTTPStatus.OK
|
||||
), f"tx request returned HTTP status {r.status}"
|
||||
status = TxStatus(r.result["status"])
|
||||
status = TxStatus(r.body["status"])
|
||||
if status == TxStatus.Committed:
|
||||
return
|
||||
elif status == TxStatus.Invalid:
|
||||
|
@ -40,24 +40,25 @@ class Checker:
|
|||
self.notification_queue = notification_queue
|
||||
self.notified_commit = 0
|
||||
|
||||
# TODO: that API's not right!
|
||||
def __call__(self, rpc_result, result=None, error=None, timeout=2):
|
||||
if error is not None:
|
||||
if callable(error):
|
||||
assert error(
|
||||
rpc_result.status, rpc_result.error
|
||||
), f"{rpc_result.status}: {rpc_result.error}"
|
||||
rpc_result.status, rpc_result.body
|
||||
), f"{rpc_result.status}: {rpc_result.body}"
|
||||
else:
|
||||
assert rpc_result.error == error, "Expected {}, got {}".format(
|
||||
error, rpc_result.error
|
||||
assert rpc_result.body == error, "Expected {}, got {}".format(
|
||||
error, rpc_result.body
|
||||
)
|
||||
return
|
||||
|
||||
if result is not None:
|
||||
if callable(result):
|
||||
assert result(rpc_result.result), rpc_result.result
|
||||
assert result(rpc_result.body), rpc_result.body
|
||||
else:
|
||||
assert rpc_result.result == result, "Expected {}, got {}".format(
|
||||
result, rpc_result.result
|
||||
assert rpc_result.body == result, "Expected {}, got {}".format(
|
||||
result, rpc_result.body
|
||||
)
|
||||
|
||||
assert rpc_result.seqno and rpc_result.view, rpc_result
|
||||
|
|
|
@ -24,7 +24,7 @@ import websocket
|
|||
|
||||
def truncate(string, max_len=256):
|
||||
if len(string) > max_len:
|
||||
return string[: max_len - 3] + "..."
|
||||
return f"{string[: max_len]} + {len(string) - max_len} chars"
|
||||
else:
|
||||
return string
|
||||
|
||||
|
@ -40,20 +40,28 @@ DEFAULT_REQUEST_TIMEOUT_SEC = 3
|
|||
|
||||
class Request:
|
||||
def __init__(
|
||||
self, method, params=None, http_verb="POST", headers=None, params_in_query=None
|
||||
self, path, params=None, http_verb="POST", headers=None, params_in_query=None
|
||||
):
|
||||
if headers is None:
|
||||
headers = {}
|
||||
|
||||
# TODO: remove
|
||||
if params_in_query is None:
|
||||
params_in_query = http_verb == "GET"
|
||||
|
||||
self.method = method
|
||||
self.path = path
|
||||
self.params = params
|
||||
self.http_verb = http_verb
|
||||
self.headers = headers
|
||||
self.params_in_query = params_in_query
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"{self.http_verb} {self.path} {self.headers} " + truncate(f"{self.params}")
|
||||
if self.params is not None
|
||||
else ""
|
||||
)
|
||||
|
||||
|
||||
def int_or_none(v):
|
||||
return int(v) if v is not None else None
|
||||
|
@ -68,34 +76,29 @@ class FakeSocket:
|
|||
|
||||
|
||||
class Response:
|
||||
def __init__(self, status, result, error, seqno, view, global_commit, headers):
|
||||
def __init__(self, status, body, seqno, view, global_commit, headers):
|
||||
self.status = status
|
||||
self.result = result
|
||||
self.error = error
|
||||
self.body = body
|
||||
self.seqno = seqno
|
||||
self.view = view
|
||||
self.global_commit = global_commit
|
||||
self.headers = headers
|
||||
|
||||
# TODO: what's this for?
|
||||
def to_dict(self):
|
||||
d = {
|
||||
return {
|
||||
"seqno": self.seqno,
|
||||
"global_commit": self.global_commit,
|
||||
"view": self.view,
|
||||
"body": self.body,
|
||||
}
|
||||
if self.result is not None:
|
||||
d["result"] = self.result
|
||||
else:
|
||||
d["error"] = self.error
|
||||
return d
|
||||
|
||||
def __str__(self):
|
||||
versioned = (self.view, self.seqno) != (None, None)
|
||||
body = self.result if f"{self.status}"[0] == "2" else self.error
|
||||
return (
|
||||
f"{self.status} "
|
||||
+ (f"@{self.view}.{self.seqno} " if versioned else "")
|
||||
+ truncate(f"{body}")
|
||||
+ truncate(f"{self.body}")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
@ -112,8 +115,7 @@ class Response:
|
|||
|
||||
return Response(
|
||||
status=rr.status_code,
|
||||
result=parsed_body if rr.ok else None,
|
||||
error=None if rr.ok else parsed_body,
|
||||
body=parsed_body,
|
||||
seqno=int_or_none(rr.headers.get(CCF_TX_SEQNO_HEADER)),
|
||||
view=int_or_none(rr.headers.get(CCF_TX_VIEW_HEADER)),
|
||||
global_commit=int_or_none(rr.headers.get(CCF_GLOBAL_COMMIT_HEADER)),
|
||||
|
@ -126,7 +128,6 @@ class Response:
|
|||
response = HTTPResponse(sock)
|
||||
response.begin()
|
||||
raw_body = response.read(raw)
|
||||
ok = response.status == 200
|
||||
|
||||
content_type = response.headers.get("content-type")
|
||||
if content_type == "application/json":
|
||||
|
@ -140,8 +141,7 @@ class Response:
|
|||
|
||||
return Response(
|
||||
status=response.status,
|
||||
result=parsed_body if ok else None,
|
||||
error=None if ok else parsed_body,
|
||||
body=parsed_body,
|
||||
seqno=int_or_none(response.getheader(CCF_TX_SEQNO_HEADER)),
|
||||
view=int_or_none(response.getheader(CCF_TX_VIEW_HEADER)),
|
||||
global_commit=int_or_none(response.getheader(CCF_GLOBAL_COMMIT_HEADER)),
|
||||
|
@ -158,35 +158,6 @@ def human_readable_size(n):
|
|||
return f"{n:,.2f} {suffixes[i]}"
|
||||
|
||||
|
||||
class RPCLogger:
|
||||
def log_request(self, request, name, description):
|
||||
LOG.info(
|
||||
f"{name} {request.http_verb} {request.method}"
|
||||
+ (truncate(f" {request.params}") if request.params is not None else "")
|
||||
+ f"{description}"
|
||||
)
|
||||
|
||||
def log_response(self, response):
|
||||
LOG.debug(response)
|
||||
|
||||
|
||||
class RPCFileLogger(RPCLogger):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def log_request(self, request, name, description):
|
||||
with open(self.path, "a") as f:
|
||||
f.write(f">> Request: {request.http_verb} {request.method}" + os.linesep)
|
||||
json.dump(request.params, f, indent=2)
|
||||
f.write(os.linesep)
|
||||
|
||||
def log_response(self, response):
|
||||
with open(self.path, "a") as f:
|
||||
f.write("<< Response:" + os.linesep)
|
||||
json.dump(response.to_dict() if response else "None", f, indent=2)
|
||||
f.write(os.linesep)
|
||||
|
||||
|
||||
class CCFConnectionException(Exception):
|
||||
pass
|
||||
|
||||
|
@ -245,7 +216,7 @@ class CurlClient:
|
|||
else:
|
||||
cmd = ["curl"]
|
||||
|
||||
url = f"https://{self.host}:{self.port}{request.method}"
|
||||
url = f"https://{self.host}:{self.port}{request.path}"
|
||||
|
||||
if request.params_in_query:
|
||||
if request.params is not None:
|
||||
|
@ -269,7 +240,7 @@ class CurlClient:
|
|||
msg_bytes = request.params
|
||||
else:
|
||||
msg_bytes = json.dumps(request.params).encode()
|
||||
LOG.debug(f"Writing request body: {msg_bytes}")
|
||||
LOG.debug(f"Writing request body: {truncate(msg_bytes)}")
|
||||
nf.write(msg_bytes)
|
||||
nf.flush()
|
||||
cmd.extend(["--data-binary", f"@{nf.name}"])
|
||||
|
@ -367,7 +338,7 @@ class RequestClient:
|
|||
|
||||
request_args = {
|
||||
"method": request.http_verb,
|
||||
"url": f"https://{self.host}:{self.port}{request.method}",
|
||||
"url": f"https://{self.host}:{self.port}{request.path}",
|
||||
"auth": auth_value,
|
||||
"headers": extra_headers,
|
||||
}
|
||||
|
@ -434,7 +405,7 @@ class WSClient:
|
|||
except Exception as exc:
|
||||
raise CCFConnectionException from exc
|
||||
payload = json.dumps(request.params).encode()
|
||||
path = (request.method).encode()
|
||||
path = (request.path).encode()
|
||||
header = struct.pack("<h", len(path)) + path
|
||||
# FIN, no RSV, BIN, UNMASKED every time, because it's all we support right now
|
||||
frame = websocket.ABNF(
|
||||
|
@ -447,13 +418,12 @@ class WSClient:
|
|||
(view,) = struct.unpack("<Q", out[10:18])
|
||||
(global_commit,) = struct.unpack("<Q", out[18:26])
|
||||
payload = out[26:]
|
||||
# TODO: move out the decoding!
|
||||
if status == 200:
|
||||
result = json.loads(payload) if payload else None
|
||||
error = None
|
||||
body = json.loads(payload) if payload else None
|
||||
else:
|
||||
result = None
|
||||
error = payload.decode()
|
||||
return Response(status, result, error, seqno, view, global_commit, headers={})
|
||||
body = payload.decode()
|
||||
return Response(status, body, seqno, view, global_commit, headers={})
|
||||
|
||||
|
||||
class CCFClient:
|
||||
|
@ -466,7 +436,6 @@ class CCFClient:
|
|||
if "connection_timeout" in kwargs
|
||||
else DEFAULT_CONNECTION_TIMEOUT_SEC
|
||||
)
|
||||
self.rpc_loggers = (RPCLogger(),)
|
||||
self.name = f"[{host}:{port}]"
|
||||
|
||||
if os.getenv("CURL_CLIENT"):
|
||||
|
@ -477,31 +446,28 @@ class CCFClient:
|
|||
self.client_impl = RequestClient(host, port, *args, **kwargs)
|
||||
|
||||
def _response(self, response):
|
||||
for logger in self.rpc_loggers:
|
||||
logger.log_response(response)
|
||||
LOG.info(response)
|
||||
return response
|
||||
|
||||
# pylint: disable=method-hidden
|
||||
def _just_rpc(self, method, *args, **kwargs):
|
||||
def _direct_call(self, method, *args, **kwargs):
|
||||
is_signed = "signed" in kwargs and kwargs.pop("signed")
|
||||
r = Request(method, *args, **kwargs)
|
||||
|
||||
description = ""
|
||||
if self.description:
|
||||
description = f" ({self.description})" + (" [signed]" if is_signed else "")
|
||||
for logger in self.rpc_loggers:
|
||||
logger.log_request(r, self.name, description)
|
||||
|
||||
LOG.info(f"{self.name} {r} ({description})")
|
||||
return self._response(self.client_impl.request(r, is_signed))
|
||||
|
||||
def rpc(self, *args, **kwargs):
|
||||
def call(self, *args, **kwargs):
|
||||
end_time = time.time() + self.connection_timeout
|
||||
while True:
|
||||
try:
|
||||
response = self._just_rpc(*args, **kwargs)
|
||||
response = self._direct_call(*args, **kwargs)
|
||||
# Only the first request gets this timeout logic - future calls
|
||||
# call _just_rpc directly
|
||||
self.rpc = self._just_rpc
|
||||
# call _direct_call directly
|
||||
self.call = self._direct_call
|
||||
return response
|
||||
except (CCFConnectionException, TimeoutError) as e:
|
||||
# If the initial connection fails (e.g. due to node certificate
|
||||
|
@ -514,16 +480,16 @@ class CCFClient:
|
|||
time.sleep(0.1)
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.rpc(*args, http_verb="GET", **kwargs)
|
||||
return self.call(*args, http_verb="GET", **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.rpc(*args, http_verb="POST", **kwargs)
|
||||
return self.call(*args, http_verb="POST", **kwargs)
|
||||
|
||||
def put(self, *args, **kwargs):
|
||||
return self.rpc(*args, http_verb="PUT", **kwargs)
|
||||
return self.call(*args, http_verb="PUT", **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
return self.rpc(*args, http_verb="DELETE", **kwargs)
|
||||
return self.call(*args, http_verb="DELETE", **kwargs)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
@ -534,7 +500,6 @@ def client(
|
|||
key=None,
|
||||
ca=None,
|
||||
description=None,
|
||||
log_file=None,
|
||||
binary_dir=".",
|
||||
connection_timeout=DEFAULT_CONNECTION_TIMEOUT_SEC,
|
||||
request_timeout=DEFAULT_REQUEST_TIMEOUT_SEC,
|
||||
|
@ -553,7 +518,4 @@ def client(
|
|||
ws=ws,
|
||||
)
|
||||
|
||||
if log_file is not None:
|
||||
c.rpc_loggers += (RPCFileLogger(log_file),)
|
||||
|
||||
yield c
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "consensus/pbft/pbft_requests.h"
|
||||
#include "node/encryptor.h"
|
||||
#include "node/history.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "tests/flatbuffer_wrapper_test.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
@ -38,7 +38,7 @@ static std::vector<uint8_t> packed_json_tx()
|
|||
nlohmann::json j;
|
||||
j["name"] = std::to_string(account_name);
|
||||
j["value"] = transaction_value;
|
||||
return jsonrpc::pack(j, jsonrpc::Pack::MsgPack);
|
||||
return serdes::pack(j, serdes::Pack::MsgPack);
|
||||
}
|
||||
|
||||
static std::unique_ptr<flatbuffers::DetachedBuffer> fb_tx_buffer()
|
||||
|
@ -117,7 +117,7 @@ static void json_msgpack_des(picobench::state& s)
|
|||
s.start_timer();
|
||||
for (int i = 0; i < s.iterations(); i++)
|
||||
{
|
||||
auto params = jsonrpc::unpack(p, jsonrpc::Pack::MsgPack);
|
||||
auto params = serdes::unpack(p, serdes::Pack::MsgPack);
|
||||
std::string name = params["name"];
|
||||
int64_t value = params["value"];
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ static void jm_large_payload(picobench::state& s)
|
|||
auto payload = large_payload(S);
|
||||
nlohmann::json j;
|
||||
j["data"] = payload;
|
||||
auto d = jsonrpc::pack(j, jsonrpc::Pack::MsgPack);
|
||||
auto d = serdes::pack(j, serdes::Pack::MsgPack);
|
||||
auto data = kv_serialized_data(d);
|
||||
run_mt_benchmark(s, data);
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ def run(args):
|
|||
check = ccf.checker.Checker()
|
||||
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"REG_register",
|
||||
{
|
||||
"regulator_id": regulator.ccf_id,
|
||||
|
@ -113,7 +113,7 @@ def run(args):
|
|||
result=regulator.ccf_id,
|
||||
)
|
||||
check(
|
||||
c.rpc("REG_get", {"id": regulator.ccf_id}),
|
||||
c.post("REG_get", {"id": regulator.ccf_id}),
|
||||
result=[
|
||||
regulator.country,
|
||||
scripts[regulator.name],
|
||||
|
@ -128,12 +128,12 @@ def run(args):
|
|||
check = ccf.checker.Checker()
|
||||
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"BK_register", {"bank_id": bank.ccf_id, "country": bank.country}
|
||||
),
|
||||
result=bank.ccf_id,
|
||||
)
|
||||
check(c.rpc("BK_get", {"id": bank.ccf_id}), result=bank.country)
|
||||
check(c.post("BK_get", {"id": bank.ccf_id}), result=bank.country)
|
||||
LOG.debug(f"User {bank} successfully registered as bank")
|
||||
|
||||
LOG.success(
|
||||
|
@ -145,7 +145,7 @@ def run(args):
|
|||
|
||||
with primary.user_client(format="msgpack", user_id=regulators[0].name) as reg_c:
|
||||
with primary.user_client(
|
||||
format="msgpack", user_id=banks[0].name, log_file=None
|
||||
format="msgpack", user_id=banks[0].name
|
||||
) as c:
|
||||
with open(args.datafile, newline="") as f:
|
||||
start_time = perf_counter()
|
||||
|
@ -163,7 +163,7 @@ def run(args):
|
|||
"dst_country": row["dst_country"],
|
||||
}
|
||||
|
||||
check(c.rpc("TX_record", json_tx), result=tx_id)
|
||||
check(c.post("TX_record", json_tx), result=tx_id)
|
||||
print(json.dumps(json_tx))
|
||||
tx_id += 1
|
||||
|
||||
|
|
|
@ -44,16 +44,16 @@ def run(args):
|
|||
) as c:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
resp = reg_c.rpc("REG_poll_flagged").to_dict()
|
||||
resp = reg_c.post("REG_poll_flagged").to_dict()
|
||||
|
||||
if "result" in resp:
|
||||
flagged_txs = resp["result"]
|
||||
|
||||
for flagged in flagged_txs:
|
||||
# bank reveal the transaction
|
||||
c.rpc("TX_reveal", {"tx_id": flagged[0]})
|
||||
c.post("TX_reveal", {"tx_id": flagged[0]})
|
||||
# regulator get the transaction
|
||||
tx_resp = reg_c.rpc(
|
||||
tx_resp = reg_c.post(
|
||||
"REG_get_revealed", {"tx_id": flagged[0]}
|
||||
).to_dict()
|
||||
if "result" in tx_resp:
|
||||
|
|
|
@ -25,7 +25,7 @@ class AppUser:
|
|||
network.consortium.add_users(primary, [self.name])
|
||||
|
||||
with primary.client(f"user{self.name}") as client:
|
||||
self.ccf_id = client.get("/app/user_id").result["caller_id"]
|
||||
self.ccf_id = client.get("/app/user_id").body["caller_id"]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.ccf_id} ({self.name})"
|
||||
|
@ -91,18 +91,18 @@ def run(args):
|
|||
# Check permissions are enforced
|
||||
with primary.client(f"user{regulator.name}") as c:
|
||||
check(
|
||||
c.rpc("/app/REG_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
c.post("/app/REG_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
)
|
||||
check(
|
||||
c.rpc("/app/BK_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
c.post("/app/BK_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
)
|
||||
|
||||
with primary.client(f"user{banks[0].name}") as c:
|
||||
check(
|
||||
c.rpc("/app/REG_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
c.post("/app/REG_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
)
|
||||
check(
|
||||
c.rpc("/app/BK_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
c.post("/app/BK_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
)
|
||||
|
||||
# As permissioned manager, register regulator and banks
|
||||
|
@ -111,7 +111,7 @@ def run(args):
|
|||
|
||||
with primary.client(f"user{manager.name}") as c:
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"/app/REG_register",
|
||||
{
|
||||
"regulator_id": regulator.ccf_id,
|
||||
|
@ -122,12 +122,12 @@ def run(args):
|
|||
result=regulator.ccf_id,
|
||||
)
|
||||
check(
|
||||
c.rpc("/app/REG_get", {"id": regulator.ccf_id}),
|
||||
c.post("/app/REG_get", {"id": regulator.ccf_id}),
|
||||
result=[regulator.country, script],
|
||||
)
|
||||
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"/app/BK_register",
|
||||
{"bank_id": regulator.ccf_id, "country": regulator.country},
|
||||
),
|
||||
|
@ -137,16 +137,16 @@ def run(args):
|
|||
|
||||
for bank in banks:
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"/app/BK_register",
|
||||
{"bank_id": bank.ccf_id, "country": bank.country},
|
||||
),
|
||||
result=bank.ccf_id,
|
||||
)
|
||||
check(c.rpc("/app/BK_get", {"id": bank.ccf_id}), result=bank.country)
|
||||
check(c.post("/app/BK_get", {"id": bank.ccf_id}), result=bank.country)
|
||||
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"/app/REG_register",
|
||||
{"regulator_id": bank.ccf_id, "country": bank.country},
|
||||
),
|
||||
|
@ -171,9 +171,9 @@ def run(args):
|
|||
print(transaction)
|
||||
amount = transaction["amt"]
|
||||
|
||||
check(c.rpc("/app/TX_record", transaction), result=tx_id)
|
||||
check(c.post("/app/TX_record", transaction), result=tx_id)
|
||||
check(
|
||||
c.rpc("/app/TX_get", {"tx_id": tx_id}),
|
||||
c.post("/app/TX_get", {"tx_id": tx_id}),
|
||||
result={
|
||||
"amt": amount,
|
||||
"bank_id": bank.ccf_id,
|
||||
|
@ -187,7 +187,7 @@ def run(args):
|
|||
)
|
||||
if float(amount) > flagged_amt:
|
||||
check(
|
||||
c.rpc("/app/FLAGGED_TX_get", {"tx_id": tx_id}),
|
||||
c.post("/app/FLAGGED_TX_get", {"tx_id": tx_id}),
|
||||
result=[regulator.ccf_id, False, transaction["timestamp"]],
|
||||
)
|
||||
flagged_tx = {
|
||||
|
@ -205,7 +205,7 @@ def run(args):
|
|||
flagged_txs[tx_id] = flagged_tx
|
||||
else:
|
||||
check(
|
||||
c.rpc("/app/FLAGGED_TX_get", {"tx_id": tx_id}),
|
||||
c.post("/app/FLAGGED_TX_get", {"tx_id": tx_id}),
|
||||
error=check_status(http.HTTPStatus.BAD_REQUEST),
|
||||
)
|
||||
non_flagged_ids.append(tx_id)
|
||||
|
@ -217,20 +217,20 @@ def run(args):
|
|||
with primary.client(f"user{bank.name}") as c:
|
||||
# try to poll flagged but fail as you are not a regulator
|
||||
check(
|
||||
c.rpc("/app/REG_poll_flagged"),
|
||||
c.post("/app/REG_poll_flagged"),
|
||||
error=check_status(http.HTTPStatus.FORBIDDEN),
|
||||
)
|
||||
|
||||
# bank reveal some transactions that were flagged
|
||||
for i, tx_id in enumerate(flagged_ids):
|
||||
if i % 2 == 0:
|
||||
check(c.rpc("/app/TX_reveal", {"tx_id": tx_id}), result=True)
|
||||
check(c.post("/app/TX_reveal", {"tx_id": tx_id}), result=True)
|
||||
revealed_tx_ids.append(tx_id)
|
||||
|
||||
# bank try to reveal non flagged txs
|
||||
for tx_id in non_flagged_ids:
|
||||
check(
|
||||
c.rpc("/app/TX_reveal", {"tx_id": tx_id}),
|
||||
c.post("/app/TX_reveal", {"tx_id": tx_id}),
|
||||
error=check_status(http.HTTPStatus.BAD_REQUEST),
|
||||
)
|
||||
|
||||
|
@ -238,9 +238,9 @@ def run(args):
|
|||
with primary.client() as mc:
|
||||
with primary.client(f"user{regulator.name}") as c:
|
||||
# assert that the flagged txs that we poll for are correct
|
||||
resp = c.rpc("/app/REG_poll_flagged")
|
||||
resp = c.post("/app/REG_poll_flagged")
|
||||
poll_flagged_ids = []
|
||||
for poll_flagged in resp.result:
|
||||
for poll_flagged in resp.body:
|
||||
# poll flagged is a list [tx_id, regulator_id]
|
||||
poll_flagged_ids.append(poll_flagged[0])
|
||||
poll_flagged_ids.sort()
|
||||
|
@ -250,14 +250,14 @@ def run(args):
|
|||
# get from flagged txs, try to get the flagged one that was not revealed
|
||||
if tx_id not in revealed_tx_ids:
|
||||
check(
|
||||
c.rpc("/app/REG_get_revealed", {"tx_id": tx_id}),
|
||||
c.post("/app/REG_get_revealed", {"tx_id": tx_id}),
|
||||
error=check_status(http.HTTPStatus.BAD_REQUEST),
|
||||
)
|
||||
|
||||
# get from flagged txs, try to get the flagged ones that were revealed
|
||||
for tx_id in revealed_tx_ids:
|
||||
check(
|
||||
c.rpc("/app/REG_get_revealed", {"tx_id": tx_id}),
|
||||
c.post("/app/REG_get_revealed", {"tx_id": tx_id}),
|
||||
result=flagged_txs[tx_id],
|
||||
)
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ namespace ccfapp
|
|||
|
||||
args.rpc_ctx->set_response_status(HTTP_STATUS_OK);
|
||||
args.rpc_ctx->set_response_body(
|
||||
jsonrpc::pack(response, jsonrpc::Pack::Text));
|
||||
serdes::pack(response, serdes::Pack::Text));
|
||||
args.rpc_ctx->set_response_header(
|
||||
http::headers::CONTENT_TYPE, http::headervalues::contenttype::JSON);
|
||||
return;
|
||||
|
|
|
@ -394,7 +394,7 @@ namespace loggingapp
|
|||
{
|
||||
nlohmann::json notify_j;
|
||||
notify_j["commit"] = version;
|
||||
notifier.notify(jsonrpc::pack(notify_j, jsonrpc::Pack::Text));
|
||||
notifier.notify(serdes::pack(notify_j, serdes::Pack::Text));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "lua_interp/lua_interp.h"
|
||||
#include "node/genesis_gen.h"
|
||||
#include "node/rpc/json_handler.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "node/rpc/test/node_stub.h"
|
||||
#include "runtime_config/default_whitelists.h"
|
||||
#include "tls/key_pair.h"
|
||||
|
@ -23,12 +23,12 @@
|
|||
using namespace ccfapp;
|
||||
using namespace ccf;
|
||||
using namespace std;
|
||||
using namespace jsonrpc;
|
||||
using namespace serdes;
|
||||
using namespace nlohmann;
|
||||
|
||||
auto kp = tls::make_key_pair();
|
||||
|
||||
constexpr auto default_format = jsonrpc::Pack::MsgPack;
|
||||
constexpr auto default_format = serdes::Pack::MsgPack;
|
||||
constexpr auto content_type =
|
||||
ccf::jsonhandler::pack_to_content_type(default_format);
|
||||
|
||||
|
@ -56,7 +56,7 @@ TResponse check_error(const vector<uint8_t>& v, http_status expected)
|
|||
template <typename T>
|
||||
T parse_response_body(const TResponse& r)
|
||||
{
|
||||
const auto body_j = jsonrpc::unpack(r.body, default_format);
|
||||
const auto body_j = serdes::unpack(r.body, default_format);
|
||||
return body_j.get<T>();
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ std::vector<uint8_t> make_pc(const string& method, const Params& params)
|
|||
{
|
||||
auto request = http::Request(method);
|
||||
request.set_header(http::headers::CONTENT_TYPE, content_type);
|
||||
const auto body = jsonrpc::pack(params, default_format);
|
||||
const auto body = serdes::pack(params, default_format);
|
||||
request.set_body(&body);
|
||||
return request.build_request();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "http/http_parser.h"
|
||||
#include "http/ws_builder.h"
|
||||
#include "http/ws_parser.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "tls_client.h"
|
||||
|
||||
#define FMT_HEADER_ONLY
|
||||
|
@ -163,7 +163,7 @@ public:
|
|||
std::vector<uint8_t> body;
|
||||
if (!params.is_null())
|
||||
{
|
||||
body = jsonrpc::pack(params, jsonrpc::Pack::MsgPack);
|
||||
body = serdes::pack(params, serdes::Pack::MsgPack);
|
||||
}
|
||||
return gen_request(
|
||||
method,
|
||||
|
@ -222,7 +222,7 @@ public:
|
|||
else if (http::status_success(resp.status))
|
||||
{
|
||||
const auto& content_type = resp.headers.find(http::headers::CONTENT_TYPE);
|
||||
return jsonrpc::unpack(resp.body, jsonrpc::Pack::MsgPack);
|
||||
return serdes::unpack(resp.body, serdes::Pack::MsgPack);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -273,11 +273,11 @@ namespace ccf
|
|||
tx, caller, id, method, params = ...
|
||||
|
||||
function jsucc(id, result)
|
||||
return {jsonrpc = "2.0", id = id, result = result}
|
||||
return {serdes = "2.0", id = id, result = result}
|
||||
end
|
||||
|
||||
function jerr(id, code, message)
|
||||
return {jsonrpc = "2.0", id = id, error = {code = code, message = message}}
|
||||
return {serdes = "2.0", id = id, error = {code = code, message = message}}
|
||||
end
|
||||
|
||||
handlers = {}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "genesis_gen.h"
|
||||
#include "history.h"
|
||||
#include "network_state.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "node_to_node.h"
|
||||
#include "notifier.h"
|
||||
#include "rpc/frontend.h"
|
||||
|
@ -382,7 +382,7 @@ namespace ccf
|
|||
return false;
|
||||
}
|
||||
|
||||
auto j = jsonrpc::unpack(data, jsonrpc::Pack::Text);
|
||||
auto j = serdes::unpack(data, serdes::Pack::Text);
|
||||
|
||||
JoinNetworkNodeToNode::Out resp;
|
||||
try
|
||||
|
@ -471,7 +471,7 @@ namespace ccf
|
|||
args.config.joining.target_host,
|
||||
args.config.joining.target_port);
|
||||
|
||||
const auto body = jsonrpc::pack(join_params, jsonrpc::Pack::Text);
|
||||
const auto body = serdes::pack(join_params, serdes::Pack::Text);
|
||||
|
||||
http::Request r(fmt::format(
|
||||
"/{}/{}", ccf::get_actor_prefix(ccf::ActorsType::nodes), "join"));
|
||||
|
@ -1171,7 +1171,7 @@ namespace ccf
|
|||
create_params.consensus_type = network.consensus_type;
|
||||
create_params.recovery_threshold = args.config.genesis.recovery_threshold;
|
||||
|
||||
const auto body = jsonrpc::pack(create_params, jsonrpc::Pack::Text);
|
||||
const auto body = serdes::pack(create_params, serdes::Pack::Text);
|
||||
|
||||
http::Request request(fmt::format(
|
||||
"/{}/{}", ccf::get_actor_prefix(ccf::ActorsType::members), "create"));
|
||||
|
@ -1218,7 +1218,7 @@ namespace ccf
|
|||
return false;
|
||||
}
|
||||
|
||||
const auto body = jsonrpc::unpack(r.body, jsonrpc::Pack::Text);
|
||||
const auto body = serdes::unpack(r.body, serdes::Pack::Text);
|
||||
if (!body.is_boolean())
|
||||
{
|
||||
LOG_FAIL_FMT("Expected boolean body in create response");
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "enclave/rpc_context.h"
|
||||
#include "endpoint_registry.h"
|
||||
#include "http/http_consts.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
|
||||
#include <http-parser/http_parser.h>
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace ccf
|
|||
* Rather than:
|
||||
* auto foo = [](auto& args) {
|
||||
* nlohmann::json params;
|
||||
* jsonrpc::Pack pack_type;
|
||||
* serdes::Pack pack_type;
|
||||
* if (<content-type is JSON>)
|
||||
* {
|
||||
* params = unpack(args.rpc_ctx->get_request_body());
|
||||
|
@ -72,15 +72,15 @@ namespace ccf
|
|||
|
||||
using JsonAdapterResponse = std::variant<ErrorDetails, nlohmann::json>;
|
||||
|
||||
static constexpr char const* pack_to_content_type(jsonrpc::Pack p)
|
||||
static constexpr char const* pack_to_content_type(serdes::Pack p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case jsonrpc::Pack::Text:
|
||||
case serdes::Pack::Text:
|
||||
{
|
||||
return http::headervalues::contenttype::JSON;
|
||||
}
|
||||
case jsonrpc::Pack::MsgPack:
|
||||
case serdes::Pack::MsgPack:
|
||||
{
|
||||
return http::headervalues::contenttype::MSGPACK;
|
||||
}
|
||||
|
@ -91,10 +91,10 @@ namespace ccf
|
|||
}
|
||||
}
|
||||
|
||||
static jsonrpc::Pack detect_json_pack(
|
||||
static serdes::Pack detect_json_pack(
|
||||
const std::shared_ptr<enclave::RpcContext>& ctx)
|
||||
{
|
||||
std::optional<jsonrpc::Pack> packing = std::nullopt;
|
||||
std::optional<serdes::Pack> packing = std::nullopt;
|
||||
|
||||
const auto content_type_it =
|
||||
ctx->get_request_header(http::headers::CONTENT_TYPE);
|
||||
|
@ -103,11 +103,11 @@ namespace ccf
|
|||
const auto& content_type = content_type_it.value();
|
||||
if (content_type == http::headervalues::contenttype::JSON)
|
||||
{
|
||||
packing = jsonrpc::Pack::Text;
|
||||
packing = serdes::Pack::Text;
|
||||
}
|
||||
else if (content_type == http::headervalues::contenttype::MSGPACK)
|
||||
{
|
||||
packing = jsonrpc::Pack::MsgPack;
|
||||
packing = serdes::Pack::MsgPack;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -121,16 +121,16 @@ namespace ccf
|
|||
}
|
||||
else
|
||||
{
|
||||
packing = jsonrpc::detect_pack(ctx->get_request_body());
|
||||
packing = serdes::detect_pack(ctx->get_request_body());
|
||||
}
|
||||
|
||||
return packing.value_or(jsonrpc::Pack::Text);
|
||||
return packing.value_or(serdes::Pack::Text);
|
||||
}
|
||||
|
||||
static nlohmann::json get_params_from_body(
|
||||
const std::shared_ptr<enclave::RpcContext>& ctx, jsonrpc::Pack pack)
|
||||
const std::shared_ptr<enclave::RpcContext>& ctx, serdes::Pack pack)
|
||||
{
|
||||
return jsonrpc::unpack(ctx->get_request_body(), pack);
|
||||
return serdes::unpack(ctx->get_request_body(), pack);
|
||||
}
|
||||
|
||||
static nlohmann::json get_params_from_query(
|
||||
|
@ -176,7 +176,7 @@ namespace ccf
|
|||
return params;
|
||||
}
|
||||
|
||||
static std::pair<jsonrpc::Pack, nlohmann::json> get_json_params(
|
||||
static std::pair<serdes::Pack, nlohmann::json> get_json_params(
|
||||
const std::shared_ptr<enclave::RpcContext>& ctx)
|
||||
{
|
||||
const auto pack = detect_json_pack(ctx);
|
||||
|
@ -200,7 +200,7 @@ namespace ccf
|
|||
static void set_response(
|
||||
JsonAdapterResponse&& res,
|
||||
std::shared_ptr<enclave::RpcContext>& ctx,
|
||||
jsonrpc::Pack packing)
|
||||
serdes::Pack packing)
|
||||
{
|
||||
auto error = std::get_if<ErrorDetails>(&res);
|
||||
if (error != nullptr)
|
||||
|
@ -214,20 +214,20 @@ namespace ccf
|
|||
ctx->set_response_status(HTTP_STATUS_OK);
|
||||
switch (packing)
|
||||
{
|
||||
case jsonrpc::Pack::Text:
|
||||
case serdes::Pack::Text:
|
||||
{
|
||||
const auto s = fmt::format("{}\n", body->dump());
|
||||
ctx->set_response_body(std::vector<uint8_t>(s.begin(), s.end()));
|
||||
break;
|
||||
}
|
||||
case jsonrpc::Pack::MsgPack:
|
||||
case serdes::Pack::MsgPack:
|
||||
{
|
||||
ctx->set_response_body(nlohmann::json::to_msgpack(*body));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw std::logic_error("Unhandled jsonrpc::Pack");
|
||||
throw std::logic_error("Unhandled serdes::Pack");
|
||||
}
|
||||
}
|
||||
ctx->set_response_header(
|
||||
|
|
|
@ -1,362 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ds/json.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace jsonrpc
|
||||
{
|
||||
using SeqNo = uint64_t;
|
||||
|
||||
static constexpr auto RPC_VERSION = "2.0";
|
||||
static constexpr auto ID = "id";
|
||||
static constexpr auto JSON_RPC = "jsonrpc";
|
||||
static constexpr auto METHOD = "method";
|
||||
static constexpr auto READONLY = "readonly";
|
||||
static constexpr auto PARAMS = "params";
|
||||
static constexpr auto RESULT = "result";
|
||||
static constexpr auto ERR = "error";
|
||||
static constexpr auto CODE = "code";
|
||||
static constexpr auto MESSAGE = "message";
|
||||
static constexpr auto DATA = "data";
|
||||
static constexpr auto SIG = "sig";
|
||||
static constexpr auto REQ = "req";
|
||||
|
||||
// -32000 to -32099 are reserved for implementation-defined server-errors
|
||||
#define XX_STANDARD_ERROR_CODES \
|
||||
XX(PARSE_ERROR, -32700) \
|
||||
XX(INVALID_REQUEST, -32600) \
|
||||
XX(METHOD_NOT_FOUND, -32601) \
|
||||
XX(INVALID_PARAMS, -32602) \
|
||||
XX(INTERNAL_ERROR, -32603) \
|
||||
XX(SERVER_ERROR_START, -32000) \
|
||||
XX(SERVER_ERROR_END, -32099)
|
||||
|
||||
#define XX_CCF_ERROR_CODES \
|
||||
XX(TX_NOT_PRIMARY, -32001) \
|
||||
XX(TX_FAILED_TO_REPLICATE, -32002) \
|
||||
XX(SCRIPT_ERROR, -32003) \
|
||||
XX(INSUFFICIENT_RIGHTS, -32004) \
|
||||
XX(TX_PRIMARY_UNKNOWN, -32005) \
|
||||
XX(RPC_NOT_SIGNED, -32006) \
|
||||
XX(INVALID_CLIENT_SIGNATURE, -32007) \
|
||||
XX(INVALID_CALLER_ID, -32008) \
|
||||
XX(CODE_ID_NOT_FOUND, -32009) \
|
||||
XX(CODE_ID_RETIRED, -32010) \
|
||||
XX(RPC_NOT_FORWARDED, -32011) \
|
||||
XX(QUOTE_NOT_VERIFIED, -32012) \
|
||||
XX(APP_ERROR_START, -32050)
|
||||
|
||||
using ErrorBaseType = int;
|
||||
|
||||
enum StandardErrorCodes : ErrorBaseType
|
||||
{
|
||||
#define XX(Name, Value) Name = Value,
|
||||
XX_STANDARD_ERROR_CODES
|
||||
#undef XX
|
||||
};
|
||||
|
||||
enum CCFErrorCodes : ErrorBaseType
|
||||
{
|
||||
#define XX(Name, Value) Name = Value,
|
||||
XX_CCF_ERROR_CODES
|
||||
#undef XX
|
||||
};
|
||||
|
||||
inline std::string get_error_prefix(ErrorBaseType ec)
|
||||
{
|
||||
#define XX(Name, Value) \
|
||||
case (CCFErrorCodes::Name): \
|
||||
return "[" #Name "]: ";
|
||||
|
||||
switch (CCFErrorCodes(ec))
|
||||
{
|
||||
XX_CCF_ERROR_CODES
|
||||
}
|
||||
#undef XX
|
||||
|
||||
#define XX(Name, Value) \
|
||||
case (StandardErrorCodes::Name): \
|
||||
return "[" #Name "]: ";
|
||||
|
||||
switch (StandardErrorCodes(ec))
|
||||
{
|
||||
XX_STANDARD_ERROR_CODES
|
||||
}
|
||||
#undef XX
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
enum class Pack
|
||||
{
|
||||
Text,
|
||||
MsgPack
|
||||
};
|
||||
|
||||
inline std::vector<uint8_t> pack(const nlohmann::json& j, Pack pack)
|
||||
{
|
||||
switch (pack)
|
||||
{
|
||||
case Pack::Text:
|
||||
{
|
||||
auto s = j.dump();
|
||||
return std::vector<uint8_t>{s.begin(), s.end()};
|
||||
}
|
||||
|
||||
case Pack::MsgPack:
|
||||
return nlohmann::json::to_msgpack(j);
|
||||
}
|
||||
|
||||
throw std::logic_error("Invalid jsonrpc::Pack");
|
||||
}
|
||||
|
||||
inline nlohmann::json unpack(const std::vector<uint8_t>& data, Pack pack)
|
||||
{
|
||||
switch (pack)
|
||||
{
|
||||
case Pack::Text:
|
||||
return nlohmann::json::parse(data);
|
||||
|
||||
case Pack::MsgPack:
|
||||
return nlohmann::json::from_msgpack(data);
|
||||
}
|
||||
|
||||
throw std::logic_error("Invalid jsonrpc::Pack");
|
||||
}
|
||||
|
||||
inline std::optional<jsonrpc::Pack> detect_pack(
|
||||
const std::vector<uint8_t>& input)
|
||||
{
|
||||
if (input.size() == 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (input[0] == '{')
|
||||
{
|
||||
return jsonrpc::Pack::Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
return jsonrpc::Pack::MsgPack;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Requests
|
||||
//
|
||||
struct ProcedureCallBase
|
||||
{
|
||||
std::string method;
|
||||
SeqNo id;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& j, const ProcedureCallBase& pc)
|
||||
{
|
||||
j[JSON_RPC] = RPC_VERSION;
|
||||
j[ID] = pc.id;
|
||||
j[METHOD] = pc.method;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, ProcedureCallBase& pc)
|
||||
{
|
||||
std::string jsonRpc = j[JSON_RPC];
|
||||
if (jsonRpc != RPC_VERSION)
|
||||
throw std::logic_error("Wrong JSON-RPC version: " + j.dump());
|
||||
pc.id = j[ID];
|
||||
assign_j(pc.method, j[METHOD]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct ProcedureCall : public ProcedureCallBase
|
||||
{
|
||||
T params = {};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void to_json(nlohmann::json& j, const ProcedureCall<T>& pc)
|
||||
{
|
||||
to_json(j, dynamic_cast<const ProcedureCallBase&>(pc));
|
||||
j[PARAMS] = pc.params;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void from_json(const nlohmann::json& j, ProcedureCall<T>& pc)
|
||||
{
|
||||
from_json(j, dynamic_cast<ProcedureCallBase&>(pc));
|
||||
pc.params = j[PARAMS];
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProcedureCall<void> : public ProcedureCallBase
|
||||
{};
|
||||
|
||||
template <>
|
||||
inline void to_json(nlohmann::json& j, const ProcedureCall<void>& pc)
|
||||
{
|
||||
to_json(j, dynamic_cast<const ProcedureCallBase&>(pc));
|
||||
j[PARAMS] = nlohmann::json::object();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void from_json(const nlohmann::json& j, ProcedureCall<void>& pc)
|
||||
{
|
||||
from_json(j, dynamic_cast<ProcedureCallBase&>(pc));
|
||||
}
|
||||
|
||||
//
|
||||
// Responses
|
||||
//
|
||||
template <typename T>
|
||||
struct Response
|
||||
{
|
||||
T result;
|
||||
SeqNo id;
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
return &result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void to_json(nlohmann::json& j, const Response<T>& r)
|
||||
{
|
||||
j[JSON_RPC] = RPC_VERSION;
|
||||
j[ID] = r.id;
|
||||
j[RESULT] = r.result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void from_json(const nlohmann::json& j, Response<T>& r)
|
||||
{
|
||||
std::string jsonRpc = j[JSON_RPC];
|
||||
if (jsonRpc != RPC_VERSION)
|
||||
throw std::logic_error("Wrong JSON-RPC version: " + j.dump());
|
||||
|
||||
r.id = j[ID];
|
||||
auto search = j.find(RESULT);
|
||||
if (search == j.end())
|
||||
throw std::logic_error("No result field: " + j.dump());
|
||||
|
||||
decltype(r.result) temp = *search;
|
||||
r.result = temp;
|
||||
}
|
||||
|
||||
struct Error
|
||||
{
|
||||
ErrorBaseType code;
|
||||
std::string message;
|
||||
|
||||
template <typename ErrorEnum>
|
||||
Error(ErrorEnum error_code, const std::string& msg = "") :
|
||||
code(static_cast<ErrorBaseType>(error_code)),
|
||||
message(get_error_prefix(code) + msg)
|
||||
{}
|
||||
};
|
||||
DECLARE_JSON_TYPE(Error)
|
||||
DECLARE_JSON_REQUIRED_FIELDS(Error, code, message)
|
||||
|
||||
template <typename T>
|
||||
struct ErrorEx : public Error
|
||||
{
|
||||
T data;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void to_json(nlohmann::json& j, const ErrorEx<T>& e)
|
||||
{
|
||||
j[CODE] = e.code;
|
||||
j[MESSAGE] = e.message;
|
||||
j[DATA] = e.data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void from_json(const nlohmann::json& j, ErrorEx<T>& e)
|
||||
{
|
||||
e.code = j[CODE];
|
||||
e.message = j[MESSAGE];
|
||||
e.data = j[DATA];
|
||||
}
|
||||
|
||||
template <typename ErrorEnum>
|
||||
inline std::pair<bool, nlohmann::json> error(
|
||||
ErrorEnum error_code, const std::string msg = "")
|
||||
{
|
||||
return std::make_pair(false, Error(error_code, msg));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::pair<bool, nlohmann::json> success(T&& result)
|
||||
{
|
||||
nlohmann::json j(result);
|
||||
return std::make_pair(true, j);
|
||||
}
|
||||
|
||||
inline nlohmann::json result_response(SeqNo id, const nlohmann::json& result)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j[JSON_RPC] = RPC_VERSION;
|
||||
j[ID] = id;
|
||||
j[RESULT] = result;
|
||||
return j;
|
||||
}
|
||||
|
||||
inline nlohmann::json error_response(SeqNo id, const nlohmann::json& error)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j[JSON_RPC] = RPC_VERSION;
|
||||
j[ID] = id;
|
||||
j[ERR] = error;
|
||||
return j;
|
||||
}
|
||||
|
||||
template <typename ErrorEnum>
|
||||
inline nlohmann::json error_response(
|
||||
SeqNo id, ErrorEnum error_code, const std::string& msg)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j[JSON_RPC] = RPC_VERSION;
|
||||
j[ID] = id;
|
||||
j[ERR] = Error(error_code, msg);
|
||||
return j;
|
||||
}
|
||||
|
||||
inline std::pair<bool, nlohmann::json> unpack_rpc(
|
||||
const std::vector<uint8_t>& input, std::optional<Pack>& o_pack)
|
||||
{
|
||||
const auto pack = detect_pack(input);
|
||||
if (!pack.has_value())
|
||||
{
|
||||
return jsonrpc::error(
|
||||
StandardErrorCodes::INVALID_REQUEST,
|
||||
"Unable to detect packing format of request");
|
||||
}
|
||||
|
||||
o_pack = pack;
|
||||
|
||||
nlohmann::json rpc;
|
||||
try
|
||||
{
|
||||
rpc = unpack(input, pack.value());
|
||||
if (!rpc.is_object())
|
||||
{
|
||||
return jsonrpc::error(
|
||||
StandardErrorCodes::INVALID_REQUEST,
|
||||
fmt::format("RPC payload is a not a valid object: {}", rpc.dump()));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return error(
|
||||
StandardErrorCodes::INVALID_REQUEST,
|
||||
fmt::format("Exception during unpack: {}", e.what()));
|
||||
}
|
||||
|
||||
return {true, rpc};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ds/json.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace serdes
|
||||
{
|
||||
enum class Pack
|
||||
{
|
||||
Text,
|
||||
MsgPack
|
||||
};
|
||||
|
||||
inline std::vector<uint8_t> pack(const nlohmann::json& j, Pack pack)
|
||||
{
|
||||
switch (pack)
|
||||
{
|
||||
case Pack::Text:
|
||||
{
|
||||
auto s = j.dump();
|
||||
return std::vector<uint8_t>{s.begin(), s.end()};
|
||||
}
|
||||
|
||||
case Pack::MsgPack:
|
||||
return nlohmann::json::to_msgpack(j);
|
||||
}
|
||||
|
||||
throw std::logic_error("Invalid serdes::Pack");
|
||||
}
|
||||
|
||||
inline nlohmann::json unpack(const std::vector<uint8_t>& data, Pack pack)
|
||||
{
|
||||
switch (pack)
|
||||
{
|
||||
case Pack::Text:
|
||||
return nlohmann::json::parse(data);
|
||||
|
||||
case Pack::MsgPack:
|
||||
return nlohmann::json::from_msgpack(data);
|
||||
}
|
||||
|
||||
throw std::logic_error("Invalid serdes::Pack");
|
||||
}
|
||||
|
||||
inline std::optional<serdes::Pack> detect_pack(
|
||||
const std::vector<uint8_t>& input)
|
||||
{
|
||||
if (input.size() == 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (input[0] == '{')
|
||||
{
|
||||
return serdes::Pack::Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
return serdes::Pack::MsgPack;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,9 +13,9 @@
|
|||
#include "node/history.h"
|
||||
#include "node/network_state.h"
|
||||
#include "node/rpc/json_handler.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/member_frontend.h"
|
||||
#include "node/rpc/node_frontend.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "node/rpc/user_frontend.h"
|
||||
#include "node/test/channel_stub.h"
|
||||
#include "node_stub.h"
|
||||
|
@ -33,7 +33,7 @@ using namespace ccfapp;
|
|||
using namespace ccf;
|
||||
using namespace std;
|
||||
|
||||
static constexpr auto default_pack = jsonrpc::Pack::MsgPack;
|
||||
static constexpr auto default_pack = serdes::Pack::MsgPack;
|
||||
|
||||
class TestUserFrontend : public SimpleUserRpcFrontend
|
||||
{
|
||||
|
@ -157,7 +157,7 @@ public:
|
|||
|
||||
auto maybe_commit = [this](EndpointContext& args) {
|
||||
const auto parsed =
|
||||
jsonrpc::unpack(args.rpc_ctx->get_request_body(), default_pack);
|
||||
serdes::unpack(args.rpc_ctx->get_request_body(), default_pack);
|
||||
|
||||
const auto new_value = parsed["value"].get<size_t>();
|
||||
auto view = args.tx.get_view(values);
|
||||
|
@ -363,7 +363,7 @@ StubNodeState stub_node(share_manager);
|
|||
|
||||
auto create_simple_request(
|
||||
const std::string& method = "empty_function",
|
||||
jsonrpc::Pack pack = default_pack)
|
||||
serdes::Pack pack = default_pack)
|
||||
{
|
||||
http::Request request(method);
|
||||
request.set_header(
|
||||
|
@ -402,9 +402,9 @@ http::SimpleResponseProcessor::Response parse_response(const vector<uint8_t>& v)
|
|||
}
|
||||
|
||||
nlohmann::json parse_response_body(
|
||||
const vector<uint8_t>& body, jsonrpc::Pack pack = default_pack)
|
||||
const vector<uint8_t>& body, serdes::Pack pack = default_pack)
|
||||
{
|
||||
return jsonrpc::unpack(body, pack);
|
||||
return serdes::unpack(body, pack);
|
||||
}
|
||||
|
||||
std::optional<SignedReq> get_signed_req(CallerId caller_id)
|
||||
|
@ -515,7 +515,7 @@ TEST_CASE("process_pbft")
|
|||
auto simple_call = create_simple_request();
|
||||
|
||||
const nlohmann::json call_body = {{"foo", "bar"}, {"baz", 42}};
|
||||
const auto serialized_body = jsonrpc::pack(call_body, default_pack);
|
||||
const auto serialized_body = serdes::pack(call_body, default_pack);
|
||||
simple_call.set_body(&serialized_body);
|
||||
|
||||
const auto serialized_call = simple_call.build_request();
|
||||
|
@ -813,14 +813,14 @@ TEST_CASE("MinimalEndpointFunction")
|
|||
{
|
||||
prepare_callers();
|
||||
TestMinimalEndpointFunction frontend(*network.tables);
|
||||
for (const auto pack_type : {jsonrpc::Pack::Text, jsonrpc::Pack::MsgPack})
|
||||
for (const auto pack_type : {serdes::Pack::Text, serdes::Pack::MsgPack})
|
||||
{
|
||||
{
|
||||
INFO("Calling echo, with params in body");
|
||||
auto echo_call = create_simple_request("echo", pack_type);
|
||||
const nlohmann::json j_body = {{"data", {"nested", "Some string"}},
|
||||
{"other", "Another string"}};
|
||||
const auto serialized_body = jsonrpc::pack(j_body, pack_type);
|
||||
const auto serialized_body = serdes::pack(j_body, pack_type);
|
||||
|
||||
auto [signed_call, signed_req] =
|
||||
create_signed_request(echo_call, &serialized_body);
|
||||
|
@ -892,7 +892,7 @@ TEST_CASE("MinimalEndpointFunction")
|
|||
auto fail = create_simple_request("failable");
|
||||
const nlohmann::json j_body = {
|
||||
{"error", {{"code", err}, {"message", msg}}}};
|
||||
const auto serialized_body = jsonrpc::pack(j_body, default_pack);
|
||||
const auto serialized_body = serdes::pack(j_body, default_pack);
|
||||
|
||||
const auto [signed_call, signed_req] =
|
||||
create_signed_request(fail, &serialized_body);
|
||||
|
@ -1022,7 +1022,7 @@ TEST_CASE("Explicit commitability")
|
|||
|
||||
const nlohmann::json request_body = {{"value", new_value},
|
||||
{"status", status}};
|
||||
const auto serialized_body = jsonrpc::pack(request_body, default_pack);
|
||||
const auto serialized_body = serdes::pack(request_body, default_pack);
|
||||
request.set_body(&serialized_body);
|
||||
|
||||
const auto serialized_request = request.build_request();
|
||||
|
@ -1058,7 +1058,7 @@ TEST_CASE("Explicit commitability")
|
|||
|
||||
const nlohmann::json request_body = {
|
||||
{"value", new_value}, {"apply", apply}, {"status", status}};
|
||||
const auto serialized_body = jsonrpc::pack(request_body, default_pack);
|
||||
const auto serialized_body = serdes::pack(request_body, default_pack);
|
||||
request.set_body(&serialized_body);
|
||||
|
||||
const auto serialized_request = request.build_request();
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#include "kv/test/null_encryptor.h"
|
||||
#include "node/client_signatures.h"
|
||||
#include "node/genesis_gen.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/member_frontend.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "node/rpc/user_frontend.h"
|
||||
#include "node_stub.h"
|
||||
#include "runtime_config/default_whitelists.h"
|
||||
|
@ -26,7 +26,7 @@ extern "C"
|
|||
using namespace ccfapp;
|
||||
using namespace ccf;
|
||||
using namespace std;
|
||||
using namespace jsonrpc;
|
||||
using namespace serdes;
|
||||
using namespace nlohmann;
|
||||
|
||||
using TResponse = http::SimpleResponseProcessor::Response;
|
||||
|
@ -41,7 +41,7 @@ std::vector<uint8_t> dummy_key_share = {1, 2, 3};
|
|||
|
||||
auto encryptor = std::make_shared<kv::NullTxEncryptor>();
|
||||
|
||||
constexpr auto default_pack = jsonrpc::Pack::Text;
|
||||
constexpr auto default_pack = serdes::Pack::Text;
|
||||
|
||||
string get_script_path(string name)
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ T parse_response_body(const TResponse& r)
|
|||
nlohmann::json body_j;
|
||||
try
|
||||
{
|
||||
body_j = jsonrpc::unpack(r.body, jsonrpc::Pack::Text);
|
||||
body_j = serdes::unpack(r.body, serdes::Pack::Text);
|
||||
}
|
||||
catch (const nlohmann::json::parse_error& e)
|
||||
{
|
||||
|
@ -113,7 +113,7 @@ std::vector<uint8_t> create_request(
|
|||
{
|
||||
http::Request r(method_name, verb);
|
||||
const auto body = params.is_null() ? std::vector<uint8_t>() :
|
||||
jsonrpc::pack(params, default_pack);
|
||||
serdes::pack(params, default_pack);
|
||||
r.set_body(&body);
|
||||
return r.build_request();
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ std::vector<uint8_t> create_signed_request(
|
|||
http::Request r(method_name, verb);
|
||||
|
||||
const auto body = params.is_null() ? std::vector<uint8_t>() :
|
||||
jsonrpc::pack(params, default_pack);
|
||||
serdes::pack(params, default_pack);
|
||||
|
||||
r.set_body(&body);
|
||||
http::sign_request(r, kp_);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include "ds/logger.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "node/genesis_gen.h"
|
||||
#include "node/rpc/json_rpc.h"
|
||||
#include "node/rpc/node_frontend.h"
|
||||
#include "node/rpc/serdes.h"
|
||||
#include "node_stub.h"
|
||||
#include "tls/pem.h"
|
||||
#include "tls/verifier.h"
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
using namespace ccf;
|
||||
using namespace nlohmann;
|
||||
using namespace jsonrpc;
|
||||
using namespace serdes;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ TResponse frontend_process(
|
|||
http::Request r(method);
|
||||
const auto body = json_params.is_null() ?
|
||||
std::vector<uint8_t>() :
|
||||
jsonrpc::pack(json_params, Pack::Text);
|
||||
serdes::pack(json_params, Pack::Text);
|
||||
r.set_body(&body);
|
||||
auto serialise_request = r.build_request();
|
||||
|
||||
|
@ -72,7 +72,7 @@ TResponse frontend_process(
|
|||
template <typename T>
|
||||
T parse_response_body(const TResponse& r)
|
||||
{
|
||||
const auto body_j = jsonrpc::unpack(r.body, jsonrpc::Pack::Text);
|
||||
const auto body_j = serdes::unpack(r.body, serdes::Pack::Text);
|
||||
return body_j.get<T>();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ def run(args):
|
|||
|
||||
with primary.client() as uc:
|
||||
r = uc.get("/node/code")
|
||||
assert r.result == {
|
||||
assert r.body == {
|
||||
"versions": [{"digest": first_code_id, "status": "ACCEPTED"}],
|
||||
}, r.result
|
||||
}, r.body
|
||||
|
||||
LOG.info("Adding a new node")
|
||||
new_node = network.create_and_trust_node(args.package, "localhost", args)
|
||||
|
@ -71,7 +71,7 @@ def run(args):
|
|||
|
||||
with primary.client() as uc:
|
||||
r = uc.get("/node/code")
|
||||
versions = sorted(r.result["versions"], key=lambda x: x["digest"])
|
||||
versions = sorted(r.body["versions"], key=lambda x: x["digest"])
|
||||
expected = sorted(
|
||||
[
|
||||
{"digest": first_code_id, "status": "ACCEPTED"},
|
||||
|
|
|
@ -43,7 +43,7 @@ def run(args):
|
|||
LOG.error(f"Failed to connect client {i}")
|
||||
|
||||
c = clients[int(random.random() * len(clients))]
|
||||
check(c.rpc("/app/log/private", {"id": 42, "msg": "foo"}), result=True)
|
||||
check(c.post("/app/log/private", {"id": 42, "msg": "foo"}), result=True)
|
||||
|
||||
assert (
|
||||
len(clients) >= max_fds - num_fds - 1
|
||||
|
@ -64,7 +64,7 @@ def run(args):
|
|||
LOG.info(f"Connected client {i}")
|
||||
|
||||
c = clients[int(random.random() * len(clients))]
|
||||
check(c.rpc("/app/log/private", {"id": 42, "msg": "foo"}), result=True)
|
||||
check(c.post("/app/log/private", {"id": 42, "msg": "foo"}), result=True)
|
||||
|
||||
assert (
|
||||
len(clients) >= max_fds - num_fds - 1
|
||||
|
|
|
@ -35,7 +35,7 @@ def test(network, args, batch_size=100, write_key_divisor=1, write_size_multipli
|
|||
|
||||
pre_submit = time.time()
|
||||
check(
|
||||
c.rpc(
|
||||
c.post(
|
||||
"/app/BATCH_submit",
|
||||
{
|
||||
"entries": messages,
|
||||
|
@ -50,7 +50,7 @@ def test(network, args, batch_size=100, write_key_divisor=1, write_size_multipli
|
|||
f"Submitting {batch_size} new keys took {post_submit - pre_submit}s"
|
||||
)
|
||||
|
||||
fetch_response = c.rpc("/app/BATCH_fetch", message_ids)
|
||||
fetch_response = c.post("/app/BATCH_fetch", message_ids)
|
||||
|
||||
if write_key_divisor == 1 and write_size_multiplier == 1:
|
||||
check(fetch_response, result=messages)
|
||||
|
|
|
@ -88,7 +88,7 @@ def test_large_messages(network, args):
|
|||
for p in range(14, 20) if args.consensus == "raft" else range(10, 13):
|
||||
long_msg = "X" * (2 ** p)
|
||||
check_commit(
|
||||
c.rpc("/app/log/private", {"id": log_id, "msg": long_msg}),
|
||||
c.post("/app/log/private", {"id": log_id, "msg": long_msg}),
|
||||
result=True,
|
||||
)
|
||||
check(
|
||||
|
@ -117,7 +117,7 @@ def test_remove(network, args):
|
|||
for table in ["private", "public"]:
|
||||
resource = f"/app/log/{table}"
|
||||
check_commit(
|
||||
c.rpc(resource, {"id": log_id, "msg": msg}), result=True,
|
||||
c.post(resource, {"id": log_id, "msg": msg}), result=True,
|
||||
)
|
||||
check(c.get(resource, {"id": log_id}), result={"msg": msg})
|
||||
check(
|
||||
|
@ -153,10 +153,9 @@ def test_cert_prefix(network, args):
|
|||
with primary.client(f"user{user_id}") as c:
|
||||
log_id = 101
|
||||
msg = "This message will be prefixed"
|
||||
c.rpc("/app/log/private/prefix_cert", {"id": log_id, "msg": msg})
|
||||
c.post("/app/log/private/prefix_cert", {"id": log_id, "msg": msg})
|
||||
r = c.get("/app/log/private", {"id": log_id})
|
||||
assert r.result is not None
|
||||
assert f"CN=user{user_id}" in r.result["msg"]
|
||||
assert f"CN=user{user_id}" in r.body["msg"], r
|
||||
|
||||
else:
|
||||
LOG.warning(
|
||||
|
@ -178,17 +177,15 @@ def test_anonymous_caller(network, args):
|
|||
log_id = 101
|
||||
msg = "This message is anonymous"
|
||||
with primary.client("user4") as c:
|
||||
r = c.rpc("/app/log/private/anonymous", {"id": log_id, "msg": msg})
|
||||
assert r.result == True
|
||||
r = c.post("/app/log/private/anonymous", {"id": log_id, "msg": msg})
|
||||
assert r.body == True
|
||||
r = c.get("/app/log/private", {"id": log_id})
|
||||
assert (
|
||||
r.error is not None
|
||||
), "Anonymous user is not authorised to call log/private"
|
||||
assert r.status == 403, r
|
||||
|
||||
with primary.client("user0") as c:
|
||||
r = c.get("/app/log/private", {"id": log_id})
|
||||
assert r.result is not None
|
||||
assert msg in r.result["msg"]
|
||||
assert msg in r.body["msg"], r
|
||||
|
||||
else:
|
||||
LOG.warning(
|
||||
f"Skipping {inspect.currentframe().f_code.co_name} as application is not C++"
|
||||
|
@ -206,15 +203,14 @@ def test_raw_text(network, args):
|
|||
log_id = 101
|
||||
msg = "This message is not in JSON"
|
||||
with primary.client("user0") as c:
|
||||
r = c.rpc(
|
||||
r = c.post(
|
||||
f"/app/log/private/raw_text/{log_id}",
|
||||
msg,
|
||||
headers={"content-type": "text/plain"},
|
||||
)
|
||||
assert r.status == http.HTTPStatus.OK.value
|
||||
r = c.get("/app/log/private", {"id": log_id})
|
||||
assert r.result is not None
|
||||
assert msg in r.result["msg"]
|
||||
assert msg in r.body["msg"], r
|
||||
|
||||
else:
|
||||
LOG.warning(
|
||||
|
@ -241,14 +237,14 @@ def test_historical_query(network, args):
|
|||
with primary.client("user0") as c:
|
||||
log_id = 10
|
||||
msg = "This tests historical queries"
|
||||
record_response = c.rpc("/app/log/private", {"id": log_id, "msg": msg})
|
||||
record_response = c.post("/app/log/private", {"id": log_id, "msg": msg})
|
||||
check_commit(record_response, result=True)
|
||||
view = record_response.view
|
||||
seqno = record_response.seqno
|
||||
|
||||
msg2 = "This overwrites the original message"
|
||||
check_commit(
|
||||
c.rpc("/app/log/private", {"id": log_id, "msg": msg2}), result=True
|
||||
c.post("/app/log/private", {"id": log_id, "msg": msg2}), result=True
|
||||
)
|
||||
check(c.get("/app/log/private", {"id": log_id}), result={"msg": msg2})
|
||||
|
||||
|
@ -274,9 +270,7 @@ def test_historical_query(network, args):
|
|||
retry_after = int(retry_after)
|
||||
time.sleep(retry_after)
|
||||
elif get_response.status == http.HTTPStatus.OK:
|
||||
assert (
|
||||
get_response.result["msg"] == msg
|
||||
), f"{get_response.result}"
|
||||
assert get_response.body["msg"] == msg, get_response
|
||||
found = True
|
||||
break
|
||||
elif get_response.status == http.HTTPStatus.NO_CONTENT:
|
||||
|
@ -285,7 +279,7 @@ def test_historical_query(network, args):
|
|||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unexpected response status {get_response.status}: {get_response.error}"
|
||||
f"Unexpected response status {get_response.status}: {get_response.body}"
|
||||
)
|
||||
|
||||
if not found:
|
||||
|
@ -318,7 +312,7 @@ def test_forwarding_frontends(network, args):
|
|||
msg = "forwarded_msg"
|
||||
log_id = 123
|
||||
check_commit(
|
||||
c.rpc("/app/log/private", {"id": log_id, "msg": msg}), result=True,
|
||||
c.post("/app/log/private", {"id": log_id, "msg": msg}), result=True,
|
||||
)
|
||||
check(c.get("/app/log/private", {"id": log_id}), result={"msg": msg})
|
||||
|
||||
|
@ -351,7 +345,7 @@ def test_update_lua(network, args):
|
|||
remote_node=primary, app_script_path=new_app_file
|
||||
)
|
||||
with primary.client("user0") as c:
|
||||
check(c.rpc("/app/ping"), result="pong")
|
||||
check(c.post("/app/ping"), result="pong")
|
||||
|
||||
LOG.debug("Check that former endpoints no longer exists")
|
||||
for endpoint in [
|
||||
|
@ -359,7 +353,7 @@ def test_update_lua(network, args):
|
|||
"/app/log/public",
|
||||
]:
|
||||
check(
|
||||
c.rpc(endpoint),
|
||||
c.post(endpoint),
|
||||
error=lambda status, msg: status == http.HTTPStatus.NOT_FOUND.value,
|
||||
)
|
||||
else:
|
||||
|
@ -388,13 +382,8 @@ def test_view_history(network, args):
|
|||
r = c.get("/node/commit")
|
||||
check(c)
|
||||
|
||||
commit_view = r.result["view"]
|
||||
commit_seqno = r.result["seqno"]
|
||||
|
||||
# Temporarily disable logging of RPCs for readability
|
||||
rpc_loggers = c.rpc_loggers
|
||||
c.rpc_loggers = ()
|
||||
LOG.warning("RPC logging temporarily suppressed")
|
||||
commit_view = r.body["view"]
|
||||
commit_seqno = r.body["seqno"]
|
||||
|
||||
# Retrieve status for all possible Tx IDs
|
||||
seqno_to_views = {}
|
||||
|
@ -403,14 +392,11 @@ def test_view_history(network, args):
|
|||
for view in range(1, commit_view + 1):
|
||||
r = c.get("/node/tx", {"view": view, "seqno": seqno})
|
||||
check(r)
|
||||
status = TxStatus(r.result["status"])
|
||||
status = TxStatus(r.body["status"])
|
||||
if status == TxStatus.Committed:
|
||||
views.append(view)
|
||||
seqno_to_views[seqno] = views
|
||||
|
||||
c.rpc_loggers = rpc_loggers
|
||||
LOG.warning("RPC logging restored")
|
||||
|
||||
# Check we have exactly one Tx ID for each seqno
|
||||
txs_ok = True
|
||||
for seqno, views in seqno_to_views.items():
|
||||
|
@ -486,7 +472,7 @@ def test_tx_statuses(network, args):
|
|||
|
||||
with primary.client("user0") as c:
|
||||
check = ccf.checker.Checker()
|
||||
r = c.rpc("/app/log/private", {"id": 0, "msg": "Ignored"})
|
||||
r = c.post("/app/log/private", {"id": 0, "msg": "Ignored"})
|
||||
check(r)
|
||||
# Until this tx is globally committed, poll for the status of this and some other
|
||||
# related transactions around it (and also any historical transactions we're tracking)
|
||||
|
@ -507,7 +493,7 @@ def test_tx_statuses(network, args):
|
|||
for view, seqno in SentTxs.get_all_tx_ids():
|
||||
r = c.get("/node/tx", {"view": view, "seqno": seqno})
|
||||
check(r)
|
||||
status = TxStatus(r.result["status"])
|
||||
status = TxStatus(r.body["status"])
|
||||
SentTxs.update_status(view, seqno, status)
|
||||
if (
|
||||
status == TxStatus.Committed
|
||||
|
|
|
@ -52,7 +52,7 @@ def run(args):
|
|||
txs += json.load(f)
|
||||
|
||||
for tx in txs:
|
||||
r = client.rpc(
|
||||
r = client.call(
|
||||
tx["method"],
|
||||
params=tx["params"],
|
||||
http_verb=tx.get("verb", "POST"),
|
||||
|
|
|
@ -46,7 +46,7 @@ def wait_for_seqno_to_commit(seqno, view, nodes):
|
|||
assert (
|
||||
r.status == http.HTTPStatus.OK
|
||||
), f"tx request returned HTTP status {r.status}"
|
||||
status = TxStatus(r.result["status"])
|
||||
status = TxStatus(r.body["status"])
|
||||
if status == TxStatus.Committed:
|
||||
up_to_date_f.append(f.node_id)
|
||||
elif status == TxStatus.Invalid:
|
||||
|
@ -95,7 +95,7 @@ def run(args):
|
|||
)
|
||||
)
|
||||
with primary.client("user0") as c:
|
||||
res = c.rpc(
|
||||
res = c.post(
|
||||
"/app/log/private",
|
||||
{
|
||||
"id": current_view,
|
||||
|
|
|
@ -38,7 +38,7 @@ def test_quote(network, args, notifications_queue=None, verify=True):
|
|||
expected_mrenclave = lines[0].strip().split("=")[1]
|
||||
|
||||
r = c.get("/node/quote")
|
||||
quotes = r.result["quotes"]
|
||||
quotes = r.body["quotes"]
|
||||
assert len(quotes) == 1
|
||||
primary_quote = quotes[0]
|
||||
assert primary_quote["node_id"] == 0
|
||||
|
@ -49,7 +49,7 @@ def test_quote(network, args, notifications_queue=None, verify=True):
|
|||
)
|
||||
|
||||
r = c.get("/node/quotes")
|
||||
quotes = r.result["quotes"]
|
||||
quotes = r.body["quotes"]
|
||||
assert len(quotes) == len(network.find_nodes())
|
||||
for quote in quotes:
|
||||
mrenclave = quote["mrenclave"]
|
||||
|
|
|
@ -96,7 +96,7 @@ def run(args):
|
|||
new_member_proposal.proposer_id
|
||||
).withdraw(primary, new_member_proposal)
|
||||
assert response.status == http.HTTPStatus.OK.value
|
||||
assert response.result["state"] == ProposalState.Withdrawn.value
|
||||
assert response.body["state"] == ProposalState.Withdrawn.value
|
||||
withdrawals_issued += 1
|
||||
|
||||
(final_proposals, final_votes, final_withdrawals,) = count_governance_operations(
|
||||
|
|
|
@ -46,7 +46,7 @@ class Consortium:
|
|||
self.recovery_threshold = len(self.members)
|
||||
else:
|
||||
with remote_node.client("member0") as mc:
|
||||
r = mc.rpc(
|
||||
r = mc.post(
|
||||
"/gov/query",
|
||||
{
|
||||
"text": """tables = ...
|
||||
|
@ -60,7 +60,7 @@ class Consortium:
|
|||
"""
|
||||
},
|
||||
)
|
||||
for m in r.result or []:
|
||||
for m in r.body or []:
|
||||
new_member = infra.member.Member(
|
||||
m[0], curve, self.common_dir, share_script
|
||||
)
|
||||
|
@ -72,7 +72,7 @@ class Consortium:
|
|||
self.members.append(new_member)
|
||||
LOG.info(f"Successfully recovered member {m[0]} with status {m[1]}")
|
||||
|
||||
r = mc.rpc(
|
||||
r = mc.post(
|
||||
"/gov/query",
|
||||
{
|
||||
"text": """tables = ...
|
||||
|
@ -80,7 +80,7 @@ class Consortium:
|
|||
"""
|
||||
},
|
||||
)
|
||||
self.recovery_threshold = r.result["recovery_threshold"]
|
||||
self.recovery_threshold = r.body["recovery_threshold"]
|
||||
|
||||
def activate(self, remote_node):
|
||||
for m in self.members:
|
||||
|
@ -157,7 +157,7 @@ class Consortium:
|
|||
wait_for_global_commit=wait_for_global_commit,
|
||||
)
|
||||
assert response.status == http.HTTPStatus.OK.value
|
||||
proposal.state = infra.proposal.ProposalState(response.result["state"])
|
||||
proposal.state = infra.proposal.ProposalState(response.body["state"])
|
||||
proposal.increment_votes_for()
|
||||
|
||||
if proposal.state is not ProposalState.Accepted:
|
||||
|
@ -176,9 +176,9 @@ class Consortium:
|
|||
|
||||
proposals = []
|
||||
with remote_node.client(f"member{self.get_any_active_member().member_id}") as c:
|
||||
r = c.rpc("/gov/query", {"text": script})
|
||||
r = c.post("/gov/query", {"text": script})
|
||||
assert r.status == http.HTTPStatus.OK.value
|
||||
for proposal_id, attr in r.result.items():
|
||||
for proposal_id, attr in r.body.items():
|
||||
has_proposer_voted_for = False
|
||||
for vote in attr["votes"]:
|
||||
if attr["proposer"] == vote[0]:
|
||||
|
@ -203,10 +203,10 @@ class Consortium:
|
|||
self.vote_using_majority(remote_node, proposal)
|
||||
|
||||
with remote_node.client(f"member{self.get_any_active_member().member_id}") as c:
|
||||
r = c.rpc(
|
||||
r = c.post(
|
||||
"/gov/read", {"table": "ccf.nodes", "key": node_to_retire.node_id}
|
||||
)
|
||||
assert r.result["status"] == infra.node.NodeStatus.RETIRED.name
|
||||
assert r.body["status"] == infra.node.NodeStatus.RETIRED.name
|
||||
|
||||
def trust_node(self, remote_node, node_id):
|
||||
if not self._check_node_exists(
|
||||
|
@ -314,10 +314,10 @@ class Consortium:
|
|||
check_commit(r)
|
||||
|
||||
if submitted_shares_count >= self.recovery_threshold:
|
||||
assert "End of recovery procedure initiated" in r.result
|
||||
assert "End of recovery procedure initiated" in r.body
|
||||
break
|
||||
else:
|
||||
assert "End of recovery procedure initiated" not in r.result
|
||||
assert "End of recovery procedure initiated" not in r.body
|
||||
|
||||
def set_recovery_threshold(self, remote_node, recovery_threshold):
|
||||
proposal_body, careful_vote = self.proposal_generator.set_recovery_threshold(
|
||||
|
@ -352,7 +352,7 @@ class Consortium:
|
|||
f"member{self.get_any_active_member().member_id}",
|
||||
request_timeout=(30 if pbft_open else 3),
|
||||
) as c:
|
||||
r = c.rpc(
|
||||
r = c.post(
|
||||
"/gov/query",
|
||||
{
|
||||
"text": """tables = ...
|
||||
|
@ -374,8 +374,8 @@ class Consortium:
|
|||
"""
|
||||
},
|
||||
)
|
||||
current_status = r.result["status"]
|
||||
current_cert = array.array("B", r.result["cert"]).tobytes()
|
||||
current_status = r.body["status"]
|
||||
current_cert = array.array("B", r.body["cert"]).tobytes()
|
||||
|
||||
expected_cert = open(
|
||||
os.path.join(self.common_dir, "networkcert.pem"), "rb"
|
||||
|
@ -389,10 +389,10 @@ class Consortium:
|
|||
|
||||
def _check_node_exists(self, remote_node, node_id, node_status=None):
|
||||
with remote_node.client(f"member{self.get_any_active_member().member_id}") as c:
|
||||
r = c.rpc("/gov/read", {"table": "ccf.nodes", "key": node_id})
|
||||
r = c.post("/gov/read", {"table": "ccf.nodes", "key": node_id})
|
||||
|
||||
if r.error is not None or (
|
||||
node_status and r.result["status"] != node_status.name
|
||||
if r.status != 200 or (
|
||||
node_status and r.body["status"] != node_status.name
|
||||
):
|
||||
return False
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ def cli_args(add=lambda x: None, parser=None, accept_unknown=False):
|
|||
"--ledger-recovery-timeout",
|
||||
help="On recovery, maximum timeout (s) while reading the ledger",
|
||||
type=int,
|
||||
default=10,
|
||||
default=30,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ledger-chunk-max-bytes",
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the Apache 2.0 License.
|
||||
|
||||
from enum import IntEnum
|
||||
|
||||
# Values defined in node/rpc/jsonrpc.h
|
||||
class ErrorCode(IntEnum):
|
||||
# Standard JSON RPC errors
|
||||
PARSE_ERROR = -32700
|
||||
INVALID_REQUEST = -32600
|
||||
METHOD_NOT_FOUND = -32601
|
||||
INVALID_PARAMS = -32602
|
||||
INTERNAL_ERROR = -32603
|
||||
|
||||
# CCF-specific errors
|
||||
SERVER_ERROR_START = -32000
|
||||
TX_NOT_PRIMARY = -32001
|
||||
TX_FAILED_TO_REPLICATE = -32002
|
||||
SCRIPT_ERROR = -32003
|
||||
INSUFFICIENT_RIGHTS = -32004
|
||||
TX_PRIMARY_UNKNOWN = -32005
|
||||
RPC_NOT_SIGNED = -32006
|
||||
INVALID_CLIENT_SIGNATURE = -32007
|
||||
INVALID_CALLER_ID = -32008
|
||||
CODE_ID_NOT_FOUND = -32009
|
||||
CODE_ID_RETIRED = -32010
|
||||
RPC_NOT_FORWARDED = -32011
|
||||
QUOTE_NOT_VERIFIED = -32012
|
||||
SERVER_ERROR_END = -32099
|
|
@ -101,11 +101,11 @@ class LoggingTxs:
|
|||
f"Private message at index {self.next_priv_index}"
|
||||
)
|
||||
pub_msg = f"Public message at index {self.next_pub_index}"
|
||||
rep_priv = uc.rpc(
|
||||
rep_priv = uc.post(
|
||||
"/app/log/private",
|
||||
{"id": self.next_priv_index, "msg": priv_msg,},
|
||||
)
|
||||
rep_pub = uc.rpc(
|
||||
rep_pub = uc.post(
|
||||
"/app/log/public",
|
||||
{"id": self.next_pub_index, "msg": pub_msg,},
|
||||
)
|
||||
|
|
|
@ -67,14 +67,14 @@ class Member:
|
|||
|
||||
def propose(self, remote_node, proposal, has_proposer_voted_for=True):
|
||||
with remote_node.client(f"member{self.member_id}") as mc:
|
||||
r = mc.rpc("/gov/proposals", proposal, signed=True,)
|
||||
r = mc.post("/gov/proposals", proposal, signed=True,)
|
||||
if r.status != http.HTTPStatus.OK.value:
|
||||
raise infra.proposal.ProposalNotCreated(r)
|
||||
|
||||
return infra.proposal.Proposal(
|
||||
proposer_id=self.member_id,
|
||||
proposal_id=r.result["proposal_id"],
|
||||
state=infra.proposal.ProposalState(r.result["state"]),
|
||||
proposal_id=r.body["proposal_id"],
|
||||
state=infra.proposal.ProposalState(r.body["state"]),
|
||||
has_proposer_voted_for=has_proposer_voted_for,
|
||||
)
|
||||
|
||||
|
@ -82,20 +82,20 @@ class Member:
|
|||
self, remote_node, proposal, accept=True, wait_for_global_commit=True,
|
||||
):
|
||||
with remote_node.client(f"member{self.member_id}") as mc:
|
||||
r = mc.rpc(
|
||||
r = mc.post(
|
||||
f"/gov/proposals/{proposal.proposal_id}/votes",
|
||||
params=proposal.vote_for,
|
||||
signed=True,
|
||||
)
|
||||
|
||||
if r.error is not None:
|
||||
if r.status != 200:
|
||||
return r
|
||||
|
||||
# If the proposal was accepted, wait for it to be globally committed
|
||||
# This is particularly useful for the open network proposal to wait
|
||||
# until the global hook on the SERVICE table is triggered
|
||||
if (
|
||||
r.result["state"] == infra.proposal.ProposalState.Accepted.value
|
||||
r.body["state"] == infra.proposal.ProposalState.Accepted.value
|
||||
and wait_for_global_commit
|
||||
):
|
||||
with remote_node.client() as mc:
|
||||
|
@ -109,24 +109,24 @@ class Member:
|
|||
|
||||
def withdraw(self, remote_node, proposal):
|
||||
with remote_node.client(f"member{self.member_id}") as c:
|
||||
r = c.rpc(f"/gov/proposals/{proposal.proposal_id}/withdraw", signed=True)
|
||||
r = c.post(f"/gov/proposals/{proposal.proposal_id}/withdraw", signed=True)
|
||||
if r.status == http.HTTPStatus.OK.value:
|
||||
proposal.state = infra.proposal.ProposalState.Withdrawn
|
||||
return r
|
||||
|
||||
def update_ack_state_digest(self, remote_node):
|
||||
with remote_node.client(f"member{self.member_id}") as mc:
|
||||
r = mc.rpc("/gov/ack/update_state_digest")
|
||||
assert r.error is None, f"Error ack/update_state_digest: {r.error}"
|
||||
return bytearray(r.result["state_digest"])
|
||||
r = mc.post("/gov/ack/update_state_digest")
|
||||
assert r.status == 200, f"Error ack/update_state_digest: {r}"
|
||||
return bytearray(r.body["state_digest"])
|
||||
|
||||
def ack(self, remote_node):
|
||||
state_digest = self.update_ack_state_digest(remote_node)
|
||||
with remote_node.client(f"member{self.member_id}") as mc:
|
||||
r = mc.rpc(
|
||||
r = mc.post(
|
||||
"/gov/ack", params={"state_digest": list(state_digest)}, signed=True
|
||||
)
|
||||
assert r.error is None, f"Error ACK: {r.error}"
|
||||
assert r.status == 200, f"Error ACK: {r}"
|
||||
self.status = MemberStatus.ACTIVE
|
||||
return r
|
||||
|
||||
|
@ -141,10 +141,8 @@ class Member:
|
|||
defunct_network_enc_pubk,
|
||||
)
|
||||
|
||||
nonce_bytes = base64.b64decode(r.result["nonce"])
|
||||
encrypted_share_bytes = base64.b64decode(
|
||||
r.result["encrypted_recovery_share"]
|
||||
)
|
||||
nonce_bytes = base64.b64decode(r.body["nonce"])
|
||||
encrypted_share_bytes = base64.b64decode(r.body["encrypted_recovery_share"])
|
||||
return ctx.decrypt(encrypted_share_bytes, nonce_bytes)
|
||||
|
||||
def get_and_submit_recovery_share(self, remote_node, defunct_network_enc_pubk):
|
||||
|
|
|
@ -137,9 +137,9 @@ class Network:
|
|||
|
||||
with primary.client() as nc:
|
||||
r = nc.get("/node/primary_info")
|
||||
first_node_id = r.result["primary_id"]
|
||||
assert (r.result["primary_host"] == primary.host) and (
|
||||
int(r.result["primary_port"]) == primary.rpc_port
|
||||
first_node_id = r.body["primary_id"]
|
||||
assert (r.body["primary_host"] == primary.host) and (
|
||||
int(r.body["primary_port"]) == primary.rpc_port
|
||||
), "Primary is not the node that just started"
|
||||
for n in self.nodes:
|
||||
n.node_id = n.node_id + first_node_id
|
||||
|
@ -489,8 +489,7 @@ class Network:
|
|||
try:
|
||||
with node.client(connection_timeout=timeout) as c:
|
||||
r = c.get("/node/state")
|
||||
LOG.info(r.result)
|
||||
if r.result["state"] == state:
|
||||
if r.body["state"] == state:
|
||||
break
|
||||
except ConnectionRefusedError:
|
||||
pass
|
||||
|
@ -519,12 +518,12 @@ class Network:
|
|||
with node.client(request_timeout=request_timeout) as c:
|
||||
try:
|
||||
res = c.get("/node/primary_info")
|
||||
if res.error is None:
|
||||
primary_id = res.result["primary_id"]
|
||||
view = res.result["current_view"]
|
||||
if res.status == 200:
|
||||
primary_id = res.body["primary_id"]
|
||||
view = res.body["current_view"]
|
||||
break
|
||||
else:
|
||||
assert "Primary unknown" in res.error, res.error
|
||||
assert "Primary unknown" in res.body, res
|
||||
except CCFConnectionException:
|
||||
pass
|
||||
if primary_id is not None:
|
||||
|
@ -563,8 +562,8 @@ class Network:
|
|||
while time.time() < end_time:
|
||||
with primary.client() as c:
|
||||
resp = c.get("/node/commit")
|
||||
seqno = resp.result["seqno"]
|
||||
view = resp.result["view"]
|
||||
seqno = resp.body["seqno"]
|
||||
view = resp.body["view"]
|
||||
if seqno != 0:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
|
@ -577,10 +576,10 @@ class Network:
|
|||
for node in self.get_joined_nodes():
|
||||
with node.client() as c:
|
||||
resp = c.get("/node/tx", {"view": view, "seqno": seqno})
|
||||
if resp.error is not None:
|
||||
if resp.status != 200:
|
||||
# Node may not have joined the network yet, try again
|
||||
break
|
||||
status = TxStatus(resp.result["status"])
|
||||
status = TxStatus(resp.body["status"])
|
||||
if status == TxStatus.Committed:
|
||||
caught_up_nodes.append(node)
|
||||
elif status == TxStatus.Invalid:
|
||||
|
|
|
@ -236,8 +236,8 @@ class Node:
|
|||
with self.client(connection_timeout=timeout) as nc:
|
||||
rep = nc.get("/node/commit")
|
||||
assert (
|
||||
rep.error is None and rep.result is not None
|
||||
), f"An error occured after node {self.node_id} joined the network: {rep.error}"
|
||||
rep.status == 200
|
||||
), f"An error occured after node {self.node_id} joined the network: {rep.body}"
|
||||
except ccf.clients.CCFConnectionException:
|
||||
raise TimeoutError(f"Node {self.node_id} failed to join the network")
|
||||
|
||||
|
|
|
@ -54,8 +54,7 @@ class TxRates:
|
|||
def process_next(self):
|
||||
with self.primary.client() as client:
|
||||
rv = client.get("/node/commit")
|
||||
result = rv.to_dict()
|
||||
next_commit = result["result"]["seqno"]
|
||||
next_commit = rv.body["seqno"]
|
||||
more_to_process = self.commit != next_commit
|
||||
self.commit = next_commit
|
||||
|
||||
|
@ -64,13 +63,11 @@ class TxRates:
|
|||
def get_metrics(self):
|
||||
with self.primary.client() as client:
|
||||
rv = client.get("/node/metrics")
|
||||
result = rv.to_dict()
|
||||
result = result["result"]
|
||||
self.all_metrics = result
|
||||
self.all_metrics = rv.body
|
||||
|
||||
all_rates = []
|
||||
all_durations = []
|
||||
rates = result.get("tx_rates")
|
||||
rates = self.all_metrics.get("tx_rates")
|
||||
if rates is None:
|
||||
LOG.info("No tx rate metrics found...")
|
||||
else:
|
||||
|
@ -79,7 +76,7 @@ class TxRates:
|
|||
all_durations.append(float(rates[key]["duration"]))
|
||||
self.tx_rates_data = all_rates
|
||||
|
||||
histogram = result.get("histogram")
|
||||
histogram = self.all_metrics.get("histogram")
|
||||
if histogram is None:
|
||||
LOG.info("No histogram metrics found...")
|
||||
else:
|
||||
|
|
|
@ -42,7 +42,7 @@ def update_view_info(network, view_info):
|
|||
def get_node_local_commit(node):
|
||||
with node.client() as c:
|
||||
r = c.get("/node/commit")
|
||||
return r.result["seqno"], r.global_commit
|
||||
return r.body["seqno"], r.global_commit
|
||||
|
||||
|
||||
def wait_for_late_joiner(old_node, late_joiner, strict=False, timeout=60):
|
||||
|
|
|
@ -15,12 +15,8 @@ const baseURL = `https://${__ENV.HOST}/`;
|
|||
export function setup()
|
||||
{
|
||||
const body = JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
method: "users/log/private",
|
||||
params: {
|
||||
id: 0,
|
||||
msg: "Unique message: d41d8cd98f00b204e9800998ecf8427e"
|
||||
}
|
||||
id: 0,
|
||||
msg: "Unique message: d41d8cd98f00b204e9800998ecf8427e"
|
||||
});
|
||||
const params = {headers: { "Content-Type": "application/json" }};
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ def test_add_member(network, args):
|
|||
)
|
||||
assert False, "New accepted members are not given recovery shares"
|
||||
except infra.member.NoRecoveryShareFound as e:
|
||||
assert e.response.error == "Only active members are given recovery shares"
|
||||
assert e.response.body == "Only active members are given recovery shares"
|
||||
|
||||
new_member.ack(primary)
|
||||
|
||||
|
@ -79,7 +79,7 @@ def test_missing_signature(network, args):
|
|||
primary, _ = network.find_primary()
|
||||
member = network.consortium.get_any_active_member()
|
||||
with primary.client(f"member{member.member_id}") as mc:
|
||||
r = mc.rpc("/gov/proposals", signed=False)
|
||||
r = mc.post("/gov/proposals", signed=False)
|
||||
assert r.status == http.HTTPStatus.UNAUTHORIZED, r.status
|
||||
www_auth = "www-authenticate"
|
||||
assert www_auth in r.headers, r.headers
|
||||
|
@ -290,7 +290,7 @@ def run(args):
|
|||
assert False, "Retired member cannot make a new proposal"
|
||||
except infra.proposal.ProposalNotCreated as e:
|
||||
assert e.response.status == http.HTTPStatus.FORBIDDEN.value
|
||||
assert e.response.error == "Member is not active"
|
||||
assert e.response.body == "Member is not active"
|
||||
|
||||
LOG.debug("New member should still be able to make a new proposal")
|
||||
new_proposal = new_member.propose(primary, proposal_trust_0)
|
||||
|
|
|
@ -25,26 +25,26 @@ def test(network, args, notifications_queue=None):
|
|||
|
||||
LOG.info("Write/Read on primary")
|
||||
with primary.client("user0") as c:
|
||||
r = c.rpc("/app/log/private", {"id": 42, "msg": msg})
|
||||
r = c.post("/app/log/private", {"id": 42, "msg": msg})
|
||||
check_commit(r, result=True)
|
||||
check(c.get("/app/log/private", {"id": 42}), result={"msg": msg})
|
||||
for _ in range(10):
|
||||
c.rpc(
|
||||
c.post(
|
||||
"/app/log/private", {"id": 43, "msg": "Additional messages"},
|
||||
)
|
||||
check_commit(
|
||||
c.rpc("/app/log/private", {"id": 43, "msg": "A final message"}),
|
||||
c.post("/app/log/private", {"id": 43, "msg": "A final message"}),
|
||||
result=True,
|
||||
)
|
||||
r = c.get("/app/receipt", {"commit": r.seqno})
|
||||
check(
|
||||
c.rpc("/app/receipt/verify", {"receipt": r.result["receipt"]}),
|
||||
c.post("/app/receipt/verify", {"receipt": r.body["receipt"]}),
|
||||
result={"valid": True},
|
||||
)
|
||||
invalid = r.result["receipt"]
|
||||
invalid = r.body["receipt"]
|
||||
invalid[-3] += 1
|
||||
check(
|
||||
c.rpc("/app/receipt/verify", {"receipt": invalid}),
|
||||
c.post("/app/receipt/verify", {"receipt": invalid}),
|
||||
result={"valid": False},
|
||||
)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ def check_can_progress(node, timeout=3):
|
|||
uc.post("/app/log/private", {"id": 42, "msg": "Hello world"})
|
||||
end_time = time.time() + timeout
|
||||
while time.time() < end_time:
|
||||
if c.get("/node/commit").result["seqno"] > r.result["seqno"]:
|
||||
if c.get("/node/commit").body["seqno"] > r.body["seqno"]:
|
||||
return
|
||||
time.sleep(0.1)
|
||||
assert False, f"Stuck at {r}"
|
||||
|
|
|
@ -36,7 +36,7 @@ def run(args):
|
|||
check(
|
||||
list_response, error=lambda status, msg: status == http.HTTPStatus.OK.value
|
||||
)
|
||||
methods = list_response.result["methods"]
|
||||
methods = list_response.body["methods"]
|
||||
all_methods.extend(methods)
|
||||
|
||||
for method in methods:
|
||||
|
@ -49,8 +49,8 @@ def run(args):
|
|||
error=lambda status, msg: status == http.HTTPStatus.OK.value,
|
||||
)
|
||||
|
||||
if schema_response.result is not None:
|
||||
for verb, schema_element in schema_response.result.items():
|
||||
if schema_response.body is not None:
|
||||
for verb, schema_element in schema_response.body.items():
|
||||
for schema_type in ["params", "result"]:
|
||||
element_name = "{}_schema".format(schema_type)
|
||||
element = schema_element[element_name]
|
||||
|
|
|
@ -52,7 +52,7 @@ def supports_methods(*methods):
|
|||
primary, _ = network.find_primary()
|
||||
with primary.client("user0") as c:
|
||||
response = c.get("/app/api")
|
||||
supported_methods = response.result["methods"]
|
||||
supported_methods = response.body["methods"]
|
||||
missing = {*methods}.difference(supported_methods)
|
||||
if missing:
|
||||
concat = ", ".join(missing)
|
||||
|
@ -90,9 +90,9 @@ def sufficient_member_count():
|
|||
def can_kill_n_nodes(nodes_to_kill_count):
|
||||
def check(network, args, *nargs, **kwargs):
|
||||
primary, _ = network.find_primary()
|
||||
with primary.client(identity="member0") as c:
|
||||
r = c.rpc(
|
||||
"query",
|
||||
with primary.client("member0") as c:
|
||||
r = c.post(
|
||||
"gov/query",
|
||||
{
|
||||
"text": """tables = ...
|
||||
trusted_nodes_count = 0
|
||||
|
@ -106,7 +106,7 @@ def can_kill_n_nodes(nodes_to_kill_count):
|
|||
},
|
||||
)
|
||||
|
||||
trusted_nodes_count = r.result
|
||||
trusted_nodes_count = r.body
|
||||
running_nodes_count = len(network.get_joined_nodes())
|
||||
would_leave_nodes_count = running_nodes_count - nodes_to_kill_count
|
||||
minimum_nodes_to_run_count = ceil((trusted_nodes_count + 1) / 2)
|
||||
|
|
|
@ -21,8 +21,8 @@ def test(network, args, notifications_queue=None):
|
|||
LOG.info("Write on primary")
|
||||
with primary.client("user0", ws=True) as c:
|
||||
for i in [1, 50, 500]:
|
||||
r = c.rpc("/app/log/private", {"id": 42, "msg": msg * i})
|
||||
assert r.result == True, r.result
|
||||
r = c.post("/app/log/private", {"id": 42, "msg": msg * i})
|
||||
assert r.body == True, r
|
||||
|
||||
# Before we start sending transactions to the secondary,
|
||||
# we want to wait for its app frontend to be open, which is
|
||||
|
@ -31,7 +31,7 @@ def test(network, args, notifications_queue=None):
|
|||
end_time = time.time() + 10
|
||||
with other.client("user0") as nc:
|
||||
while time.time() < end_time:
|
||||
r = nc.rpc("/app/log/private", {"id": 42, "msg": msg * i})
|
||||
r = nc.post("/app/log/private", {"id": 42, "msg": msg * i})
|
||||
if r.status == 200:
|
||||
break
|
||||
else:
|
||||
|
@ -41,8 +41,8 @@ def test(network, args, notifications_queue=None):
|
|||
LOG.info("Write on secondary through forwarding")
|
||||
with other.client("user0", ws=True) as c:
|
||||
for i in [1, 50, 500]:
|
||||
r = c.rpc("/app/log/private", {"id": 42, "msg": msg * i})
|
||||
assert r.result == True, r.result
|
||||
r = c.post("/app/log/private", {"id": 42, "msg": msg * i})
|
||||
assert r.body == True, r
|
||||
|
||||
return network
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче