tapyrus 0.2.4 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -2,10 +2,8 @@ require 'securerandom'
2
2
 
3
3
  module Tapyrus
4
4
  module SLIP39
5
-
6
5
  # Shamir's Secret Sharing
7
6
  class SSS
8
-
9
7
  include Tapyrus::Util
10
8
  extend Tapyrus::Util
11
9
 
@@ -37,39 +35,56 @@ module Tapyrus
37
35
  raise ArgumentError, 'Groups is empty.' if groups.empty?
38
36
  raise ArgumentError, 'Group threshold must be greater than 0.' if group_threshold.nil? || group_threshold < 1
39
37
  raise ArgumentError, 'Master secret does not specified.' unless secret
40
- raise ArgumentError, "The length of the master secret (#{secret.htb.bytesize} bytes) must be at least #{MIN_STRENGTH_BITS / 8} bytes." if (secret.htb.bytesize * 8) < MIN_STRENGTH_BITS
41
- raise ArgumentError, 'The length of the master secret in bytes must be an even number.' unless secret.bytesize.even?
42
- raise ArgumentError, 'The passphrase must contain only printable ASCII characters (code points 32-126).' unless passphrase.ascii_only?
43
- raise ArgumentError, "The requested group threshold (#{group_threshold}) must not exceed the number of groups (#{groups.length})." if group_threshold > groups.length
38
+ if (secret.htb.bytesize * 8) < MIN_STRENGTH_BITS
39
+ raise ArgumentError,
40
+ "The length of the master secret (#{secret.htb.bytesize} bytes) must be at least #{MIN_STRENGTH_BITS / 8} bytes."
41
+ end
42
+ unless secret.bytesize.even?
43
+ raise ArgumentError, 'The length of the master secret in bytes must be an even number.'
44
+ end
45
+ unless passphrase.ascii_only?
46
+ raise ArgumentError, 'The passphrase must contain only printable ASCII characters (code points 32-126).'
47
+ end
48
+ if group_threshold > groups.length
49
+ raise ArgumentError,
50
+ "The requested group threshold (#{group_threshold}) must not exceed the number of groups (#{groups.length})."
51
+ end
44
52
  groups.each do |threshold, count|
45
53
  raise ArgumentError, 'Group threshold must be greater than 0.' if threshold.nil? || threshold < 1
46
- raise ArgumentError, "The requested member threshold (#{threshold}) must not exceed the number of share (#{count})." if threshold > count
47
- raise ArgumentError, "Creating multiple member shares with member threshold 1 is not allowed. Use 1-of-1 member sharing instead." if threshold == 1 && count > 1
54
+ if threshold > count
55
+ raise ArgumentError,
56
+ "The requested member threshold (#{threshold}) must not exceed the number of share (#{count})."
57
+ end
58
+ if threshold == 1 && count > 1
59
+ raise ArgumentError,
60
+ 'Creating multiple member shares with member threshold 1 is not allowed. Use 1-of-1 member sharing instead.'
61
+ end
48
62
  end
49
63
 
50
- id = SecureRandom.random_number(32767) # 32767 is max number for 15 bits.
64
+ id = SecureRandom.random_number(32_767) # 32767 is max number for 15 bits.
51
65
  ems = encrypt(secret, passphrase, exp, id)
52
66
 
53
67
  group_shares = split_secret(group_threshold, groups.length, ems)
54
68
 
55
- shares = group_shares.map.with_index do |s, i|
56
- group_index, group_share = s[0], s[1]
57
- member_threshold, member_count = groups[i][0], groups[i][1]
58
- shares = split_secret(member_threshold, member_count, group_share)
59
- shares.map do |member_index, member_share|
60
- share = Tapyrus::SLIP39::Share.new
61
- share.id = id
62
- share.iteration_exp = exp
63
- share.group_index = group_index
64
- share.group_threshold = group_threshold
65
- share.group_count = groups.length
66
- share.member_index = member_index
67
- share.member_threshold = member_threshold
68
- share.value = member_share
69
- share.checksum = share.calculate_checksum
70
- share
69
+ shares =
70
+ group_shares.map.with_index do |s, i|
71
+ group_index, group_share = s[0], s[1]
72
+ member_threshold, member_count = groups[i][0], groups[i][1]
73
+ shares = split_secret(member_threshold, member_count, group_share)
74
+ shares.map do |member_index, member_share|
75
+ share = Tapyrus::SLIP39::Share.new
76
+ share.id = id
77
+ share.iteration_exp = exp
78
+ share.group_index = group_index
79
+ share.group_threshold = group_threshold
80
+ share.group_count = groups.length
81
+ share.member_index = member_index
82
+ share.member_threshold = member_threshold
83
+ share.value = member_share
84
+ share.checksum = share.calculate_checksum
85
+ share
86
+ end
71
87
  end
