Class: Tapyrus::TxChecker
- Inherits:
-
Object
- Object
- Tapyrus::TxChecker
- Defined in:
- lib/tapyrus/script/tx_checker.rb
Instance Attribute Summary collapse
-
#input_index ⇒ Object
Returns the value of attribute input_index.
-
#tx ⇒ Object
Returns the value of attribute tx.
Instance Method Summary collapse
- #check_locktime(locktime) ⇒ Object
- #check_sequence(sequence) ⇒ Object
-
#check_sig(script_sig, pubkey, script_code) ⇒ Boolean
check signature.
-
#initialize(tx: nil, input_index: nil) ⇒ TxChecker
constructor
A new instance of TxChecker.
-
#verify_sig(sig, pubkey, digest, allow_hybrid: false) ⇒ Boolean
Check data signature.
Constructor Details
#initialize(tx: nil, input_index: nil) ⇒ TxChecker
Returns a new instance of TxChecker.
6 7 8 9 |
# File 'lib/tapyrus/script/tx_checker.rb', line 6 def initialize(tx: nil, input_index: nil) @tx = tx @input_index = input_index end |
Instance Attribute Details
#input_index ⇒ Object
Returns the value of attribute input_index.
4 5 6 |
# File 'lib/tapyrus/script/tx_checker.rb', line 4 def input_index @input_index end |
#tx ⇒ Object
Returns the value of attribute tx.
3 4 5 |
# File 'lib/tapyrus/script/tx_checker.rb', line 3 def tx @tx end |
Instance Method Details
#check_locktime(locktime) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/tapyrus/script/tx_checker.rb', line 43 def check_locktime(locktime) # There are two kinds of nLockTime: lock-by-blockheight and lock-by-blocktime, # distinguished by whether nLockTime < LOCKTIME_THRESHOLD. # We want to compare apples to apples, so fail the script unless the type of nLockTime being tested is the same as the nLockTime in the transaction. unless ( (tx.lock_time < LOCKTIME_THRESHOLD && locktime < LOCKTIME_THRESHOLD) || (tx.lock_time >= LOCKTIME_THRESHOLD && locktime >= LOCKTIME_THRESHOLD) ) return false end # Now that we know we're comparing apples-to-apples, the comparison is a simple numeric one. return false if locktime > tx.lock_time # Finally the nLockTime feature can be disabled and thus CHECKLOCKTIMEVERIFY bypassed if every txin has been finalized by setting nSequence to maxint. # The transaction would be allowed into the blockchain, making the opcode ineffective. # Testing if this vin is not final is sufficient to prevent this condition. # Alternatively we could test all inputs, but testing just this input minimizes the data required to prove correct CHECKLOCKTIMEVERIFY execution. return false if TxIn::SEQUENCE_FINAL == tx.inputs[input_index].sequence true end |
#check_sequence(sequence) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/tapyrus/script/tx_checker.rb', line 67 def check_sequence(sequence) tx_sequence = tx.inputs[input_index].sequence # Sequence numbers with their most significant bit set are not consensus constrained. # Testing that the transaction's sequence number do not have this bit set prevents using this property to get around a CHECKSEQUENCEVERIFY check. return false unless tx_sequence & TxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG == 0 # Mask off any bits that do not have consensus-enforced meaning before doing the integer comparisons locktime_mask = TxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | TxIn::SEQUENCE_LOCKTIME_MASK tx_sequence_masked = tx_sequence & locktime_mask sequence_masked = sequence & locktime_mask # There are two kinds of nSequence: lock-by-blockheight and lock-by-blocktime, # distinguished by whether sequence_masked < TxIn#SEQUENCE_LOCKTIME_TYPE_FLAG. # We want to compare apples to apples, so fail the script # unless the type of nSequenceMasked being tested is the same as the nSequenceMasked in the transaction. unless ( ( tx_sequence_masked < TxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && sequence_masked < TxIn::SEQUENCE_LOCKTIME_TYPE_FLAG ) || ( tx_sequence_masked >= TxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && sequence_masked >= TxIn::SEQUENCE_LOCKTIME_TYPE_FLAG ) ) return false end # Now that we know we're comparing apples-to-apples, the comparison is a simple numeric one. sequence_masked <= tx_sequence_masked end |
#check_sig(script_sig, pubkey, script_code) ⇒ Boolean
check signature
16 17 18 19 20 21 22 23 |
# File 'lib/tapyrus/script/tx_checker.rb', line 16 def check_sig(script_sig, pubkey, script_code) return false if script_sig.empty? script_sig = script_sig.htb hash_type = script_sig[-1].unpack("C").first sig = script_sig[0..-2] sighash = tx.sighash_for_input(input_index, script_code, hash_type: hash_type) verify_sig(sig.bth, pubkey, sighash) end |
#verify_sig(sig, pubkey, digest, allow_hybrid: false) ⇒ Boolean
Check data signature.
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/tapyrus/script/tx_checker.rb', line 30 def verify_sig(sig, pubkey, digest, allow_hybrid: false) key_type = pubkey.start_with?("02") || pubkey.start_with?("03") ? Key::TYPES[:compressed] : Key::TYPES[:uncompressed] sig = sig.htb algo = sig.bytesize == 64 ? :schnorr : :ecdsa begin key = Key.new(pubkey: pubkey, key_type: key_type, allow_hybrid: allow_hybrid) key.verify(sig, digest, algo: algo) rescue Exception false end end |