UnableToSignTxError

I managed to add a test certificate to bitcoin regtest by following the instructions in the cert-issuer README.md. However when I attempt to do the same process on the bitcoin testnet, I get the following error when attempting to issue with cert-issuer -c /etc/cert-issuer/conf.ini.

WARNING - Your app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
INFO - This run will try to issue on the bitcoin_testnet chain
/usr/lib/python3.6/site-packages/merkletools/__init__.py:7: UserWarning: sha3 is not working!
  warn("sha3 is not working!")
INFO - Set cost constants to recommended_tx_fee=0.000600,min_per_output=0.000028,satoshi_per_byte=250
INFO - Processing 1 certificates
INFO - Processing 1 certificates under work path=/etc/cert-issuer/work
INFO - Total cost will be 133500 satoshis
INFO - Starting finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
INFO - Stopping finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
INFO - here is the op_return_code data: f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf
INFO - Unsigned hextx=010000000125339d6f0e4a7105fb791c357ef69ed31f2af2ca23d5ab4cc07c04974ed355060000000000ffffffff0214553f02000000001600141475e3352a7878db0a59d97035f7347101fab9ca0000000000000000226a20f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf00000000
INFO - Preparing tx for signing
INFO - Starting finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
ERROR - Unable to sign transaction. hextx=0100000000010125339d6f0e4a7105fb791c357ef69ed31f2af2ca23d5ab4cc07c04974ed355060000000000ffffffff0214553f02000000001600141475e3352a7878db0a59d97035f7347101fab9ca0000000000000000226a20f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf02483045022100fd0504893469dd887a299555b299fbd04b315abbb38852afefff479bb39dd25602203663ed7ff5ba6babc64ca8ade2ff8b49b1c97e3b99de8a3ddbcfd86ccec807fb012102af62cd1cf9e85153f6129aacf319d0637d8b4cac7580b96666f07294bd78d4d200000000
INFO - Stopping finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
Traceback (most recent call last):
  File "/usr/bin/cert-issuer", line 33, in <module>
    sys.exit(load_entry_point('cert-issuer==2.0.27', 'console_scripts', 'cert-issuer')())
  File "/usr/lib/python3.6/site-packages/cert_issuer/__main__.py", line 17, in cert_issuer_main
    issue_certificates.main(parsed_config)
  File "/usr/lib/python3.6/site-packages/cert_issuer/issue_certificates.py", line 36, in main
    return issue(app_config, certificate_batch_handler, transaction_handler)
  File "/usr/lib/python3.6/site-packages/cert_issuer/issue_certificates.py", line 22, in issue
    tx_id = issuer.issue(app_config.chain)
  File "/usr/lib/python3.6/site-packages/cert_issuer/issuer.py", line 27, in issue
    txid = self.transaction_handler.issue_transaction(blockchain_bytes)
  File "/usr/lib/python3.6/site-packages/cert_issuer/blockchain_handlers/bitcoin/transaction_handlers.py", line 56, in issue_transaction
    signed_tx = self.sign_transaction(prepared_tx)
  File "/usr/lib/python3.6/site-packages/cert_issuer/blockchain_handlers/bitcoin/transaction_handlers.py", line 92, in sign_transaction
    signed_tx = signer.sign_transaction(prepared_tx)
  File "/usr/lib/python3.6/site-packages/cert_issuer/models.py", line 84, in sign_transaction
    return self.signer.sign_transaction(self.wif, transaction_to_sign)
  File "/usr/lib/python3.6/site-packages/cert_issuer/blockchain_handlers/bitcoin/signer.py", line 35, in sign_transaction
    raise UnableToSignTxError('Unable to sign transaction')
cert_issuer.errors.UnableToSignTxError: Unable to sign transaction

This is my conf.ini file:

issuing_address=tb1qz367xdf20pudkzjem9crtae5wyql4ww2lvgtuh

