Skip to content

Commit f5009fb

Browse files
authored
Members should vote for Lua app before opening the network (#411)
1 parent 079e830 commit f5009fb

File tree

18 files changed

+298
-140
lines changed

18 files changed

+298
-140
lines changed

CMakeLists.txt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,6 @@ if(BUILD_TESTS)
273273
NAME voting_history_test
274274
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/votinghistory.py)
275275

276-
## Lua Logging client end to end test
277-
add_e2e_test(
278-
NAME lua_logging_client_test
279-
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/loggingclient.py
280-
ADDITIONAL_ARGS
281-
--app-script ${CMAKE_SOURCE_DIR}/src/apps/logging/logging.lua)
282-
283276
## Lua sample app (tx regulator) end to end test
284277
add_e2e_test(
285278
NAME lua_txregulator_test
@@ -317,6 +310,12 @@ if(BUILD_TESTS)
317310
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/e2e_logging.py
318311
)
319312

313+
add_e2e_test(
314+
NAME lua_end_to_end_logging
315+
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/e2e_logging.py
316+
ADDITIONAL_ARGS
317+
--app-script ${CMAKE_SOURCE_DIR}/src/apps/logging/logging.lua)
318+
320319
add_e2e_test(
321320
NAME end_to_end_scenario
322321
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/e2e_scenarios.py

sphinx/source/start_network.rst

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,30 @@ Other members are then allowed to vote for the proposal, using the proposal ID r
7373
7474
The user is successfully added once a :term:`quorum` of members have accepted the proposal (``"result":true"``).
7575

76+
Register the Lua application
77+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78+
79+
.. note:: This section only applies when deploying Lua applications (i.e. using the ``libluageneric.so.signed`` enclave library). For C++ applications, this step should be skipped.
80+
81+
Before opening the CCF network to users, members should vote to register the Lua application defining the user-specific business logic (see for example :ref:`Logging (Lua)`):
82+
83+
.. code-block:: bash
84+
85+
$ memberclient --cert member1_cert --privk member1_privk --rpc-address rpc_ip:rpc_port --ca network_cert set_lua_app --lua-app-file /path/to/lua/app_script
86+
{"commit":9,"global_commit":8,"id":0,"jsonrpc":"2.0","result":{"completed":false,"id":1},"term":2}
87+
88+
Other members are then allowed to vote for the proposal, using the proposal ID returned to the proposer member (here ``1``, as per ``"result":{"completed":false,"id":1}``).
89+
90+
.. code-block::
91+
92+
$ memberclient --cert member2_cert --privk member2_privk --rpc-address rpc_ip:rpc_port --ca network_cert vote --proposal-id 1 --accept
93+
{"commit":11,"global_commit":10,"id":0,"jsonrpc":"2.0","result":{"completed":false,"id":1},"term":2}
94+
95+
$ memberclient --cert member3_cert --privk member3_privk --rpc-address rpc_ip:rpc_port --ca network_cert vote --proposal-id 1 --accept
96+
{"commit":13,"global_commit":12,"id":0,"jsonrpc":"2.0","result":{"completed":true,"id":1},"term":2}
97+
98+
The Lua application is successfully registered once a :term:`quorum` of members have accepted the proposal (``"result":true"``).
99+
76100
Open a network
77101
~~~~~~~~~~~~~~
78102

@@ -81,17 +105,17 @@ Once users are added to the opening network, members should decide to make a pro
81105
.. code-block:: bash
82106
83107
$ memberclient --cert member1_cert --privk member1_privk --rpc-address rpc_ip:rpc_port --ca network_cert open_network
84-
{"commit":4,"global_commit":3,"id":0,"jsonrpc":"2.0","result":{"completed":false,"id":1},"term":2}
108+
{"commit":15,"global_commit":14,"id":0,"jsonrpc":"2.0","result":{"completed":false,"id":2},"term":2}
85109
86-
Other members are then allowed to vote for the proposal, using the proposal ID returned to the proposer member (here ``1``, as per ``"result":{"completed":false,"id":1}``).
110+
Other members are then allowed to vote for the proposal, using the proposal ID returned to the proposer member (here ``2``, as per ``"result":{"completed":false,"id":2}``).
87111

88112
.. code-block:: bash
89113
90-
$ memberclient --cert member2_cert --privk member2_privk --rpc-address rpc_ip:rpc_port --ca network_cert vote --proposal-id 1 --accept
91-
{"commit":9,"global_commit":8,"id":0,"jsonrpc":"2.0","result":false,"term":2}
114+
$ memberclient --cert member2_cert --privk member2_privk --rpc-address rpc_ip:rpc_port --ca network_cert vote --proposal-id 2 --accept
115+
{"commit":17,"global_commit":16,"id":0,"jsonrpc":"2.0","result":false,"term":2}
92116
93-
$ memberclient --cert member3_cert --privk member3_privk --rpc-address rpc_ip:rpc_port --ca network_cert vote --proposal-id 1 --accept
94-
{"commit":11,"global_commit":10,"id":0,"jsonrpc":"2.0","result":true,"term":2}
117+
$ memberclient --cert member3_cert --privk member3_privk --rpc-address rpc_ip:rpc_port --ca network_cert vote --proposal-id 2 --accept
118+
{"commit":19,"global_commit":18,"id":0,"jsonrpc":"2.0","result":true,"term":2}
95119
96120
Once a quorum of members have approved the network opening (``"result":true``), the network is opened to users (see :ref:`Example App` for a simple business logic and :term:`JSON-RPC` transactions). It is only then that users are able to execute transactions on the business logic defined by the enclave file (``--enclave-file`` option to ``cchost``).
97121

@@ -128,7 +152,7 @@ Summary diagram
128152

129153
Once a node is part of the network (started with either the ``start`` or ``join`` option), members are authorised to issue governance transactions and eventually open the network. Only then are users authorised to issue JSON-RPC transactions to CCF.
130154

131-
.. note:: After the network is open to users, members can still issue governance transactions to CCF (for example, adding new users or additional members to the consortium). See :ref:`Governance` for more information about member governance.
155+
.. note:: After the network is open to users, members can still issue governance transactions to CCF (for example, adding new users or additional members to the consortium or updating the Lua app, when applicable). See :ref:`Governance` for more information about member governance.
132156

133157
The following diagram summarises the steps required to bootstrap a CCF network:
134158

src/apps/logging/logging.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ return {
1818
function env.get(table)
1919
msg = table:get(args.params.id)
2020
if not msg then
21-
return env.jerr(env.error_codes.UNKNOWN_ID, "No such record: " .. args.params.id)
21+
return env.jerr(env.error_codes.UNKNOWN_ID, "No such record: " .. args.params.id)
2222
end
23-
return env.jsucc(msg)
23+
return env.jsucc({msg = msg})
2424
end
25-
25+
2626
function env.record(table)
2727
if string.len(args.params.msg) == 0 then
28-
return env.jerr(env.error_codes.MESSAGE_EMPTY, "Cannot record an empty log message")
28+
return env.jerr(env.error_codes.MESSAGE_EMPTY, "Cannot record an empty log message")
2929
end
3030
table:put(args.params.id, args.params.msg)
3131
return env.jsucc(true)

src/apps/luageneric/luageneric.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ namespace ccfapp
162162
return make_pair(false, *err_it);
163163
}
164164
};
165-
set_default(default_handler, MayWrite);
165+
166+
// TODO: https://github.com/microsoft/CCF/issues/409
167+
set_default(default_handler, Write);
166168
}
167169
};
168170

