Author

Topic: Custom P2SH redeem script - any wallet software that can handle it? (Read 536 times)

copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
Found another interesting example. I call it "the nothing P2SH address". Because the script is NOTHING (code below).

Here is how to calculate the address (Python command line):

Code:
>>> import hashlib, base58, binascii
>>> script = ''
>>> base58.b58encode_check(binascii.unhexlify('05'+ hashlib.new('ripemd160', hashlib.sha256(binascii.unhexlify(script)).digest()).hexdigest())).decode()
'3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy'

What's fascinating is its high activity, relatively large transactions and very recent use:

https://www.blockchain.com/btc/address/3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy

To spend from it, simply

Code:
OP_1 OP_0

will do as the unlocking script, judging from looking at the blockchain (example transaction: 6f033ffb5eb1be1527f7d03b6dfe195ced3575965ac619d6c2ca67e37ca5d0d9).

And it's a pity no one can control it automatically from Bitcoin Core or Electrum, or any standard wallet software, in my humble opinion.



sr. member
Activity: 310
Merit: 727
---------> 1231006505

These addresses have been funded as an experiment on October first 2014:
Code:
OP_1 -> 33bpsD9CRTsPpx7dW4GtLbZUX7QwFrBvW2
OP_2 -> 3BLfZAdt1syots4kATFfo8sXDk6WZS2YfN
OP_3 -> 31vFvEkyAb2iusbPip36H9rVt6pxExuaVR
OP_4 -> 3CkUmt6tpyj5VhCweGBZpN8bhYnPmSnpD7
OP_5 -> 361xwdrcq4LT7B2zdeJjguycY6S6tqWYZv
OP_6 -> 32f3brEpVCo6y5CnFqpiHDqgsM4LRxT4dX
OP_7 -> 3Mp1a3vgpQST2wA5q9mxTEdeEqNCgUbChF
OP_8 -> 33bpsD9CRTsPpx7dW4GtLbZUX7QwFrBvW2
OP_9 -> 3AHCsW1qsWcNPDwbBKLgtZu9AdRj4YeK7V
In case you wonder why OP_2 to OP_9 work as well since they are not equal to 1 (TRUE) as the final value on stack after all commands are evaluated, well that's because the top element of the stock should be a non-zero value to resolve as valid.

But anyway, the article is from 2020 and presented like it's a new thing while this was done already six years ago.
legendary
Activity: 3472
Merit: 10611
Looks like these guys solved a puzzle transaction using methods from this post - it is referenced!
I would not say that it was a "puzzle" as such, in that it wasn't publicly listed as a challenge or anything like that... it seems they were just experimenting with P2SH scripts and discovered someone had been sending dust to the address generated from the "1=1" script address...

It might have been useful for readers if they had actually shown the step by step guide to how they constructed the transaction, rather than "here is the finished transaction, feel free to decode it yourself" Undecided

Still, it's nice to see theory being used in practice Wink

that whole website is shady. they have been making this type of articles 2 other times before too with the titles such as "hack bitcoin". i believe that it was mainly created to get traffic from those searching for this type of nonsense that seems to becoming popular again these days.
HCP
legendary
Activity: 2086
Merit: 4361
Looks like these guys solved a puzzle transaction using methods from this post - it is referenced!
I would not say that it was a "puzzle" as such, in that it wasn't publicly listed as a challenge or anything like that... it seems they were just experimenting with P2SH scripts and discovered someone had been sending dust to the address generated from the "1=1" script address...

It might have been useful for readers if they had actually shown the step by step guide to how they constructed the transaction, rather than "here is the finished transaction, feel free to decode it yourself" Undecided

Still, it's nice to see theory being used in practice Wink
newbie
Activity: 3
Merit: 1
Looks like these guys solved a puzzle transaction using methods from this post - it is referenced! They too had to do it manually and could use Bitcoin Core to construct the transaction. I'm gonna look at their raw transaction and try to figure out how they did it. Cool topic.

