bitcoinrb 0.0.1

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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +41 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/bitcoinrb.gemspec +32 -0
  15. data/exe/bitcoinrb-cli +5 -0
  16. data/exe/bitcoinrbd +49 -0
  17. data/lib/bitcoin.rb +121 -0
  18. data/lib/bitcoin/base58.rb +40 -0
  19. data/lib/bitcoin/block_header.rb +41 -0
  20. data/lib/bitcoin/chain_params.rb +57 -0
  21. data/lib/bitcoin/chainparams/mainnet.yml +25 -0
  22. data/lib/bitcoin/chainparams/regtest.yml +20 -0
  23. data/lib/bitcoin/chainparams/testnet.yml +24 -0
  24. data/lib/bitcoin/connection.rb +66 -0
  25. data/lib/bitcoin/ext_key.rb +205 -0
  26. data/lib/bitcoin/key.rb +131 -0
  27. data/lib/bitcoin/logger.rb +18 -0
  28. data/lib/bitcoin/merkle_tree.rb +120 -0
  29. data/lib/bitcoin/message.rb +42 -0
  30. data/lib/bitcoin/message/addr.rb +74 -0
  31. data/lib/bitcoin/message/base.rb +40 -0
  32. data/lib/bitcoin/message/block.rb +41 -0
  33. data/lib/bitcoin/message/error.rb +10 -0
  34. data/lib/bitcoin/message/fee_filter.rb +27 -0
  35. data/lib/bitcoin/message/filter_add.rb +28 -0
  36. data/lib/bitcoin/message/filter_clear.rb +17 -0
  37. data/lib/bitcoin/message/filter_load.rb +43 -0
  38. data/lib/bitcoin/message/get_addr.rb +17 -0
  39. data/lib/bitcoin/message/get_blocks.rb +29 -0
  40. data/lib/bitcoin/message/get_data.rb +21 -0
  41. data/lib/bitcoin/message/get_headers.rb +28 -0
  42. data/lib/bitcoin/message/handler.rb +170 -0
  43. data/lib/bitcoin/message/headers.rb +34 -0
  44. data/lib/bitcoin/message/headers_parser.rb +24 -0
  45. data/lib/bitcoin/message/inv.rb +21 -0
  46. data/lib/bitcoin/message/inventories_parser.rb +23 -0
  47. data/lib/bitcoin/message/inventory.rb +47 -0
  48. data/lib/bitcoin/message/mem_pool.rb +17 -0
  49. data/lib/bitcoin/message/merkle_block.rb +42 -0
  50. data/lib/bitcoin/message/not_found.rb +29 -0
  51. data/lib/bitcoin/message/ping.rb +30 -0
  52. data/lib/bitcoin/message/pong.rb +26 -0
  53. data/lib/bitcoin/message/reject.rb +46 -0
  54. data/lib/bitcoin/message/send_cmpct.rb +43 -0
  55. data/lib/bitcoin/message/send_headers.rb +16 -0
  56. data/lib/bitcoin/message/tx.rb +30 -0
  57. data/lib/bitcoin/message/ver_ack.rb +17 -0
  58. data/lib/bitcoin/message/version.rb +79 -0
  59. data/lib/bitcoin/mnemonic.rb +76 -0
  60. data/lib/bitcoin/mnemonic/wordlist/chinese_simplified.txt +2048 -0
  61. data/lib/bitcoin/mnemonic/wordlist/chinese_traditional.txt +2048 -0
  62. data/lib/bitcoin/mnemonic/wordlist/english.txt +2048 -0
  63. data/lib/bitcoin/mnemonic/wordlist/french.txt +2048 -0
  64. data/lib/bitcoin/mnemonic/wordlist/italian.txt +2048 -0
  65. data/lib/bitcoin/mnemonic/wordlist/japanese.txt +2048 -0
  66. data/lib/bitcoin/mnemonic/wordlist/spanish.txt +2048 -0
  67. data/lib/bitcoin/nodes.rb +5 -0
  68. data/lib/bitcoin/nodes/spv.rb +13 -0
  69. data/lib/bitcoin/nodes/spv/cli.rb +12 -0
  70. data/lib/bitcoin/nodes/spv/daemon.rb +21 -0
  71. data/lib/bitcoin/opcodes.rb +172 -0
  72. data/lib/bitcoin/out_point.rb +31 -0
  73. data/lib/bitcoin/script/script.rb +347 -0
  74. data/lib/bitcoin/script/script_error.rb +168 -0
  75. data/lib/bitcoin/script/script_interpreter.rb +694 -0
  76. data/lib/bitcoin/script/tx_checker.rb +44 -0
  77. data/lib/bitcoin/script_witness.rb +29 -0
  78. data/lib/bitcoin/secp256k1.rb +10 -0
  79. data/lib/bitcoin/secp256k1/native.rb +22 -0
  80. data/lib/bitcoin/secp256k1/ruby.rb +96 -0
  81. data/lib/bitcoin/tx.rb +191 -0
  82. data/lib/bitcoin/tx_in.rb +45 -0
  83. data/lib/bitcoin/tx_out.rb +32 -0
  84. data/lib/bitcoin/util.rb +105 -0
  85. data/lib/bitcoin/version.rb +3 -0
  86. metadata +256 -0
@@ -0,0 +1,5 @@
1
+ module Bitcoin
2
+ module Nodes
3
+ autoload :SPV, 'bitcoin/nodes/spv'
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module Bitcoin
2
+ module Nodes
3
+
4
+ # SPV module
5
+ module SPV
6
+
7
+ autoload :CLI, 'bitcoin/nodes/spv/cli'
8
+ autoload :Daemon, 'bitcoin/nodes/spv/daemon'
9
+
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'thor'
2
+
3
+ module Bitcoin
4
+ module Nodes
5
+ module SPV
6
+
7
+ class CLI < Thor
8
+
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ require 'daemon_spawn'
2
+ module Bitcoin
3
+ module Nodes
4
+ module SPV
5
+
6
+ # SPV node daemon
7
+ class Daemon < DaemonSpawn::Base
8
+
9
+ def start(args)
10
+
11
+ end
12
+
13
+ def stop
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,172 @@
1
+ module Bitcoin
2
+
3
+ # https://bitcoin.org/en/developer-reference#opcodes
4
+ module Opcodes
5
+
6
+ module_function
7
+
8
+ # https://en.bitcoin.it/wiki/Script#Constants
9
+ OP_0 = 0x00
10
+ OP_1 = 0x51
11
+ OP_2 = 0x52
12
+ OP_3 = 0x53
13
+ OP_4 = 0x54
14
+ OP_5 = 0x55
15
+ OP_6 = 0x56
16
+ OP_7 = 0x57
17
+ OP_8 = 0x58
18
+ OP_9 = 0x59
19
+ OP_10 = 0x5a
20
+ OP_11 = 0x5b
21
+ OP_12 = 0x5c
22
+ OP_13 = 0x5d
23
+ OP_14 = 0x5e
24
+ OP_15 = 0x5f
25
+ OP_16 = 0x60
26
+
27
+ OP_PUSHDATA1 = 0x4c
28
+ OP_PUSHDATA2 = 0x4d
29
+ OP_PUSHDATA4 = 0x4e
30
+ OP_1NEGATE = 0x4f
31
+
32
+ # https://en.bitcoin.it/wiki/Script#Flow_control
33
+ OP_NOP = 0x61
34
+ OP_IF = 0x63
35
+ OP_NOTIF = 0x64
36
+ OP_ELSE = 0x67
37
+ OP_ENDIF = 0x68
38
+ OP_VERIFY = 0x69
39
+ OP_RETURN = 0x6a
40
+
41
+ # https://en.bitcoin.it/wiki/Script#Stack
42
+ OP_TOALTSTACK = 0x6b
43
+ OP_FROMALTSTACK = 0x6c
44
+ OP_IFDUP = 0x73
45
+ OP_DEPTH = 0x74
46
+ OP_DROP = 0x75
47
+ OP_DUP = 0x76
48
+ OP_NIP = 0x77
49
+ OP_OVER = 0x78
50
+ OP_PICK = 0x79
51
+ OP_ROLL = 0x7a
52
+ OP_ROT = 0x7b
53
+ OP_SWAP = 0x7c
54
+ OP_TUCK = 0x7d
55
+ OP_2DROP = 0x6d
56
+ OP_2DUP = 0x6e
57
+ OP_3DUP = 0x6f
58
+ OP_2OVER = 0x70
59
+ OP_2ROT = 0x71
60
+ OP_2SWAP = 0x72
61
+
62
+ # https://en.bitcoin.it/wiki/Script#Splice
63
+ OP_CAT = 0x7e # disabled
64
+ OP_SUBSTR = 0x7f # disabled
65
+ OP_LEFT = 0x80 # disabled
66
+ OP_RIGHT = 0x81 # disabled
67
+ OP_SIZE = 0x82
68
+
69
+ # https://en.bitcoin.it/wiki/Script#Bitwise_logic
70
+ OP_INVERT = 0x83 # disabled
71
+ OP_AND = 0x84 # disabled
72
+ OP_OR = 0x85 # disabled
73
+ OP_XOR = 0x86 # disabled
74
+ OP_EQUAL = 0x87
75
+ OP_EQUALVERIFY = 0x88
76
+
77
+ # https://en.bitcoin.it/wiki/Script#Arithmetic
78
+ OP_1ADD = 0x8b
79
+ OP_1SUB = 0x8c
80
+ OP_2MUL = 0x8d # disabled
81
+ OP_2DIV = 0x8e # disabled
82
+ OP_NEGATE = 0x8f
83
+ OP_ABS = 0x90
84
+ OP_NOT = 0x91
85
+ OP_0NOTEQUAL = 0x92
86
+ OP_ADD = 0x93
87
+ OP_SUB = 0x94
88
+ OP_MUL = 0x95 # disabled
89
+ OP_DIV = 0x96 # disabled
90
+ OP_MOD = 0x97 # disabled
91
+ OP_LSHIFT = 0x98 # disabled
92
+ OP_RSHIFT = 0x99 # disabled
93
+ OP_BOOLAND = 0x9a
94
+ OP_BOOLOR = 0x9b
95
+ OP_NUMEQUAL = 0x9c
96
+ OP_NUMEQUALVERIFY = 0x9d
97
+ OP_NUMNOTEQUAL = 0x9e
98
+ OP_LESSTHAN = 0x9f
99
+ OP_GREATERTHAN = 0xa0
100
+ OP_LESSTHANOREQUAL = 0xa1
101
+ OP_GREATERTHANOREQUAL = 0xa2
102
+ OP_MIN = 0xa3
103
+ OP_MAX = 0xa4
104
+ OP_WITHIN = 0xa5
105
+
106
+ # https://en.bitcoin.it/wiki/Script#Crypto
107
+ OP_RIPEMD160 = 0xa6
108
+ OP_SHA1 = 0xa7
109
+ OP_SHA256 = 0xa8
110
+ OP_HASH160 = 0xa9
111
+ OP_HASH256 = 0xaa
112
+ OP_CODESEPARATOR = 0xab
113
+ OP_CHECKSIG = 0xac
114
+ OP_CHECKSIGVERIFY= 0xad
115
+ OP_CHECKMULTISIG = 0xae
116
+ OP_CHECKMULTISIGVERIFY = 0xaf
117
+
118
+ # https://en.bitcoin.it/wiki/Script#Locktime
119
+ OP_CHECKLOCKTIMEVERIFY = OP_NOP2 = 0xb1
120
+ OP_CHECKSEQUENCEVERIFY = OP_NOP3 = 0xb2
121
+
122
+ # https://en.bitcoin.it/wiki/Script#Reserved_words
123
+ OP_RESERVED = 0x50
124
+ OP_VER = 0x62
125
+ OP_VERIF = 0x65
126
+ OP_VERNOTIF = 0x66
127
+ OP_RESERVED1= 0x89
128
+ OP_RESERVED2 = 0x8a
129
+
130
+ OP_NOP1 = 0xb0
131
+ OP_NOP4 = 0xb3
132
+ OP_NOP5 = 0xb4
133
+ OP_NOP6 = 0xb5
134
+ OP_NOP7 = 0xb6
135
+ OP_NOP8 = 0xb7
136
+ OP_NOP9 = 0xb8
137
+ OP_NOP10 = 0xb9
138
+
139
+ OPCODES_MAP = Hash[*constants.grep(/^OP_/).map { |c| [const_get(c), c.to_s] }.flatten]
140
+ NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
141
+
142
+ def opcode_to_name(opcode)
143
+ return OPCODES_MAP[opcode].delete('OP_') if opcode == OP_0 || (opcode <= OP_16 && opcode >= OP_1)
144
+ OPCODES_MAP[opcode]
145
+ end
146
+
147
+ def name_to_opcode(name)
148
+ return NAME_MAP['OP_' + name] if name =~ /^\d/ && name.to_i < 17 && name.to_i > -1
149
+ NAME_MAP[name]
150
+ end
151
+
152
+ # whether opcode is predefined opcode
153
+ def defined?(opcode)
154
+ !opcode_to_name(opcode).nil?
155
+ end
156
+
157
+ def small_int_to_opcode(int)
158
+ return OP_0 if int == 0
159
+ return OP_1NEGATE if int == -1
160
+ return OP_1 + (int - 1) if int >= 1 && int <= 16
161
+ nil
162
+ end
163
+
164
+ def opcode_to_small_int(opcode)
165
+ return 0 if opcode == ''.b || opcode == OP_0
166
+ return -1 if opcode == OP_1NEGATE
167
+ return opcode - (OP_1 - 1) if opcode >= OP_1 && opcode <= OP_16
168
+ nil
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,31 @@
1
+ module Bitcoin
2
+
3
+ # outpoint class
4
+ class OutPoint
5
+
6
+ COINBASE_HASH = '0000000000000000000000000000000000000000000000000000000000000000'
7
+ COINBASE_INDEX = 4294967295
8
+
9
+ attr_reader :hash
10
+ attr_reader :index
11
+
12
+ def initialize(hash, index)
13
+ @hash = hash
14
+ @index = index
15
+ end
16
+
17
+ def coinbase?
18
+ hash == COINBASE_HASH && index == COINBASE_INDEX
19
+ end
20
+
21
+ def to_payload
22
+ [hash.htb.reverse, index].pack('a32V')
23
+ end
24
+
25
+ def self.create_coinbase_outpoint
26
+ new(COINBASE_HASH, COINBASE_INDEX)
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,347 @@
1
+ module Bitcoin
2
+
3
+ # bitcoin script
4
+ class Script
5
+ include Bitcoin::Opcodes
6
+
7
+ # witness version
8
+ WITNESS_VERSION = 0x00
9
+
10
+ # Maximum script length in bytes
11
+ MAX_SCRIPT_SIZE = 10000
12
+
13
+ # Maximum number of public keys per multisig
14
+ MAX_PUBKEYS_PER_MULTISIG = 20
15
+
16
+ # Maximum number of non-push operations per script
17
+ MAX_OPS_PER_SCRIPT = 201
18
+
19
+ # Maximum number of bytes pushable to the stack
20
+ MAX_SCRIPT_ELEMENT_SIZE = 520
21
+
22
+ # Maximum number of size in the stack
23
+ MAX_STACK_SIZE = 1000
24
+
25
+ # Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
26
+ LOCKTIME_THRESHOLD = 500000000
27
+
28
+ # Signature hash types/flags
29
+ SIGHASH_TYPE = { all: 1, none: 2, single: 3, anyonecanpay: 128 }
30
+
31
+ # Maximum number length in bytes
32
+ DEFAULT_MAX_NUM_SIZE = 4
33
+
34
+ attr_accessor :chunks
35
+
36
+ def initialize
37
+ @chunks = []
38
+ end
39
+
40
+ # generate P2PKH script
41
+ def self.to_p2pkh(pubkey_hash)
42
+ new << OP_DUP << OP_HASH160 << pubkey_hash << OP_EQUALVERIFY << OP_CHECKSIG
43
+ end
44
+
45
+ # generate P2WPKH script
46
+ def self.to_p2wpkh(pubkey_hash)
47
+ new << WITNESS_VERSION << pubkey_hash
48
+ end
49
+
50
+ # generate m of n multisig p2sh script
51
+ # @param [String] m the number of signatures required for multisig
52
+ # @param [Array] pubkeys array of public keys that compose multisig
53
+ # @return [Script, Script] first element is p2sh script, second one is redeem script.
54
+ def self.to_p2sh_multisig_script(m, pubkeys)
55
+ redeem_script = to_multisig_script(m, pubkeys)
56
+ p2sh_script = new << OP_HASH160 << redeem_script.to_hash160 << OP_EQUAL
57
+ [p2sh_script, redeem_script]
58
+ end
59
+
60
+ # generate m of n multisig script
61
+ # @param [String] m the number of signatures required for multisig
62
+ # @param [Array] pubkeys array of public keys that compose multisig
63
+ # @return [Script] multisig script.
64
+ def self.to_multisig_script(m, pubkeys)
65
+ new << m << pubkeys << pubkeys.size << OP_CHECKMULTISIG
66
+ end
67
+
68
+ # generate p2wsh script for +redeem_script+
69
+ # @param [Script] redeem_script target redeem script
70
+ # @param [Script] p2wsh script
71
+ def self.to_p2wsh(redeem_script)
72
+ new << WITNESS_VERSION << redeem_script.to_sha256
73
+ end
74
+
75
+ # generate script from string.
76
+ def self.from_string(string)
77
+ script = new
78
+ string.split(' ').each do |v|
79
+ opcode = Opcodes.name_to_opcode(v)
80
+ if opcode
81
+ script << (v =~ /^\d/ && Opcodes.small_int_to_opcode(v.ord) ? v.ord : opcode)
82
+ else
83
+ script << v
84
+ end
85
+ end
86
+ script
87
+ end
88
+
89
+ def self.parse_from_payload(payload)
90
+ s = new
91
+ buf = StringIO.new(payload)
92
+ until buf.eof?
93
+ opcode = buf.read(1)
94
+ if opcode.pushdata?
95
+ pushcode = opcode.ord
96
+ len = case pushcode
97
+ when OP_PUSHDATA1
98
+ buf.read(1).unpack('C').first
99
+ when OP_PUSHDATA2
100
+ buf.read(2).unpack('v').first
101
+ when OP_PUSHDATA4
102
+ buf.read(4).unpack('V').first
103
+ else
104
+ pushcode if pushcode < OP_PUSHDATA1
105
+ end
106
+ s << buf.read(len).bth if len
107
+ else
108
+ s << opcode.ord
109
+ end
110
+ end
111
+ s
112
+ end
113
+
114
+ def to_payload
115
+ chunks.join
116
+ end
117
+
118
+ def to_addr
119
+ return p2pkh_addr if p2pkh?
120
+ return p2wpkh_addr if p2wpkh?
121
+ return p2wsh_addr if p2wsh?
122
+ return p2sh_addr if p2sh?
123
+ end
124
+
125
+ # whether this script is a P2PKH format script.
126
+ def p2pkh?
127
+ return false unless chunks.size == 5
128
+ [OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG] ==
129
+ (chunks[0..1]+ chunks[3..4]).map(&:ord) && chunks[2].bytesize == 21
130
+ end
131
+
132
+ # whether this script is a P2WPKH format script.
133
+ def p2wpkh?
134
+ return false unless chunks.size == 2
135
+ chunks[0].ord == WITNESS_VERSION && chunks[1].bytesize == 21
136
+ end
137
+
138
+ def p2wsh?
139
+ return false unless chunks.size == 2
140
+ chunks[0].ord == WITNESS_VERSION && chunks[1].bytesize == 33
141
+ end
142
+
143
+ def p2sh?
144
+ return false unless chunks.size == 3
145
+ OP_HASH160 == chunks[0].ord && OP_EQUAL == chunks[2].ord && chunks[1].bytesize == 21
146
+ end
147
+
148
+ # whether data push only script which dose not include other opcode
149
+ def data_only?
150
+ chunks.each do |c|
151
+ return false if !c.opcode.nil? && c.opcode > OP_16
152
+ end
153
+ true
154
+ end
155
+
156
+ # A witness program is any valid Script that consists of a 1-byte push opcode followed by a data push between 2 and 40 bytes.
157
+ def witness_program?
158
+ return false if size < 4 || size > 42 || chunks.size < 2
159
+ opcode = chunks[0].opcode
160
+ return false if opcode != OP_0 && (opcode < OP_1 || opcode > OP_16)
161
+ return false unless chunks[1].pushdata?
162
+ program_size = chunks[1].pushed_data.bytesize
163
+ program_size >= 2 && program_size <= 40
164
+ end
165
+
166
+ # get witness version and witness program
167
+ def witness_data
168
+ version = opcode_to_small_int(chunks[0].opcode)
169
+ program = chunks[1].pushed_data
170
+ [version, program]
171
+ end
172
+
173
+ # append object to payload
174
+ def <<(obj)
175
+ if obj.is_a?(Integer)
176
+ push_int(obj)
177
+ elsif obj.is_a?(String)
178
+ append_data(obj.b)
179
+ elsif obj.is_a?(Array)
180
+ obj.each { |o| self.<< o}
181
+ self
182
+ end
183
+ end
184
+
185
+ # push integer to stack.
186
+ def push_int(n)
187
+ begin
188
+ append_opcode(n)
189
+ rescue ArgumentError
190
+ append_data(Script.encode_number(n))
191
+ end
192
+ self
193
+ end
194
+
195
+ # append opcode to payload
196
+ # @param [Integer] opcode append opcode which defined by Bitcoin::Opcodes
197
+ # @return [Script] return self
198
+ def append_opcode(opcode)
199
+ opcode = Opcodes.small_int_to_opcode(opcode) if -1 <= opcode && opcode <= 16
200
+ raise ArgumentError, "specified invalid opcode #{opcode}." unless Opcodes.defined?(opcode)
201
+ chunks << opcode.chr
202
+ self
203
+ end
204
+
205
+ # append data to payload with pushdata opcode
206
+ # @param [String] data append data. this data is not binary
207
+ # @return [Script] return self
208
+ def append_data(data)
209
+ chunks << Bitcoin::Script.pack_pushdata(data.htb)
210
+ self
211
+ end
212
+
213
+ def to_s
214
+ chunks.map { |c|
215
+ if c.pushdata?
216
+ v = Opcodes.opcode_to_small_int(c.ord)
217
+ v ? v : c.pushed_data.bth
218
+ else
219
+ Opcodes.opcode_to_name(c.ord)
220
+ end
221
+ }.join(' ')
222
+ end
223
+
224
+ # generate sha-256 hash for payload
225
+ def to_sha256
226
+ Bitcoin.sha256(to_payload).bth
227
+ end
228
+
229
+ # generate hash160 hash for payload
230
+ def to_hash160
231
+ Bitcoin.hash160(to_payload.bth)
232
+ end
233
+
234
+ # script size
235
+ def size
236
+ to_payload.bytesize
237
+ end
238
+
239
+ # encode int value to script number hex.
240
+ # The stacks hold byte vectors.
241
+ # When used as numbers, byte vectors are interpreted as little-endian variable-length integers
242
+ # with the most significant bit determining the sign of the integer.
243
+ # Thus 0x81 represents -1. 0x80 is another representation of zero (so called negative 0).
244
+ # Positive 0 is represented by a null-length vector.
245
+ # Byte vectors are interpreted as Booleans where False is represented by any representation of zero,
246
+ # and True is represented by any representation of non-zero.
247
+ def self.encode_number(i)
248
+ return '' if i == 0
249
+ negative = i < 0
250
+
251
+ hex = i.abs.to_s(16)
252
+ hex = '0' + hex unless (hex.length % 2).zero?
253
+ v = hex.htb.reverse # change endian
254
+
255
+ v = v << (negative ? 0x80 : 0x00) unless (v[-1].unpack('C').first & 0x80) == 0
256
+ v[-1] = [v[-1].unpack('C').first | 0x80].pack('C') if negative
257
+ v.bth
258
+ end
259
+
260
+ # decode script number hex to int value
261
+ def self.decode_number(s)
262
+ v = s.htb.reverse
263
+ return 0 if v.length.zero?
264
+ mbs = v[0].unpack('C').first
265
+ v[0] = [mbs - 0x80].pack('C') unless (mbs & 0x80) == 0
266
+ result = v.bth.to_i(16)
267
+ result = -result unless (mbs & 0x80) == 0
268
+ result
269
+ end
270
+
271
+ # binary +data+ convert pushdata which contains data length and append PUSHDATA opcode if necessary.
272
+ def self.pack_pushdata(data)
273
+ size = data.bytesize
274
+ header = if size < OP_PUSHDATA1
275
+ [size].pack('C')
276
+ elsif size < 0xff
277
+ [OP_PUSHDATA1, size].pack('CC')
278
+ elsif size < 0xffff
279
+ [OP_PUSHDATA2, size].pack('Cv')
280
+ elsif size < 0xffffffff
281
+ [OP_PUSHDATA4, size].pack('CV')
282
+ else
283
+ raise ArgumentError, 'data size is too big.'
284
+ end
285
+ header + data
286
+ end
287
+
288
+ # subscript this script to the specified range.
289
+ def subscript(*args)
290
+ s = self.class.new
291
+ s.chunks = chunks[*args]
292
+ s
293
+ end
294
+
295
+ # removes chunks matching subscript byte-for-byte and returns as a new object.
296
+ def find_and_delete(subscript)
297
+ raise ArgumentError, 'subscript must be Bitcoin::Script' unless subscript.is_a?(Script)
298
+ diff = to_payload.bth.gsub(subscript.to_payload.bth, '')
299
+ Script.parse_from_payload(diff.htb)
300
+ end
301
+
302
+ def ==(other)
303
+ return false unless other
304
+ chunks == other.chunks
305
+ end
306
+
307
+ private
308
+
309
+ # generate p2pkh address. if script dose not p2pkh, return nil.
310
+ def p2pkh_addr
311
+ return nil unless p2pkh?
312
+ hash160 = chunks[2].pushed_data.bth
313
+ return nil unless hash160.htb.bytesize == 20
314
+ hex = Bitcoin.chain_params.address_version + hash160
315
+ Bitcoin.encode_base58_address(hex)
316
+ end
317
+
318
+ # generate p2wpkh address. if script dose not p2wpkh, return nil.
319
+ def p2wpkh_addr
320
+ p2wpkh? ? bech32_addr : nil
321
+ end
322
+
323
+ # generate p2sh address. if script dose not p2sh, return nil.
324
+ def p2sh_addr
325
+ return nil unless p2sh?
326
+ hash160 = chunks[1].pushed_data.bth
327
+ return nil unless hash160.htb.bytesize == 20
328
+ hex = Bitcoin.chain_params.p2sh_version + hash160
329
+ Bitcoin.encode_base58_address(hex)
330
+ end
331
+
332
+ # generate p2wsh address. if script dose not p2wsh, return nil.
333
+ def p2wsh_addr
334
+ p2wsh? ? bech32_addr : nil
335
+ end
336
+
337
+ # return bech32 address for payload
338
+ def bech32_addr
339
+ segwit_addr = Bech32::SegwitAddr.new
340
+ segwit_addr.hrp = Bitcoin.chain_params.bech32_hrp
341
+ segwit_addr.script_pubkey = to_payload.bth
342
+ segwit_addr.addr
343
+ end
344
+
345
+ end
346
+
347
+ end