tapyrus 0.1.0 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -15
- data/exe/tapyrusrbd +2 -2
- data/lib/openassets/util.rb +2 -4
- data/lib/schnorr.rb +83 -0
- data/lib/schnorr/signature.rb +38 -0
- data/lib/tapyrus.rb +11 -18
- data/lib/tapyrus/block.rb +3 -38
- data/lib/tapyrus/block_header.rb +70 -41
- data/lib/tapyrus/chain_params.rb +13 -36
- data/lib/tapyrus/chainparams/{regtest.yml → dev.yml} +10 -19
- data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -19
- data/lib/tapyrus/constants.rb +12 -34
- data/lib/tapyrus/errors.rb +17 -0
- data/lib/tapyrus/ext.rb +5 -0
- data/lib/tapyrus/ext/ecdsa.rb +39 -0
- data/lib/tapyrus/ext/json_parser.rb +47 -0
- data/lib/tapyrus/ext_key.rb +42 -23
- data/lib/tapyrus/key.rb +47 -40
- data/lib/tapyrus/message.rb +2 -2
- data/lib/tapyrus/message/base.rb +1 -0
- data/lib/tapyrus/message/block.rb +4 -4
- data/lib/tapyrus/message/cmpct_block.rb +3 -5
- data/lib/tapyrus/message/header_and_short_ids.rb +1 -1
- data/lib/tapyrus/message/headers.rb +1 -1
- data/lib/tapyrus/message/merkle_block.rb +1 -1
- data/lib/tapyrus/message/tx.rb +2 -2
- data/lib/tapyrus/network/peer.rb +1 -15
- data/lib/tapyrus/node/cli.rb +15 -11
- data/lib/tapyrus/node/configuration.rb +1 -1
- data/lib/tapyrus/node/spv.rb +1 -1
- data/lib/tapyrus/opcodes.rb +5 -0
- data/lib/tapyrus/out_point.rb +1 -1
- data/lib/tapyrus/rpc/request_handler.rb +7 -6
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
- data/lib/tapyrus/script/color.rb +79 -0
- data/lib/tapyrus/script/multisig.rb +0 -27
- data/lib/tapyrus/script/script.rb +74 -89
- data/lib/tapyrus/script/script_error.rb +8 -14
- data/lib/tapyrus/script/script_interpreter.rb +65 -86
- data/lib/tapyrus/script/tx_checker.rb +21 -5
- data/lib/tapyrus/secp256k1.rb +1 -0
- data/lib/tapyrus/secp256k1/native.rb +93 -20
- data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
- data/lib/tapyrus/secp256k1/ruby.rb +63 -54
- data/lib/tapyrus/store/chain_entry.rb +3 -2
- data/lib/tapyrus/store/db/level_db.rb +58 -0
- data/lib/tapyrus/store/spv_chain.rb +29 -11
- data/lib/tapyrus/tx.rb +18 -160
- data/lib/tapyrus/tx_in.rb +4 -11
- data/lib/tapyrus/tx_out.rb +2 -1
- data/lib/tapyrus/util.rb +8 -0
- data/lib/tapyrus/validation.rb +1 -6
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +1 -0
- data/lib/tapyrus/wallet/master_key.rb +1 -0
- data/tapyrusrb.gemspec +3 -3
- metadata +44 -39
- data/lib/tapyrus/chainparams/testnet.yml +0 -41
- data/lib/tapyrus/descriptor.rb +0 -147
- data/lib/tapyrus/script_witness.rb +0 -38
data/lib/tapyrus/key.rb
CHANGED
@@ -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,
|
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,
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
114
|
-
|
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
|
-
|
195
|
-
|
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
|
-
|
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
|
data/lib/tapyrus/message.rb
CHANGED
@@ -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]
|
54
|
+
DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:none]
|
55
55
|
|
56
56
|
DEFAULT_STOP_HASH = "00"*32
|
57
57
|
|
data/lib/tapyrus/message/base.rb
CHANGED
@@ -11,15 +11,15 @@ module Tapyrus
|
|
11
11
|
|
12
12
|
COMMAND = 'block'
|
13
13
|
|
14
|
-
def initialize(header, transactions = []
|
14
|
+
def initialize(header, transactions = [])
|
15
15
|
@header = header
|
16
16
|
@transactions = transactions
|
17
|
-
@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
|
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
|
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,
|
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(
|
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
|
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
|
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
|
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
|
data/lib/tapyrus/message/tx.rb
CHANGED
@@ -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
|
20
|
+
new(tx)
|
21
21
|
end
|
22
22
|
|
23
23
|
def to_payload
|
24
|
-
|
24
|
+
tx.to_payload
|
25
25
|
end
|
26
26
|
|
27
27
|
end
|
data/lib/tapyrus/network/peer.rb
CHANGED
@@ -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
|
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.
|
data/lib/tapyrus/node/cli.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
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: :
|
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
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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] = :
|
11
|
+
opts[:network] = :prod unless opts[:network]
|
12
12
|
opts[:relay] = false unless opts[:relay]
|
13
13
|
Tapyrus.chain_params = opts[:network]
|
14
14
|
|
data/lib/tapyrus/node/spv.rb
CHANGED
data/lib/tapyrus/opcodes.rb
CHANGED
@@ -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]
|
data/lib/tapyrus/out_point.rb
CHANGED
@@ -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
|
-
|
35
|
-
|
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
|
-
|
40
|
-
|
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.
|
46
|
+
entry.header.to_hex
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -1,15 +1,16 @@
|
|
1
|
-
require '
|
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
|
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::
|
11
|
+
# client = Tapyrus::RPC::TapyrusCoreClient.new(config)
|
11
12
|
#
|
12
|
-
# You can execute the CLI command supported by
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|