https://btcleak.com/2020/07/19/we-solved-a-p2sh-transaction-puzzle-and-redeemed-bitcoin/

staff
Activity: 3458
Merit: 6793
Just writing some code
I'm not really sure what you mean. Yes, Bitcoin scripts can be infinitely complex, but hashes are only hashes (the "H" in P2SH), there are only so many opcodes, and the "only" thing your code needs to make sure is that when everything is combined and executed, the end result is "TRUE" (i.e. a single 01 in the stack top element, and no other stack elements). Pretty trivial.

These two pages accomplish just this, fast and easy relying only on relatively easy-to-understand javascript:

https://bitcoin-script-debugger.visvirial.com/
https://bip32jp.github.io/english/createp2sh.html

I have coded my own quick and dirty Python script that creates valid raw transactions from self-made sigscript and redeemscript (as in the OP), the output can indeed be broadcast with Bitcoin Core without a problem. In other words, they must be considered standard (if we by standard mean "doesn't get caught in Bitcoin Core's 'isStandad' function"), and they propagate normally through the network (i.e. the other standard nodes have problems with them) and are confirmed, mined and included in blocks, as expected.

I still find it fascinating that no wallet software does this natively, as I think this is the most simple form of a Bitcoin transaction - they don't even have signatures! Take Peter Todd's (in)famous SHA1 transaction puzzle for example; the solution could not have been created in Bitcoin Core, but very well broadcast with it.

What's I'm gonna do next to automate the process further is to make an Electrum plugin. Which will yield the end-result I was looking for all along. A simple GUI-solution.

I do think it's a little sad I can't do it in Bitcoin Core (without forking it, which at this point is not desirable).
What I meant was having Bitcoin Core automatically create the scriptSig for you for an arbitrary script is not feasible. As in it isn't possible to have sendtoaddress automatically construct, sign,  and send the transaction if it has arbitrary scripts because Core doesn't know how to make the scriptSigs for those arbitrary scripts.

Those sites are for you to create the scriptSig manually, which I guess is what you are asking: to be able  to provide the scriptSig manually.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
I find it a little funny you can easily create a transaction here, and then later broadcast it in Bitcoin Core without a problem at all, but not create it within the client. These transactions thus pass "isStandard",
The node IsStandard check is a little looser than the wallet's check for standard scripts. It isn't looking for standard script templates because it doesn't need to.

