tapyrus 0.1.0
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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +100 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/tapyrusrb-cli +5 -0
- data/exe/tapyrusrbd +41 -0
- data/lib/openassets/marker_output.rb +20 -0
- data/lib/openassets/payload.rb +54 -0
- data/lib/openassets/util.rb +28 -0
- data/lib/openassets.rb +9 -0
- data/lib/tapyrus/base58.rb +38 -0
- data/lib/tapyrus/block.rb +77 -0
- data/lib/tapyrus/block_header.rb +88 -0
- data/lib/tapyrus/bloom_filter.rb +78 -0
- data/lib/tapyrus/chain_params.rb +90 -0
- data/lib/tapyrus/chainparams/mainnet.yml +41 -0
- data/lib/tapyrus/chainparams/regtest.yml +38 -0
- data/lib/tapyrus/chainparams/testnet.yml +41 -0
- data/lib/tapyrus/constants.rb +195 -0
- data/lib/tapyrus/descriptor.rb +147 -0
- data/lib/tapyrus/ext_key.rb +337 -0
- data/lib/tapyrus/key.rb +296 -0
- data/lib/tapyrus/key_path.rb +26 -0
- data/lib/tapyrus/logger.rb +42 -0
- data/lib/tapyrus/merkle_tree.rb +149 -0
- data/lib/tapyrus/message/addr.rb +35 -0
- data/lib/tapyrus/message/base.rb +28 -0
- data/lib/tapyrus/message/block.rb +46 -0
- data/lib/tapyrus/message/block_transaction_request.rb +45 -0
- data/lib/tapyrus/message/block_transactions.rb +31 -0
- data/lib/tapyrus/message/block_txn.rb +27 -0
- data/lib/tapyrus/message/cmpct_block.rb +42 -0
- data/lib/tapyrus/message/error.rb +10 -0
- data/lib/tapyrus/message/fee_filter.rb +27 -0
- data/lib/tapyrus/message/filter_add.rb +28 -0
- data/lib/tapyrus/message/filter_clear.rb +17 -0
- data/lib/tapyrus/message/filter_load.rb +39 -0
- data/lib/tapyrus/message/get_addr.rb +17 -0
- data/lib/tapyrus/message/get_block_txn.rb +27 -0
- data/lib/tapyrus/message/get_blocks.rb +29 -0
- data/lib/tapyrus/message/get_data.rb +21 -0
- data/lib/tapyrus/message/get_headers.rb +28 -0
- data/lib/tapyrus/message/header_and_short_ids.rb +57 -0
- data/lib/tapyrus/message/headers.rb +35 -0
- data/lib/tapyrus/message/headers_parser.rb +24 -0
- data/lib/tapyrus/message/inv.rb +21 -0
- data/lib/tapyrus/message/inventories_parser.rb +23 -0
- data/lib/tapyrus/message/inventory.rb +51 -0
- data/lib/tapyrus/message/mem_pool.rb +17 -0
- data/lib/tapyrus/message/merkle_block.rb +42 -0
- data/lib/tapyrus/message/network_addr.rb +63 -0
- data/lib/tapyrus/message/not_found.rb +21 -0
- data/lib/tapyrus/message/ping.rb +30 -0
- data/lib/tapyrus/message/pong.rb +26 -0
- data/lib/tapyrus/message/prefilled_tx.rb +29 -0
- data/lib/tapyrus/message/reject.rb +46 -0
- data/lib/tapyrus/message/send_cmpct.rb +43 -0
- data/lib/tapyrus/message/send_headers.rb +16 -0
- data/lib/tapyrus/message/tx.rb +30 -0
- data/lib/tapyrus/message/ver_ack.rb +17 -0
- data/lib/tapyrus/message/version.rb +69 -0
- data/lib/tapyrus/message.rb +70 -0
- data/lib/tapyrus/mnemonic/wordlist/chinese_simplified.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/chinese_traditional.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/english.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/french.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/italian.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/japanese.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/spanish.txt +2048 -0
- data/lib/tapyrus/mnemonic.rb +77 -0
- data/lib/tapyrus/network/connection.rb +73 -0
- data/lib/tapyrus/network/message_handler.rb +241 -0
- data/lib/tapyrus/network/peer.rb +223 -0
- data/lib/tapyrus/network/peer_discovery.rb +42 -0
- data/lib/tapyrus/network/pool.rb +135 -0
- data/lib/tapyrus/network.rb +13 -0
- data/lib/tapyrus/node/cli.rb +112 -0
- data/lib/tapyrus/node/configuration.rb +38 -0
- data/lib/tapyrus/node/spv.rb +79 -0
- data/lib/tapyrus/node.rb +7 -0
- data/lib/tapyrus/opcodes.rb +178 -0
- data/lib/tapyrus/out_point.rb +44 -0
- data/lib/tapyrus/rpc/http_server.rb +65 -0
- data/lib/tapyrus/rpc/request_handler.rb +150 -0
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +72 -0
- data/lib/tapyrus/rpc.rb +7 -0
- data/lib/tapyrus/script/multisig.rb +92 -0
- data/lib/tapyrus/script/script.rb +551 -0
- data/lib/tapyrus/script/script_error.rb +111 -0
- data/lib/tapyrus/script/script_interpreter.rb +668 -0
- data/lib/tapyrus/script/tx_checker.rb +81 -0
- data/lib/tapyrus/script_witness.rb +38 -0
- data/lib/tapyrus/secp256k1/native.rb +174 -0
- data/lib/tapyrus/secp256k1/ruby.rb +123 -0
- data/lib/tapyrus/secp256k1.rb +12 -0
- data/lib/tapyrus/slip39/share.rb +122 -0
- data/lib/tapyrus/slip39/sss.rb +245 -0
- data/lib/tapyrus/slip39/wordlist/english.txt +1024 -0
- data/lib/tapyrus/slip39.rb +93 -0
- data/lib/tapyrus/store/chain_entry.rb +67 -0
- data/lib/tapyrus/store/db/level_db.rb +98 -0
- data/lib/tapyrus/store/db.rb +9 -0
- data/lib/tapyrus/store/spv_chain.rb +101 -0
- data/lib/tapyrus/store.rb +9 -0
- data/lib/tapyrus/tx.rb +347 -0
- data/lib/tapyrus/tx_in.rb +89 -0
- data/lib/tapyrus/tx_out.rb +74 -0
- data/lib/tapyrus/util.rb +133 -0
- data/lib/tapyrus/validation.rb +115 -0
- data/lib/tapyrus/version.rb +3 -0
- data/lib/tapyrus/wallet/account.rb +151 -0
- data/lib/tapyrus/wallet/base.rb +162 -0
- data/lib/tapyrus/wallet/db.rb +81 -0
- data/lib/tapyrus/wallet/master_key.rb +110 -0
- data/lib/tapyrus/wallet.rb +8 -0
- data/lib/tapyrus.rb +219 -0
- data/tapyrusrb.conf.sample +0 -0
- data/tapyrusrb.gemspec +47 -0
- metadata +451 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
|
|
3
|
+
class ScriptInterpreter
|
|
4
|
+
|
|
5
|
+
include Tapyrus::Opcodes
|
|
6
|
+
|
|
7
|
+
attr_reader :stack
|
|
8
|
+
attr_reader :debug
|
|
9
|
+
attr_reader :flags
|
|
10
|
+
attr_accessor :error
|
|
11
|
+
attr_reader :checker
|
|
12
|
+
attr_reader :require_minimal
|
|
13
|
+
|
|
14
|
+
DISABLE_OPCODES = [OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT, OP_INVERT, OP_AND, OP_OR, OP_XOR, OP_2MUL, OP_2DIV, OP_DIV, OP_MUL, OP_MOD, OP_LSHIFT, OP_RSHIFT]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# syntax sugar for simple evaluation for script.
|
|
18
|
+
# @param [Tapyrus::Script] script_sig a scriptSig.
|
|
19
|
+
# @param [Tapyrus::Script] script_pubkey a scriptPubkey.
|
|
20
|
+
def self.eval(script_sig, script_pubkey)
|
|
21
|
+
self.new.verify_script(script_sig, script_pubkey)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# initialize runner
|
|
25
|
+
def initialize(flags: SCRIPT_VERIFY_NONE, checker: TxChecker.new)
|
|
26
|
+
@stack, @debug = [], []
|
|
27
|
+
@flags = flags
|
|
28
|
+
@checker = checker
|
|
29
|
+
@require_minimal = flag?(SCRIPT_VERIFY_MINIMALDATA)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# eval script
|
|
33
|
+
# @param [Tapyrus::Script] script_sig a signature script (unlock script which data push only)
|
|
34
|
+
# @param [Tapyrus::Script] script_pubkey a script pubkey (locking script)
|
|
35
|
+
# @param [Tapyrus::ScriptWitness] witness a witness script
|
|
36
|
+
# @return [Boolean] result
|
|
37
|
+
def verify_script(script_sig, script_pubkey, witness = ScriptWitness.new)
|
|
38
|
+
|
|
39
|
+
return set_error(SCRIPT_ERR_SIG_PUSHONLY) if flag?(SCRIPT_VERIFY_SIGPUSHONLY) && !script_sig.push_only?
|
|
40
|
+
|
|
41
|
+
stack_copy = nil
|
|
42
|
+
had_witness = false
|
|
43
|
+
|
|
44
|
+
return false unless eval_script(script_sig, :base)
|
|
45
|
+
|
|
46
|
+
stack_copy = stack.dup if flag?(SCRIPT_VERIFY_P2SH)
|
|
47
|
+
|
|
48
|
+
return false unless eval_script(script_pubkey, :base)
|
|
49
|
+
|
|
50
|
+
return set_error(SCRIPT_ERR_EVAL_FALSE) if stack.empty? || !cast_to_bool(stack.last.htb)
|
|
51
|
+
|
|
52
|
+
# Bare witness programs
|
|
53
|
+
if flag?(SCRIPT_VERIFY_WITNESS) && script_pubkey.witness_program?
|
|
54
|
+
had_witness = true
|
|
55
|
+
return set_error(SCRIPT_ERR_WITNESS_MALLEATED) unless script_sig.size == 0
|
|
56
|
+
version, program = script_pubkey.witness_data
|
|
57
|
+
stack_copy = stack.dup
|
|
58
|
+
return false unless verify_witness_program(witness, version, program)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Additional validation for spend-to-script-hash transactions
|
|
62
|
+
if flag?(SCRIPT_VERIFY_P2SH) && script_pubkey.p2sh?
|
|
63
|
+
return set_error(SCRIPT_ERR_SIG_PUSHONLY) unless script_sig.push_only?
|
|
64
|
+
tmp = stack
|
|
65
|
+
@stack = stack_copy
|
|
66
|
+
raise 'stack cannot be empty.' if stack.empty?
|
|
67
|
+
begin
|
|
68
|
+
redeem_script = Tapyrus::Script.parse_from_payload(stack.pop.htb)
|
|
69
|
+
rescue Exception => e
|
|
70
|
+
return set_error(SCRIPT_ERR_BAD_OPCODE, "Failed to parse serialized redeem script for P2SH. #{e.message}")
|
|
71
|
+
end
|
|
72
|
+
return false unless eval_script(redeem_script, :base)
|
|
73
|
+
return set_error(SCRIPT_ERR_EVAL_FALSE) if stack.empty? || !cast_to_bool(stack.last)
|
|
74
|
+
|
|
75
|
+
# P2SH witness program
|
|
76
|
+
if flag?(SCRIPT_VERIFY_WITNESS) && redeem_script.witness_program?
|
|
77
|
+
had_witness = true
|
|
78
|
+
# The scriptSig must be _exactly_ a single push of the redeemScript. Otherwise we reintroduce malleability.
|
|
79
|
+
return set_error(SCRIPT_ERR_WITNESS_MALLEATED_P2SH) unless script_sig == (Tapyrus::Script.new << redeem_script.to_payload.bth)
|
|
80
|
+
|
|
81
|
+
version, program = redeem_script.witness_data
|
|
82
|
+
return false unless verify_witness_program(witness, version, program)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# The CLEANSTACK check is only performed after potential P2SH evaluation,
|
|
87
|
+
# as the non-P2SH evaluation of a P2SH script will obviously not result in a clean stack (the P2SH inputs remain).
|
|
88
|
+
# The same holds for witness evaluation.
|
|
89
|
+
if flag?(SCRIPT_VERIFY_CLEANSTACK)
|
|
90
|
+
# Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK would be possible,
|
|
91
|
+
# which is not a softfork (and P2SH should be one).
|
|
92
|
+
raise 'assert' unless flag?(SCRIPT_VERIFY_P2SH)
|
|
93
|
+
return set_error(SCRIPT_ERR_CLEANSTACK) unless stack.size == 1
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if flag?(SCRIPT_VERIFY_WITNESS)
|
|
97
|
+
raise 'assert' unless flag?(SCRIPT_VERIFY_P2SH)
|
|
98
|
+
return set_error(SCRIPT_ERR_WITNESS_UNEXPECTED) if !had_witness && !witness.empty?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def set_error(err_code, extra_message = nil)
|
|
105
|
+
@error = ScriptError.new(err_code, extra_message)
|
|
106
|
+
false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def verify_witness_program(witness, version, program)
|
|
110
|
+
if version == 0
|
|
111
|
+
if program.bytesize == 32
|
|
112
|
+
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY) if witness.stack.size == 0
|
|
113
|
+
script_pubkey = Tapyrus::Script.parse_from_payload(witness.stack.last)
|
|
114
|
+
@stack = witness.stack[0..-2].map{|w|w.bth}
|
|
115
|
+
script_hash = Tapyrus.sha256(script_pubkey.to_payload)
|
|
116
|
+
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH) unless script_hash == program
|
|
117
|
+
elsif program.bytesize == 20
|
|
118
|
+
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH) unless witness.stack.size == 2
|
|
119
|
+
script_pubkey = Tapyrus::Script.to_p2pkh(program.bth)
|
|
120
|
+
@stack = witness.stack.map{|w|w.bth}
|
|
121
|
+
else
|
|
122
|
+
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH)
|
|
123
|
+
end
|
|
124
|
+
elsif flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
|
125
|
+
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
|
126
|
+
else
|
|
127
|
+
return true # Higher version witness scripts return true for future softfork compatibility
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
stack.each do |s| # Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
|
|
131
|
+
return set_error(SCRIPT_ERR_PUSH_SIZE) if s.htb.bytesize > MAX_SCRIPT_ELEMENT_SIZE
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
return false unless eval_script(script_pubkey, :witness_v0)
|
|
135
|
+
|
|
136
|
+
return set_error(SCRIPT_ERR_EVAL_FALSE) unless stack.size == 1
|
|
137
|
+
return set_error(SCRIPT_ERR_EVAL_FALSE) unless cast_to_bool(stack.last)
|
|
138
|
+
true
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def eval_script(script, sig_version)
|
|
142
|
+
return set_error(SCRIPT_ERR_SCRIPT_SIZE) if script.size > MAX_SCRIPT_SIZE
|
|
143
|
+
begin
|
|
144
|
+
flow_stack = []
|
|
145
|
+
alt_stack = []
|
|
146
|
+
last_code_separator_index = 0
|
|
147
|
+
op_count = 0
|
|
148
|
+
|
|
149
|
+
script.chunks.each_with_index do |c, index|
|
|
150
|
+
need_exec = !flow_stack.include?(false)
|
|
151
|
+
|
|
152
|
+
return set_error(SCRIPT_ERR_PUSH_SIZE) if c.pushdata? && c.pushed_data.bytesize > MAX_SCRIPT_ELEMENT_SIZE
|
|
153
|
+
|
|
154
|
+
opcode = c.opcode
|
|
155
|
+
|
|
156
|
+
if need_exec && c.pushdata?
|
|
157
|
+
if require_minimal && !minimal_push?(c.pushed_data, opcode)
|
|
158
|
+
return set_error(SCRIPT_ERR_MINIMALDATA)
|
|
159
|
+
end
|
|
160
|
+
return set_error(SCRIPT_ERR_BAD_OPCODE) unless verify_pushdata_length(c)
|
|
161
|
+
stack << c.pushed_data.bth
|
|
162
|
+
else
|
|
163
|
+
if opcode > OP_16 && (op_count += 1) > MAX_OPS_PER_SCRIPT
|
|
164
|
+
return set_error(SCRIPT_ERR_OP_COUNT)
|
|
165
|
+
end
|
|
166
|
+
return set_error(SCRIPT_ERR_DISABLED_OPCODE) if DISABLE_OPCODES.include?(opcode)
|
|
167
|
+
return set_error(SCRIPT_ERR_OP_CODESEPARATOR) if opcode == OP_CODESEPARATOR && sig_version == :base && flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE)
|
|
168
|
+
next unless (need_exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
|
169
|
+
small_int = Opcodes.opcode_to_small_int(opcode)
|
|
170
|
+
if small_int && opcode != OP_0
|
|
171
|
+
push_int(small_int)
|
|
172
|
+
else
|
|
173
|
+
case opcode
|
|
174
|
+
when OP_0
|
|
175
|
+
stack << ''
|
|
176
|
+
when OP_DEPTH
|
|
177
|
+
push_int(stack.size)
|
|
178
|
+
when OP_EQUAL, OP_EQUALVERIFY
|
|
179
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
180
|
+
a, b = pop_string(2)
|
|
181
|
+
result = a == b
|
|
182
|
+
push_int(result ? 1 : 0)
|
|
183
|
+
if opcode == OP_EQUALVERIFY
|
|
184
|
+
if result
|
|
185
|
+
stack.pop
|
|
186
|
+
else
|
|
187
|
+
return set_error(SCRIPT_ERR_EQUALVERIFY)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
when OP_0NOTEQUAL
|
|
191
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
192
|
+
push_int(pop_int == 0 ? 0 : 1)
|
|
193
|
+
when OP_ADD
|
|
194
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
195
|
+
a, b = pop_int(2)
|
|
196
|
+
push_int(a + b)
|
|
197
|
+
when OP_1ADD
|
|
198
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
199
|
+
push_int(pop_int + 1)
|
|
200
|
+
when OP_SUB
|
|
201
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
202
|
+
a, b = pop_int(2)
|
|
203
|
+
push_int(a - b)
|
|
204
|
+
when OP_1SUB
|
|
205
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
206
|
+
push_int(pop_int - 1)
|
|
207
|
+
when OP_IF, OP_NOTIF
|
|
208
|
+
result = false
|
|
209
|
+
if need_exec
|
|
210
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if stack.size < 1
|
|
211
|
+
value = pop_string.htb
|
|
212
|
+
if sig_version == :witness_v0 && flag?(SCRIPT_VERIFY_MINIMALIF)
|
|
213
|
+
if value.bytesize > 1 || (value.bytesize == 1 && value[0].unpack('C').first != 1)
|
|
214
|
+
return set_error(SCRIPT_ERR_MINIMALIF)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
result = cast_to_bool(value)
|
|
218
|
+
result = !result if opcode == OP_NOTIF
|
|
219
|
+
end
|
|
220
|
+
flow_stack << result
|
|
221
|
+
when OP_ELSE
|
|
222
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if flow_stack.size < 1
|
|
223
|
+
flow_stack << !flow_stack.pop
|
|
224
|
+
when OP_ENDIF
|
|
225
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if flow_stack.empty?
|
|
226
|
+
flow_stack.pop
|
|
227
|
+
when OP_NOP
|
|
228
|
+
when OP_NOP1, OP_NOP4..OP_NOP10
|
|
229
|
+
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS) if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
|
230
|
+
when OP_CHECKLOCKTIMEVERIFY
|
|
231
|
+
next unless flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
|
232
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
233
|
+
# Note that elsewhere numeric opcodes are limited to operands in the range -2**31+1 to 2**31-1,
|
|
234
|
+
# however it is legal for opcodes to produce results exceeding that range.
|
|
235
|
+
# This limitation is implemented by CScriptNum's default 4-byte limit.
|
|
236
|
+
# If we kept to that limit we'd have a year 2038 problem,
|
|
237
|
+
# even though the nLockTime field in transactions themselves is uint32 which only becomes meaningless after the year 2106.
|
|
238
|
+
# Thus as a special case we tell CScriptNum to accept up to 5-byte bignums,
|
|
239
|
+
# which are good until 2**39-1, well beyond the 2**32-1 limit of the nLockTime field itself.
|
|
240
|
+
locktime = cast_to_int(stack.last, 5)
|
|
241
|
+
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if locktime < 0
|
|
242
|
+
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME) unless checker.check_locktime(locktime)
|
|
243
|
+
when OP_CHECKSEQUENCEVERIFY
|
|
244
|
+
next unless flag?(SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
|
245
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
246
|
+
|
|
247
|
+
# nSequence, like nLockTime, is a 32-bit unsigned integer field.
|
|
248
|
+
# See the comment in CHECKLOCKTIMEVERIFY regarding 5-byte numeric operands.
|
|
249
|
+
sequence = cast_to_int(stack.last, 5)
|
|
250
|
+
|
|
251
|
+
# In the rare event that the argument may be < 0 due to some arithmetic being done first,
|
|
252
|
+
# you can always use 0 MAX CHECKSEQUENCEVERIFY.
|
|
253
|
+
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if sequence < 0
|
|
254
|
+
|
|
255
|
+
# To provide for future soft-fork extensibility,
|
|
256
|
+
# if the operand has the disabled lock-time flag set, CHECKSEQUENCEVERIFY behaves as a NOP.
|
|
257
|
+
next if (sequence & Tapyrus::TxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0
|
|
258
|
+
|
|
259
|
+
# Compare the specified sequence number with the input.
|
|
260
|
+
unless checker.check_sequence(sequence)
|
|
261
|
+
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME)
|
|
262
|
+
end
|
|
263
|
+
when OP_DUP
|
|
264
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
265
|
+
stack << stack.last
|
|
266
|
+
when OP_2DUP
|
|
267
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
268
|
+
2.times { stack << stack[-2] }
|
|
269
|
+
when OP_3DUP
|
|
270
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
|
271
|
+
3.times { stack << stack[-3] }
|
|
272
|
+
when OP_IFDUP
|
|
273
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
274
|
+
stack << stack.last if cast_to_bool(stack.last)
|
|
275
|
+
when OP_RIPEMD160
|
|
276
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
277
|
+
stack << Digest::RMD160.hexdigest(pop_string.htb)
|
|
278
|
+
when OP_SHA1
|
|
279
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
280
|
+
stack << Digest::SHA1.hexdigest(pop_string.htb)
|
|
281
|
+
when OP_SHA256
|
|
282
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
283
|
+
stack << Digest::SHA256.hexdigest(pop_string.htb)
|
|
284
|
+
when OP_HASH160
|
|
285
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
286
|
+
stack << Tapyrus.hash160(pop_string)
|
|
287
|
+
when OP_HASH256
|
|
288
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
289
|
+
stack << Tapyrus.double_sha256(pop_string.htb).bth
|
|
290
|
+
when OP_VERIFY
|
|
291
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
292
|
+
return set_error(SCRIPT_ERR_VERIFY) unless pop_bool
|
|
293
|
+
when OP_TOALTSTACK
|
|
294
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
295
|
+
alt_stack << stack.pop
|
|
296
|
+
when OP_FROMALTSTACK
|
|
297
|
+
return set_error(SCRIPT_ERR_INVALID_ALTSTACK_OPERATION) if alt_stack.size < 1
|
|
298
|
+
stack << alt_stack.pop
|
|
299
|
+
when OP_DROP
|
|
300
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
301
|
+
stack.pop
|
|
302
|
+
when OP_2DROP
|
|
303
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
304
|
+
2.times { stack.pop }
|
|
305
|
+
when OP_NIP
|
|
306
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
307
|
+
stack.delete_at(-2)
|
|
308
|
+
when OP_OVER
|
|
309
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
310
|
+
stack << stack[-2]
|
|
311
|
+
when OP_2OVER
|
|
312
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 4
|
|
313
|
+
2.times { stack << stack[-4]}
|
|
314
|
+
when OP_PICK, OP_ROLL
|
|
315
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
316
|
+
pos = pop_int
|
|
317
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if pos < 0 || pos >= stack.size
|
|
318
|
+
stack << stack[-pos - 1]
|
|
319
|
+
stack.delete_at(-pos - 2) if opcode == OP_ROLL
|
|
320
|
+
when OP_ROT
|
|
321
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
|
322
|
+
stack << stack[-3]
|
|
323
|
+
stack.delete_at(-4)
|
|
324
|
+
when OP_2ROT
|
|
325
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 6
|
|
326
|
+
2.times { stack << stack[-6] }
|
|
327
|
+
2.times { stack.delete_at(-7) }
|
|
328
|
+
when OP_SWAP
|
|
329
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
330
|
+
tmp = stack.last
|
|
331
|
+
stack[-1] = stack[-2]
|
|
332
|
+
stack[-2] = tmp
|
|
333
|
+
when OP_2SWAP
|
|
334
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 4
|
|
335
|
+
2.times {stack << stack[-4]}
|
|
336
|
+
2.times {stack.delete_at(-5)}
|
|
337
|
+
when OP_TUCK
|
|
338
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
339
|
+
stack.insert(-3, stack.last)
|
|
340
|
+
when OP_ABS
|
|
341
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
342
|
+
v = pop_int
|
|
343
|
+
push_int(v.abs)
|
|
344
|
+
when OP_BOOLAND
|
|
345
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
346
|
+
a, b = pop_int(2)
|
|
347
|
+
push_int((!a.zero? && !b.zero?) ? 1 : 0)
|
|
348
|
+
when OP_BOOLOR
|
|
349
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
350
|
+
a, b = pop_int(2)
|
|
351
|
+
push_int((!a.zero? || !b.zero?) ? 1 : 0)
|
|
352
|
+
when OP_NUMEQUAL, OP_NUMEQUALVERIFY
|
|
353
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
354
|
+
a, b = pop_int(2)
|
|
355
|
+
result = a == b
|
|
356
|
+
push_int(result ? 1 : 0)
|
|
357
|
+
if opcode == OP_NUMEQUALVERIFY
|
|
358
|
+
if result
|
|
359
|
+
stack.pop
|
|
360
|
+
else
|
|
361
|
+
return set_error(SCRIPT_ERR_NUMEQUALVERIFY)
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
when OP_LESSTHAN, OP_LESSTHANOREQUAL
|
|
365
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
366
|
+
a, b = pop_int(2)
|
|
367
|
+
push_int(a < b ? 1 : 0) if opcode == OP_LESSTHAN
|
|
368
|
+
push_int(a <= b ? 1 : 0) if opcode == OP_LESSTHANOREQUAL
|
|
369
|
+
when OP_GREATERTHAN, OP_GREATERTHANOREQUAL
|
|
370
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
371
|
+
a, b = pop_int(2)
|
|
372
|
+
push_int(a > b ? 1 : 0) if opcode == OP_GREATERTHAN
|
|
373
|
+
push_int(a >= b ? 1 : 0) if opcode == OP_GREATERTHANOREQUAL
|
|
374
|
+
when OP_MIN
|
|
375
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
376
|
+
push_int(pop_int(2).min)
|
|
377
|
+
when OP_MAX
|
|
378
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
379
|
+
push_int(pop_int(2).max)
|
|
380
|
+
when OP_WITHIN
|
|
381
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
|
382
|
+
x, a, b = pop_int(3)
|
|
383
|
+
push_int((a <= x && x < b) ? 1 : 0)
|
|
384
|
+
when OP_NOT
|
|
385
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
386
|
+
push_int(pop_int == 0 ? 1 : 0)
|
|
387
|
+
when OP_SIZE
|
|
388
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
389
|
+
item = stack.last
|
|
390
|
+
item = Tapyrus::Script.encode_number(item) if item.is_a?(Numeric)
|
|
391
|
+
size = item.htb.bytesize
|
|
392
|
+
push_int(size)
|
|
393
|
+
when OP_NEGATE
|
|
394
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
395
|
+
push_int(-pop_int)
|
|
396
|
+
when OP_NUMNOTEQUAL
|
|
397
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
398
|
+
a, b = pop_int(2)
|
|
399
|
+
push_int(a == b ? 0 : 1)
|
|
400
|
+
when OP_CODESEPARATOR
|
|
401
|
+
last_code_separator_index = index + 1
|
|
402
|
+
when OP_CHECKSIG, OP_CHECKSIGVERIFY
|
|
403
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 2
|
|
404
|
+
sig, pubkey = pop_string(2)
|
|
405
|
+
|
|
406
|
+
subscript = script.subscript(last_code_separator_index..-1)
|
|
407
|
+
if sig_version == :base
|
|
408
|
+
tmp = subscript.find_and_delete(Script.new << sig)
|
|
409
|
+
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE) if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
|
410
|
+
subscript = tmp
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
return false if !check_pubkey_encoding(pubkey, sig_version) || !check_signature_encoding(sig) # error already set.
|
|
414
|
+
|
|
415
|
+
success = checker.check_sig(sig, pubkey, subscript, sig_version)
|
|
416
|
+
|
|
417
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#NULLFAIL
|
|
418
|
+
if !success && flag?(SCRIPT_VERIFY_NULLFAIL) && sig.bytesize > 0
|
|
419
|
+
return set_error(SCRIPT_ERR_SIG_NULLFAIL)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
push_int(success ? 1 : 0)
|
|
423
|
+
|
|
424
|
+
if opcode == OP_CHECKSIGVERIFY
|
|
425
|
+
if success
|
|
426
|
+
stack.pop
|
|
427
|
+
else
|
|
428
|
+
return set_error(SCRIPT_ERR_CHECKSIGVERIFY)
|
|
429
|
+
end
|
|
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
|
+
unless (0..MAX_PUBKEYS_PER_MULTISIG).include?(pubkey_count)
|
|
435
|
+
return set_error(SCRIPT_ERR_PUBKEY_COUNT)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
op_count += pubkey_count
|
|
439
|
+
return set_error(SCRIPT_ERR_OP_COUNT) if op_count > MAX_OPS_PER_SCRIPT
|
|
440
|
+
|
|
441
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < pubkey_count
|
|
442
|
+
|
|
443
|
+
pubkeys = pop_string(pubkey_count)
|
|
444
|
+
pubkeys = [pubkeys] if pubkeys.is_a?(String)
|
|
445
|
+
|
|
446
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
447
|
+
|
|
448
|
+
sig_count = pop_int
|
|
449
|
+
return set_error(SCRIPT_ERR_SIG_COUNT) if sig_count < 0 || sig_count > pubkey_count
|
|
450
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < (sig_count)
|
|
451
|
+
|
|
452
|
+
sigs = pop_string(sig_count)
|
|
453
|
+
sigs = [sigs] if sigs.is_a?(String)
|
|
454
|
+
|
|
455
|
+
subscript = script.subscript(last_code_separator_index..-1)
|
|
456
|
+
|
|
457
|
+
if sig_version == :base
|
|
458
|
+
sigs.each do |sig|
|
|
459
|
+
tmp = subscript.find_and_delete(Script.new << sig)
|
|
460
|
+
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE) if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
|
461
|
+
subscript = tmp
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
success = true
|
|
466
|
+
while success && sig_count > 0
|
|
467
|
+
sig = sigs.pop
|
|
468
|
+
pubkey = pubkeys.pop
|
|
469
|
+
return false if !check_pubkey_encoding(pubkey, sig_version) || !check_signature_encoding(sig) # error already set.
|
|
470
|
+
ok = checker.check_sig(sig, pubkey, subscript, sig_version)
|
|
471
|
+
if ok
|
|
472
|
+
sig_count -= 1
|
|
473
|
+
else
|
|
474
|
+
sigs << sig
|
|
475
|
+
end
|
|
476
|
+
pubkey_count -= 1
|
|
477
|
+
success = false if sig_count > pubkey_count
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
if !success && flag?(SCRIPT_VERIFY_NULLFAIL)
|
|
481
|
+
sigs.each do |sig|
|
|
482
|
+
# If the operation failed, we require that all signatures must be empty vector
|
|
483
|
+
return set_error(SCRIPT_ERR_SIG_NULLFAIL) if sig.bytesize > 0
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# A bug causes CHECKMULTISIG to consume one extra argument whose contents were not checked in any way.
|
|
488
|
+
# Unfortunately this is a potential source of mutability,
|
|
489
|
+
# so optionally verify it is exactly equal to zero prior to removing it from the stack.
|
|
490
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
|
491
|
+
if flag?(SCRIPT_VERIFY_NULLDUMMY) && stack[-1].size > 0
|
|
492
|
+
return set_error(SCRIPT_ERR_SIG_NULLDUMMY)
|
|
493
|
+
end
|
|
494
|
+
stack.pop
|
|
495
|
+
|
|
496
|
+
push_int(success ? 1 : 0)
|
|
497
|
+
if opcode == OP_CHECKMULTISIGVERIFY
|
|
498
|
+
if success
|
|
499
|
+
stack.pop
|
|
500
|
+
else
|
|
501
|
+
return set_error(SCRIPT_ERR_CHECKMULTISIGVERIFY)
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
when OP_RETURN
|
|
505
|
+
return set_error(SCRIPT_ERR_OP_RETURN)
|
|
506
|
+
else
|
|
507
|
+
return set_error(SCRIPT_ERR_BAD_OPCODE)
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# max stack size check
|
|
513
|
+
return set_error(SCRIPT_ERR_STACK_SIZE) if stack.size + alt_stack.size > MAX_STACK_SIZE
|
|
514
|
+
end
|
|
515
|
+
rescue Exception => e
|
|
516
|
+
puts e
|
|
517
|
+
puts e.backtrace
|
|
518
|
+
return set_error(SCRIPT_ERR_UNKNOWN_ERROR, e.message)
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) unless flow_stack.empty?
|
|
522
|
+
|
|
523
|
+
set_error(SCRIPT_ERR_OK)
|
|
524
|
+
true
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
private
|
|
528
|
+
|
|
529
|
+
def flag?(flag)
|
|
530
|
+
(flags & flag) != 0
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
# pop the item with the int value for the number specified by +count+ from the stack.
|
|
534
|
+
def pop_int(count = 1)
|
|
535
|
+
i = stack.pop(count).map{ |s| cast_to_int(s) }
|
|
536
|
+
count == 1 ? i.first : i
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
# cast item to int value.
|
|
540
|
+
def cast_to_int(s, max_num_size = DEFAULT_MAX_NUM_SIZE)
|
|
541
|
+
data = s.htb
|
|
542
|
+
raise '"script number overflow"' if data.bytesize > max_num_size
|
|
543
|
+
if require_minimal && data.bytesize > 0
|
|
544
|
+
if data.bytes[-1] & 0x7f == 0 && (data.bytesize <= 1 || data.bytes[data.bytesize - 2] & 0x80 == 0)
|
|
545
|
+
raise 'non-minimally encoded script number'
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
Script.decode_number(s)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# push +i+ into stack as encoded by Script#encode_number
|
|
552
|
+
def push_int(i)
|
|
553
|
+
stack << Script.encode_number(i)
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
# pop the item with the string(hex) value for the number specified by +count+ from the stack.
|
|
557
|
+
def pop_string(count = 1)
|
|
558
|
+
s = stack.pop(count).map do |s|
|
|
559
|
+
case s
|
|
560
|
+
when Numeric
|
|
561
|
+
Script.encode_number(s)
|
|
562
|
+
else
|
|
563
|
+
s
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
count == 1 ? s.first : s
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# pop the item with the boolean value from the stack.
|
|
570
|
+
def pop_bool
|
|
571
|
+
cast_to_bool(pop_string.htb)
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# see https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L36-L49
|
|
575
|
+
def cast_to_bool(v)
|
|
576
|
+
case v
|
|
577
|
+
when Numeric
|
|
578
|
+
return v != 0
|
|
579
|
+
when String
|
|
580
|
+
v.each_byte.with_index do |b, i|
|
|
581
|
+
return !(i == (v.bytesize - 1) && b == 0x80) unless b == 0
|
|
582
|
+
end
|
|
583
|
+
false
|
|
584
|
+
else
|
|
585
|
+
false
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
def check_signature_encoding(sig)
|
|
590
|
+
return true if sig.size.zero?
|
|
591
|
+
if (flag?(SCRIPT_VERIFY_DERSIG) || flag?(SCRIPT_VERIFY_LOW_S) || flag?(SCRIPT_VERIFY_STRICTENC)) && !Key.valid_signature_encoding?(sig.htb)
|
|
592
|
+
return set_error(SCRIPT_ERR_SIG_DER)
|
|
593
|
+
elsif flag?(SCRIPT_VERIFY_LOW_S) && !low_der_signature?(sig)
|
|
594
|
+
return false
|
|
595
|
+
elsif flag?(SCRIPT_VERIFY_STRICTENC) && !defined_hashtype_signature?(sig)
|
|
596
|
+
return set_error(SCRIPT_ERR_SIG_HASHTYPE)
|
|
597
|
+
end
|
|
598
|
+
true
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
def low_der_signature?(sig)
|
|
602
|
+
return set_error(SCRIPT_ERR_SIG_DER) unless Key.valid_signature_encoding?(sig.htb)
|
|
603
|
+
return set_error(SCRIPT_ERR_SIG_HIGH_S) unless Key.low_signature?(sig.htb)
|
|
604
|
+
true
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def defined_hashtype_signature?(signature)
|
|
608
|
+
sig = signature.htb
|
|
609
|
+
return false if sig.empty?
|
|
610
|
+
s = sig.unpack('C*')
|
|
611
|
+
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
|
|
612
|
+
hash_type &= (~(Tapyrus::SIGHASH_FORK_ID)) if Tapyrus.chain_params.fork_chain? # for fork coin.
|
|
613
|
+
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single]
|
|
614
|
+
true
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def check_pubkey_encoding(pubkey, sig_version)
|
|
618
|
+
if flag?(SCRIPT_VERIFY_STRICTENC) && !Key.compress_or_uncompress_pubkey?(pubkey)
|
|
619
|
+
return set_error(SCRIPT_ERR_PUBKEYTYPE)
|
|
620
|
+
end
|
|
621
|
+
# Only compressed keys are accepted in segwit
|
|
622
|
+
if flag?(SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) &&
|
|
623
|
+
sig_version == :witness_v0 && !Key.compress_pubkey?(pubkey)
|
|
624
|
+
return set_error(SCRIPT_ERR_WITNESS_PUBKEYTYPE)
|
|
625
|
+
end
|
|
626
|
+
true
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def minimal_push?(data, opcode)
|
|
630
|
+
if data.bytesize.zero?
|
|
631
|
+
return opcode == OP_0
|
|
632
|
+
elsif data.bytesize == 1 && data.bytes[0] >= 1 && data.bytes[0] <= 16
|
|
633
|
+
return opcode == OP_1 + (data.bytes[0] - 1)
|
|
634
|
+
elsif data.bytesize == 1 && data.bytes[0] == 0x81
|
|
635
|
+
return opcode == OP_1NEGATE
|
|
636
|
+
elsif data.bytesize <= 75
|
|
637
|
+
return opcode == data.bytesize
|
|
638
|
+
elsif data.bytesize <= 255
|
|
639
|
+
return opcode == OP_PUSHDATA1
|
|
640
|
+
elsif data.bytesize <= 65535
|
|
641
|
+
return opcode == OP_PUSHDATA2
|
|
642
|
+
end
|
|
643
|
+
true
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
def verify_pushdata_length(chunk)
|
|
647
|
+
buf = StringIO.new(chunk)
|
|
648
|
+
opcode = buf.read(1).ord
|
|
649
|
+
offset = 1
|
|
650
|
+
len = case opcode
|
|
651
|
+
when OP_PUSHDATA1
|
|
652
|
+
offset += 1
|
|
653
|
+
buf.read(1).unpack('C').first
|
|
654
|
+
when OP_PUSHDATA2
|
|
655
|
+
offset += 2
|
|
656
|
+
buf.read(2).unpack('v').first
|
|
657
|
+
when OP_PUSHDATA4
|
|
658
|
+
offset += 4
|
|
659
|
+
buf.read(4).unpack('V').first
|
|
660
|
+
else
|
|
661
|
+
opcode
|
|
662
|
+
end
|
|
663
|
+
chunk.bytesize == len + offset
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
end
|