|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 17, 2015, 06:17:43 PM |
|
How would I use Pycoin to play around with non-standard scripts like this? Alternatively, pybitcointools.
Writing a Script "compiler" in python should be very straight forward. PyBitcoinTools will parse out the scripts with deserialize, then you take the Script 'asm' and write a decompiler. If you then put the 'asm' data back in the dict and serialize with pybitcointools you should be good to go. I'll give it a shot next week.
|
|
|
|
HeadsOrTails (OP)
|
|
July 18, 2015, 06:41:04 AM |
|
How would I use Pycoin to play around with non-standard scripts like this? Alternatively, pybitcointools.
Writing a Script "compiler" in python should be very straight forward. PyBitcoinTools will parse out the scripts with deserialize, then you take the Script 'asm' and write a decompiler. If you then put the 'asm' data back in the dict and serialize with pybitcointools you should be good to go. Thanks for the reply! I'm really familiar with pybitcointools, so I can certainly see how your suggestion works. However, the issue is when using serialize_script; namely, if you've got objects (like a pubkey), the serialize_script method doesn't add push codes for the size of the object. Ie: my_script = serialize_script([OP_foo, OP_bar, "20byte_pubkey_hash", OP_spam])
myscript will return 11 22 01234567890123456789 33 instead of 11 22 14 01234567890123456789 33
|
|
|
|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 18, 2015, 06:53:46 AM Last edit: July 18, 2015, 10:09:13 AM by d4n13 |
|
I'm really familiar with pybitcointools, so I can certainly see how your suggestion works. However, the issue is when using serialize_script; namely, if you've got objects (like a pubkey), the serialize_script method doesn't add push codes for the size of the object. Ie: my_script = serialize_script([OP_foo, OP_bar, "20byte_pubkey_hash", OP_spam])
myscript will return 11 22 01234567890123456789 33 instead of 11 22 14 01234567890123456789 33LOL... I'm terribly unfamiliar with PyBitcoinTools, as my 'Wow there is a PyBitcoinTools module" post from today will likely attest. I never realized there was a serialize_ script method. I was simply thinking of the serialize(tx_dict). I was thinking you would right your own (or overwrite) the serialize_script method. I mean there are less than 100 op codes right?
|
|
|
|
HeadsOrTails (OP)
|
|
July 18, 2015, 08:49:12 AM |
|
I never realized there was a serialize_script method. I was simply thinking of the serialize(tx_dict). I was thinking you would right your own (or overwrite) the serialize_script method. I mean there are less than 100 op codes right?[/size] Yeah, that's certainly do-able. I'll fork the pybitcointools library and see how I go with it. I've been looking at Peter Todd's python-bitcoinlib and Richard Kiss' Pycoin, mainly because the classes are much more powerful for playing around with scripting, SIGHASH, etc. That being said, the OOP for python-bitcoinlib tries to emulate the Core software naming conventions, and it's really complicated. If anyone else can provide a single example of a non-standard script Tx using Pycoin/python-bitcoinlib, I'd really appreciate it. d4n13: Thanks for the input, I'll look at trying this with pybitcointools
|
|
|
|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 19, 2015, 06:28:34 AM |
|
Yep... there is a bug in there somewhere... Try the following from bitcoin import * serialize_script(deserialize_script('ac')) --- RuntimeError: maximum recursion depth exceeded while calling a Python object
|
|
|
|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 20, 2015, 07:13:30 AM |
|
I was simply thinking of the serialize(tx_dict). I was thinking you would right your own (or overwrite) the serialize_script method. I mean there are less than 100 op codes right?
It worked.... Transaction 5e4cf125218fcab2746303485ce3a2a74dc12271f678e851fc95fd97cd0153e4 puts "Hello World" on the blockchain Transaction 602c4d614351ee615ee1dc280c16a4cf962ccc928a8c3a0dca6f9ccd46104976 spends "Hello World" on the blockchain. Interestingly... the script debugger says OP_SIGCHECK failed... but it didn't. Also, the funky output script does an interesting job of making the coins quasi-anonomized.
|
|
|
|
HeadsOrTails (OP)
|
|
July 20, 2015, 09:09:31 AM |
|
Yep... there is a bug in there somewhere... Try the following from bitcoin import * serialize_script(deserialize_script('ac')) --- RuntimeError: maximum recursion depth exceeded while calling a Python object
Yeh, I often run scripts on iOS Pythonista, and there's a lot of recursion errors that come up since by default the recursion depth is 256; so setting sys.setrecursiondepth(512) often works in that environment. The pybitcointools bug is strange because the code serializes multisig scripts, but there's a bug with the CHECKMULTISIG; so instead of serializing the 'ae', it just appends 'ae' to the end of the returned string. I am looking at using this code: def mk_script(*args): # lst = ['76', 'a9', '14', 'dd6cce9f255a8cc17bda8ba0373df8e861cb866e', '88', 'ac'] if len(args) == 1 and isinstance(args[0], (list, tuple)) lst = list(args[0]) elif len(args) > 1 and all(map(lambda o: isinstance(o, str), args)): lst = [args] else: lst = [changebase(str(x), 10, 16, 2) if isinstance(x, (int, long)) else x for x in args] llens = [len(changebase(x, 16, 256, 1)) for x in lst] # byte lengths lint = map(lambda h: decode(h, 16), lst) # list as ints asm = 0xff for i in range(len(lint)): asm = asm << (8*llens[i]) | lint[i] asmhex = "0x" + encode(asm, 16, (sum(llens) + 1)*2) final = asmhex.partition('0xff')[-1] return final How would I go about tweaking this code to avoid the manual addition of push20? ie. I want to use mk_script(['76', 'a9', 'dd6cce9f255a8cc17bda8ba0373df8e861cb866e', '88', 'ac']) ... instead of mk_script(['76', 'a9', '14', 'dd6cce9f255a8cc17bda8ba0373df8e861cb866e', '88', 'ac']) (note the "14" preceding the pubkeyhash, which acts as push 20 bytes). I'd prefer to avoid using the push bytes
|
|
|
|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 20, 2015, 09:39:45 AM |
|
How would I go about tweaking this code to avoid the manual addition of push20? ie. I want to use mk_script(['76', 'a9', 'dd6cce9f255a8cc17bda8ba0373df8e861cb866e', '88', 'ac']) ... instead of mk_script(['76', 'a9', '14', 'dd6cce9f255a8cc17bda8ba0373df8e861cb866e', '88', 'ac']) (note the "14" preceding the pubkeyhash, which acts as push 20 bytes). I'd prefer to avoid using the push bytes Yeah, the bit about push20 is clean... no bug. The fact that you have a list item of 40 hex digits is proof that deserialize consumed a push20. If it consumed a push10 you would have a list item of 20 hex digits instead.. get it?
|
|
|
|
edmundedgar
|
|
July 20, 2015, 12:41:57 PM |
|
I don't know if this is related but something seems to have changed in the way pybitcointool serializes scripts since I was working with this around: https://github.com/vbuterin/pybitcointools/commit/87aaf6dc3f38d853dd8cb324a4eaf72ae309d322...which I think is still the version you get if you do pip install pybitcointool (This is before the name changed to "bitcoin".) I haven't had a chance to get to the bottom of this and it may be that the old version is broken and the new one is right, but you might like to try comparing what you get with the old version.
|
|
|
|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 20, 2015, 11:26:09 PM |
|
Yep... there is a bug in there somewhere... Try the following from bitcoin import * serialize_script(deserialize_script('ac')) --- RuntimeError: maximum recursion depth exceeded while calling a Python object
Submitted issue #104
|
|
|
|
HeadsOrTails (OP)
|
|
July 21, 2015, 03:06:08 AM |
|
Yep... there is a bug in there somewhere... Try the following from bitcoin import * serialize_script(deserialize_script('ac')) --- RuntimeError: maximum recursion depth exceeded while calling a Python object
Submitted issue #104 I fixed it
|
|
|
|
HeadsOrTails (OP)
|
|
July 21, 2015, 03:15:40 AM |
|
Maybe we can work on this Tx: http://test.webbtc.com/tx/2e7f518ce5ab61c1c959d25e396bc9d3d684d22ea86dc477b1a90329c6ca354fI've set up the script like this: OP_IF 0330ed33784ee1891122bc608b89da2da45194efaca68564051e5a7be9bee7f63f OP_CHECKSIGVERIFY OP_ELSE 80bf07 OP_NOP2 OP_DROP OP_ENDIF 042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9 OP_CHECKSIG So its a master key, which is sha256("master"*42) How would I use pybitcointools to spend this script? Nb script: myscript = "63210330ed33784ee1891122bc608b89da2da45194efaca68564051e5a7be9bee7f63fad670380bf07b1756841042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9ac"
|
|
|
|
d4n13
Full Member
Offline
Activity: 210
Merit: 104
“Create Your Decentralized Life”
|
|
July 21, 2015, 04:07:50 AM |
|
Maybe we can work on this Tx: http://test.webbtc.com/tx/2e7f518ce5ab61c1c959d25e396bc9d3d684d22ea86dc477b1a90329c6ca354fI've set up the script like this: OP_IF 0330ed33784ee1891122bc608b89da2da45194efaca68564051e5a7be9bee7f63f OP_CHECKSIGVERIFY OP_ELSE 80bf07 OP_NOP2 OP_DROP OP_ENDIF 042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9 OP_CHECKSIG So its a master key, which is sha256("master"*42) How would I use pybitcointools to spend this script? Nb script: myscript = "63210330ed33784ee1891122bc608b89da2da45194efaca68564051e5a7be9bee7f63fad670380bf07b1756841042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9ac"
I was working on a cleaner implementation... but got pulled away tonight... Basically you have to override You want to change line 341 of transaction.py so that it accepts an input script. You need to feed it the scriptPubKey of the UTXO you are spending. signing_tx = signature_form(tx, i, '<utxo_scriptPubKey>', hashcode) Then you need to sign the transaction with pubkey 042d...d17c, and copy the sig into "sig1", then sign the transaction with pubkey 0330...f63f, and copy the sig into "sig2". Finally your non-standard scriptSig is: I've done it on the "Hello World" example I did above, but the code is kinda ugly. Let me clean it up and I'll write a pybitcointools implementation to spend the coin.
|
|
|
|
HeadsOrTails (OP)
|
|
July 21, 2015, 04:15:28 AM |
|
Basically you have to override You want to change line 341 of transaction.py so that it accepts an input script. You need to feed it the scriptPubKey of the UTXO you are spending. signing_tx = signature_form(tx, i, '<utxo_scriptPubKey>', hashcode) Then you need to sign the transaction with pubkey 042d...d17c, and copy the sig into "sig1", then sign the transaction with pubkey 0330...f63f, and copy the sig into "sig2". Finally your non-standard scriptSig is: I've done it on the "Hello World" example I did above, but the code is kinda ugly. Let me clean it up and I'll write a pybitcointools implementation to spend the coin. Ah ha! OK, that makes perfect sense. I'll try it out. There's a fork of pybitcointools which is updated more often here. One of the issues I've encountered with pybitcointools is the DER encoding; the fork checks for DER encoding, whereas the original pybitcointools isn't even BER in some instances (eg if the r or s value has the leading bit set and is less than 2**255, the encoding doesn't prepend nullbytes)
|
|
|
|
|