tapyrus 0.3.4 → 0.3.5

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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/{.prettierrc.yaml → .prettierrc.yml} +0 -1
  4. data/.ruby-version +1 -1
  5. data/Gemfile +2 -2
  6. data/README.md +1 -1
  7. data/Rakefile +2 -2
  8. data/exe/tapyrus-script-debugger +5 -5
  9. data/exe/tapyrusrb-cli +1 -1
  10. data/exe/tapyrusrbd +18 -17
  11. data/lib/openassets/payload.rb +2 -2
  12. data/lib/openassets/util.rb +2 -2
  13. data/lib/openassets.rb +4 -4
  14. data/lib/schnorr/sign_to_contract.rb +4 -4
  15. data/lib/schnorr/signature.rb +5 -5
  16. data/lib/schnorr.rb +14 -14
  17. data/lib/tapyrus/base58.rb +8 -8
  18. data/lib/tapyrus/bip175.rb +5 -5
  19. data/lib/tapyrus/block_header.rb +2 -2
  20. data/lib/tapyrus/bloom_filter.rb +1 -1
  21. data/lib/tapyrus/chain_params.rb +5 -5
  22. data/lib/tapyrus/constants.rb +1 -1
  23. data/lib/tapyrus/errors.rb +9 -9
  24. data/lib/tapyrus/ext/ecdsa.rb +4 -4
  25. data/lib/tapyrus/ext/json_parser.rb +1 -1
  26. data/lib/tapyrus/ext.rb +3 -3
  27. data/lib/tapyrus/ext_key.rb +21 -21
  28. data/lib/tapyrus/jws.rb +76 -0
  29. data/lib/tapyrus/key.rb +48 -20
  30. data/lib/tapyrus/key_path.rb +3 -3
  31. data/lib/tapyrus/logger.rb +4 -11
  32. data/lib/tapyrus/merkle_tree.rb +1 -1
  33. data/lib/tapyrus/message/addr.rb +2 -2
  34. data/lib/tapyrus/message/base.rb +2 -2
  35. data/lib/tapyrus/message/block.rb +1 -1
  36. data/lib/tapyrus/message/block_txn.rb +1 -1
  37. data/lib/tapyrus/message/cmpct_block.rb +1 -1
  38. data/lib/tapyrus/message/fee_filter.rb +3 -3
  39. data/lib/tapyrus/message/filter_add.rb +1 -1
  40. data/lib/tapyrus/message/filter_clear.rb +2 -2
  41. data/lib/tapyrus/message/filter_load.rb +7 -7
  42. data/lib/tapyrus/message/get_addr.rb +2 -2
  43. data/lib/tapyrus/message/get_block_txn.rb +1 -1
  44. data/lib/tapyrus/message/get_blocks.rb +1 -1
  45. data/lib/tapyrus/message/get_data.rb +1 -1
  46. data/lib/tapyrus/message/get_headers.rb +1 -1
  47. data/lib/tapyrus/message/header_and_short_ids.rb +6 -6
  48. data/lib/tapyrus/message/headers.rb +1 -1
  49. data/lib/tapyrus/message/headers_parser.rb +2 -2
  50. data/lib/tapyrus/message/inv.rb +1 -1
  51. data/lib/tapyrus/message/inventory.rb +3 -3
  52. data/lib/tapyrus/message/mem_pool.rb +2 -2
  53. data/lib/tapyrus/message/merkle_block.rb +3 -3
  54. data/lib/tapyrus/message/network_addr.rb +9 -9
  55. data/lib/tapyrus/message/not_found.rb +1 -1
  56. data/lib/tapyrus/message/ping.rb +3 -3
  57. data/lib/tapyrus/message/pong.rb +3 -3
  58. data/lib/tapyrus/message/reject.rb +6 -6
  59. data/lib/tapyrus/message/send_cmpct.rb +4 -4
  60. data/lib/tapyrus/message/send_headers.rb +2 -2
  61. data/lib/tapyrus/message/tx.rb +1 -1
  62. data/lib/tapyrus/message/ver_ack.rb +2 -2
  63. data/lib/tapyrus/message/version.rb +7 -7
  64. data/lib/tapyrus/message.rb +37 -37
  65. data/lib/tapyrus/mnemonic.rb +18 -16
  66. data/lib/tapyrus/network/connection.rb +2 -2
  67. data/lib/tapyrus/network/message_handler.rb +11 -11
  68. data/lib/tapyrus/network/peer.rb +1 -1
  69. data/lib/tapyrus/network/peer_discovery.rb +1 -1
  70. data/lib/tapyrus/network/pool.rb +4 -4
  71. data/lib/tapyrus/network.rb +6 -6
  72. data/lib/tapyrus/node/cli.rb +34 -34
  73. data/lib/tapyrus/node/configuration.rb +3 -3
  74. data/lib/tapyrus/node/spv.rb +2 -2
  75. data/lib/tapyrus/node.rb +3 -3
  76. data/lib/tapyrus/opcodes.rb +7 -7
  77. data/lib/tapyrus/out_point.rb +2 -2
  78. data/lib/tapyrus/rpc/http_server.rb +6 -6
  79. data/lib/tapyrus/rpc/request_handler.rb +5 -5
  80. data/lib/tapyrus/rpc/tapyrus_core_client.rb +10 -10
  81. data/lib/tapyrus/rpc.rb +4 -4
  82. data/lib/tapyrus/script/color.rb +3 -3
  83. data/lib/tapyrus/script/debugger.rb +9 -9
  84. data/lib/tapyrus/script/multisig.rb +2 -2
  85. data/lib/tapyrus/script/script.rb +28 -28
  86. data/lib/tapyrus/script/script_error.rb +42 -42
  87. data/lib/tapyrus/script/script_interpreter.rb +9 -9
  88. data/lib/tapyrus/script/tx_checker.rb +2 -2
  89. data/lib/tapyrus/secp256k1/native.rb +23 -23
  90. data/lib/tapyrus/secp256k1/rfc6979.rb +7 -7
  91. data/lib/tapyrus/secp256k1/ruby.rb +2 -2
  92. data/lib/tapyrus/secp256k1.rb +3 -3
  93. data/lib/tapyrus/slip39/share.rb +7 -7
  94. data/lib/tapyrus/slip39/sss.rb +24 -24
  95. data/lib/tapyrus/slip39.rb +514 -37
  96. data/lib/tapyrus/store/db/level_db.rb +2 -2
  97. data/lib/tapyrus/store/db.rb +1 -1
  98. data/lib/tapyrus/store/spv_chain.rb +7 -7
  99. data/lib/tapyrus/store.rb +3 -3
  100. data/lib/tapyrus/tip0137.rb +201 -0
  101. data/lib/tapyrus/tx.rb +12 -12
  102. data/lib/tapyrus/tx_builder.rb +3 -3
  103. data/lib/tapyrus/tx_in.rb +3 -3
  104. data/lib/tapyrus/tx_out.rb +3 -3
  105. data/lib/tapyrus/util.rb +21 -21
  106. data/lib/tapyrus/validation.rb +9 -9
  107. data/lib/tapyrus/version.rb +1 -1
  108. data/lib/tapyrus/wallet/account.rb +12 -12
  109. data/lib/tapyrus/wallet/base.rb +9 -8
  110. data/lib/tapyrus/wallet/db.rb +11 -11
  111. data/lib/tapyrus/wallet/master_key.rb +13 -13
  112. data/lib/tapyrus/wallet.rb +4 -4
  113. data/lib/tapyrus.rb +62 -59
  114. data/tapyrusrb.gemspec +33 -31
  115. metadata +30 -14
@@ -1,4 +1,4 @@
1
- require 'leveldb-native'
1
+ require "leveldb-native"
2
2
 
3
3
  module Tapyrus
4
4
  module Store
@@ -134,7 +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
- raise 'block height is small than current best block.' unless tip_block.height + 1 == entry.height
137
+ raise "block height is small than current best block." unless tip_block.height + 1 == entry.height
138
138
  end
139
139
  db.put(KEY_PREFIX[:best], entry.block_hash)
140
140
  db.put(KEY_PREFIX[:next] + entry.prev_hash, entry.block_hash)
@@ -1,7 +1,7 @@
1
1
  module Tapyrus
2
2
  module Store
3
3
  module DB
4
- autoload :LevelDB, 'tapyrus/store/db/level_db'
4
+ autoload :LevelDB, "tapyrus/store/db/level_db"
5
5
  end
6
6
  end
7
7
  end
@@ -1,12 +1,12 @@
1
1
  module Tapyrus
2
2
  module Store
3
3
  KEY_PREFIX = {
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.
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.
10
10
  }
11
11
 
12
12
  class SPVChain
@@ -17,7 +17,7 @@ module Tapyrus
17
17
  # @param[Tapyrus::Store::DB::LevelDB] db
18
18
  # @param[Tapyrus::Block] genesis genesis block
19
19
  def initialize(db = Tapyrus::Store::DB::LevelDB.new, genesis: nil)
20
- raise ArgumentError, 'genesis block should be specified.' unless genesis
20
+ raise ArgumentError, "genesis block should be specified." unless genesis
21
21
  @db = db # TODO multiple db switch
22
22
  @logger = Tapyrus::Logger.create(:debug)
23
23
  initialize_block(genesis)
data/lib/tapyrus/store.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Tapyrus
2
2
  module Store
3
- autoload :DB, 'tapyrus/store/db'
4
- autoload :SPVChain, 'tapyrus/store/spv_chain'
5
- autoload :ChainEntry, 'tapyrus/store/chain_entry'
3
+ autoload :DB, "tapyrus/store/db"
4
+ autoload :SPVChain, "tapyrus/store/spv_chain"
5
+ autoload :ChainEntry, "tapyrus/store/chain_entry"
6
6
  end
7
7
  end
@@ -0,0 +1,201 @@
1
+ module Tapyrus
2
+ module TIP0137
3
+ # @param key [Tapyrus::Key] A private key
4
+ # @param txid [String] A transaction id string in hexadecimal format (64 characters long)
5
+ # @param index [Integer] Index of the transaction output, a non-negative integer less than 2^32
6
+ # @param color_id [Tapyrus::Color::ColorIdentifier] A valid instance of Tapyrus::Color::ColorIdentifier
7
+ # @param value [Integer] A non-negative integer less than 2^64 representing the value of the transaction output
8
+ # @param script_pubkey [Tapyrus::Script] A script pubkey in the transaction output
9
+ # @param address [String] A valid Tapyrus address string for the transaction output
10
+ # @param message [String] A hexadecimal formatted string
11
+ # @param client [Tapyrus::RPC::TapyrusCoreClient] The RPC client instance. If the client is specified, verify that the transaction associated with the txid and index exists on the blockchain and that a valid script_pubkey exists in the transaction.
12
+ # @return [String] Returns the message signed in JWS Format
13
+ # @raise [ArgumentError] If the txid is not a 64-character hexadecimal string
14
+ # @raise [ArgumentError] If the index is not a non-negative integer less than 2^32
15
+ # @raise [ArgumentError] If the color_id is not a valid Tapyrus::Color::ColorIdentifier object
16
+ # @raise [ArgumentError] If the value is not a non-negative integer less than 2^64
17
+ # @raise [ArgumentError] If the script_pubkey is not a valid Tapyrus::Script object
18
+ # @raise [ArgumentError] If the provided Tapyrus address is invalid
19
+ # @raise [ArgumentError] If the message is not a hexadecimal string
20
+ # @raise [ArgumentError] If the transaction with the given txid and index is not found in the blockchain
21
+ # @raise [ArgumentError] If the script and value do not correspond with those in the blockchain
22
+ # @raise [Tapyrus::RPC::Error] If RPC access fails
23
+ def sign_message!(
24
+ key,
25
+ txid:,
26
+ index:,
27
+ value:,
28
+ script_pubkey:,
29
+ color_id: nil,
30
+ address: nil,
31
+ message: nil,
32
+ client: nil
33
+ )
34
+ validate_payload!(
35
+ key: key,
36
+ txid: txid,
37
+ index: index,
38
+ color_id: color_id,
39
+ value: value,
40
+ script_pubkey: script_pubkey,
41
+ address: address,
42
+ message: message
43
+ )
44
+ if client
45
+ validate_on_blockchain!(
46
+ client: client,
47
+ txid: txid,
48
+ index: index,
49
+ color_id: color_id,
50
+ value: value,
51
+ script_pubkey: script_pubkey
52
+ )
53
+ end
54
+ data = {
55
+ txid: txid,
56
+ index: index,
57
+ color_id: color_id&.to_hex,
58
+ value: value,
59
+ script_pubkey: script_pubkey&.to_hex,
60
+ address: address,
61
+ message: message
62
+ }
63
+ Tapyrus::JWS.encode(data, key.priv_key)
64
+ end
65
+
66
+ # @param jws [String] JWS (JSON Web Signature)
67
+ # @param client [Tapyrus::RPC::TapyrusCoreClient] The RPC client instance. If the client is specified, verify that the transaction associated with the txid and index exists on the blockchain and that a valid script_pubkey exists in the transaction.
68
+ # @return A decoded JSON Object
69
+ # @raise [ArgumentError] If the decoded txid is not a 64-character hexadecimal string
70
+ # @raise [ArgumentError] If the decoded index is not a non-negative integer less than 2^32
71
+ # @raise [ArgumentError] If the decoded color_id is an invalid Tapyrus::Color::ColorIdentifier object
72
+ # @raise [ArgumentError] If the decoded value is not a non-negative integer less than 2^64
73
+ # @raise [ArgumentError] If the decoded script_pubkey is an invalid Tapyrus::Script object
74
+ # @raise [ArgumentError] If the decoded address is an invalid Tapyrus address
75
+ # @raise [ArgumentError] If the decoded message is not a hexadecimal string
76
+ # @raise [ArgumentError] If a transaction is not found with the decoded txid and index in the blockchain
77
+ # @raise [ArgumentError] If the decoded script and value do not match the ones in the blockchain
78
+ # @raise [JWT::DecodeError] If JWS decoding fails
79
+ # @raise [Tapyus::JWS::DecodeError] If the JWK key is invalid
80
+ # @raise [JWT::VerificationError] If the verification of the signature fails
81
+ # @raise [Tapyrus::RPC::Error] If RPC access fails
82
+ def verify_message!(jws, client: nil)
83
+ Tapyrus::JWS
84
+ .decode(jws)
85
+ .tap do |decoded|
86
+ header = decoded[1]
87
+ validate_header!(header)
88
+ jwk = header.dig("jwk", "keys", 0)
89
+ key = to_tapyrus_key(jwk)
90
+ payload = decoded[0]
91
+ color_id =
92
+ begin
93
+ Tapyrus::Color::ColorIdentifier.parse_from_payload(payload["color_id"]&.htb) if payload["color_id"]
94
+ rescue => _e
95
+ raise ArgumentError, "color_id is invalid"
96
+ end
97
+ script_pubkey =
98
+ begin
99
+ Tapyrus::Script.parse_from_payload(payload["script_pubkey"]&.htb)
100
+ rescue => _e
101
+ raise ArgumentError, "script_pubkey is invalid"
102
+ end
103
+ validate_payload!(
104
+ key: key,
105
+ txid: payload["txid"],
106
+ index: payload["index"],
107
+ color_id: color_id,
108
+ value: payload["value"],
109
+ script_pubkey: script_pubkey,
110
+ address: payload["address"],
111
+ message: payload["message"]
112
+ )
113
+ if client
114
+ validate_on_blockchain!(
115
+ client: client,
116
+ txid: payload["txid"],
117
+ index: payload["index"],
118
+ color_id: color_id,
119
+ value: payload["value"],
120
+ script_pubkey: script_pubkey
121
+ )
122
+ end
123
+ end
124
+ end
125
+
126
+ # @param jws [String] JWS (JSON Web Signature)
127
+ # @param client [Tapyrus::RPC::TapyrusCoreClient] The RPC client instance
128
+ # @return [Boolean] true if JWT and decoded object is valid.
129
+ def verify_message(jws, client: nil)
130
+ verify_message!(jws, client: client)
131
+ true
132
+ rescue ArgumentError, JWT::DecodeError, JWT::VerificationError
133
+ return false
134
+ end
135
+
136
+ def validate_header!(header)
137
+ raise ArgumentError, 'type must be "JWT"' if header["typ"] && header["typ"] != "JWT"
138
+ raise ArgumentError, 'alg must be "ES256K"' if header["alg"] && header["alg"] != Tapyrus::JWS::ALGO
139
+ end
140
+
141
+ def validate_payload!(key:, txid:, index:, value:, script_pubkey:, color_id: nil, address: nil, message: nil)
142
+ raise ArgumentError, "txid is invalid" if !txid || !/^[0-9a-fA-F]{64}$/.match(txid)
143
+ raise ArgumentError, "index is invalid" if !index || !/^\d+$/.match(index.to_s) || index < 0 || index >= 2**32
144
+
145
+ raise ArgumentError, "value is invalid" if !value || !/^\d+$/.match(value.to_s) || value < 0 || value >= 2**64
146
+ if !script_pubkey || !script_pubkey.is_a?(Tapyrus::Script) || !(script_pubkey.p2pkh? || script_pubkey.cp2pkh?)
147
+ raise ArgumentError,
148
+ "script_pubkey is invalid. scirpt_pubkey must be a hex string and its type must be p2pkh or cp2pkh"
149
+ end
150
+
151
+ if color_id
152
+ if !color_id.is_a?(Tapyrus::Color::ColorIdentifier) || !color_id.valid?
153
+ raise ArgumentError, "color_id is invalid"
154
+ end
155
+
156
+ raise ArgumentError, "color_id should be equal to colorId in scriptPubkey" if color_id != script_pubkey.color_id
157
+ end
158
+
159
+ begin
160
+ address && Base58.decode(address)
161
+ rescue ArgumentError => e
162
+ raise ArgumentError, "address is invalid"
163
+ end
164
+
165
+ if address && script_pubkey.to_addr != address
166
+ raise ArgumentError, "address is invalid. An address should be derived from scriptPubkey"
167
+ end
168
+
169
+ if (script_pubkey.p2pkh? && key.to_p2pkh != script_pubkey.to_addr) ||
170
+ (script_pubkey.cp2pkh? && key.to_p2pkh != script_pubkey.remove_color.to_addr)
171
+ raise ArgumentError, "key is invalid"
172
+ end
173
+
174
+ if message && !/^([0-9a-fA-F]{2})+$/.match(message)
175
+ raise ArgumentError, "message is invalid. message must be a hex string"
176
+ end
177
+ end
178
+
179
+ def validate_on_blockchain!(client: nil, txid: nil, index: nil, color_id: nil, value: nil, script_pubkey: nil)
180
+ raw_tx = client.getrawtransaction(txid)
181
+ tx = Tapyrus::Tx.parse_from_payload(raw_tx.htb)
182
+ output = tx.outputs[index]
183
+ raise ArgumentError, "output not found in blockchain" unless output
184
+ if color_id != output.color_id
185
+ raise ArgumentError, "color_id of transaction in blockchain is not match to one in the signed message"
186
+ end
187
+ if value != output.value
188
+ raise ArgumentError, "value of transaction in blockchain is not match to one in the signed message"
189
+ end
190
+ if script_pubkey != output.script_pubkey
191
+ raise ArgumentError, "script_pubkey of transaction in blockchain is not match to one in the signed message"
192
+ end
193
+ end
194
+
195
+ def to_tapyrus_key(jwk)
196
+ vefiry_key = JWT::JWK.new(jwk).verify_key
197
+ pubkey = vefiry_key.public_key.to_octet_string(:compressed)
198
+ Tapyrus::Key.new(pubkey: pubkey.bth)
199
+ end
200
+ end
201
+ end
data/lib/tapyrus/tx.rb CHANGED
@@ -29,7 +29,7 @@ module Tapyrus
29
29
  def self.parse_from_payload(payload)
30
30
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
31
31
  tx = new
32
- tx.features = buf.read(4).unpack('V').first
32
+ tx.features = buf.read(4).unpack("V").first
33
33
 
34
34
  in_count = Tapyrus.unpack_var_int_from_io(buf)
35
35
 
@@ -38,7 +38,7 @@ module Tapyrus
38
38
  out_count = Tapyrus.unpack_var_int_from_io(buf)
39
39
  out_count.times { tx.outputs << TxOut.parse_from_payload(buf) }
40
40
 
41
- tx.lock_time = buf.read(4).unpack('V').first
41
+ tx.lock_time = buf.read(4).unpack("V").first
42
42
 
43
43
  tx
44
44
  end
@@ -52,18 +52,18 @@ module Tapyrus
52
52
  end
53
53
 
54
54
  def txid
55
- buf = [features].pack('V')
55
+ buf = [features].pack("V")
56
56
  buf << Tapyrus.pack_var_int(inputs.length) << inputs.map { |i| i.to_payload(use_malfix: true) }.join
57
57
  buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join
58
- buf << [lock_time].pack('V')
58
+ buf << [lock_time].pack("V")
59
59
  Tapyrus.double_sha256(buf).reverse.bth
60
60
  end
61
61
 
62
62
  def to_payload