chain=bitcoin_testnet
no_bitcoind

usb_name=/etc/cert-issuer/
key_file=pk_issuer.txt

unsigned_certificates_dir=/etc/cert-issuer/data/unsigned_certificates
blockchain_certificates_dir=/etc/cert-issuer/data/blockchain_certificates
work_dir=/etc/cert-issuer/work

no_safe_mode

Any help solving this would be much appreciated.

I still haven’t had any look fixing this issue. I have managed to remove the UserWarning: sha3 is not working! warn("sha3 is not working!") by manually installing pysha3>=1.0.2. I think this line of the docker file was meant to address this, but didn’t:
&& sed -i.bak s/==1\.0b1/\>=1\.0\.2/g /usr/lib/python3.*/site-packages/merkletools-1.0.2-py3.*.egg-info/requires.txt

This is the error I get now:

WARNING - Your app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
INFO - This run will try to issue on the bitcoin_testnet chain
INFO - Set cost constants to recommended_tx_fee=0.000600,min_per_output=0.000028,satoshi_per_byte=250
INFO - Processing 1 certificates
INFO - Processing 1 certificates under work path=/etc/cert-issuer/work
INFO - Total cost will be 133500 satoshis
INFO - Starting finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
INFO - Stopping finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
INFO - here is the op_return_code data: f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf
INFO - Unsigned hextx=010000000125339d6f0e4a7105fb791c357ef69ed31f2af2ca23d5ab4cc07c04974ed355060000000000ffffffff0214553f02000000001600141475e3352a7878db0a59d97035f7347101fab9ca0000000000000000226a20f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf00000000
INFO - Preparing tx for signing
INFO - Starting finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
ERROR - Unable to sign transaction. hextx=0100000000010125339d6f0e4a7105fb791c357ef69ed31f2af2ca23d5ab4cc07c04974ed355060000000000ffffffff0214553f02000000001600141475e3352a7878db0a59d97035f7347101fab9ca0000000000000000226a20f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf02483045022100fd0504893469dd887a299555b299fbd04b315abbb38852afefff479bb39dd25602203663ed7ff5ba6babc64ca8ade2ff8b49b1c97e3b99de8a3ddbcfd86ccec807fb012102af62cd1cf9e85153f6129aacf319d0637d8b4cac7580b96666f07294bd78d4d200000000
INFO - Stopping finalizable signer
WARNING - app is configured to skip the wifi check when the USB is plugged in. Read the documentation to ensure this is what you want, since this is less secure
Traceback (most recent call last):
  File "/usr/bin/cert-issuer", line 33, in <module>
    sys.exit(load_entry_point('cert-issuer==2.0.27', 'console_scripts', 'cert-issuer')())
  File "/usr/lib/python3.6/site-packages/cert_issuer/__main__.py", line 17, in cert_issuer_main
    issue_certificates.main(parsed_config)
  File "/usr/lib/python3.6/site-packages/cert_issuer/issue_certificates.py", line 36, in main
    return issue(app_config, certificate_batch_handler, transaction_handler)
  File "/usr/lib/python3.6/site-packages/cert_issuer/issue_certificates.py", line 22, in issue
    tx_id = issuer.issue(app_config.chain)
  File "/usr/lib/python3.6/site-packages/cert_issuer/issuer.py", line 27, in issue
    txid = self.transaction_handler.issue_transaction(blockchain_bytes)
  File "/usr/lib/python3.6/site-packages/cert_issuer/blockchain_handlers/bitcoin/transaction_handlers.py", line 56, in issue_transaction
    signed_tx = self.sign_transaction(prepared_tx)
  File "/usr/lib/python3.6/site-packages/cert_issuer/blockchain_handlers/bitcoin/transaction_handlers.py", line 92, in sign_transaction
    signed_tx = signer.sign_transaction(prepared_tx)
  File "/usr/lib/python3.6/site-packages/cert_issuer/models.py", line 84, in sign_transaction
    return self.signer.sign_transaction(self.wif, transaction_to_sign)
  File "/usr/lib/python3.6/site-packages/cert_issuer/blockchain_handlers/bitcoin/signer.py", line 35, in sign_transaction
    raise UnableToSignTxError('Unable to sign transaction')
