【bitcoinjs-lib】签名错误提示:Error: No inputs were signed

基于【bitcoinjs-lib】的转出钱包地址【是否隔离见证,生成方式】都会决定是否签名成功!

import bitcoin from "bitcoinjs-lib";
 
/**
 * 实战环境温馨提示:
 *      1、基于【bitcoinjs-lib】转账交易封装比较复杂,更适合了解Bitcoin交易的原理【自己封装可能存在各种小Bug】
 *      2、基于【bitcore-lib】转账交易是bitpay官方封装,简单易用,更适合生产环境!
 */
 
export default class BitcoinJS extend BitcoinBase {
 
    async sendBitcoinNetworkTransactionCommon(token_type, utxo_inputs, to, fee_satoshis, to_btc_satoshis_amount, amount, total_btc_satoshis_balance) {
        /**
         * 功能:重写父类方法【基于原生的bitcoinjs-lib的转账方法】
         * 基于【bitcoinjs-lib】对比【bitcore-lib】:都是基于离线签名【绝对安全】都是基于【MIT】发布的证书
         *      a、基于【bitcoinjs-lib】
         *          1、封装比较复杂,基于各种Address的特性,input需要携带不一样的参数!
         *          2、转账Omni-USDT未完成确认之前,转账全部BTC余额是无法广播成功【只能转账非参与USDT的BTC部分】
         *      b、基于【bitcore-lib】一切问题都是自动解决了,因为bitpay官方内部已做好一切封装,直接调用即可!
         */
        const psbt = new bitcoin.Psbt({ network: this.originalBitcoinNetworkNode });
        for (const _utxo_input of utxo_inputs) {
            /**
             * 1、基于【bitcoinjs-lib】的执行转出的wallet地址,必须根据地址的特性配置一些特殊参数!
             * 2、请参考官方案例:https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts
             */
            psbt.addInput({
                hash: _utxo_input.txId,
                index: _utxo_input.outputIndex,
                ...await this.__getAddressInputNonOrWitnessUtxoObject(_utxo_input),
                ...this.__getAddressRedeemOrWitnessScriptObject(),
            });
        }
        if (token_type === "usdt") {
            /**
             * 1、这里的【_transaction.addData(string)会自动生成【OP_RETURN】格式的数据【等价于new bitcore.Script.buildDataOut(string)】
             * 2、参考官方文档:https://github.com/bitpay/bitcore-lib/blob/master/docs/examples.md#create-an-op-return-transaction
             */
            psbt.addOutput({
                script: Buffer.from(this.generateOmniUSDTOutputOpReturnScript(amount)), value: 0,
            });
        }
        psbt.addOutput({
            address: to, value: to_btc_satoshis_amount,
        });
        let _remainingBTCBalanceSatoshis = total_btc_satoshis_balance - to_btc_satoshis_amount - fee_satoshis;
        if (_remainingBTCBalanceSatoshis > 0) {
            /**
             * 1、【非常重要】每次交易当前Wallet剩余的余额必须再次转给自己【change找零地址】否则剩余余额部分会全部自动变成手续费fee消耗了【直接挂逼!!!】
             * 2、比特币交易原理:
             *      a、取出全部可用【UtxoInput】余额,然后一次性分配给【toAddress金额】+【剩余的数量转入找零change地址】+【fee手续费】
             *      b、change找零地址,通常为当前转出钱包地址
             *      c、【务必注意】如果【未提供change找零地址】则全部可用【UtxoInput】余额自动分配给【toAddress金额】+【剩余的数量全部自动当fee手续费消耗了】
             */
            psbt.addOutput({
                address: this.walletAddress, value: _remainingBTCBalanceSatoshis,
            });
        }
        // 签名全部inputs
        psbt.signAllInputs(this.keyPair);
        // 序列化全部inputs
        psbt.finalizeAllInputs();
        return this.broadcastTx(psbt.extractTransaction().toHex(), token_type, to, to_btc_satoshis_amount, amount);
    }
 
    async __getAddressInputNonOrWitnessUtxoObject(utxo_input) {
        /**
         * 功能:获取是否隔离见证地址的utxo特殊参数对象
         * 特殊说明:
         *      1、基于是否隔离见证地址,input传入的Utxo参数不一样!
         *      2、如果未提供对应的nonWitnessUtxo或witnessUtxo参数,签名会抛异常【Error: No inputs were signed】
         */
        if (this.addressType === "prefix_1") {
            /**
             * 1、转出Address如为非隔离见证【1开头地址】则必填参数nonWitnessUtxo【非隔离见证输入现在需要将整个前一个tx作为缓冲区传递】
             */
            return this.__getAddressNonWitnessUtxoObj(utxo_input);
        }
        return {
            /**
             * 1、转出Address如为隔离见证【bc1或3开头地址】则必填参数witnessUtxo【只需要Utxo的scriptPubkey和value】
             */
            witnessUtxo: {
                script: Buffer.from(utxo_input.script, "hex"), value: utxo_input.satoshis,
            },
        };
    }
 
