Skip to content

Commit 6888c5c

Browse files
committed
Add read locks to the Lua runner
Support requesting read locks from Lua contracts instead of only write-locks. Signed-off-by: Michael Maurer <[email protected]>
1 parent d792c5e commit 6888c5c

File tree

4 files changed

+49
-6
lines changed

4 files changed

+49
-6
lines changed

scripts/gen_bytecode.lua

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
function gen_bytecode()
22
pay_contract = function(param)
3+
-- 0 is a read lock, 1 is a write lock in C++ scope
4+
Locks = {
5+
READ = 0,
6+
WRITE = 1,
7+
}
38
from, to, value, sequence, sig = string.unpack("c32 c32 I8 I8 c64", param)
49

510
function get_account_key(name)
@@ -10,7 +15,8 @@ function gen_bytecode()
1015

1116
function get_account(name)
1217
account_key = get_account_key(name)
13-
account_data = coroutine.yield(account_key)
18+
19+
account_data = coroutine.yield(account_key, Locks.WRITE)
1420
if string.len(account_data) > 0 then
1521
account_balance, account_sequence
1622
= string.unpack("I8 I8", account_data)

src/parsec/agent/runners/interface.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace cbdc::parsec::agent::runner {
3838
internal_error,
3939
/// Function yielded more than one key to lock.
4040
yield_count,
41-
/// Function yielded a non-string key.
41+
/// Function yielded a invalid datatype.
4242
yield_type,
4343
/// Error acquiring lock on key.
4444
lock_error,

src/parsec/agent/runners/lua/impl.cpp

+35-4
Original file line numberDiff line numberDiff line change
@@ -138,25 +138,56 @@ namespace cbdc::parsec::agent::runner {
138138
return buf;
139139
}
140140

141+
auto lua_runner::get_stack_integer(int index) -> std::optional<int64_t> {
142+
if(lua_isinteger(m_state.get(), index) != 1) {
143+
return std::nullopt;
144+
}
145+
return lua_tointeger(m_state.get(), index);
146+
}
147+
141148
void lua_runner::schedule_contract() {
142149
int n_results{};
143150
auto resume_ret = lua_resume(m_state.get(), nullptr, 1, &n_results);
144151
if(resume_ret == LUA_YIELD) {
145-
if(n_results != 1) {
146-
m_log->error("Contract yielded more than one key");
152+
if(n_results > 2) {
153+
m_log->error("Contract yielded more than two keys");
154+
m_result_callback(error_code::yield_count);
155+
return;
156+
}
157+
if(n_results < 1) {
158+
m_log->error("Contract yielded no keys");
147159
m_result_callback(error_code::yield_count);
148160
return;
149161
}
162+
163+
auto lock_level = broker::lock_type::write;
164+
if(n_results == 2) {
165+
auto lock_type = get_stack_integer(-1);
166+
if(!lock_type.has_value()) {
167+
m_log->error("Contract yielded two keys, but the second "
168+
"is not an integer");
169+
m_result_callback(error_code::yield_type);
170+
return;
171+
}
172+
lua_pop(m_state.get(), 1);
173+
174+
lock_level = (lock_type.value() == 0)
175+
? broker::lock_type::read
176+
: broker::lock_type::write;
177+
}
178+
150179
auto key_buf = get_stack_string(-1);
151180
if(!key_buf.has_value()) {
152181
m_log->error("Contract did not yield a string");
153182
m_result_callback(error_code::yield_type);
154183
return;
155184
}
156-
lua_pop(m_state.get(), n_results);
185+
186+
lua_pop(m_state.get(), 1);
187+
157188
auto success
158189
= m_try_lock_callback(std::move(key_buf.value()),
159-
broker::lock_type::write,
190+
lock_level,
160191
[&](auto res) {
161192
handle_try_lock(std::move(res));
162193
});

src/parsec/agent/runners/lua/impl.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ namespace cbdc::parsec::agent::runner {
1818
/// function execution, signature checking and commiting execution results.
1919
/// Class cannot be re-used for different functions/transactions, manages
2020
/// the lifecycle of a single transaction.
21+
/// NOTE: When writing contracts, to pass data between the Lua environment
22+
/// and the C++ environment, use `coroutine.yield()`. To request a
23+
/// read-lock use coroutine.yield(<data>, 0). To request a write-lock use
24+
/// coroutine.yield(<data>, 1) or coroutine.yield(<data>).
2125
class lua_runner : public interface {
2226
public:
2327
/// \copydoc interface::interface()
@@ -47,6 +51,8 @@ namespace cbdc::parsec::agent::runner {
4751

4852
auto get_stack_string(int index) -> std::optional<buffer>;
4953

54+
auto get_stack_integer(int index) -> std::optional<int64_t>;
55+
5056
void schedule_contract();
5157

5258
void

0 commit comments

Comments
 (0)