btcruby 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2ed39f95cdd06b5950c9164180c4086592519ef
4
- data.tar.gz: 826463f6e12c74f02e122f696251d9c212cf9077
3
+ metadata.gz: e26eccf4e25b07bfb7c0a20d4757c73112ef36ac
4
+ data.tar.gz: 44f3ca44eb7f7c36e666a7a0987055c5a16efeb7
5
5
  SHA512:
6
- metadata.gz: 26f331d4b44fc40c0e211693baca89866176b101600b6dd70860eef7a05bf4db2047c54f7e2a676cb4154683da2d17764b9bfd1c652de805af259f5ab33e9623
7
- data.tar.gz: 96817a00e44da817f3a83d91890c24b6ebde7d5079499e1e759303a99df4002067439761b12f34203f76b26d1afc361d3cb2ff873abde04937fa7ff4a7706858
6
+ metadata.gz: 6c891533a5c79e2091f095ae8a9c103cf326cb5d6f532e62497dfc677e887ddf3b718cee7fc16f5b86c53b45b7f9a08320942b088cb55d92ec246aadf84c0f7b
7
+ data.tar.gz: 8c0dda6751152a16cf585c5472e5f9bb6ee0c0f2bca7fc64ff3e204ea85b9a93924c2d70e88ed70c20e04f36dfec04bc4032633c4ba0c99854fb6fee56c4b823
data/README.md CHANGED
@@ -28,6 +28,7 @@ Please see [BTCRuby Reference](documentation/index.md) for API documentation and
28
28
  and [BIP62](https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki).
29
29
  * Automatic normalization of existing ECDSA signatures (see `BTC::Key#normalized_signature`).
30
30
  * Rich script analysis and compositing support (see `BTC::Script`).
31
+ * Full script interpreter with [P2SH](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki) and [CLTV](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) features.
31
32
  * Powerful diagnostics API covering the entire library (see `BTC::Diagnostics`).
32
33
  * Canonicality checks for transactions, public keys and script elements.
33
34
  * Fee computation and signature script simulation for building transactions without signing them.
@@ -36,7 +37,7 @@ Please see [BTCRuby Reference](documentation/index.md) for API documentation and
36
37
  ## Philosophy
37
38
 
38
39
  * We use clear, expressive names for all methods and classes.
39
- * Self-contained implementation. Only external dependency is `ffi` gem that helps linking directly with OpenSSL.
40
+ * Self-contained implementation. Only external dependency is `ffi` gem that helps linking directly with OpenSSL and libsecp256k1.
40
41
  * For efficiency and consistency we use binary strings throughout the library (not the hex strings as in other libraries).
41
42
  * We do not pollute standard classes with our methods. To use utility extensions like `String#to_hex` you should explicitly `require 'btcruby/extensions'`.
42
43
  * We use OpenSSL `BIGNUM` implementation where compatibility is critical (instead of the built-in Ruby Bignum).
@@ -49,6 +50,7 @@ The goal is to provide a complete Bitcoin toolkit in Ruby.
49
50
 
50
51
  ```
51
52
  $ bundle install
53
+ $ brew install ./vendor/homebrew/secp256k1.rb
52
54
  $ rake
53
55
  ```
54
56
 
@@ -2,6 +2,14 @@
2
2
  BTCRuby Release Notes
3
3
  =====================
4
4
 
5
+ 1.1.2 (August 17, 2015)
6
+ ---------------------
7
+
8
+ * Added scripts test suite from Bitcoin Core.
9
+ * Added transactions test suite from Bitcoin Core.
10
+ * As a result, fixed a few consensus bugs.
11
+ * Renamed `TransactionOutpoint` to `Outpoint` (previous name kept for backwards compatibility).
12
+
5
13
  1.1.1 (July 30, 2015)
6
14
  ---------------------
7
15
 
@@ -23,10 +23,11 @@ require_relative 'btcruby/key.rb'
23
23
  require_relative 'btcruby/keychain.rb'
24
24
  require_relative 'btcruby/wire_format.rb'
25
25
  require_relative 'btcruby/hash_id.rb'
26
+ require_relative 'btcruby/outpoint.rb'
26
27
  require_relative 'btcruby/transaction.rb'
27
28
  require_relative 'btcruby/transaction_input.rb'
28
29
  require_relative 'btcruby/transaction_output.rb'
29
- require_relative 'btcruby/transaction_outpoint.rb'
30
+ require_relative 'btcruby/validation.rb'
30
31
 
31
32
  require_relative 'btcruby/script/script_error.rb'
32
33
  require_relative 'btcruby/script/script_flags.rb'
@@ -39,6 +40,10 @@ require_relative 'btcruby/script/signature_checker.rb'
39
40
  require_relative 'btcruby/script/test_signature_checker.rb'
40
41
  require_relative 'btcruby/script/transaction_signature_checker.rb'
41
42
 
43
+ require_relative 'btcruby/script/script_interpreter_plugin.rb'
44
+ require_relative 'btcruby/script/p2sh_plugin.rb'
45
+ require_relative 'btcruby/script/cltv_plugin.rb'
46
+
42
47
  require_relative 'btcruby/transaction_builder.rb'
43
48
  require_relative 'btcruby/proof_of_work.rb'
44
49
  require_relative 'btcruby/block_header.rb'
@@ -269,7 +269,7 @@ module BTC
269
269
  # Nonce k is equal to HMAC-SHA256(data: hash, key: privkey)
270
270
  def ecdsa_signature(hash, privkey, normalized: true)
271
271
  raise ArgumentError, "Hash is missing" if !hash
272
- raise ArgumentError, "Cannot make a ECDSA signature without the private key" if !privkey
272
+ raise ArgumentError, "Private key is missing" if !privkey
273
273
 
274
274
  # ECDSA signature is a pair of numbers: (Kx, s)
275
275
  # Where Kx = x coordinate of k*G mod n (n is the order of secp256k1).
@@ -345,6 +345,10 @@ module BTC
345
345
  # Normalizes S value of the signature and returns normalized signature.
346
346
  # Returns nil if signature is completely invalid.
347
347
  def ecdsa_normalized_signature(signature)
348
+ ecdsa_reserialize_signature(signature, normalize_s: true)
349
+ end
350
+
351
+ def ecdsa_reserialize_signature(signature, normalize_s: false)
348
352
  raise ArgumentError, "Signature is missing" if !signature
349
353
 
350
354
  autorelease do |pool|
@@ -358,15 +362,19 @@ module BTC
358
362
  buf = FFI::MemoryPointer.from_string(signature)
359
363
  psig = d2i_ECDSA_SIG(nil, pointer_to_pointer(buf), buf.size-1)
360
364
  if psig.null?
361
- raise BTCError, "OpenSSL failed to read ECDSA signature with DER: #{BTC.to_hex(signature).inspect}"
365
+ Diagnostics.current.add_message("OpenSSL failed to read ECDSA signature with DER during reserialize: #{BTC.to_hex(signature).inspect}")
366
+ return signature
367
+ #raise BTCError, "OpenSSL failed to read ECDSA signature with DER: #{BTC.to_hex(signature).inspect}"
362
368
  end
363
369
 
364
370
  sig = ECDSA_SIG.new(psig) # read sig from its pointer
365
- s = sig[:s]
366
-
367
- # Enforce low S values, by negating the value (modulo the order) if above order/2.
368
- if BN_cmp(s, halfn) > 0
369
- BN_sub(s, n, s)
371
+
372
+ if normalize_s
373
+ # Enforce low S values, by negating the value (modulo the order) if above order/2.
374
+ s = sig[:s]
375
+ if BN_cmp(s, halfn) > 0
376
+ BN_sub(s, n, s)
377
+ end
370
378
  end
371
379
 
372
380
  # Note: we'll place new s value back to s bignum,
@@ -393,6 +401,9 @@ module BTC
393
401
  raise ArgumentError, "Signature is missing" if !signature
394
402
  raise ArgumentError, "Hash is missing" if !hash
395
403
  raise ArgumentError, "Public key is missing" if !public_key
404
+
405
+ # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
406
+ signature = ecdsa_reserialize_signature(signature, normalize_s: false)
396
407
 
397
408
  autorelease do |pool|
398
409
  eckey = pool.new_ec_key
@@ -400,13 +411,14 @@ module BTC
400
411
  buf = FFI::MemoryPointer.from_string(public_key)
401
412
  eckey = o2i_ECPublicKey(pointer_to_pointer(eckey), pointer_to_pointer(buf), buf.size - 1)
402
413
  if eckey.null?
414
+ Diagnostics.current.add_message("OpenSSL failed to create EC_KEY with public key: #{BTC.to_hex(public_key).inspect}")
403
415
  raise BTCError, "OpenSSL failed to create EC_KEY with public key: #{BTC.to_hex(public_key).inspect}"
404
416
  end
405
417
 
406
418
  # -1 = error, 0 = bad sig, 1 = good
407
419
  hash_buf = FFI::MemoryPointer.from_string(hash)
408
420
  sig_buf = FFI::MemoryPointer.from_string(signature)
409
- result = ECDSA_verify(0, hash_buf, hash_buf.size-1, sig_buf, sig_buf.size-1, eckey)
421
+ result = ECDSA_verify(0, hash_buf, hash.bytesize, sig_buf, signature.bytesize, eckey)
410
422
 
411
423
  if result == 1
412
424
  return true
@@ -415,7 +427,9 @@ module BTC
415
427
  if result == 0
416
428
  Diagnostics.current.add_message("OpenSSL detected invalid ECDSA signature. Signature: #{BTC.to_hex(signature).inspect}; Hash: #{BTC.to_hex(hash).inspect}; Pubkey: #{BTC.to_hex(public_key).inspect}")
417
429
  else
418
- raise BTCError, "OpenSSL failed with error while verifying ECDSA signature. Signature: #{BTC.to_hex(signature).inspect}; Hash: #{BTC.to_hex(hash).inspect}; Pubkey: #{BTC.to_hex(public_key).inspect}"
430
+ Diagnostics.current.add_message("OpenSSL failed with error while verifying ECDSA signature. Signature: #{BTC.to_hex(signature).inspect}; Hash: #{BTC.to_hex(hash).inspect}; Pubkey: #{BTC.to_hex(public_key).inspect}; Result: #{result}")
431
+ return false
432
+ # raise BTCError, "OpenSSL failed with error while verifying ECDSA signature. Signature: #{BTC.to_hex(signature).inspect}; Hash: #{BTC.to_hex(hash).inspect}; Pubkey: #{BTC.to_hex(public_key).inspect}; Result: #{result}"
419
433
  end
420
434
  return false
421
435
  end
@@ -1,6 +1,9 @@
1
1
  module BTC
2
2
  # Represents a reference to a previous transaction.
3
- class TransactionOutpoint
3
+ class Outpoint
4
+ INVALID_INDEX = 0xFFFFFFFF # aka "(unsigned int) -1" in BitcoinQT.
5
+ ZERO_HASH256 = ("\x00".b*32).freeze
6
+
4
7
  attr_accessor :transaction_hash
5
8
  attr_accessor :transaction_id
6
9
  attr_accessor :index
@@ -8,6 +11,9 @@ module BTC
8
11
  def initialize(transaction_hash: nil, transaction_id: nil, index: 0)
9
12
  @transaction_hash = transaction_hash
10
13
  self.transaction_id = transaction_id if transaction_id
14
+ while index < 0
15
+ index += 2**32
16
+ end
11
17
  @index = index
12
18
  end
13
19
 
@@ -22,6 +28,10 @@ module BTC
22
28
  def outpoint_id
23
29
  %{#{transaction_id}:#{index}}
24
30
  end
31
+
32
+ def null?
33
+ @index == INVALID_INDEX && @transaction_hash == ZERO_HASH256
34
+ end
25
35
 
26
36
  def ==(other)
27
37
  index == other.index &&
@@ -37,4 +47,7 @@ module BTC
37
47
  outpoint_id
38
48
  end
39
49
  end
50
+
51
+ # For backwards compatibility keep the longer name.
52
+ TransactionOutpoint = Outpoint
40
53
  end
@@ -0,0 +1,63 @@
1
+ module BTC
2
+ # Performs CHECKLOCKTIMEVERIFY (BIP65) evaluation
3
+ class CLTVPlugin
4
+ include ScriptInterpreterPlugin
5
+
6
+ # Default `locktime_max_size` is 5.
7
+ # Default `lock_time_checker` equals current interpreter's signature checker.
8
+ def initialize(locktime_max_size: nil, lock_time_checker: nil)
9
+ @locktime_max_size = locktime_max_size || 5
10
+ @lock_time_checker = lock_time_checker
11
+ end
12
+
13
+ def extra_flags
14
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
15
+ end
16
+
17
+ def should_handle_opcode(interpreter: nil, opcode: nil)
18
+ opcode == OP_CHECKLOCKTIMEVERIFY
19
+ end
20
+
21
+ # Returns `false` if failed to execute the opcode.
22
+ def handle_opcode(interpreter: nil, opcode: nil)
23
+ # We are not supposed to handle any other opcodes here.
24
+ return false if opcode != OP_CHECKLOCKTIMEVERIFY
25
+
26
+ if interpreter.stack.size < 1
27
+ return interpreter.set_error(SCRIPT_ERR_INVALID_STACK_OPERATION)
28
+ end
29
+
30
+ # Note that elsewhere numeric opcodes are limited to
31
+ # operands in the range -2**31+1 to 2**31-1, however it is
32
+ # legal for opcodes to produce results exceeding that
33
+ # range. This limitation is implemented by CScriptNum's
34
+ # default 4-byte limit.
35
+ #
36
+ # If we kept to that limit we'd have a year 2038 problem,
37
+ # even though the nLockTime field in transactions
38
+ # themselves is uint32 which only becomes meaningless
39
+ # after the year 2106.
40
+ #
41
+ # Thus as a special case we tell CScriptNum to accept up
42
+ # to 5-byte bignums, which are good until 2**39-1, well
43
+ # beyond the 2**32-1 limit of the nLockTime field itself.
44
+ locktime = interpreter.cast_to_number(interpreter.stack.last, max_size: @locktime_max_size)
45
+
46
+ # In the rare event that the argument may be < 0 due to
47
+ # some arithmetic being done first, you can always use
48
+ # 0 MAX CHECKLOCKTIMEVERIFY.
49
+ if locktime < 0
50
+ return interpreter.set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME)
51
+ end
52
+
53
+ # Actually compare the specified lock time with the transaction.
54
+ checker = @lock_time_checker || interpreter.signature_checker
55
+ if !checker.check_lock_time(locktime)
56
+ return interpreter.set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME)
57
+ end
58
+
59
+ return true
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,71 @@
1
+ module BTC
2
+ # Performs Pay-to-Script-Hash (BIP16) evaluation
3
+ class P2SHPlugin
4
+ include ScriptInterpreterPlugin
5
+
6
+ # Returns additional flags to be available to #flag? checks during script execution.
7
+ # This way one plugin can affect evaluation of another.
8
+ def extra_flags
9
+ SCRIPT_VERIFY_P2SH
10
+ end
11
+
12
+ # Every plugin gets this callback. If plugin return `false`, execution is stopped and interpreter returns `false`.
13
+ # Default value is `true`.
14
+ def did_execute_signature_script(interpreter: nil, signature_script: nil)
15
+ @signature_script = signature_script
16
+ @stack_copy = interpreter.stack.dup
17
+ true
18
+ end
19
+
20
+ def did_execute_output_script(interpreter: nil, output_script: nil)
21
+ # Cleanup ivars
22
+ stack_copy = @stack_copy
23
+ @stack_copy = nil
24
+
25
+ signature_script = @signature_script
26
+ @signature_script = nil
27
+
28
+ # If output script is not P2SH, do nothing.
29
+ return true if !output_script.p2sh?
30
+
31
+ # Additional validation for pay-to-script-hash (P2SH) transactions:
32
+
33
+ # scriptSig must be literals-only or validation fails
34
+ if !signature_script.data_only?
35
+ return interpreter.set_error(SCRIPT_ERR_SIG_PUSHONLY)
36
+ end
37
+
38
+ # Restore stack.
39
+ interpreter.stack = stack_copy
40
+
41
+ # stack cannot be empty here, because if it was the
42
+ # P2SH HASH <> EQUAL scriptPubKey would be evaluated with
43
+ # an empty stack and the EvalScript above would return false.
44
+ raise "Stack cannot be empty" if stack_copy.empty?
45
+
46
+ serialized_redeem_script = interpreter.stack.pop
47
+ begin
48
+ redeem_script = BTC::Script.new(data: serialized_redeem_script)
49
+ rescue => e
50
+ return interpreter.set_error(SCRIPT_ERR_BAD_OPCODE, "Failed to parse serialized redeem script for P2SH. #{e.message}")
51
+ end
52
+
53
+ # Actually execute the script.
54
+ if !interpreter.run_script(redeem_script)
55
+ # error is set in run_script
56
+ return false
57
+ end
58
+
59
+ if interpreter.stack.empty?
60
+ return interpreter.set_error(SCRIPT_ERR_EVAL_FALSE)
61
+ end
62
+
63
+ if interpreter.cast_to_bool(interpreter.stack.last) == false
64
+ return interpreter.set_error(SCRIPT_ERR_EVAL_FALSE)
65
+ end
66
+
67
+ return true
68
+ end
69
+
70
+ end
71
+ end
@@ -421,9 +421,11 @@ module BTC
421
421
 
422
422
  # Appends an opcode (Integer), pushdata (String) or Script and returns self.
423
423
  # If Array is passed, this method is recursively called for each element in the array.
424
- def <<(object)
424
+ def append(object)
425
425
  if object.is_a?(BTC::Script)
426
426
  append_script(object)
427
+ elsif object.is_a?(BTC::ScriptNumber)
428
+ append_pushdata(object.data)
427
429
  elsif object.is_a?(Integer)
428
430
  append_opcode(object)
429
431
  elsif object.is_a?(String)
@@ -439,6 +441,10 @@ module BTC
439
441
  end
440
442
  return self
441
443
  end
444
+
445
+ def <<(object)
446
+ append(object)
447
+ end
442
448
 
443
449
  # Returns a new instance with concatenation of two scripts.
444
450
  def +(other)
@@ -134,6 +134,6 @@ module BTC
134
134
  end
135
135
 
136
136
  if $0 == __FILE__
137
- puts BTC::ScriptError.new(BTC::ScriptError::SCRIPT_ERR_SIG_HIGH_S).inspect
137
+ puts BTC::ScriptError.new(BTC::SCRIPT_ERR_SIG_HIGH_S).inspect
138
138
  end
139
139
 
@@ -13,51 +13,88 @@ module BTC
13
13
  class ScriptInterpreter
14
14
  include ScriptFlags
15
15
 
16
+ # Flags specified for this interpreter, not including flags added by plugins.
16
17
  attr_accessor :flags
18
+ attr_accessor :plugins
17
19
  attr_accessor :signature_checker
20
+ attr_accessor :raise_on_failure
21
+ attr_accessor :max_pushdata_size
22
+ attr_accessor :max_op_count
23
+ attr_accessor :max_stack_size
24
+ attr_accessor :max_script_size
25
+ attr_accessor :integer_max_size
26
+ attr_accessor :locktime_max_size
27
+
28
+ # Execution state
18
29
  attr_accessor :stack
19
- attr_accessor :altstack
30
+ attr_reader :altstack
20
31
  attr_accessor :error # ScriptError instance
21
32
 
22
33
  # Instantiates interpreter with validation flags and an optional checker
23
34
  # (required if the scripts use signature-checking opcodes).
24
35
  # Checker can be transaction checker or block checker
25
36
  def initialize(flags: SCRIPT_VERIFY_NONE,
37
+ plugins: nil,
26
38
  signature_checker: nil,
27
39
  raise_on_failure: false,
28
40
  max_pushdata_size: MAX_SCRIPT_ELEMENT_SIZE,
29
41
  max_op_count: MAX_OPS_PER_SCRIPT,
30
42
  max_stack_size: MAX_STACK_SIZE,
43
+ max_script_size: MAX_SCRIPT_SIZE,
31
44
  integer_max_size: 4,
32
45
  locktime_max_size: 5)
33
46
  @flags = flags
47
+ @plugins = plugins || []
34
48
  @signature_checker = signature_checker
49
+
35
50
  @raise_on_failure = raise_on_failure
36
51
  @max_pushdata_size = max_pushdata_size
37
52
  @max_op_count = max_op_count
38
53
  @max_stack_size = max_stack_size
54
+ @max_script_size = max_script_size
39
55
  @integer_max_size = integer_max_size
40
56
  @locktime_max_size = locktime_max_size
41
-
42
- @stack = []
43
- @altstack = []
44
57
  end
45
58
 
46
59
  # Returns true if succeeded or false in case of failure.
47
60
  # If fails, sets the error attribute.
48
61
  def verify_script(signature_script: nil, output_script: nil)
49
62
 
63
+ @stack = []
64
+ @altstack = []
65
+
50
66
  if flag?(SCRIPT_VERIFY_SIGPUSHONLY) && !signature_script.data_only?
51
67
  return set_error(SCRIPT_ERR_SIG_PUSHONLY)
52
68
  end
53
69
 
70
+ if plugin = plugin_to_handle_scripts(signature_script, output_script)
71
+ return plugin.handle_scripts(
72
+ interpreter: self,
73
+ signature_script: signature_script,
74
+ output_script: output_script
75
+ ) && verify_clean_stack_if_needed
76
+ end
77
+
54
78
  if !run_script(signature_script)
55
79
  # error is set in run_script
56
80
  return false
57
81
  end
58
82
 
59
- stack_copy = if flag?(SCRIPT_VERIFY_P2SH)
60
- @stack.dup
83
+ if !did_execute_signature_script(signature_script)
84
+ # error is set already
85
+ return false
86
+ end
87
+
88
+ # This is implemented in P2SHPlugin
89
+ # stack_copy = if flag?(SCRIPT_VERIFY_P2SH)
90
+ # @stack.dup
91
+ # end
92
+
93
+ if plugin = plugin_to_handle_output_script(output_script)
94
+ return plugin.handle_output_script(
95
+ interpreter: self,
96
+ output_script: output_script
97
+ ) && verify_clean_stack_if_needed
61
98
  end
62
99
 
63
100
  if !run_script(output_script)
@@ -73,58 +110,15 @@ module BTC
73
110
  return set_error(SCRIPT_ERR_EVAL_FALSE)
74
111
  end
75
112
 
76
- # Additional validation for pay-to-script-hash (P2SH) transactions:
77
- if flag?(SCRIPT_VERIFY_P2SH) && output_script.p2sh?
78
-
79
- # scriptSig must be literals-only or validation fails
80
- if !signature_script.data_only?
81
- return set_error(SCRIPT_ERR_SIG_PUSHONLY)
82
- end
83
-
84
- # Restore stack.
85
- @stack = stack_copy
86
-
87
- # stack cannot be empty here, because if it was the
88
- # P2SH HASH <> EQUAL scriptPubKey would be evaluated with
89
- # an empty stack and the EvalScript above would return false.
90
- raise "Stack cannot be empty" if @stack.empty?
91
-
92
- serialized_redeem_script = stack_pop
93
- begin
94
- redeem_script = BTC::Script.new(data: serialized_redeem_script)
95
- rescue => e
96
- return set_error(SCRIPT_ERR_BAD_OPCODE, "Failed to parse serialized redeem script for P2SH. #{e.message}")
97
- end
98
-
99
- if !run_script(redeem_script)
100
- # error is set in run_script
101
- return false
102
- end
103
-
104
- if @stack.empty?
105
- return set_error(SCRIPT_ERR_EVAL_FALSE)
106
- end
107
-
108
- if cast_to_bool(@stack.last) == false
109
- return set_error(SCRIPT_ERR_EVAL_FALSE)
110
- end
113
+ if !did_execute_output_script(output_script)
114
+ # error is set already
115
+ return false
111
116
  end
112
117
 
113
- # The CLEANSTACK check is only performed after potential P2SH evaluation,
114
- # as the non-P2SH evaluation of a P2SH script will obviously not result in
115
- # a clean stack (the P2SH inputs remain).
116
- if flag?(SCRIPT_VERIFY_CLEANSTACK)
117
- # Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
118
- # would be possible, which is not a softfork (and P2SH should be one).
119
- if !flag?(SCRIPT_VERIFY_P2SH)
120
- raise ArgumentError, "CLEANSTACK without P2SH is disallowed"
121
- end
122
- if @stack.size != 1
123
- return set_error(SCRIPT_ERR_CLEANSTACK, "Stack must be clean (should contain one item 'true')")
124
- end
125
- end
126
-
127
- return true
118
+ # Additional validation for pay-to-script-hash (P2SH) transactions:
119
+ # See P2SHPlugin#did_execute_output_script.
120
+
121
+ return verify_clean_stack_if_needed
128
122
  end
129
123
 
130
124
 
@@ -140,6 +134,13 @@ module BTC
140
134
  # Used internally in `verify_script` and also in unit tests.
141
135
  def run_script(script)
142
136
 
137
+ if script.data.bytesize > @max_script_size
138
+ return set_error(SCRIPT_ERR_SCRIPT_SIZE)
139
+ end
140
+
141
+ # Altstack is not shared between individual runs, but we still store it in ivar to make available to the plugins.
142
+ @altstack = []
143
+
143
144
  number_zero = ScriptNumber.new(integer: 0)
144
145
  number_one = ScriptNumber.new(integer: 1)
145
146
  zero_value = "".b
@@ -165,32 +166,45 @@ module BTC
165
166
  return set_error(SCRIPT_ERR_OP_COUNT)
166
167
  end
167
168
  end
168
-
169
- if opcode == OP_CAT ||
170
- opcode == OP_SUBSTR ||
171
- opcode == OP_LEFT ||
172
- opcode == OP_RIGHT ||
173
- opcode == OP_INVERT ||
174
- opcode == OP_AND ||
175
- opcode == OP_OR ||
176
- opcode == OP_XOR ||
177
- opcode == OP_2MUL ||
178
- opcode == OP_2DIV ||
179
- opcode == OP_MUL ||
180
- opcode == OP_DIV ||
181
- opcode == OP_MOD ||
182
- opcode == OP_LSHIFT ||
183
- opcode == OP_RSHIFT
184
-
185
- return set_error(SCRIPT_ERR_DISABLED_OPCODE)
169
+
170
+ # Check if there is a plugin for this opcode before we check for disabled opcodes.
171
+ opcode_plugin = plugin_to_handle_opcode(opcode)
172
+
173
+ if !opcode_plugin
174
+ if opcode == OP_CAT ||
175
+ opcode == OP_SUBSTR ||
176
+ opcode == OP_LEFT ||
177
+ opcode == OP_RIGHT ||
178
+ opcode == OP_INVERT ||
179
+ opcode == OP_AND ||
180
+ opcode == OP_OR ||
181
+ opcode == OP_XOR ||
182
+ opcode == OP_2MUL ||
183
+ opcode == OP_2DIV ||
184
+ opcode == OP_MUL ||
185
+ opcode == OP_DIV ||
186
+ opcode == OP_MOD ||
187
+ opcode == OP_LSHIFT ||
188
+ opcode == OP_RSHIFT
189
+
190
+ return set_error(SCRIPT_ERR_DISABLED_OPCODE)
191
+ end
186
192
  end
187
193
 
188
194
  if should_execute && 0 <= opcode && opcode <= OP_PUSHDATA4
189
195
  # Pushdata (including OP_0).
190
- if require_minimal && !chunk.canonical?
196
+ if require_minimal && !check_minimal_push(chunk.pushdata, opcode)
191
197
  return set_error(SCRIPT_ERR_MINIMALDATA)
192
198
  end
193
199
  stack_push(chunk.pushdata)
200
+
201
+ elsif should_execute && opcode_plugin
202
+
203
+ if !opcode_plugin.handle_opcode(interpreter: self, opcode: opcode)
204
+ # error is set already
205
+ return false
206
+ end
207
+
194
208
  elsif should_execute || (OP_IF <= opcode && opcode <= OP_ENDIF)
195
209
 
196
210
  case opcode
@@ -207,47 +221,50 @@ module BTC
207
221
 
208
222
  when OP_NOP
209
223
  # nothing
210
-
211
- when OP_CHECKLOCKTIMEVERIFY
212
- if !flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
213
- # not enabled; treat as a NOP2
214
- if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
215
- return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS)
216
- end
217
- break
218
- end
219
-
220
- if @stack.size < 1
221
- return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION)
222
- end
223
-
224
- # Note that elsewhere numeric opcodes are limited to
225
- # operands in the range -2**31+1 to 2**31-1, however it is
226
- # legal for opcodes to produce results exceeding that
227
- # range. This limitation is implemented by CScriptNum's
228
- # default 4-byte limit.
229
- #
230
- # If we kept to that limit we'd have a year 2038 problem,
231
- # even though the nLockTime field in transactions
232
- # themselves is uint32 which only becomes meaningless
233
- # after the year 2106.
234
- #
235
- # Thus as a special case we tell CScriptNum to accept up
236
- # to 5-byte bignums, which are good until 2**39-1, well
237
- # beyond the 2**32-1 limit of the nLockTime field itself.
238
- locktime = cast_to_number(@stack.last, max_size: @locktime_max_size)
239
-
240
- # In the rare event that the argument may be < 0 due to
241
- # some arithmetic being done first, you can always use
242
- # 0 MAX CHECKLOCKTIMEVERIFY.
243
- if locktime < 0
244
- return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME)
245
- end
246
-
247
- # Actually compare the specified lock time with the transaction.
248
- if !signature_checker.check_lock_time(locktime)
249
- return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME)
250
- end
224
+
225
+ # See CLTVPlugin
226
+ # when OP_CHECKLOCKTIMEVERIFY
227
+ # begin
228
+ # if !flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
229
+ # # not enabled; treat as a NOP2
230
+ # if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
231
+ # return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS)
232
+ # end
233
+ # break # breaks out of begin ... end while false
234
+ # end
235
+ #
236
+ # if @stack.size < 1
237
+ # return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION)
238
+ # end
239
+ #
240
+ # # Note that elsewhere numeric opcodes are limited to
241
+ # # operands in the range -2**31+1 to 2**31-1, however it is
242
+ # # legal for opcodes to produce results exceeding that
243
+ # # range. This limitation is implemented by CScriptNum's
244
+ # # default 4-byte limit.
245
+ # #
246
+ # # If we kept to that limit we'd have a year 2038 problem,
247
+ # # even though the nLockTime field in transactions
248
+ # # themselves is uint32 which only becomes meaningless
249
+ # # after the year 2106.
250
+ # #
251
+ # # Thus as a special case we tell CScriptNum to accept up
252
+ # # to 5-byte bignums, which are good until 2**39-1, well
253
+ # # beyond the 2**32-1 limit of the nLockTime field itself.
254
+ # locktime = cast_to_number(@stack.last, max_size: @locktime_max_size)
255
+ #
256
+ # # In the rare event that the argument may be < 0 due to
257
+ # # some arithmetic being done first, you can always use
258
+ # # 0 MAX CHECKLOCKTIMEVERIFY.
259
+ # if locktime < 0
260
+ # return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME)
261
+ # end
262
+ #
263
+ # # Actually compare the specified lock time with the transaction.
264
+ # if !signature_checker.check_lock_time(locktime)
265
+ # return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME)
266
+ # end
267
+ # end while false
251
268
 
252
269
  when OP_NOP1..OP_NOP10
253
270
  if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@@ -567,9 +584,9 @@ module BTC
567
584
  when OP_GREATERTHANOREQUAL
568
585
  bn = ScriptNumber.new(boolean: (bn1 >= bn2))
569
586
  when OP_MIN
570
- bn = ScriptNumber.new(boolean: (bn1 < bn2 ? bn1 : bn2))
587
+ bn = (bn1 < bn2 ? bn1 : bn2)
571
588
  when OP_MAX
572
- bn = ScriptNumber.new(boolean: (bn1 > bn2 ? bn1 : bn2))
589
+ bn = (bn1 > bn2 ? bn1 : bn2)
573
590
  else
574
591
  raise "Invalid opcode"
575
592
  end
@@ -775,7 +792,7 @@ module BTC
775
792
  end
776
793
 
777
794
  else # unknown opcode
778
- return set_error(SCRIPT_ERR_BAD_OPCODE)
795
+ return set_error(SCRIPT_ERR_BAD_OPCODE, "Unknown opcode 0x#{opcode.to_s(16)}")
779
796
 
