diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 2bd8914716f..1881bb12f7e 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -972,7 +972,7 @@ static RPCHelpMan sendrawtransaction() // will always be blinded and not explicit. In the former case, we // error out because the transaction is not blinded properly. if (!out.nNonce.IsNull() && out.nValue.IsExplicit()) { - throw JSONRPCError(RPC_TRANSACTION_ERROR, "Transaction output has nonce, but is not blinded. Did you forget to call blindrawtranssaction, or rawblindrawtransaction?"); + throw JSONRPCError(RPC_TRANSACTION_ERROR, "Transaction output has nonce, but is not blinded. Did you forget to call blindrawtransaction, or rawblindrawtransaction?"); } } diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index dd0fc8fbd0f..d282c81b4fe 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -110,6 +110,7 @@ 'feature_progress.py', 'rpc_getnewblockhex.py', 'wallet_elements_regression_1172.py --legacy-wallet', + 'wallet_elements_regression_1259.py --legacy-wallet', # Longest test should go first, to favor running tests in parallel 'wallet_hd.py --legacy-wallet', 'wallet_hd.py --descriptors', diff --git a/test/functional/wallet_elements_regression_1259.py b/test/functional/wallet_elements_regression_1259.py new file mode 100755 index 00000000000..642062c579d --- /dev/null +++ b/test/functional/wallet_elements_regression_1259.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017-2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Tests that fundrawtransaction correcly handles the case of sending many +inputs of an issued asset, with no policy asset recipient. + +See: https://github.com/ElementsProject/elements/issues/1259 + +This test issues an asset and creates many utxos, which are then used as inputs in +a consolidation transaction created with the various raw transaction calls. +""" +from decimal import Decimal + +from test_framework.blocktools import COINBASE_MATURITY +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, +) + +class WalletTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 3 + self.extra_args = [[ + "-blindedaddresses=1", + "-initialfreecoins=2100000000000000", + "-con_blocksubsidy=0", + "-con_connect_genesis_outputs=1", + "-txindex=1", + ]] * self.num_nodes + self.extra_args[0].append("-anyonecanspendaremine=1") + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + self.generate(self.nodes[0], COINBASE_MATURITY + 1) + self.sync_all() + + self.log.info(f"Send some policy asset to node 1") + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) + self.generate(self.nodes[0], 1) + + self.log.info(f"Issuing an asset from node 0") + issuance = self.nodes[0].issueasset(1000, 1, True) + self.generate(self.nodes[0], 1) + asset = issuance["asset"] + self.log.info(f"Asset ID is {asset}") + + # create many outputs of the new asset on node 1 + num_utxos = 45 + value = 10 + fee_rate = 10 + self.log.info(f"Sending {num_utxos} utxos of asset to node 1") + for i in range(num_utxos): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), value, "", "", False, False, None, None, None, asset, False, fee_rate, True) + self.generate(self.nodes[0], 1) + + # create a raw tx on node 1 consolidating the asset utxos + self.log.info(f"Create the raw consolidation transaction") + hex = self.nodes[1].createrawtransaction([], [{ 'asset': asset, self.nodes[2].getnewaddress(): num_utxos * value }]) + + # fund the raw tx + self.log.info(f"Fund the raw transaction") + raw_tx = self.nodes[1].fundrawtransaction(hex, True) + + # blind and sign the tx + self.log.info(f"Blind and sign the raw transaction") + hex = self.nodes[1].blindrawtransaction(raw_tx['hex']) + signed_tx = self.nodes[1].signrawtransactionwithwallet(hex) + assert_equal(signed_tx['complete'], True) + + # decode tx + tx = self.nodes[1].decoderawtransaction(signed_tx['hex']) + + assert_equal(len(tx['vin']), num_utxos + 1) + assert_equal(len(tx['vout']), 3) + assert_equal(tx['fee'], {'b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23': Decimal('0.00112380')}) # fee output + + # send and mine the tx + self.log.info(f"Send the raw transaction") + self.nodes[1].sendrawtransaction(signed_tx['hex']) + self.generate(self.nodes[0], 1) + self.sync_all() + balance = self.nodes[2].getbalance() + assert_equal(balance[asset], Decimal(num_utxos * value)) + + +if __name__ == '__main__': + WalletTest().main()