src/clients/memberclient.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ using namespace std;
2323
using namespace nlohmann;
2424

2525
constexpr auto members_sni = "members";
26-
constexpr NodeId INVALID_NODE_ID = std::numeric_limits<NodeId>::max();
2726

2827
static const string add_member_proposal(R"xxx(
2928
tables, member_cert = ...
@@ -77,6 +76,11 @@ static const string accept_code_proposal(R"xxx(
7776
return Calls:call("new_code", code_digest)
7877
)xxx");
7978

79+
static const string set_lua_app(R"xxx(
80+
tables, app = ...
81+
return Calls:call("set_lua_app", app)
82+
)xxx");
83+
8084
json proposal_params(const string& script)
8185
{
8286
return Propose::In{script};
@@ -186,6 +190,14 @@ void submit_open_network(RpcTlsClient& tls_connection)
186190
cout << response.dump() << std::endl;
187191
}
188192

193+
void submit_set_lua_app(RpcTlsClient& tls_connection, const std::string& app)
194+
{
195+
const auto params = proposal_params<json>(set_lua_app, app);
196+
const auto response =
197+
json::from_msgpack(tls_connection.call("propose", params));
198+
cout << response.dump() << std::endl;
199+
}
200+
189201
void submit_raw_puts(
190202
RpcTlsClient& tls_connection, const string& script, const string& param_file)
191203
{
@@ -363,6 +375,14 @@ int main(int argc, char** argv)
363375
auto accept_recovery =
364376
app.add_subcommand("accept_recovery", "Accept to recover network");
365377

378+
auto set_lua_app =
379+
app.add_subcommand("set_lua_app", "Update lua application");
380+
string lua_app_file;
381+
set_lua_app
382+
->add_option("--lua-app-file", lua_app_file, "Lua application file")
383+
->required(true)
384+
->check(CLI::ExistingFile);
385+
366386
string sealed_secrets_file;
367387
accept_recovery
368388
->add_option(
@@ -487,6 +507,11 @@ int main(int argc, char** argv)
487507
{
488508
submit_open_network(*tls_connection);
489509
}
510+
511+
if (*set_lua_app)
512+
{
513+
submit_set_lua_app(*tls_connection, slurp_string(lua_app_file));
514+
}
490515
}
491516
catch (const exception& ex)
492517
{

src/enclave/interface.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ struct CCFConfig
4747
{
4848
std::vector<std::vector<uint8_t>> member_certs;
4949
std::string gov_script;
50-
std::string app_script;
51-
MSGPACK_DEFINE(member_certs, gov_script, app_script);
50+
MSGPACK_DEFINE(member_certs, gov_script);
5251
};
5352
Genesis genesis = {};
5453

src/host/main.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,6 @@ int main(int argc, char** argv)
194194
->check(CLI::ExistingFile)
195195
->required();
196196

197-
// TODO: For now, lua app is passed when the node starts up
198-
// See https://github.com/microsoft/CCF/issues/293
199-
std::string app_script;
200-
const auto app_script_opt = start->add_option(
201-
"--app-script",
202-
app_script,
203-
"Path to Lua file that defines the user business logic",
204-
true);
205-
206197
std::string member_cert_file = "member*_cert.pem";
207198
start
208199
->add_option(
@@ -317,8 +308,6 @@ int main(int argc, char** argv)
317308
start_type = StartType::New;
318309
ccf_config.genesis.member_certs = files::slurp_certs(member_cert_file);
319310
ccf_config.genesis.gov_script = files::slurp_string(gov_script);
320-
if (*app_script_opt)
321-
ccf_config.genesis.app_script = files::slurp_string(app_script);
322311
}
323312
else if (*join)
324313
{

src/node/nodestate.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,6 @@ namespace ccf
241241
g.set_gov_scripts(lua::Interpreter().invoke<nlohmann::json>(
242242
args.config.genesis.gov_script));
243243

244-
if (!args.config.genesis.app_script.empty())
245-
g.set_app_scripts(lua::Interpreter().invoke<nlohmann::json>(
246-
args.config.genesis.app_script));
247-
248244
network.secrets = std::make_unique<NetworkSecrets>(
249245
"CN=The CA", std::make_unique<Seal>(writer_factory));
250246

src/node/rpc/memberfrontend.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the Apache 2.0 License.
33
#pragma once
4-
#include "../../luainterp/txscriptrunner.h"
5-
#include "../../tls/entropy.h"
6-
#include "../../tls/keypair.h"
7-
#include "../quoteverification.h"
84
#include "frontend.h"
5+
#include "luainterp/txscriptrunner.h"
6+
#include "node/quoteverification.h"
7+
#include "tls/entropy.h"
8+
#include "tls/keypair.h"
99

1010
#include <exception>
1111
#include <initializer_list>
@@ -28,11 +28,39 @@ namespace ccf
2828
return *s;
2929
}
3030

31+
// TODO: This function is very similar to set_app_scripts() in genesisgen.h
32+
// Change this as part of https://github.com/microsoft/CCF/issues/320
33+
void set_app_scripts(
34+
Store::Tx& tx, std::map<std::string, std::string> scripts)
35+
{
36+
auto tx_scripts = tx.get_view(network.app_scripts);
37+
38+
// First, remove all existing handlers
39+
tx_scripts->foreach(
40+
[&tx_scripts](const std::string& name, const Script& script) {
41+
tx_scripts->remove(name);
42+
return true;
43+
});
44+
45+
for (auto& rs : scripts)
46+
{
47+
tx_scripts->put(rs.first, lua::compile(rs.second));
48+
}
49+
}
50+
3151
//! Table of functions that proposal scripts can propose to invoke
3252
const std::unordered_map<
3353
std::string,
3454
std::function<bool(Store::Tx&, const nlohmann::json&)>>
3555
hardcoded_funcs = {
56+
// set the lua application script
57+
{"set_lua_app",
58+
[this](Store::Tx& tx, const nlohmann::json& args) {
59+
const std::string app = args;
60+
set_app_scripts(tx, lua::Interpreter().invoke<nlohmann::json>(app));
61+
62+
return true;
63+
}},
3664
// add a new member
3765
{"new_member",
3866
[this](Store::Tx& tx, const nlohmann::json& args) {

tests/code_update.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def add_new_code(network, new_code_id):
3030
LOG.debug(f"Adding new code id: {new_code_id}")
3131

3232
primary, _ = network.find_primary()
33-
result = network.propose(1, primary, "add_code", f"--new-code-id={new_code_id}")
33+
result = network.propose(
34+
1, primary, None, None, "add_code", f"--new-code-id={new_code_id}"
35+
)
3436

3537
network.vote_using_majority(primary, result[1]["id"])
3638

0 commit comments

Comments
 (0)