tapyrus 0.1.0 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -15
  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 +11 -18
  8. data/lib/tapyrus/block.rb +3 -38
  9. data/lib/tapyrus/block_header.rb +70 -41
  10. data/lib/tapyrus/chain_params.rb +13 -36
  11. data/lib/tapyrus/chainparams/{regtest.yml → dev.yml} +10 -19
  12. data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -19
  13. data/lib/tapyrus/constants.rb +12 -34
  14. data/lib/tapyrus/errors.rb +17 -0
  15. data/lib/tapyrus/ext.rb +5 -0
  16. data/lib/tapyrus/ext/ecdsa.rb +39 -0
  17. data/lib/tapyrus/ext/json_parser.rb +47 -0
  18. data/lib/tapyrus/ext_key.rb +42 -23
  19. data/lib/tapyrus/key.rb +47 -40
  20. data/lib/tapyrus/message.rb +2 -2
  21. data/lib/tapyrus/message/base.rb +1 -0
  22. data/lib/tapyrus/message/block.rb +4 -4
  23. data/lib/tapyrus/message/cmpct_block.rb +3 -5
  24. data/lib/tapyrus/message/header_and_short_ids.rb +1 -1
  25. data/lib/tapyrus/message/headers.rb +1 -1
  26. data/lib/tapyrus/message/merkle_block.rb +1 -1
  27. data/lib/tapyrus/message/tx.rb +2 -2
  28. data/lib/tapyrus/network/peer.rb +1 -15
  29. data/lib/tapyrus/node/cli.rb +15 -11
  30. data/lib/tapyrus/node/configuration.rb +1 -1
  31. data/lib/tapyrus/node/spv.rb +1 -1
  32. data/lib/tapyrus/opcodes.rb +5 -0
  33. data/lib/tapyrus/out_point.rb +1 -1
  34. data/lib/tapyrus/rpc/request_handler.rb +7 -6
  35. data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
  36. data/lib/tapyrus/script/color.rb +79 -0
  37. data/lib/tapyrus/script/multisig.rb +0 -27
  38. data/lib/tapyrus/script/script.rb +74 -89
  39. data/lib/tapyrus/script/script_error.rb +8 -14
  40. data/lib/tapyrus/script/script_interpreter.rb +65 -86
  41. data/lib/tapyrus/script/tx_checker.rb +21 -5
  42. data/lib/tapyrus/secp256k1.rb +1 -0
  43. data/lib/tapyrus/secp256k1/native.rb +93 -20
  44. data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
  45. data/lib/tapyrus/secp256k1/ruby.rb +63 -54
  46. data/lib/tapyrus/store/chain_entry.rb +3 -2
  47. data/lib/tapyrus/store/db/level_db.rb +58 -0
  48. data/lib/tapyrus/store/spv_chain.rb +29 -11
  49. data/lib/tapyrus/tx.rb +18 -160
  50. data/lib/tapyrus/tx_in.rb +4 -11
  51. data/lib/tapyrus/tx_out.rb +2 -1
  52. data/lib/tapyrus/util.rb +8 -0
  53. data/lib/tapyrus/validation.rb +1 -6
  54. data/lib/tapyrus/version.rb +1 -1
  55. data/lib/tapyrus/wallet/account.rb +1 -0
  56. data/lib/tapyrus/wallet/master_key.rb +1 -0
  57. data/tapyrusrb.gemspec +3 -3
  58. metadata +44 -39
  59. data/lib/tapyrus/chainparams/testnet.yml +0 -41
  60. data/lib/tapyrus/descriptor.rb +0 -147
  61. data/lib/tapyrus/script_witness.rb +0 -38
@@ -11,6 +11,8 @@ module Tapyrus
11
11
  SIGNATURE_SIZE = 72
12
12
  COMPACT_SIGNATURE_SIZE = 65
13
13
 
14
+ SIG_ALGO = [:ecdsa, :schnorr]
15
+
14
16
  attr_accessor :priv_key
15
17
  attr_accessor :pubkey
16
18
  attr_accessor :key_type
@@ -28,7 +30,7 @@ module Tapyrus
28
30
  # @param [Integer] key_type a key type which determine address type.
29
31
  # @param [Boolean] compressed [Deprecated] whether public key is compressed.
30
32
  # @return [Tapyrus::Key] a key object.
31
- def initialize(priv_key: nil, pubkey: nil, key_type: nil, compressed: true)
33
+ def initialize(priv_key: nil, pubkey: nil, key_type: nil, compressed: true, allow_hybrid: false)
32
34
  puts "[Warning] Use key_type parameter instead of compressed. compressed parameter removed in the future." if key_type.nil? && !compressed.nil? && pubkey.nil?
33
35
  if key_type
34
36
  @key_type = key_type
@@ -39,13 +41,14 @@ module Tapyrus
39
41
  @secp256k1_module = Tapyrus.secp_impl
40
42
  @priv_key = priv_key
41
43
  if @priv_key
42
- raise ArgumentError, 'private key is not on curve' unless validate_private_key_range(@priv_key)
44
+ raise ArgumentError, Errors::Messages::INVALID_PRIV_KEY unless validate_private_key_range(@priv_key)
43
45
  end
44
46
  if pubkey
45
47
  @pubkey = pubkey
46
48
  else
47
49
  @pubkey = generate_pubkey(priv_key, compressed: compressed) if priv_key
48
50
  end
51
+ raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless fully_valid_pubkey?(allow_hybrid)
49
52
  end
50
53
 
51
54
  # generate key pair
@@ -63,7 +66,7 @@ module Tapyrus
63
66
  data = hex[2...-8].htb
64
67
  checksum = hex[-8..-1]
65
68
  raise ArgumentError, 'invalid version' unless version == Tapyrus.chain_params.privkey_version
66
- raise ArgumentError, 'invalid checksum' unless Tapyrus.calc_checksum(version + data.bth) == checksum
69
+ raise ArgumentError, Errors::Messages::INVALID_CHECKSUM unless Tapyrus.calc_checksum(version + data.bth) == checksum
67
70
  key_len = data.bytesize
68
71
  if key_len == COMPRESSED_PUBLIC_KEY_SIZE && data[-1].unpack('C').first == 1
69
72
  key_type = TYPES[:compressed]
@@ -89,29 +92,31 @@ module Tapyrus
89
92
  # @param [String] data a data to be signed with binary format
90
93
  # @param [Boolean] low_r flag to apply low-R.
91
94
  # @param [String] extra_entropy the extra entropy for rfc6979.
95
+ # @param [Symbol] algo Algorithms used for verification. Either :ecdsa or :schnorr is supported. default value is :ecdsa.
92
96
  # @return [String] signature data with binary format
93
- def sign(data, low_r = true, extra_entropy = nil)
94
- sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
95
- if low_r && !sig_has_low_r?(sig)
96
- counter = 1
97
- until sig_has_low_r?(sig)
98
- extra_entropy = [counter].pack('I*').bth.ljust(64, '0').htb
99
- sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
100
- counter += 1
101
- end
97
+ def sign(data, low_r = true, extra_entropy = nil, algo: :ecdsa)
98
+ raise ArgumentError, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
99
+ case algo
100
+ when :ecdsa
101
+ sign_ecdsa(data, low_r, extra_entropy)
102
+ when :schnorr
103
+ secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: algo)
104
+ else
105
+ false
102
106
  end
103
- sig
104
107
  end
105
108
 
106
109
  # verify signature using public key
107
110
  # @param [String] sig signature data with binary format
108
111
  # @param [String] origin original message
112
+ # @param [Symbol] algo Algorithms used for verification. Either :ecdsa or :schnorr is supported. default value is :ecdsa.
109
113
  # @return [Boolean] verify result
110
- def verify(sig, origin)
114
+ def verify(sig, origin, algo: :ecdsa)
111
115
  return false unless valid_pubkey?
112
116
  begin
113
- sig = ecdsa_signature_parse_der_lax(sig)
114
- secp256k1_module.verify_sig(origin, sig, pubkey)
117
+ raise ArgumentError, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
118
+ sig = ecdsa_signature_parse_der_lax(sig) if algo == :ecdsa
119
+ secp256k1_module.verify_sig(origin, sig, pubkey, algo: algo)
115
120
  rescue Exception
116
121
  false
117
122
  end
@@ -128,18 +133,6 @@ module Tapyrus
128
133
  Tapyrus::Script.to_p2pkh(hash160).addresses.first
129
134
  end
130
135
 
131
- # get pay to witness pubkey hash address
132
- # @deprecated
133
- def to_p2wpkh
134
- Tapyrus::Script.to_p2wpkh(hash160).addresses.first
135
- end
136
-
137
- # get p2wpkh address nested in p2sh.
138
- # @deprecated
139
- def to_nested_p2wpkh
140
- Tapyrus::Script.to_p2wpkh(hash160).to_p2sh.addresses.first
141
- end
142
-
143
136
  def compressed?
144
137
  key_type != TYPES[:uncompressed]
145
138
  end
@@ -191,18 +184,24 @@ module Tapyrus
191
184
 
192
185
  # check +sig+ is correct der encoding.
193
186
  # This function is consensus-critical since BIP66.
194
- def self.valid_signature_encoding?(sig)
195
- return false if sig.bytesize < 9 || sig.bytesize > 73 # Minimum and maximum size check
187
+ # @param [String] sig a signature data with binary format.
188
+ # @param [Boolean] data_sig whether data signature or not.
189
+ # @return [Boolean] result
190
+ def self.valid_signature_encoding?(sig, data_sig = false)
191
+ num_parts = data_sig ? 8 : 9
192
+ size = data_sig ? 72 : 73
193
+
194
+ return false if sig.bytesize < num_parts || sig.bytesize > size # Minimum and maximum size check
196
195
 
197
196
  s = sig.unpack('C*')
198
197
 
199
- return false if s[0] != 0x30 || s[1] != s.size - 3 # A signature is of type 0x30 (compound). Make sure the length covers the entire signature.
198
+ return false if s[0] != 0x30 || s[1] != s.size - (data_sig ? 2 : 3) # A signature is of type 0x30 (compound). Make sure the length covers the entire signature.
200
199
 
201
200
  len_r = s[3]
202
201
  return false if 5 + len_r >= s.size # Make sure the length of the S element is still inside the signature.
203
202
 
204
203
  len_s = s[5 + len_r]
205
- return false unless len_r + len_s + 7 == s.size #Verify that the length of the signature matches the sum of the length of the elements.
204
+ return false unless len_r + len_s + (data_sig ? 6 : 7) == s.size #Verify that the length of the signature matches the sum of the length of the elements.
206
205
 
207
206
  return false unless s[2] == 0x02 # Check whether the R element is an integer.
208
207
 
@@ -225,14 +224,8 @@ module Tapyrus
225
224
  end
226
225
 
227
226
  # fully validate whether this is a valid public key (more expensive than IsValid())
228
- def fully_valid_pubkey?
229
- return false unless valid_pubkey?
230
- begin
231
- point = ECDSA::Format::PointOctetString.decode(pubkey.htb, ECDSA::Group::Secp256k1)
232
- ECDSA::Group::Secp256k1.valid_public_key?(point)
233
- rescue ECDSA::Format::DecodeError
234
- false
235
- end
227
+ def fully_valid_pubkey?(allow_hybrid = false)
228
+ valid_pubkey? && secp256k1_module.parse_ec_pubkey?(pubkey, allow_hybrid)
236
229
  end
237
230
 
238
231
  private
@@ -291,6 +284,20 @@ module Tapyrus
291
284
  sig[3].bth.to_i(16) == 0x20 && sig[4].bth.to_i(16) < 0x80
292
285
  end
293
286
 
287
+ # generate ecdsa signature
288
+ def sign_ecdsa(data, low_r, extra_entropy)
289
+ sig = secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :ecdsa)
290
+ if low_r && !sig_has_low_r?(sig)
291
+ counter = 1
292
+ until sig_has_low_r?(sig)
293
+ extra_entropy = [counter].pack('I*').bth.ljust(64, '0').htb
294
+ sig = secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :ecdsa)
295
+ counter += 1
296
+ end
297
+ end
298
+ sig
299
+ end
300
+
294
301
  end
295
302
 
296
303
  end
@@ -45,13 +45,13 @@ module Tapyrus
45
45
  network: 1 << 0, # the node is capable of serving the block chain. It is currently set by all Bitcoin Core node, and is unset by SPV clients or other peers that just want network services but don't provide them.
46
46
  # getutxo: 1 << 1, # BIP-64. not implemented in Bitcoin Core.
47
47
  bloom: 1 << 2, # the node is capable and willing to handle bloom-filtered connections. Bitcoin Core node used to support this by default, without advertising this bit, but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)
48
- witness: 1 << 3, # the node can be asked for blocks and transactions including witness data.
48
+ #witness: 1 << 3, # the node can be asked for blocks and transactions including witness data.
49
49
  # xthin: 1 << 4 # support Xtreme Thinblocks. not implemented in Bitcoin Core
50
50
  }
51
51
 
52
52
  # DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:network] | SERVICE_FLAGS[:bloom] | SERVICE_FLAGS[:witness]
53
53
 
54
- DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:none] | SERVICE_FLAGS[:witness]
54
+ DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:none]
55
55
 
56
56
  DEFAULT_STOP_HASH = "00"*32
57
57
 
@@ -3,6 +3,7 @@ module Tapyrus
3
3
 
4
4
  # Base message class
5
5
  class Base
6
+ include Tapyrus::HexConverter
6
7
  include Tapyrus::Util
7
8
  extend Tapyrus::Util
8
9
 
@@ -11,15 +11,15 @@ module Tapyrus
11
11
 
12
12
  COMMAND = 'block'
13
13
 
14
- def initialize(header, transactions = [], use_segwit = false)
14
+ def initialize(header, transactions = [])
15
15
  @header = header
16
16
  @transactions = transactions
17
- @use_segwit = use_segwit
17
+ @use_segwit = false
18
18
  end
19
19
 
20
20
  def self.parse_from_payload(payload)
21
21
  buf = StringIO.new(payload)
22
- header = Tapyrus::BlockHeader.parse_from_payload(buf.read(80))
22
+ header = Tapyrus::BlockHeader.parse_from_payload(buf)
23
23
  transactions = []
24
24
  unless buf.eof?
25
25
  tx_count = Tapyrus.unpack_var_int_from_io(buf)
@@ -32,7 +32,7 @@ module Tapyrus
32
32
 
33
33
  def to_payload
34
34
  header.to_payload << Tapyrus.pack_var_int(transactions.size) <<
35
- transactions.map{|t|use_segwit ? t.to_payload : t.serialize_old_format}.join
35
+ transactions.map(&:to_payload).join
36
36
  end
37
37
 
38
38
  # generate Tapyrus::Block object.
@@ -1,7 +1,7 @@
1
1
  module Tapyrus
2
2
  module Message
3
3
 
4
- # cmpctblock message
4
+ # cmpctblock message. support only version 1.
5
5
  # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
6
6
  class CmpctBlock < Base
7
7
 
@@ -15,14 +15,12 @@ module Tapyrus
15
15
 
16
16
  # generate CmpctBlock from Block data.
17
17
  # @param [Tapyrus::Block] block the block to generate CmpctBlock.
18
- # @param [Integer] version Compact Block version specified by sendcmpct message.
19
18
  # @param [Integer] nonce
20
19
  # @return [Tapyrus::Message::CmpctBlock]
21
- def self.from_block(block, version, nonce = SecureRandom.hex(8).to_i(16))
22
- raise 'Unsupported version.' unless [1, 2].include?(version)
20
+ def self.from_block(block, nonce = SecureRandom.hex(8).to_i(16))
23
21
  h = HeaderAndShortIDs.new(block.header, nonce)
24
22
  block.transactions[1..-1].each do |tx|
25
- h.short_ids << h.short_id(version == 1 ? tx.txid : tx.wtxid)
23
+ h.short_ids << h.short_id(tx.txid)
26
24
  end
27
25
  h.prefilled_txn << PrefilledTx.new(0, block.transactions.first)
28
26
  self.new(h)
@@ -21,7 +21,7 @@ module Tapyrus
21
21
 
22
22
  def self.parse_from_payload(payload)
23
23
  buf = StringIO.new(payload)
24
- header = Tapyrus::BlockHeader.parse_from_payload(buf.read(80))
24
+ header = Tapyrus::BlockHeader.parse_from_payload(buf)
25
25
  nonce = buf.read(8).unpack('q*').first
26
26
  short_ids_len = Tapyrus.unpack_var_int_from_io(buf)
27
27
  short_ids = short_ids_len.times.map do
@@ -19,7 +19,7 @@ module Tapyrus
19
19
  header_count = Tapyrus.unpack_var_int_from_io(buf)
20
20
  h = new
21
21
  header_count.times do
22
- h.headers << Tapyrus::BlockHeader.parse_from_payload(buf.read(80))
22
+ h.headers << Tapyrus::BlockHeader.parse_from_payload(buf)
23
23
  buf.read(1) # read tx count 0x00 (headers message doesn't include any tx.)
24
24
  end
25
25
  h
@@ -19,7 +19,7 @@ module Tapyrus
19
19
  def self.parse_from_payload(payload)
20
20
  m = new
21
21
  buf = StringIO.new(payload)
22
- m.header = Tapyrus::BlockHeader.parse_from_payload(buf.read(80))
22
+ m.header = Tapyrus::BlockHeader.parse_from_payload(buf)
23
23
  m.tx_count = buf.read(4).unpack('V').first
24
24
  hash_count = Tapyrus.unpack_var_int_from_io(buf)
25
25
  hash_count.times do
@@ -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
@@ -11,7 +11,6 @@ module Tapyrus
11
11
  best_block = node.chain.latest_block
12
12
  h[:headers] = best_block.height
13
13
  h[:bestblockhash] = best_block.header.block_id
14
- h[:chainwork] = best_block.header.work
15
14
  h[:mediantime] = node.chain.mtp(best_block.block_hash)
16
15
  h
17
16
  end
@@ -31,18 +30,20 @@ module Tapyrus
31
30
  {
32
31
  hash: block_id,
33
32
  height: entry.height,
34
- version: entry.header.version,
35
- versionHex: entry.header.version.to_even_length_hex,
33
+ features: entry.header.features,
34
+ featuresHex: entry.header.features.to_even_length_hex.ljust(8, '0'),
36
35
  merkleroot: entry.header.merkle_root.rhex,
36
+ immutablemerkleroot: entry.header.im_merkle_root.rhex,
37
37
  time: entry.header.time,
38
38
  mediantime: node.chain.mtp(block_hash),
39
- nonce: entry.header.nonce,
40
- bits: entry.header.bits.to_even_length_hex,
39
+ xfield_type: entry.header.x_field_type,
40
+ xfield: entry.header.x_field,
41
+ proof: entry.header.proof,
41
42
  previousblockhash: entry.prev_hash.rhex,
42
43
  nextblockhash: node.chain.next_hash(block_hash).rhex
43
44
  }
44
45
  else
45
- entry.header.to_payload.bth
46
+ entry.header.to_hex
46
47
  end
47
48
  end
48
49
 
@@ -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(uri.path.empty? ? '/' : uri.path)
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_json if response['error']
68
+ response['result']
67
69
  end
68
70
 
69
71
  end