lib/tapyrus/tx.rb in tapyrus-0.2.7 vs lib/tapyrus/tx.rb in tapyrus-0.2.8

- old
+ new

@@ -1,18 +1,17 @@ # Porting part of the code from bitcoin-ruby. see the license. # https://github.com/lian/bitcoin-ruby/blob/master/COPYING module Tapyrus - # Transaction class class Tx include Tapyrus::HexConverter MAX_STANDARD_VERSION = 2 # The maximum weight for transactions we're willing to relay/mine - MAX_STANDARD_TX_WEIGHT = 400000 + MAX_STANDARD_TX_WEIGHT = 400_000 attr_accessor :features attr_reader :inputs attr_reader :outputs attr_accessor :lock_time @@ -32,18 +31,14 @@ tx = new tx.features = buf.read(4).unpack('V').first in_count = Tapyrus.unpack_var_int_from_io(buf) - in_count.times do - tx.inputs << TxIn.parse_from_payload(buf) - end + in_count.times { tx.inputs << TxIn.parse_from_payload(buf) } out_count = Tapyrus.unpack_var_int_from_io(buf) - out_count.times do - tx.outputs << TxOut.parse_from_payload(buf) - end + out_count.times { tx.outputs << TxOut.parse_from_payload(buf) } tx.lock_time = buf.read(4).unpack('V').first tx end @@ -56,11 +51,11 @@ Tapyrus.double_sha256(to_payload).bth end def txid buf = [features].pack('V') - buf << Tapyrus.pack_var_int(inputs.length) << inputs.map{|i|i.to_payload(use_malfix: true)}.join + buf << Tapyrus.pack_var_int(inputs.length) << inputs.map { |i| i.to_payload(use_malfix: true) }.join buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join buf << [lock_time].pack('V') Tapyrus.double_sha256(buf).reverse.bth end @@ -93,10 +88,11 @@ end data_count = 0 outputs.each do |o| return false unless o.script_pubkey.standard? data_count += 1 if o.script_pubkey.op_return? + # TODO add non P2SH multisig relay(permitbaremultisig) return false if o.dust? end return false if data_count > 1 true @@ -112,12 +108,18 @@ # @param [Integer] hash_type signature hash type # @param [Tapyrus::Script] output_script script pubkey or script code. if script pubkey is P2WSH, set witness script to this. # @param [Integer] amount tapyrus amount locked in input. required for witness input only. # @param [Integer] skip_separator_index If output_script is P2WSH and output_script contains any OP_CODESEPARATOR, # the script code needs is the witnessScript but removing everything up to and including the last executed OP_CODESEPARATOR before the signature checking opcode being executed. - def sighash_for_input(input_index, output_script, hash_type: SIGHASH_TYPE[:all], - sig_version: :base, amount: nil, skip_separator_index: 0) + def sighash_for_input( + input_index, + output_script, + hash_type: SIGHASH_TYPE[:all], + sig_version: :base, + amount: nil, + skip_separator_index: 0 + ) raise ArgumentError, 'input_index must be specified.' unless input_index raise ArgumentError, 'does not exist input corresponding to input_index.' if input_index >= inputs.size raise ArgumentError, 'script_pubkey must be specified.' unless output_script raise ArgumentError, 'unsupported sig version specified.' unless SIG_VERSION.include?(sig_version) sighash_for_legacy(input_index, output_script, hash_type) @@ -127,20 +129,23 @@ # @param [Integer] input_index # @param [Tapyrus::Script] script_pubkey the script pubkey for target input. # @param [Integer] amount the amount of tapyrus, require for witness program only. # @param [Array] flags the flags used when execute script interpreter. def verify_input_sig(input_index, script_pubkey, amount: nil, flags: STANDARD_SCRIPT_VERIFY_FLAGS) - if script_pubkey.p2sh? - flags << SCRIPT_VERIFY_P2SH - end + flags << SCRIPT_VERIFY_P2SH if script_pubkey.p2sh? verify_input_sig_for_legacy(input_index, script_pubkey, flags) end def to_h { - txid: txid, hash: tx_hash, features: features, size: size, locktime: lock_time, - vin: inputs.map(&:to_h), vout: outputs.map.with_index{|tx_out, index| tx_out.to_h.merge({n: index})} + txid: txid, + hash: tx_hash, + features: features, + size: size, + locktime: lock_time, + vin: inputs.map(&:to_h), + vout: outputs.map.with_index { |tx_out, index| tx_out.to_h.merge({ n: index }) } } end # Verify transaction validity. # @return [Boolean] whether this tx is valid or not. @@ -152,54 +157,57 @@ private # generate sighash with legacy format def sighash_for_legacy(index, script_code, hash_type) - ins = inputs.map.with_index do |i, idx| - if idx == index - i.to_payload(script_code.delete_opcode(Tapyrus::Opcodes::OP_CODESEPARATOR)) - else - case hash_type & 0x1f + ins = + inputs.map.with_index do |i, idx| + if idx == index + i.to_payload(script_code.delete_opcode(Tapyrus::Opcodes::OP_CODESEPARATOR)) + else + case hash_type & 0x1f when SIGHASH_TYPE[:none], SIGHASH_TYPE[:single] i.to_payload(Tapyrus::Script.new, 0) else i.to_payload(Tapyrus::Script.new) + end end end - end outs = outputs.map(&:to_payload) out_size = Tapyrus.pack_var_int(outputs.size) case hash_type & 0x1f - when SIGHASH_TYPE[:none] - outs = '' - out_size = Tapyrus.pack_var_int(0) - when SIGHASH_TYPE[:single] - return "\x01".ljust(32, "\x00") if index >= outputs.size - outs = outputs[0...(index + 1)].map.with_index { |o, idx| (idx == index) ? o.to_payload : o.to_empty_payload }.join - out_size = Tapyrus.pack_var_int(index + 1) + when SIGHASH_TYPE[:none] + outs = '' + out_size = Tapyrus.pack_var_int(0) + when SIGHASH_TYPE[:single] + return "\x01".ljust(32, "\x00") if index >= outputs.size + outs = + outputs[0...(index + 1)].map.with_index { |o, idx| (idx == index) ? o.to_payload : o.to_empty_payload }.join + out_size = Tapyrus.pack_var_int(index + 1) end - if hash_type & SIGHASH_TYPE[:anyonecanpay] != 0 - ins = [ins[index]] - end + ins = [ins[index]] if hash_type & SIGHASH_TYPE[:anyonecanpay] != 0 - buf = [[features].pack('V'), Tapyrus.pack_var_int(ins.size), - ins, out_size, outs, [lock_time, hash_type].pack('VV')].join + buf = [ + [features].pack('V'), + Tapyrus.pack_var_int(ins.size), + ins, + out_size, + outs, + [lock_time, hash_type].pack('VV') + ].join Tapyrus.double_sha256(buf) end - # verify input signature for legacy tx. def verify_input_sig_for_legacy(input_index, script_pubkey, flags) script_sig = inputs[input_index].script_sig checker = Tapyrus::TxChecker.new(tx: self, input_index: input_index) interpreter = Tapyrus::ScriptInterpreter.new(checker: checker, flags: flags) interpreter.verify_script(script_sig, script_pubkey) end - end - end