72
- end
73
88
  shares
74
89
  end
75
90
 
@@ -92,9 +107,15 @@ module Tapyrus
92
107
 
93
108
  shares.each do |share|
94
109
  raise ArgumentError, 'Invalid set of shares. All shares must have the same id.' unless id == share.id
95
- raise ArgumentError, 'Invalid set of shares. All shares must have the same group threshold.' unless group_threshold == share.group_threshold
96
- raise ArgumentError, 'Invalid set of shares. All shares must have the same group count.' unless group_count == share.group_count
97
- raise ArgumentError, 'Invalid set of shares. All Shares must have the same iteration exponent.' unless exp == share.iteration_exp
110
+ unless group_threshold == share.group_threshold
111
+ raise ArgumentError, 'Invalid set of shares. All shares must have the same group threshold.'
112
+ end
113
+ unless group_count == share.group_count
114
+ raise ArgumentError, 'Invalid set of shares. All shares must have the same group count.'
115
+ end
116
+ unless exp == share.iteration_exp
117
+ raise ArgumentError, 'Invalid set of shares. All Shares must have the same iteration exponent.'
118
+ end
98
119
  groups[share.group_index] ||= []
99
120
  groups[share.group_index] << share
100
121
  end
@@ -102,20 +123,29 @@ module Tapyrus
102
123
  group_shares = {}
103
124
  groups.each do |group_index, shares|
104
125
  member_threshold = shares.first.member_threshold
105
- raise ArgumentError, "Wrong number of mnemonics. Threshold is #{member_threshold}, but share count is #{shares.length}" if shares.length < member_threshold
126
+ if shares.length < member_threshold
127
+ raise ArgumentError,
128
+ "Wrong number of mnemonics. Threshold is #{member_threshold}, but share count is #{shares.length}"
129
+ end
106
130
  if shares.length == 1 && member_threshold == 1
107
131
  group_shares[group_index] = shares.first.value
108
132
  else
109
133
  value_length = shares.first.value.length
110
134
  x_coordinates = []
111
135
  shares.each do |share|
112
- raise ArgumentError, 'Invalid set of shares. All shares in a group must have the same member threshold.' unless member_threshold == share.member_threshold
113
- raise ArgumentError, 'Invalid set of shares. All share values must have the same length.' unless value_length == share.value.length
136
+ unless member_threshold == share.member_threshold
137
+ raise ArgumentError, 'Invalid set of shares. All shares in a group must have the same member threshold.'
138
+ end
139
+ unless value_length == share.value.length
140
+ raise ArgumentError, 'Invalid set of shares. All share values must have the same length.'
141
+ end
114
142
  x_coordinates << share.member_index
115
143
  end
116
144
  x_coordinates.uniq!
117
- raise ArgumentError, 'Invalid set of shares. Share indices must be unique.' unless x_coordinates.size == shares.size
118
- interpolate_shares = shares.map{|s|[s.member_index, s.value]}
145
+ unless x_coordinates.size == shares.size
146
+ raise ArgumentError, 'Invalid set of shares. Share indices must be unique.'
147
+ end
148
+ interpolate_shares = shares.map { |s| [s.member_index, s.value] }
119
149
 
120
150
  secret = interpolate(interpolate_shares, SECRET_INDEX)
121
151
  digest_value = interpolate(interpolate_shares, DIGEST_INDEX).htb
@@ -129,9 +159,12 @@ module Tapyrus
129
159
 
130
160
  return decrypt(group_shares.values.first, passphrase, exp, id) if group_threshold == 1
131
161
 
132
- raise ArgumentError, "Wrong number of mnemonics. Group threshold is #{group_threshold}, but share count is #{group_shares.length}" if group_shares.length < group_threshold
162
+ if group_shares.length < group_threshold
163
+ raise ArgumentError,
164
+ "Wrong number of mnemonics. Group threshold is #{group_threshold}, but share count is #{group_shares.length}"
165
+ end
133
166
 
134
- interpolate_shares = group_shares.map{|k, v|[k, v]}
167
+ interpolate_shares = group_shares.map { |k, v| [k, v] }
135
168
  secret = interpolate(interpolate_shares, SECRET_INDEX)
136
169
  digest_value = interpolate(interpolate_shares, DIGEST_INDEX).htb
137
170
  digest, random_value = digest_value[0...DIGEST_LENGTH_BYTES].bth, digest_value[DIGEST_LENGTH_BYTES..-1].bth
@@ -148,17 +181,18 @@ module Tapyrus
148
181
  # @param [Integer] x the x coordinate of the result.
149
182
  # @return [String] f(x) value with hex format.
150
183
  def self.interpolate(shares, x)
151
- s = shares.find{|s|s[0] == x}
184
+ s = shares.find { |s| s[0] == x }
152
185
  return s[1] if s
153
186
 
154
- log_prod = shares.sum{|s|LOG_TABLE[s[0] ^ x]}
187
+ log_prod = shares.sum { |s| LOG_TABLE[s[0] ^ x] }
155
188
 
156
189
  result = ('00' * shares.first[1].length).htb
157
190
  shares.each do |share|
158
- log_basis_eval = (log_prod - LOG_TABLE[share[0] ^ x] - shares.sum{|s|LOG_TABLE[share[0] ^ s[0]]}) % 255
159
- result = share[1].htb.bytes.each.map.with_index do |v, i|
160
- (result[i].bti ^ (v == 0 ? 0 : (EXP_TABLE[(LOG_TABLE[v] + log_basis_eval) % 255]))).itb
161
- end.join
191
+ log_basis_eval = (log_prod - LOG_TABLE[share[0] ^ x] - shares.sum { |s| LOG_TABLE[share[0] ^ s[0]] }) % 255
192
+ result =
193
+ share[1].htb.bytes.each.map.with_index do |v, i|
194
+ (result[i].bti ^ (v == 0 ? 0 : (EXP_TABLE[(LOG_TABLE[v] + log_basis_eval) % 255]))).itb
195
+ end.join
162
196
  end
163
197
  result.bth
164
198
  end
@@ -172,10 +206,14 @@ module Tapyrus
172
206
  l, r = ems[0...(ems.length / 2)].htb, ems[(ems.length / 2)..-1].htb
173
207
  salt = get_salt(id)
174
208
  e = (Tapyrus::SLIP39::BASE_ITERATION_COUNT << exp) / Tapyrus::SLIP39::ROUND_COUNT
175
- Tapyrus::SLIP39::ROUND_COUNT.times.to_a.reverse.each do |i|
176
- f = OpenSSL::PKCS5.pbkdf2_hmac((i.itb + passphrase), salt + r, e, r.bytesize, 'sha256')
177
- l, r = padding_zero(r, r.bytesize), padding_zero((l.bti ^ f.bti).itb, r.bytesize)
178
- end
209
+ Tapyrus::SLIP39::ROUND_COUNT
210
+ .times
211
+ .to_a
212
+ .reverse
213
+ .each do |i|
214
+ f = OpenSSL::PKCS5.pbkdf2_hmac((i.itb + passphrase), salt + r, e, r.bytesize, 'sha256')
215
+ l, r = padding_zero(r, r.bytesize), padding_zero((l.bti ^ f.bti).itb, r.bytesize)
216
+ end
179
217
  (r + l).bth
180
218
  end
181
219
 
@@ -190,10 +228,13 @@ module Tapyrus
190
228
  l, r = s[0...(s.bytesize / 2)], s[(s.bytesize / 2)..-1]
191
229
  salt = get_salt(id)
192
230
  e = (Tapyrus::SLIP39::BASE_ITERATION_COUNT << exp) / Tapyrus::SLIP39::ROUND_COUNT
