Skip to content

feat(key-wallet-ffi): typed special-transaction payload on FFITransactionRecord (expose ProRegTx service IP) #875

Description

@QuantumExplorer

Motivation

When a wallet's provider owner/voting key matches a ProRegTx during compact-filter sync (works since #863/#864, part of #861), consumers need the transaction's special payload data — most importantly the masternode's service_address (IP:port), but also proTxHash linkage, collateral outpoint, and the owner/voting/operator keys — to display anything useful about the masternode ("this key was used by the masternode at 54.148.58.128:9999"). The legacy DashSync SDK exposed this via DSLocalMasternode (built from DSProviderRegistrationTransaction.ipAddress/port); the Rust SDK currently cannot.

Current state

FFITransactionRecord (key-wallet-ffi/src/managed_account.rs) has no typed payload field. The only way to recover payload data is to consensus-decode the raw tx_data bytes on the consumer side — verified working (the service IP sits in those bytes), but it forces every binding (Swift/Kotlin) to reimplement DIP-2/DIP-3 payload parsing.

Worse, every other FFI conversion path explicitly drops the payload when reconstructing a transaction:

  • key-wallet-ffi/src/transaction.rs:280special_transaction_payload: None
  • key-wallet-ffi/src/tx_decode.rs:361special_transaction_payload: None
  • key-wallet-ffi/src/managed_account.rs:2350special_transaction_payload: None

And with keep-finalized-transactions off (the default in mobile builds), a chainlocked-at-first-sight historical ProRegTx's full record is dropped right after processing (managed_core_keys_account.rs, drop_finalized_transaction), so even the raw-bytes escape hatch disappears for the very transactions masternode-key discovery cares about.

Proposal

Add a typed, FFI-safe specialized-payload representation to FFITransactionRecord:

  1. A tagged union (e.g. FFISpecialTransactionPayload with a payload_type discriminant matching the DIP-2 tx types) covering at least:
    • ProviderRegistration: version, masternode type, collateral outpoint, service address (string form + raw ip/port), owner/voting key hashes, operator pubkey, operator reward, payout script, platform node id/ports
    • ProviderUpdateService: proTxHash, new service address, operator payout script
    • ProviderUpdateRegistrar: proTxHash, voting key hash, operator pubkey, payout script
    • ProviderUpdateRevocation: proTxHash, reason
    • (AssetLock/AssetUnlock/Coinbase payloads can follow the same shape later)
  2. Populate it in FFITransactionRecord construction from the stored TransactionRecord's special_transaction_payload, and stop hardcoding special_transaction_payload: None in the three conversion paths above where the source payload is available.
  3. Ensure the payload (or at least the provider-relevant fields) survives drop_finalized_transaction for transactions that matched a provider key account, so the data remains queryable without keep-finalized-transactions.

Item 3 overlaps with the broader "local masternode surface" idea (a persistent DashSync-DSLocalMasternode-style struct, plus monitoring proTxHash in the filter query for follow-on ProUpServTx IP updates — the pending remainder of #861). This issue is scoped to the FFI record shape; the local-masternode registry can build on it.

Acceptance

  • FFITransactionRecord for a stored ProRegTx exposes a typed payload including service_address without the consumer decoding tx_data.
  • The three special_transaction_payload: None sites populate the payload when the source has one.
  • Round-trip test: record a mainnet-shape ProRegTx (e.g. owner/voting hash160 70993555a01f7e8d6179d6135b5c56809d2d1d36, service 54.148.58.128:9999) → FFI record exposes those fields.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions