You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用bitcoin-ruby广播原始比特币交易?(含报错排查)

解决比特币测试网交易广播的高手续费报错问题

嗨,我看到你用bitcoin-ruby gem在测试网广播交易时遇到了「手续费过高」的报错,这个问题其实很常见——核心原因是你没有添加找零输出,导致原UTXO的剩余金额全部被当成手续费,远远超出了节点允许的范围。下面我来一步步帮你修复:

问题根源拆解

比特币交易的规则是:所有输入的总金额 = 所有输出的总金额 + 手续费。你现在的代码只指定了一个目标输出,相当于把原交易输入的全部金额减去50000聪的部分都当成了手续费,这显然远远超过了正常手续费(测试网一般几千聪就够),所以节点直接拒绝了你的交易。

修复后的完整代码

我调整了代码逻辑,主要补全了UTXO金额获取、找零计算和交易广播的部分,你可以直接参考:

Bitcoin.network = :testnet

# 配置你的地址、私钥和目标地址
your_address = "muLGqMS6tkqb9sBQ4sqeXjMzaV8rk8o3gv"
your_private_key = Connect.get_private_key # 确保这个方法能正确返回你的私钥
dest_address = "msPHTrHSktDLMwPXcMYwWTqth3ZyykN17H"

# 1. 获取你的地址下未花费的UTXO(直接拿到可用金额,避免手动计算错误)
utxo_url = "https://testnet.blockexplorer.com/api/addr/#{your_address}/utxo"
uri = URI(utxo_url)
response = Net::HTTP.get(uri)
utxos = Connect.valid_json(response) ? JSON.parse(response) : []

# 取第一个可用的UTXO(如果有多个,你可以选金额合适的)
prev_utxo = utxos.first
prev_tx_hash = prev_utxo["txid"]
prev_output_index = prev_utxo["vout"]
prev_output_value = prev_utxo["amount"] * 100000000 # 转换为聪(1BTC = 1亿聪)

# 2. 获取前置交易的完整数据
raw_tx_url = "https://testnet.blockexplorer.com/api/rawtx/#{prev_tx_hash}"
uri = URI(raw_tx_url)
response = Net::HTTP.get(uri)
raw_prev_tx = Connect.valid_json(response) ? JSON.parse(response)["rawtx"] : ""
prev_tx = Bitcoin::P::Tx.new(raw_prev_tx.htb)

# 3. 创建新交易
tx = Bitcoin::Protocol::Tx.new
tx.add_in Bitcoin::Protocol::TxIn.new(prev_tx.binary_hash, prev_output_index, 0)

# 4. 设置输出和找零
send_amount = 50000 # 要转给目标地址的金额(0.0005 BTC)
min_fee = 1000 # 测试网最低手续费,可根据交易大小调整(一般1000-5000聪足够)
change_amount = prev_output_value - send_amount - min_fee # 计算找零金额,转回自己的地址

# 添加目标地址输出
tx.add_out Bitcoin::Protocol::TxOut.value_to_address(send_amount, dest_address)
# 添加找零输出(必须!否则剩余金额全变手续费)
tx.add_out Bitcoin::Protocol::TxOut.value_to_address(change_amount, your_address)

# 5. 签名交易输入
key = Bitcoin.open_key(your_private_key)
sig = Bitcoin.sign_data(key, tx.signature_hash_for_input(0, prev_tx))
tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [key.public_key_hex].pack("H*"))

# 6. 验证签名并广播交易
if tx.verify_input_signature(0, prev_tx)
  puts "✅ 签名验证通过,准备广播交易..."
  # 使用blockexplorer的API广播原始交易
  broadcast_url = "https://testnet.blockexplorer.com/api/tx/send"
  uri = URI(broadcast_url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json'})
  request.body = JSON.generate({rawtx: tx.to_payload.unpack("H*")[0]})
  broadcast_response = http.request(request)
  puts "📢 广播响应: #{broadcast_response.body}"
else
  puts "❌ 签名验证失败,请检查私钥和UTXO信息是否正确"
end

关键调整点说明

  • 正确获取UTXO金额:用/addr/{address}/utxo接口直接拿到未花费输出的准确金额,避免了原代码中从交易列表拿数据后无法获取对应输出金额的问题。
  • 强制添加找零输出:把扣除转账金额和手续费后的剩余金额转回自己的地址,确保手续费在合理范围内。
  • 明确手续费设置:测试网不用设置高额手续费,1000聪基本就能快速确认。
  • 完整的广播流程:直接在代码里实现了交易广播,不用手动复制hex去浏览器提交。

额外排查提示

如果运行后还是有问题,你可以检查这几点:

  • 你的UTXO是否已经被花费?如果之前测试过,这个UTXO可能已经被用掉了,换一个UTXO试试。
  • 私钥是否对应你的地址?签名错误会导致交易验证失败,节点也不会接收。
  • 手续费是否设置合理?如果交易数据较大(比如多个输入输出),可以适当提高手续费到5000聪左右。

内容的提问来源于stack exchange,提问作者Ayan Nurbolat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:54:39