The Bitcoin programming language¶
From input to output¶
Tx cc3b743938e485578315b2f6848c1a416c917585ea2f75d5d3e09f21a95008b0 output 0
“asm:” “OP_DUP OP_HASH160 df75ee5b514b5253979ed29524fde386482f05cf OP_EQUALVERIFY OP_CHECKSIG”,
“hex:” “76a914df75ee5b514b5253979ed29524fde386482f05cf88ac”,
i.e.
hex: 76 a9 14 df75ee5b514b5253979ed29524fde386482f05cf 88 ac
The assembler¶
where we see (from https://en.bitcoin.it/wiki/Script ) the meaning of the sequence
OP_DUP OP_HASH160 OP_EQUALVERY OP_CHECKSIG OP_EQUAL OP_VERIFY
in the table in the handout.
Handout¶
code |
dec |
hex |
Input |
Output |
Description |
|---|---|---|---|---|---|
OP_DUP |
118 |
0x76 |
Duplicates the
top stack item.
|
||
OP_HASH160 |
169 |
0xa9 |
in |
hash |
The input is hashed twice:
first with SHA-256 and then
with RIPEMD-160.
|
OP_EQUALVERIFY |
136 |
0x88 |
x1 x2 |
Nothing/fail |
Same as OP_EQUAL, but
runs OP_VERIFY afterward.
|
OP_CHECKSIG |
172 |
0xac |
sig pubkey |
True / false |
The entire transaction
outputs, inputs, and script
(from the most recently-executed
OP_CODESEPARATOR to the end)
are hashed. The signature used
by OP_CHECKSIG must be a valid
signature for this hash and
public key. If it is, 1 is
returned, 0 otherwise.
|
OP_EQUAL |
135 |
0x87 |
x1 x2 |
True/false |
Returns 1 if the inputs are
exactly equal, 0 otherwise.
|
OP_VERIFY |
105 |
0x69 |
True /
false
|
Nothing/
/ fail
|
Marks transaction as invalid
if top stack value is not true.
The top stack value is removed.
|
20 |
0x14 |
push 20 bytes onto the stack
the following 160 bit hash
|
Simple example¶
2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
Example
——-
Consider how the following code would be executed
2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
2 |
2 goes on stack |
||
7 |
2 |
2 on stack; 7 goes on stack |
|
7 |
2 |
7 and 2 on stack |
|
OP_ADD |
7 |
2 |
+ operator adds from stack |
9 |
sum gets put on stack |
||
3 |
9 |
3 goes on stack |
|
3 |
9 |
3 and 9 on stack |
|
OP_SUB |
3 |
9 |
- operator |
6 |
difference is put on stack |
||
1 |
6 |
1 goes on stack |
|
1 |
6 |
1 and 6 on stack |
|
OP_ADD |
1 |
6 |
+ operator adds from stack |
7 |
sum gets put on stack |
||
7 |
7 |
new 7 to be put on stack |
|
7 |
7 |
||
OP_EQUAL |
7 |
7 |
= operator compares |
TRUE |
result is TRUE |
spending¶
Then the value gets used in
Tx e870614afe3cb9fde97566b024a72f11d22ce08dbd89a971655b15f71d6e203b
(see handout)Handout¶
with
asm:
30450221009411566e0a7965fc5b8a73ca788a52c4fc0d4f6eaf3089812e55 \
e7def520c79502205d7db54c0851d650d80e9236ecfbe9a94ea0b17976255f \
2170259b652524d0b301
hex:
4830450221009411566e0a7965fc5b8a73ca788a52c4fc0d4f6eaf3089812e55 \
e7def520c79502205d7db54c0851d650d80e9236ecfbe9a94ea0b17976255f \
2170259b652524d0b3012102df1da8c39a9823016dbe56d11b11b1369b4567 \
4115cbbd9a2a531e365a532bc7``
A more detailed look inside the spending transaction¶
Looking at SMLY transactions
dee018b9be101c519ad326c581807581a4e46711f242b4878afa1d98c5f521e1
and
08a5430a667a700e7b913d1895908c56d035559cd32a999a5c8cd56f409f4d15
The former’s vout:0 gets spent in the latter. Example ——-
Consider SMLY transactions
dee018b9be101c519ad326c581807581a4e46711f242b4878afa1d98c5f521e1
and
08a5430a667a700e7b913d1895908c56d035559cd32a999a5c8cd56f409f4d15
The former’s vout:0 gets spent in the latter.
The output of dee0...
"vout": [
{
"value": 61,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 52a7c9d832b31c044faa63782ef252e7a4a34291 \
OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a91452a7c9d832b31c044faa63782ef252e7a4a3429188ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"BBz82bHDLKC3CGMHhJtNPbwTAYFGrRT1o6"
]
}
},
and the spending part in 08a5…
"vin": [
{
"txid": "dee018b9be101c519ad326c581807581a4e46711f242b4878afa1d98c5f521e1",
"vout": 0,
"scriptSig": {
"asm": "3044022050587d300d060b912526164f24b1e24897ed9822b1d23fce9a7c103e1c6b3d2102202b42a536a82582 \
ac26495c3a3f5c34add4c1aa2fecede1c50ce5f22fd06739920102188c91a675464d2dc475d4f0 \
1bc8cd60fe418d99142ed1ce5f8ce45a997080d5",
"hex": "473044022050587d300d060b912526164f24b1e24897ed9822b1d23fce9a7c103e1c6b3d2102202b42a536a82 \
582ac26495c3a3f5c34add4c1aa2fecede1c50ce5f22fd0673992012102188c91a675464d2dc475d4f0 \
1bc8cd60fe418d99142ed1ce5f8ce45a997080d5"
},
"sequence": 4294967295
}
],
We want to understand the entire process.
First, to spend the UTXO you need to be the owner of the addres, so verify that:
validateaddress BBz82bHDLKC3CGMHhJtNPbwTAYFGrRT1o6
{
"isvalid" : true,
"address" : "BBz82bHDLKC3CGMHhJtNPbwTAYFGrRT1o6",
"ismine" : true,
"isscript" : false,
"pubkey" : "02188c91a675464d2dc475d4f01bc8cd60fe418d99142ed1ce5f8ce45a997080d5",
"iscompressed" : true
}
Note how the validateaddress command also shows the public key and this is the second part in the “asm” string in the spending transaction. You can also verify that this address does indeed correspond to this public key: https://en.bitcoin.it/wiki/Base58Check_encoding#Creating_a_Base58Check_string
Next, validate the public key to hash transformation, ripemd160(sha256(publickey)) using python:
>>> import hashlib
>>> publickey = '02188c91a675464d2dc475d4f01bc8cd60fe418d99142ed1ce5f8ce45a997080d5' \
.decode('hex')
>>> s = hashlib.new('sha256', publickey).digest()
>>> r = hashlib.new('ripemd160', s ).digest()
>>> s.encode('hex')
'7c8edaf5fe99c4729e8903271fb5f0f34fdf3e461c4db1890b298b3807964505'
>>> r.encode('hex')
'52a7c9d832b31c044faa63782ef252e7a4a34291'
>>>
or in R, not so subtle:
> public<-"02188c91a675464d2dc475d4f01bc8cd60fe418d99142ed1ce5f8ce45a997080d5"
> as.character(ripemd160(sha256(as.raw(strtoi(sapply(seq(1, nchar(public), by=2), \
function(x) substr(public, x, x+1)), 16L)))))
[1] "52a7c9d832b31c044faa63782ef252e7a4a34291"
The final action is to validate the signature, which was the first part of the “asm” string in the spending transaction, i.e.
3044022050587d300d060b912526164f24b1e24897ed9822b1d23fce9a7c103e1c6b3d2102202b42a536a8 \
2582ac26495c3a3f5c34add4c1aa2fecede1c50ce5f22fd067399201
This is validated using OP_CHECKSIG which is the last operation in the locking script. This opcode takes the two values left on the stack, namely the signature and the public key, and validates the signature. The process is fairly involved but can be found here: https://en.bitcoin.it/wiki/OP_CHECKSIG
These various parts of the spending transaction can be reasonably easily found in the hex output from getrawtransaction as follows:
getrawtransaction 08a5430a667a700e7b913d1895908c56d035559cd32a999a5c8cd56f409f4d15
0100000001e121f5c5981dfa8a87b442f21167e4a481758081c526d39a511c10beb918e0de \
000000006a473044022050587d300d060b912526164f24b1e24897ed9822b1d23fce9a7c10 \
3e1c6b3d2102202b42a536a82582ac26495c3a3f5c34add4c1aa2fecede1c50ce5f22fd067 \
3992012102188c91a675464d2dc475d4f01bc8cd60fe418d99142ed1ce5f8ce45a997080d5 \
ffffffff0200f2052a010000001976a91401227043367a947a0754e44f0c0da197cc1d929d \
88ac00ca9a3b000000001976a9147283560a1a0e4d5ba2868e3ec7a7d98c6816d4e188ac00000000
The signature part is seen in green and the public key is given in blue.
As this is the spending transaction it will send outputs to new addresses. The corresponding opcodes are highlighted in yellow: 76=OP_DUP, a9=OP_HASH160, 88=OP_EQUALVERIFY and ac=OP_CHECKSIG. All of these can be found at https://en.bitcoin.it/wiki/Script. Right after each 0xa9, one can see 0x14 (=20 decimal) followed by 20 bytes of data, these being the hashed public keys for the new recipients.
Finally, look carefully at the hex code again and you will find the string 00f2052a01 which contains the byte representation of the amount, in reverse byte order, so to evaluate the amount, take the reversed hex notation, 0x012a05f200, and convert this to decimal (in R)
0x012a05f200
[1] 5e+09
These amounts are given in units of \(10^{-8}\) SMLY (Smile-oshi?), so these are 50 SMLY, as can be seen by looking at https://chainz.cryptoid.info/smly/tx.dws?08a5430a667a700e7b913d1895908c56d035559cd32a999a5c8cd56f409f4d15.htm
This can also be computed directly using the algorithm to go from base 16 to base 10:
0 1 2 a 0 5 f 2 0 0
> ((((((((0*16+1)*16+2)*16+10)*16+0)*16+5)*16+15)*16+2)*16+0)*16+0
[1] 5e+09
The other amount is coded as the string
00ca9a3b00000000
which amounts to
0x3b9aca00
or 10 SMLY.
A more detailed look at P2SH¶
A case study in P2SH is given below in the form of using a multisig address
Several tutorials are available on this topic
A detailed explanation of using a multisig address, from setting up through generating the address to deposits and spending.
Example¶
The addresses are generated on three Linux computers using the command
smileycoin-cli getnewaddress
on each computer separately.
In this case study the following 3 addresses were obtained, belonging to wallets on 3 different computers
BTU58m57Jo61jU3WeWujPj2aZ9LEYLnpYd
BP6AsFWQHPggnXNYTLssykopsx6r3y2Qnh
B66UXukGkPCgasKp9nVTwb93K7XGMzvjTX
By running
validateaddress
on each computer, the corresponding public key is also shown.
For example, the
validateaddress
command on computer 1 resulted in the following output:
smileycoind validateaddress BTU58m57Jo61jU3WeWujPj2aZ9LEYLnpYd
{
"isvalid" : true,
"address" : "BTU58m57Jo61jU3WeWujPj2aZ9LEYLnpYd",
"ismine" : true,
"isscript" : false,
"pubkey" : "03971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c63646",
"iscompressed" : true,
"account" : ""
}
Note that requesting this exact
validateaddress
on another computer will not give the public key, which will be required later. Thus the
validateaddress
command needs to be executed on each of the three computers.
In our example we obtain:
Address - Public key
BTU58m57Jo61jU3WeWujPj2aZ9LEYLnpYd - 03971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c63646
BP6AsFWQHPggnXNYTLssykopsx6r3y2Qnh - 02b416988c8f209b4ccddb96132685882932405641bac69ba3cae38dd21f619983
B66UXukGkPCgasKp9nVTwb93K7XGMzvjTX - 0380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db3fee65df
Normally the process would involve three different individuals as it is usually of importance that the three signatures be independent. Thus no one person should know all private keys nor have access to the three wallets.
At this stage we have all the information to set up a
multisig address
where two of the three signatures are required for spending.
We have two methods for generating the address. The first and simpler is
addmultisigaddress:
smileyCoin/src/smileycoin-cli addmultisigaddress 2 \
'["0380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db3fee65df",\
"02b416988c8f209b4ccddb96132685882932405641bac69ba3cae38dd21f619983",\
"03971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c63646"]'
**3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp**
The output from the command is the “multisig address” or “script hash”, 3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp.
Note that the backslashes are not a part of the command, which should be all on one line.
Note also that all three public keys are used when generating the address, which is not a traditional address but a hash which can receive payments just like a regular address.
The second method is to use the
createmultisig
command. This is very similar:
smileycoin-cli createmultisig 2
'["0380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db3fee65df",\
"02b416988c8f209b4ccddb96132685882932405641bac69ba3cae38dd21f619983",\
"03971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c63646"]'
but provides more output, which will be used later:
{
"address" : "3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp",
"redeemScript" : "52210380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db\
3fee65df2102b416988c8f209b4ccddb96132685882932405641bac69ba3ca\
e38dd21f6199832103971fbd962c5b61432efecf07dbf69f93653ea8a14cc1\
04dc71700e7874c6364653ae"
}
Note that the
redeemScript
is on one line but is merely printed here on multiple lines (as indicated by the backslash, the continuation symbol).
The redeemScript will be used later, when we will find a way to spend from the address.
Also note that the multisig address is the same as before: If you use the same three public keys and request the same number of signatures, then the same address is generated.
Now, note that the address is valid on all machines, but it is only “mine” on machines which know how it was generated, as seen in this session on another one of the three:
smileycoin-cli validateaddress 3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp
{
"isvalid" : true,
"address" : "3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp",
"ismine" : false
}
- Now we can send to this “address”::
smileyCoin/src/smileycoind sendtoaddress 3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp 1000 f05d1c98d761f1b53727436c2b168bcb4f4e17e92779d065a8ca928f17089e60
The transaction Id can be viewed by using
getrawtransaction
followed by
decoderawtransaction
smileyCoin/src/smileycoind decoderawtransaction \
010000000113adb392c276310901597edfdae180cdaa60f71bcbe1148419e27b\
dc6718bf20000000006a47304402204d1ffe1c1d6d03d03912e6ecc495ff1172\
cc61530e17402d436069a6afa33b0a0220036436af1c0d60af4973b07d5e54c8\
ad8830ecb4686354e6cd71a8e766975338012103a75b127dcb90966b99ae8951\
ac83b6fb57752f80138125042d14cafeac8e0cd1ffffffff0200e87648170000\
0017a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b8700ff0f270b0000\
001976a91462745ef11b10e42f05799d1ea6e1289537d52cf388ac00000000
{
"txid" : "f05d1c98d761f1b53727436c2b168bcb4f4e17e92779d065a8ca928f17089e60",
"version" : 1,
"locktime" : 0,
"vin" : [
{
"txid" : "20bf1867dc7be2198414e1cb1bf760aacd80e1dadf7e5901093176c292b3ad13",
"vout" : 0,
"scriptSig" : {
"asm" : "304402204d1ffe1c1d6d03d03912e6ecc495ff1172cc61530e17402d436069a6\
afa33b0a0220036436af1c0d60af4973b07d5e54c8ad8830ecb4686354e6cd71a8e76697533801
03a75b127dcb90966b99ae8951ac83b6fb57752f80138125042d14cafeac8e0cd1",
"hex" : "47304402204d1ffe1c1d6d03d03912e6ecc495ff1172cc61530e17402d436069\
a6afa33b0a0220036436af1c0d60af4973b07d5e54c8ad8830ecb4686354e6cd\
71a8e766975338012103a75b127dcb90966b99ae8951ac83b6fb57752f801381\
25042d14cafeac8e0cd1"
},
"sequence" : 4294967295
}
],
"vout" : [
{
"value" : 1000.00000000,
"n" : 0,
"scriptPubKey" : {
"asm" : "OP_HASH160 c3f4f3243886b8ed77a9d4d464d27be55ae7000b OP_EQUAL",
"hex" : "a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b87",
"reqSigs" : 1,
"type" : "scripthash",
"addresses" : [
"3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp"
]
}
},
{
"value" : 479.00000000,
"n" : 1,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 62745ef11b10e42f05799d1ea6e1289537d52cf3 OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a91462745ef11b10e42f05799d1ea6e1289537d52cf388ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"BDRfF71aUNzBWdgw3f7W8Ai1pwF7DVPiC8"
]
}
}
]
}
Check the amount in the P2SH address: https://chainz.cryptoid.info/smly/address.dws?3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp.htm
Creating the raw transaction
- Recall that the UTXO is::
vout: 0 txid: f05d1c98d761f1b53727436c2b168bcb4f4e17e92779d065a8ca928f17089e60
and this needs to be specified in the transaction.
Now we are all set to try to spend the funds:
createrawtransaction '[{"txid":"f05d1c98d761f1b53727436c2b168bcb4f4e17e92779d065a8ca928f17089e60","vout":0}]' \
'{"BNVZ3mJ2jadZtEfT8wyw6ttHVuZFos9Vw3":100,"3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp":899}'
0100000001609e08178f92caa865d07927e9174e4fcb8b162b6c432737b5f161d7981c5df00000000000\
ffffffff0200e40b54020000001976a914c5e9feb90ddcd06bb538ec87ab13643121b5131388ac002375\
ee1400000017a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b8700000000
Alternatively we may be on a machine which does not know about the redeemScript and then we need to provide it, aka Gavin Andersen:
smileycoin-cli createrawtransaction \
'[{"txid":"f05d1c98d761f1b53727436c2b168bcb4f4e17e92779d065a8ca928f17089e60",\
"vout":0,\
"scriptPubKey":"a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b87",\
"redeemScript":"52210380304a74398b04af944831a4e51c41cc0c9f29d4b\
25f6530976d46db3fee65df2102b416988c8f209b4ccddb\
96132685882932405641bac69ba3cae38dd21f619983210\
3971fbd962c5b61432efecf07dbf69f93653ea8a14cc104\
dc71700e7874c6364653ae"}]' \
'{"BNVZ3mJ2jadZtEfT8wyw6ttHVuZFos9Vw3":100,"3KZ98MnX4Uzv7hcQNyA5QfMaGCqLvbF3Sp":899}'
and this gives a fully constructed transaction as before:
0100000001609e08178f92caa865d07927e9174e4fcb8b162b6c432737b5f161d\
7981c5df00000000000ffffffff0200e40b54020000001976a914c5e9feb90ddc\
d06bb538ec87ab13643121b5131388ac002375ee1400000017a914c3f4f324388\
6b8ed77a9d4d464d27be55ae7000b8700000000
This transaction needs to be signed by at least two of the three address-holders.
User 1:
pi@raspberrypi ~ $ smileyCoin/src/smileycoind signrawtransaction
0100000001609e08178f92caa865d07927e9174e4fcb8b162b6c432737b5f161d7981c5df00000000000ffffffff0200e40b54020000001976a914c5e9feb90ddcd06bb538ec87ab13643121b5131388ac002375ee1400000017a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b8700000000
{
"hex" : "0100000001609e08178f92caa865d07927e9174e4fcb8b162b6c432737b5f161d7981c5df000000000b500483045022100ad97bd7a35043187ac1972db1127f3fd74e63f5e3b2a1c660bff29a62ffb786a02201853bddb9ff92c96e5a09b442455b39234de898e03ac8516717c43f0ac6e7190014c6952210380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db3fee65df2102b416988c8f209b4ccddb96132685882932405641bac69ba3cae38dd21f6199832103971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c6364653aeffffffff0200e40b54020000001976a914c5e9feb90ddcd06bb538ec87ab13643121b5131388ac002375ee1400000017a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b8700000000",
"complete" : false
}
User 2
signrawtransaction
0100000001609e08178f92caa865d07927e9174e4fcb8b162b6c432737b5f161d7981c5df000000000b500483045022100ad97bd7a35043187ac1972db1127f3fd74e63f5e3b2a1c660bff29a62ffb786a02201853bddb9ff92c96e5a09b442455b39234de898e03ac8516717c43f0ac6e7190014c6952210380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db3fee65df2102b416988c8f209b4ccddb96132685882932405641bac69ba3cae38dd21f6199832103971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c6364653aeffffffff0200e40b54020000001976a914c5e9feb90ddcd06bb538ec87ab13643121b5131388ac002375ee1400000017a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b8700000000
{
"hex" : "0100000001609e08178f92caa865d07927e9174e4fcb8b162b6c432737b5f161d7981c5df000000000fdfe0000483045022100b3c3d230fa677230b05f352a1c5481d4ad6792e579f2d559069563ad412c3ebd02207c5cf419d4a2a5fb242d840491b664ba69ae5fd2547adb790b7c9b1aa8ff34e801483045022100ad97bd7a35043187ac1972db1127f3fd74e63f5e3b2a1c660bff29a62ffb786a02201853bddb9ff92c96e5a09b442455b39234de898e03ac8516717c43f0ac6e7190014c6952210380304a74398b04af944831a4e51c41cc0c9f29d4b25f6530976d46db3fee65df2102b416988c8f209b4ccddb96132685882932405641bac69ba3cae38dd21f6199832103971fbd962c5b61432efecf07dbf69f93653ea8a14cc104dc71700e7874c6364653aeffffffff0200e40b54020000001976a914c5e9feb90ddcd06bb538ec87ab13643121b5131388ac002375ee1400000017a914c3f4f3243886b8ed77a9d4d464d27be55ae7000b8700000000",
"complete" : true
}
Note how the second signature generates a valid transaction (complete=true).
This transaction is seen as