tapyrus 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/exe/tapyrus-script-debugger +131 -0
- data/lib/tapyrus/block_header.rb +1 -1
- data/lib/tapyrus/constants.rb +0 -2
- data/lib/tapyrus/script/script_interpreter.rb +441 -432
- data/lib/tapyrus/script/tx_checker.rb +5 -9
- data/lib/tapyrus/tx.rb +8 -17
- data/lib/tapyrus/tx_builder.rb +10 -5
- data/lib/tapyrus/version.rb +1 -1
- data/tapyrusrb.gemspec +1 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfdff40e4807919098065d5d956383663673f20a264d0eaadaa89124467166f8
|
4
|
+
data.tar.gz: 731e768f37f843fc6a03d337e8aea349d57f23449068356348d2bef171d02a2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0360ede886fe0a3512ea68e212270b5d931b8c085ceb04c6790978e325bc98b1d112d74deaa80232c97109c50ad8b1175566cb04ccd5324a218563677d90fbbd
|
7
|
+
data.tar.gz: 3f6f38a994e81c0b1d5157584cf14669ee7f8be612a6e878bf7cc216995ca60255a133b1b318e6210d6328015fdd99434bde021fd124bdc44454da564023ddab
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Tapyrusrb [](https://github.com/chaintope/tapyrusrb/actions/workflows/ruby.yml) [](https://badge.fury.io/rb/tapyrus) [](LICENSE)
|
2
2
|
|
3
3
|
Tapyrusrb is a Ruby implementation of [Tapyrus](https://github.com/chaintope/tapyrus-core) Protocol.
|
4
4
|
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tapyrus'
|
4
|
+
require 'terminal-table'
|
5
|
+
|
6
|
+
class EmptyTxChecker
|
7
|
+
def check_sig(script_sig, pubkey, script_code)
|
8
|
+
warn "Signature verification failed. You need to enter tx and input index."
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
def verify_sig(sig, pubkey, digest, allow_hybrid: false)
|
12
|
+
warn "Signature verification failed. You need to enter tx and input index."
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_step(interpreter, script, chunk, index, is_redeem_script)
|
18
|
+
if chunk.pushdata?
|
19
|
+
puts "PUSH #{chunk.pushed_data.bth}"
|
20
|
+
else
|
21
|
+
puts "APPLY #{Tapyrus::Opcodes.opcode_to_name(chunk.opcode)}"
|
22
|
+
end
|
23
|
+
result = interpreter.next_step(script, chunk, index, is_redeem_script)
|
24
|
+
if result.is_a?(FalseClass)
|
25
|
+
warn "script failed. Reason: #{interpreter.error}"
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
rows = interpreter.stack.map{|s|[s]}.reverse
|
29
|
+
table = Terminal::Table.new(title: 'Current Stack', rows: rows )
|
30
|
+
puts table
|
31
|
+
end
|
32
|
+
|
33
|
+
print "Enter scriptPubkey: "
|
34
|
+
script_pubkey_hex = gets.chomp
|
35
|
+
script_pubkey = Tapyrus::Script.parse_from_payload(script_pubkey_hex.htb)
|
36
|
+
puts script_pubkey unless script_pubkey_hex.empty?
|
37
|
+
|
38
|
+
print "Enter scriptSig: "
|
39
|
+
script_sig_hex = gets.chomp
|
40
|
+
script_sig = Tapyrus::Script.parse_from_payload(script_sig_hex.htb)
|
41
|
+
puts script_sig unless script_sig_hex.empty?
|
42
|
+
|
43
|
+
unless script_sig.push_only?
|
44
|
+
warn "scriptSig has non-push opcode."
|
45
|
+
puts
|
46
|
+
end
|
47
|
+
|
48
|
+
if script_pubkey_hex.empty? && script_sig.empty?
|
49
|
+
puts "Empty script."
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
|
53
|
+
print "Enter tx: "
|
54
|
+
tx_hex = gets.chomp
|
55
|
+
if tx_hex.length == 0
|
56
|
+
tx_checker = EmptyTxChecker.new
|
57
|
+
else
|
58
|
+
print "Enter index of the input: "
|
59
|
+
input_index = gets.chomp
|
60
|
+
tx_checker = Tapyrus::TxChecker.new
|
61
|
+
begin
|
62
|
+
tx_checker.tx = Tapyrus::Tx.parse_from_payload(tx_hex.htb)
|
63
|
+
rescue StandardError
|
64
|
+
warn "Invalid tx data."
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
if input_index.empty?
|
68
|
+
warn "Index of input missing."
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
tx_checker.input_index = input_index.to_i
|
72
|
+
if (tx_checker.tx.in.size - 1) < tx_checker.input_index
|
73
|
+
warn "Tx does not have #{tx_checker.input_index}-th input."
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
interpreter = Tapyrus::ScriptInterpreter.new(checker: tx_checker)
|
79
|
+
|
80
|
+
target_script = script_sig
|
81
|
+
is_redeem = false
|
82
|
+
interpreter.reset_params
|
83
|
+
chunks = target_script.chunks.each
|
84
|
+
chunk_index = 0
|
85
|
+
chunks_size = target_script.chunks.length
|
86
|
+
stack_copy = nil
|
87
|
+
|
88
|
+
puts "The Script is ready to be executed; you can step execution it by putting the Enter key."
|
89
|
+
print "> "
|
90
|
+
while cmd = gets.chomp
|
91
|
+
if cmd.length == 0
|
92
|
+
if chunks_size == chunk_index
|
93
|
+
if target_script == script_sig
|
94
|
+
stack_copy = interpreter.stack.dup
|
95
|
+
target_script = script_pubkey
|
96
|
+
interpreter.reset_params
|
97
|
+
chunks = target_script.chunks.each
|
98
|
+
chunk_index = 0
|
99
|
+
chunks_size = target_script.chunks.length
|
100
|
+
elsif target_script == script_pubkey
|
101
|
+
if interpreter.stack.empty? || !interpreter.cast_to_bool(interpreter.stack.last.htb)
|
102
|
+
warn "Script evaluated without error but finished with a false/empty top stack element"
|
103
|
+
exit
|
104
|
+
end
|
105
|
+
if script_pubkey.p2sh?
|
106
|
+
interpreter.stack = stack_copy
|
107
|
+
redeem_script = Tapyrus::Script.parse_from_payload(interpreter.stack.pop.htb)
|
108
|
+
puts "APPLY P2SH: #{redeem_script}"
|
109
|
+
rows = interpreter.stack.map{|s|[s]}.reverse
|
110
|
+
table = Terminal::Table.new(title: 'Current Stack', rows: rows )
|
111
|
+
puts table
|
112
|
+
target_script = redeem_script
|
113
|
+
chunks = target_script.chunks.each
|
114
|
+
chunk_index = 0
|
115
|
+
chunks_size = target_script.chunks.length
|
116
|
+
else
|
117
|
+
puts "Execution finished."
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
else
|
121
|
+
puts "Execution finished."
|
122
|
+
exit
|
123
|
+
end
|
124
|
+
end
|
125
|
+
run_step(interpreter, target_script, chunks.next, chunk_index, is_redeem)
|
126
|
+
chunk_index += 1
|
127
|
+
else
|
128
|
+
puts "Put enter key to step execution or Ctrl+D to exit."
|
129
|
+
end
|
130
|
+
print "> "
|
131
|
+
end
|
data/lib/tapyrus/block_header.rb
CHANGED
@@ -104,7 +104,7 @@ module Tapyrus
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
# Check this header contains upgrade aggregated
|
107
|
+
# Check this header contains upgrade aggregated public key.
|
108
108
|
# @return [Boolean] if contains return true, otherwise false.
|
109
109
|
def upgrade_agg_pubkey?
|
110
110
|
x_field_type == X_FILED_TYPES[:aggregate_pubkey]
|
data/lib/tapyrus/constants.rb
CHANGED
@@ -2,13 +2,19 @@ module Tapyrus
|
|
2
2
|
class ScriptInterpreter
|
3
3
|
include Tapyrus::Opcodes
|
4
4
|
|
5
|
-
|
5
|
+
attr_accessor :stack
|
6
6
|
attr_reader :debug
|
7
7
|
attr_reader :flags
|
8
8
|
attr_accessor :error
|
9
9
|
attr_reader :checker
|
10
10
|
attr_reader :require_minimal
|
11
11
|
|
12
|
+
attr_accessor :flow_stack
|
13
|
+
attr_accessor :alt_stack
|
14
|
+
attr_accessor :last_code_separator_index
|
15
|
+
attr_accessor :op_count
|
16
|
+
attr_accessor :color_id
|
17
|
+
|
12
18
|
DISABLE_OPCODES = [
|
13
19
|
OP_CAT,
|
14
20
|
OP_SUBSTR,
|
@@ -51,11 +57,11 @@ module Tapyrus
|
|
51
57
|
|
52
58
|
stack_copy = nil
|
53
59
|
|
54
|
-
return false unless eval_script(script_sig,
|
60
|
+
return false unless eval_script(script_sig, false)
|
55
61
|
|
56
62
|
stack_copy = stack.dup if flag?(SCRIPT_VERIFY_P2SH)
|
57
63
|
|
58
|
-
return false unless eval_script(script_pubkey,
|
64
|
+
return false unless eval_script(script_pubkey, false)
|
59
65
|
|
60
66
|
return set_error(SCRIPT_ERR_EVAL_FALSE) if stack.empty? || !cast_to_bool(stack.last.htb)
|
61
67
|
|
@@ -70,7 +76,7 @@ module Tapyrus
|
|
70
76
|
rescue Exception => e
|
71
77
|
return set_error(SCRIPT_ERR_BAD_OPCODE, "Failed to parse serialized redeem script for P2SH. #{e.message}")
|
72
78
|
end
|
73
|
-
return false unless eval_script(redeem_script,
|
79
|
+
return false unless eval_script(redeem_script, true)
|
74
80
|
return set_error(SCRIPT_ERR_EVAL_FALSE) if stack.empty? || !cast_to_bool(stack.last)
|
75
81
|
end
|
76
82
|
|
@@ -92,457 +98,473 @@ module Tapyrus
|
|
92
98
|
false
|
93
99
|
end
|
94
100
|
|
95
|
-
def eval_script(script,
|
101
|
+
def eval_script(script, is_redeem_script)
|
96
102
|
return set_error(SCRIPT_ERR_SCRIPT_SIZE) if script.size > MAX_SCRIPT_SIZE
|
97
103
|
begin
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
104
|
+
reset_params
|
105
|
+
script.chunks.each_with_index do |chunk, index|
|
106
|
+
result = next_step(script, chunk, index, is_redeem_script)
|
107
|
+
return result if result.is_a?(FalseClass)
|
108
|
+
end
|
109
|
+
rescue Exception => e
|
110
|
+
puts e
|
111
|
+
puts e.backtrace
|
112
|
+
return set_error(SCRIPT_ERR_UNKNOWN_ERROR, e.message)
|
113
|
+
end
|
106
114
|
|
107
|
-
|
115
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) unless @flow_stack.empty?
|
108
116
|
|
109
|
-
|
117
|
+
set_error(SCRIPT_ERR_OK)
|
118
|
+
true
|
119
|
+
end
|
110
120
|
|
111
|
-
|
112
|
-
|
113
|
-
return set_error(SCRIPT_ERR_BAD_OPCODE) unless verify_pushdata_length(c)
|
114
|
-
stack << c.pushed_data.bth
|
115
|
-
else
|
116
|
-
if opcode > OP_16 && (op_count += 1) > MAX_OPS_PER_SCRIPT
|
117
|
-
return set_error(SCRIPT_ERR_OP_COUNT)
|
118
|
-
end
|
119
|
-
return set_error(SCRIPT_ERR_DISABLED_OPCODE) if DISABLE_OPCODES.include?(opcode)
|
120
|
-
if opcode == OP_CODESEPARATOR && sig_version == :base && flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE)
|
121
|
-
return set_error(SCRIPT_ERR_OP_CODESEPARATOR)
|
122
|
-
end
|
123
|
-
next unless (need_exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
124
|
-
small_int = Opcodes.opcode_to_small_int(opcode)
|
125
|
-
if small_int && opcode != OP_0
|
126
|
-
push_int(small_int)
|
127
|
-
else
|
128
|
-
case opcode
|
129
|
-
when OP_0
|
130
|
-
stack << ''
|
131
|
-
when OP_DEPTH
|
132
|
-
push_int(stack.size)
|
133
|
-
when OP_EQUAL, OP_EQUALVERIFY
|
134
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
135
|
-
a, b = pop_string(2)
|
136
|
-
result = a == b
|
137
|
-
push_int(result ? 1 : 0)
|
138
|
-
if opcode == OP_EQUALVERIFY
|
139
|
-
if result
|
140
|
-
stack.pop
|
141
|
-
else
|
142
|
-
return set_error(SCRIPT_ERR_EQUALVERIFY)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
when OP_0NOTEQUAL
|
146
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
147
|
-
push_int(pop_int == 0 ? 0 : 1)
|
148
|
-
when OP_ADD
|
149
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
150
|
-
a, b = pop_int(2)
|
151
|
-
push_int(a + b)
|
152
|
-
when OP_1ADD
|
153
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
154
|
-
push_int(pop_int + 1)
|
155
|
-
when OP_SUB
|
156
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
157
|
-
a, b = pop_int(2)
|
158
|
-
push_int(a - b)
|
159
|
-
when OP_1SUB
|
160
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
161
|
-
push_int(pop_int - 1)
|
162
|
-
when OP_IF, OP_NOTIF
|
163
|
-
result = false
|
164
|
-
if need_exec
|
165
|
-
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if stack.size < 1
|
166
|
-
value = pop_string.htb
|
167
|
-
if flag?(SCRIPT_VERIFY_MINIMALIF)
|
168
|
-
if value.bytesize > 1 || (value.bytesize == 1 && value[0].unpack('C').first != 1)
|
169
|
-
return set_error(SCRIPT_ERR_MINIMALIF)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
result = cast_to_bool(value)
|
173
|
-
result = !result if opcode == OP_NOTIF
|
174
|
-
end
|
175
|
-
flow_stack << result
|
176
|
-
when OP_ELSE
|
177
|
-
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if flow_stack.size < 1
|
178
|
-
flow_stack << !flow_stack.pop
|
179
|
-
when OP_ENDIF
|
180
|
-
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if flow_stack.empty?
|
181
|
-
flow_stack.pop
|
182
|
-
when OP_NOP
|
183
|
-
when OP_NOP1, OP_NOP4..OP_NOP10
|
184
|
-
if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
185
|
-
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS)
|
186
|
-
end
|
187
|
-
when OP_CHECKLOCKTIMEVERIFY
|
188
|
-
next unless flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
189
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
190
|
-
|
191
|
-
# Note that elsewhere numeric opcodes are limited to operands in the range -2**31+1 to 2**31-1,
|
192
|
-
# however it is legal for opcodes to produce results exceeding that range.
|
193
|
-
# This limitation is implemented by CScriptNum's default 4-byte limit.
|
194
|
-
# If we kept to that limit we'd have a year 2038 problem,
|
195
|
-
# even though the nLockTime field in transactions themselves is uint32 which only becomes meaningless after the year 2106.
|
196
|
-
# Thus as a special case we tell CScriptNum to accept up to 5-byte bignums,
|
197
|
-
# which are good until 2**39-1, well beyond the 2**32-1 limit of the nLockTime field itself.
|
198
|
-
locktime = cast_to_int(stack.last, 5)
|
199
|
-
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if locktime < 0
|
200
|
-
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME) unless checker.check_locktime(locktime)
|
201
|
-
when OP_CHECKSEQUENCEVERIFY
|
202
|
-
next unless flag?(SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
203
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
204
|
-
|
205
|
-
# nSequence, like nLockTime, is a 32-bit unsigned integer field.
|
206
|
-
# See the comment in CHECKLOCKTIMEVERIFY regarding 5-byte numeric operands.
|
207
|
-
sequence = cast_to_int(stack.last, 5)
|
208
|
-
|
209
|
-
# In the rare event that the argument may be < 0 due to some arithmetic being done first,
|
210
|
-
# you can always use 0 MAX CHECKSEQUENCEVERIFY.
|
211
|
-
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if sequence < 0
|
212
|
-
|
213
|
-
# To provide for future soft-fork extensibility,
|
214
|
-
# if the operand has the disabled lock-time flag set, CHECKSEQUENCEVERIFY behaves as a NOP.
|
215
|
-
next if (sequence & Tapyrus::TxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0
|
216
|
-
|
217
|
-
# Compare the specified sequence number with the input.
|
218
|
-
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME) unless checker.check_sequence(sequence)
|
219
|
-
when OP_DUP
|
220
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
221
|
-
stack << stack.last
|
222
|
-
when OP_2DUP
|
223
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
224
|
-
2.times { stack << stack[-2] }
|
225
|
-
when OP_3DUP
|
226
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
227
|
-
3.times { stack << stack[-3] }
|
228
|
-
when OP_IFDUP
|
229
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
230
|
-
stack << stack.last if cast_to_bool(stack.last)
|
231
|
-
when OP_RIPEMD160
|
232
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
233
|
-
stack << Digest::RMD160.hexdigest(pop_string.htb)
|
234
|
-
when OP_SHA1
|
235
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
236
|
-
stack << Digest::SHA1.hexdigest(pop_string.htb)
|
237
|
-
when OP_SHA256
|
238
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
239
|
-
stack << Digest::SHA256.hexdigest(pop_string.htb)
|
240
|
-
when OP_HASH160
|
241
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
242
|
-
stack << Tapyrus.hash160(pop_string)
|
243
|
-
when OP_HASH256
|
244
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
245
|
-
stack << Tapyrus.double_sha256(pop_string.htb).bth
|
246
|
-
when OP_VERIFY
|
247
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
248
|
-
return set_error(SCRIPT_ERR_VERIFY) unless pop_bool
|
249
|
-
when OP_TOALTSTACK
|
250
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
251
|
-
alt_stack << stack.pop
|
252
|
-
when OP_FROMALTSTACK
|
253
|
-
return set_error(SCRIPT_ERR_INVALID_ALTSTACK_OPERATION) if alt_stack.size < 1
|
254
|
-
stack << alt_stack.pop
|
255
|
-
when OP_DROP
|
256
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
257
|
-
stack.pop
|
258
|
-
when OP_2DROP
|
259
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
260
|
-
2.times { stack.pop }
|
261
|
-
when OP_NIP
|
262
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
263
|
-
stack.delete_at(-2)
|
264
|
-
when OP_OVER
|
265
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
266
|
-
stack << stack[-2]
|
267
|
-
when OP_2OVER
|
268
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 4
|
269
|
-
2.times { stack << stack[-4] }
|
270
|
-
when OP_PICK, OP_ROLL
|
271
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
272
|
-
pos = pop_int
|
273
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if pos < 0 || pos >= stack.size
|
274
|
-
stack << stack[-pos - 1]
|
275
|
-
stack.delete_at(-pos - 2) if opcode == OP_ROLL
|
276
|
-
when OP_ROT
|
277
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
278
|
-
stack << stack[-3]
|
279
|
-
stack.delete_at(-4)
|
280
|
-
when OP_2ROT
|
281
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 6
|
282
|
-
2.times { stack << stack[-6] }
|
283
|
-
2.times { stack.delete_at(-7) }
|
284
|
-
when OP_SWAP
|
285
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
286
|
-
tmp = stack.last
|
287
|
-
stack[-1] = stack[-2]
|
288
|
-
stack[-2] = tmp
|
289
|
-
when OP_2SWAP
|
290
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 4
|
291
|
-
2.times { stack << stack[-4] }
|
292
|
-
2.times { stack.delete_at(-5) }
|
293
|
-
when OP_TUCK
|
294
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
295
|
-
stack.insert(-3, stack.last)
|
296
|
-
when OP_ABS
|
297
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
298
|
-
v = pop_int
|
299
|
-
push_int(v.abs)
|
300
|
-
when OP_BOOLAND
|
301
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
302
|
-
a, b = pop_int(2)
|
303
|
-
push_int((!a.zero? && !b.zero?) ? 1 : 0)
|
304
|
-
when OP_BOOLOR
|
305
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
306
|
-
a, b = pop_int(2)
|
307
|
-
push_int((!a.zero? || !b.zero?) ? 1 : 0)
|
308
|
-
when OP_NUMEQUAL, OP_NUMEQUALVERIFY
|
309
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
310
|
-
a, b = pop_int(2)
|
311
|
-
result = a == b
|
312
|
-
push_int(result ? 1 : 0)
|
313
|
-
if opcode == OP_NUMEQUALVERIFY
|
314
|
-
if result
|
315
|
-
stack.pop
|
316
|
-
else
|
317
|
-
return set_error(SCRIPT_ERR_NUMEQUALVERIFY)
|
318
|
-
end
|
319
|
-
end
|
320
|
-
when OP_LESSTHAN, OP_LESSTHANOREQUAL
|
321
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
322
|
-
a, b = pop_int(2)
|
323
|
-
push_int(a < b ? 1 : 0) if opcode == OP_LESSTHAN
|
324
|
-
push_int(a <= b ? 1 : 0) if opcode == OP_LESSTHANOREQUAL
|
325
|
-
when OP_GREATERTHAN, OP_GREATERTHANOREQUAL
|
326
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
327
|
-
a, b = pop_int(2)
|
328
|
-
push_int(a > b ? 1 : 0) if opcode == OP_GREATERTHAN
|
329
|
-
push_int(a >= b ? 1 : 0) if opcode == OP_GREATERTHANOREQUAL
|
330
|
-
when OP_MIN
|
331
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
332
|
-
push_int(pop_int(2).min)
|
333
|
-
when OP_MAX
|
334
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
335
|
-
push_int(pop_int(2).max)
|
336
|
-
when OP_WITHIN
|
337
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
338
|
-
x, a, b = pop_int(3)
|
339
|
-
push_int((a <= x && x < b) ? 1 : 0)
|
340
|
-
when OP_NOT
|
341
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
342
|
-
push_int(pop_int == 0 ? 1 : 0)
|
343
|
-
when OP_SIZE
|
344
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
345
|
-
item = stack.last
|
346
|
-
item = Tapyrus::Script.encode_number(item) if item.is_a?(Numeric)
|
347
|
-
size = item.htb.bytesize
|
348
|
-
push_int(size)
|
349
|
-
when OP_NEGATE
|
350
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
351
|
-
push_int(-pop_int)
|
352
|
-
when OP_NUMNOTEQUAL
|
353
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
354
|
-
a, b = pop_int(2)
|
355
|
-
push_int(a == b ? 0 : 1)
|
356
|
-
when OP_CODESEPARATOR
|
357
|
-
last_code_separator_index = index + 1
|
358
|
-
when OP_CHECKSIG, OP_CHECKSIGVERIFY
|
359
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
360
|
-
sig, pubkey = pop_string(2)
|
361
|
-
|
362
|
-
subscript = script.subscript(last_code_separator_index..-1)
|
363
|
-
if sig_version == :base
|
364
|
-
tmp = subscript.find_and_delete(Script.new << sig)
|
365
|
-
if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
366
|
-
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE)
|
367
|
-
end
|
368
|
-
subscript = tmp
|
369
|
-
end
|
370
|
-
if (
|
371
|
-
if sig.htb.bytesize == Tapyrus::Key::COMPACT_SIGNATURE_SIZE
|
372
|
-
!check_schnorr_signature_encoding(sig)
|
373
|
-
else
|
374
|
-
!check_ecdsa_signature_encoding(sig)
|
375
|
-
end
|
376
|
-
) || !check_pubkey_encoding(pubkey)
|
377
|
-
return false
|
378
|
-
end
|
121
|
+
def next_step(script, c, index, is_redeem_script)
|
122
|
+
need_exec = !@flow_stack.include?(false)
|
379
123
|
|
380
|
-
|
124
|
+
return set_error(SCRIPT_ERR_PUSH_SIZE) if c.pushdata? && c.pushed_data.bytesize > MAX_SCRIPT_ELEMENT_SIZE
|
381
125
|
|
382
|
-
|
383
|
-
if !success && flag?(SCRIPT_VERIFY_NULLFAIL) && sig.bytesize > 0
|
384
|
-
return set_error(SCRIPT_ERR_SIG_NULLFAIL)
|
385
|
-
end
|
126
|
+
opcode = c.opcode
|
386
127
|
|
387
|
-
|
128
|
+
if need_exec && c.pushdata?
|
129
|
+
return set_error(SCRIPT_ERR_MINIMALDATA) if require_minimal && !minimal_push?(c.pushed_data, opcode)
|
130
|
+
return set_error(SCRIPT_ERR_BAD_OPCODE) unless verify_pushdata_length(c)
|
131
|
+
stack << c.pushed_data.bth
|
132
|
+
else
|
133
|
+
if opcode > OP_16 && (@op_count += 1) > MAX_OPS_PER_SCRIPT
|
134
|
+
return set_error(SCRIPT_ERR_OP_COUNT)
|
135
|
+
end
|
136
|
+
return set_error(SCRIPT_ERR_DISABLED_OPCODE) if DISABLE_OPCODES.include?(opcode)
|
137
|
+
if opcode == OP_CODESEPARATOR && flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE)
|
138
|
+
return set_error(SCRIPT_ERR_OP_CODESEPARATOR)
|
139
|
+
end
|
388
140
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
141
|
+
# next unless (need_exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
142
|
+
return unless (need_exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
143
|
+
small_int = Opcodes.opcode_to_small_int(opcode)
|
144
|
+
if small_int && opcode != OP_0
|
145
|
+
push_int(small_int)
|
146
|
+
else
|
147
|
+
case opcode
|
148
|
+
when OP_0
|
149
|
+
stack << ''
|
150
|
+
when OP_DEPTH
|
151
|
+
push_int(stack.size)
|
152
|
+
when OP_EQUAL, OP_EQUALVERIFY
|
153
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
154
|
+
a, b = pop_string(2)
|
155
|
+
result = a == b
|
156
|
+
push_int(result ? 1 : 0)
|
157
|
+
if opcode == OP_EQUALVERIFY
|
158
|
+
if result
|
159
|
+
stack.pop
|
160
|
+
else
|
161
|
+
return set_error(SCRIPT_ERR_EQUALVERIFY)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
when OP_0NOTEQUAL
|
165
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
166
|
+
push_int(pop_int == 0 ? 0 : 1)
|
167
|
+
when OP_ADD
|
168
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
169
|
+
a, b = pop_int(2)
|
170
|
+
push_int(a + b)
|
171
|
+
when OP_1ADD
|
172
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
173
|
+
push_int(pop_int + 1)
|
174
|
+
when OP_SUB
|
175
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
176
|
+
a, b = pop_int(2)
|
177
|
+
push_int(a - b)
|
178
|
+
when OP_1SUB
|
179
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
180
|
+
push_int(pop_int - 1)
|
181
|
+
when OP_IF, OP_NOTIF
|
182
|
+
result = false
|
183
|
+
if need_exec
|
184
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if stack.size < 1
|
185
|
+
value = pop_string.htb
|
186
|
+
if flag?(SCRIPT_VERIFY_MINIMALIF)
|
187
|
+
if value.bytesize > 1 || (value.bytesize == 1 && value[0].unpack('C').first != 1)
|
188
|
+
return set_error(SCRIPT_ERR_MINIMALIF)
|
416
189
|
end
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
190
|
+
end
|
191
|
+
result = cast_to_bool(value)
|
192
|
+
result = !result if opcode == OP_NOTIF
|
193
|
+
end
|
194
|
+
@flow_stack << result
|
195
|
+
when OP_ELSE
|
196
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if @flow_stack.size < 1
|
197
|
+
@flow_stack << !@flow_stack.pop
|
198
|
+
when OP_ENDIF
|
199
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if @flow_stack.empty?
|
200
|
+
@flow_stack.pop
|
201
|
+
when OP_NOP
|
202
|
+
when OP_NOP1, OP_NOP4..OP_NOP10
|
203
|
+
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS) if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
204
|
+
when OP_CHECKLOCKTIMEVERIFY
|
205
|
+
# next unless flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
206
|
+
return unless flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
207
|
+
|
208
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
209
|
+
|
210
|
+
# Note that elsewhere numeric opcodes are limited to operands in the range -2**31+1 to 2**31-1,
|
211
|
+
# however it is legal for opcodes to produce results exceeding that range.
|
212
|
+
# This limitation is implemented by CScriptNum's default 4-byte limit.
|
213
|
+
# If we kept to that limit we'd have a year 2038 problem,
|
214
|
+
# even though the nLockTime field in transactions themselves is uint32 which only becomes meaningless after the year 2106.
|
215
|
+
# Thus as a special case we tell CScriptNum to accept up to 5-byte bignums,
|
216
|
+
# which are good until 2**39-1, well beyond the 2**32-1 limit of the nLockTime field itself.
|
217
|
+
locktime = cast_to_int(stack.last, 5)
|
218
|
+
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if locktime < 0
|
219
|
+
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME) unless checker.check_locktime(locktime)
|
220
|
+
when OP_CHECKSEQUENCEVERIFY
|
221
|
+
# next unless flag?(SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
222
|
+
return unless flag?(SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
223
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
224
|
+
|
225
|
+
# nSequence, like nLockTime, is a 32-bit unsigned integer field.
|
226
|
+
# See the comment in CHECKLOCKTIMEVERIFY regarding 5-byte numeric operands.
|
227
|
+
sequence = cast_to_int(stack.last, 5)
|
228
|
+
|
229
|
+
# In the rare event that the argument may be < 0 due to some arithmetic being done first,
|
230
|
+
# you can always use 0 MAX CHECKSEQUENCEVERIFY.
|
231
|
+
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if sequence < 0
|
232
|
+
|
233
|
+
# To provide for future soft-fork extensibility,
|
234
|
+
# if the operand has the disabled lock-time flag set, CHECKSEQUENCEVERIFY behaves as a NOP.
|
235
|
+
# next if (sequence & Tapyrus::TxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0
|
236
|
+
return if (sequence & Tapyrus::TxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0
|
237
|
+
|
238
|
+
# Compare the specified sequence number with the input.
|
239
|
+
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME) unless checker.check_sequence(sequence)
|
240
|
+
when OP_DUP
|
241
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
242
|
+
stack << stack.last
|
243
|
+
when OP_2DUP
|
244
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
245
|
+
2.times { stack << stack[-2] }
|
246
|
+
when OP_3DUP
|
247
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
248
|
+
3.times { stack << stack[-3] }
|
249
|
+
when OP_IFDUP
|
250
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
251
|
+
stack << stack.last if cast_to_bool(stack.last)
|
252
|
+
when OP_RIPEMD160
|
253
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
254
|
+
stack << Digest::RMD160.hexdigest(pop_string.htb)
|
255
|
+
when OP_SHA1
|
256
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
257
|
+
stack << Digest::SHA1.hexdigest(pop_string.htb)
|
258
|
+
when OP_SHA256
|
259
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
260
|
+
stack << Digest::SHA256.hexdigest(pop_string.htb)
|
261
|
+
when OP_HASH160
|
262
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
263
|
+
stack << Tapyrus.hash160(pop_string)
|
264
|
+
when OP_HASH256
|
265
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
266
|
+
stack << Tapyrus.double_sha256(pop_string.htb).bth
|
267
|
+
when OP_VERIFY
|
268
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
269
|
+
return set_error(SCRIPT_ERR_VERIFY) unless pop_bool
|
270
|
+
when OP_TOALTSTACK
|
271
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
272
|
+
@alt_stack << stack.pop
|
273
|
+
when OP_FROMALTSTACK
|
274
|
+
return set_error(SCRIPT_ERR_INVALID_ALTSTACK_OPERATION) if @alt_stack.size < 1
|
275
|
+
stack << @alt_stack.pop
|
276
|
+
when OP_DROP
|
277
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
278
|
+
stack.pop
|
279
|
+
when OP_2DROP
|
280
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
281
|
+
2.times { stack.pop }
|
282
|
+
when OP_NIP
|
283
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
284
|
+
stack.delete_at(-2)
|
285
|
+
when OP_OVER
|
286
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
287
|
+
stack << stack[-2]
|
288
|
+
when OP_2OVER
|
289
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 4
|
290
|
+
2.times { stack << stack[-4] }
|
291
|
+
when OP_PICK, OP_ROLL
|
292
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
293
|
+
pos = pop_int
|
294
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if pos < 0 || pos >= stack.size
|
295
|
+
stack << stack[-pos - 1]
|
296
|
+
stack.delete_at(-pos - 2) if opcode == OP_ROLL
|
297
|
+
when OP_ROT
|
298
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
299
|
+
stack << stack[-3]
|
300
|
+
stack.delete_at(-4)
|
301
|
+
when OP_2ROT
|
302
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 6
|
303
|
+
2.times { stack << stack[-6] }
|
304
|
+
2.times { stack.delete_at(-7) }
|
305
|
+
when OP_SWAP
|
306
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
307
|
+
tmp = stack.last
|
308
|
+
stack[-1] = stack[-2]
|
309
|
+
stack[-2] = tmp
|
310
|
+
when OP_2SWAP
|
311
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 4
|
312
|
+
2.times { stack << stack[-4] }
|
313
|
+
2.times { stack.delete_at(-5) }
|
314
|
+
when OP_TUCK
|
315
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
316
|
+
stack.insert(-3, stack.last)
|
317
|
+
when OP_ABS
|
318
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
319
|
+
v = pop_int
|
320
|
+
push_int(v.abs)
|
321
|
+
when OP_BOOLAND
|
322
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
323
|
+
a, b = pop_int(2)
|
324
|
+
push_int((!a.zero? && !b.zero?) ? 1 : 0)
|
325
|
+
when OP_BOOLOR
|
326
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
327
|
+
a, b = pop_int(2)
|
328
|
+
push_int((!a.zero? || !b.zero?) ? 1 : 0)
|
329
|
+
when OP_NUMEQUAL, OP_NUMEQUALVERIFY
|
330
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
331
|
+
a, b = pop_int(2)
|
332
|
+
result = a == b
|
333
|
+
push_int(result ? 1 : 0)
|
334
|
+
if opcode == OP_NUMEQUALVERIFY
|
335
|
+
if result
|
336
|
+
stack.pop
|
337
|
+
else
|
338
|
+
return set_error(SCRIPT_ERR_NUMEQUALVERIFY)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
when OP_LESSTHAN, OP_LESSTHANOREQUAL
|
342
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
343
|
+
a, b = pop_int(2)
|
344
|
+
push_int(a < b ? 1 : 0) if opcode == OP_LESSTHAN
|
345
|
+
push_int(a <= b ? 1 : 0) if opcode == OP_LESSTHANOREQUAL
|
346
|
+
when OP_GREATERTHAN, OP_GREATERTHANOREQUAL
|
347
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
348
|
+
a, b = pop_int(2)
|
349
|
+
push_int(a > b ? 1 : 0) if opcode == OP_GREATERTHAN
|
350
|
+
push_int(a >= b ? 1 : 0) if opcode == OP_GREATERTHANOREQUAL
|
351
|
+
when OP_MIN
|
352
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
353
|
+
push_int(pop_int(2).min)
|
354
|
+
when OP_MAX
|
355
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
356
|
+
push_int(pop_int(2).max)
|
357
|
+
when OP_WITHIN
|
358
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
359
|
+
x, a, b = pop_int(3)
|
360
|
+
push_int((a <= x && x < b) ? 1 : 0)
|
361
|
+
when OP_NOT
|
362
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
363
|
+
push_int(pop_int == 0 ? 1 : 0)
|
364
|
+
when OP_SIZE
|
365
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
366
|
+
item = stack.last
|
367
|
+
item = Tapyrus::Script.encode_number(item) if item.is_a?(Numeric)
|
368
|
+
size = item.htb.bytesize
|
369
|
+
push_int(size)
|
370
|
+
when OP_NEGATE
|
371
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
372
|
+
push_int(-pop_int)
|
373
|
+
when OP_NUMNOTEQUAL
|
374
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
375
|
+
a, b = pop_int(2)
|
376
|
+
push_int(a == b ? 0 : 1)
|
377
|
+
when OP_CODESEPARATOR
|
378
|
+
@last_code_separator_index = index + 1
|
379
|
+
when OP_CHECKSIG, OP_CHECKSIGVERIFY
|
380
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
381
|
+
sig, pubkey = pop_string(2)
|
382
|
+
|
383
|
+
subscript = script.subscript(@last_code_separator_index..-1)
|
384
|
+
tmp = subscript.find_and_delete(Script.new << sig)
|
385
|
+
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE) if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
386
|
+
subscript = tmp
|
387
|
+
|
388
|
+
if (
|
389
|
+
if sig.htb.bytesize == Tapyrus::Key::COMPACT_SIGNATURE_SIZE
|
390
|
+
!check_schnorr_signature_encoding(sig)
|
391
|
+
else
|
392
|
+
!check_ecdsa_signature_encoding(sig)
|
393
|
+
end
|
394
|
+
) || !check_pubkey_encoding(pubkey)
|
395
|
+
return false
|
396
|
+
end
|
424
397
|
|
425
|
-
|
398
|
+
success = checker.check_sig(sig, pubkey, subscript)
|
426
399
|
|
427
|
-
|
428
|
-
|
400
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#NULLFAIL
|
401
|
+
return set_error(SCRIPT_ERR_SIG_NULLFAIL) if !success && flag?(SCRIPT_VERIFY_NULLFAIL) && sig.bytesize > 0
|
429
402
|
|
430
|
-
|
403
|
+
push_int(success ? 1 : 0)
|
431
404
|
|
432
|
-
|
433
|
-
|
434
|
-
|
405
|
+
if opcode == OP_CHECKSIGVERIFY
|
406
|
+
if success
|
407
|
+
stack.pop
|
408
|
+
else
|
409
|
+
return set_error(SCRIPT_ERR_CHECKSIGVERIFY)
|
410
|
+
end
|
411
|
+
end
|
412
|
+
when OP_CHECKDATASIG, OP_CHECKDATASIGVERIFY
|
413
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
414
|
+
sig, msg, pubkey = pop_string(3)
|
415
|
+
|
416
|
+
# check signature encoding without hashtype byte
|
417
|
+
if (
|
418
|
+
sig.htb.bytesize != (Tapyrus::Key::COMPACT_SIGNATURE_SIZE - 1) &&
|
419
|
+
!check_ecdsa_signature_encoding(sig, true)
|
420
|
+
) || !check_pubkey_encoding(pubkey)
|
421
|
+
return false
|
422
|
+
end
|
423
|
+
digest = Tapyrus.sha256(msg)
|
424
|
+
success = checker.verify_sig(sig, pubkey, digest)
|
425
|
+
return set_error(SCRIPT_ERR_SIG_NULLFAIL) if !success && flag?(SCRIPT_VERIFY_NULLFAIL) && sig.bytesize > 0
|
426
|
+
push_int(success ? 1 : 0)
|
427
|
+
if opcode == OP_CHECKDATASIGVERIFY
|
428
|
+
stack.pop if success
|
429
|
+
return set_error(SCRIPT_ERR_CHECKDATASIGVERIFY) unless success
|
430
|
+
end
|
431
|
+
when OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY
|
432
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
433
|
+
pubkey_count = pop_int
|
434
|
+
return set_error(SCRIPT_ERR_PUBKEY_COUNT) unless (0..MAX_PUBKEYS_PER_MULTISIG).include?(pubkey_count)
|
435
435
|
|
436
|
-
|
437
|
-
|
436
|
+
@op_count += pubkey_count
|
437
|
+
return set_error(SCRIPT_ERR_OP_COUNT) if @op_count > MAX_OPS_PER_SCRIPT
|
438
438
|
|
439
|
-
|
439
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < pubkey_count
|
440
440
|
|
441
|
-
|
442
|
-
|
443
|
-
tmp = subscript.find_and_delete(Script.new << sig)
|
444
|
-
if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
445
|
-
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE)
|
446
|
-
end
|
447
|
-
subscript = tmp
|
448
|
-
end
|
449
|
-
end
|
441
|
+
pubkeys = pop_string(pubkey_count)
|
442
|
+
pubkeys = [pubkeys] if pubkeys.is_a?(String)
|
450
443
|
|
451
|
-
|
452
|
-
current_sig_scheme = nil
|
453
|
-
while success && sig_count > 0
|
454
|
-
sig = sigs.pop
|
455
|
-
pubkey = pubkeys.pop
|
456
|
-
sig_scheme = sig.htb.bytesize == Tapyrus::Key::COMPACT_SIGNATURE_SIZE ? :schnorr : :ecdsa
|
457
|
-
current_sig_scheme = sig_scheme if current_sig_scheme.nil?
|
458
|
-
|
459
|
-
if (
|
460
|
-
if sig_scheme == :schnorr
|
461
|
-
!check_schnorr_signature_encoding(sig)
|
462
|
-
else
|
463
|
-
!check_ecdsa_signature_encoding(sig)
|
464
|
-
end
|
465
|
-
) || !check_pubkey_encoding(pubkey)
|
466
|
-
return false
|
467
|
-
end # error already set.
|
468
|
-
|
469
|
-
return set_error(SCRIPT_ERR_MIXED_SCHEME_MULTISIG) unless sig_scheme == current_sig_scheme
|
470
|
-
|
471
|
-
ok = checker.check_sig(sig, pubkey, subscript, sig_version)
|
472
|
-
if ok
|
473
|
-
sig_count -= 1
|
474
|
-
else
|
475
|
-
sigs << sig
|
476
|
-
end
|
477
|
-
pubkey_count -= 1
|
478
|
-
success = false if sig_count > pubkey_count
|
479
|
-
end
|
444
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
480
445
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
return set_error(SCRIPT_ERR_SIG_NULLFAIL) if sig.bytesize > 0
|
485
|
-
end
|
486
|
-
end
|
446
|
+
sig_count = pop_int
|
447
|
+
return set_error(SCRIPT_ERR_SIG_COUNT) if sig_count < 0 || sig_count > pubkey_count
|
448
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < (sig_count)
|
487
449
|
|
488
|
-
|
489
|
-
|
490
|
-
# so optionally verify it is exactly equal to zero prior to removing it from the stack.
|
491
|
-
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
492
|
-
return set_error(SCRIPT_ERR_SIG_NULLDUMMY) if stack[-1].size > 0
|
450
|
+
sigs = pop_string(sig_count)
|
451
|
+
sigs = [sigs] if sigs.is_a?(String)
|
493
452
|
|
494
|
-
|
453
|
+
subscript = script.subscript(@last_code_separator_index..-1)
|
495
454
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
end
|
504
|
-
when OP_RETURN
|
505
|
-
return set_error(SCRIPT_ERR_OP_RETURN)
|
506
|
-
when OP_COLOR
|
507
|
-
# Color id is not permitted in p2sh redeem script
|
508
|
-
return set_error(SCRIPT_ERR_OP_COLOR_UNEXPECTED) if is_redeem_script
|
509
|
-
|
510
|
-
# if Color id is already initialized this must be an extra
|
511
|
-
if color_id && color_id.type != Tapyrus::Color::TokenTypes::NONE
|
512
|
-
return set_error(SCRIPT_ERR_OP_COLOR_MULTIPLE)
|
513
|
-
end
|
455
|
+
sigs.each do |sig|
|
456
|
+
tmp = subscript.find_and_delete(Script.new << sig)
|
457
|
+
if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
458
|
+
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE)
|
459
|
+
end
|
460
|
+
subscript = tmp
|
461
|
+
end
|
514
462
|
|
515
|
-
|
516
|
-
|
463
|
+
success = true
|
464
|
+
current_sig_scheme = nil
|
465
|
+
while success && sig_count > 0
|
466
|
+
sig = sigs.pop
|
467
|
+
pubkey = pubkeys.pop
|
468
|
+
sig_scheme = sig.htb.bytesize == Tapyrus::Key::COMPACT_SIGNATURE_SIZE ? :schnorr : :ecdsa
|
469
|
+
current_sig_scheme = sig_scheme if current_sig_scheme.nil?
|
470
|
+
|
471
|
+
if (
|
472
|
+
if sig_scheme == :schnorr
|
473
|
+
!check_schnorr_signature_encoding(sig)
|
474
|
+
else
|
475
|
+
!check_ecdsa_signature_encoding(sig)
|
476
|
+
end
|
477
|
+
) || !check_pubkey_encoding(pubkey)
|
478
|
+
return false
|
479
|
+
end # error already set.
|
480
|
+
|
481
|
+
return set_error(SCRIPT_ERR_MIXED_SCHEME_MULTISIG) unless sig_scheme == current_sig_scheme
|
482
|
+
|
483
|
+
ok = checker.check_sig(sig, pubkey, subscript)
|
484
|
+
if ok
|
485
|
+
sig_count -= 1
|
486
|
+
else
|
487
|
+
sigs << sig
|
488
|
+
end
|
489
|
+
pubkey_count -= 1
|
490
|
+
success = false if sig_count > pubkey_count
|
491
|
+
end
|
517
492
|
|
518
|
-
|
519
|
-
|
493
|
+
if !success && flag?(SCRIPT_VERIFY_NULLFAIL)
|
494
|
+
sigs.each do |sig|
|
495
|
+
# If the operation failed, we require that all signatures must be empty vector
|
496
|
+
return set_error(SCRIPT_ERR_SIG_NULLFAIL) if sig.bytesize > 0
|
497
|
+
end
|
498
|
+
end
|
520
499
|
|
521
|
-
|
500
|
+
# A bug causes CHECKMULTISIG to consume one extra argument whose contents were not checked in any way.
|
501
|
+
# Unfortunately this is a potential source of mutability,
|
502
|
+
# so optionally verify it is exactly equal to zero prior to removing it from the stack.
|
503
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
504
|
+
return set_error(SCRIPT_ERR_SIG_NULLDUMMY) if stack[-1].size > 0
|
522
505
|
|
523
|
-
|
524
|
-
return set_error(SCRIPT_ERR_OP_COLOR_ID_INVALID) unless color_id.valid?
|
506
|
+
stack.pop
|
525
507
|
|
508
|
+
push_int(success ? 1 : 0)
|
509
|
+
if opcode == OP_CHECKMULTISIGVERIFY
|
510
|
+
if success
|
526
511
|
stack.pop
|
527
512
|
else
|
528
|
-
return set_error(
|
513
|
+
return set_error(SCRIPT_ERR_CHECKMULTISIGVERIFY)
|
529
514
|
end
|
530
515
|
end
|
531
|
-
|
516
|
+
when OP_RETURN
|
517
|
+
return set_error(SCRIPT_ERR_OP_RETURN)
|
518
|
+
when OP_COLOR
|
519
|
+
# Color id is not permitted in p2sh redeem script
|
520
|
+
return set_error(SCRIPT_ERR_OP_COLOR_UNEXPECTED) if is_redeem_script
|
521
|
+
|
522
|
+
# if Color id is already initialized this must be an extra
|
523
|
+
if @color_id && @color_id.type != Tapyrus::Color::TokenTypes::NONE
|
524
|
+
return set_error(SCRIPT_ERR_OP_COLOR_MULTIPLE)
|
525
|
+
end
|
526
|
+
|
527
|
+
# color id is not allowed inside OP_IF
|
528
|
+
return set_error(SCRIPT_ERR_OP_COLOR_IN_BRANCH) unless @flow_stack.empty?
|
532
529
|
|
533
|
-
|
534
|
-
|
530
|
+
# pop one stack element and verify that it exists
|
531
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
532
|
+
|
533
|
+
@color_id = Tapyrus::Color::ColorIdentifier.parse_from_payload(stack.last.htb)
|
534
|
+
|
535
|
+
# check ColorIdentifier is valid
|
536
|
+
return set_error(SCRIPT_ERR_OP_COLOR_ID_INVALID) unless @color_id.valid?
|
537
|
+
|
538
|
+
stack.pop
|
539
|
+
else
|
540
|
+
return set_error(SCRIPT_ERR_BAD_OPCODE)
|
541
|
+
end
|
535
542
|
end
|
536
|
-
rescue Exception => e
|
537
|
-
puts e
|
538
|
-
puts e.backtrace
|
539
|
-
return set_error(SCRIPT_ERR_UNKNOWN_ERROR, e.message)
|
540
543
|
end
|
541
544
|
|
542
|
-
|
545
|
+
# max stack size check
|
546
|
+
return set_error(SCRIPT_ERR_STACK_SIZE) if stack.size + @alt_stack.size > MAX_STACK_SIZE
|
547
|
+
end
|
543
548
|
|
544
|
-
|
545
|
-
|
549
|
+
def reset_params
|
550
|
+
@flow_stack = []
|
551
|
+
@alt_stack = []
|
552
|
+
@last_code_separator_index = 0
|
553
|
+
@op_count = 0
|
554
|
+
@color_id = nil
|
555
|
+
end
|
556
|
+
|
557
|
+
# see https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L36-L49
|
558
|
+
def cast_to_bool(v)
|
559
|
+
case v
|
560
|
+
when Numeric
|
561
|
+
return v != 0
|
562
|
+
when String
|
563
|
+
v.each_byte.with_index { |b, i| return !(i == (v.bytesize - 1) && b == 0x80) unless b == 0 }
|
564
|
+
false
|
565
|
+
else
|
566
|
+
false
|
567
|
+
end
|
546
568
|
end
|
547
569
|
|
548
570
|
private
|
@@ -595,19 +617,6 @@ module Tapyrus
|
|
595
617
|
cast_to_bool(pop_string.htb)
|
596
618
|
end
|
597
619
|
|
598
|
-
# see https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L36-L49
|
599
|
-
def cast_to_bool(v)
|
600
|
-
case v
|
601
|
-
when Numeric
|
602
|
-
return v != 0
|
603
|
-
when String
|
604
|
-
v.each_byte.with_index { |b, i| return !(i == (v.bytesize - 1) && b == 0x80) unless b == 0 }
|
605
|
-
false
|
606
|
-
else
|
607
|
-
false
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
620
|
def check_ecdsa_signature_encoding(sig, data_sig = false)
|
612
621
|
return true if sig.size.zero?
|
613
622
|
if !Key.valid_signature_encoding?(sig.htb, data_sig)
|
@@ -1,12 +1,10 @@
|
|
1
1
|
module Tapyrus
|
2
2
|
class TxChecker
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :amount
|
3
|
+
attr_accessor :tx
|
4
|
+
attr_accessor :input_index
|
6
5
|
|
7
|
-
def initialize(tx: nil,
|
6
|
+
def initialize(tx: nil, input_index: nil)
|
8
7
|
@tx = tx
|
9
|
-
@amount = amount
|
10
8
|
@input_index = input_index
|
11
9
|
end
|
12
10
|
|
@@ -14,15 +12,13 @@ module Tapyrus
|
|
14
12
|
# @param [String] script_sig a signature with hex format.
|
15
13
|
# @param [String] pubkey a public key with hex format.
|
16
14
|
# @param [Tapyrus::Script] script_code
|
17
|
-
# @param [Integer] sig_version
|
18
15
|
# @return [Boolean] if check is passed return true, otherwise false.
|
19
|
-
def check_sig(script_sig, pubkey, script_code
|
16
|
+
def check_sig(script_sig, pubkey, script_code)
|
20
17
|
return false if script_sig.empty?
|
21
18
|
script_sig = script_sig.htb
|
22
19
|
hash_type = script_sig[-1].unpack('C').first
|
23
20
|
sig = script_sig[0..-2]
|
24
|
-
sighash =
|
25
|
-
tx.sighash_for_input(input_index, script_code, hash_type: hash_type, amount: amount, sig_version: sig_version)
|
21
|
+
sighash = tx.sighash_for_input(input_index, script_code, hash_type: hash_type)
|
26
22
|
verify_sig(sig.bth, pubkey, sighash)
|
27
23
|
end
|
28
24
|
|
data/lib/tapyrus/tx.rb
CHANGED
@@ -103,34 +103,23 @@ module Tapyrus
|
|
103
103
|
to_payload.bytesize
|
104
104
|
end
|
105
105
|
|
106
|
-
#
|
106
|
+
# Generate signature hash
|
107
107
|
# @param [Integer] input_index input index.
|
108
108
|
# @param [Integer] hash_type signature hash type
|
109
|
-
# @param [Tapyrus::Script] output_script script pubkey or script code. if script pubkey is
|
110
|
-
# @
|
111
|
-
|
112
|
-
# 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.
|
113
|
-
def sighash_for_input(
|
114
|
-
input_index,
|
115
|
-
output_script,
|
116
|
-
hash_type: SIGHASH_TYPE[:all],
|
117
|
-
sig_version: :base,
|
118
|
-
amount: nil,
|
119
|
-
skip_separator_index: 0
|
120
|
-
)
|
109
|
+
# @param [Tapyrus::Script] output_script script pubkey or script code. if script pubkey is P2SH, set redeem script to this.
|
110
|
+
# @return [String] sighash
|
111
|
+
def sighash_for_input(input_index, output_script, hash_type: SIGHASH_TYPE[:all])
|
121
112
|
raise ArgumentError, 'input_index must be specified.' unless input_index
|
122
113
|
raise ArgumentError, 'does not exist input corresponding to input_index.' if input_index >= inputs.size
|
123
114
|
raise ArgumentError, 'script_pubkey must be specified.' unless output_script
|
124
|
-
raise ArgumentError, 'unsupported sig version specified.' unless SIG_VERSION.include?(sig_version)
|
125
115
|
sighash_for_legacy(input_index, output_script, hash_type)
|
126
116
|
end
|
127
117
|
|
128
118
|
# verify input signature.
|
129
119
|
# @param [Integer] input_index
|
130
120
|
# @param [Tapyrus::Script] script_pubkey the script pubkey for target input.
|
131
|
-
# @param [Integer] amount the amount of tapyrus, require for witness program only.
|
132
121
|
# @param [Array] flags the flags used when execute script interpreter.
|
133
|
-
def verify_input_sig(input_index, script_pubkey,
|
122
|
+
def verify_input_sig(input_index, script_pubkey, flags: STANDARD_SCRIPT_VERIFY_FLAGS)
|
134
123
|
flags << SCRIPT_VERIFY_P2SH if script_pubkey.p2sh?
|
135
124
|
verify_input_sig_for_legacy(input_index, script_pubkey, flags)
|
136
125
|
end
|
@@ -207,7 +196,9 @@ module Tapyrus
|
|
207
196
|
checker = Tapyrus::TxChecker.new(tx: self, input_index: input_index)
|
208
197
|
interpreter = Tapyrus::ScriptInterpreter.new(checker: checker, flags: flags)
|
209
198
|
|
210
|
-
interpreter.verify_script(script_sig, script_pubkey)
|
199
|
+
result = interpreter.verify_script(script_sig, script_pubkey)
|
200
|
+
warn("Verify failed. Cause: #{interpreter.error}") unless result
|
201
|
+
result
|
211
202
|
end
|
212
203
|
end
|
213
204
|
end
|
data/lib/tapyrus/tx_builder.rb
CHANGED
@@ -89,9 +89,11 @@ module Tapyrus
|
|
89
89
|
script_pubkey = script_pubkey.add_color(color_id)
|
90
90
|
end
|
91
91
|
|
92
|
+
output = Tapyrus::TxOut.new(script_pubkey: script_pubkey, value: value)
|
93
|
+
raise ArgumentError, 'The transaction amount is too small' if color_id.default? && output.dust?
|
92
94
|
@outgoings[color_id] ||= 0
|
93
95
|
@outgoings[color_id] += value
|
94
|
-
@outputs <<
|
96
|
+
@outputs << output
|
95
97
|
self
|
96
98
|
end
|
97
99
|
|
@@ -136,13 +138,16 @@ module Tapyrus
|
|
136
138
|
def add_change(tx)
|
137
139
|
@incomings.each do |color_id, in_amount|
|
138
140
|
out_amount = @outgoings[color_id] || 0
|
139
|
-
|
141
|
+
output =
|
140
142
|
if color_id.default?
|
141
|
-
|
143
|
+
change = in_amount - out_amount - estimated_fee
|
144
|
+
change_output = Tapyrus::TxOut.new(script_pubkey: @change_script_pubkey, value: change)
|
145
|
+
change_output unless change_output.dust?
|
142
146
|
else
|
143
|
-
|
147
|
+
change = in_amount - out_amount
|
148
|
+
Tapyrus::TxOut.new(script_pubkey: @change_script_pubkey.add_color(color_id), value: change) if change > 0
|
144
149
|
end
|
145
|
-
tx.outputs <<
|
150
|
+
tx.outputs << output if output
|
146
151
|
end
|
147
152
|
end
|
148
153
|
|
data/lib/tapyrus/version.rb
CHANGED
data/tapyrusrb.gemspec
CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_runtime_dependency 'siphash'
|
32
32
|
spec.add_runtime_dependency 'activesupport', '>= 5.2.3'
|
33
33
|
spec.add_runtime_dependency 'json_pure', '>= 2.3.1'
|
34
|
+
spec.add_runtime_dependency 'terminal-table', '~> 3.0.2'
|
34
35
|
|
35
36
|
# for options
|
36
37
|
spec.add_development_dependency 'leveldb-native'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapyrus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: 2.3.1
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: terminal-table
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 3.0.2
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 3.0.2
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: leveldb-native
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -280,6 +294,7 @@ description: The implementation of Tapyrus Protocol for Ruby.
|
|
280
294
|
email:
|
281
295
|
- azuchi@chaintope.com
|
282
296
|
executables:
|
297
|
+
- tapyrus-script-debugger
|
283
298
|
- tapyrusrb-cli
|
284
299
|
- tapyrusrbd
|
285
300
|
extensions: []
|
@@ -299,6 +314,7 @@ files:
|
|
299
314
|
- Rakefile
|
300
315
|
- bin/console
|
301
316
|
- bin/setup
|
317
|
+
- exe/tapyrus-script-debugger
|
302
318
|
- exe/tapyrusrb-cli
|
303
319
|
- exe/tapyrusrbd
|
304
320
|
- lib/openassets.rb
|
@@ -440,7 +456,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
440
456
|
- !ruby/object:Gem::Version
|
441
457
|
version: '0'
|
442
458
|
requirements: []
|
443
|
-
rubygems_version: 3.3.
|
459
|
+
rubygems_version: 3.3.21
|
444
460
|
signing_key:
|
445
461
|
specification_version: 4
|
446
462
|
summary: The implementation of Tapyrus Protocol for Ruby.
|