8#include "crypto/sha256.h"
14#include <secp256k1_schnorrsig.h>
17 static const auto secp_context
19 decltype(&secp256k1_context_destroy)>(
20 secp256k1_context_create(SECP256K1_CONTEXT_VERIFY),
21 &secp256k1_context_destroy);
30 std::shared_ptr<secp256k1_context> secp,
31 std::shared_ptr<thread_pool> t_pool,
38 std::move(result_callback),
39 std::move(try_lock_callback),
47 = std::shared_ptr<lua_State>(luaL_newstate(), [](lua_State* s) {
52 m_log->error(
"Failed to allocate new lua state");
53 m_result_callback(error_code::internal_error);
59 luaL_openlibs(m_state.get());
61 lua_register(m_state.get(),
"check_sig", &lua_runner::check_sig);
63 static constexpr auto function_name =
"contract";
65 auto load_ret = luaL_loadbufferx(m_state.get(),
70 if(load_ret != LUA_OK) {
71 m_log->error(
"Failed to load function chunk");
72 m_result_callback(error_code::function_load);
76 if(lua_pushlstring(m_state.get(), m_param.c_str(), m_param.size())
78 m_log->error(
"Failed to push function params");
79 m_result_callback(error_code::internal_error);
88 void lua_runner::contract_epilogue(
int n_results) {
90 m_log->error(
"Contract returned more than one result");
95 if(lua_istable(m_state.get(), -1) != 1) {
96 m_log->error(
"Contract did not return a table");
103 lua_pushnil(m_state.get());
104 while(lua_next(m_state.get(), -2) != 0) {
105 auto key_buf = get_stack_string(-2);
106 if(!key_buf.has_value()) {
107 m_log->error(
"Result key is not a string");
111 auto value_buf = get_stack_string(-1);
112 if(!value_buf.has_value()) {
113 m_log->error(
"Result value is not a string");
118 results.emplace(std::move(key_buf.value()),
119 std::move(value_buf.value()));
121 lua_pop(m_state.get(), 1);
124 m_log->trace(
this,
"running calling result callback");
125 m_result_callback(std::move(results));
126 m_log->trace(
this,
"lua_runner finished contract epilogue");
129 auto lua_runner::get_stack_string(
int index) -> std::optional<buffer> {
130 if(lua_isstring(m_state.get(), index) != 1) {
134 const auto* str = lua_tolstring(m_state.get(), index, &sz);
135 assert(str !=
nullptr);
141 auto lua_runner::get_stack_integer(
int index) -> std::optional<int64_t> {
142 if(lua_isinteger(m_state.get(), index) != 1) {
145 return lua_tointeger(m_state.get(), index);
148 void lua_runner::schedule_contract() {
150 auto resume_ret = lua_resume(m_state.get(),
nullptr, 1, &n_results);
151 if(resume_ret == LUA_YIELD) {
153 m_log->error(
"Contract yielded more than two keys");
158 m_log->error(
"Contract yielded no keys");
163 auto lock_level = broker::lock_type::write;
167 m_log->error(
"Contract yielded two keys, but the second "
168 "is not an integer");
172 lua_pop(m_state.get(), 1);
175 ? broker::lock_type::read
176 : broker::lock_type::write;
179 auto key_buf = get_stack_string(-1);
180 if(!key_buf.has_value()) {
181 m_log->error(
"Contract did not yield a string");
186 lua_pop(m_state.get(), 1);
189 = m_try_lock_callback(std::move(key_buf.value()),
192 handle_try_lock(std::move(res));
195 m_log->error(
"Failed to issue try lock command");
198 }
else if(resume_ret != LUA_OK) {
199 const auto* err = lua_tostring(m_state.get(), -1);
200 m_log->error(
"Error running contract:", err);
203 contract_epilogue(n_results);
207 void lua_runner::handle_try_lock(
209 auto maybe_error = std::visit(
212 if(lua_pushlstring(m_state.get(), v.c_str(), v.size())
214 m_log->error(
"Failed to push yield params");
220 -> std::optional<error_code> {
221 m_log->error(
"Broker error acquiring lock");
224 [&](
const runtime_locking_shard::shard_error& e)
225 -> std::optional<error_code> {
230 m_log->error(
"Shard error acquiring lock");
234 if(maybe_error.has_value()) {
235 m_result_callback(maybe_error.value());
241 auto lua_runner::check_sig(lua_State* L) ->
int {
242 int n = lua_gettop(L);
244 lua_pushliteral(L,
"not enough arguments");
247 for(
int i = 1; i <= n; i++) {
248 if(lua_isstring(L, i) != 1) {
249 lua_pushliteral(L,
"invalid argument");
255 const auto* str = lua_tolstring(L, 1, &sz);
256 assert(str !=
nullptr);
258 if(sz != key.size()) {
259 lua_pushliteral(L,
"invalid pubkey");
262 std::memcpy(key.data(), str, sz);
264 str = lua_tolstring(L, 2, &sz);
265 assert(str !=
nullptr);
267 if(sz != sig.size()) {
268 lua_pushliteral(L,
"invalid signature");
271 std::memcpy(sig.data(), str, sz);
273 secp256k1_xonly_pubkey pubkey{};
274 if(secp256k1_xonly_pubkey_parse(secp_context.get(),
278 lua_pushliteral(L,
"invalid pubkey");
282 str = lua_tolstring(L, 3, &sz);
283 assert(str !=
nullptr);
284 auto sha = CSHA256();
285 auto unsigned_str = std::vector<unsigned char>(sz);
286 std::memcpy(unsigned_str.data(), str, sz);
287 sha.Write(unsigned_str.data(), sz);
289 sha.Finalize(sighash.data());
291 if(secp256k1_schnorrsig_verify(secp_context.get(),
296 lua_pushliteral(L,
"invalid signature");
Buffer to store and retrieve byte data.
Interface for a contract runner.
std::function< void(run_return_type)> run_callback_type
Callback type for function execution.
std::function< bool(broker::key_type, broker::lock_type, broker::interface::try_lock_callback_type)> try_lock_callback_type
Callback function type for acquiring locks during function execution.
parsec::ticket_machine::ticket_number_type ticket_number_type
Type alias for a ticket number.
@ yield_count
Function yielded more than one key to lock.
@ wounded
Ticket wounded during execution.
@ internal_error
Internal Runner error.
@ result_count
Function more than one result.
@ result_value_type
Function did not return a string value.
@ yield_type
Function yielded a invalid datatype.
@ lock_error
Error acquiring lock on key.
@ result_type
Function did not return a map.
@ result_key_type
Function did not return a string key.
@ exec_error
Runner error during function execution.
auto run() -> bool override
Begins function execution.
std::variant< value_type, error_code, runtime_locking_shard::shard_error > try_lock_return_type
Return type from a try lock operation.
error_code
Error codes returned by broker operations.
struct secp256k1_context_struct secp256k1_context
runtime_locking_shard::value_type value_type
Shard value type.
@ wounded
Request invalid because ticket is in the wounded state.
std:: unordered_map< key_type, value_type, hashing::const_sip_hash< key_type > > state_update_type
Type for state updates to a shard. A map of keys and their new values.
lock_type
Types of key lock supported by shards.
overloaded(Ts...) -> overloaded< Ts... >
std::array< unsigned char, cbdc::hash_size > hash_t
SHA256 hash container.
@ buffer
A singular RLP value (byte array)
std::array< unsigned char, sig_len > signature_t
A signature.
std::array< unsigned char, pubkey_len > pubkey_t
A public key of a public/private keypair.
Configuration parameters for a phase two system.