btcruby 1.1.6 → 1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/btcruby/script/{cltv_plugin.rb → cltv_extension.rb} +2 -2
- data/lib/btcruby/script/{p2sh_plugin.rb → p2sh_extension.rb} +4 -4
- data/lib/btcruby/script/script_interpreter.rb +34 -34
- data/lib/btcruby/script/{script_interpreter_plugin.rb → script_interpreter_extension.rb} +10 -10
- data/lib/btcruby/version.rb +1 -1
- data/lib/btcruby.rb +3 -3
- data/spec/script_interpreter_spec.rb +4 -4
- data/spec/transaction_spec.rb +8 -8
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69203af0ce59eee2b3131a2df44cae9a7ca517be
|
4
|
+
data.tar.gz: f5fc80c6a9fed850298d7eb9b5812af45474e0d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82f4dcc9b9114d38049baddc9675bbbde98ced25699cf4c03f9ff01c83217e265c06d096b6d945e967424ddad6b2975b755d821d5bfaecb1e9553b97c52d9bb3
|
7
|
+
data.tar.gz: 4818136ee80be83560ed4432889eb80de6b14973f1f8448cadebfc35cd47103f6ede63753656fc3b9ffcb32bdf814381abce98fd8dcd4d240f182182075bd497
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module BTC
|
2
2
|
# Performs CHECKLOCKTIMEVERIFY (BIP65) evaluation
|
3
|
-
class
|
4
|
-
include
|
3
|
+
class CLTVExtension
|
4
|
+
include ScriptInterpreterExtension
|
5
5
|
|
6
6
|
# Default `locktime_max_size` is 5.
|
7
7
|
# Default `lock_time_checker` equals current interpreter's signature checker.
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module BTC
|
2
2
|
# Performs Pay-to-Script-Hash (BIP16) evaluation
|
3
|
-
class
|
4
|
-
include
|
3
|
+
class P2SHExtension
|
4
|
+
include ScriptInterpreterExtension
|
5
5
|
|
6
6
|
# Returns additional flags to be available to #flag? checks during script execution.
|
7
|
-
# This way one
|
7
|
+
# This way one extension can affect evaluation of another.
|
8
8
|
def extra_flags
|
9
9
|
SCRIPT_VERIFY_P2SH
|
10
10
|
end
|
11
11
|
|
12
|
-
# Every
|
12
|
+
# Every extension gets this callback. If extension return `false`, execution is stopped and interpreter returns `false`.
|
13
13
|
# Default value is `true`.
|
14
14
|
def did_execute_signature_script(interpreter: nil, signature_script: nil)
|
15
15
|
@signature_script = signature_script
|
@@ -15,9 +15,9 @@ module BTC
|
|
15
15
|
include ScriptErrors
|
16
16
|
include Opcodes
|
17
17
|
|
18
|
-
# Flags specified for this interpreter, not including flags added by
|
18
|
+
# Flags specified for this interpreter, not including flags added by extensions.
|
19
19
|
attr_accessor :flags
|
20
|
-
attr_accessor :
|
20
|
+
attr_accessor :extensions
|
21
21
|
attr_accessor :signature_checker
|
22
22
|
attr_accessor :raise_on_failure
|
23
23
|
attr_accessor :max_pushdata_size
|
@@ -36,7 +36,7 @@ module BTC
|
|
36
36
|
# (required if the scripts use signature-checking opcodes).
|
37
37
|
# Checker can be transaction checker or block checker
|
38
38
|
def initialize(flags: SCRIPT_VERIFY_NONE,
|
39
|
-
|
39
|
+
extensions: nil,
|
40
40
|
signature_checker: nil,
|
41
41
|
raise_on_failure: false,
|
42
42
|
max_pushdata_size: MAX_SCRIPT_ELEMENT_SIZE,
|
@@ -46,7 +46,7 @@ module BTC
|
|
46
46
|
integer_max_size: 4,
|
47
47
|
locktime_max_size: 5)
|
48
48
|
@flags = flags
|
49
|
-
@
|
49
|
+
@extensions = extensions || []
|
50
50
|
@signature_checker = signature_checker
|
51
51
|
|
52
52
|
@raise_on_failure = raise_on_failure
|
@@ -69,8 +69,8 @@ module BTC
|
|
69
69
|
return set_error(SCRIPT_ERR_SIG_PUSHONLY)
|
70
70
|
end
|
71
71
|
|
72
|
-
if
|
73
|
-
return
|
72
|
+
if extension = extension_to_handle_scripts(signature_script, output_script)
|
73
|
+
return extension.handle_scripts(
|
74
74
|
interpreter: self,
|
75
75
|
signature_script: signature_script,
|
76
76
|
output_script: output_script
|
@@ -87,13 +87,13 @@ module BTC
|
|
87
87
|
return false
|
88
88
|
end
|
89
89
|
|
90
|
-
# This is implemented in
|
90
|
+
# This is implemented in P2SHExtension
|
91
91
|
# stack_copy = if flag?(SCRIPT_VERIFY_P2SH)
|
92
92
|
# @stack.dup
|
93
93
|
# end
|
94
94
|
|
95
|
-
if
|
96
|
-
return
|
95
|
+
if extension = extension_to_handle_output_script(output_script)
|
96
|
+
return extension.handle_output_script(
|
97
97
|
interpreter: self,
|
98
98
|
output_script: output_script
|
99
99
|
) && verify_clean_stack_if_needed
|
@@ -118,7 +118,7 @@ module BTC
|
|
118
118
|
end
|
119
119
|
|
120
120
|
# Additional validation for pay-to-script-hash (P2SH) transactions:
|
121
|
-
# See
|
121
|
+
# See P2SHExtension#did_execute_output_script.
|
122
122
|
|
123
123
|
return verify_clean_stack_if_needed
|
124
124
|
end
|
@@ -140,7 +140,7 @@ module BTC
|
|
140
140
|
return set_error(SCRIPT_ERR_SCRIPT_SIZE)
|
141
141
|
end
|
142
142
|
|
143
|
-
# Altstack is not shared between individual runs, but we still store it in ivar to make available to the
|
143
|
+
# Altstack is not shared between individual runs, but we still store it in ivar to make available to the extensions.
|
144
144
|
@altstack = []
|
145
145
|
|
146
146
|
number_zero = ScriptNumber.new(integer: 0)
|
@@ -169,10 +169,10 @@ module BTC
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
|
-
# Check if there is a
|
173
|
-
|
172
|
+
# Check if there is a extension for this opcode before we check for disabled opcodes.
|
173
|
+
opcode_extension = extension_to_handle_opcode(opcode)
|
174
174
|
|
175
|
-
if !
|
175
|
+
if !opcode_extension
|
176
176
|
if opcode == OP_CAT ||
|
177
177
|
opcode == OP_SUBSTR ||
|
178
178
|
opcode == OP_LEFT ||
|
@@ -200,9 +200,9 @@ module BTC
|
|
200
200
|
end
|
201
201
|
stack_push(chunk.pushdata)
|
202
202
|
|
203
|
-
elsif should_execute &&
|
203
|
+
elsif should_execute && opcode_extension
|
204
204
|
|
205
|
-
if !
|
205
|
+
if !opcode_extension.handle_opcode(interpreter: self, opcode: opcode)
|
206
206
|
# error is set already
|
207
207
|
return false
|
208
208
|
end
|
@@ -224,7 +224,7 @@ module BTC
|
|
224
224
|
when OP_NOP
|
225
225
|
# nothing
|
226
226
|
|
227
|
-
# See
|
227
|
+
# See CLTVExtension
|
228
228
|
# when OP_CHECKLOCKTIMEVERIFY
|
229
229
|
# begin
|
230
230
|
# if !flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
@@ -896,7 +896,7 @@ module BTC
|
|
896
896
|
end
|
897
897
|
|
898
898
|
def all_flags
|
899
|
-
@
|
899
|
+
@extensions.inject(@flags) do |f, p|
|
900
900
|
f | p.extra_flags
|
901
901
|
end
|
902
902
|
end
|
@@ -929,44 +929,44 @@ module BTC
|
|
929
929
|
|
930
930
|
private
|
931
931
|
|
932
|
-
def
|
933
|
-
@
|
934
|
-
if
|
935
|
-
return
|
932
|
+
def extension_to_handle_scripts(signature_script, output_script)
|
933
|
+
@extensions.each do |extension|
|
934
|
+
if extension.should_handle_scripts(interpreter: self, signature_script: signature_script, output_script: output_script)
|
935
|
+
return extension
|
936
936
|
end
|
937
937
|
end
|
938
938
|
nil
|
939
939
|
end
|
940
940
|
|
941
|
-
def
|
942
|
-
@
|
943
|
-
if
|
944
|
-
return
|
941
|
+
def extension_to_handle_output_script(output_script)
|
942
|
+
@extensions.each do |extension|
|
943
|
+
if extension.should_handle_output_script(interpreter: self, output_script: output_script)
|
944
|
+
return extension
|
945
945
|
end
|
946
946
|
end
|
947
947
|
nil
|
948
948
|
end
|
949
949
|
|
950
|
-
def
|
951
|
-
@
|
952
|
-
if
|
953
|
-
return
|
950
|
+
def extension_to_handle_opcode(opcode)
|
951
|
+
@extensions.each do |extension|
|
952
|
+
if extension.should_handle_opcode(interpreter: self, opcode: opcode)
|
953
|
+
return extension
|
954
954
|
end
|
955
955
|
end
|
956
956
|
nil
|
957
957
|
end
|
958
958
|
|
959
959
|
def did_execute_signature_script(signature_script)
|
960
|
-
@
|
961
|
-
if !
|
960
|
+
@extensions.each do |extension|
|
961
|
+
if !extension.did_execute_signature_script(interpreter: self, signature_script: signature_script)
|
962
962
|
return false
|
963
963
|
end
|
964
964
|
end
|
965
965
|
end
|
966
966
|
|
967
967
|
def did_execute_output_script(output_script)
|
968
|
-
@
|
969
|
-
if !
|
968
|
+
@extensions.each do |extension|
|
969
|
+
if !extension.did_execute_output_script(interpreter: self, output_script: output_script)
|
970
970
|
return false
|
971
971
|
end
|
972
972
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module BTC
|
2
|
-
#
|
2
|
+
# ScriptInterpreterExtension allows adding extensions to the script machinery without requiring source code meddling.
|
3
3
|
# ScriptInterpreter provides several extension points:
|
4
4
|
# - extra flags (e.g. requirement for push-only opcodes in signature script)
|
5
5
|
# - pre-flight hook to completely take control over both scripts' execution
|
@@ -7,19 +7,19 @@ module BTC
|
|
7
7
|
# - interior hook to take control over output script execution after signature script is being executed
|
8
8
|
# - callback after output script execution
|
9
9
|
# - hook for handling the opcodes
|
10
|
-
module
|
10
|
+
module ScriptInterpreterExtension
|
11
11
|
include ScriptFlags
|
12
12
|
include ScriptErrors
|
13
13
|
include Opcodes
|
14
14
|
|
15
15
|
# Returns additional flags to be available to #flag? checks during script execution.
|
16
|
-
# This way one
|
16
|
+
# This way one extension can affect evaluation of another.
|
17
17
|
def extra_flags
|
18
18
|
0
|
19
19
|
end
|
20
20
|
|
21
|
-
# The first
|
22
|
-
# No other callbacks are called for this
|
21
|
+
# The first extension that returns true takes control over both scripts via `handle_scripts`.
|
22
|
+
# No other callbacks are called for this extension or any other.
|
23
23
|
# Default value is `false`.
|
24
24
|
def should_handle_scripts(interpreter: nil, signature_script: nil, output_script: nil)
|
25
25
|
false
|
@@ -30,14 +30,14 @@ module BTC
|
|
30
30
|
false
|
31
31
|
end
|
32
32
|
|
33
|
-
# Every
|
33
|
+
# Every extension gets this callback. If extension return `false`, execution is stopped and interpreter returns `false`.
|
34
34
|
# Default value is `true`.
|
35
35
|
def did_execute_signature_script(interpreter: nil, signature_script: nil)
|
36
36
|
true
|
37
37
|
end
|
38
38
|
|
39
|
-
# The first
|
40
|
-
# No other callbacks are called for this
|
39
|
+
# The first extension that returns true takes control over output script via #handle_output_script.
|
40
|
+
# No other callbacks are called for this extension or any other.
|
41
41
|
# Default value is `false`.
|
42
42
|
def should_handle_output_script(interpreter: nil, output_script: nil)
|
43
43
|
false
|
@@ -48,13 +48,13 @@ module BTC
|
|
48
48
|
false
|
49
49
|
end
|
50
50
|
|
51
|
-
# Every
|
51
|
+
# Every extension gets this callback. If extension return `false`, execution is stopped and interpreter returns `false`.
|
52
52
|
# Default value is `true`.
|
53
53
|
def did_execute_output_script(interpreter: nil, output_script: nil)
|
54
54
|
true
|
55
55
|
end
|
56
56
|
|
57
|
-
# The first
|
57
|
+
# The first extension that returns true takes control over that opcode.
|
58
58
|
# Default value is `false`.
|
59
59
|
def should_handle_opcode(interpreter: nil, opcode: nil)
|
60
60
|
false
|
data/lib/btcruby/version.rb
CHANGED
data/lib/btcruby.rb
CHANGED
@@ -41,9 +41,9 @@ require_relative 'btcruby/script/signature_checker.rb'
|
|
41
41
|
require_relative 'btcruby/script/test_signature_checker.rb'
|
42
42
|
require_relative 'btcruby/script/transaction_signature_checker.rb'
|
43
43
|
|
44
|
-
require_relative 'btcruby/script/
|
45
|
-
require_relative 'btcruby/script/
|
46
|
-
require_relative 'btcruby/script/
|
44
|
+
require_relative 'btcruby/script/script_interpreter_extension.rb'
|
45
|
+
require_relative 'btcruby/script/p2sh_extension.rb'
|
46
|
+
require_relative 'btcruby/script/cltv_extension.rb'
|
47
47
|
|
48
48
|
require_relative 'btcruby/transaction_builder.rb'
|
49
49
|
require_relative 'btcruby/proof_of_work.rb'
|
@@ -10,12 +10,12 @@ describe BTC::ScriptInterpreter do
|
|
10
10
|
def verify_script(sig_script, output_script, flags, expected_result, record)
|
11
11
|
tx = build_spending_transaction(sig_script, build_crediting_transaction(output_script));
|
12
12
|
checker = BTC::TransactionSignatureChecker.new(transaction: tx, input_index: 0)
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
extensions = []
|
14
|
+
extensions << BTC::P2SHExtension.new if (flags & BTC::ScriptFlags::SCRIPT_VERIFY_P2SH) != 0
|
15
|
+
extensions << BTC::CLTVExtension.new if (flags & BTC::ScriptFlags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) != 0
|
16
16
|
interpreter = BTC::ScriptInterpreter.new(
|
17
17
|
flags: flags,
|
18
|
-
|
18
|
+
extensions: extensions,
|
19
19
|
signature_checker: checker,
|
20
20
|
raise_on_failure: false,
|
21
21
|
)
|
data/spec/transaction_spec.rb
CHANGED
@@ -75,12 +75,12 @@ describe BTC::Transaction do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
checker = BTC::TransactionSignatureChecker.new(transaction: tx, input_index: txin.index)
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
extensions = []
|
79
|
+
extensions << BTC::P2SHExtension.new if (flags & BTC::ScriptFlags::SCRIPT_VERIFY_P2SH) != 0
|
80
|
+
extensions << BTC::CLTVExtension.new if (flags & BTC::ScriptFlags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) != 0
|
81
81
|
interpreter = BTC::ScriptInterpreter.new(
|
82
82
|
flags: flags,
|
83
|
-
|
83
|
+
extensions: extensions,
|
84
84
|
signature_checker: checker,
|
85
85
|
raise_on_failure: expected_result,
|
86
86
|
)
|
@@ -123,12 +123,12 @@ describe BTC::Transaction do
|
|
123
123
|
|
124
124
|
# def verify_script(tx, txin, sig_script, output_script, flags, expected_result, record)
|
125
125
|
# checker = TransactionSignatureChecker.new(transaction: tx, input_index: txin.index)
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
126
|
+
# extensions = []
|
127
|
+
# extensions << P2SHExtension.new if (flags & ScriptFlags::SCRIPT_VERIFY_P2SH) != 0
|
128
|
+
# extensions << CLTVExtension.new if (flags & ScriptFlags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) != 0
|
129
129
|
# interpreter = ScriptInterpreter.new(
|
130
130
|
# flags: flags,
|
131
|
-
#
|
131
|
+
# extensions: extensions,
|
132
132
|
# signature_checker: checker,
|
133
133
|
# raise_on_failure: expected_result,
|
134
134
|
# )
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: btcruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Andreev
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-08
|
12
|
+
date: 2015-09-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -104,15 +104,15 @@ files:
|
|
104
104
|
- lib/btcruby/outpoint.rb
|
105
105
|
- lib/btcruby/proof_of_work.rb
|
106
106
|
- lib/btcruby/safety.rb
|
107
|
-
- lib/btcruby/script/
|
107
|
+
- lib/btcruby/script/cltv_extension.rb
|
108
108
|
- lib/btcruby/script/opcode.rb
|
109
|
-
- lib/btcruby/script/
|
109
|
+
- lib/btcruby/script/p2sh_extension.rb
|
110
110
|
- lib/btcruby/script/script.rb
|
111
111
|
- lib/btcruby/script/script_chunk.rb
|
112
112
|
- lib/btcruby/script/script_error.rb
|
113
113
|
- lib/btcruby/script/script_flags.rb
|
114
114
|
- lib/btcruby/script/script_interpreter.rb
|
115
|
-
- lib/btcruby/script/
|
115
|
+
- lib/btcruby/script/script_interpreter_extension.rb
|
116
116
|
- lib/btcruby/script/script_number.rb
|
117
117
|
- lib/btcruby/script/signature_checker.rb
|
118
118
|
- lib/btcruby/script/signature_hashtype.rb
|