but you have to rely on third-party tools (web services or simply Notepad++ - it's not THAT difficult) to assemble them.
But how do you have a piece of software know how to make the scriptSig/scriptWitness? You have to hard code it, or make something that's smart enough to figure it out own its own. Hardcoding means that the developers have to think of literally every possible script and write scenarios for them. That's basically impossible because there is basically an infinite number of possible scripts. And something smart enough to cover all scripts is also not really possible. Miniscript is something that does the "smart enough to figure it out own its own" but within a very limited subset of script that can be reasoned about.


I'm not really sure what you mean. Yes, Bitcoin scripts can be infinitely complex, but hashes are only hashes (the "H" in P2SH), there are only so many opcodes, and the "only" thing your code needs to make sure is that when everything is combined and executed, the end result is "TRUE" (i.e. a single 01 in the stack top element, and no other stack elements). Pretty trivial.

These two pages accomplish just this, fast and easy relying only on relatively easy-to-understand javascript:

https://bitcoin-script-debugger.visvirial.com/
https://bip32jp.github.io/english/createp2sh.html

I have coded my own quick and dirty Python script that creates valid raw transactions from self-made sigscript and redeemscript (as in the OP), the output can indeed be broadcast with Bitcoin Core without a problem. In other words, they must be considered standard (if we by standard mean "doesn't get caught in Bitcoin Core's 'isStandad' function"), and they propagate normally through the network (i.e. the other standard nodes have problems with them) and are confirmed, mined and included in blocks, as expected.

I still find it fascinating that no wallet software does this natively, as I think this is the most simple form of a Bitcoin transaction - they don't even have signatures! Take Peter Todd's (in)famous SHA1 transaction puzzle for example; the solution could not have been created in Bitcoin Core, but very well broadcast with it.

What's I'm gonna do next to automate the process further is to make an Electrum plugin. Which will yield the end-result I was looking for all along. A simple GUI-solution.

I do think it's a little sad I can't do it in Bitcoin Core (without forking it, which at this point is not desirable).
staff
Activity: 3458
Merit: 6793
Just writing some code
I find it a little funny you can easily create a transaction here, and then later broadcast it in Bitcoin Core without a problem at all, but not create it within the client. These transactions thus pass "isStandard",
The node IsStandard check is a little looser than the wallet's check for standard scripts. It isn't looking for standard script templates because it doesn't need to.

but you have to rely on third-party tools (web services or simply Notepad++ - it's not THAT difficult) to assemble them.
But how do you have a piece of software know how to make the scriptSig/scriptWitness? You have to hard code it, or make something that's smart enough to figure it out own its own. Hardcoding means that the developers have to think of literally every possible script and write scenarios for them. That's basically impossible because there is basically an infinite number of possible scripts. And something smart enough to cover all scripts is also not really possible. Miniscript is something that does the "smart enough to figure it out own its own" but within a very limited subset of script that can be reasoned about.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
If it really is the case that importmulti for P2SH with scriptPubKey and redeemscript can only produce watchonly-addresses in Bitcoin Core, I don't understand why the function exists in the first place since the public address alone is, of course, enough for watchonly.
importmulti can be used to import private keys and import scripts for which you already have the private keys for (e.g. adding a multisig to the wallet where you have one of the keys).

importmulti is also useful for adding scripts and keys to your wallet so that you can use PSBT with those things.

Gotcha. Thanks for taking the time to explain.

I find it a little funny you can easily create a transaction here, and then later broadcast it in Bitcoin Core without a problem at all, but not create it within the client. These transactions thus pass "isStandard", but you have to rely on third-party tools (web services or simply Notepad++ - it's not THAT difficult) to assemble them.

staff
Activity: 3458
Merit: 6793
Just writing some code
If it really is the case that importmulti for P2SH with scriptPubKey and redeemscript can only produce watchonly-addresses in Bitcoin Core, I don't understand why the function exists in the first place since the public address alone is, of course, enough for watchonly.
importmulti can be used to import private keys and import scripts for which you already have the private keys for (e.g. adding a multisig to the wallet where you have one of the keys).

importmulti is also useful for adding scripts and keys to your wallet so that you can use PSBT with those things.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
Code:
src/bitcoin-cli -regtest importmulti '[{"watchonly":true,"timestamp":"now","redeemscript":"522102c3e42b212b6d9481869af2afda4861ebe3299b29c714d19b2fbd47564a40be102102d6b1958d3de900d3da6d0465437c331d8fa2645fa1d353d7fe3d9a84f7de30fc2103f0012c00c703d1ee5e1314dd6f07263ae65ba0fe40694071982c72c5eaf1521a53ae","scriptPubKey":"a9145acce455c2046881eb1c3c82f42d9ff128b1fe9187"}]'
src/bitcoin-cli -regtest importmulti '[{"watchonly":true,"timestamp":"now","redeemscript":"522102c3e42b212b6d9481869af2afda4861ebe3299b29c714d19b2fbd47564a40be102102d6b1958d3de900d3da6d0465437c331d8fa2645fa1d353d7fe3d9a84f7de30fc2103f0012c00c703d1ee5e1314dd6f07263ae65ba0fe40694071982c72c5eaf1521a53ae","scriptPubKey":{"address":"2N1XLFgxmv2KRNycNe2zKSEKSj3RgV4Z8df"}}]'
Both import the same  thing. The second one just uses the notation to give an address instead of a raw scriptPubKey.

Thanks!

If it really is the case that importmulti for P2SH with scriptPubKey and redeemscript can only produce watchonly-addresses in Bitcoin Core, I don't understand why the function exists in the first place since the public address alone is, of course, enough for watchonly.

Edit:

I tried your first example. It works. But so does this, without redeemscript, with the identical outcome:

Code:
importmulti '[{"watchonly":true,"timestamp":"now","scriptPubKey":"a9145acce455c2046881eb1c3c82f42d9ff128b1fe9187"}]'

So..... why can you insert a value that doesn't add any functionality, I don't get it.
staff
Activity: 3458
Merit: 6793
Just writing some code
Code:
src/bitcoin-cli -regtest importmulti '[{"watchonly":true,"timestamp":"now","redeemscript":"522102c3e42b212b6d9481869af2afda4861ebe3299b29c714d19b2fbd47564a40be102102d6b1958d3de900d3da6d0465437c331d8fa2645fa1d353d7fe3d9a84f7de30fc2103f0012c00c703d1ee5e1314dd6f07263ae65ba0fe40694071982c72c5eaf1521a53ae","scriptPubKey":"a9145acce455c2046881eb1c3c82f42d9ff128b1fe9187"}]'
src/bitcoin-cli -regtest importmulti '[{"watchonly":true,"timestamp":"now","redeemscript":"522102c3e42b212b6d9481869af2afda4861ebe3299b29c714d19b2fbd47564a40be102102d6b1958d3de900d3da6d0465437c331d8fa2645fa1d353d7fe3d9a84f7de30fc2103f0012c00c703d1ee5e1314dd6f07263ae65ba0fe40694071982c72c5eaf1521a53ae","scriptPubKey":{"address":"2N1XLFgxmv2KRNycNe2zKSEKSj3RgV4Z8df"}}]'
Both import the same  thing. The second one just uses the notation to give an address instead of a raw scriptPubKey.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
Feels like a stupid JSON formatting thing; please help!
It isn't.

Bitcoin Core only accepts a fix set of standard script formats. Your redeemScript is not one of those, so it gives a warning about it. Note that this is just a warning and the script and address are still added to your wallet. However because Bitcoin Core does not recognize the type of script, it is unable to produce a valid input for that script. It can only produce inputs for the standard scripts.


Very interesting, thanks. Could you please give me an example with a what would be considered a standard P2SH address and its redeem script and a JSON-string that will be accepted by importmulti in Bitcoin Core? The manual explicitly says it can be done, but I haven't found one single working example; I find it strange that there is a documented function but zero (at least that I am able to find) published examples.
staff
Activity: 3458
Merit: 6793
Just writing some code
Feels like a stupid JSON formatting thing; please help!
It isn't.

Bitcoin Core only accepts a fix set of standard script formats. Your redeemScript is not one of those, so it gives a warning about it. Note that this is just a warning and the script and address are still added to your wallet. However because Bitcoin Core does not recognize the type of script, it is unable to produce a valid input for that script. It can only produce inputs for the standard scripts.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
Result (written as part of a raw transaction): a82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887
You can import this to Bitcoin core using:
Code:
importaddress "a82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887" "label" false true
Where the last "true" indicates that the first value is a P2SH script.
It will produce the same address: 33CGouuJW2G66mDaQ13pMBDuztW9eLKiKw.

But it wont let you spend from it through the GUI though  Tongue

I can replicate and confirm this, thank you.

importaddress is for watch-only addresses though, according to the specs:
https://bitcoincore.org/en/doc/0.20.0/rpc/wallet/importaddress/

However,

importmulti specifically says you can have redeem scripts instead of private keys

https://bitcoincore.org/en/doc/0.20.0/rpc/wallet/importmulti/

But I don't understand how to get it to work...

Edit: there may be some leads here https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa - have to dig deeper into how to properly format JSON-strings with redeemscript - try it you too!
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
Damn, this is frustrating! The manual for Bitcoin Core says you can do it (import sigscript together with redeem script):

https://bitcoincore.org/en/doc/0.20.0/rpc/wallet/importmulti/

But the closest I get is this command (run in the console):

Code:
importmulti '[{"scriptPubKey":"17a91410809d572ef90f7ea6c2c0c9017a5cc5314606ba87","redeemscript":"0123456789abcdef","internal":true,"timestamp":"now"}]' '{ "rescan": false}'

which adds 33CGouuJW2G66mDaQ13pMBDuztW9eLKiKw as a watch-only address; specifically it responds with


Code:
[
  {
    "success": true,
    "warnings": [
      "Importing as non-solvable: unrecognized script. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript."
    ]
  }
]

We have to crack this!

Edit: It doesn't matter what I write in the redeemscript string, it won't accept any of it. It does complain if one character is not hexadecimal, so at least we know the program is reading it, but... then nope. Feels like a stupid JSON formatting thing; please help!
legendary
Activity: 2534
Merit: 6080
Self-proclaimed Genius
Result (written as part of a raw transaction): a82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887
You can import this to Bitcoin core using:
Code:
importaddress "a82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887" "label" false true
Where the last "true" indicates that the first value is a P2SH script.
It will produce the same address: 33CGouuJW2G66mDaQ13pMBDuztW9eLKiKw.

But it wont let you spend from it through the GUI though  Tongue
legendary
Activity: 3472
Merit: 10611
no wallet has this type of options and i don't think any of them would add it since there is no reason for a user to create this type of non-standard scripts. not to mention the risks that these bring up which will affect the user experience.
this is why the process is hard and you have to do it manually and "other tools", it is meant to be used by someone who understands how things work and accepts the risks on their own.
HCP
legendary
Activity: 2086
Merit: 4361
Have you looked at Coinb.in? Huh

It's raw transaction creation tool will accept a redeem script (also address or WIF Key)... However, I've not tested it with "custom" redeem scripts like your example, but it is worth testing out to see if it is able to handle it.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
It is very easy to create valid, custom scriptSig/scriptPubkey-combinations, calculate a P2SH address, send coins to it, and semi-manually spend from it. One example:

scriptSig
Code:
#Push 8 byte secret hexadecimal string "0123456789abcdef"
8 0x0123456789abcdef
Result (written as part of a raw transaction): 080123456789abcdef

scriptPubkey
Code:
#SHA-256 of the input, push SHA-256 hash of string in scriptSig, verify that the are equal, which will return "TRUE", i.e. a valid script
OP_SHA256
32 0x55c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be9818
OP_EQUAL
Result (written as part of a raw transaction): a82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887

The redeem script is simply combining the two, i.e. (here padded with a lenght byte "2c" in front to make it valid):
Code:
2c080123456789abcdefa82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887

Calculating the P2SH address can easily be done in Python like so:
Code:
>>> import hashlib, base58, binascii
>>> base58.b58encode_check(binascii.unhexlify('05'+ hashlib.new('ripemd160', hashlib.sha256(binascii.unhexlify(b'a82055c53f5d490297900cefa825d0c8e8e9532ee8a118abe7d8570762cd38be981887')).digest()).hexdigest())).decode()
'33CGouuJW2G66mDaQ13pMBDuztW9eLKiKw'

So, we have a public P2SH address 33CGouuJW2G66mDaQ13pMBDuztW9eLKiKw, and all you need to spend from it is the redeem script.

You can use this online service to spend from it:

https://bitcoin-script-debugger.visvirial.com/

This works almost OK in my experience (specifically this tends to insert an annoying OP_PUSHDATA1 that you may have to delete [and fix length size byte], before you can push the unsigned transaction via a web service directly or in your wallet); broadcast('xxx') in Electrum works like a charm for me in these cases.

In other words, I can get all of the above to work well, but it is semi-manual work.

And yes, this example should not be used IRL, since the first time you spend from it, the scriptSig will be exposed on the blockchain; an since there are no real signatures involved, anyone can spend from the address using the same scriptSig again and again.

My question:
Is there any wallet software (not a web service!) that can take a scriptSig and a scriptPubkey (or just "import redeem script"), calculate and treat your custom P2SH address as a "normal" address and give you "normal" control over it? Without involving private keys, for which there are none in examples like this.


As already mentioned, I can already do all of it manually, but... software wallets, hello?
Jump to: