Class: BTC::TransactionSignatureChecker

Inherits:
Object
  • Object
show all
Includes:
SignatureChecker
Defined in:
lib/btcruby/script/transaction_signature_checker.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version: 0, transaction: nil, input_index: nil, amount: 0) ⇒ TransactionSignatureChecker

Returns a new instance of TransactionSignatureChecker.



10
11
12
13
14
15
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 10

def initialize(version: 0, transaction: nil, input_index: nil, amount: 0)
  @version     = version
  @transaction = transaction
  @input_index = input_index
  @amount      = amount
end

Instance Attribute Details

#amountObject

Returns the value of attribute amount.



8
9
10
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 8

def amount
  @amount
end

#input_indexObject

Returns the value of attribute input_index.



7
8
9
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 7

def input_index
  @input_index
end

#transactionObject

Returns the value of attribute transaction.



6
7
8
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 6

def transaction
  @transaction
end

#versionObject

Returns the value of attribute version.



5
6
7
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 5

def version
  @version
end

Instance Method Details

#check_lock_time(lock_time) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 41

def check_lock_time(lock_time)
  # There are two times 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
  # if the type of nLockTime being tested is not the same as
  # the nLockTime in the transaction.
  if !(
       (@transaction.lock_time <  LOCKTIME_THRESHOLD && lock_time <  LOCKTIME_THRESHOLD) ||
       (@transaction.lock_time >= LOCKTIME_THRESHOLD && lock_time >= LOCKTIME_THRESHOLD)
   )
    return false
  end

  # Now that we know we're comparing apples-to-apples, the
  # comparison is a simple numeric one.
  if lock_time > @transaction.lock_time
    return false
  end

  # 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.
  if @transaction.inputs[@input_index].final?
    return false
  end

  return true
end

#check_signature(script_signature: nil, public_key: nil, script: nil) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/btcruby/script/transaction_signature_checker.rb', line 17

def check_signature(script_signature:nil, public_key:nil, script:nil)
  # Signature must be long enough to contain a sighash byte.
  return false if script_signature.size < 1
  
  hashtype = script_signature[-1].bytes.first

  # Extract raw ECDSA signature by stripping off the last hashtype byte
  ecdsa_sig = script_signature[0..-2]
  
  key = BTC::Key.new(public_key: public_key)
  hash = @transaction.signature_hash(
    input_index:   @input_index, 
    output_script: script, 
    hash_type:     hashtype, 
    version:       version, 
    amount:        amount
  )
  result = key.verify_ecdsa_signature(ecdsa_sig, hash)
  return result
rescue BTC::FormatError => e # public key is invalid
  Diagnostics.current.add_message(e.message)
  return false
end