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.
- checksums.yaml +4 -4
- data/README.md +6 -14
- 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 +9 -11
- data/lib/tapyrus/block.rb +1 -32
- data/lib/tapyrus/block_header.rb +7 -6
- data/lib/tapyrus/chain_params.rb +13 -26
- data/lib/tapyrus/chainparams/{testnet.yml → dev.yml} +7 -9
- data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -10
- data/lib/tapyrus/constants.rb +12 -34
- data/lib/tapyrus/ext.rb +5 -0
- data/lib/tapyrus/ext/json_parser.rb +47 -0
- data/lib/tapyrus/ext_key.rb +5 -10
- data/lib/tapyrus/key.rb +57 -29
- data/lib/tapyrus/message.rb +2 -2
- data/lib/tapyrus/message/base.rb +1 -0
- data/lib/tapyrus/message/block.rb +3 -3
- data/lib/tapyrus/message/cmpct_block.rb +3 -5
- 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 +3 -3
- 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 +16 -4
- data/lib/tapyrus/secp256k1.rb +1 -0
- data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
- data/lib/tapyrus/secp256k1/ruby.rb +5 -31
- data/lib/tapyrus/store/chain_entry.rb +1 -0
- 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 +42 -39
- data/lib/tapyrus/chainparams/regtest.yml +0 -38
- data/lib/tapyrus/descriptor.rb +0 -147
- data/lib/tapyrus/script_witness.rb +0 -38
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapyrus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: bech32
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.0.3
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.0.3
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: daemon-spawn
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,20 +122,6 @@ dependencies:
|
|
136
122
|
- - ">="
|
137
123
|
- !ruby/object:Gem::Version
|
138
124
|
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: rest-client
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :runtime
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
125
|
- !ruby/object:Gem::Dependency
|
154
126
|
name: iniparse
|
155
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -220,6 +192,20 @@ dependencies:
|
|
220
192
|
- - ">="
|
221
193
|
- !ruby/object:Gem::Version
|
222
194
|
version: 5.2.3
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: json_pure
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 2.3.1
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 2.3.1
|
223
209
|
- !ruby/object:Gem::Dependency
|
224
210
|
name: leveldb-native
|
225
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -252,16 +238,16 @@ dependencies:
|
|
252
238
|
name: rake
|
253
239
|
requirement: !ruby/object:Gem::Requirement
|
254
240
|
requirements:
|
255
|
-
- - "
|
241
|
+
- - ">="
|
256
242
|
- !ruby/object:Gem::Version
|
257
|
-
version:
|
243
|
+
version: 12.3.3
|
258
244
|
type: :development
|
259
245
|
prerelease: false
|
260
246
|
version_requirements: !ruby/object:Gem::Requirement
|
261
247
|
requirements:
|
262
|
-
- - "
|
248
|
+
- - ">="
|
263
249
|
- !ruby/object:Gem::Version
|
264
|
-
version:
|
250
|
+
version: 12.3.3
|
265
251
|
- !ruby/object:Gem::Dependency
|
266
252
|
name: rspec
|
267
253
|
requirement: !ruby/object:Gem::Requirement
|
@@ -290,6 +276,20 @@ dependencies:
|
|
290
276
|
- - ">="
|
291
277
|
- !ruby/object:Gem::Version
|
292
278
|
version: '0'
|
279
|
+
- !ruby/object:Gem::Dependency
|
280
|
+
name: webmock
|
281
|
+
requirement: !ruby/object:Gem::Requirement
|
282
|
+
requirements:
|
283
|
+
- - "~>"
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '3.0'
|
286
|
+
type: :development
|
287
|
+
prerelease: false
|
288
|
+
version_requirements: !ruby/object:Gem::Requirement
|
289
|
+
requirements:
|
290
|
+
- - "~>"
|
291
|
+
- !ruby/object:Gem::Version
|
292
|
+
version: '3.0'
|
293
293
|
description: "[WIP]The implementation of Tapyrus Protocol for Ruby."
|
294
294
|
email:
|
295
295
|
- azuchi@chaintope.com
|
@@ -317,17 +317,19 @@ files:
|
|
317
317
|
- lib/openassets/marker_output.rb
|
318
318
|
- lib/openassets/payload.rb
|
319
319
|
- lib/openassets/util.rb
|
320
|
+
- lib/schnorr.rb
|
321
|
+
- lib/schnorr/signature.rb
|
320
322
|
- lib/tapyrus.rb
|
321
323
|
- lib/tapyrus/base58.rb
|
322
324
|
- lib/tapyrus/block.rb
|
323
325
|
- lib/tapyrus/block_header.rb
|
324
326
|
- lib/tapyrus/bloom_filter.rb
|
325
327
|
- lib/tapyrus/chain_params.rb
|
326
|
-
- lib/tapyrus/chainparams/
|
327
|
-
- lib/tapyrus/chainparams/
|
328
|
-
- lib/tapyrus/chainparams/testnet.yml
|
328
|
+
- lib/tapyrus/chainparams/dev.yml
|
329
|
+
- lib/tapyrus/chainparams/prod.yml
|
329
330
|
- lib/tapyrus/constants.rb
|
330
|
-
- lib/tapyrus/
|
331
|
+
- lib/tapyrus/ext.rb
|
332
|
+
- lib/tapyrus/ext/json_parser.rb
|
331
333
|
- lib/tapyrus/ext_key.rb
|
332
334
|
- lib/tapyrus/key.rb
|
333
335
|
- lib/tapyrus/key_path.rb
|
@@ -394,14 +396,15 @@ files:
|
|
394
396
|
- lib/tapyrus/rpc/http_server.rb
|
395
397
|
- lib/tapyrus/rpc/request_handler.rb
|
396
398
|
- lib/tapyrus/rpc/tapyrus_core_client.rb
|
399
|
+
- lib/tapyrus/script/color.rb
|
397
400
|
- lib/tapyrus/script/multisig.rb
|
398
401
|
- lib/tapyrus/script/script.rb
|
399
402
|
- lib/tapyrus/script/script_error.rb
|
400
403
|
- lib/tapyrus/script/script_interpreter.rb
|
401
404
|
- lib/tapyrus/script/tx_checker.rb
|
402
|
-
- lib/tapyrus/script_witness.rb
|
403
405
|
- lib/tapyrus/secp256k1.rb
|
404
406
|
- lib/tapyrus/secp256k1/native.rb
|
407
|
+
- lib/tapyrus/secp256k1/rfc6979.rb
|
405
408
|
- lib/tapyrus/secp256k1/ruby.rb
|
406
409
|
- lib/tapyrus/slip39.rb
|
407
410
|
- lib/tapyrus/slip39/share.rb
|
@@ -1,38 +0,0 @@
|
|
1
|
-
--- !ruby/object:Tapyrus::ChainParams
|
2
|
-
network: "regtest"
|
3
|
-
magic_head: "fabfb5da"
|
4
|
-
message_magic: "Bitcoin Signed Message:\n"
|
5
|
-
address_version: "6f"
|
6
|
-
p2sh_version: "c4"
|
7
|
-
bech32_hrp: 'bcrt'
|
8
|
-
privkey_version: "ef"
|
9
|
-
extended_privkey_version: "04358394"
|
10
|
-
extended_pubkey_version: "043587cf"
|
11
|
-
bip49_pubkey_p2wpkh_p2sh_version: "044a5262"
|
12
|
-
bip49_pubkey_p2wsh_p2sh_version: "024285ef"
|
13
|
-
bip49_privkey_p2wpkh_p2sh_version: "044a4e28"
|
14
|
-
bip49_privkey_p2wsh_p2sh_version: "024285b5"
|
15
|
-
bip84_pubkey_p2wpkh_version: "045f1cf6"
|
16
|
-
bip84_pubkey_p2wsh_version: "02575483"
|
17
|
-
bip84_privkey_p2wpkh_version: "045f18bc"
|
18
|
-
bip84_privkey_p2wsh_version: "02575048"
|
19
|
-
default_port: 18444
|
20
|
-
protocol_version: 70013
|
21
|
-
retarget_interval: 2016
|
22
|
-
retarget_time: 1209600 # 2 weeks
|
23
|
-
target_spacing: 600 # block interval
|
24
|
-
max_money: 21000000
|
25
|
-
bip34_height: 0
|
26
|
-
genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
27
|
-
proof_of_work_limit: 0x207fffff
|
28
|
-
dns_seeds:
|
29
|
-
genesis:
|
30
|
-
hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
31
|
-
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
32
|
-
time: 1296688602
|
33
|
-
nonce: 2
|
34
|
-
bits: 0x207fffff
|
35
|
-
version: 1
|
36
|
-
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
37
|
-
bip44_coin_type: 1
|
38
|
-
dust_relay_fee: 3600
|
data/lib/tapyrus/descriptor.rb
DELETED
@@ -1,147 +0,0 @@
|
|
1
|
-
module Tapyrus
|
2
|
-
|
3
|
-
module Descriptor
|
4
|
-
|
5
|
-
include Tapyrus::Opcodes
|
6
|
-
|
7
|
-
# generate P2PK output for the given public key.
|
8
|
-
# @param [String] key private key or public key with hex format
|
9
|
-
# @return [Tapyrus::Script] P2PK script.
|
10
|
-
def pk(key)
|
11
|
-
Tapyrus::Script.new << extract_pubkey(key) << OP_CHECKSIG
|
12
|
-
end
|
13
|
-
|
14
|
-
# generate P2PKH output for the given public key.
|
15
|
-
# @param [String] key private key or public key with hex format.
|
16
|
-
# @return [Tapyrus::Script] P2PKH script.
|
17
|
-
def pkh(key)
|
18
|
-
Tapyrus::Script.to_p2pkh(Tapyrus.hash160(extract_pubkey(key)))
|
19
|
-
end
|
20
|
-
|
21
|
-
# generate P2PKH output for the given public key.
|
22
|
-
# @param [String] key private key or public key with hex format.
|
23
|
-
# @return [Tapyrus::Script] P2WPKH script.
|
24
|
-
def wpkh(key)
|
25
|
-
pubkey = extract_pubkey(key)
|
26
|
-
raise ArgumentError, "Uncompressed key are not allowed." unless compressed_key?(pubkey)
|
27
|
-
Tapyrus::Script.to_p2wpkh(Tapyrus.hash160(pubkey))
|
28
|
-
end
|
29
|
-
|
30
|
-
# generate P2SH embed the argument.
|
31
|
-
# @param [String or Script] script script to be embed.
|
32
|
-
# @return [Tapyrus::Script] P2SH script.
|
33
|
-
def sh(script)
|
34
|
-
script = script.to_hex if script.is_a?(Tapyrus::Script)
|
35
|
-
raise ArgumentError, "P2SH script is too large, 547 bytes is larger than #{Tapyrus::MAX_SCRIPT_ELEMENT_SIZE} bytes." if script.htb.bytesize > Tapyrus::MAX_SCRIPT_ELEMENT_SIZE
|
36
|
-
Tapyrus::Script.to_p2sh(Tapyrus.hash160(script))
|
37
|
-
end
|
38
|
-
|
39
|
-
# generate P2WSH embed the argument.
|
40
|
-
# @param [String or Script] script script to be embed.
|
41
|
-
# @return [Tapyrus::Script] P2WSH script.
|
42
|
-
def wsh(script)
|
43
|
-
script = Tapyrus::Script(script.htb) if script.is_a?(String)
|
44
|
-
raise ArgumentError, "P2SH script is too large, 547 bytes is larger than #{Tapyrus::MAX_SCRIPT_ELEMENT_SIZE} bytes." if script.to_payload.bytesize > Tapyrus::MAX_SCRIPT_ELEMENT_SIZE
|
45
|
-
raise ArgumentError, "Uncompressed key are not allowed." if script.get_pubkeys.any?{|p|!compressed_key?(p)}
|
46
|
-
Tapyrus::Script.to_p2wsh(script)
|
47
|
-
end
|
48
|
-
|
49
|
-
# an alias for the collection of `pk(KEY)` and `pkh(KEY)`.
|
50
|
-
# If the key is compressed, it also includes `wpkh(KEY)` and `sh(wpkh(KEY))`.
|
51
|
-
# @param [String] key private key or public key with hex format.
|
52
|
-
# @return [Array[Tapyrus::Script]]
|
53
|
-
def combo(key)
|
54
|
-
result = [pk(key), pkh(key)]
|
55
|
-
pubkey = extract_pubkey(key)
|
56
|
-
if compressed_key?(pubkey)
|
57
|
-
result << wpkh(key)
|
58
|
-
result << sh(result.last)
|
59
|
-
end
|
60
|
-
result
|
61
|
-
end
|
62
|
-
|
63
|
-
# generate multisig output for given keys.
|
64
|
-
# @param [Integer] threshold the threshold of multisig.
|
65
|
-
# @param [Array[String]] keys an array of keys.
|
66
|
-
# @return [Tapyrus::Script] multisig script.
|
67
|
-
def multi(threshold, *keys, sort: false)
|
68
|
-
raise ArgumentError, 'Multisig threshold is not valid.' unless threshold.is_a?(Integer)
|
69
|
-
raise ArgumentError, 'Multisig threshold cannot be 0, must be at least 1.' unless threshold > 0
|
70
|
-
raise ArgumentError, 'Multisig threshold cannot be larger than the number of keys.' if threshold > keys.size
|
71
|
-
raise ArgumentError, 'Multisig must have between 1 and 16 keys, inclusive.' if keys.size > 16
|
72
|
-
pubkeys = keys.map{|key| extract_pubkey(key) }
|
73
|
-
Tapyrus::Script.to_multisig_script(threshold, pubkeys, sort: sort)
|
74
|
-
end
|
75
|
-
|
76
|
-
# generate sorted multisig output for given keys.
|
77
|
-
# @param [Integer] threshold the threshold of multisig.
|
78
|
-
# @param [Array[String]] keys an array of keys.
|
79
|
-
# @return [Tapyrus::Script] multisig script.
|
80
|
-
def sortedmulti(threshold, *keys)
|
81
|
-
multi(threshold, *keys, sort: true)
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
# extract public key from KEY format.
|
87
|
-
# @param [String] key KEY string.
|
88
|
-
# @return [String] public key.
|
89
|
-
def extract_pubkey(key)
|
90
|
-
if key.start_with?('[') # BIP32 fingerprint
|
91
|
-
raise ArgumentError, 'Invalid key origin.' if key.count('[') > 1 || key.count(']') > 1
|
92
|
-
info = key[1...key.index(']')] # TODO
|
93
|
-
fingerprint, *paths = info.split('/')
|
94
|
-
raise ArgumentError, 'Fingerprint is not hex.' unless fingerprint.valid_hex?
|
95
|
-
raise ArgumentError, 'Fingerprint is not 4 bytes.' unless fingerprint.size == 8
|
96
|
-
key = key[(key.index(']') + 1)..-1]
|
97
|
-
else
|
98
|
-
raise ArgumentError, 'Invalid key origin.' if key.include?(']')
|
99
|
-
end
|
100
|
-
|
101
|
-
# check BIP32 derivation path
|
102
|
-
key, *paths = key.split('/')
|
103
|
-
|
104
|
-
if key.start_with?('xprv')
|
105
|
-
key = Tapyrus::ExtKey.from_base58(key)
|
106
|
-
key = derive_path(key, paths, true) if paths
|
107
|
-
elsif key.start_with?('xpub')
|
108
|
-
key = Tapyrus::ExtPubkey.from_base58(key)
|
109
|
-
key = derive_path(key, paths, false) if paths
|
110
|
-
else
|
111
|
-
begin
|
112
|
-
key = Tapyrus::Key.from_wif(key)
|
113
|
-
rescue ArgumentError
|
114
|
-
key_type = compressed_key?(key) ? Tapyrus::Key::TYPES[:compressed] : Tapyrus::Key::TYPES[:uncompressed]
|
115
|
-
key = Tapyrus::Key.new(pubkey: key, key_type: key_type)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
key = key.is_a?(Tapyrus::Key) ? key : key.key
|
119
|
-
raise ArgumentError, 'Invalid pubkey.' unless key.fully_valid_pubkey?
|
120
|
-
key.pubkey
|
121
|
-
end
|
122
|
-
|
123
|
-
def compressed_key?(key)
|
124
|
-
%w(02 03).include?(key[0..1]) && [key].pack("H*").bytesize == 33
|
125
|
-
end
|
126
|
-
|
127
|
-
def derive_path(key, paths, is_private)
|
128
|
-
paths.each do |path|
|
129
|
-
raise ArgumentError, 'xpub can not derive hardened key.' if !is_private && path.end_with?("'")
|
130
|
-
if is_private
|
131
|
-
hardened = path.end_with?("'")
|
132
|
-
path = hardened ? path[0..-2] : path
|
133
|
-
raise ArgumentError, 'Key path value is not a valid value.' unless path =~ /^[0-9]+$/
|
134
|
-
raise ArgumentError, 'Key path value is out of range.' if !hardened && path.to_i >= Tapyrus::HARDENED_THRESHOLD
|
135
|
-
key = key.derive(path.to_i, hardened)
|
136
|
-
else
|
137
|
-
raise ArgumentError, 'Key path value is not a valid value.' unless path =~ /^[0-9]+$/
|
138
|
-
raise ArgumentError, 'Key path value is out of range.' if path.to_i >= Tapyrus::HARDENED_THRESHOLD
|
139
|
-
key = key.derive(path.to_i)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
key
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module Tapyrus
|
2
|
-
|
3
|
-
# witness
|
4
|
-
class ScriptWitness
|
5
|
-
|
6
|
-
attr_reader :stack
|
7
|
-
|
8
|
-
def initialize(stack = [])
|
9
|
-
@stack = stack
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.parse_from_payload(payload)
|
13
|
-
buf = payload.is_a?(StringIO) ? payload : StringIO.new(payload)
|
14
|
-
size = Tapyrus.unpack_var_int_from_io(buf)
|
15
|
-
stack = size.times.map do
|
16
|
-
buf.read(Tapyrus.unpack_var_int_from_io(buf))
|
17
|
-
end
|
18
|
-
self.new(stack)
|
19
|
-
end
|
20
|
-
|
21
|
-
def empty?
|
22
|
-
stack.empty?
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_payload
|
26
|
-
p = Tapyrus.pack_var_int(stack.size)
|
27
|
-
p << stack.map { |s|
|
28
|
-
Tapyrus.pack_var_int(s.bytesize) << s
|
29
|
-
}.join
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_s
|
33
|
-
stack.map{|s|s.bth}.join(' ')
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|