feat(wallet): expose claimable vouchers

This commit is contained in:
andrussal 2026-06-15 12:21:56 +02:00
parent fc1439cf16
commit 508efde1fe
7 changed files with 113 additions and 7 deletions

8
flake.lock generated
View File

@ -24,17 +24,17 @@
"rust-rapidsnark": "rust-rapidsnark"
},
"locked": {
"lastModified": 1781525456,
"narHash": "sha256-SOH9dY1Jg8JmfqMWMZ9YzbGQgWL+ifJ4z+8tHW/4zWs=",
"lastModified": 1781681576,
"narHash": "sha256-o/NvjwdX0Bi5eQVnUv3/J122QJclTIufHSJHBjuT5Zs=",
"owner": "logos-blockchain",
"repo": "logos-blockchain",
"rev": "4efdf816e2a3d1447096c3f64c9e230769eb4ecb",
"rev": "93b44bd9ff277546df240ca857a20003da953409",
"type": "github"
},
"original": {
"owner": "logos-blockchain",
"ref": "4efdf816e2a3d1447096c3f64c9e230769eb4ecb",
"repo": "logos-blockchain",
"rev": "93b44bd9ff277546df240ca857a20003da953409",
"type": "github"
}
},

View File

@ -3,8 +3,7 @@
inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder";
# 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";
logos-blockchain.url = "github:logos-blockchain/logos-blockchain?rev=93b44bd9ff277546df240ca857a20003da953409"; # claimable vouchers C binding
};
outputs = inputs@{ logos-module-builder, ... }:

View File

@ -626,6 +626,36 @@ std::string LogosBlockchainModule::leader_claim() {
return bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), TX_HASH_BYTES);
}
std::string LogosBlockchainModule::wallet_get_claimable_vouchers() {
if (!node) {
return "Error: The node is not running.";
}
auto [value, error] = get_claimable_vouchers(node, nullptr);
if (!is_ok(&error)) {
return "Error: Failed to get claimable vouchers: " + std::to_string(error);
}
json obj;
obj["tip"] = bytes_to_hex(reinterpret_cast<const uint8_t*>(&value.tip), ADDRESS_BYTES);
obj["vouchers"] = json::array();
for (size_t i = 0; i < value.len; ++i) {
const ClaimableVoucher& voucher = value.vouchers[i];
obj["vouchers"].push_back({
{"commitment", bytes_to_hex(reinterpret_cast<const uint8_t*>(&voucher.commitment), ADDRESS_BYTES)},
{"nullifier", bytes_to_hex(reinterpret_cast<const uint8_t*>(&voucher.nullifier), ADDRESS_BYTES)},
});
}
const OperationStatus free_status = free_claimable_vouchers(value);
if (!is_ok(&free_status)) {
fprintf(stderr, "Failed to free claimable vouchers. Error: %d\n", free_status);
}
return obj.dump();
}
// Blend
std::string LogosBlockchainModule::blend_join_as_core_node(
@ -772,4 +802,3 @@ std::string LogosBlockchainModule::get_cryptarchia_info() {
}
return obj.dump();
}

View File

