Skip to content

Commit 92ef3e6

Browse files
committed
up
1 parent d0d9b7d commit 92ef3e6

6 files changed

+193
-18
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#### for testing scripts / sandbox
2+
/test/

README.md

+83-18
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,70 @@ op_2( stack ) #=> stack = [2,2]
3737
op_add( stack ) #=> stack = [4]
3838
```
3939

40+
(Source: [`stackmachine_add.rb`](stackmachine_add.rb))
41+
42+
43+
4044
Yes, that's all the magic! You have built your own stack machine with
4145
two operations / ops, that is, `op_add` and `op_2`.
4246

43-
Push and Pop
44-
4547
The `op_2` operation pushes the number `2` onto the stack.
4648
The `op_add` operation pops the top two numbers from the stack
4749
and pushes the result onto the stack.
4850

4951

52+
Aside - What's a Stack? Push 'n' Pop
53+
54+
A stack is a last-in first-out (LIFO) data structure. Use `push`
55+
to add an element to the top of the stack and use `pop`
56+
to remove the top element from the stack.
57+
Example:
58+
59+
``` ruby
60+
stack = [] #=> []
61+
stack.empty? #=> true
62+
63+
stack.push( 1 ) #=> [1]
64+
stack.empty? #=> false
65+
stack.push( 2 ) #=> [1, 2]
66+
stack.push( 3 ) #=> [1, 2, 3]
67+
stack.push( "<signature>" ) #=> [1, 2, 3, "<signature>"]
68+
stack.push( "<pubkey>") #=> [1, 2, 3, "<signature>", "<pubkey>"]
69+
70+
stack.pop #=> "<pubkey>"
71+
stack #=> [1, 2, 3, "<signature>"]
72+
stack.pop #=> "<signature>"
73+
stack #=> [1, 2, 3]
74+
75+
stack.push( 4 ) #=> [1, 2, 3, 4]
76+
stack.push( 5 ) #=> [1, 2, 3, 4, 5]
77+
78+
stack.pop #=> 5
79+
stack #=> [1, 2, 3, 4]
80+
stack.pop #=> 4
81+
stack #=> [1, 2, 3]
82+
stack.pop #=> 3
83+
stack #=> [1, 2]
84+
stack.pop #=> 2
85+
stack #=> [1]
86+
stack.empty? #=> false
87+
stack.pop #=> 1
88+
stack #=> []
89+
stack.empty? #=> true
90+
stack.pop #=> nil
91+
```
92+
93+
(Source: [`stack.rb`](stack.rb))
94+
95+
96+
97+
Unlock+Lock / Input+Output / ScriptSig+ScriptPubKey
98+
5099
In "real world" bitcoin the script has two parts / halves in two transactions
51100
that get combined.
52-
The "lock" or "output" or "ScriptSig" script
101+
The "lock" or "output" or "ScriptPubKey" script
53102
that locks the "unspent transaction output (UTXO)"
54-
and the "unlock" or "input" or "ScriptPubKey" script that unlocks
103+
and the "unlock" or "input" or "ScriptSig" script that unlocks
55104
the bitcoins.
56105

57106

@@ -70,27 +119,30 @@ end
70119
## Let's run!
71120

72121
stack = []
73-
## scriptPubKey part
74-
## - Empty
75-
76-
## scriptSig part
122+
## I) ScriptSig (input/unlock) part
77123
op_true( stack ) #=> stack = [1]
124+
125+
## II) ScriptPubKey (output/lock) part
126+
## <Empty>
78127
```
79128

129+
(Source: [`stackmachine_anyone.rb`](stackmachine_anyone.rb))
130+
131+
80132
Bingo! Yes, that's all the magic!
81133
The `op_true` operation pushes the number `1`, that is, `true` onto the stack.
82134

83135
The "official" bitcoin script notation reads:
84136

85137
```
86-
scriptPubKey: (empty)
87-
scriptSig: OP_TRUE
138+
ScriptSig (input): OP_TRUE
139+
ScriptPubKey: (empty)
88140
```
89141

90142
Now let's split the adding `2+2` script into a two part puzzle,
91143
that is, `?+2=4`
92-
or into `scriptSig` and `scriptPubKey`.
93-
If you know the answer you can "unlock" the bounty,
144+
or into `ScriptSig` and `ScriptPubKey`.
145+
If you know the answer you can "unlock" the bounty,
94146
that is, the bitcoin are yours!
95147
Here's the challenge:
96148

@@ -119,21 +171,26 @@ end
119171
## Let's run!
120172

121173
stack = []
122-
## scriptPubKey part
123-
## - add your "unlock" stack operation / operations here
174+
## I) ScriptSig (input/unlock) part
175+
## FIX!!! - add your "unlock" stack operation / operations here
124176

125-
## scriptSig part
177+
## II) ScriptPubKey (output/lock) part
126178
op_2( stack ) #=> stack = [?, 2]
127179
op_add( stack ) #=> stack = [4]
128180
op_4( stack ) #=> stack = [4,4]
129181
op_equal( stack ) #=> stack = [1]
130182
```
131183

184+
(Source: [`stackmachine_puzzle.rb`](stackmachine_puzzle.rb))
185+
186+
187+
188+
132189
The "official" bitcoin script notation reads:
133190

134191
```
135-
scriptPubKey: ?
136-
scriptSig: OP_2 OP_ADD OP_4 OP_EQUAL
192+
ScriptSig (input): ?
193+
ScriptPubKey: OP_2 OP_ADD OP_4 OP_EQUAL
137194
```
138195

139196

@@ -169,7 +226,8 @@ has been banned, that is, disabled! Why?
169226
Because of security concerns, that is, fear of stack overflows.
170227
What about `OP_DIV` for divisions (e.g. `4/2`)? Don't ask!
171228
Ask who's protecting you from stack underflows?
172-
So what's left for programming - not much really :-).
229+
So what's left for programming - not much really other than checking
230+
signatures and timelocks :-).
173231

174232

175233

@@ -179,6 +237,7 @@ To be continued ...
179237

180238

181239

240+
182241
## Standard Scripts
183242

184243

@@ -187,6 +246,11 @@ To be continued ...
187246
| p2pk | Pay-to-pubkey |
188247
| p2pkh | Pay-to-pubkey-hash |
189248
| p2sh | Pay-to-script-hash |
249+
250+
251+
252+
## Standard Scripts with SegWit (Segregated Witness)
253+
190254
| p2wpkh | Pay-to-witness-pubkey-hash |
191255
| p2wsh | Pay-to-witness-script-hash |
192256

@@ -213,6 +277,7 @@ Books / Series
213277
- [Programming Bitcoin from Scratch](https://github.com/jimmysong/programmingbitcoin) by Jimmy Song
214278
- [Chapter 6 - Script](https://github.com/jimmysong/programmingbitcoin/blob/master/ch06.asciidoc) - How Script Works • Example Operations • Parsing the Script Fields • Combining the Script Fields • Standard Scripts • p2pk • Problems with p2pk • Solving the Problems with p2pkh • Scripts Can Be Arbitrarily Constructed • Conclusion
215279
- [Chapter 8 - Pay-to-Script Hash](https://github.com/jimmysong/programmingbitcoin/blob/master/ch08.asciidoc) - Bare Multisig • Coding OP_CHECKMULTISIG • Problems with Bare Multisig • Pay-to-Script-Hash (p2sh) • Coding p2sh • Conclusion
280+
- [Chapter 13 - Segregated Witness](https://github.com/jimmysong/programmingbitcoin/blob/master/ch13.asciidoc) - Pay-to-Witness-Pubkey-Hash (p2wpkh) • p2wpkh Transactions • p2sh-p2wpkh • Coding p2wpkh and p2sh-p2wpkh • Pay-to-Witness-Script-Hash (p2wsh) • p2sh-p2wsh • Coding p2wsh and p2sh-p2wsh • Other Improvements • Conclusion
216281

217282

218283
Talk Notes

stack.rb

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## A stack - last-in first out (LIFO) data structure
2+
3+
require 'pp' ## pp = pretty print
4+
5+
pp stack = [] #=> []
6+
pp stack.empty? #=> true
7+
8+
pp stack.push( 1 ) #=> [1]
9+
pp stack.empty? #=> false
10+
pp stack.push( 2 ) #=> [1, 2]
11+
pp stack.push( 3 ) #=> [1, 2, 3]
12+
pp stack.push( "<signature>" ) #=> [1, 2, 3, "<signature>"]
13+
pp stack.push( "<pubkey>") #=> [1, 2, 3, "<signature>", "<pubkey>"]
14+
15+
pp stack.pop #=> "<pubkey>"
16+
pp stack #=> [1, 2, 3, "<signature>"]
17+
pp stack.pop #=> "<signature>"
18+
pp stack #=> [1, 2, 3]
19+
20+
pp stack.push( 4 ) #=> [1, 2, 3, 4]
21+
pp stack.push( 5 ) #=> [1, 2, 3, 4, 5]
22+
23+
pp stack.pop #=> 5
24+
pp stack #=> [1, 2, 3, 4]
25+
pp stack.pop #=> 4
26+
pp stack #=> [1, 2, 3]
27+
pp stack.pop #=> 3
28+
pp stack #=> [1, 2]
29+
pp stack.pop #=> 2
30+
pp stack #=> [1]
31+
pp stack.empty? #=> false
32+
pp stack.pop #=> 1
33+
pp stack #=> []
34+
pp stack.empty? #=> true
35+
pp stack.pop #=> nil

stackmachine_add.rb

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## A simple stack machine
2+
3+
require 'pp'
4+
5+
def op_add( stack )
6+
left = stack.pop
7+
right = stack.pop
8+
stack.push( left + right )
9+
end
10+
11+
def op_2( stack )
12+
stack.push( 2 )
13+
end
14+
15+
## Let's run!
16+
17+
stack = []
18+
pp op_2( stack ) #=> stack = [2]
19+
pp op_2( stack ) #=> stack = [2,2]
20+
pp op_add( stack ) #=> stack = [4]

stackmachine_anyone.rb

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## A simple stack machine
2+
3+
require 'pp'
4+
5+
def op_true( stack )
6+
stack.push( 1 )
7+
end
8+
9+
## Let's run!
10+
11+
pp stack = [] #=> []
12+
## I) ScriptSig (input/unlock) part
13+
pp op_true( stack ) #=> [1]
14+
15+
## II) ScriptPubKey (output/lock) part
16+
## <Empty>

stackmachine_puzzle.rb

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## A simple stack machine
2+
3+
require 'pp'
4+
5+
6+
def op_add( stack )
7+
left = stack.pop
8+
right = stack.pop
9+
stack.push( left + right )
10+
end
11+
12+
def op_2( stack )
13+
stack.push( 2 )
14+
end
15+
16+
def op_4( stack )
17+
stack.push( 4 )
18+
end
19+
20+
def op_equal( stack )
21+
left = stack.pop
22+
right = stack.pop
23+
stack.push( left == right ? 1 : 0 )
24+
end
25+
26+
## Let's run!
27+
28+
stack = []
29+
## I) ScriptSig (input/unlock) part
30+
## FIX!!! - add your "unlock" stack operation / operations here
31+
32+
33+
## II) ScriptPubKey (output/lock) part
34+
pp op_2( stack ) #=> stack = [?, 2]
35+
pp op_add( stack ) #=> stack = [4]
36+
pp op_4( stack ) #=> stack = [4,4]
37+
pp op_equal( stack ) #=> stack = [1]

0 commit comments

Comments
 (0)