diff --git a/examples/js_client/lib/hp-client-lib.js b/examples/js_client/lib/hp-client-lib.js index da4c272e..ec9a779f 100644 --- a/examples/js_client/lib/hp-client-lib.js +++ b/examples/js_client/lib/hp-client-lib.js @@ -356,6 +356,10 @@ return getMultiConnectionResult(con => con.getStatus()); } + this.getLcl = () => { + return getMultiConnectionResult(con => con.getLcl()); + } + this.getLedgerBySeqNo = (seqNo, includeInputs, includeOutputs) => { return getMultiConnectionResult(con => con.getLedgerBySeqNo(seqNo, includeInputs, includeOutputs)); } @@ -378,6 +382,7 @@ let handshakeResolver = null; let closeResolver = null; let statResponseResolvers = []; + let lclResponseResolvers = []; let contractInputResolvers = {}; // Contract input status-awaiting resolvers (keyed by input hash). let ledgerQueryResolvers = {}; // Message resolvers that uses request/reply associations. @@ -620,12 +625,21 @@ contractExecutionEnabled: m.contract_execution_enabled, readRequestsEnabled: m.read_requests_enabled, isFullHistoryNode: m.is_full_history_node, - currentUnl: m.current_unl, + currentUnl: m.current_unl.map(u => msgHelper.deserializeValue(u)), peers: m.peers }); }) statResponseResolvers = []; } + else if (m.type == "lcl_response") { + lclResponseResolvers.forEach(resolver => { + resolver({ + ledgerSeqNo: m.ledger_seq_no, + ledgerHash: msgHelper.deserializeValue(m.ledger_hash) + }); + }) + lclResponseResolvers = []; + } else if (m.type == "unl_change") { if (m.unl) { // Convert unl pubkeys to hex string. @@ -823,6 +837,24 @@ return p; } + this.getLcl = () => { + + if (connectionStatus != 2) + return Promise.resolve(null); + + const p = new Promise(resolve => { + lclResponseResolvers.push(resolve); + }); + + // If this is the only awaiting lcl request, then send an actual lcl request. + // Otherwise simply wait for the previously sent request. + if (lclResponseResolvers.length == 1) { + const msg = msgHelper.createLclRequest(); + wsSend(msgHelper.serializeObject(msg)); + } + return p; + } + this.submitContractInput = async (input, nonce, maxLedger, isOffset) => { if (connectionStatus != 2) @@ -843,12 +875,12 @@ if (!maxLedger) maxLedger = 10; // Default offset applied if not specified. - // Acquire the current ledger status and add the specified offset. - const stat = await this.getStatus(); - if (!stat) - throw "Error retrieving ledger status." + // Acquire the last ledger information and add the specified offset. + const lcl = await this.getLcl(); + if (!lcl) + throw "Error retrieving last closed ledger." - maxLedger += stat.ledgerSeqNo; + maxLedger += lcl.ledgerSeqNo; } const inp = msgHelper.createContractInputComponents(input, nonce, maxLedger); @@ -1018,6 +1050,10 @@ return { type: "stat" }; } + this.createLclRequest = () => { + return { type: "lcl" }; + } + this.createLedgerQuery = (filterBy, params, includeInputs, includeOutputs) => { const includes = []; diff --git a/src/msg/bson/usrmsg_bson.cpp b/src/msg/bson/usrmsg_bson.cpp index 6c044cd4..b9ac3c23 100644 --- a/src/msg/bson/usrmsg_bson.cpp +++ b/src/msg/bson/usrmsg_bson.cpp @@ -17,8 +17,15 @@ namespace msg::usrmsg::bson * Message format: * { * "type": "stat_response", + * "hp_version": "", * "ledger_seq_no": , - * "ledger_hash": + * "ledger_hash": , + * "roundtime": , + * "contract_execution_enabled": true | false, + * "read_requests_enabled": true | false, + * "is_full_history_node": true | false, + * "current_unl": [ , ... ], + * "peers": [ "ip:port", ... ] * } */ void create_status_response(std::vector &msg) @@ -70,6 +77,32 @@ namespace msg::usrmsg::bson encoder.flush(); } + /** + * Constructs a lcl response message. + * @param msg Buffer to construct the generated bson message into. + * Message format: + * { + * "type": "lcl_response", + * "ledger_seq_no": , + * "ledger_hash": + * } + */ + void create_lcl_response(std::vector &msg) + { + const util::sequence_hash lcl_id = status::get_lcl_id(); + + jsoncons::bson::bson_bytes_encoder encoder(msg); + encoder.begin_object(); + encoder.key(msg::usrmsg::FLD_TYPE); + encoder.string_value(msg::usrmsg::MSGTYPE_LCL_RESPONSE); + encoder.key(msg::usrmsg::FLD_LEDGER_SEQ_NO); + encoder.int64_value(lcl_id.seq_no); + encoder.key(msg::usrmsg::FLD_LEDGER_HASH); + encoder.byte_string_value(lcl_id.hash.to_string_view()); + encoder.end_object(); + encoder.flush(); + } + /** * Constructs a contract input status message. * @param msg Buffer to construct the generated bson message into. diff --git a/src/msg/bson/usrmsg_bson.hpp b/src/msg/bson/usrmsg_bson.hpp index 82a2d39b..29a18167 100644 --- a/src/msg/bson/usrmsg_bson.hpp +++ b/src/msg/bson/usrmsg_bson.hpp @@ -10,6 +10,8 @@ namespace msg::usrmsg::bson void create_status_response(std::vector &msg); + void create_lcl_response(std::vector &msg); + void create_contract_input_status(std::vector &msg, std::string_view status, std::string_view reason, std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash); diff --git a/src/msg/json/usrmsg_json.cpp b/src/msg/json/usrmsg_json.cpp index 58c506a6..c881f87a 100644 --- a/src/msg/json/usrmsg_json.cpp +++ b/src/msg/json/usrmsg_json.cpp @@ -136,8 +136,15 @@ namespace msg::usrmsg::json * Message format: * { * "type": "stat_response", + * "hp_version": "", * "ledger_seq_no": , - * "ledger_hash": "" + * "ledger_hash": "", + * "roundtime": , + * "contract_execution_enabled": true | false, + * "read_requests_enabled": true | false, + * "is_full_history_node": true | false, + * "current_unl": [ """, ... ], + * "peers": [ "ip:port", ... ] * } */ void create_status_response(std::vector &msg) @@ -217,6 +224,36 @@ namespace msg::usrmsg::json msg += "}"; } + /** + * Constructs a lcl response message. + * @param msg Buffer to construct the generated json message string into. + * Message format: + * { + * "type": "lcl_response", + * "ledger_seq_no": , + * "ledger_hash": "" + * } + */ + void create_lcl_response(std::vector &msg) + { + const util::sequence_hash lcl_id = status::get_lcl_id(); + + msg.reserve(512); + msg += "{\""; + msg += msg::usrmsg::FLD_TYPE; + msg += SEP_COLON; + msg += msg::usrmsg::MSGTYPE_LCL_RESPONSE; + msg += SEP_COMMA; + msg += msg::usrmsg::FLD_LEDGER_SEQ_NO; + msg += SEP_COLON_NOQUOTE; + msg += std::to_string(lcl_id.seq_no); + msg += SEP_COMMA_NOQUOTE; + msg += msg::usrmsg::FLD_LEDGER_HASH; + msg += SEP_COLON; + msg += util::to_hex(lcl_id.hash.to_string_view()); + msg += "\"}"; + } + /** * Constructs a contract input status message. * @param msg Buffer to construct the generated json message string into. diff --git a/src/msg/json/usrmsg_json.hpp b/src/msg/json/usrmsg_json.hpp index e004191b..1779a3b8 100644 --- a/src/msg/json/usrmsg_json.hpp +++ b/src/msg/json/usrmsg_json.hpp @@ -10,6 +10,8 @@ namespace msg::usrmsg::json void create_user_challenge(std::vector &msg, std::string &challenge); + void create_lcl_response(std::vector &msg); + void create_server_challenge_response(std::vector &msg, const std::string &original_challenge); void create_status_response(std::vector &msg); diff --git a/src/msg/usrmsg_common.hpp b/src/msg/usrmsg_common.hpp index 09e62a2f..e83a96f3 100644 --- a/src/msg/usrmsg_common.hpp +++ b/src/msg/usrmsg_common.hpp @@ -72,6 +72,8 @@ namespace msg::usrmsg constexpr const char *MSGTYPE_CONTRACT_OUTPUT = "contract_output"; constexpr const char *MSGTYPE_STAT = "stat"; constexpr const char *MSGTYPE_STAT_RESPONSE = "stat_response"; + constexpr const char *MSGTYPE_LCL = "lcl"; + constexpr const char *MSGTYPE_LCL_RESPONSE = "lcl_response"; constexpr const char *MSGTYPE_UNL_CHANGE = "unl_change"; constexpr const char *MSGTYPE_LEDGER_QUERY = "ledger_query"; constexpr const char *MSGTYPE_LEDGER_QUERY_RESULT = "ledger_query_result"; diff --git a/src/msg/usrmsg_parser.cpp b/src/msg/usrmsg_parser.cpp index 355e6a7a..c45232ae 100644 --- a/src/msg/usrmsg_parser.cpp +++ b/src/msg/usrmsg_parser.cpp @@ -21,6 +21,14 @@ namespace msg::usrmsg busrmsg::create_status_response(msg); } + void usrmsg_parser::create_lcl_response(std::vector &msg) const + { + if (protocol == util::PROTOCOL::JSON) + jusrmsg::create_lcl_response(msg); + else + busrmsg::create_lcl_response(msg); + } + void usrmsg_parser::create_contract_input_status(std::vector &msg, std::string_view status, std::string_view reason, std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash) const { diff --git a/src/msg/usrmsg_parser.hpp b/src/msg/usrmsg_parser.hpp index 089675b7..87a84876 100644 --- a/src/msg/usrmsg_parser.hpp +++ b/src/msg/usrmsg_parser.hpp @@ -22,6 +22,8 @@ namespace msg::usrmsg void create_status_response(std::vector &msg) const; + void create_lcl_response(std::vector &msg) const; + void create_contract_input_status(std::vector &msg, std::string_view status, std::string_view reason, std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash) const; diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index c297de87..0724090d 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -239,6 +239,13 @@ namespace usr user.session.send(resp); return 0; } + else if (msg_type == msg::usrmsg::MSGTYPE_LCL) + { + std::vector resp; + parser.create_lcl_response(resp); + user.session.send(resp); + return 0; + } else if (msg_type == msg::usrmsg::MSGTYPE_LEDGER_QUERY) { ledger::query::query_request req;