From fc1439cf164edbd1ff17ef8af1493d6ba6720536 Mon Sep 17 00:00:00 2001 From: Andrus Salumets Date: Mon, 15 Jun 2026 15:53:24 +0200 Subject: [PATCH] feat(leader): expose leader reward claim (#31) --- flake.lock | 8 +++--- flake.nix | 4 +-- src/logos_blockchain_module.cpp | 14 ++++++++++ src/logos_blockchain_module.h | 1 + tests/mocks/mock_logos_blockchain.cpp | 8 ++++++ tests/stubs/logos_blockchain.h | 2 ++ tests/test_blockchain.cpp | 38 +++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 909afae..3a0e27f 100644 --- a/flake.lock +++ b/flake.lock @@ -24,16 +24,16 @@ "rust-rapidsnark": "rust-rapidsnark" }, "locked": { - "lastModified": 1781288172, - "narHash": "sha256-4anGBb7slL6WfMCGlI4BmLAjim7kQOMD/qv4FCPJwII=", + "lastModified": 1781525456, + "narHash": "sha256-SOH9dY1Jg8JmfqMWMZ9YzbGQgWL+ifJ4z+8tHW/4zWs=", "owner": "logos-blockchain", "repo": "logos-blockchain", - "rev": "86e24cfd985b6341e96bba76ecad36ff379bd243", + "rev": "4efdf816e2a3d1447096c3f64c9e230769eb4ecb", "type": "github" }, "original": { "owner": "logos-blockchain", - "ref": "86e24cfd985b6341e96bba76ecad36ff379bd243", + "ref": "4efdf816e2a3d1447096c3f64c9e230769eb4ecb", "repo": "logos-blockchain", "type": "github" } diff --git a/flake.nix b/flake.nix index e33cab8..aad4675 100644 --- a/flake.nix +++ b/flake.nix @@ -3,8 +3,8 @@ inputs = { logos-module-builder.url = "github:logos-co/logos-module-builder"; - # v0.1.3-rc.10-compatible + rust-rapidsnark nix fixes + cli commands - logos-blockchain.url = "github:logos-blockchain/logos-blockchain?ref=86e24cfd985b6341e96bba76ecad36ff379bd243"; + # v0.1.3-rc.10-compatible + rust-rapidsnark nix fixes + cli commands + leader_claim C binding + logos-blockchain.url = "github:logos-blockchain/logos-blockchain?ref=4efdf816e2a3d1447096c3f64c9e230769eb4ecb"; }; outputs = inputs@{ logos-module-builder, ... }: diff --git a/src/logos_blockchain_module.cpp b/src/logos_blockchain_module.cpp index f1cd115..1dbe22f 100644 --- a/src/logos_blockchain_module.cpp +++ b/src/logos_blockchain_module.cpp @@ -29,6 +29,7 @@ namespace { // Use the C API type Hash (from logos_blockchain.h) to define address/hash byte size. constexpr int ADDRESS_BYTES = sizeof(Hash); + constexpr int TX_HASH_BYTES = sizeof(TxHash); constexpr int ADDRESS_HEX_LEN = ADDRESS_BYTES * 2; std::vector parse_address_hex(const std::string& address_hex) { @@ -612,6 +613,19 @@ std::vector LogosBlockchainModule::wallet_get_known_addresses() { return out; } +std::string LogosBlockchainModule::leader_claim() { + if (!node) { + return "Error: The node is not running."; + } + + auto [value, error] = ::leader_claim(node); + if (!is_ok(&error)) { + return "Error: Failed to claim leader rewards: " + std::to_string(error); + } + + return bytes_to_hex(reinterpret_cast(&value), TX_HASH_BYTES); +} + // Blend std::string LogosBlockchainModule::blend_join_as_core_node( diff --git a/src/logos_blockchain_module.h b/src/logos_blockchain_module.h index 237ea5e..9ebde0d 100644 --- a/src/logos_blockchain_module.h +++ b/src/logos_blockchain_module.h @@ -75,6 +75,7 @@ public: const std::string& optional_tip_hex ); std::vector wallet_get_known_addresses(); + std::string leader_claim(); // Blend std::string blend_join_as_core_node( diff --git a/tests/mocks/mock_logos_blockchain.cpp b/tests/mocks/mock_logos_blockchain.cpp index cb3439e..19e13f5 100644 --- a/tests/mocks/mock_logos_blockchain.cpp +++ b/tests/mocks/mock_logos_blockchain.cpp @@ -135,6 +135,14 @@ TransferHashResult transfer_funds(LogosBlockchainNode* node, const TransferFunds return result; } +FfiLeaderClaimResult leader_claim(LogosBlockchainNode* node) { + LOGOS_CMOCK_RECORD("leader_claim"); + FfiLeaderClaimResult result; + memset(result.value, 0xEF, sizeof(TxHash)); + result.error = LOGOS_CMOCK_RETURN(int, "leader_claim_error"); + return result; +} + KnownAddressesResult get_known_addresses(LogosBlockchainNode* node) { LOGOS_CMOCK_RECORD("get_known_addresses"); KnownAddressesResult result; diff --git a/tests/stubs/logos_blockchain.h b/tests/stubs/logos_blockchain.h index 6eb1b3b..7455a95 100644 --- a/tests/stubs/logos_blockchain.h +++ b/tests/stubs/logos_blockchain.h @@ -83,6 +83,7 @@ typedef struct { typedef struct { LogosBlockchainNode* value; OperationStatus error; } NodeResult; typedef struct { uint64_t value; OperationStatus error; } BalanceResult; typedef struct { Hash value; OperationStatus error; } TransferHashResult; +typedef struct { TxHash value; OperationStatus error; } FfiLeaderClaimResult; typedef struct { KnownAddresses value; OperationStatus error; } KnownAddressesResult; typedef struct { Hash value; OperationStatus error; } BlendHashResult; typedef struct { char* value; OperationStatus error; } StringResult; @@ -136,6 +137,7 @@ StringResult get_peer_id(const char* config_path); // Wallet BalanceResult get_balance(LogosBlockchainNode* node, const uint8_t* address, const void* reserved); TransferHashResult transfer_funds(LogosBlockchainNode* node, const TransferFundsArguments* args); +FfiLeaderClaimResult leader_claim(LogosBlockchainNode* node); KnownAddressesResult get_known_addresses(LogosBlockchainNode* node); OperationStatus free_known_addresses(KnownAddresses addrs); diff --git a/tests/test_blockchain.cpp b/tests/test_blockchain.cpp index e6c8f59..a9ad982 100644 --- a/tests/test_blockchain.cpp +++ b/tests/test_blockchain.cpp @@ -147,6 +147,14 @@ LOGOS_TEST(wallet_transfer_funds_without_node_returns_error) { LOGOS_ASSERT_TRUE(contains(result, "not running")); } +LOGOS_TEST(leader_claim_without_node_returns_error) { + auto t = LogosTestContext("blockchain_module"); + LogosBlockchainModule module; + std::string result = module.leader_claim(); + LOGOS_ASSERT_TRUE(starts_with(result, "Error:")); + LOGOS_ASSERT_TRUE(contains(result, "not running")); +} + LOGOS_TEST(wallet_get_known_addresses_without_node_returns_empty) { auto t = LogosTestContext("blockchain_module"); LogosBlockchainModule module; @@ -496,6 +504,36 @@ LOGOS_TEST(wallet_transfer_funds_returns_error_on_ffi_failure) { delete module; } +LOGOS_TEST(leader_claim_returns_tx_hash) { + auto t = LogosTestContext("blockchain_module"); + TempDir tmpDir; + auto* module = createStartedModule(t, tmpDir); + LOGOS_ASSERT_TRUE(module != nullptr); + + t.mockCFunction("leader_claim_error").returns(0); + + std::string result = module->leader_claim(); + LOGOS_ASSERT_FALSE(starts_with(result, "Error:")); + LOGOS_ASSERT_EQ(static_cast(result.length()), 64); + LOGOS_ASSERT_TRUE(starts_with(result, "ef")); + LOGOS_ASSERT(t.cFunctionCalled("leader_claim")); + delete module; +} + +LOGOS_TEST(leader_claim_returns_error_on_ffi_failure) { + auto t = LogosTestContext("blockchain_module"); + TempDir tmpDir; + auto* module = createStartedModule(t, tmpDir); + LOGOS_ASSERT_TRUE(module != nullptr); + + t.mockCFunction("leader_claim_error").returns(1); + + std::string result = module->leader_claim(); + LOGOS_ASSERT_TRUE(starts_with(result, "Error:")); + LOGOS_ASSERT_TRUE(contains(result, "Failed to claim leader rewards")); + delete module; +} + LOGOS_TEST(wallet_transfer_funds_single_sender_via_vector) { auto t = LogosTestContext("blockchain_module"); TempDir tmpDir;