Environment
- Network:
kaspatest testnet-10 (rpc api-tn10.kaspa.org)
- Tooling: Python SDK
kaspa 2.0.1 (PyPI) + Rust kaspa-wasm 0.13.0
- Date: July 2026
What I'm trying to do
Deploy a simple timelock covenant on testnet-10:
- Spend a v0 P2PK UTXO (40.928 KAS, Schnorr-signed)
- Create a version-1 transaction with
computeBudget = 65535 on the input
- Output[0]: 1,000,000 sompi → P2SH-wrapped redeem script containing
OP_CHECKLOCKTIMEVERIFY + Schnorr pubkey check, with CovenantBinding attached and covenant_id = blake2b(outpoint || authorized_outputs)
- Output[1]: fee; output[2]: change
- Sign with BIP-340 Schnorr via
sign_transaction()
- Broadcast via
/transactions
The JSON we send includes "computeBudget": 65535 on each input, version: 1, sigOpCount: 1, Schnorr signature script.
What happens
The node consistently rejects with:
RPC Server (remote error) -> Rejected transaction <txid>:
failed to verify the signature script: script units exceeded the amount committed
in the input: used=100000, limit=9999
The value 9999 matches the free-script-unit allowance on the underlying v0 UTXO. The 100,000 figure is roughly the cost of verifying one Schnorr signature. The computeBudget = 65535 that I set on the v1 input is completely ignored.
What I've tried
| # |
Change |
Result |
| 1 |
Default compute_budget |
rejected — same error |
| 2 |
Smaller outputs (5 KAS total) |
rejected |
| 3 |
Split funds into many small UTXOs |
rejected |
| 4 |
Manually inject computeBudget: 200000 into the signed JSON |
rejected |
| 5 |
Monkey-patch Transaction.to_dict() in the Python SDK to serialize compute_budget |
rejected — same error |
| 6 |
sig_op_count = 0 on input (v1 covenant convention) |
rejected |
The transaction signs successfully and produces a valid txid locally; the problem is at consensus validation.
Questions
-
Field semantics: Is computeBudget the wrong field for raising the signature-verification limit? The error message says "the amount committed in the input" — that phrasing suggests the budget is derived from the UTXO itself (committed at spend time), not from the transaction that spends it. If so, what is the correct field to raise it?
-
v0 → v1 bootstrap: Can a v1 covenant transaction actually spend a v0 UTXO? Or does the protocol require that covenant transactions only spend UTXOs that were themselves created by v1 (covenant-aware) transactions? If a bootstrap path exists, I'd love to see it.
-
Signing scheme: Schnorr verification costs ~100K script units. If the input-side budget truly cannot exceed the v0 UTXO's 9999, does that mean covenant-input signature verification needs a cheaper scheme (ECDSA, or something else), or is the budget supposed to be raised via a different mechanism entirely?
-
Reference deployment: Has anyone successfully deployed any covenant on testnet-10 (or mainnet)? A single known-good txid would let me diff the structure byte-for-byte against what I'm sending.
What I've verified locally
- Covenant-id hash (
blake2b(outpoint ‖ authorized_outputs)) matches the Rust SDK's own test vector.
- Transaction signs; local txid computation matches node-side rejection txid.
- Wallet side (
getUtxosByAddresses, sendTransaction) is fine — the same wallet can send normal v0 payments without issue.
Repo references I checked
wip/covenants — no working example found
- Consensus code under
consensus/core/src/tx/ — I haven't been able to pinpoint where the 9999 limit is read without more time tracing through the script-unit accounting.
Happy to provide the signed tx hex / full JSON if that helps. Thanks for any pointer.
Posting recipe (for when user has 2 min)
# 1) install gh if not present (Ubuntu/Debian):
# sudo mkdir -p -m 755 /etc/apt/keyrings
# wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg \
# | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
# echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \
# https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list
# sudo apt update && sudo apt install gh -y
# 2) auth
gh auth login # paste token, choose HTTPS, default everything
# 3) post
cd /home/jeff-siegel/.hermes/projects/kaspa-suite
gh issue create \
--repo kaspanet/rusty-kaspa \
--title "v1 covenant transaction rejected on testnet-10: \"script units exceeded\" even with computeBudget set" \
--label question \
Environment
kaspatesttestnet-10 (rpcapi-tn10.kaspa.org)kaspa2.0.1 (PyPI) + Rustkaspa-wasm0.13.0What I'm trying to do
Deploy a simple timelock covenant on testnet-10:
computeBudget = 65535on the inputOP_CHECKLOCKTIMEVERIFY+ Schnorr pubkey check, withCovenantBindingattached andcovenant_id = blake2b(outpoint || authorized_outputs)sign_transaction()/transactionsThe JSON we send includes
"computeBudget": 65535on each input,version: 1,sigOpCount: 1, Schnorr signature script.What happens
The node consistently rejects with:
The value
9999matches the free-script-unit allowance on the underlying v0 UTXO. The 100,000 figure is roughly the cost of verifying one Schnorr signature. ThecomputeBudget = 65535that I set on the v1 input is completely ignored.What I've tried
computeBudget: 200000into the signed JSONTransaction.to_dict()in the Python SDK to serializecompute_budgetsig_op_count = 0on input (v1 covenant convention)The transaction signs successfully and produces a valid txid locally; the problem is at consensus validation.
Questions
Field semantics: Is
computeBudgetthe wrong field for raising the signature-verification limit? The error message says "the amount committed in the input" — that phrasing suggests the budget is derived from the UTXO itself (committed at spend time), not from the transaction that spends it. If so, what is the correct field to raise it?v0 → v1 bootstrap: Can a v1 covenant transaction actually spend a v0 UTXO? Or does the protocol require that covenant transactions only spend UTXOs that were themselves created by v1 (covenant-aware) transactions? If a bootstrap path exists, I'd love to see it.
Signing scheme: Schnorr verification costs ~100K script units. If the input-side budget truly cannot exceed the v0 UTXO's
9999, does that mean covenant-input signature verification needs a cheaper scheme (ECDSA, or something else), or is the budget supposed to be raised via a different mechanism entirely?Reference deployment: Has anyone successfully deployed any covenant on testnet-10 (or mainnet)? A single known-good txid would let me diff the structure byte-for-byte against what I'm sending.
What I've verified locally
blake2b(outpoint ‖ authorized_outputs)) matches the Rust SDK's own test vector.getUtxosByAddresses,sendTransaction) is fine — the same wallet can send normal v0 payments without issue.Repo references I checked
wip/covenants— no working example foundconsensus/core/src/tx/— I haven't been able to pinpoint where the9999limit is read without more time tracing through the script-unit accounting.Happy to provide the signed tx hex / full JSON if that helps. Thanks for any pointer.
Posting recipe (for when user has 2 min)