From 9ccf21b0ac925fb429a8373803ea33e76239688c Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 30 Jul 2026 15:09:30 -0300 Subject: [PATCH 1/2] chore: bump lez version --- flake.lock | 8 ++++---- flake.nix | 2 +- src/lez_core_module.cpp | 13 +++++++------ src/lez_core_module.h | 4 ++-- tests/mocks/mock_wallet_ffi.cpp | 4 ++-- tests/stubs/wallet_ffi.h | 4 ++-- tests/test_lez_core.cpp | 8 ++++---- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index dfdcc2d..aecdf32 100644 --- a/flake.lock +++ b/flake.lock @@ -2716,17 +2716,17 @@ "rust-rapidsnark": "rust-rapidsnark" }, "locked": { - "lastModified": 1782922431, - "narHash": "sha256-loCudmjk5qD12UqgiS7lyUc2UpTDzNpH1y0e8qojkNs=", + "lastModified": 1785414238, + "narHash": "sha256-SNo5ZvmzB39HMgY+f0a93XoNA92e/T5Ki9Gho62COWY=", "owner": "logos-blockchain", "repo": "logos-execution-zone", - "rev": "571f35b3849c889f893109fd2b9dad040f0a3b57", + "rev": "f58cde1a2251c20cf418a561ad974a8c64ab2393", "type": "github" }, "original": { "owner": "logos-blockchain", "repo": "logos-execution-zone", - "rev": "571f35b3849c889f893109fd2b9dad040f0a3b57", + "rev": "f58cde1a2251c20cf418a561ad974a8c64ab2393", "type": "github" } }, diff --git a/flake.nix b/flake.nix index c3c4b97..529e992 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { logos-module-builder.url = "github:logos-co/logos-module-builder"; nix-bundle-lgx.url = "github:logos-co/nix-bundle-lgx"; - logos-execution-zone.url = "github:logos-blockchain/logos-execution-zone?rev=571f35b3849c889f893109fd2b9dad040f0a3b57"; + logos-execution-zone.url = "github:logos-blockchain/logos-execution-zone?rev=f58cde1a2251c20cf418a561ad974a8c64ab2393"; }; outputs = inputs@{ logos-module-builder, ... }: diff --git a/src/lez_core_module.cpp b/src/lez_core_module.cpp index dbd7290..11a6bc3 100644 --- a/src/lez_core_module.cpp +++ b/src/lez_core_module.cpp @@ -924,7 +924,7 @@ std::vector LEZCoreModule::token_elf() { std::vector LEZCoreModule::amm_elf() { FfiProgram ffi_program{}; - WalletFfiError error = wallet_ffi_token_elf(&ffi_program); + WalletFfiError error = wallet_ffi_amm_elf(&ffi_program); if (error != SUCCESS) { fprintf(stderr, "amm_elf: wallet FFI error %d\n", error); return std::vector{}; @@ -939,7 +939,7 @@ std::vector LEZCoreModule::amm_elf() { std::vector LEZCoreModule::ata_elf() { FfiProgram ffi_program{}; - WalletFfiError error = wallet_ffi_token_elf(&ffi_program); + WalletFfiError error = wallet_ffi_ata_elf(&ffi_program); if (error != SUCCESS) { fprintf(stderr, "ata_elf: wallet FFI error %d\n", error); return std::vector{}; @@ -954,7 +954,7 @@ std::vector LEZCoreModule::ata_elf() { std::vector LEZCoreModule::authenticated_transfer_elf() { FfiProgram ffi_program{}; - WalletFfiError error = wallet_ffi_token_elf(&ffi_program); + WalletFfiError error = wallet_ffi_transfer_elf(&ffi_program); if (error != SUCCESS) { fprintf(stderr, "authenticated_transfer_elf: wallet FFI error %d\n", error); return std::vector{}; @@ -1150,6 +1150,7 @@ std::string LEZCoreModule::send_program_deployment_transaction( std::string LEZCoreModule::create_new( const std::string& config_path, const std::string& storage_path, + const std::string& statistics_path, const std::string& password ) { if (walletHandle) { @@ -1157,7 +1158,7 @@ std::string LEZCoreModule::create_new( return {}; } - FfiCreateWalletOutput create_output = wallet_ffi_create_new(config_path.c_str(), storage_path.c_str(), password.c_str()); + FfiCreateWalletOutput create_output = wallet_ffi_create_new(config_path.c_str(), storage_path.c_str(), statistics_path.c_str(), password.c_str()); if (!create_output.wallet) { fprintf(stderr, "create_new: wallet_ffi_create_new returned null\n"); return {}; @@ -1181,13 +1182,13 @@ int64_t LEZCoreModule::restore_storage(const std::string& mnemonic, const std::s return SUCCESS; } -int64_t LEZCoreModule::open(const std::string& config_path, const std::string& storage_path) { +int64_t LEZCoreModule::open(const std::string& config_path, const std::string& storage_path, const std::string& statistics_path) { if (walletHandle) { fprintf(stderr, "open: wallet is already open\n"); return INTERNAL_ERROR; } - walletHandle = wallet_ffi_open(config_path.c_str(), storage_path.c_str()); + walletHandle = wallet_ffi_open(config_path.c_str(), storage_path.c_str(), statistics_path.c_str()); if (!walletHandle) { fprintf(stderr, "open: wallet_ffi_open returned null\n"); return INTERNAL_ERROR; diff --git a/src/lez_core_module.h b/src/lez_core_module.h index 4a1059c..86b6246 100644 --- a/src/lez_core_module.h +++ b/src/lez_core_module.h @@ -30,8 +30,8 @@ public: std::string version() const; // === Wallet Lifecycle === - std::string create_new(const std::string& config_path, const std::string& storage_path, const std::string& password); - int64_t open(const std::string& config_path, const std::string& storage_path); + std::string create_new(const std::string& config_path, const std::string& storage_path, const std::string& statistics_path, const std::string& password); + int64_t open(const std::string& config_path, const std::string& storage_path, const std::string& statistics_path); int64_t save(); int64_t restore_storage(const std::string& mnemonic, const std::string password, uint32_t depth); diff --git a/tests/mocks/mock_wallet_ffi.cpp b/tests/mocks/mock_wallet_ffi.cpp index 421b272..7fe13a4 100644 --- a/tests/mocks/mock_wallet_ffi.cpp +++ b/tests/mocks/mock_wallet_ffi.cpp @@ -54,7 +54,7 @@ extern "C" { // === Lifecycle === -FfiCreateWalletOutput wallet_ffi_create_new(const char*, const char*, const char*) { +FfiCreateWalletOutput wallet_ffi_create_new(const char*, const char*, const char*, const char*) { LOGOS_CMOCK_RECORD("wallet_ffi_create_new"); const int ok = LOGOS_CMOCK_RETURN(int, "wallet_ffi_create_new"); const char* mnemonic_ok = LOGOS_CMOCK_RETURN_STRING("wallet_ffi_create_new"); @@ -65,7 +65,7 @@ FfiCreateWalletOutput wallet_ffi_create_new(const char*, const char*, const char return output; } -WalletHandle* wallet_ffi_open(const char*, const char*) { +WalletHandle* wallet_ffi_open(const char*, const char*, const char*) { LOGOS_CMOCK_RECORD("wallet_ffi_open"); const int ok = LOGOS_CMOCK_RETURN(int, "wallet_ffi_open"); return ok ? reinterpret_cast(&g_fakeWallet) : nullptr; diff --git a/tests/stubs/wallet_ffi.h b/tests/stubs/wallet_ffi.h index 4204b15..03d126d 100644 --- a/tests/stubs/wallet_ffi.h +++ b/tests/stubs/wallet_ffi.h @@ -191,8 +191,8 @@ typedef struct LabelList { // === Lifecycle === -FfiCreateWalletOutput wallet_ffi_create_new(const char* config_path, const char* storage_path, const char* password); -WalletHandle* wallet_ffi_open(const char* config_path, const char* storage_path); +FfiCreateWalletOutput wallet_ffi_create_new(const char* config_path, const char* storage_path, const char* statistics_path, const char* password); +WalletHandle* wallet_ffi_open(const char* config_path, const char* storage_path, const char* statistics_path); int wallet_ffi_save(WalletHandle* handle); void wallet_ffi_destroy(WalletHandle* handle); diff --git a/tests/test_lez_core.cpp b/tests/test_lez_core.cpp index a709e51..bb072f1 100644 --- a/tests/test_lez_core.cpp +++ b/tests/test_lez_core.cpp @@ -590,10 +590,10 @@ LOGOS_TEST(create_new_success_then_double_open_fails) { t.mockCFunction("wallet_ffi_create_new").returns(1); // non-null handle LEZCoreModule module; - LOGOS_ASSERT_TRUE(!module.create_new("/cfg", "/store", "pw").empty()); + LOGOS_ASSERT_TRUE(!module.create_new("/cfg", "/store", "/stats", "pw").empty()); LOGOS_ASSERT(t.cFunctionCalled("wallet_ffi_create_new")); // Second attempt: already open. - LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), ""); + LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "/stats", "pw"), ""); } LOGOS_TEST(create_new_null_handle_returns_internal_error) { @@ -601,7 +601,7 @@ LOGOS_TEST(create_new_null_handle_returns_internal_error) { t.mockCFunction("wallet_ffi_create_new").returns(0); // null handle LEZCoreModule module; - LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), ""); + LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "/stats", "pw"), ""); } LOGOS_TEST(open_success) { @@ -609,7 +609,7 @@ LOGOS_TEST(open_success) { t.mockCFunction("wallet_ffi_open").returns(1); LEZCoreModule module; - LOGOS_ASSERT_EQ(module.open("/cfg", "/store"), static_cast(SUCCESS)); + LOGOS_ASSERT_EQ(module.open("/cfg", "/store", "/stats"), static_cast(SUCCESS)); LOGOS_ASSERT(t.cFunctionCalled("wallet_ffi_open")); } From f9e517766a7f38c54f071f5acdeb5637fed418ee Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 31 Jul 2026 19:10:07 -0300 Subject: [PATCH 2/2] fix: #115 --- flake.lock | 8 ++--- flake.nix | 2 +- src/lez_core_module.cpp | 27 +++++++++------- tests/test_lez_core.cpp | 72 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index aecdf32..812f17b 100644 --- a/flake.lock +++ b/flake.lock @@ -2716,17 +2716,17 @@ "rust-rapidsnark": "rust-rapidsnark" }, "locked": { - "lastModified": 1785414238, - "narHash": "sha256-SNo5ZvmzB39HMgY+f0a93XoNA92e/T5Ki9Gho62COWY=", + "lastModified": 1785659324, + "narHash": "sha256-xtC9Qksgp3f3ZEDdhLuM0DegelFl4EW20jqSmhqHeHQ=", "owner": "logos-blockchain", "repo": "logos-execution-zone", - "rev": "f58cde1a2251c20cf418a561ad974a8c64ab2393", + "rev": "15144ddb8437f48cdce32908e122dbb7eea68399", "type": "github" }, "original": { "owner": "logos-blockchain", + "ref": "v0.2.1", "repo": "logos-execution-zone", - "rev": "f58cde1a2251c20cf418a561ad974a8c64ab2393", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 529e992..0aeb25f 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { logos-module-builder.url = "github:logos-co/logos-module-builder"; nix-bundle-lgx.url = "github:logos-co/nix-bundle-lgx"; - logos-execution-zone.url = "github:logos-blockchain/logos-execution-zone?rev=f58cde1a2251c20cf418a561ad974a8c64ab2393"; + logos-execution-zone.url = "github:logos-blockchain/logos-execution-zone?ref=v0.2.1"; }; outputs = inputs@{ logos-module-builder, ... }: diff --git a/src/lez_core_module.cpp b/src/lez_core_module.cpp index 11a6bc3..9e88398 100644 --- a/src/lez_core_module.cpp +++ b/src/lez_core_module.cpp @@ -212,28 +212,31 @@ bool jsonToFfiPrivateAccountKeys(const std::string& json, FfiPrivateAccountKeys* if (doc.is_discarded() || !doc.is_object()) return false; - if (doc.contains(JsonKeys::NullifierPublicKey) && doc[JsonKeys::NullifierPublicKey].is_string()) { - if (!hexToBytes32(doc[JsonKeys::NullifierPublicKey].get(), &output_keys->nullifier_public_key)) - return false; - } + // Nullifier public key is mandatory: a missing/wrong-typed value must not fall back to zero. + if (!doc.contains(JsonKeys::NullifierPublicKey) || !doc[JsonKeys::NullifierPublicKey].is_string()) + return false; + if (!hexToBytes32(doc[JsonKeys::NullifierPublicKey].get(), &output_keys->nullifier_public_key)) + return false; + + output_keys->viewing_public_key = nullptr; + output_keys->viewing_public_key_len = 0; + + if (doc.contains(JsonKeys::ViewingPublicKey)) { + if (!doc[JsonKeys::ViewingPublicKey].is_string()) + return false; - if (doc.contains(JsonKeys::ViewingPublicKey) && doc[JsonKeys::ViewingPublicKey].is_string()) { std::vector buffer; if (!hexToBytes(doc[JsonKeys::ViewingPublicKey].get(), buffer)) return false; - if (buffer.empty()) { - output_keys->viewing_public_key = nullptr; - output_keys->viewing_public_key_len = 0; - } else { + if (!buffer.empty()) { auto* data = static_cast(malloc(buffer.size())); + if (!data) + return false; memcpy(data, buffer.data(), buffer.size()); output_keys->viewing_public_key = data; output_keys->viewing_public_key_len = buffer.size(); } - } else { - output_keys->viewing_public_key = nullptr; - output_keys->viewing_public_key_len = 0; } return true; diff --git a/tests/test_lez_core.cpp b/tests/test_lez_core.cpp index bb072f1..3af98ef 100644 --- a/tests/test_lez_core.cpp +++ b/tests/test_lez_core.cpp @@ -288,6 +288,68 @@ LOGOS_TEST(transfer_shielded_invalid_keys_json_error) { LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); } +// A missing nullifier_public_key must not succeed with a zero key. +LOGOS_TEST(transfer_shielded_missing_nullifier_key_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const nlohmann::json obj = parseObject(module.transfer_shielded(VALID_ID, "{}", VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); +} + +LOGOS_TEST(transfer_shielded_misspelled_nullifier_key_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const std::string keysJson = std::string("{\"nullifierPublicKey\":\"") + std::string(64, 'a') + "\"}"; + const nlohmann::json obj = parseObject(module.transfer_shielded(VALID_ID, keysJson, VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); +} + +LOGOS_TEST(transfer_shielded_abbreviated_nullifier_key_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const std::string keysJson = std::string("{\"nullifier_pubkey\":\"") + std::string(64, 'a') + "\"}"; + const nlohmann::json obj = parseObject(module.transfer_shielded(VALID_ID, keysJson, VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); +} + +LOGOS_TEST(transfer_shielded_nullifier_key_omitted_viewing_key_only_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const std::string keysJson = std::string("{\"viewing_public_key\":\"") + std::string(64, 'a') + "\"}"; + const nlohmann::json obj = parseObject(module.transfer_shielded(VALID_ID, keysJson, VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); +} + +LOGOS_TEST(transfer_shielded_nullifier_key_wrong_type_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const std::string keysJson = "{\"nullifier_public_key\": 12345}"; + const nlohmann::json obj = parseObject(module.transfer_shielded(VALID_ID, keysJson, VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); +} + +// A non-string viewing_public_key must be rejected, not treated as absent. +LOGOS_TEST(transfer_shielded_viewing_key_wrong_type_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const std::string keysJson = std::string("{\"nullifier_public_key\":\"") + std::string(64, 'a') + + "\",\"viewing_public_key\": 12345}"; + const nlohmann::json obj = parseObject(module.transfer_shielded(VALID_ID, keysJson, VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_shielded")); +} + LOGOS_TEST(transfer_shielded_success_json) { auto t = LogosTestContext("logos_execution_zone"); LEZCoreModule module; @@ -335,6 +397,16 @@ LOGOS_TEST(transfer_shielded_without_identifier_uses_random_nonzero_identifier) LOGOS_ASSERT_FALSE(memcmp(first, second, sizeof(first)) == 0); } +// transfer_private shares the same parser, so it must reject a missing key too. +LOGOS_TEST(transfer_private_missing_nullifier_key_error) { + auto t = LogosTestContext("logos_execution_zone"); + LEZCoreModule module; + + const nlohmann::json obj = parseObject(module.transfer_private(VALID_ID, "{}", VALID_U128)); + LOGOS_ASSERT_FALSE(obj["success"].get()); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_transfer_private")); +} + // transfer_private mirrors transfer_shielded's identifier handling exactly (see above). LOGOS_TEST(transfer_private_with_identifier_forwards_it_unchanged) { auto t = LogosTestContext("logos_execution_zone");