tapyrus 0.1.0 → 0.2.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -14
  3. data/exe/tapyrusrbd +2 -2
  4. data/lib/openassets/util.rb +2 -4
  5. data/lib/schnorr.rb +83 -0
  6. data/lib/schnorr/signature.rb +38 -0
  7. data/lib/tapyrus.rb +9 -11
  8. data/lib/tapyrus/block.rb +1 -32
  9. data/lib/tapyrus/block_header.rb +7 -6
  10. data/lib/tapyrus/chain_params.rb +13 -26
  11. data/lib/tapyrus/chainparams/{testnet.yml → dev.yml} +7 -9
  12. data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -10
  13. data/lib/tapyrus/constants.rb +12 -34
  14. data/lib/tapyrus/ext.rb +5 -0
  15. data/lib/tapyrus/ext/json_parser.rb +47 -0
  16. data/lib/tapyrus/ext_key.rb +5 -10
  17. data/lib/tapyrus/key.rb +57 -29
  18. data/lib/tapyrus/message.rb +2 -2
  19. data/lib/tapyrus/message/base.rb +1 -0
  20. data/lib/tapyrus/message/block.rb +3 -3
  21. data/lib/tapyrus/message/cmpct_block.rb +3 -5
  22. data/lib/tapyrus/message/tx.rb +2 -2
  23. data/lib/tapyrus/network/peer.rb +1 -15
  24. data/lib/tapyrus/node/cli.rb +15 -11
  25. data/lib/tapyrus/node/configuration.rb +1 -1
  26. data/lib/tapyrus/node/spv.rb +1 -1
  27. data/lib/tapyrus/opcodes.rb +5 -0
  28. data/lib/tapyrus/out_point.rb +1 -1
  29. data/lib/tapyrus/rpc/request_handler.rb +3 -3
  30. data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
  31. data/lib/tapyrus/script/color.rb +79 -0
  32. data/lib/tapyrus/script/multisig.rb +0 -27
  33. data/lib/tapyrus/script/script.rb +74 -89
  34. data/lib/tapyrus/script/script_error.rb +8 -14
  35. data/lib/tapyrus/script/script_interpreter.rb +65 -86
  36. data/lib/tapyrus/script/tx_checker.rb +16 -4
  37. data/lib/tapyrus/secp256k1.rb +1 -0
  38. data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
  39. data/lib/tapyrus/secp256k1/ruby.rb +5 -31
  40. data/lib/tapyrus/store/chain_entry.rb +1 -0
  41. data/lib/tapyrus/tx.rb +18 -160
  42. data/lib/tapyrus/tx_in.rb +4 -11
  43. data/lib/tapyrus/tx_out.rb +2 -1
  44. data/lib/tapyrus/util.rb +8 -0
  45. data/lib/tapyrus/validation.rb +1 -6
  46. data/lib/tapyrus/version.rb +1 -1
  47. data/lib/tapyrus/wallet/account.rb +1 -0
  48. data/lib/tapyrus/wallet/master_key.rb +1 -0
  49. data/tapyrusrb.gemspec +3 -3
  50. metadata +42 -39
  51. data/lib/tapyrus/chainparams/regtest.yml +0 -38
  52. data/lib/tapyrus/descriptor.rb +0 -147
  53. data/lib/tapyrus/script_witness.rb +0 -38
@@ -17,11 +17,11 @@ module Tapyrus
17
17
 
18
18
  def self.parse_from_payload(payload)
19
19
  tx = Tapyrus::Tx.parse_from_payload(payload)
20
- new(tx, tx.witness?)
20
+ new(tx)
21
21
  end
22
22
 
23
23
  def to_payload
24
- use_segwit ? tx.to_payload : tx.serialize_old_format
24
+ tx.to_payload
25
25
  end
26
26
 
27
27
  end
@@ -99,21 +99,7 @@ module Tapyrus
99
99
 
100
100
  # broadcast tx.
101
101
  def broadcast_tx(tx)
102
- conn.send_message(Tapyrus::Message::Tx.new(tx, support_witness?))
103
- end
104
-
105
- # check the remote peer support witness.
106
- def support_witness?
107
- return false unless remote_version
108
- remote_version.services & Tapyrus::Message::SERVICE_FLAGS[:witness] > 0
109
- end
110
-
111
- # check the remote peer supports compact block.
112
- def support_cmpct?
113
- return false if remote_version.version < Tapyrus::Message::VERSION[:compact]
114
- return true unless local_version.services & Tapyrus::Message::SERVICE_FLAGS[:witness] > 0
115
- return false unless support_witness?
116
- remote_version.version >= Tapyrus::Message::VERSION[:compact_witness]
102
+ conn.send_message(Tapyrus::Message::Tx.new(tx))
117
103
  end
118
104
 
119
105
  # get peer's block type.
@@ -1,4 +1,4 @@
1
- require 'rest-client'
1
+ require 'net/http'
2
2
  require 'thor'
3
3
  require 'json'
4
4
 
@@ -7,7 +7,7 @@ module Tapyrus
7
7
 
8
8
  class CLI < Thor
9
9
 
10
- class_option :network, aliases: '-n', default: :mainnet
10
+ class_option :network, aliases: '-n', default: :prod
11
11
 
12
12
  desc 'getblockchaininfo', 'Returns an object containing various state info regarding blockchain processing.'
13
13
  def getblockchaininfo
@@ -92,15 +92,19 @@ module Tapyrus
92
92
  :id => 'jsonrpc'
93
93
  }
94
94
  begin
95
- RestClient::Request.execute(method: :post, url: config.server_url, payload: data.to_json,
96
- headers: {content_type: :json}) do |response, request, result|
97
- return false if !result.kind_of?(Net::HTTPSuccess) && response.empty?
98
- begin
99
- json = JSON.parse(response.to_str)
100
- puts JSON.pretty_generate(json)
101
- rescue Exception
102
- puts response.to_str
103
- end
95
+ uri = URI.parse(config.server_url)
96
+ http = Net::HTTP.new(uri.hostname, uri.port)
97
+ http.use_ssl = uri.scheme === "https"
98
+ request = Net::HTTP::Post.new('/')
99
+ request.content_type = 'application/json'
100
+ request.body = data.to_json
101
+ response = http.request(request)
102
+ body = response.body
103
+ begin
104
+ json = JSON.parse(body.to_str)
105
+ puts JSON.pretty_generate(json)
106
+ rescue Exception
107
+ puts body.to_str
104
108
  end
105
109
  rescue Exception => e
106
110
  puts e.message
@@ -8,7 +8,7 @@ module Tapyrus
8
8
 
9
9
  def initialize(opts = {})
10
10
  # TODO apply configuration file.
11
- opts[:network] = :mainnet unless opts[:network]
11
+ opts[:network] = :prod unless opts[:network]
12
12
  opts[:relay] = false unless opts[:relay]
13
13
  Tapyrus.chain_params = opts[:network]
14
14
 
@@ -45,7 +45,7 @@ module Tapyrus
45
45
  # broadcast a transaction
46
46
  def broadcast(tx)
47
47
  pool.broadcast(tx)
48
- logger.debug "broadcast tx: #{tx.to_payload.bth}"
48
+ logger.debug "broadcast tx: #{tx.to_hex}"
49
49
  end
50
50
 
51
51
  # add filter element to bloom filter.
@@ -141,6 +141,11 @@ module Tapyrus
141
141
  OP_PUBKEY = 0xfe
142
142
  OP_INVALIDOPCODE = 0xff
143
143
 
144
+ # tapyrus extension
145
+ OP_CHECKDATASIG = 0xba
146
+ OP_CHECKDATASIGVERIFY = 0xbb
147
+ OP_COLOR = 0xbc
148
+
144
149
  DUPLICATE_KEY = [:OP_NOP2, :OP_NOP3]
145
150
  OPCODES_MAP = Hash[*(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map { |c| [const_get(c), c.to_s] }.flatten]
146
151
  NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
@@ -19,7 +19,7 @@ module Tapyrus
19
19
  end
20
20
 
21
21
  def coinbase?
22
- tx_hash == COINBASE_HASH && index == COINBASE_INDEX
22
+ tx_hash == COINBASE_HASH
23
23
  end
24
24
 
25
25
  def to_payload
@@ -31,8 +31,8 @@ module Tapyrus
31
31
  {
32
32
  hash: block_id,
33
33
  height: entry.height,
34
- version: entry.header.version,
35
- versionHex: entry.header.version.to_even_length_hex,
34
+ features: entry.header.features,
35
+ featuresHex: entry.header.features.to_even_length_hex,
36
36
  merkleroot: entry.header.merkle_root.rhex,
37
37
  time: entry.header.time,
38
38
  mediantime: node.chain.mtp(block_hash),
@@ -42,7 +42,7 @@ module Tapyrus
42
42
  nextblockhash: node.chain.next_hash(block_hash).rhex
43
43
  }
44
44
  else
45
- entry.header.to_payload.bth
45
+ entry.header.to_hex
46
46
  end
47
47
  end
48
48
 
@@ -1,15 +1,16 @@
1
- require 'rest-client'
1
+ require 'net/http'
2
+ require 'json/pure'
2
3
 
3
4
  module Tapyrus
4
5
  module RPC
5
6
 
6
- # Client implementation for RPC to Bitcoin Core.
7
+ # Client implementation for RPC to Tapyrus Core.
7
8
  #
8
9
  # [Usage]
9
10
  # config = {schema: 'http', host: 'localhost', port: 18332, user: 'xxx', password: 'yyy'}
10
- # client = Tapyrus::RPC::BitcoinCoreClient.new(config)
11
+ # client = Tapyrus::RPC::TapyrusCoreClient.new(config)
11
12
  #
12
- # You can execute the CLI command supported by Bitcoin Core as follows:
13
+ # You can execute the CLI command supported by Tapyrus Core as follows:
13
14
  #
14
15
  # client.listunspent
15
16
  # client.getblockchaininfo
@@ -53,17 +54,18 @@ module Tapyrus
53
54
  :params => params,
54
55
  :id => 'jsonrpc'
55
56
  }
56
- post(server_url, @config[:timeout], @config[:open_timeout], data.to_json, content_type: :json) do |respdata, request, result|
57
- raise result.message if !result.kind_of?(Net::HTTPSuccess) && respdata.empty?
58
- response = JSON.parse(respdata.gsub(/\\u([\da-fA-F]{4})/) { [$1].pack('H*').unpack('n*').pack('U*').encode('ISO-8859-1').force_encoding('UTF-8') })
59
- raise response['error'] if response['error']
60
- response['result']
61
- end
62
- end
63
-
64
- def post(url, timeout, open_timeout, payload, headers={}, &block)
65
- RestClient::Request.execute(method: :post, url: url, timeout: timeout,
66
- open_timeout: open_timeout, payload: payload, headers: headers, &block)
57
+ uri = URI.parse(server_url)
58
+ http = Net::HTTP.new(uri.hostname, uri.port)
59
+ http.use_ssl = uri.scheme === "https"
60
+ request = Net::HTTP::Post.new('/')
61
+ request.basic_auth(uri.user, uri.password)
62
+ request.content_type = 'application/json'
63
+ request.body = data.to_json
64
+ response = http.request(request)
65
+ body = response.body
66
+ response = Tapyrus::Ext::JsonParser.new(body.gsub(/\\u([\da-fA-F]{4})/) { [$1].pack('H*').unpack('n*').pack('U*').encode('ISO-8859-1').force_encoding('UTF-8') }).parse
67
+ raise response['error'].to_s if response['error']
68
+ response['result']
67
69
  end
68
70
 
69
71
  end
@@ -0,0 +1,79 @@
1
+ module Tapyrus
2
+ module Color
3
+ module TokenTypes
4
+ NONE = 0x00
5
+ REISSUABLE = 0xC1
6
+ NON_REISSUABLE = 0xC2
7
+ NFT = 0xC3
8
+ end
9
+
10
+ class ColorIdentifier
11
+ include Tapyrus::HexConverter
12
+
13
+ attr_reader :type, :payload
14
+
15
+ def self.reissuable(script_pubkey)
16
+ new(TokenTypes::REISSUABLE, Tapyrus.sha256(script_pubkey.to_payload))
17
+ end
18
+
19
+ def self.non_reissuable(out_point)
20
+ new(TokenTypes::NON_REISSUABLE, Tapyrus.sha256(out_point.to_payload))
21
+ end
22
+
23
+ def self.nft(out_point)
24
+ new(TokenTypes::NFT, Tapyrus.sha256(out_point.to_payload))
25
+ end
26
+
27
+ def to_payload
28
+ [type, payload].pack('Ca*')
29
+ end
30
+
31
+ def self.parse_from_payload(payload)
32
+ type, payload = payload.unpack('Ca*')
33
+ new(type, payload)
34
+ end
35
+
36
+ def ==(other)
37
+ other && other.to_payload == to_payload
38
+ end
39
+
40
+ def valid?
41
+ return false unless [TokenTypes::REISSUABLE, TokenTypes::NON_REISSUABLE, TokenTypes::NFT].include?(type)
42
+ return false unless payload.bytesize == 32
43
+ true
44
+ end
45
+
46
+ private
47
+
48
+ def initialize(type, payload)
49
+ @type = type
50
+ @payload = payload
51
+ end
52
+ end
53
+
54
+ module ColoredOutput
55
+ def colored?
56
+ script_pubkey.cp2pkh? || script_pubkey.cp2sh?
57
+ end
58
+
59
+ def color_id
60
+ @color_id ||= ColorIdentifier.parse_from_payload(script_pubkey.chunks[0].pushed_data)
61
+ end
62
+
63
+ def reissuable?
64
+ return false unless colored?
65
+ color_id.type == TokenTypes::REISSUABLE
66
+ end
67
+
68
+ def non_reissuable?
69
+ return false unless colored?
70
+ color_id.type == TokenTypes::NON_REISSUABLE
71
+ end
72
+
73
+ def nft?
74
+ return false unless colored?
75
+ color_id.type == TokenTypes::NFT
76
+ end
77
+ end
78
+ end
79
+ end
@@ -61,32 +61,5 @@ module Tapyrus
61
61
  prefix + pubkeys.map { |k| sigs[k] ? Tapyrus::Script.pack_pushdata(sigs[k]) : nil }.join +
62
62
  Tapyrus::Script.pack_pushdata(script.chunks[-1].pushed_data)
63
63
  end
64
-
65
- def self.add_sig_to_multisig_script_witness(sig_to_add, script_witness, hash_type = SIGHASH_TYPE[:all])
66
- signature = sig_to_add + [hash_type].pack("C*")
67
- script_witness.stack << signature
68
- end
69
-
70
- # Sort signatures in the given +script_witness+ according to the order of pubkeys in
71
- # the redeem script. Also needs the +sig_hash+ to match signatures to pubkeys.
72
- # @param [ScriptWitness] script_witness for multisig.
73
- # @param [String] sig_hash to be signed.
74
- def self.sort_witness_multisig_signatures(script_witness, sig_hash)
75
- redeem_script = Tapyrus::Script.parse_from_payload(script_witness.stack[-1])
76
- pubkeys = redeem_script.get_multisig_pubkeys
77
- sigs = Hash[script_witness.stack[1...-1].map.with_index do |sig, idx|
78
- pubkey = pubkeys.map do |key|
79
- Tapyrus::Key.new(pubkey: key.bth).verify(sig, sig_hash) ? key : nil
80
- end.compact.first
81
- raise "Key for signature ##{idx} not found in redeem script!" unless pubkey
82
- [pubkey, sig]
83
- end]
84
- script_witness.stack.clear
85
- script_witness.stack << ''
86
- pubkeys.each do |pubkey|
87
- script_witness.stack << sigs[pubkey] if sigs[pubkey]
88
- end
89
- script_witness.stack << redeem_script.to_payload
90
- end
91
64
  end
92
65
  end
@@ -5,6 +5,7 @@ module Tapyrus
5
5
 
6
6
  # tapyrus script
7
7
  class Script
8
+ include Tapyrus::HexConverter
8
9
  include Tapyrus::Opcodes
9
10
 
10
11
  attr_accessor :chunks
@@ -18,11 +19,6 @@ module Tapyrus
18
19
  new << OP_DUP << OP_HASH160 << pubkey_hash << OP_EQUALVERIFY << OP_CHECKSIG
19
20
  end
20
21
 
21
- # generate P2WPKH script
22
- def self.to_p2wpkh(pubkey_hash)
23
- new << WITNESS_VERSION << pubkey_hash
24
- end
25
-
26
22
  # generate m of n multisig p2sh script
27
23
  # @param [String] m the number of signatures required for multisig
28
24
  # @param [Array] pubkeys array of public keys that compose multisig
@@ -45,6 +41,40 @@ module Tapyrus
45
41
  Script.to_p2sh(to_hash160)
46
42
  end
47
43
 
44
+ # generate cp2pkh script
45
+ # @param [ColorIdentifier] color identifier
46
+ # @param [String] hash160 of pubkey
47
+ # @return [Script] CP2PKH script
48
+ # @raise [ArgumentError] if color_id is nil or invalid
49
+ def self.to_cp2pkh(color_id, pubkey_hash)
50
+ raise ArgumentError, 'Specified color identifier is invalid' unless color_id&.valid?
51
+ new << color_id.to_payload << OP_COLOR << OP_DUP << OP_HASH160 << pubkey_hash << OP_EQUALVERIFY << OP_CHECKSIG
52
+ end
53
+
54
+ # generate cp2sh script
55
+ # @param [ColorIdentifier] color identifier
56
+ # @param [String] hash160 of script
57
+ # @return [Script] CP2SH script
58
+ # @raise [ArgumentError] if color_id is nil or invalid
59
+ def self.to_cp2sh(color_id, script_hash)
60
+ raise ArgumentError, 'Specified color identifier is invalid' unless color_id&.valid?
61
+ new << color_id.to_payload << OP_COLOR << OP_HASH160 << script_hash << OP_EQUAL
62
+ end
63
+
64
+ # Add color identifier to existing p2pkh or p2sh
65
+ # @param [ColorIdentifier] color identifier
66
+ # @return [Script] CP2PKH or CP2SH script
67
+ # @raise [ArgumentError] if color_id is nil or invalid
68
+ # @raise [RuntimeError] if script is neither p2pkh nor p2sh
69
+ def add_color(color_id)
70
+ raise ArgumentError, 'Specified color identifier is invalid' unless color_id&.valid?
71
+ raise RuntimeError, 'Only p2pkh and p2sh can add color' unless p2pkh? or p2sh?
72
+ Tapyrus::Script.new.tap do |s|
73
+ s << color_id.to_payload << OP_COLOR
74
+ s.chunks += self.chunks
75
+ end
76
+ end
77
+
48
78
  def get_multisig_pubkeys
49
79
  num = Tapyrus::Opcodes.opcode_to_small_int(chunks[-2].bth.to_i(16))
50
80
  (1..num).map{ |i| chunks[i].pushed_data }
@@ -59,13 +89,6 @@ module Tapyrus
59
89
  new << m << pubkeys << pubkeys.size << OP_CHECKMULTISIG
60
90
  end
61
91
 
62
- # generate p2wsh script for +redeem_script+
63
- # @param [Script] redeem_script target redeem script
64
- # @param [Script] p2wsh script
65
- def self.to_p2wsh(redeem_script)
66
- new << WITNESS_VERSION << redeem_script.to_sha256
67
- end
68
-
69
92
  # generate script from string.
70
93
  def self.from_string(string)
71
94
  script = new
@@ -151,14 +174,15 @@ module Tapyrus
151
174
  def addresses
152
175
  return [p2pkh_addr] if p2pkh?
153
176
  return [p2sh_addr] if p2sh?
154
- return [bech32_addr] if witness_program?
177
+ return [cp2pkh_addr] if cp2pkh?
178
+ return [cp2sh_addr] if cp2sh?
155
179
  return get_multisig_pubkeys.map{|pubkey| Tapyrus::Key.new(pubkey: pubkey.bth).to_p2pkh} if multisig?
156
180
  []
157
181
  end
158
182
 
159
183
  # check whether standard script.
160
184
  def standard?
161
- p2pkh? | p2sh? | p2wpkh? | p2wsh? | multisig? | standard_op_return?
185
+ p2pkh? | p2sh? | multisig? | standard_op_return?
162
186
  end
163
187
 
164
188
  # whether this script is a P2PKH format script.
@@ -168,17 +192,6 @@ module Tapyrus
168
192
  (chunks[0..1]+ chunks[3..4]).map(&:ord) && chunks[2].bytesize == 21
169
193
  end
170
194
 
171
- # whether this script is a P2WPKH format script.
172
- def p2wpkh?
173
- return false unless chunks.size == 2
174
- chunks[0].ord == WITNESS_VERSION && chunks[1].bytesize == 21
175
- end
176
-
177
- def p2wsh?
178
- return false unless chunks.size == 2
179
- chunks[0].ord == WITNESS_VERSION && chunks[1].bytesize == 33
180
- end
181
-
182
195
  def p2sh?
183
196
  return false unless chunks.size == 3
184
197
  OP_HASH160 == chunks[0].ord && OP_EQUAL == chunks[2].ord && chunks[1].bytesize == 21
@@ -201,6 +214,23 @@ module Tapyrus
201
214
  (chunks.size == 1 || chunks[1].opcode <= OP_16)
202
215
  end
203
216
 
217
+ def cp2pkh?
218
+ return false unless chunks.size == 7
219
+ return false unless chunks[0].bytesize == 34
220
+ return false unless Tapyrus::Color::ColorIdentifier.parse_from_payload(chunks[0].pushed_data)&.valid?
221
+ return false unless chunks[1].ord == OP_COLOR
222
+ [OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG] ==
223
+ (chunks[2..3]+ chunks[5..6]).map(&:ord) && chunks[4].bytesize == 21
224
+ end
225
+
226
+ def cp2sh?
227
+ return false unless chunks.size == 5
228
+ return false unless chunks[0].bytesize == 34
229
+ return false unless Tapyrus::Color::ColorIdentifier.parse_from_payload(chunks[0].pushed_data)&.valid?
230
+ return false unless chunks[1].ord == OP_COLOR
231
+ OP_HASH160 == chunks[2].ord && OP_EQUAL == chunks[4].ord && chunks[3].bytesize == 21
232
+ end
233
+
204
234
  def op_return_data
205
235
  return nil unless op_return?
206
236
  return nil if chunks.size == 1
@@ -221,50 +251,15 @@ module Tapyrus
221
251
  chunks.select{|c|c.pushdata? && [33, 65].include?(c.pushed_data.bytesize) && [2, 3, 4, 6, 7].include?(c.pushed_data[0].bth.to_i(16))}.map{|c|c.pushed_data.bth}
222
252
  end
223
253
 
224
- # 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.
225
- def witness_program?
226
- return false if size < 4 || size > 42 || chunks.size < 2
227
-
228
- opcode = chunks[0].opcode
229
-
230
- return false if opcode != OP_0 && (opcode < OP_1 || opcode > OP_16)
231
- return false unless chunks[1].pushdata?
232
-
233
- if size == (chunks[1][0].unpack('C').first + 2)
234
- program_size = chunks[1].pushed_data.bytesize
235
- return program_size >= 2 && program_size <= 40
236
- end
237
-
238
- false
239
- end
240
-
241
- # get witness commitment
242
- def witness_commitment
243
- return nil if !op_return? || op_return_data.bytesize < 36
244
- buf = StringIO.new(op_return_data)
245
- return nil unless buf.read(4).bth == WITNESS_COMMITMENT_HEADER
246
- buf.read(32).bth
247
- end
248
-
249
- # If this script is witness program, return its script code,
250
- # otherwise returns the self payload. ScriptInterpreter does not use this.
254
+ # returns the self payload. ScriptInterpreter does not use this.
251
255
  def to_script_code(skip_separator_index = 0)
252
256
  payload = to_payload
253
- if p2wpkh?
254
- payload = Script.to_p2pkh(chunks[1].pushed_data.bth).to_payload
255
- elsif skip_separator_index > 0
257
+ if skip_separator_index > 0
256
258
  payload = subscript_codeseparator(skip_separator_index)
257
259
  end
258
260
  Tapyrus.pack_var_string(payload)
259
261
  end
260
262
 
261
- # get witness version and witness program
262
- def witness_data
263
- version = opcode_to_small_int(chunks[0].opcode)
264
- program = chunks[1].pushed_data
265
- [version, program]
266
- end
267
-
268
263
  # append object to payload
269
264
  def <<(obj)
270
265
  if obj.is_a?(Integer)
@@ -324,6 +319,7 @@ module Tapyrus
324
319
  when Integer
325
320
  opcode_to_name(c)
326
321
  when String
322
+ return c if c.empty?
327
323
  if c.pushdata?
328
324
  v = Opcodes.opcode_to_small_int(c.ord)
329
325
  if v
@@ -351,7 +347,7 @@ module Tapyrus
351
347
 
352
348
  # generate hash160 hash for payload
353
349
  def to_hash160
354
- Tapyrus.hash160(to_payload.bth)
350
+ Tapyrus.hash160(to_hex)
355
351
  end
356
352
 
357
353
  # script size
@@ -482,13 +478,11 @@ module Tapyrus
482
478
  return 'pubkeyhash' if p2pkh?
483
479
  return 'scripthash' if p2sh?
484
480
  return 'multisig' if multisig?
485
- return 'witness_v0_keyhash' if p2wpkh?
486
- return 'witness_v0_scripthash' if p2wsh?
487
481
  'nonstandard'
488
482
  end
489
483
 
490
484
  def to_h
491
- h = {asm: to_s, hex: to_payload.bth, type: type}
485
+ h = {asm: to_s, hex: to_hex, type: type}
492
486
  addrs = addresses
493
487
  unless addrs.empty?
494
488
  h[:req_sigs] = multisig? ? Tapyrus::Opcodes.opcode_to_small_int(chunks[0].bth.to_i(16)) :addrs.size
@@ -504,48 +498,39 @@ module Tapyrus
504
498
  (size > 0 && op_return?) || size > Tapyrus::MAX_SCRIPT_SIZE
505
499
  end
506
500
 
507
- # convert payload to hex data.
508
- # @return [String] script with hex format.
509
- def to_hex
510
- to_payload.bth
511
- end
512
-
513
501
  private
514
502
 
515
503
  # generate p2pkh address. if script dose not p2pkh, return nil.
516
504
  def p2pkh_addr
517
505
  return nil unless p2pkh?
518
506
  hash160 = chunks[2].pushed_data.bth
519
- return nil unless hash160.htb.bytesize == 20
520
507
  Tapyrus.encode_base58_address(hash160, Tapyrus.chain_params.address_version)
521
508
  end
522
509
 
523
- # generate p2wpkh address. if script dose not p2wpkh, return nil.
524
- def p2wpkh_addr
525
- p2wpkh? ? bech32_addr : nil
526
- end
527
-
528
510
  # generate p2sh address. if script dose not p2sh, return nil.
529
511
  def p2sh_addr
530
512
  return nil unless p2sh?
531
513
  hash160 = chunks[1].pushed_data.bth
532
- return nil unless hash160.htb.bytesize == 20
533
514
  Tapyrus.encode_base58_address(hash160, Tapyrus.chain_params.p2sh_version)
534
515
  end
535
516
 
536
- # generate p2wsh address. if script dose not p2wsh, return nil.
537
- def p2wsh_addr
538
- p2wsh? ? bech32_addr : nil
539
- end
517
+ # generate cp2pkh address. if script dose not cp2pkh, return nil.
518
+ def cp2pkh_addr
519
+ return nil unless cp2pkh?
540
520
 
541
- # return bech32 address for payload
542
- def bech32_addr
543
- segwit_addr = Bech32::SegwitAddr.new
544
- segwit_addr.hrp = Tapyrus.chain_params.bech32_hrp
545
- segwit_addr.script_pubkey = to_payload.bth
546
- segwit_addr.addr
521
+ color_id = chunks[0].pushed_data.bth
522
+ hash160 = chunks[4].pushed_data.bth
523
+ Tapyrus.encode_base58_address(color_id + hash160, Tapyrus.chain_params.cp2pkh_version)
547
524
  end
548
525
 
526
+ # generate cp2sh address. if script dose not cp2sh, return nil.
527
+ def cp2sh_addr
528
+ return nil unless cp2sh?
529
+
530
+ color_id = chunks[0].pushed_data.bth
531
+ hash160 = chunks[3].pushed_data.bth
532
+ Tapyrus.encode_base58_address(color_id + hash160, Tapyrus.chain_params.cp2sh_version)
533
+ end
549
534
  end
550
535
 
551
536
  end