cert_issuer.errors.UnableToSignTxError: Unable to sign transaction```

Sorry,

it’s hard to debug from here. Moreover I have little experience with this side of the project so it’s my first encounter of the error.

You will need to add some prints of the various objects (more specifically transaction_to_sign) along it’s life path and test when you have something that works (mocknet) and something that does not work (testnet) and identify what could be going wrong. Looking at the code without being able to see the data makes it hard for me to help you more than that.

I injected some code into signer.py to get some prints of the objects you mentioned

Here is the output for the bitcoin_testnet:

transaction_to_sign: Tx [796a612c6e658c7bbe17a1d1dc0d2ee7dce231a3b57adbde734b2eb6a59c4c23]

signed_transaction: Tx [796a612c6e658c7bbe17a1d1dc0d2ee7dce231a3b57adbde734b2eb6a59c4c23]

[for input in signed_transaction.txs_in: print(input.script)]: 
b''

And this is the output for bitcoin_regtest (Which was successful):

transaction_to_sign: Tx [e7adf96918ca97148a9caf65930f1be861ff903204a98ca3b2e3d46192725c92]

signed_transaction: Tx [e7adf96918ca97148a9caf65930f1be861ff903204a98ca3b2e3d46192725c92]

[for input in signed_transaction.txs_in: print(input.script)]: 
b'H0E\x02!\x00\xf0h\xd2\xb4\x10\x84\xa8\x17aG\xd6\xb4\xa1i\xf3\x9f\xff\x958@$\xa6\xff\xd3\xa0\x03cT?$\xb3\xef\x02 O\xe2T\x9d\xc2\xfc\xf7\xd1\x06\xfb\x9eg\x0ca\x96s\xef\x996\x8f\xf4*\xb7\xf4\x0b\x9c5\x18\x9aZL\x8f\x01!\x03\xa1\xca\x99\xbb\xad"\x1c\xb0b\xdf\xa3\xfc(L&\xe6\x06\x06\x18!\xa1\xb1G\x8f`\x8fn\xc3>j\xc2\x98'

It’s safe to say I understand this output less than you do @lemoustachiste, As I only started attempting to use Blockcerts very recently. Any additional insight would be really helpful.

Both times I was following this tutorial to the letter (GitHub - blockchain-certificates/cert-issuer: Issues Blockcerts using either the Bitcoin or Ethereum blockchain). The only difference with the bitcoin_testnet attempt was that I ignored the “Create issuing address” step and manually input my testnet address and private key.

This appears to be caused by using a SegWit address and corresponding UTXO. Cert-issuer does not have SegWit support at this time. We did some work on it in the past, but it hasn’t made it into the product.

My recommendation is to do something like:

  1. Make a note of your current address and its private key. You’ll need these later.
  2. Generate a new testnet address that is specifically not a Bech32 address. You’ll know you got it right when it no longer has that ‘tb’ prefix (List of address prefixes - Bitcoin Wiki). If you’re using an online generator, there might be a checkbox - make sure that Bech32 support is FALSE.
  3. Using your private key from the first step, transfer some or all of your available tBTC to the new address. Given the limitation in cert-issuer, I kind of suspect that you might have to do this twice - once from the old address to the new address, and again from the new address, back to the new address.
  4. In your cert-issuer installation, replace the private key and issuing address with your new ones.

That ought to get you unstuck.


Here’s what happened. First, looking at your unsigned transaction:

0100000000010125339d6f0e4a7105fb791c357ef69ed31f2af2ca23d5ab4cc07c04974ed355060000000000ffffffff0214553f02000000001600141475e3352a7878db0a59d97035f7347101fab9ca0000000000000000226a20f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf02483045022100fd0504893469dd887a299555b299fbd04b315abbb38852afefff479bb39dd25602203663ed7ff5ba6babc64ca8ade2ff8b49b1c97e3b99de8a3ddbcfd86ccec807fb012102af62cd1cf9e85153f6129aacf319d0637d8b4cac7580b96666f07294bd78d4d200000000

We can copy that and paste it directly into https://live.blockcypher.com/btc/decodetx/ to decode it into a JSON payload that looks like so:

{
    "addresses": [
        "tb1qz367xdf20pudkzjem9crtae5wyql4ww2lvgtuh"
    ],
    "block_height": -1,
    "block_index": -1,
    "confirmations": 0,
    "data_protocol": "unknown",
    "double_spend": false,
    "fees": 60000,
    "hash": "0a23156bbac11ac067a091f2946b9e7117bc0a011d7ae56457e3931b732f30d1",
    "inputs": [
        {
            "addresses": [
                "tb1qz367xdf20pudkzjem9crtae5wyql4ww2lvgtuh"
            ],
            "age": 1973094,
            "output_index": 0,
            "output_value": 37764980,
            "prev_hash": "0655d34e97047cc04cabd523caf22a1fd39ef67e351c79fb05714a0e6f9d3325",
            "script_type": "pay-to-witness-pubkey-hash",
            "sequence": 4294967295,
            "witness": [
                "3045022100fd0504893469dd887a299555b299fbd04b315abbb38852afefff479bb39dd25602203663ed7ff5ba6babc64ca8ade2ff8b49b1c97e3b99de8a3ddbcfd86ccec807fb01",
                "02af62cd1cf9e85153f6129aacf319d0637d8b4cac7580b96666f07294bd78d4d2"
            ]
        }
    ],
    "outputs": [
        {
            "addresses": [
                "tb1qz367xdf20pudkzjem9crtae5wyql4ww2lvgtuh"
            ],
            "script": "00141475e3352a7878db0a59d97035f7347101fab9ca",
            "script_type": "pay-to-witness-pubkey-hash",
            "value": 37704980
        },
        {
            "addresses": null,
            "data_hex": "f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf",
            "script": "6a20f734ef686132b9c12bc284e720e9212466344c2e7b8218974b7186200a08aebf",
            "script_type": "null-data",
            "value": 0
        }
    ],
    "preference": "high",
    "received": "2021-05-12T22:15:39.227071955Z",
    "relayed_by": "3.86.251.213",
    "size": 235,
    "total": 37704980,
    "ver": 1,
    "vin_sz": 1,
    "vout_sz": 2,
    "vsize": 153
}

There are two things worth noting in the decoded transaction. First, the previous transaction, 0655d34e97047cc04cabd523caf22a1fd39ef67e351c79fb05714a0e6f9d3325, is your sole UTXO. Comparing it to the output, you’ll see that your input lacks the “script” field. Instead, it contains a script_type of pay-to-witness-pubkey-hash, and a witness array.

Second is that script_type of the output is also pay-to-witness-pubkey-hash, which should not be the case. Instead, it should be pay-to-pubkey-hash. I suspect that this is a bug, and even if cert-issuer managed to sign and broadcast the transaction in that state, the BTC (testnet or mainnet) network might reject it as invalid.

As far as the code is concerned, here’s the failing block of code, from cert-issuer/signer.py at master · blockchain-certificates/cert-issuer (github.com):

def sign_transaction(self, wif, transaction_to_sign):
    secret_exponent = wif_to_secret_exponent(wif, self.allowable_wif_prefixes)
    lookup = build_hash160_lookup([secret_exponent])
    signed_transaction = transaction_to_sign.sign(lookup)
    # Because signing failures silently continue, first check that the inputs are signed
    for input in signed_transaction.txs_in:
        if len(input.script) == 0:
            logging.error('Unable to sign transaction. hextx=%s', signed_transaction.as_hex())
            raise UnableToSignTxError('Unable to sign transaction')
    return signed_transaction