    async __getAddressNonWitnessUtxoObj(utxo_input) {
        /**
         * 功能:获取已完成的utxo_input【等价于上一个previous】交易的tx_hex的Buffer对象【non-segwit inputs now require passing the whole previous tx as Buffer】
         * 特殊说明:
         *      1、注:每一个utxo_input相比【当前即将执行的转账交易来说】都是【previous】
         */
        return {
            nonWitnessUtxo: Buffer.from(
                (await this.getTx(utxo_input.txId)).tx_hex, "hex"),
        };
    }
 
    __getAddressRedeemOrWitnessScriptObject() {
        /**
         * 功能:获取address匹配的redeemScript或witnessScript对象!
         */
        let _addressObj = this.getWalletAddress(true);
        /**
         * 1、address基于P2SH方式生成,则必须redeemScript
         * 2、address基于P2WSH方式生成,则必须witnessScript
         * 3、address基于其他方式生成,则以上2个参数都不需要!
         */
        if (_addressObj.redeem) {
            return {
                redeemScript: _addressObj.redeem.output,
            };
        }
        if (_addressObj.witness) {
            return {
                witnessScript: _addressObj.witness.output,
            };
        }
        return {};
    }
}

参考:

【重磅推荐】基于【bitcoinjs-lib】对比【bitcore-lib】两个库开发Bitcoin-Wallet的实战总结_比特币爱好者007的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果出现`AttributeError: module 'gradio.inputs' has no attribute 'Files'`错误,可能是因为您使用的Gradio版本较旧,不支持`gradio.inputs.Files`组件。 `gradio.inputs.Files`组件是在Gradio 2.0版本中引入的,如果您使用的是旧版本的Gradio,请使用`gradio.inputs.File`组件来上传单个文件,然后在回调函数中将其复制到指定文件夹中。 具体步骤如下: 1. 导入`os`和`shutil`: ```python import os import shutil ``` 2. 定义一个函数,用于保存上传的文件: ```python def save_file(file, folder): # 如果指定的文件夹不存在,则创建它 if not os.path.exists(folder): os.makedirs(folder) # 保存文件到指定的文件夹中 file_path = os.path.join(folder, file.name) with open(file_path, "wb") as f: shutil.copyfileobj(file, f) ``` 3. 在`gradio.Interface`中使用`gradio.inputs.File`组件,并在回调函数中调用上述函数: ```python import gradio as gr def upload_file(file): save_file(file, "path/to/folder") inputs = gr.inputs.File(label="Upload File") outputs = None gr.Interface(upload_file, inputs, outputs).launch() ``` 注意,`save_file`函数中的`folder`参数是指定的文件夹路径,需要根据实际情况进行修改。 这样,用户上传的文件就会被保存到指定的文件夹中。 ### 回答2: 这个错误是由于`gradio.inputs`模块中没有`Files`属性引起的。`gradio.inputs`模块是一个用于定义Gradio应用程序输入的模块,而`Files`是该模块中的一个属性,用于处理上传的文件输入。但是根据错误提示,这个属性似乎不存在。 要解决这个问题,可以尝试以下几个步骤: 1. 确认Gradio的版本。如果你使用的是一个过时的Gradio版本,或者根本没有包括`Files`属性,那么你需要升级Gradio或找到一个支持`Files`属性的版本。 2. 检查你的代码是否正确导入了`gradio.inputs`模块。确保你在代码中正确导入了`gradio.inputs`模块,并且没有使用错误的别名或缩写。 3. 查看`gradio.inputs`模块的文档或示例代码。查阅Gradio的官方文档或示例代码,确认是否有关于`Files`属性的详细说明和使用方法。 4. 向Gradio的开发者社区寻求帮助。如果以上步骤都没有解决问题,那么你可以向Gradio的开发者社区寻求帮助。他们可能会给你提供更具体的解决方案或反馈相关的bug信息。 总之,要解决`AttributeError: module 'gradio.inputs' has no attribute 'Files'`错误,您需要确认Gradio的版本、正确导入模块并查阅相关文档,并向开发者寻求帮助。 ### 回答3: AttributeError: module 'gradio.inputs' has no attribute 'Files' 错误表示在使用gradio库时,尝试访问了gradio.inputs.Files的属性,但该属性不存在。 gradio是一个用于构建Web界面的Python库,可以用于快速创建交互式的机器学习模型演示、原型等。在gradio中,inputs模块用于定义输入组件,例如文本输入框、图像上传等。 然而,gradio.inputs模块中并没有名为Files的属性或类。因此,当我们尝试访问gradio.inputs.Files时,会出现AttributeError错误。 可能的原因是版本问题或代码错误。要解决此问题,可以采取以下步骤: 1. 确保你已经正确安装了gradio库,可以尝试升级到最新版本。 ``` pip install gradio --upgrade ``` 2. 检查代码中是否存在拼写错误或其他语法错误。特别是要确认是否正确导入了gradio.inputs模块。正确的导入语句应该是: ``` import gradio.inputs as gi ``` 3. 检查gradio文档,查看是否有可用的输入组件可以满足你的需求。你可以尝试使用其他输入组件进行替代。 总之,AttributeError: module 'gradio.inputs' has no attribute 'Files'错误表示你尝试访问的属性或类并不存在。需要确保安装了正确的版本,并检查代码中的拼写或语法错误。如有必要,可以参考gradio文档以获取更多帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值