English | 中文
Summary
On FNN 0.9.1, a dual-funded SUDT channel fails to open at the default fee rate. FNN builds a funding transaction with a fee of 1077 shannons, but CKB requires 1162 and rejects it.
In this transaction, FNN does not reserve witness space for the channel acceptor's lock when calculating the fee.
Environment
| Item |
Value |
| FNN |
Official macOS arm64 release, fnn Fiber v0.9.1 (9a561b3 2026-09-10). |
| CKB |
0.208.0, local devnet, tx_pool.min_fee_rate = 1000. |
| Setup |
Two connected FNN nodes with different funding locks. |
funding_fee_rate is omitted, so Fiber uses DEFAULT_FEE_RATE = 1000. The channel initiator opens with 5000 SUDT (0x1388) and the acceptor accepts with 10000 SUDT (0x2710), both from their own secp locks:
{
"pubkey": "<acceptor_pubkey>",
"funding_amount": "0x1388",
"funding_udt_type_script": {
"code_hash": "0x6283a479a3cf5d4276cd93594de9f1827ab9b55c7b05b3d28e4c2e0a696cfefd",
"hash_type": "type",
"args": "0x4472b33b4e1845ebe82f2ce5f511bbe012f144c5f3d7b539909adffc83ccda61"
}
}
Actual and expected results
Expected: the channel opens at the default fee rate.
Actual: after the acceptor accepts, CKB rejects the funding transaction. The channel stays unusable. Node log:
2026-09-24T10:29:02.165872Z ERROR fnn::ckb::actor: [ckb] send transaction Byte32(0xbc45c7633b1b89063bc43e3a714cbc6064d7b34e194d29dbad3e22f3a897fee3) failed: Rpc(Error { code: ServerError(-1104), message: "PoolRejectedTransactionByMinFeeRate: The min fee rate is 1000 shannons/KW, requiring a transaction fee of at least 1162 shannons, but the fee provided is only 1077", data: Some(String("LowFeeRate(FeeRate(1000), 1162, 1077)")) })
The same scenario at funding_fee_rate 2000 opens successfully; the fee is then 2154 shannons and the size underestimate is still there.
Cause
The two peers use different secp locks. The acceptor's UDT input is already present when balancing runs and is its first input, at index 2, while Fiber reserves signature space only at index 0. The fee is therefore fixed while the acceptor's witness entry is still empty, and the signature written at signing time grows the transaction by 85 bytes without changing the fee.
The fee is fixed during transaction construction by CapacityBalancer; the CKB actor's LocalSigner::sign_funding_tx only signs and does not recalculate it.
This issue is not specific to SUDT. In this funding transaction construction path, the acceptor's secp script group already has an input before balancing, but the lock field of its witness entry is still empty when the fee is calculated. Other UDTs, including xUDT, are expected to be affected under the same conditions; the reproduction reported here uses SUDT.
| What is counted |
Size used to calculate the fee |
Fee required at rate 1000 |
| Before signing: space reserved for only one of the two required signatures |
1077 bytes |
1077 shannons |
| After signing: both required signatures are present |
1162 bytes |
1162 shannons |
| Difference |
85 bytes |
85 shannons |
Code locations
| Location |
What goes wrong |
Fiber build_base_from_funding_cell, lines 501–550 |
Builds the transaction from both peers' funds, but resets witnesses to one entry. The first entry, used by the initiator's account, reserves signature space. The SDK later adds an empty entry for the acceptor, with no space reserved for its signature. |
Fiber build_and_balance_tx, lines 552–575 |
Creates the SDK signing helper with no private keys, so the SDK's automatic placeholder filling matches neither account. |
SDK has_provider check and signature-data branch |
The acceptor's UDT input is already in the transaction, so the SDK skips the branch that would reserve signature space when adding the first CKB input from that account. |
SDK fee calculation, then Fiber LocalSigner::sign_funding_tx |
The fee is calculated with the acceptor's field still empty; signing fills it later without rebalancing. |
中文版
接受方 script group 的 witness lock 字段为空,导致开通道交易因手续费不足被拒绝
问题概述
在 FNN 0.9.1 中,双方共同出资的 SUDT 通道在默认费率下无法开通。FNN 构造的交易手续费为 1077 shannons,而 CKB 要求 1162,因此拒绝了这笔交易。
本次交易中,FNN 计算手续费时没有为通道接受方的账户锁预留 witness 空间。
测试环境
| 项目 |
配置 |
| FNN |
官方 macOS arm64 发布包,fnn Fiber v0.9.1 (9a561b3 2026-09-10)。 |
| CKB |
0.208.0,本地开发链,tx_pool.min_fee_rate = 1000。 |
| 节点 |
两个已连接的 FNN 节点,使用不同的出资账户锁。 |
未指定 funding_fee_rate,Fiber 使用 DEFAULT_FEE_RATE = 1000。通道发起方以 5000 SUDT(0x1388)发起,通道接受方以 10000 SUDT(0x2710)接受,双方各自使用自己的 secp 账户锁:
{
"pubkey": "<acceptor_pubkey>",
"funding_amount": "0x1388",
"funding_udt_type_script": {
"code_hash": "0x6283a479a3cf5d4276cd93594de9f1827ab9b55c7b05b3d28e4c2e0a696cfefd",
"hash_type": "type",
"args": "0x4472b33b4e1845ebe82f2ce5f511bbe012f144c5f3d7b539909adffc83ccda61"
}
}
预期与实际结果
预期:通道能以默认费率正常开通。
实际:通道接受方接受后,CKB 拒绝了开通道交易,通道无法使用。节点日志:
2026-09-24T10:29:02.165872Z ERROR fnn::ckb::actor: [ckb] send transaction Byte32(0xbc45c7633b1b89063bc43e3a714cbc6064d7b34e194d29dbad3e22f3a897fee3) failed: Rpc(Error { code: ServerError(-1104), message: "PoolRejectedTransactionByMinFeeRate: The min fee rate is 1000 shannons/KW, requiring a transaction fee of at least 1162 shannons, but the fee provided is only 1077", data: Some(String("LowFeeRate(FeeRate(1000), 1162, 1077)")) })
同一场景改用 funding_fee_rate 2000 可以正常开通,此时手续费为 2154 shannons,交易大小仍然少算了。
问题原因
双方使用不同的 secp 账户锁。估费时,通道接受方的 UDT 输入已经在交易中,且是它的首个输入、位于索引 2,而 Fiber 只为索引 0 预留了签名空间。手续费因此在接受方 witness 仍为空时就已定死,签名阶段写入后交易增加 85 字节,手续费不变。
手续费在构造交易时由 CapacityBalancer 算好,CKB actor 调用的 LocalSigner::sign_funding_tx 只签名,不重新计算。
此问题并非 SUDT 特有。在这条开通道交易构造路径中,接受方的 secp script group 在平衡交易前已有输入,但计算手续费时,它对应的 witness 里 lock 字段仍为空。在相同条件下,其他 UDT(包括 xUDT)预计也会受影响;本文实际复现使用的是 SUDT。
| 计算时机 |
用来计算手续费的交易大小 |
按费率 1000 应付的手续费 |
| 签名前:需要两份签名,只预留了一份的空间 |
1077 字节 |
1077 shannons |
| 签名后:需要的两份签名都已加入 |
1162 字节 |
1162 shannons |
| 少算的部分 |
85 字节 |
85 shannons |
具体代码位置
English | 中文
Summary
On FNN
0.9.1, a dual-funded SUDT channel fails to open at the default fee rate. FNN builds a funding transaction with a fee of1077shannons, but CKB requires1162and rejects it.In this transaction, FNN does not reserve witness space for the channel acceptor's lock when calculating the fee.
Environment
fnn Fiber v0.9.1 (9a561b3 2026-09-10).0.208.0, local devnet,tx_pool.min_fee_rate = 1000.funding_fee_rateis omitted, so Fiber usesDEFAULT_FEE_RATE=1000. The channel initiator opens with5000SUDT (0x1388) and the acceptor accepts with10000SUDT (0x2710), both from their own secp locks:{ "pubkey": "<acceptor_pubkey>", "funding_amount": "0x1388", "funding_udt_type_script": { "code_hash": "0x6283a479a3cf5d4276cd93594de9f1827ab9b55c7b05b3d28e4c2e0a696cfefd", "hash_type": "type", "args": "0x4472b33b4e1845ebe82f2ce5f511bbe012f144c5f3d7b539909adffc83ccda61" } }Actual and expected results
Expected: the channel opens at the default fee rate.
Actual: after the acceptor accepts, CKB rejects the funding transaction. The channel stays unusable. Node log:
The same scenario at
funding_fee_rate2000opens successfully; the fee is then2154shannons and the size underestimate is still there.Cause
The two peers use different secp locks. The acceptor's UDT input is already present when balancing runs and is its first input, at index
2, while Fiber reserves signature space only at index0. The fee is therefore fixed while the acceptor's witness entry is still empty, and the signature written at signing time grows the transaction by85bytes without changing the fee.The fee is fixed during transaction construction by
CapacityBalancer; the CKB actor'sLocalSigner::sign_funding_txonly signs and does not recalculate it.This issue is not specific to SUDT. In this funding transaction construction path, the acceptor's secp script group already has an input before balancing, but the
lockfield of its witness entry is still empty when the fee is calculated. Other UDTs, including xUDT, are expected to be affected under the same conditions; the reproduction reported here uses SUDT.10001077bytes1077shannons1162bytes1162shannons85bytes85shannonsCode locations
build_base_from_funding_cell, lines 501–550witnessesto one entry. The first entry, used by the initiator's account, reserves signature space. The SDK later adds an empty entry for the acceptor, with no space reserved for its signature.build_and_balance_tx, lines 552–575has_providercheck and signature-data branchLocalSigner::sign_funding_tx中文版
接受方 script group 的 witness lock 字段为空,导致开通道交易因手续费不足被拒绝
问题概述
在 FNN
0.9.1中,双方共同出资的 SUDT 通道在默认费率下无法开通。FNN 构造的交易手续费为1077shannons,而 CKB 要求1162,因此拒绝了这笔交易。本次交易中,FNN 计算手续费时没有为通道接受方的账户锁预留 witness 空间。
测试环境
fnn Fiber v0.9.1 (9a561b3 2026-09-10)。0.208.0,本地开发链,tx_pool.min_fee_rate = 1000。未指定
funding_fee_rate,Fiber 使用DEFAULT_FEE_RATE=1000。通道发起方以5000SUDT(0x1388)发起,通道接受方以10000SUDT(0x2710)接受,双方各自使用自己的 secp 账户锁:{ "pubkey": "<acceptor_pubkey>", "funding_amount": "0x1388", "funding_udt_type_script": { "code_hash": "0x6283a479a3cf5d4276cd93594de9f1827ab9b55c7b05b3d28e4c2e0a696cfefd", "hash_type": "type", "args": "0x4472b33b4e1845ebe82f2ce5f511bbe012f144c5f3d7b539909adffc83ccda61" } }预期与实际结果
预期:通道能以默认费率正常开通。
实际:通道接受方接受后,CKB 拒绝了开通道交易,通道无法使用。节点日志:
同一场景改用
funding_fee_rate2000可以正常开通,此时手续费为2154shannons,交易大小仍然少算了。问题原因
双方使用不同的 secp 账户锁。估费时,通道接受方的 UDT 输入已经在交易中,且是它的首个输入、位于索引
2,而 Fiber 只为索引0预留了签名空间。手续费因此在接受方 witness 仍为空时就已定死,签名阶段写入后交易增加85字节,手续费不变。手续费在构造交易时由
CapacityBalancer算好,CKB actor 调用的LocalSigner::sign_funding_tx只签名,不重新计算。此问题并非 SUDT 特有。在这条开通道交易构造路径中,接受方的 secp script group 在平衡交易前已有输入,但计算手续费时,它对应的 witness 里
lock字段仍为空。在相同条件下,其他 UDT(包括 xUDT)预计也会受影响;本文实际复现使用的是 SUDT。1000应付的手续费1077字节1077shannons1162字节1162shannons85字节85shannons具体代码位置
build_base_from_funding_cell,501–550 行witnesses列表重置为只有一项。第一项用于发起方账户,预留了签名所需的空间。SDK 后续虽然补上了接受方对应的项,但其中是空值,没有预留签名空间。build_and_balance_tx,552–575 行has_provider判断及补充签名数据的分支LocalSigner::sign_funding_tx签名