193
- Tapyrus::SLIP39::ROUND_COUNT.times.to_a.each do |i|
194
- f = OpenSSL::PKCS5.pbkdf2_hmac((i.itb + passphrase), salt + r, e, r.bytesize, 'sha256')
195
- l, r = padding_zero(r, r.bytesize), padding_zero((l.bti ^ f.bti).itb, r.bytesize)
196
- end
231
+ Tapyrus::SLIP39::ROUND_COUNT
232
+ .times
233
+ .to_a
234
+ .each do |i|
235
+ f = OpenSSL::PKCS5.pbkdf2_hmac((i.itb + passphrase), salt + r, e, r.bytesize, 'sha256')
236
+ l, r = padding_zero(r, r.bytesize), padding_zero((l.bti ^ f.bti).itb, r.bytesize)
237
+ end
197
238
  (r + l).bth
198
239
  end
199
240
 
@@ -220,26 +261,29 @@ module Tapyrus
220
261
  # @return [Array[Integer, String]] the array of split secret.
221
262
  def self.split_secret(threshold, count, secret)
222
263
  raise ArgumentError, "The requested threshold (#{threshold}) must be a positive integer." if threshold < 1
223
- raise ArgumentError, "The requested threshold (#{threshold}) must not exceed the number of shares (#{count})." if threshold > count
224
- raise ArgumentError, "The requested number of shares (#{count}) must not exceed #{MAX_SHARE_COUNT}." if count > MAX_SHARE_COUNT
264
+ if threshold > count
265
+ raise ArgumentError, "The requested threshold (#{threshold}) must not exceed the number of shares (#{count})."
266
+ end
267
+ if count > MAX_SHARE_COUNT
268
+ raise ArgumentError, "The requested number of shares (#{count}) must not exceed #{MAX_SHARE_COUNT}."
269
+ end
225
270
 
226
- return count.times.map{|i|[i, secret]} if threshold == 1 # if the threshold is 1, digest of the share is not used.
271
+ return count.times.map { |i| [i, secret] } if threshold == 1 # if the threshold is 1, digest of the share is not used.
227
272
 
228
273
  random_share_count = threshold - 2
229
274
 
230
- shares = random_share_count.times.map{|i|[i, SecureRandom.hex(secret.htb.bytesize)]}
275
+ shares = random_share_count.times.map { |i| [i, SecureRandom.hex(secret.htb.bytesize)] }
231
276
  random_part = SecureRandom.hex(secret.htb.bytesize - DIGEST_LENGTH_BYTES)
232
277
  digest = create_digest(secret, random_part)
233
278
 
234
279
  base_shares = shares + [[DIGEST_INDEX, digest + random_part], [SECRET_INDEX, secret]]
235
280
 
236
- (random_share_count...count).each { |i| shares << [i, interpolate(base_shares, i)]}
281
+ (random_share_count...count).each { |i| shares << [i, interpolate(base_shares, i)] }
237
282
 
238
283
  shares
239
284
  end
240
285
 
241
286
  private_class_method :split_secret, :get_salt, :interpolate, :encrypt, :decrypt, :create_digest
242
-
243
287
  end
244
288
  end
245
- end
289
+ end
data/lib/tapyrus/store.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  module Tapyrus
2
2
  module Store
3
-
4
3
  autoload :DB, 'tapyrus/store/db'
5
4
  autoload :SPVChain, 'tapyrus/store/spv_chain'
6
5
  autoload :ChainEntry, 'tapyrus/store/chain_entry'
7
-
8
6
  end
9
- end
7
+ end
@@ -1,6 +1,5 @@
1
1
  module Tapyrus
2
2
  module Store
3
-
4
3
  # wrap a block header object with extra data.
5
4
  class ChainEntry
6
5
  include Tapyrus::HexConverter
@@ -60,9 +59,6 @@ module Tapyrus
60
59
  height_value = height_value.htb.reverse
61
60
  Tapyrus.pack_var_int(height_value.bytesize) + height_value + header.to_payload
62
61
  end
63
-
64
62
  end
65
-
66
63
  end
67
-
68
64
  end
@@ -1,9 +1,7 @@
1
1
  module Tapyrus
2
2
  module Store
3
-
4
3
  module DB
5
4
  autoload :LevelDB, 'tapyrus/store/db/level_db'
6
5
  end
7
-
8
6
  end
9
7
  end
@@ -3,9 +3,7 @@ require 'leveldb-native'
3
3
  module Tapyrus
4
4
  module Store
5
5
  module DB
6
-
7
6
  class LevelDB
8
-
9
7
  attr_reader :db
10
8
  attr_reader :logger
11
9
 
@@ -62,9 +60,11 @@ module Tapyrus
62
60
  # @param [Tapyrus::Store::ChainEntry]
63
61
  def save_entry(entry)
64
62
  db.batch do
65
- db.put(entry.key ,entry.to_payload)
63
+ db.put(entry.key, entry.to_payload)
66
64
  db.put(height_key(entry.height), entry.block_hash)
67
- add_agg_pubkey(entry.height == 0 ? 0 : entry.height + 1, entry.header.x_field) if entry.header.upgrade_agg_pubkey?
65
+ if entry.header.upgrade_agg_pubkey?
66
+ add_agg_pubkey(entry.height == 0 ? 0 : entry.height + 1, entry.header.x_field)
67
+ end
68
68
  connect_entry(entry)
69
69
  end
70
70
  end
@@ -134,9 +134,7 @@ module Tapyrus
134
134
  unless tip_block.block_hash == entry.prev_hash
135
135
  raise "entry(#{entry.block_hash}) does not reference current best block hash(#{tip_block.block_hash})"
136
136
  end
137
- unless tip_block.height + 1 == entry.height
138
- raise "block height is small than current best block."
139
- end
137
+ raise 'block height is small than current best block.' unless tip_block.height + 1 == entry.height
140
138
  end
141
139
  db.put(KEY_PREFIX[:best], entry.block_hash)
142
140
  db.put(KEY_PREFIX[:next] + entry.prev_hash, entry.block_hash)
@@ -148,9 +146,7 @@ module Tapyrus
148
146
  index = db.get(KEY_PREFIX[:latest_agg_pubkey])
149
147
  index&.to_i(16)
150
148
  end
151
-
152
149
  end
153
-
154
150
  end
155
151
  end
156
152
  end
@@ -1,18 +1,15 @@
1
1
  module Tapyrus
2
-
3
2
  module Store
4
-
5
3
  KEY_PREFIX = {
6
- entry: 'e', # key: block hash, value: Tapyrus::Store::ChainEntry payload
7
- height: 'h', # key: block height, value: block hash.
8
- best: 'B', # value: best block hash.
9
- next: 'n', # key: block hash, value: A hash of the next block of the specified hash
10
- agg_pubkey: 'a', # key: index, value: Activated block height | aggregated public key.
11
- latest_agg_pubkey: 'g' # value: latest agg pubkey index.
4
+ entry: 'e', # key: block hash, value: Tapyrus::Store::ChainEntry payload
5
+ height: 'h', # key: block height, value: block hash.
6
+ best: 'B', # value: best block hash.
7
+ next: 'n', # key: block hash, value: A hash of the next block of the specified hash
8
+ agg_pubkey: 'a', # key: index, value: Activated block height | aggregated public key.
9
+ latest_agg_pubkey: 'g' # value: latest agg pubkey index.
12
10
  }
13
11
 
14
12
  class SPVChain
15
-
16
13
  attr_reader :db
17
14
  attr_reader :logger
18
15
 
@@ -53,7 +50,9 @@ module Tapyrus
53
50
  logger.info("append header #{header.block_id}")
54
51
  best_block = latest_block
55
52
  current_height = best_block.height
56
- raise "this header is invalid. #{header.block_hash}" unless header.valid?(db.agg_pubkey_with_height(current_height + 1))
53
+ unless header.valid?(db.agg_pubkey_with_height(current_height + 1))
54
+ raise "this header is invalid. #{header.block_hash}"
55
+ end
57
56
  if best_block.block_hash == header.prev_hash
58
57
  entry = Tapyrus::Store::ChainEntry.new(header, current_height + 1)
59
58
  db.save_entry(entry)
@@ -107,13 +106,8 @@ module Tapyrus
107
106
  # if database is empty, put genesis block.
108
107
  # @param [Tapyrus::Block] genesis genesis block
109
108
  def initialize_block(genesis)
110
- unless latest_block
111
- db.save_entry(ChainEntry.new(genesis.header, 0))
112
- end
109
+ db.save_entry(ChainEntry.new(genesis.header, 0)) unless latest_block
113
110
  end
114
-
115
111
  end
116
-
117
112
  end
118
-
119
- end
113
+ end
data/lib/tapyrus/tx.rb CHANGED
@@ -2,7 +2,6 @@
2
2
  # https://github.com/lian/bitcoin-ruby/blob/master/COPYING
3
3
 
4
4
  module Tapyrus
5
-
6
5
  # Transaction class
7
6
  class Tx
8
7
  include Tapyrus::HexConverter
@@ -10,7 +9,7 @@ module Tapyrus
10
9
  MAX_STANDARD_VERSION = 2
11
10
 
12
11
  # The maximum weight for transactions we're willing to relay/mine
13
- MAX_STANDARD_TX_WEIGHT = 400000
12
+ MAX_STANDARD_TX_WEIGHT = 400_000
14
13
 
15
14
  attr_accessor :features
16
15
  attr_reader :inputs
@@ -34,14 +33,10 @@ module Tapyrus
34
33
 
35
34
  in_count = Tapyrus.unpack_var_int_from_io(buf)
36
35
 
37
- in_count.times do
38
- tx.inputs << TxIn.parse_from_payload(buf)
39
- end
36
+ in_count.times { tx.inputs << TxIn.parse_from_payload(buf) }
40
37
 
41
38
  out_count = Tapyrus.unpack_var_int_from_io(buf)
42
- out_count.times do
43
- tx.outputs << TxOut.parse_from_payload(buf)
44
- end
39
+ out_count.times { tx.outputs << TxOut.parse_from_payload(buf) }
45
40
 
46
41
  tx.lock_time = buf.read(4).unpack('V').first
47
42
 
@@ -58,7 +53,7 @@ module Tapyrus
58
53
 
59
54
  def txid
60
55
  buf = [features].pack('V')
61
- buf << Tapyrus.pack_var_int(inputs.length) << inputs.map{|i|i.to_payload(use_malfix: true)}.join
56
+ buf << Tapyrus.pack_var_int(inputs.length) << inputs.map { |i| i.to_payload(use_malfix: true) }.join
62
57
  buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join
63
58
  buf << [lock_time].pack('V')
64
59
  Tapyrus.double_sha256(buf).reverse.bth
@@ -95,6 +90,7 @@ module Tapyrus
95
90
  outputs.each do |o|
96
91
  return false unless o.script_pubkey.standard?
97
92
  data_count += 1 if o.script_pubkey.op_return?
93
+
98
94
  # TODO add non P2SH multisig relay(permitbaremultisig)
99
95
  return false if o.dust?
100
96
  end
@@ -114,8 +110,14 @@ module Tapyrus
114
110
  # @param [Integer] amount tapyrus amount locked in input. required for witness input only.
115
111
  # @param [Integer] skip_separator_index If output_script is P2WSH and output_script contains any OP_CODESEPARATOR,
116
112
  # the script code needs is the witnessScript but removing everything up to and including the last executed OP_CODESEPARATOR before the signature checking opcode being executed.
117
- def sighash_for_input(input_index, output_script, hash_type: SIGHASH_TYPE[:all],
118
- sig_version: :base, amount: nil, skip_separator_index: 0)
113
+ def sighash_for_input(
114
+ input_index,
115
+ output_script,
116
+ hash_type: SIGHASH_TYPE[:all],
117
+ sig_version: :base,
118
+ amount: nil,
119
+ skip_separator_index: 0
120
+ )
119
121
  raise ArgumentError, 'input_index must be specified.' unless input_index
120
122
  raise ArgumentError, 'does not exist input corresponding to input_index.' if input_index >= inputs.size
121
123
  raise ArgumentError, 'script_pubkey must be specified.' unless output_script
@@ -129,16 +131,19 @@ module Tapyrus
129
131
  # @param [Integer] amount the amount of tapyrus, require for witness program only.
130
132
  # @param [Array] flags the flags used when execute script interpreter.
131
133
  def verify_input_sig(input_index, script_pubkey, amount: nil, flags: STANDARD_SCRIPT_VERIFY_FLAGS)
132
- if script_pubkey.p2sh?
133
- flags << SCRIPT_VERIFY_P2SH
134
- end
134
+ flags << SCRIPT_VERIFY_P2SH if script_pubkey.p2sh?
135
135
  verify_input_sig_for_legacy(input_index, script_pubkey, flags)
136
136
  end
137
137
 
138
138
  def to_h
139
139
  {
140
- txid: txid, hash: tx_hash, features: features, size: size, locktime: lock_time,
141
- vin: inputs.map(&:to_h), vout: outputs.map.with_index{|tx_out, index| tx_out.to_h.merge({n: index})}
140
+ txid: txid,
141
+ hash: tx_hash,
142
+ features: features,
143
+ size: size,
144
+ locktime: lock_time,
145
+ vin: inputs.map(&:to_h),
146
+ vout: outputs.map.with_index { |tx_out, index| tx_out.to_h.merge({ n: index }) }
142
147
  }
143
148
  end
144
149
 
@@ -154,43 +159,48 @@ module Tapyrus
154
159
 
155
160
  # generate sighash with legacy format
156
161
  def sighash_for_legacy(index, script_code, hash_type)
157
- ins = inputs.map.with_index do |i, idx|
158
- if idx == index
159
- i.to_payload(script_code.delete_opcode(Tapyrus::Opcodes::OP_CODESEPARATOR))
160
- else
161
- case hash_type & 0x1f
162
+ ins =
163
+ inputs.map.with_index do |i, idx|
164
+ if idx == index
165
+ i.to_payload(script_code.delete_opcode(Tapyrus::Opcodes::OP_CODESEPARATOR))
166
+ else
167
+ case hash_type & 0x1f
162
168
  when SIGHASH_TYPE[:none], SIGHASH_TYPE[:single]
163
169
  i.to_payload(Tapyrus::Script.new, 0)
164
170
  else
165
171
  i.to_payload(Tapyrus::Script.new)
172
+ end
166
173
  end
167
174
  end
168
- end
169
175
 
170
176
  outs = outputs.map(&:to_payload)
171
177
  out_size = Tapyrus.pack_var_int(outputs.size)
172
178
 
173
179
  case hash_type & 0x1f
174
- when SIGHASH_TYPE[:none]
175
- outs = ''
176
- out_size = Tapyrus.pack_var_int(0)
177
- when SIGHASH_TYPE[:single]
178
- return "\x01".ljust(32, "\x00") if index >= outputs.size
179
- outs = outputs[0...(index + 1)].map.with_index { |o, idx| (idx == index) ? o.to_payload : o.to_empty_payload }.join
180
- out_size = Tapyrus.pack_var_int(index + 1)
180
+ when SIGHASH_TYPE[:none]
181
+ outs = ''
182
+ out_size = Tapyrus.pack_var_int(0)
183
+ when SIGHASH_TYPE[:single]
184
+ return "\x01".ljust(32, "\x00") if index >= outputs.size
185
+ outs =
186
+ outputs[0...(index + 1)].map.with_index { |o, idx| (idx == index) ? o.to_payload : o.to_empty_payload }.join
187
+ out_size = Tapyrus.pack_var_int(index + 1)
181
188
  end
182
189
 
183
- if hash_type & SIGHASH_TYPE[:anyonecanpay] != 0
184
- ins = [ins[index]]
185
- end
190
+ ins = [ins[index]] if hash_type & SIGHASH_TYPE[:anyonecanpay] != 0
186
191
 
187
- buf = [[features].pack('V'), Tapyrus.pack_var_int(ins.size),
188
- ins, out_size, outs, [lock_time, hash_type].pack('VV')].join
192
+ buf = [
193
+ [features].pack('V'),
194
+ Tapyrus.pack_var_int(ins.size),
195
+ ins,
196
+ out_size,
197
+ outs,
198
+ [lock_time, hash_type].pack('VV')
199
+ ].join
189
200
 
190
201
  Tapyrus.double_sha256(buf)
191
202
  end
192
203
 
193
-
194
204
  # verify input signature for legacy tx.
195
205
  def verify_input_sig_for_legacy(input_index, script_pubkey, flags)
196
206
  script_sig = inputs[input_index].script_sig
@@ -199,7 +209,5 @@ module Tapyrus
199
209
 
200
210
  interpreter.verify_script(script_sig, script_pubkey)
201
211
  end
202
-
203
212
  end
204
-
205
213
  end