By this point in the code, your raw, unsigned transaction is already created. The input transaction(s), fetched from the network, are in an array called signed_transaction.txs_in. For each input transaction, the code does a simple check: is there a script (with length not equal to zero)? If so, great. If not, then the pre-SegWit code assumes that the input transaction is unsigned, and therefore, not valid.

This check assumes that a valid transaction must include a script field of non-zero length, and it does so without checking the script_type. Different script types might (and do) have different schematic conventions. SegWit transactions will fail here, which is why, as I mentioned above, I suspect you might have to do a second transaction from your new address, back to your new address: so that your latest transaction is guaranteed not to be SegWit.

Good luck :slight_smile:

1 Like

Thanks for the help @lparker

I followed your steps, and made a new non-Bech32 address:
2N56j7ijhQ7hiBcjqY94KUMk5hXztFyQmX7
I sent my testnet coins to it, and then had it send those coins to itself.

Here is the new unsigned transaction:
010000000103617fac1258805552d987a98b379df7aae5ea24e98d77b238cf76fd4de8373e0000000000ffffffff021f543f020000000017a914820614ac94a468387fb72a06cba2d1e39afae9ff870000000000000000226a20ff74acf692f45de8e011d8803e6791d7add727a5de54117d133f906df609188d00000000

{
    "addresses": [
        "2N56j7ijhQ7hiBcjqY94KUMk5hXztFyQmX7"
    ],
    "block_height": -1,
    "block_index": -1,
    "confirmations": 0,
    "data_protocol": "unknown",
    "double_spend": false,
    "fees": 60000,
    "hash": "ab40c0ae5b1e49b5eb17206edc7d99d6f1aa43a4386ce87458a0f24ee9dfc2e2",
    "inputs": [
        {
            "addresses": [
                "2N56j7ijhQ7hiBcjqY94KUMk5hXztFyQmX7"
            ],
            "age": 1975222,
            "output_index": 0,
            "output_value": 37764735,
            "prev_hash": "3e37e84dfd76cf38b2778de924eae5aaf79d378ba987d95255805812ac7f6103",
            "script_type": "pay-to-script-hash",
            "sequence": 4294967295
        }
    ],
    "outputs": [
        {
            "addresses": [
                "2N56j7ijhQ7hiBcjqY94KUMk5hXztFyQmX7"
            ],
            "script": "a914820614ac94a468387fb72a06cba2d1e39afae9ff87",
            "script_type": "pay-to-script-hash",
            "value": 37704735
        },
        {
            "addresses": null,
            "data_hex": "ff74acf692f45de8e011d8803e6791d7add727a5de54117d133f906df609188d",
            "script": "6a20ff74acf692f45de8e011d8803e6791d7add727a5de54117d133f906df609188d",
            "script_type": "null-data",
            "value": 0
        }
    ],
    "preference": "high",
    "received": "2021-05-13T12:43:47.962971956Z",
    "relayed_by": "54.224.13.97",
    "size": 126,
    "total": 37704735,
    "ver": 1,
    "vin_sz": 1,
    "vout_sz": 2,
    "vsize": 126
}

The script_type is now pay-to-script-hash instead of pay-to-witness-pubkey-hash, which isn’t pay-to-pubkey-hash like you mentioned, and there is still no “script” field.

If it’s relevant, I’m generating these addresses with bitcoin core running in testnet mode.

1 Like

The issue has been resolved.

I was using the graphical interface for Bitcoin Core, and unchecking the “Generate native segwit (Bech32) address” box tells it to use p2sh-segwit. I had to use the bitcoin-cli to generate a legacy address. It works fine now.

Thanks for the help @lparker