Fix get_outs HTTP 500 by using global index space for decoy selection

The transfer pipeline was passing asset-type-specific asset_type to get_output_distribution and get_outs but using global output indices from the wallet DB, causing an index space mismatch that made the daemon return HTTP
   500. Switched to empty asset_type (global index space) for both calls, matching the existing salvium-cli pattern. Removed unused is_global_out field from OutputRequest. Bumped version to r012.
This commit is contained in:
Matt Hess
2026-02-27 03:19:45 +00:00
parent 401a6c2013
commit 9996b116a7
6 changed files with 110 additions and 25 deletions
Generated
+13 -13
View File
@@ -2047,7 +2047,7 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "salvium-cli"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"clap",
"dirs",
@@ -2069,7 +2069,7 @@ dependencies = [
[[package]]
name = "salvium-consensus"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"hex",
"salvium-types",
@@ -2081,7 +2081,7 @@ dependencies = [
[[package]]
name = "salvium-crypto"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"aes-gcm",
"argon2",
@@ -2107,7 +2107,7 @@ dependencies = [
[[package]]
name = "salvium-ffi"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"hex",
"log",
@@ -2125,7 +2125,7 @@ dependencies = [
[[package]]
name = "salvium-miner"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"clap",
"hex",
@@ -2140,7 +2140,7 @@ dependencies = [
[[package]]
name = "salvium-miner-gr"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"cc",
"clap",
@@ -2152,7 +2152,7 @@ dependencies = [
[[package]]
name = "salvium-miner-v2"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"cc",
"clap",
@@ -2167,7 +2167,7 @@ dependencies = [
[[package]]
name = "salvium-multisig"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"curve25519-dalek",
"hex",
@@ -2183,7 +2183,7 @@ dependencies = [
[[package]]
name = "salvium-rpc"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"base64",
"hex",
@@ -2197,7 +2197,7 @@ dependencies = [
[[package]]
name = "salvium-sync-bench"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"clap",
"env_logger",
@@ -2214,7 +2214,7 @@ dependencies = [
[[package]]
name = "salvium-tx"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"curve25519-dalek",
"getrandom 0.2.17",
@@ -2232,7 +2232,7 @@ dependencies = [
[[package]]
name = "salvium-types"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"hex",
"serde",
@@ -2242,7 +2242,7 @@ dependencies = [
[[package]]
name = "salvium-wallet"
version = "1.0.7-r011"
version = "1.0.7-r012"
dependencies = [
"aes-gcm",
"chacha20",
+1 -1
View File
@@ -20,7 +20,7 @@ members = [
]
[workspace.package]
version = "1.0.7-r011"
version = "1.0.7-r012"
edition = "2021"
license = "LicenseRef-Salvium-RS"
repository = "https://github.com/salvium/salvium-rs"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "salvium-explorer"
version = "1.0.7-r011"
version = "1.0.7-r012"
edition = "2021"
description = "High-level WASM APIs for Salvium blockchain explorers"
+8 -5
View File
@@ -95,7 +95,7 @@ fn parse_priority(s: &str) -> FeePriority {
/// ```json
/// {
/// "destinations": [{"address": "Svk1...", "amount": "1000000000"}],
/// "asset_type": "SAL",
/// "assetType": "SAL1",
/// "priority": "normal",
/// "ring_size": 16
/// }
@@ -139,7 +139,7 @@ pub unsafe extern "C" fn salvium_wallet_transfer(
/// ```json
/// {
/// "amount": "1000000000",
/// "asset_type": "SAL",
/// "assetType": "SAL1",
/// "priority": "normal",
/// "ring_size": 16
/// }
@@ -212,7 +212,7 @@ pub unsafe extern "C" fn salvium_wallet_stake_dry_run(
/// ```json
/// {
/// "address": "Svk1...",
/// "asset_type": "SAL",
/// "assetType": "SAL1",
/// "priority": "normal",
/// "ring_size": 16,
/// "dry_run": false
@@ -560,8 +560,11 @@ async fn build_sign_maybe_broadcast(
let keys = wallet.keys();
// 1. Get output distribution for decoy selection.
// We use global index space (empty asset_type) because our wallet stores
// global output indices. Both decoys and the real output use global IDs,
// so the index spaces are consistent. This matches salvium-cli's approach.
let dist = daemon
.get_output_distribution(&[0], 0, 0, true, asset_type)
.get_output_distribution(&[0], 0, 0, true, "")
.await
.map_err(|e| format!("get_output_distribution failed: {e}"))?;
@@ -590,7 +593,7 @@ async fn build_sign_maybe_broadcast(
.collect();
let outs = daemon
.get_outs(&requests, true, asset_type)
.get_outs(&requests, true, "")
.await
.map_err(|e| format!("get_outs failed: {e}"))?;
+5 -4
View File
@@ -988,9 +988,9 @@ impl DaemonRpc {
/// Get output details by amount and index.
///
/// When `asset_type` is non-empty, indices in `OutputRequest` are treated as
/// asset-type-specific indices (unless `is_global_out` is set on individual
/// entries). The daemon converts them to global output IDs internally.
/// When `asset_type` is empty, indices are treated as global output IDs.
/// asset-type-specific indices. The daemon converts them to global output IDs
/// internally. When `asset_type` is empty, indices are treated as global
/// output IDs.
pub async fn get_outs(
&self,
outputs: &[OutputRequest],
@@ -1556,7 +1556,8 @@ impl DaemonRpc {
/// Request for a specific output by amount and index.
///
/// When `asset_type` is set on the parent `get_outs` request, `index` is treated
/// as an asset-type-specific index. Without `asset_type`, it's a global output ID.
/// as an asset-type-specific index. Without `asset_type`, `index` is a global
/// output ID.
#[derive(Debug, Clone, Serialize)]
pub struct OutputRequest {
pub amount: u64,
+82 -1
View File
@@ -343,7 +343,88 @@ salvium_string_free(stakes);
| `returnHeight` | i64/null | Block height of return |
| `returnAmount` | string | Amount returned (atomic) |
## 11. Cleanup
## 11. Sending Transactions
All transaction functions take a JSON params string. **`assetType` is required** — there is
no default. Omitting it returns an error.
All return a JSON string on success (caller must free with `salvium_string_free()`), or
NULL on error.
### Transfer
```c
char* result = salvium_wallet_transfer(wallet, daemon, "{\"destinations\":[{\"address\":\"Svk1...\",\"amount\":\"100000000\"}],\"assetType\":\"SAL1\"}");
salvium_string_free(result);
```
**Params (camelCase):**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `destinations` | array | yes | `[{"address": "...", "amount": "..."}]` (atomic units) |
| `assetType` | string | yes | Asset to spend (e.g. `"SAL1"`) |
| `priority` | string | no | `"low"`, `"normal"` (default), `"elevated"`, `"priority"` |
| `ringSize` | number | no | Default 16 |
| `dryRun` | bool | no | If true, build + sign but don't broadcast |
**Result:** `{"txHash": "...", "fee": "...", "amount": "..."}`
When `dryRun` is true, also includes `txHex` and `weight`.
### Transfer Dry Run
Convenience wrapper — forces `dryRun: true` regardless of params.
```c
char* result = salvium_wallet_transfer_dry_run(wallet, daemon, params_json);
```
### Stake
```c
char* result = salvium_wallet_stake(wallet, daemon, "{\"amount\":\"100000000\",\"assetType\":\"SAL1\"}");
salvium_string_free(result);
```
**Params:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `amount` | string | yes | Amount to stake (atomic units) |
| `assetType` | string | yes | Asset to stake |
| `priority` | string | no | Fee priority (default `"normal"`) |
| `ringSize` | number | no | Default 16 |
**Result:** `{"txHash": "...", "fee": "...", "amount": "...", "weight": ...}`
### Stake Dry Run
```c
char* result = salvium_wallet_stake_dry_run(wallet, daemon, params_json);
```
### Sweep
Sends all unlocked outputs of the specified asset to a single address.
```c
char* result = salvium_wallet_sweep(wallet, daemon, "{\"address\":\"Svk1...\",\"assetType\":\"SAL1\"}");
salvium_string_free(result);
```
**Params:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `address` | string | yes | Destination address |
| `assetType` | string | yes | Asset to sweep |
| `priority` | string | no | Fee priority (default `"normal"`) |
| `ringSize` | number | no | Default 16 |
| `dryRun` | bool | no | If true, build + sign but don't broadcast |
**Result:** `{"txHash": "...", "fee": "...", "amount": "..."}`
## 12. Cleanup
**Close in reverse order.** Always close handles when done.