lib/bitcoin/script.rb in bitcoin-ruby-0.0.10 vs lib/bitcoin/script.rb in bitcoin-ruby-0.0.11

- old
+ new

@@ -295,10 +295,21 @@ end } to_binary(buf) end + # Returns a script that deleted the script before the index specified by separator_index. + def subscript_codeseparator(separator_index) + buf = [] + process_separator_index = 0 + (chunks || @chunks).each{|chunk| + buf << chunk if process_separator_index == separator_index + process_separator_index += 1 if chunk == OP_CODESEPARATOR and process_separator_index < separator_index + } + to_binary(buf) + end + # Adds opcode (OP_0, OP_1, ... OP_CHECKSIG etc.) # Returns self. def append_opcode(opcode) raise "Opcode should be a Fixnum" if !opcode.is_a?(Fixnum) if opcode >= OP_0 && opcode <= 0xff @@ -538,11 +549,11 @@ end alias :is_p2sh? :is_pay_to_script_hash? # check if script is in one of the recognized standard formats def is_standard? - is_pubkey? || is_hash160? || is_multisig? || is_p2sh? || is_op_return? + is_pubkey? || is_hash160? || is_multisig? || is_p2sh? || is_op_return? || is_witness_v0_keyhash? || is_witness_v0_scripthash? end # is this a pubkey script def is_pubkey? return false if @chunks.size != 2 @@ -567,10 +578,25 @@ # is this an op_return script def is_op_return? @chunks[0] == OP_RETURN && @chunks.size <= 2 end + # is this a witness script(witness_v0_keyhash or witness_v0_scripthash) + def is_witness? + is_witness_v0_keyhash? || is_witness_v0_scripthash? + end + + # is this a witness pubkey script + def is_witness_v0_keyhash? + @chunks.length == 2 &&@chunks[0] == 0 && @chunks[1].is_a?(String) && @chunks[1].bytesize == 20 + end + + # is this a witness script hash + def is_witness_v0_scripthash? + @chunks.length == 2 &&@chunks[0] == 0 && @chunks[1].is_a?(String) && @chunks[1].bytesize == 32 + end + # Verify the script is only pushing data onto the stack def is_push_only?(script_data=nil) check_pushes(push_only=true, canonical_only=false, (script_data||@input_script)) end @@ -610,23 +636,25 @@ return false if canonical_only && len <= 0xffff program.shift(len) end end true - rescue => ex + rescue # catch parsing errors false end # get type of this tx def type - if is_hash160?; :hash160 - elsif is_pubkey?; :pubkey - elsif is_multisig?; :multisig - elsif is_p2sh?; :p2sh - elsif is_op_return?;:op_return - else; :unknown + if is_hash160?; :hash160 + elsif is_pubkey?; :pubkey + elsif is_multisig?; :multisig + elsif is_p2sh?; :p2sh + elsif is_op_return?; :op_return + elsif is_witness_v0_keyhash?; :witness_v0_keyhash + elsif is_witness_v0_scripthash?;:witness_v0_scripthash + else; :unknown end end # get the public key for this pubkey script def get_pubkey @@ -642,10 +670,12 @@ # get the hash160 for this hash160 or pubkey script def get_hash160 return @chunks[2..-3][0].unpack("H*")[0] if is_hash160? return @chunks[-2].unpack("H*")[0] if is_p2sh? return Bitcoin.hash160(get_pubkey) if is_pubkey? + return @chunks[1].unpack("H*")[0] if is_witness_v0_keyhash? + return @chunks[1].unpack("H*")[0] if is_witness_v0_scripthash? end # get the hash160 address for this hash160 script def get_hash160_address Bitcoin.hash160_to_address(get_hash160) @@ -711,10 +741,26 @@ return nil unless p2sh # HASH160 length hash EQUAL [ ["a9", "14", p2sh, "87"].join ].pack("H*") end + # generate p2wpkh tx for given +address+. returns a raw binary script of the form: + # 0 <hash160> + def self.to_witness_hash160_script(hash160) + return nil unless hash160 + # witness ver length hash160 + [ ["00", "14", hash160].join ].pack("H*") + end + + # generate p2wsh output script for given +p2sh+ sha256. returns a raw binary script of the form: + # 0 <p2sh> + def self.to_witness_p2sh_script(p2sh) + return nil unless p2sh + # witness ver length sha256 + [ [ "00", "20", p2sh].join].pack("H*") + end + # generate hash160 or p2sh output script, depending on the type of the given +address+. # see #to_hash160_script and #to_p2sh_script. def self.to_address_script(address) hash160 = Bitcoin.hash160_from_address(address) case Bitcoin.address_type(address) @@ -828,9 +874,13 @@ end def get_keys_provided return false unless is_multisig? @chunks[-2] - 80 + end + + def codeseparator_count + @chunks.select{|c|c == Bitcoin::Script::OP_CODESEPARATOR}.length end # This matches CScript::GetSigOpCount(bool fAccurate) # Note: this does not cover P2SH script which is to be unserialized # and checked explicitly when validating blocks.