Skip to content

Create a test that reproduces Sapling-to-Orchard ZIP-317 fee bug #90

@pacu

Description

@pacu

Reproducing the zcashd ZIP 317 Fee Bug

This note documents the zcashd wallet bug that the gRPC comparison fixture
surfaced while building its Sapling-to-Orchard funding transaction.

The short version is:

  • a Sapling-funded account sends to an Orchard-only UA,
  • z_sendmany is called with AllowRevealedAmounts,
  • the caller relies on the default ZIP 317 fee (None / ZIP_317_FEE),
  • and the asynchronous operation later fails with an unpaid Orchard action
    error.

In the gRPC comparison test we worked around that by passing
conventional_fee(4) explicitly. This page isolates the same bug in a small
test so it can be reported upstream without the rest of the gRPC fixture.

Repro test

The dedicated repro is:

Run it directly with:

uv run python3 qa/rpc-tests/wallet_zip317_fee_repro.py

Or through the RPC harness with:

uv run ./qa/pull-tester/rpc-tests.py wallet_zip317_fee_repro.py

What the test does

The repro intentionally keeps the setup small:

  1. fund a unified address on node 0 so the account balance initially sits in
    the Sapling pool,
  2. activate NU5,
  3. create an Orchard-only UA on node 1,
  4. call:
z_sendmany(source_ua, [{"address": orchard_only_ua, "amount": 1}], 1, ZIP_317_FEE, "AllowRevealedAmounts")
  1. observe that the async operation fails,
  2. retry the same call with conventional_fee(4) and observe that it succeeds.

Observed buggy behavior

The failing call currently returns an opid, but the operation completes with:

Transaction commit failed:: tx unpaid action limit exceeded: 1 action(s) exceeds limit of 0

That means the wallet accepted the request and picked the default ZIP 317 fee,
but later discovered that the constructed Orchard action was not fully paid for.

Expected behavior

One of these should happen instead:

  • zcashd should select a sufficient fee automatically for this transaction
    shape when None / ZIP_317_FEE is used, or
  • zcashd should reject the request synchronously before returning an opid if
    the selected default fee will be insufficient.

Returning an opid and then failing during transaction construction is the part
that made this especially confusing while bringing grpc_comparison.py live.

Current workaround

Passing conventional_fee(4) makes the same transaction succeed:

z_sendmany(source_ua, recipients, 1, conventional_fee(4), "AllowRevealedAmounts")

That workaround is now used in the gRPC comparison fixture.

Related call sites

The same wallet-side behavior was already forcing explicit fee overrides in
other tests:

Suggested upstream issue outline

Suggested title:

zcashd underestimates ZIP 317 fee for Sapling->Orchard z_sendmany with AllowRevealedAmounts

Suggested points to include:

  • minimal repro command: uv run python3 qa/rpc-tests/wallet_zip317_fee_repro.py
  • observed error: tx unpaid action limit exceeded: 1 action(s) exceeds limit of 0
  • explicit conventional_fee(4) succeeds
  • the same workaround was needed while stabilizing grpc_comparison.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions