11require_relative '../bitcoin_data_io'
22require_relative '../encoding_helper'
3+ require_relative '../hash_helper'
34require_relative './op'
45
56module Bitcoin
@@ -88,14 +89,14 @@ def serialize
8889 encode_varint ( raw . length ) + raw
8990 end
9091
91- def evaluate ( z ) # rubocop:disable Metrics/MethodLength
92+ def evaluate ( z , witness : nil )
9293 cmds = @cmds . clone
9394 stack = [ ]
9495 altstack = [ ]
9596
9697 while cmds . any?
9798 cmd = cmds . shift
98- return false unless resolve_cmd ( cmd , cmds , stack , altstack , z )
99+ return false unless resolve_cmd ( cmd , cmds , stack , altstack , z , witness : witness )
99100 end
100101
101102 return false if stack . empty? || stack . pop . empty?
@@ -110,6 +111,18 @@ def p2sh?(cmds = @cmds)
110111 && cmds [ 2 ] == 135
111112 end
112113
114+ def p2wpkh? ( cmds = @cmds )
115+ cmds . length == 2 \
116+ && cmds [ 0 ] == 0 \
117+ && cmds [ 1 ] . is_a? ( String ) && cmds [ 1 ] . length == 20
118+ end
119+
120+ def p2wsh? ( cmds = @cmds )
121+ cmds . length == 2 \
122+ && cmds [ 0 ] == 0 \
123+ && cmds [ 1 ] . is_a? ( String ) && cmds [ 1 ] . length == 32
124+ end
125+
113126 def self . p2pkh ( hash160 )
114127 Script . new ( [ 118 , 169 , hash160 , 136 , 172 ] )
115128 end
@@ -124,14 +137,18 @@ def self.p2wsh(hash256)
124137
125138 private
126139
127- def resolve_cmd ( cmd , cmds , stack , altstack , z )
140+ def resolve_cmd ( cmd , cmds , stack , altstack , z , witness : nil )
128141 if cmd . is_a? Integer
129142 return execute_operation ( cmd , cmds , stack , altstack , z )
130143 else
131144 stack . append ( cmd )
132145
133146 if p2sh? ( cmds )
134147 return execute_p2sh ( cmd , cmds , stack )
148+ elsif p2wpkh?
149+ return execute_p2wpkh ( cmds , stack , witness )
150+ elsif p2wsh?
151+ return execute_p2wsh ( cmds , stack , witness )
135152 end
136153 end
137154
@@ -154,6 +171,30 @@ def execute_p2sh(cmd, cmds, stack)
154171 cmds . concat self . class . parse ( stream ) . cmds
155172 end
156173
174+ def execute_p2wpkh ( cmds , stack , witness )
175+ h160 = stack . pop
176+ stack . pop
177+ cmds . concat witness
178+ cmds . concat self . class . p2wpkh ( h160 ) . cmds
179+ end
180+
181+ def execute_p2wsh ( cmds , stack , witness )
182+ s256_stack = stack . pop
183+ stack . pop
184+ cmds . concat witness [ 0 ...-1 ]
185+ witness_script = witness . last
186+ s256_script = HashHelper . hash256 ( witness_script )
187+
188+ unless s256_stack == s256_script
189+ raise "Witness script hash mismatch: \n " \
190+ "stack: #{ bytes_to_hex ( s256_stack ) } \n " \
191+ "script: #{ bytes_to_hex ( s256_script ) } "
192+ end
193+
194+ stream = encode_varint ( witness_script . size ) + witness_script
195+ cmds . concat parse ( stream ) . cmds
196+ end
197+
157198 def raw_serialize
158199 @cmds . map do |cmd |
159200 cmd . is_a? ( Integer ) ? int_to_little_endian ( cmd , 1 ) : serialized_element_prefix ( cmd ) + cmd
0 commit comments