63
- buf = [features].pack('V')
63
+ buf = [features].pack("V")
64
64
  buf << Tapyrus.pack_var_int(inputs.length) << inputs.map(&:to_payload).join
65
65
  buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join
66
- buf << [lock_time].pack('V')
66
+ buf << [lock_time].pack("V")
67
67
  buf
68
68
  end
69
69
 
@@ -109,9 +109,9 @@ module Tapyrus
109
109
  # @param [Tapyrus::Script] output_script script pubkey or script code. if script pubkey is P2SH, set redeem script to this.
110
110
  # @return [String] sighash
111
111
  def sighash_for_input(input_index, output_script, hash_type: SIGHASH_TYPE[:all])
112
- raise ArgumentError, 'input_index must be specified.' unless input_index
113
- raise ArgumentError, 'does not exist input corresponding to input_index.' if input_index >= inputs.size
114
- raise ArgumentError, 'script_pubkey must be specified.' unless output_script
112
+ raise ArgumentError, "input_index must be specified." unless input_index
113
+ raise ArgumentError, "does not exist input corresponding to input_index." if input_index >= inputs.size
114
+ raise ArgumentError, "script_pubkey must be specified." unless output_script
115
115
  sighash_for_legacy(input_index, output_script, hash_type)
116
116
  end
117
117
 
@@ -167,7 +167,7 @@ module Tapyrus
167
167
 
168
168
  case hash_type & 0x1f
169
169
  when SIGHASH_TYPE[:none]
170
- outs = ''
170
+ outs = ""
171
171
  out_size = Tapyrus.pack_var_int(0)
172
172
  when SIGHASH_TYPE[:single]
173
173
  return "\x01".ljust(32, "\x00") if index >= outputs.size
@@ -179,12 +179,12 @@ module Tapyrus
179
179
  ins = [ins[index]] if hash_type & SIGHASH_TYPE[:anyonecanpay] != 0
180
180
 
181
181
  buf = [
182
- [features].pack('V'),
182
+ [features].pack("V"),
183
183
  Tapyrus.pack_var_int(ins.size),
184
184
  ins,
185
185
  out_size,
186
186
  outs,
187
- [lock_time, hash_type].pack('VV')
187
+ [lock_time, hash_type].pack("VV")
188
188
  ].join
189
189
 
190
190
  Tapyrus.double_sha256(buf)
@@ -85,12 +85,12 @@ module Tapyrus
85
85
  script_pubkey = Tapyrus::Script.parse_from_addr(address)
86
86
 
87
87
  unless color_id.default?
88
- raise ArgumentError, 'invalid address' if !script_pubkey.p2pkh? && !script_pubkey.p2sh?
88
+ raise ArgumentError, "invalid address" if !script_pubkey.p2pkh? && !script_pubkey.p2sh?
89
89
  script_pubkey = script_pubkey.add_color(color_id)
90
90
  end
91
91
 
92
92
  output = Tapyrus::TxOut.new(script_pubkey: script_pubkey, value: value)
93
- raise ArgumentError, 'The transaction amount is too small' if color_id.default? && output.dust?
93
+ raise ArgumentError, "The transaction amount is too small" if color_id.default? && output.dust?
94
94
  @outgoings[color_id] ||= 0
95
95
  @outgoings[color_id] += value
96
96
  @outputs << output
@@ -119,7 +119,7 @@ module Tapyrus
119
119
  # @param address [String] p2pkh or p2sh address.
120
120
  def change_address(address)
121
121
  script_pubkey = Tapyrus::Script.parse_from_addr(address)
122
- raise ArgumentError, 'invalid address' if !script_pubkey.p2pkh? && !script_pubkey.p2sh?
122
+ raise ArgumentError, "invalid address" if !script_pubkey.p2pkh? && !script_pubkey.p2sh?
123
123
  @change_script_pubkey = script_pubkey
124
124
  self
125
125
  end
data/lib/tapyrus/tx_in.rb CHANGED
@@ -30,7 +30,7 @@ module Tapyrus
30
30
  def self.parse_from_payload(payload)
31
31
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
32
32
  i = new
33
- hash, index = buf.read(36).unpack('a32V')
33
+ hash, index = buf.read(36).unpack("a32V")
34
34
  i.out_point = OutPoint.new(hash.bth, index)
35
35
  sig_length = Tapyrus.unpack_var_int_from_io(buf)
36
36
  if sig_length == 0
@@ -38,7 +38,7 @@ module Tapyrus
38
38
  else
39
39
  i.script_sig = Script.parse_from_payload(buf.read(sig_length))
40
40
  end
41
- i.sequence = buf.read(4).unpack('V').first
41
+ i.sequence = buf.read(4).unpack("V").first
42
42
  i
43
43
  end
44
44
 
@@ -52,7 +52,7 @@ module Tapyrus
52
52
  p << Tapyrus.pack_var_int(script_sig.to_payload.bytesize)
53
53
  p << script_sig.to_payload
54
54
  end
55
- p << [sequence].pack('V')
55
+ p << [sequence].pack("V")
56
56
  p
57
57
  end
58
58
 
@@ -17,18 +17,18 @@ module Tapyrus
17
17
 
18
18
  def self.parse_from_payload(payload)
19
19
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
20
- value = buf.read(8).unpack('q').first
20
+ value = buf.read(8).unpack("q").first
21
21
  script_size = Tapyrus.unpack_var_int_from_io(buf)
22
22
  new(value: value, script_pubkey: Script.parse_from_payload(buf.read(script_size)))
23
23
  end
24
24
 
25
25
  def to_payload
26
26
  s = script_pubkey.to_payload
27
- [value].pack('Q') << Tapyrus.pack_var_int(s.length) << s
27
+ [value].pack("Q") << Tapyrus.pack_var_int(s.length) << s
28
28
  end
29
29
 
30
30
  def to_empty_payload
31
- 'ffffffffffffffff00'.htb
31
+ "ffffffffffffffff00".htb
32
32
  end
33
33
 
34
34
  # convert satoshi to btc
data/lib/tapyrus/util.rb CHANGED
@@ -17,13 +17,13 @@ module Tapyrus
17
17
 
18
18
  def pack_var_int(i)
19
19
  if i < 0xfd
20
- [i].pack('C')
20
+ [i].pack("C")
21
21
  elsif i <= 0xffff
22
- [0xfd, i].pack('Cv')
22
+ [0xfd, i].pack("Cv")
23
23
  elsif i <= 0xffffffff
24
- [0xfe, i].pack('CV')
24
+ [0xfe, i].pack("CV")
25
25
  elsif i <= 0xffffffffffffffff
26
- [0xff, i].pack('CQ')
26
+ [0xff, i].pack("CQ")
27
27
  else
28
28
  raise "int(#{i}) too large!"
29
29
  end
@@ -31,39 +31,39 @@ module Tapyrus
31
31
 
32
32
  # @return an integer for a valid payload, otherwise nil
33
33
  def unpack_var_int(payload)
34
- case payload.unpack('C').first
34
+ case payload.unpack("C").first
35
35
  when 0xfd
36
- payload.unpack('xva*')
36
+ payload.unpack("xva*")
37
37
  when 0xfe
38
- payload.unpack('xVa*')
38
+ payload.unpack("xVa*")
39
39
  when 0xff
40
- payload.unpack('xQa*')
40
+ payload.unpack("xQa*")
41
41
  else
42
- payload.unpack('Ca*')
42
+ payload.unpack("Ca*")
43
43
  end
44
44
  end
45
45
 
46
46
  # @return an integer for a valid payload, otherwise nil
47
47
  def unpack_var_int_from_io(buf)
48
- uchar = buf.read(1)&.unpack('C')&.first
48
+ uchar = buf.read(1)&.unpack("C")&.first
49
49
  case uchar
50
50
  when 0xfd
51
- buf.read(2)&.unpack('v')&.first
51
+ buf.read(2)&.unpack("v")&.first
52
52
  when 0xfe
53
- buf.read(4)&.unpack('V')&.first
53
+ buf.read(4)&.unpack("V")&.first
54
54
  when 0xff
55
- buf.read(8)&.unpack('Q')&.first
55
+ buf.read(8)&.unpack("Q")&.first
56
56
  else
57
57
  uchar
58
58
  end
59
59
  end
60
60
 
61
61
  def pack_boolean(b)
62
- b ? [0x01].pack('C') : [0x00].pack('C')
62
+ b ? [0x01].pack("C") : [0x00].pack("C")
63
63
  end
64
64
 
65
65
  def unpack_boolean(payload)
66
- data, payload = payload.unpack('Ca*')
66
+ data, payload = payload.unpack("Ca*")
67
67
  [(data.zero? ? false : true), payload]
68
68
  end
69
69
 
@@ -77,7 +77,7 @@ module Tapyrus
77
77
 
78
78
  # byte convert to the sequence of bits packed eight in a byte with the least significant bit first.
79
79
  def byte_to_bit(byte)
80
- byte.unpack('b*').first
80
+ byte.unpack("b*").first
81
81
  end
82
82
 
83
83
  # padding zero to the left of binary string until bytesize.
@@ -86,7 +86,7 @@ module Tapyrus
86
86
  # @return [String] padded binary string.
87
87
  def padding_zero(binary, bytesize)
88
88
  return binary unless binary.bytesize < bytesize
89
- ('00' * (bytesize - binary.bytesize)).htb + binary
89
+ ("00" * (bytesize - binary.bytesize)).htb + binary
90
90
  end
91
91
 
92
92
  # generate sha256-ripemd160 hash for value
@@ -110,16 +110,16 @@ module Tapyrus
110
110
  hex = Base58.decode(addr)
111
111
  if hex.size == 50 && calc_checksum(hex[0...-8]) == hex[-8..-1]
112
112
  unless [Tapyrus.chain_params.address_version, Tapyrus.chain_params.p2sh_version].include?(hex[0..1])
113
- raise 'Invalid version bytes.'
113
+ raise "Invalid version bytes."
114
114
  end
115
115
  [hex[2...-8], hex[0..1]]
116
116
  elsif hex.size == 116 && calc_checksum(hex[0...-8]) == hex[-8..-1]
117
117
  unless [Tapyrus.chain_params.cp2pkh_version, Tapyrus.chain_params.cp2sh_version].include?(hex[0..1])
118
- raise 'Invalid version bytes.'
118
+ raise "Invalid version bytes."
119
119
  end
120
120
  [hex[2...-8], hex[0..1]]
121
121
  else
122
- raise 'Invalid address.'
122
+ raise "Invalid address."
123
123
  end
124
124
  end
125
125
 
@@ -127,7 +127,7 @@ module Tapyrus
127
127
  double_sha256(hex.htb).bth[0..7]
128
128
  end
129
129
 
130
- DIGEST_NAME_SHA256 = 'sha256'
130
+ DIGEST_NAME_SHA256 = "sha256"
131
131
 
132
132
  def hmac_sha256(key, data)
133
133
  OpenSSL::HMAC.digest(DIGEST_NAME_SHA256, key, data)
@@ -4,42 +4,42 @@ module Tapyrus
4
4
  def check_tx(tx, state)
5
5
  # Basic checks that don't depend on any context
6
6
  if tx.inputs.empty?
