tapyrus 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://
|
1
|
+
# Tapyrusrb [![Build Status](https://github.com/chaintope/tapyrusrb/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/chaintope/tapyrusrb/actions/workflows/ruby.yml) [![Gem Version](https://badge.fury.io/rb/tapyrus.svg)](https://badge.fury.io/rb/tapyrus) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](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.
|