PAYATHON 2026

使用 Blockchain.info API 付款时出现 Runtime Error

支付老李

结论

Blockchain.info Merchant API 要求 amount 和 fee 使用 satoshi(聪)整数,不能直接传入 BTC 小数。

对应关系如下:

  • 0.001 BTC 应传入 100000
  • 0.0001 BTC 应传入 10000

错误信息 For input string: ".001" 说明服务端在将小数字符串解析为整数时失败了。

修复方法

先把默认参数改为整数:

def SendPayment(
        self,
        toaddr='TA',
        amount=100000,
        fromaddr='FA',
        shared=0,
        fee=10000,
        note='test'):

    data = {
        'address': toaddr,
        'amount': amount,
        'fee': fee
    }

    if fromaddr:
        data['from'] = fromaddr

    if shared == 1:
        data['shared'] = 'true'

    if note:
        data['note'] = note

    return self.Call('payment', data)

调用时同样传入 satoshi:

wallet = Wallet(
    guid='YOUR_GUID',
    password1='YOUR_PASSWORD',
    password2='YOUR_SECOND_PASSWORD'
)

result = wallet.SendPayment(
    toaddr='DESTINATION_ADDRESS',
    amount=100000,  # 0.001 BTC
    fee=10000       # 0.0001 BTC
)

print(result)

换算关系是:

1 BTC = 100,000,000 satoshi

如果调用方提供的是 BTC 数量,可以用 Decimal 转换,以免受到浮点数精度影响:

from decimal import Decimal

def btc_to_satoshi(value):
    return int(Decimal(str(value)) * Decimal('100000000'))

例如:

amount = btc_to_satoshi('0.001')
fee = btc_to_satoshi('0.0001')

print(amount)  # 100000
print(fee)     # 10000

不建议直接用浮点数换算:

int(0.001 * 100000000)

二进制浮点数可能让某些金额产生意外结果。处理货币金额时,使用字符串和 Decimal 更稳妥。

修正批量发送代码

原来的 SendManyPayment 还有两个问题:

  1. 类中的方法应通过 self.SendPayment(...) 调用。
  2. 如果 txs 是字典,for tx in txs 遍历的是键,未必能正确取得地址和金额。

可以将 txs 明确定义为由 (地址, satoshi 金额) 组成的列表:

def SendManyPayment(
        self,
        txs=None,
        fromaddr='FA',
        shared=0,
        fee=10000,
        note='test'):

    if txs is None:
        txs = []

    responses = []

    for toaddr, amount in txs:
        response = self.SendPayment(
            toaddr=toaddr,
            amount=amount,
            fromaddr=fromaddr,
            shared=shared,
            fee=fee,
            note=note
        )
        responses.append(response)

    return responses

调用示例:

transactions = [
    ('ADDRESS_1', 100000),  # 0.001 BTC
    ('ADDRESS_2', 250000),  # 0.0025 BTC
    ('ADDRESS_3', 50000)    # 0.0005 BTC
]

results = wallet.SendManyPayment(
    txs=transactions,
    fromaddr='SOURCE_ADDRESS',
    fee=10000
)

for result in results:
    print(result)

这段代码会依次调用多次 payment API,每次调用都会生成一笔独立付款,并不是一笔包含多个输出的 Bitcoin transaction。

注意事项

  • amount 和 fee 必须是 satoshi 整数,不能传入 '0.001'、.001 或 0.001。
  • 不要用 {} 作为函数的默认参数。可变默认值会在多次调用之间共享,应改用 None。
  • SendPayment 最好返回 API 响应,否则调用方无法获取交易哈希、余额或错误信息。
  • 批量发送时,应记录每笔请求的成功或失败状态。如果中途失败,之前已经成功广播的交易不会自动撤销。
  • 连续发送多笔付款可能重复支付矿工费,也可能遇到未确认输出、余额变化或 API 限速。
  • 示例中的 Blockchain.info Merchant API 和第三方 pyblockchain 库属于较早期接口。如果服务端接口已有调整,应以实际部署环境对应的 API 文档为准。
  • 不要把钱包密码、第二密码或私钥写入代码仓库、日志或异常信息。生产环境应从受保护的配置或密钥管理服务中读取这些信息。

备注:内容仅供参考。