tapyrus 0.2.4 → 0.2.9

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +37 -0
  3. data/.prettierignore +3 -0
  4. data/.prettierrc.yaml +3 -0
  5. data/CODE_OF_CONDUCT.md +7 -7
  6. data/README.md +14 -17
  7. data/Rakefile +3 -3
  8. data/lib/openassets.rb +0 -2
  9. data/lib/openassets/marker_output.rb +0 -4
  10. data/lib/openassets/payload.rb +4 -10
  11. data/lib/schnorr.rb +14 -9
  12. data/lib/schnorr/sign_to_contract.rb +51 -0
  13. data/lib/schnorr/signature.rb +3 -6
  14. data/lib/tapyrus.rb +8 -30
  15. data/lib/tapyrus/base58.rb +7 -6
  16. data/lib/tapyrus/bip175.rb +67 -0
  17. data/lib/tapyrus/block.rb +1 -2
  18. data/lib/tapyrus/block_header.rb +15 -9
  19. data/lib/tapyrus/bloom_filter.rb +5 -3
  20. data/lib/tapyrus/chain_params.rb +1 -4
  21. data/lib/tapyrus/chainparams/dev.yml +3 -2
  22. data/lib/tapyrus/chainparams/prod.yml +3 -2
  23. data/lib/tapyrus/constants.rb +29 -23
  24. data/lib/tapyrus/errors.rb +1 -3
  25. data/lib/tapyrus/ext.rb +1 -1
  26. data/lib/tapyrus/ext/ecdsa.rb +4 -4
  27. data/lib/tapyrus/ext/json_parser.rb +1 -4
  28. data/lib/tapyrus/ext_key.rb +44 -32
  29. data/lib/tapyrus/key.rb +31 -35
  30. data/lib/tapyrus/key_path.rb +15 -12
  31. data/lib/tapyrus/logger.rb +20 -16
  32. data/lib/tapyrus/merkle_tree.rb +19 -20
  33. data/lib/tapyrus/message.rb +14 -16
  34. data/lib/tapyrus/message/addr.rb +1 -7
  35. data/lib/tapyrus/message/base.rb +0 -3
  36. data/lib/tapyrus/message/block.rb +2 -9
  37. data/lib/tapyrus/message/block_transaction_request.rb +3 -6
  38. data/lib/tapyrus/message/block_transactions.rb +2 -6
  39. data/lib/tapyrus/message/block_txn.rb +0 -4
  40. data/lib/tapyrus/message/cmpct_block.rb +1 -7
  41. data/lib/tapyrus/message/error.rb +1 -4
  42. data/lib/tapyrus/message/fee_filter.rb +1 -4
  43. data/lib/tapyrus/message/filter_add.rb +0 -4
  44. data/lib/tapyrus/message/filter_clear.rb +0 -4
  45. data/lib/tapyrus/message/filter_load.rb +2 -5
  46. data/lib/tapyrus/message/get_addr.rb +0 -4
  47. data/lib/tapyrus/message/get_block_txn.rb +0 -4
  48. data/lib/tapyrus/message/get_blocks.rb +0 -3
  49. data/lib/tapyrus/message/get_data.rb +1 -4
  50. data/lib/tapyrus/message/get_headers.rb +1 -3
  51. data/lib/tapyrus/message/header_and_short_ids.rb +3 -9
  52. data/lib/tapyrus/message/headers.rb +0 -4
  53. data/lib/tapyrus/message/headers_parser.rb +3 -8
  54. data/lib/tapyrus/message/inv.rb +1 -4
  55. data/lib/tapyrus/message/inventories_parser.rb +2 -7
  56. data/lib/tapyrus/message/inventory.rb +12 -5
  57. data/lib/tapyrus/message/mem_pool.rb +0 -4
  58. data/lib/tapyrus/message/merkle_block.rb +4 -9
  59. data/lib/tapyrus/message/network_addr.rb +7 -6
  60. data/lib/tapyrus/message/not_found.rb +0 -3
  61. data/lib/tapyrus/message/ping.rb +0 -3
  62. data/lib/tapyrus/message/pong.rb +0 -3
  63. data/lib/tapyrus/message/prefilled_tx.rb +0 -4
  64. data/lib/tapyrus/message/reject.rb +0 -3
  65. data/lib/tapyrus/message/send_cmpct.rb +1 -3
  66. data/lib/tapyrus/message/send_headers.rb +0 -3
  67. data/lib/tapyrus/message/tx.rb +0 -4
  68. data/lib/tapyrus/message/ver_ack.rb +1 -5
  69. data/lib/tapyrus/message/version.rb +2 -5
  70. data/lib/tapyrus/mnemonic.rb +17 -15
  71. data/lib/tapyrus/network.rb +0 -2
  72. data/lib/tapyrus/network/connection.rb +0 -3
  73. data/lib/tapyrus/network/message_handler.rb +61 -60
  74. data/lib/tapyrus/network/peer.rb +13 -12
  75. data/lib/tapyrus/network/peer_discovery.rb +3 -5
  76. data/lib/tapyrus/network/pool.rb +12 -12
  77. data/lib/tapyrus/node.rb +1 -1
  78. data/lib/tapyrus/node/cli.rb +12 -14
  79. data/lib/tapyrus/node/configuration.rb +1 -3
  80. data/lib/tapyrus/node/spv.rb +2 -3
  81. data/lib/tapyrus/opcodes.rb +9 -7
  82. data/lib/tapyrus/out_point.rb +5 -5
  83. data/lib/tapyrus/rpc.rb +1 -0
  84. data/lib/tapyrus/rpc/http_server.rb +21 -22
  85. data/lib/tapyrus/rpc/request_handler.rb +42 -44
  86. data/lib/tapyrus/rpc/tapyrus_core_client.rb +67 -25
  87. data/lib/tapyrus/script/color.rb +20 -2
  88. data/lib/tapyrus/script/multisig.rb +13 -12
  89. data/lib/tapyrus/script/script.rb +104 -67
  90. data/lib/tapyrus/script/script_error.rb +1 -4
  91. data/lib/tapyrus/script/script_interpreter.rb +439 -399
  92. data/lib/tapyrus/script/tx_checker.rb +20 -10
  93. data/lib/tapyrus/secp256k1.rb +0 -4
  94. data/lib/tapyrus/secp256k1/native.rb +14 -15
  95. data/lib/tapyrus/secp256k1/rfc6979.rb +7 -4
  96. data/lib/tapyrus/secp256k1/ruby.rb +10 -12
  97. data/lib/tapyrus/slip39.rb +20 -5
  98. data/lib/tapyrus/slip39/share.rb +41 -29
  99. data/lib/tapyrus/slip39/sss.rb +101 -57
  100. data/lib/tapyrus/store.rb +1 -3
  101. data/lib/tapyrus/store/chain_entry.rb +0 -4
  102. data/lib/tapyrus/store/db.rb +0 -2
  103. data/lib/tapyrus/store/db/level_db.rb +5 -9
  104. data/lib/tapyrus/store/spv_chain.rb +11 -17
  105. data/lib/tapyrus/tx.rb +45 -37
  106. data/lib/tapyrus/tx_builder.rb +158 -0
  107. data/lib/tapyrus/tx_in.rb +1 -6
  108. data/lib/tapyrus/tx_out.rb +2 -7
  109. data/lib/tapyrus/util.rb +20 -7
  110. data/lib/tapyrus/validation.rb +12 -11
  111. data/lib/tapyrus/version.rb +1 -1
  112. data/lib/tapyrus/wallet/account.rb +22 -18
  113. data/lib/tapyrus/wallet/base.rb +12 -9
  114. data/lib/tapyrus/wallet/db.rb +6 -9
  115. data/lib/tapyrus/wallet/master_key.rb +2 -4
  116. data/tapyrusrb.gemspec +13 -16
  117. metadata +22 -31
  118. data/.travis.yml +0 -12
@@ -1,9 +1,7 @@
1
1
  module Tapyrus
2
2
  module Node
3
-
4
3
  # SPV class
5
4
  class SPV
6
-
7
5
  attr_reader :chain
8
6
  attr_reader :pool
9
7
  attr_reader :logger
@@ -20,6 +18,7 @@ module Tapyrus
20
18
  @logger = Tapyrus::Logger.create(:debug)
21
19
  @running = false
22
20
  @wallet = Tapyrus::Wallet::Base.current_wallet
21
+
23
22
  # TODO : optimize bloom filter parameters
24
23
  setup_filter
25
24
  end
@@ -72,7 +71,7 @@ module Tapyrus
72
71
 
73
72
  def setup_filter
74
73
  @bloom = Tapyrus::BloomFilter.create_filter(512, 0.01)
75
- wallet.watch_targets.each{|t|bloom.add(t.htb)} if wallet
74
+ wallet.watch_targets.each { |t| bloom.add(t.htb) } if wallet
76
75
  end
77
76
  end
78
77
  end
@@ -1,8 +1,6 @@
1
1
  module Tapyrus
2
-
3
2
  # https://bitcoin.org/en/developer-reference#opcodes
4
3
  module Opcodes
5
-
6
4
  module_function
7
5
 
8
6
  # https://en.bitcoin.it/wiki/Script#Constants
@@ -111,7 +109,7 @@ module Tapyrus
111
109
  OP_HASH256 = 0xaa
112
110
  OP_CODESEPARATOR = 0xab
113
111
  OP_CHECKSIG = 0xac
114
- OP_CHECKSIGVERIFY= 0xad
112
+ OP_CHECKSIGVERIFY = 0xad
115
113
  OP_CHECKMULTISIG = 0xae
116
114
  OP_CHECKMULTISIGVERIFY = 0xaf
117
115
 
@@ -124,7 +122,7 @@ module Tapyrus
124
122
  OP_VER = 0x62
125
123
  OP_VERIF = 0x65
126
124
  OP_VERNOTIF = 0x66
127
- OP_RESERVED1= 0x89
125
+ OP_RESERVED1 = 0x89
128
126
  OP_RESERVED2 = 0x8a
129
127
 
130
128
  OP_NOP1 = 0xb0
@@ -147,7 +145,12 @@ module Tapyrus
147
145
  OP_COLOR = 0xbc
148
146
 
149
147
  DUPLICATE_KEY = [:OP_NOP2, :OP_NOP3]
150
- OPCODES_MAP = Hash[*(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map { |c| [const_get(c), c.to_s] }.flatten]
148
+ OPCODES_MAP =
149
+ Hash[
150
+ *(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map do |c|
151
+ [const_get(c), c.to_s]
152
+ end.flatten
153
+ ]
151
154
  NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
152
155
 
153
156
  def opcode_to_name(opcode)
@@ -178,6 +181,5 @@ module Tapyrus
178
181
  return opcode - (OP_1 - 1) if opcode >= OP_1 && opcode <= OP_16
179
182
  nil
180
183
  end
181
-
182
184
  end
183
- end
185
+ end
@@ -1,10 +1,8 @@
1
1
  module Tapyrus
2
-
3
2
  # outpoint class
4
3
  class OutPoint
5
-
6
4
  COINBASE_HASH = '0000000000000000000000000000000000000000000000000000000000000000'
7
- COINBASE_INDEX = 4294967295
5
+ COINBASE_INDEX = 4_294_967_295
8
6
 
9
7
  attr_reader :tx_hash
10
8
  attr_reader :index
@@ -34,11 +32,13 @@ module Tapyrus
34
32
  index >= 0 && (!coinbase? && tx_hash != COINBASE_HASH)
35
33
  end
36
34
 
35
+ def ==(other)
36
+ to_payload == other&.to_payload
37
+ end
38
+
37
39
  # convert hash to txid
38
40
  def txid
39
41
  tx_hash.rhex
40
42
  end
41
-
42
43
  end
43
-
44
44
  end
data/lib/tapyrus/rpc.rb CHANGED
@@ -3,5 +3,6 @@ module Tapyrus
3
3
  autoload :HttpServer, 'tapyrus/rpc/http_server'
4
4
  autoload :RequestHandler, 'tapyrus/rpc/request_handler'
5
5
  autoload :TapyrusCoreClient, 'tapyrus/rpc/tapyrus_core_client'
6
+ autoload :Error, 'tapyrus/rpc/tapyrus_core_client'
6
7
  end
7
8
  end
@@ -3,7 +3,6 @@ require 'json'
3
3
 
4
4
  module Tapyrus
5
5
  module RPC
6
-
7
6
  # Tapyrusrb RPC server.
8
7
  class HttpServer < EM::Connection
9
8
  include EM::HttpServer
@@ -28,27 +27,29 @@ module Tapyrus
28
27
 
29
28
  # process http request.
30
29
  def process_http_request
31
- operation = proc {
32
- command, args = parse_json_params
33
- logger.debug("process http request. command = #{command}")
34
- begin
35
- send(command, *args).to_json
36
- rescue Exception => e
37
- e
30
+ operation =
31
+ proc do
32
+ command, args = parse_json_params
33
+ logger.debug("process http request. command = #{command}")
34
+ begin
35
+ send(command, *args).to_json
36
+ rescue Exception => e
37
+ e
38
+ end
38
39
  end
39
- }
40
- callback = proc{ |result|
41
- response = EM::DelegatedHttpResponse.new(self)
42
- if result.is_a?(Exception)
43
- response.status = 500
44
- response.content = result.message
45
- else
46
- response.status = 200
47
- response.content = result
40
+ callback =
41
+ proc do |result|
42
+ response = EM::DelegatedHttpResponse.new(self)
43
+ if result.is_a?(Exception)
44
+ response.status = 500
45
+ response.content = result.message
46
+ else
47
+ response.status = 200
48
+ response.content = result
49
+ end
50
+ response.content_type 'application/json'
51
+ response.send_response
48
52
  end
49
- response.content_type 'application/json'
50
- response.send_response
51
- }
52
53
  EM.defer(operation, callback)
53
54
  end
54
55
 
@@ -58,8 +59,6 @@ module Tapyrus
58
59
  params = JSON.parse(@http_post_content)
59
60
  [params['method'], params['params']]
60
61
  end
61
-
62
62
  end
63
-
64
63
  end
65
64
  end
@@ -1,9 +1,7 @@
1
1
  module Tapyrus
2
2
  module RPC
3
-
4
3
  # RPC server's request handler.
5
4
  module RequestHandler
6
-
7
5
  # Returns an object containing various state info regarding blockchain processing.
8
6
  def getblockchaininfo
9
7
  h = {}
@@ -28,19 +26,19 @@ module Tapyrus
28
26
  raise ArgumentError.new('Block not found') unless entry
29
27
  if verbose
30
28
  {
31
- hash: block_id,
32
- height: entry.height,
33
- features: entry.header.features,
34
- featuresHex: entry.header.features.to_even_length_hex.ljust(8, '0'),
35
- merkleroot: entry.header.merkle_root.rhex,
36
- immutablemerkleroot: entry.header.im_merkle_root.rhex,
37
- time: entry.header.time,
38
- mediantime: node.chain.mtp(block_hash),
39
- xfield_type: entry.header.x_field_type,
40
- xfield: entry.header.x_field,
41
- proof: entry.header.proof,
42
- previousblockhash: entry.prev_hash.rhex,
43
- nextblockhash: node.chain.next_hash(block_hash).rhex
29
+ hash: block_id,
30
+ height: entry.height,
31
+ features: entry.header.features,
32
+ featuresHex: entry.header.features.to_even_length_hex.ljust(8, '0'),
33
+ merkleroot: entry.header.merkle_root.rhex,
34
+ immutablemerkleroot: entry.header.im_merkle_root.rhex,
35
+ time: entry.header.time,
36
+ mediantime: node.chain.mtp(block_hash),
37
+ xfield_type: entry.header.x_field_type,
38
+ xfield: entry.header.x_field,
39
+ proof: entry.header.proof,
40
+ previousblockhash: entry.prev_hash.rhex,
41
+ nextblockhash: node.chain.next_hash(block_hash).rhex
44
42
  }
45
43
  else
46
44
  entry.header.to_hex
@@ -49,34 +47,38 @@ module Tapyrus
49
47
 
50
48
  # Returns connected peer information.
51
49
  def getpeerinfo
52
- node.pool.peers.map do |peer|
53
- local_addr = "#{peer.remote_version.remote_addr.ip}:18333"
54
- {
55
- id: peer.id,
56
- addr: "#{peer.host}:#{peer.port}",
57
- addrlocal: local_addr,
58
- services: peer.remote_version.services.to_even_length_hex.rjust(16, '0'),
59
- relaytxes: peer.remote_version.relay,
60
- lastsend: peer.last_send,
61
- lastrecv: peer.last_recv,
62
- bytessent: peer.bytes_sent,
63
- bytesrecv: peer.bytes_recv,
64
- conntime: peer.conn_time,
65
- pingtime: peer.ping_time,
66
- minping: peer.min_ping,
67
- version: peer.remote_version.version,
68
- subver: peer.remote_version.user_agent,
69
- inbound: !peer.outbound?,
70
- startingheight: peer.remote_version.start_height,
71
- best_hash: peer.best_hash,
72
- best_height: peer.best_height
73
- }
74
- end
50
+ node
51
+ .pool
52
+ .peers
53
+ .map do |peer|
54
+ local_addr = "#{peer.remote_version.remote_addr.ip}:18333"
55
+ {
56
+ id: peer.id,
57
+ addr: "#{peer.host}:#{peer.port}",
58
+ addrlocal: local_addr,
59
+ services: peer.remote_version.services.to_even_length_hex.rjust(16, '0'),
60
+ relaytxes: peer.remote_version.relay,
61
+ lastsend: peer.last_send,
62
+ lastrecv: peer.last_recv,
63
+ bytessent: peer.bytes_sent,
64
+ bytesrecv: peer.bytes_recv,
65
+ conntime: peer.conn_time,
66
+ pingtime: peer.ping_time,
67
+ minping: peer.min_ping,
68
+ version: peer.remote_version.version,
69
+ subver: peer.remote_version.user_agent,
70
+ inbound: !peer.outbound?,
71
+ startingheight: peer.remote_version.start_height,
72
+ best_hash: peer.best_hash,
73
+ best_height: peer.best_height
74
+ }
75
+ end
75
76
  end
76
77
 
77
78
  # broadcast transaction
78
79
  def sendrawtransaction(hex_tx)
79
80
  tx = Tapyrus::Tx.parse_from_payload(hex_tx.htb)
81
+
80
82
  # TODO check wether tx is valid
81
83
  node.broadcast(tx)
82
84
  tx.txid
@@ -110,7 +112,7 @@ module Tapyrus
110
112
  def createwallet(wallet_id = 1, wallet_path_prefix = Tapyrus::Wallet::Base.default_path_prefix)
111
113
  wallet = Tapyrus::Wallet::Base.create(wallet_id, wallet_path_prefix)
112
114
  node.wallet = wallet unless node.wallet
113
- {wallet_id: wallet.wallet_id, mnemonic: wallet.master_key.mnemonic}
115
+ { wallet_id: wallet.wallet_id, mnemonic: wallet.master_key.mnemonic }
114
116
  end
115
117
 
116
118
  # get wallet list.
@@ -127,9 +129,7 @@ module Tapyrus
127
129
  def listaccounts
128
130
  return {} unless node.wallet
129
131
  accounts = {}
130
- node.wallet.accounts.each do |a|
131
- accounts[a.name] = node.wallet.get_balance(a)
132
- end
132
+ node.wallet.accounts.each { |a| accounts[a.name] = node.wallet.get_balance(a) }
133
133
  accounts
134
134
  end
135
135
 
@@ -144,8 +144,6 @@ module Tapyrus
144
144
  def getnewaddress(account_name)
145
145
  node.wallet.generate_new_address(account_name)
146
146
  end
147
-
148
147
  end
149
-
150
148
  end
151
149
  end
@@ -3,6 +3,40 @@ require 'json/pure'
3
3
 
4
4
  module Tapyrus
5
5
  module RPC
6
+ # Throw when happened anything http's error with connect to server.
7
+ #
8
+ # Almost case this exception happened from 401 Unauthorized or 500 Internal Server Error.
9
+ # And also, throw by cause of other http's errors.
10
+ #
11
+ # You can pull RPC error message when happened 500 Internal Server Error, like below:
12
+ #
13
+ # rescue Tapyrus::RPC::Error => ex
14
+ # if ex.message.response_code == 500
15
+ # puts ex.message[:rpc_error]
16
+ # end
17
+ # end
18
+ class Error < StandardError
19
+ attr_reader :response_code, :response_msg, :rpc_error
20
+
21
+ def initialize(response_code, response_msg, rpc_error)
22
+ @response_code = response_code
23
+ @response_msg = response_msg
24
+ @rpc_error = rpc_error
25
+ end
26
+
27
+ def message
28
+ @message ||=
29
+ begin
30
+ m = { response_code: response_code, response_msg: response_msg }
31
+ m.merge!(rpc_error: rpc_error) if rpc_error
32
+ m
33
+ end
34
+ end
35
+
36
+ def to_s
37
+ message.to_s
38
+ end
39
+ end
6
40
 
7
41
  # Client implementation for RPC to Tapyrus Core.
8
42
  #
@@ -16,25 +50,21 @@ module Tapyrus
16
50
  # client.getblockchaininfo
17
51
  #
18
52
  class TapyrusCoreClient
19
-
20
53
  attr_reader :config
21
54
 
22
55
  # @param [Hash] config a configuration required to connect to Bitcoin Core.
23
56
  def initialize(config)
24
57
  @config = config
25
58
 
26
- commands = request(:help).split("\n").inject([]) do |memo_ary, line|
27
- if !line.empty? && !line.start_with?('==')
28
- memo_ary << line.split(' ').first.to_sym
29
- end
30
- memo_ary
31
- end
32
- TapyrusCoreClient.class_eval do
33
- commands.each do |command|
34
- define_method(command) do |*params|
35
- request(command, *params)
59
+ commands =
60
+ request(:help)
61
+ .split("\n")
62
+ .inject([]) do |memo_ary, line|
63
+ memo_ary << line.split(' ').first.to_sym if !line.empty? && !line.start_with?('==')
64
+ memo_ary
36
65
  end
37
- end
66
+ TapyrusCoreClient.class_eval do
67
+ commands.each { |command| define_method(command) { |*params| request(command, *params) } }
38
68
  end
39
69
  end
40
70
 
@@ -42,33 +72,45 @@ module Tapyrus
42
72
 
43
73
  def server_url
44
74
  url = "#{config[:schema]}://#{config[:user]}:#{config[:password]}@#{config[:host]}:#{config[:port]}"
45
- if !config[:wallet].nil? && !config[:wallet].empty?
46
- url += "/wallet/#{config[:wallet]}"
47
- end
75
+ url += "/wallet/#{config[:wallet]}" if !config[:wallet].nil? && !config[:wallet].empty?
48
76
  url
49
77
  end
50
78
 
51
79
  def request(command, *params)
52
- data = {
53
- :method => command,
54
- :params => params,
55
- :id => 'jsonrpc'
56
- }
80
+ data = { method: command, params: params, id: 'jsonrpc' }
57
81
  uri = URI.parse(server_url)
58
82
  http = Net::HTTP.new(uri.hostname, uri.port)
59
- http.use_ssl = uri.scheme === "https"
83
+ http.use_ssl = uri.scheme === 'https'
60
84
  request = Net::HTTP::Post.new(uri.path.empty? ? '/' : uri.path)
61
85
  request.basic_auth(uri.user, uri.password)
62
86
  request.content_type = 'application/json'
63
87
  request.body = data.to_json
64
88
  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_json if response['error']
89
+ raise error!(response) unless response.is_a? Net::HTTPOK
90
+ response = Tapyrus::RPC.response_body2json(response.body)
68
91
  response['result']
69
92
  end
70
93
 
94
+ def error!(response)
95
+ rpc_error =
96
+ begin
97
+ Tapyrus::RPC.response_body2json(response.body)['error']
98
+ rescue JSON::ParserError => _
99
+ # if RPC server don't send error message.
100
+ end
101
+
102
+ raise Error.new(response.code, response.msg, rpc_error)
103
+ end
104
+ end
105
+
106
+ def response_body2json(body)
107
+ Tapyrus::Ext::JsonParser.new(
108
+ body.gsub(/\\u([\da-fA-F]{4})/) do
109
+ [$1].pack('H*').unpack('n*').pack('U*').encode('ISO-8859-1').force_encoding('UTF-8')
110
+ end
111
+ ).parse
71
112
  end
72
113
 
114
+ module_function :response_body2json
73
115
  end
74
- end
116
+ end
@@ -24,6 +24,11 @@ module Tapyrus
24
24
  new(TokenTypes::NFT, Tapyrus.sha256(out_point.to_payload))
25
25
  end
26
26
 
27
+ # Return ColorIdentifier for native token(i.e TPC)
28
+ def self.default
29
+ new(TokenTypes::NONE, '0000000000000000000000000000000000000000000000000000000000000000'.htb)
30
+ end
31
+
27
32
  def to_payload
28
33
  [type, payload].pack('Ca*')
29
34
  end
@@ -43,6 +48,19 @@ module Tapyrus
43
48
  true
44
49
  end
45
50
 
51
+ def hash
52
+ to_payload.hash
53
+ end
54
+
55
+ def eql?(other)
56
+ to_payload.eql?(other.to_payload)
57
+ end
58
+
59
+ # Return true if the coin is native token(i.e TPC), otherwise false
60
+ def default?
61
+ self == ColorIdentifier.default
62
+ end
63
+
46
64
  private
47
65
 
48
66
  def initialize(type, payload)
@@ -53,11 +71,11 @@ module Tapyrus
53
71
 
54
72
  module ColoredOutput
55
73
  def colored?
56
- script_pubkey.cp2pkh? || script_pubkey.cp2sh?
74
+ script_pubkey.colored?
57
75
  end
58
76
 
59
77
  def color_id
60
- @color_id ||= ColorIdentifier.parse_from_payload(script_pubkey.chunks[0].pushed_data)
78
+ @color_id ||= script_pubkey.color_id
61
79
  end
62
80
 
63
81
  def reissuable?