1

Can someone explain this JS code to me please?

Maybe line by line? I am trying to understand and learn from it. Is this code creating a raw transaction based on an existing redeemScript? Or is it actually creating a redeemScript and then a transaction based on it?

I am on Windows server 2016 with Bitcoin Core and node installed.

Particulary this line I don't get it.

var scriptSig = bitcore.Script.fromASM('04678afd04678a ' + redeemScript.toHex())

What is 04678afd04678a?:

He is the entire code, found it on some JS examples from 2 years ago. It's about creating unsecured P2SH transactions.

> var bitcore = require('bitcore');                                              
undefined                                                                        
> var redeemScript = bitcore.Script.fromASM('OP_SHA256 894eeb82f9a851f5d1cb1be324
9f58bc8d259963832c5e7474a76f7a859ee95c OP_EQUAL');                               
undefined                                                                        
> var scriptPubKey = redeemScript.toScriptHashOut();                             
undefined                                                                        
> scriptPubKey                                                                   
<Script: OP_HASH160 20 0x028d07ac41994c915b76e00490289f5933454f90 OP_EQUAL>      
> scriptPubKey.toAddress()                                                       
<Address: 31vWDrvuRXaEaymhyuZqkbNBkPrVzw6DBc, type: scripthash, network: livenet>
> scriptPubKey.toHex()                                                           
'a914028d07ac41994c915b76e00490289f5933454f9087'                                 
> var utxo = new bitcore.Transaction.UnspentOutput({                             
...   "txId" : "a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9"
, //fake, don't try!                                                             
...   "outputIndex" : 0,                                                         
...   "script" : "a914028d07ac41994c915b76e00490289f5933454f9087",               
...   "satoshis" : 60000,                                                        
...   "address" : "31vWDrvuRXaEaymhyuZqkbNBkPrVzw6DBc"                           
... });                                                          
> var address = '13mDYExLFx7stcYJN5uJRhzxwLuTEKNJbg';                            
undefined                                                                        
> var tx = new bitcore.Transaction().from(utxo).to(address, 50000);              
undefined                                                                        
> tx.inputs[0]                                                                   
{ output: <Output (60000 sats) <Script: OP_HASH160 20 0x028d07ac41994c915b76e0049
0289f5933454f90 OP_EQUAL>>,                                                      
  prevTxId: <Buffer a0 a0 8e 39 72 03 df 68 39 2e e9 5b 3f 08 b0 b3 b3 e2 40 14 1
0 a3 8d 46 ae 08 74 f7 48 46 f2 e9>,                                             
  outputIndex: 0,                                                                
  sequenceNumber: 4294967295,                                                    
  _script: <Script: >,
                   _scriptBuffer: <Buffer > }                                                     
> tx.outputs                                                                     
[ <Output (50000 sats) <Script: OP_DUP OP_HASH160 20 0x1e4d054693c02c60e3f77f87f5
ba79a281bf9141 OP_EQUALVERIFY OP_CHECKSIG>> ]                                    
> var scriptSig = bitcore.Script.fromASM('04678afd04678a ' + redeemScript.toHex()
)                                                                                
undefined                                                                        
> tx.inputs[0].setScript(scriptSig);                                             
{ output: <Output (60000 sats) <Script: OP_HASH160 20 0x028d07ac41994c915b76e0049
0289f5933454f90 OP_EQUAL>>,                                                      
  prevTxId: <Buffer a0 a0 8e 39 72 03 df 68 39 2e e9 5b 3f 08 b0 b3 b3 e2 40 14 1
0 a3 8d 46 ae 08 74 f7 48 46 f2 e9>,                                             
  outputIndex: 0,                                                                
  sequenceNumber: 4294967295,                                                    
  _script: <Script: 7 0x04678afd04678a 35 0xa820894eeb82f9a851f5d1cb1be3249f58bc8
d259963832c5e7474a76f7a859ee95c87>,
             _scriptBuffer: <Buffer 07 04 67 8a fd 04 67 8a 23 a8 20 89 4e eb 82 f9 a8 51 f5
 d1 cb 1b e3 24 9f 58 bc 8d 25 99 63 83 2c 5e 74 74 a7 6f 7a 85 9e e9 5c 87> }   
> var rawTx = tx.toString('hex');                                                
undefined                                                                        
> rawTx                                                                          
'0100000001e9f24648f77408ae468da3101440e2b3b3b0083f5be92e3968df0372398ea0a0000000
002c0704678afd04678a23a820894eeb82f9a851f5d1cb1be3249f58bc8d259963832c5e7474a76f7
a859ee95c87ffffffff0150c30000000000001976a9141e4d054693c02c60e3f77f87f5ba79a281bf
914188ac00000000'                                                                
>                                                                             
1

I am not a JS dev, but can read and understand the code. So this is a summary from what I can see in the tx. I try to concentrate on the important lines, and compare the script to the information in the wiki:

> var redeemScript = bitcore.Script.fromASM('OP_SHA256 894eeb82f9a851f5d1cb1be324
9f58bc8d259963832c5e7474a76f7a859ee95c OP_EQUAL');

this looks like the preparation for a P2SH tx. To be noted: it starts with OP_SHA256 (0xA8), whereas "normal" p2sh scripts start with OP_HASH160 (0xA9) - see next section "scriptPubKey". Looking at the way the script execution works, the SHA256 operator would try to perform a sha256 operation on the previous item on the stack... as a sha256 is not easily reversible, we cannot know, what string is converted to some hash, that can then be evaluated to TRUE, so the transaction remains valid... For sure it is the string that you were asking to explain (04678afd04678a).

> scriptPubKey 
<Script: OP_HASH160 20 0x028d07ac41994c915b76e00490289f5933454f90 OP_EQUAL>

this is a standard script, which compares a previous item on the stack to the hash160 (0x028d07ac...). This is usually used in a P2SH, to compare a public key to its hash.

> var tx = new bitcore.Transaction().from(utxo).to(address, 50000);

prepare a data structure for the transaction with the target address and amount

> tx.inputs[0]

add the inputs (with the script)

> tx.outputs

create the outputs

> var scriptSig = bitcore.Script.fromASM('04678afd04678a ' + redeemScript.toHex()

the most interesting line! I follow up on it below, but first decode the tx:

VERSION 01000000
 TX_IN COUNT hex=01, decimal=1
  TX_IN[0] OutPoint hash A0A08E397203DF68392EE95B3F08B0B3B3E2401410A38D46AE0874F74846F2E9
  TX_IN[0] OutPoint index hex=00000000, reversed=00000000, decimal=0
  TX_IN[0] Script Length hex=2C, decimal=44
  TX_IN[0] Script Sig 0704678AFD04678A23A82...C8D259963832C5E7474A76F7A859EE95C87
  TX_IN[0] Sequence FFFFFFFF
 TX_OUT COUNT, hex=01, decimal=1
  TX_OUT[0] Value hex=50C3000000000000, reversed_hex=C350, dec=50000 Satoshi
  TX_OUT[0] PK_Script Length hex=19, dec=25
  TX_OUT[0] pk_script 76A9141E4D054693C02C60E3F77F87F5BA79A281BF914188AC
LOCK_TIME 00000000

so now analyzing the created script sig:

0704678AFD04678A23A820894EEB82F9A851F5D1CB1BE3249F58BC8D259963832C5E7474A76F7A859EE95C87

first we have "07", which pushes "next opcode bytes" (hex 07) on the stack. So the stack gets

04678AFD04678A

then follows a string beginning with 0x23. This means the next 35 Bytes go to the stack, so the rest of the script. The stack would look like this:

04678AFD04678A
OP_SHA256 20894EEB82F9A851F5D1CB1BE3249F58BC8D259963832C5E7474A76F7A859EE95C OP_EQUAL

So the string

04678afd04678a

hashes to 32 bytes (hex 0x20) of:

894EEB82F9A851F5D1CB1BE3249F58BC8D259963832C5E7474A76F7A859EE95C

When this is executed on the stack, it is equal, and as such the tx is valid. I have no windows system, but on unixoide systems one can verify at the command line, or with openssl:

printf $( echo 04678AFD04678A | sed 's/[[:xdigit:]]\{2\}/\\x&/g' ) > tmp_hex_fn
hexdump -C tmp_hex_fn
openssl dgst -sha256 <tmp_hex_fn

ATTENTION: using such a script on mainnet will probably loose the funds. A miner can change the tx, and put "his" script into the sigscript section, and divert the funds to his own addresses. Only use such unsecured tx on testnet.

  • Thank you! So to be clear please, two quick questions related. 1. On this line > var scriptSig = bitcore.Script.fromASM('04678afd04678a ' + redeemScript.toHex() the 046xxx is just a string (can be any string) which is currently hashed so it becomes equal to 894eeb82f9a851f5d1xxxxx or is the other way around where this 894eexxxxxxxxxx is the hash and the04678axx is the redeemScript? 2. What do you mean by "a miner can change the script"? Once the tx gets mined the redeemScript is revealed so it becomes vulnerable? I imagined that once the script is hashed that's irreversible. – RobertH Jun 21 '18 at 21:54
  • 1.) '04678afd04678a' is just a string, that get's sha256'd. 2.) The miner can change the script before (!) it goes into a block. The redeemscript is not part of the signature, so it can be changed, without invalidating the tx. To understand the concept of scripts and their execution, I recommend Andreas' book "Mastering Bitcoin", chapter 6 (Transactions, page 132ff). It is freely available online... I provided in a similar response for spending unsecured tx with funding and spending tx in detail here: bitcoin.stackexchange.com/questions/74753 (in the answer section). – pebwindkraft Jun 22 '18 at 7:50
  • Great explanation! Thanks for your explanation and response. Really helpful. – RobertH Jun 22 '18 at 9:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.