780
797
  end # case opcode
781
798
  end # within IF scope
@@ -792,6 +809,8 @@ module BTC
792
809
  end
793
810
 
794
811
  return true
812
+ rescue ScriptNumberError => e
813
+ return set_error(SCRIPT_ERR_UNKNOWN_ERROR, e.message)
795
814
  end # run_script
796
815
 
797
816
 
@@ -806,6 +825,30 @@ module BTC
806
825
  #puts "PUSHED TO STACK: #{@stack.map{|s|s.to_hex}.join(' ')}"
807
826
  end
808
827
 
828
+ # aka CheckMinimalPush(const valtype& data, opcodetype opcode)
829
+ def check_minimal_push(data, opcode)
830
+ if data.bytesize == 0
831
+ # Could have used OP_0.
832
+ return opcode == OP_0
833
+ elsif data.bytesize == 1 && data.bytes[0] >= 1 && data.bytes[0] <= 16
834
+ # Could have used OP_1 .. OP_16.
835
+ return opcode == OP_1 + (data.bytes[0] - 1)
836
+ elsif data.bytesize == 1 && data.bytes[0] == 0x81
837
+ # Could have used OP_1NEGATE.
838
+ return opcode == OP_1NEGATE
839
+ elsif data.bytesize <= 75
840
+ # Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
841
+ return opcode == data.bytesize
842
+ elsif data.bytesize <= 255
843
+ # Could have used OP_PUSHDATA.
844
+ return opcode == OP_PUSHDATA1
845
+ elsif (data.bytesize <= 65535)
846
+ # Could have used OP_PUSHDATA2.
847
+ return opcode == OP_PUSHDATA2
848
+ end
849
+ return true
850
+ end
851
+
809
852
  def check_signature_encoding(sig)
810
853
  # Empty signature. Not strictly DER encoded, but allowed to provide a
811
854
  # compact way to provide an invalid signature for use with CHECK(MULTI)SIG
@@ -847,7 +890,13 @@ module BTC
847
890
 
848
891
  # If multiple flags are provided, returns true if any of them are present
849
892
  def flag?(flags)
850
- (@flags & flags) != 0
893
+ (all_flags & flags) != 0
894
+ end
895
+
896
+ def all_flags
897
+ @plugins.inject(@flags) do |f, p|
898
+ f | p.extra_flags
899
+ end
851
900
  end
852
901
 
853
902
  def cast_to_number(data,
@@ -876,6 +925,67 @@ module BTC
876
925
  false
877
926
  end
878
927
 
928
+ private
929
+
930
+ def plugin_to_handle_scripts(signature_script, output_script)
931
+ @plugins.each do |plugin|
932
+ if plugin.should_handle_scripts(interpreter: self, signature_script: signature_script, output_script: output_script)
933
+ return plugin
934
+ end
935
+ end
936
+ nil
937
+ end
938
+
939
+ def plugin_to_handle_output_script(output_script)
940
+ @plugins.each do |plugin|
941
+ if plugin.should_handle_output_script(interpreter: self, output_script: output_script)
942
+ return plugin
943
+ end
944
+ end
945
+ nil
946
+ end
947
+
948
+ def plugin_to_handle_opcode(opcode)
949
+ @plugins.each do |plugin|
950
+ if plugin.should_handle_opcode(interpreter: self, opcode: opcode)
951
+ return plugin
952
+ end
953
+ end
954
+ nil
955
+ end
956
+
957
+ def did_execute_signature_script(signature_script)
958
+ @plugins.each do |plugin|
959
+ if !plugin.did_execute_signature_script(interpreter: self, signature_script: signature_script)
960
+ return false
961
+ end
962
+ end
963
+ end
964
+
965
+ def did_execute_output_script(output_script)
966
+ @plugins.each do |plugin|
967
+ if !plugin.did_execute_output_script(interpreter: self, output_script: output_script)
968
+ return false
969
+ end
970
+ end
971
+ end
972
+
973
+ def verify_clean_stack_if_needed
974
+ # The CLEANSTACK check is only performed after potential P2SH evaluation,
975
+ # as the non-P2SH evaluation of a P2SH script will obviously not result in
976
+ # a clean stack (the P2SH inputs remain).
977
+ if flag?(SCRIPT_VERIFY_CLEANSTACK)
978
+ # Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
979
+ # would be possible, which is not a softfork (and P2SH should be one).
980
+ if !flag?(SCRIPT_VERIFY_P2SH)
981
+ raise ArgumentError, "CLEANSTACK without P2SH is disallowed"
982
+ end
983
+ if @stack.size != 1
984
+ return set_error(SCRIPT_ERR_CLEANSTACK, "Stack must be clean (should contain one item 'true')")
985
+ end
986
+ end
987
+ return true
988
+ end
879
989
 
880
990
  end
881
991
  end