7
- return state.DoS(10, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-vin-empty')
7
+ return state.DoS(10, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-vin-empty")
8
8
  end
9
9
 
10
10
  if tx.outputs.empty?
11
- return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-vout-empty')
11
+ return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-vout-empty")
12
12
  end
13
13
 
14
14
  # Check for negative or overflow output values
15
15
  amount = 0
16
16
  tx.outputs.each do |o|
17
17
  if o.value < 0
18
- return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-vout-negative')
18
+ return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-vout-negative")
19
19
  end
20
20
  if MAX_MONEY < o.value
21
- return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-vout-toolarge')
21
+ return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-vout-toolarge")
22
22
  end
23
23
  amount += o.value
24
24
  if MAX_MONEY < amount
25
- return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-vout-toolarge')
25
+ return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-vout-toolarge")
26
26
  end
27
27
  end
28
28
 
29
29
  # Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
30
30
  out_points = tx.inputs.map { |i| i.out_point.to_payload }
31
31
  unless out_points.size == out_points.uniq.size
32
- return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-inputs-duplicate')
32
+ return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-inputs-duplicate")
33
33
  end
34
34
 
35
35
  if tx.coinbase_tx?
36
36
  if tx.inputs[0].out_point.index == 0xffffffff || tx.inputs[0].script_sig.size > 100
37
- return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-cb-length')
37
+ return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-cb-length")
38
38
  end
39
39
  else
40
40
  tx.inputs.each do |i|
41
41
  if i.out_point.nil? || !i.out_point.valid?
42
- return state.DoS(10, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-prevout-null')
42
+ return state.DoS(10, reject_code: Message::Reject::CODE_INVALID, reject_reason: "bad-txns-prevout-null")
43
43
  end
44
44
  end
45
45
  end
@@ -85,7 +85,7 @@ module Tapyrus
85
85
  @corruption_possible = false
86
86
  end
87
87
 
88
- def DoS(level, ret: false, reject_code: 0, reject_reason: '', corruption_in: false, debug_message: '')
88
+ def DoS(level, ret: false, reject_code: 0, reject_reason: "", corruption_in: false, debug_message: "")
89
89
  @reject_code = reject_code
90
90
  @reject_reason = reject_reason
91
91
  @corruption_possible = corruption_in
@@ -1,3 +1,3 @@
1
1
  module Tapyrus
2
- VERSION = '0.3.4'
2
+ VERSION = "0.3.5"
3
3
  end
@@ -15,7 +15,7 @@ module Tapyrus
15
15
  attr_accessor :lookahead
16
16
  attr_accessor :wallet
17
17
 
18
- def initialize(account_key, purpose = PURPOSE_TYPE[:native_segwit], index = 0, name = '')
18
+ def initialize(account_key, purpose = PURPOSE_TYPE[:native_segwit], index = 0, name = "")
19
19
  validate_params!(account_key, purpose, index)
20
20
  @purpose = purpose
21
21
  @index = index
@@ -31,8 +31,8 @@ module Tapyrus
31
31
  account_key = Tapyrus::ExtPubkey.parse_from_payload(buf.read(78))
32
32
  payload = buf.read
33
33
  name, payload = Tapyrus.unpack_var_string(payload)
34
- name = name.force_encoding('utf-8')
35
- purpose, index, receive_depth, change_depth, lookahead = payload.unpack('I*')
34
+ name = name.force_encoding("utf-8")
35
+ purpose, index, receive_depth, change_depth, lookahead = payload.unpack("I*")
36
36
  a = Account.new(account_key, purpose, index, name)
37
37
  a.receive_depth = receive_depth
38
38
  a.change_depth = change_depth
@@ -42,8 +42,8 @@ module Tapyrus
42
42
 
43
43
  def to_payload
44
44
  payload = account_key.to_payload
45
- payload << Tapyrus.pack_var_string(name.unpack('H*').first.htb)
46
- payload << [purpose, index, receive_depth, change_depth, lookahead].pack('I*')
45
+ payload << Tapyrus.pack_var_string(name.unpack("H*").first.htb)
46
+ payload << [purpose, index, receive_depth, change_depth, lookahead].pack("I*")
47
47
  payload
48
48
  end
49
49
 
@@ -98,13 +98,13 @@ module Tapyrus
98
98
  def type
99
99
  case purpose
100
100
  when PURPOSE_TYPE[:legacy]
101
- 'pubkeyhash'
101
+ "pubkeyhash"
102
102
  when PURPOSE_TYPE[:nested_witness]
103
- 'p2wpkh-p2sh'
103
+ "p2wpkh-p2sh"
104
104
  when PURPOSE_TYPE[:native_segwit]
105
- 'p2wpkh'
105
+ "p2wpkh"
106
106
  else
107
- 'unknown'
107
+ "unknown"
108
108
  end
109
109
  end
110
110
 
@@ -146,10 +146,10 @@ module Tapyrus
146
146
  end
147
147
 
148
148
  def validate_params!(account_key, purpose, index)
149
- raise 'account_key must be an instance of Tapyrus::ExtPubkey.' unless account_key.is_a?(Tapyrus::ExtPubkey)
150
- raise 'Account key and index does not match.' unless account_key.number == (index + Tapyrus::HARDENED_THRESHOLD)
149
+ raise "account_key must be an instance of Tapyrus::ExtPubkey." unless account_key.is_a?(Tapyrus::ExtPubkey)
150
+ raise "Account key and index does not match." unless account_key.number == (index + Tapyrus::HARDENED_THRESHOLD)
151
151
  version_bytes = Tapyrus::ExtPubkey.version_from_purpose(purpose + Tapyrus::HARDENED_THRESHOLD)
152
- raise 'The purpose and the account key do not match.' unless account_key.version == version_bytes
152
+ raise "The purpose and the account key do not match." unless account_key.version == version_bytes
153
153
  end
154
154
  end
155
155
  end