@ -76,6 +76,7 @@ public:
);
std::vector<std::string> wallet_get_known_addresses();
std::string leader_claim();
std::string wallet_get_claimable_vouchers();
// Blend
std::string blend_join_as_core_node(

View File

@ -16,6 +16,7 @@ static uint8_t s_mockAddr1[32];
static uint8_t s_mockAddr2[32];
static uint8_t s_mockAddr3[32];
static uint8_t* s_mockAddrs[] = { s_mockAddr0, s_mockAddr1, s_mockAddr2, s_mockAddr3 };
static ClaimableVoucher s_mockClaimableVouchers[4];
extern "C" {
@ -169,6 +170,34 @@ OperationStatus free_known_addresses(KnownAddresses addrs) {
return 0;
}
FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, const HeaderId* optional_tip) {
LOGOS_CMOCK_RECORD("get_claimable_vouchers");
FfiClaimableVouchersResult result;
int err = LOGOS_CMOCK_RETURN(int, "get_claimable_vouchers_error");
result.error = err;
if (err == 0) {
int count = LOGOS_CMOCK_RETURN(int, "get_claimable_vouchers_count");
if (count > 4) count = 4;
memset(result.value.tip, 0xAA, sizeof(HeaderId));
for (int i = 0; i < count; ++i) {
memset(s_mockClaimableVouchers[i].commitment, 0x10 + i, sizeof(Hash));
memset(s_mockClaimableVouchers[i].nullifier, 0x20 + i, sizeof(Hash));
}
result.value.vouchers = s_mockClaimableVouchers;
result.value.len = static_cast<size_t>(count);
} else {
memset(result.value.tip, 0, sizeof(HeaderId));
result.value.vouchers = nullptr;
result.value.len = 0;
}
return result;
}
OperationStatus free_claimable_vouchers(ClaimableVouchers vouchers) {
LOGOS_CMOCK_RECORD("free_claimable_vouchers");
return 0;
}
BlendHashResult blend_join_as_core_node(
LogosBlockchainNode* node,
const uint8_t* provider_id,

View File

@ -70,6 +70,17 @@ typedef struct {
size_t len;
} KnownAddresses;
typedef struct {
Hash commitment;
Hash nullifier;
} ClaimableVoucher;
typedef struct {
HeaderId tip;
ClaimableVoucher* vouchers;
size_t len;
} ClaimableVouchers;
// Cryptarchia consensus info
typedef struct {
uint8_t lib[32];
@ -85,6 +96,7 @@ 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 { ClaimableVouchers value; OperationStatus error; } FfiClaimableVouchersResult;
typedef struct { Hash value; OperationStatus error; } BlendHashResult;
typedef struct { char* value; OperationStatus error; } StringResult;
typedef struct { CryptarchiaInfo* value; OperationStatus error; } CryptarchiaInfoResult;
@ -140,6 +152,8 @@ TransferHashResult transfer_funds(LogosBlockchainNode* node, const TransferFunds
FfiLeaderClaimResult leader_claim(LogosBlockchainNode* node);
KnownAddressesResult get_known_addresses(LogosBlockchainNode* node);
OperationStatus free_known_addresses(KnownAddresses addrs);
FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, const HeaderId* optional_tip);
OperationStatus free_claimable_vouchers(ClaimableVouchers vouchers);
// Blend
BlendHashResult blend_join_as_core_node(

View File

@ -594,6 +594,40 @@ LOGOS_TEST(wallet_get_known_addresses_returns_empty_on_ffi_failure) {
delete module;
}
LOGOS_TEST(wallet_get_claimable_vouchers_returns_json) {
auto t = LogosTestContext("blockchain_module");
TempDir tmpDir;
auto* module = createStartedModule(t, tmpDir);
LOGOS_ASSERT_TRUE(module != nullptr);
t.mockCFunction("get_claimable_vouchers_error").returns(0);
t.mockCFunction("get_claimable_vouchers_count").returns(2);
std::string result = module->wallet_get_claimable_vouchers();
LOGOS_ASSERT_FALSE(starts_with(result, "Error:"));
LOGOS_ASSERT_TRUE(contains(result, "\"vouchers\""));
LOGOS_ASSERT_TRUE(contains(result, std::string(64, 'a')));
LOGOS_ASSERT_TRUE(contains(result, std::string(64, '1')));
LOGOS_ASSERT_TRUE(contains(result, "20202020"));
LOGOS_ASSERT(t.cFunctionCalled("get_claimable_vouchers"));
LOGOS_ASSERT(t.cFunctionCalled("free_claimable_vouchers"));
delete module;
}
LOGOS_TEST(wallet_get_claimable_vouchers_returns_error_on_ffi_failure) {
auto t = LogosTestContext("blockchain_module");
TempDir tmpDir;
auto* module = createStartedModule(t, tmpDir);
LOGOS_ASSERT_TRUE(module != nullptr);
t.mockCFunction("get_claimable_vouchers_error").returns(1);
std::string result = module->wallet_get_claimable_vouchers();
LOGOS_ASSERT_TRUE(starts_with(result, "Error:"));
LOGOS_ASSERT_TRUE(contains(result, "Failed to get claimable vouchers"));
delete module;
}
// Blend
LOGOS_TEST(blend_join_as_core_node_returns_declaration_id) {