btcruby 1.6 → 1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 217d2c55943bb88f2a02a77774574a82f345845f
4
- data.tar.gz: 9e74dfbf5e332e4fbda8cca3c3d6f1dd8962ac1a
3
+ metadata.gz: ffee95a66b5f287235a52944ff6f92e3335b22df
4
+ data.tar.gz: 550a1d62ecea9b95a15294f3b65477566c9baa90
5
5
  SHA512:
6
- metadata.gz: 509d5068a72d3e04ea612a92348bc7edd9929aed0acc87e55dc10866c24294e6d2f84fb26d0d54f2c18ab19ff09cd6cc0bc267735cb6694be6fbd5e3d757dda0
7
- data.tar.gz: 39b60fbdd30baf9ffaa08005d07ac2d767c3f85a8e0c5761380e369ebeae96092bcf9d7d7f1406f4c5a30f63ef3694e1598980efacada1e23e9484aff6c2a40a
6
+ metadata.gz: 517e12449e58e4866826c6f28230f854bc26b04e788f9d7d3bd864dd15aeb60ccc948da70a4c2d69bfdeef84bd1475f5ac5d78aee599ea67ba52674a30703cb0
7
+ data.tar.gz: e175176b5a85c1eb40e17134179bf29acc04b2077228c26089b308321d17f94e29960a4f66f0c216e124c108173e40f353125b2e596cef0117687f82098b31bb
@@ -2,6 +2,12 @@
2
2
  BTCRuby Release Notes
3
3
  =====================
4
4
 
5
+ 1.7 (September 28, 2017)
6
+ -------------------------
7
+
8
+ * Various bugfixes
9
+ * WIP on API for the versioned scripts
10
+
5
11
  1.6 (January 15, 2015)
6
12
  -------------------------
7
13
 
@@ -21,7 +21,7 @@
21
21
  #
22
22
  # address = BTC::PublicKeyAddress.new(hash: hash)
23
23
  #
24
- # 3. To convert address to its Base68Check format call to_s:
24
+ # 3. To convert address to its Base58Check format call to_s:
25
25
  #
26
26
  # string = address.to_s
27
27
  #
@@ -24,7 +24,7 @@ module BTC
24
24
 
25
25
  PUBLIC_MAINNET_VERSION = 0x0488B21E # xpub
26
26
  PRIVATE_MAINNET_VERSION = 0x0488ADE4 # xprv
27
- PUBLIC_TESNET_VERSION = 0x043587CF # tpub
27
+ PUBLIC_TESTNET_VERSION = 0x043587CF # tpub
28
28
  PRIVATE_TESTNET_VERSION = 0x04358394 # tprv
29
29
 
30
30
  # Instance of BTC::Key that is a "head" of this keychain.
@@ -107,9 +107,9 @@ module BTC
107
107
 
108
108
  def key
109
109
  @key ||= if @private_key
110
- BTC::Key.new(private_key: @private_key, public_key_compressed: true)
110
+ BTC::Key.new(private_key: @private_key, public_key_compressed: true, network: @network)
111
111
  else
112
- BTC::Key.new(public_key: @public_key)
112
+ BTC::Key.new(public_key: @public_key, network: @network)
113
113
  end
114
114
  end
115
115
 
@@ -127,7 +127,7 @@ module BTC
127
127
 
128
128
  def extended_public_key
129
129
  @extended_public_key ||= begin
130
- prefix = _extended_key_prefix(mainnet? ? PUBLIC_MAINNET_VERSION : PUBLIC_TESNET_VERSION)
130
+ prefix = _extended_key_prefix(mainnet? ? PUBLIC_MAINNET_VERSION : PUBLIC_TESTNET_VERSION)
131
131
  BTC::Base58.base58check_from_data(prefix + @public_key)
132
132
  end
133
133
  end
@@ -205,7 +205,7 @@ module BTC
205
205
  elsif _components
206
206
  init_with_components(*_components)
207
207
  else
208
- raise ArgumentError, "Either seed or an extended " if !private_key && !public_key
208
+ raise ArgumentError, "Either seed or an extended key must be provided"
209
209
  end
210
210
  end
211
211
 
@@ -251,13 +251,13 @@ module BTC
251
251
  @network = Network.testnet
252
252
  end
253
253
 
254
- elsif version == PUBLIC_MAINNET_VERSION || version == PUBLIC_TESNET_VERSION
254
+ elsif version == PUBLIC_MAINNET_VERSION || version == PUBLIC_TESTNET_VERSION
255
255
  # Should have a 33-byte public key with non-zero first byte.
256
256
  if keyprefix == 0x00
257
257
  raise BTCError, "Extended public key must have non-zero first byte (received #{keyprefix})"
258
258
  end
259
259
  @public_key = xkeydata[45, 33]
260
- if version == PUBLIC_TESNET_VERSION
260
+ if version == PUBLIC_TESTNET_VERSION
261
261
  @network = Network.testnet
262
262
  end
263
263
  else
@@ -452,25 +452,25 @@ module BTC
452
452
  end
453
453
  end
454
454
  end
455
-
455
+
456
456
  # BIP44 Support
457
-
457
+
458
458
  def bip44_keychain(network: Network.mainnet)
459
459
  network_index = network.mainnet? ? 0 : 1
460
460
  derived_keychain(44, hardened: true).derived_keychain(network_index, hardened: true)
461
461
  end
462
-
462
+
463
463
  def bip44_account_keychain(account_index)
464
464
  derived_keychain(account_index, hardened: true)
465
465
  end
466
-
466
+
467
467
  def bip44_external_keychain
468
468
  derived_keychain(0, hardened: false)
469
469
  end
470
-
470
+
471
471
  def bip44_internal_keychain
472
472
  derived_keychain(1, hardened: false)
473
473
  end
474
-
474
+
475
475
  end # Keychain
476
476
  end # BTC
@@ -1,4 +1,4 @@
1
- # BTC::Mnemonic implements BIP44: mnemonic-based hierarchical deterministic wallets.
1
+ # BTC::Mnemonic implements BIP39: mnemonic-based hierarchical deterministic wallets.
2
2
  # Currently only supports restoring keychain from words. Generating sentence.
3
3
  require 'openssl'
4
4
  require 'openssl/digest'
@@ -89,6 +89,14 @@ module BTC
89
89
  public_key_script? ||
90
90
  standard_op_return_script?
91
91
  end
92
+
93
+ # Returns true if this is an output script wrapped in a versioned pushdata for segwit softfork.
94
+ def versioned_script?
95
+ return chunks.size == 1 &&
96
+ chunks[0].pushdata? &&
97
+ chunks[0].canonical? &&
98
+ chunks[0].pushdata.bytesize > 2
99
+ end
92
100
 
93
101
  # Returns true if the script is a pay-to-pubkey script:
94
102
  # "<pubkey> OP_CHECKSIG"
@@ -248,7 +256,7 @@ module BTC
248
256
  # and a new script instance is returned.
249
257
  def without_dropped_prefix_data
250
258
  if dropped_prefix_data
251
- return self.class.new << @chunks[2..-1]
259
+ return Script.new << @chunks[2..-1]
252
260
  end
253
261
  self
254
262
  end
@@ -288,7 +296,7 @@ module BTC
288
296
 
289
297
  # Complete copy of a script.
290
298
  def dup
291
- self.class.new(data: self.data)
299
+ Script.new(data: self.data)
292
300
  end
293
301
 
294
302
  def ==(other)
@@ -324,7 +332,7 @@ module BTC
324
332
  # Wraps the recipient into an output P2SH script
325
333
  # (OP_HASH160 <20-byte hash of the recipient> OP_EQUAL).
326
334
  def p2sh_script
327
- self.class.new << OP_HASH160 << BTC.hash160(self.data) << OP_EQUAL
335
+ Script.new << OP_HASH160 << BTC.hash160(self.data) << OP_EQUAL
328
336
  end
329
337
 
330
338
 
@@ -336,18 +344,18 @@ module BTC
336
344
  def simulated_signature_script(strict: true)
337
345
  if public_key_hash_script?
338
346
  # assuming non-compressed pubkeys to be conservative
339
- return self.class.new << Script.simulated_signature(hashtype: SIGHASH_ALL) << Script.simulated_uncompressed_pubkey
347
+ return Script.new << Script.simulated_signature(hashtype: SIGHASH_ALL) << Script.simulated_uncompressed_pubkey
340
348
 
341
349
  elsif public_key_script?
342
- return self.class.new << Script.simulated_signature(hashtype: SIGHASH_ALL)
350
+ return Script.new << Script.simulated_signature(hashtype: SIGHASH_ALL)
343
351
 
344
352
  elsif script_hash_script? && !strict
345
353
  # This is a wild approximation, but works well if most p2sh scripts are 2-of-3 multisig scripts.
346
354
  # If you have a very particular smart contract scheme you should not use TransactionBuilder which estimates fees this way.
347
- return self.class.new << OP_0 << [Script.simulated_signature(hashtype: SIGHASH_ALL)]*2 << Script.simulated_multisig_script(2,3).data
355
+ return Script.new << OP_0 << [Script.simulated_signature(hashtype: SIGHASH_ALL)]*2 << Script.simulated_multisig_script(2,3).data
348
356
 
349
357
  elsif multisig_script?
350
- return self.class.new << OP_0 << [Script.simulated_signature(hashtype: SIGHASH_ALL)]*self.multisig_signatures_required
358
+ return Script.new << OP_0 << [Script.simulated_signature(hashtype: SIGHASH_ALL)]*self.multisig_signatures_required
351
359
  else
352
360
  return nil
353
361
  end
@@ -463,7 +471,7 @@ module BTC
463
471
 
464
472
  # Same arguments as with Array#[].
465
473
  def subscript(*args)
466
- self.class.new << chunks[*args]
474
+ Script.new << chunks[*args]
467
475
  end
468
476
  alias_method :[], :subscript
469
477
 
@@ -478,7 +486,7 @@ module BTC
478
486
  subscriptsize = subscript.chunks.size
479
487
  buf = []
480
488
  i = 0
481
- result = self.class.new
489
+ result = Script.new
482
490
  chunks.each do |chunk|
483
491
  if chunk == subscript.chunks[i]
484
492
  buf << chunk
@@ -36,7 +36,7 @@ module BTC
36
36
  # (required if the scripts use signature-checking opcodes).
37
37
  # Checker can be transaction checker or block checker
38
38
  def initialize(flags: SCRIPT_VERIFY_NONE,
39
- extensions: nil,
39
+ extensions: nil,
40
40
  signature_checker: nil,
41
41
  raise_on_failure: false,
42
42
  max_pushdata_size: MAX_SCRIPT_ELEMENT_SIZE,
@@ -144,8 +144,8 @@ module BTC
144
144
  @altstack = []
145
145
  @run_script_chunks = script.chunks.to_a.dup # can be modified by `insert_script`
146
146
 
147
- number_zero = ScriptNumber.new(integer: 0)
148
- number_one = ScriptNumber.new(integer: 1)
147
+ number_zero = BTC::ScriptNumber.new(integer: 0)
148
+ number_one = BTC::ScriptNumber.new(integer: 1)
149
149
  zero_value = "".b
150
150
  false_value = "".b
151
151
  true_value = "\x01".b
@@ -216,7 +216,7 @@ module BTC
216
216
  case opcode
217
217
  when OP_1NEGATE, OP_1..OP_16
218
218
  # ( -- value)
219
- num = ScriptNumber.new(integer: opcode - (OP_1 - 1))
219
+ num = BTC::ScriptNumber.new(integer: opcode - (OP_1 - 1))
220
220
  stack_push(num.data)
221
221
  # The result of these opcodes should always be the minimal way to push the data
222
222
  # they push, so no need for a CheckMinimalPush here.
@@ -408,7 +408,7 @@ module BTC
408
408
 
409
409
  when OP_DEPTH
410
410
  # -- stacksize
411
- sn = ScriptNumber.new(integer: @stack.size)
411
+ sn = BTC::ScriptNumber.new(integer: @stack.size)
412
412
  stack_push(sn.data)
413
413
 
414
414
  when OP_DROP
@@ -489,7 +489,7 @@ module BTC
489
489
  if @stack.size < 1
490
490
  return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION)
491
491
  end
492
- sn = ScriptNumber.new(integer: @stack.last.size)
492
+ sn = BTC::ScriptNumber.new(integer: @stack.last.size)
493
493
  stack_push(sn.data)
494
494
 
495
495
 
@@ -548,9 +548,9 @@ module BTC
548
548
  when OP_ABS
549
549
  bn = -bn if bn < 0
550
550
  when OP_NOT
551
- bn = ScriptNumber.new(boolean: (bn == 0))
551
+ bn = BTC::ScriptNumber.new(boolean: (bn == 0))
552
552
  when OP_0NOTEQUAL
553
- bn = ScriptNumber.new(boolean: (bn != 0))
553
+ bn = BTC::ScriptNumber.new(boolean: (bn != 0))
554
554
  else
555
555
  raise "invalid opcode"
556
556
  end
@@ -566,7 +566,7 @@ module BTC
566
566
 
567
567
  bn1 = cast_to_number(@stack[-2])
568
568
  bn2 = cast_to_number(@stack[-1])
569
- bn = ScriptNumber.new(integer: 0)
569
+ bn = BTC::ScriptNumber.new(integer: 0)
570
570
 
571
571
  case opcode
572
572
  when OP_ADD
@@ -574,21 +574,21 @@ module BTC
574
574
  when OP_SUB
575
575
  bn = bn1 - bn2
576
576
  when OP_BOOLAND
577
- bn = ScriptNumber.new(boolean: ((bn1 != 0) && (bn2 != 0)))
577
+ bn = BTC::ScriptNumber.new(boolean: ((bn1 != 0) && (bn2 != 0)))
578
578
  when OP_BOOLOR
579
- bn = ScriptNumber.new(boolean: ((bn1 != 0) || (bn2 != 0)))
579
+ bn = BTC::ScriptNumber.new(boolean: ((bn1 != 0) || (bn2 != 0)))
580
580
  when OP_NUMEQUAL, OP_NUMEQUALVERIFY
581
- bn = ScriptNumber.new(boolean: (bn1 == bn2))
581
+ bn = BTC::ScriptNumber.new(boolean: (bn1 == bn2))
582
582
  when OP_NUMNOTEQUAL
583
- bn = ScriptNumber.new(boolean: (bn1 != bn2))
583
+ bn = BTC::ScriptNumber.new(boolean: (bn1 != bn2))
584
584
  when OP_LESSTHAN
585
- bn = ScriptNumber.new(boolean: (bn1 < bn2))
585
+ bn = BTC::ScriptNumber.new(boolean: (bn1 < bn2))
586
586
  when OP_GREATERTHAN
587
- bn = ScriptNumber.new(boolean: (bn1 > bn2))
587
+ bn = BTC::ScriptNumber.new(boolean: (bn1 > bn2))
588
588
  when OP_LESSTHANOREQUAL
589
- bn = ScriptNumber.new(boolean: (bn1 <= bn2))
589
+ bn = BTC::ScriptNumber.new(boolean: (bn1 <= bn2))
590
590
  when OP_GREATERTHANOREQUAL
591
- bn = ScriptNumber.new(boolean: (bn1 >= bn2))
591
+ bn = BTC::ScriptNumber.new(boolean: (bn1 >= bn2))
592
592
  when OP_MIN
593
593
  bn = (bn1 < bn2 ? bn1 : bn2)
594
594
  when OP_MAX
@@ -815,7 +815,7 @@ module BTC
815
815
  end
816
816
 
817
817
  return true
818
- rescue ScriptNumberError => e
818
+ rescue BTC::ScriptNumberError => e
819
819
  return set_error(SCRIPT_ERR_UNKNOWN_ERROR, e.message)
820
820
  end # run_script
821
821
 
@@ -914,7 +914,7 @@ module BTC
914
914
  def cast_to_number(data,
915
915
  require_minimal: flag?(SCRIPT_VERIFY_MINIMALDATA),
916
916
  max_size: @integer_max_size)
917
- ScriptNumber.new(data: data, require_minimal: require_minimal, max_size: max_size)
917
+ BTC::ScriptNumber.new(data: data, require_minimal: require_minimal, max_size: max_size)
918
918
  end
919
919
 
920
920
  def cast_to_bool(data)
@@ -0,0 +1,54 @@
1
+ module BTC
2
+ class ScriptVersion
3
+ VERSION_DEFAULT = 0
4
+ VERSION_P2SH = 1
5
+
6
+ attr_reader :version # binary string containing the version
7
+ attr_reader :sighash_version
8
+
9
+ def initialize(version)
10
+ @version = version
11
+ end
12
+
13
+ # Returns a matching signature hash version for the given script version.
14
+ # All currently known script versions use sighash version 1.
15
+ def sighash_version
16
+ return 1
17
+ end
18
+
19
+ # Returns true if version is known.
20
+ # Unknown versions are supported too, but scripts are not even parsed and interpreted as "anyone can spend".
21
+ def known?
22
+ default? ||
23
+ p2sh?
24
+ end
25
+
26
+ def default?
27
+ @version == VERSION_DEFAULT
28
+ end
29
+
30
+ def p2sh?
31
+ @version == VERSION_P2SH
32
+ end
33
+
34
+ def name
35
+ case version
36
+ when VERSION_DEFAULT
37
+ "Default script"
38
+ when VERSION_P2SH
39
+ "P2SH v1"
40
+ else
41
+ "Unknown script version"
42
+ end
43
+ end
44
+
45
+ def to_i
46
+ @version
47
+ end
48
+
49
+ def to_s
50
+ "v#{@version} (#{name})"
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,64 @@
1
+ module BTC
2
+ # Versioned script is a wrapper around a regular script with a version prefix.
3
+ # Note that we support version of any length, but do not parse and interpret unknown versions.
4
+ class VersionedScript
5
+
6
+ attr_reader :version # Integer
7
+ attr_reader :data # Raw data representing script wrapped in VersionedScript. For 256-bit P2SH it's just a hash, not a script.
8
+ attr_reader :wrapper_script # BTC::Script that wraps version + data
9
+ attr_reader :script_version # BTC::ScriptVersion
10
+ attr_reader :inner_script # BTC::Script derived from data, if it makes sense for the given version.
11
+
12
+ # Initializers:
13
+ # - `VersionedScript.new(wrapper_script:)` that wraps the version and inner script data.
14
+ # - `VersionedScript.new(version:, data:)` where version is one of ScriptVersion::VERSION_* and data is a raw inner script data (hash for p2sh256).
15
+ # - `VersionedScript.new(p2sh_redeem_script:)` creates a versioned script with p2sh hash of the redeem script.
16
+ def initialize(wrapper_script: nil,
17
+ version: nil, data: nil,
18
+ script: nil,
19
+ p2sh_redeem_script: nil,
20
+ )
21
+ if wrapper_script
22
+ if !wrapper_script.versioned_script?
23
+ raise ArgumentError, "Script is not a canonical versioned script with minimal pushdata encoding"
24
+ end
25
+ @wrapper_script = wrapper_script
26
+ fulldata = BTC::Data.ensure_binary_encoding(wrapper_script.chunks.first.pushdata)
27
+ @version = fulldata.bytes[0]
28
+ @data = fulldata[1..-1]
29
+ elsif script
30
+ @version = ScriptVersion::VERSION_DEFAULT
31
+ @data = script.data
32
+ elsif p2sh_redeem_script
33
+ @version = ScriptVersion::VERSION_P2SH256
34
+ @data = BTC.hash256(p2sh_redeem_script.data)
35
+ else
36
+ @version = version or raise ArgumentError, "Version is missing"
37
+ @data = data
38
+ end
39
+ end
40
+
41
+ def wrapper_script
42
+ @wrapper_script ||= BTC::Script.new << (@version.chr.b + @data)
43
+ end
44
+
45
+ # Returns inner BTC::Script if it's a default script
46
+ def inner_script
47
+ if script_version.default?
48
+ BTC::Script.new(data: data)
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
54
+ def script_version
55
+ @script_version ||= ScriptVersion.new(@version)
56
+ end
57
+
58
+ def known_version?
59
+ script_version.known?
60
+ end
61
+
62
+ end
63
+ end
64
+
@@ -10,8 +10,10 @@ module BTC
10
10
 
11
11
  ffi_lib 'secp256k1'
12
12
 
13
- SECP256K1_CONTEXT_VERIFY = (1 << 0)
14
- SECP256K1_CONTEXT_SIGN = (1 << 1)
13
+ SECP256K1_FLAGS_TYPE_CONTEXT = (1 << 0)
14
+ SECP256K1_FLAGS_BIT_CONTEXT_VERIFY = (1 << 8)
15
+ SECP256K1_FLAGS_BIT_CONTEXT_SIGN = (1 << 9)
16
+ SECP256K1_CONTEXT_SIGN = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
15
17
 
16
18
  # Note: this struct is opaque, but public. Its size will eventually be guaranteed.
17
19
  # See https://github.com/bitcoin/secp256k1/issues/288
@@ -42,7 +44,7 @@ module BTC
42
44
  privkey_buf = FFI::MemoryPointer.new(:uchar, privkey.bytesize)
43
45
  privkey_buf.put_bytes(0, privkey)
44
46
 
45
- if secp256k1_ecdsa_sign(ctx, hash_buf, sig.pointer, privkey_buf, nil, nil) == 1
47
+ if secp256k1_ecdsa_sign(ctx, sig.pointer, hash_buf, privkey_buf, nil, nil) == 1
46
48
  # Serialize an ECDSA signature in DER format.
47
49
  bufsize = 72
48
50
  output_pointer = FFI::MemoryPointer.new(:uint8, bufsize)
@@ -60,6 +60,10 @@ module BTC
60
60
  # Default is Transaction::DEFAULT_FEE_RATE
61
61
  attr_accessor :fee_rate
62
62
 
63
+ # Miner's fee for this transaction.
64
+ # If `fee` is not nil, fee_rate is ignored and transaction uses the specified fee.
65
+ attr_accessor :fee
66
+
63
67
  # Minimum amount of change below which transaction is not composed.
64
68
  # If change amount is non-zero and below this value, more unspent outputs are used.
65
69
  # If change amount is zero, change output is not even created and this attribute is not used.
@@ -92,10 +96,10 @@ module BTC
92
96
  # A total size of all outputs in bytes (including change output).
93
97
  attr_reader :outputs_size
94
98
 
95
-
96
99
  # Implementation of the attributes declared above
97
100
  # ===============================================
98
101
 
102
+
99
103
  def network
100
104
  @network ||= Network.default
101
105
  end
@@ -223,7 +227,7 @@ module BTC
223
227
 
224
228
  # Check if inputs cover the fees
225
229
  if result.outputs_amount < 0
226
- raise InsufficientFundsError
230
+ raise InsufficientFundsError.new(result)
227
231
  end
228
232
 
229
233
  # Warn if the output amount is relatively small.
@@ -282,7 +286,7 @@ module BTC
282
286
 
283
287
  while true
284
288
  if (sorted_utxos.size + mandatory_utxos.size) == 0
285
- raise InsufficientFundsError
289
+ raise InsufficientFundsError.new(result)
286
290
  end
287
291
 
288
292
  utxo = nil
@@ -361,7 +365,7 @@ module BTC
361
365
  else
362
366
  # Change is negative, we need more funds for this transaction.
363
367
  # Try adding more utxos on the next cycle.
364
-
368
+ result.fee = fee
365
369
  end
366
370
 
367
371
  end # if inputs_amount >= outputs_amount
@@ -374,6 +378,8 @@ module BTC
374
378
  # Helper to compute total fee for a given transaction.
375
379
  # Simulates signatures to estimate final size.
376
380
  def compute_fee_for_transaction(tx, fee_rate)
381
+ # Return mining fee if set manually
382
+ return fee if fee
377
383
  # Compute fees for this tx by composing a tx with properly sized dummy signatures.
378
384
  simulated_tx = tx.dup
379
385
  simulated_tx.inputs.each do |txin|
@@ -518,4 +524,3 @@ if $0 == __FILE__
518
524
 
519
525
 
520
526
  end
521
-
@@ -10,6 +10,11 @@ module BTC
10
10
  class MissingUnspentOutputsError < Error; end
11
11
 
12
12
  # Unspent outputs are not sufficient to build the transaction.
13
- class InsufficientFundsError < Error; end
13
+ class InsufficientFundsError < Error
14
+ attr_accessor :result
15
+ def initialize(result = nil)
16
+ @result = result
17
+ end
18
+ end
14
19
  end
15
20
  end
@@ -1,3 +1,3 @@
1
1
  module BTC
2
- VERSION = "1.6".freeze
2
+ VERSION = "1.7".freeze
3
3
  end
@@ -14,7 +14,6 @@ describe BTC::CurrencyFormatter do
14
14
  fm.string_from_number(42000*BTC::COIN + BTC::COIN/2).must_equal("42000.5")
15
15
 
16
16
  fm.number_from_string("1").must_equal 1*BTC::COIN
17
- fm.number_from_string("1.").must_equal 1*BTC::COIN
18
17
  fm.number_from_string("1.0").must_equal 1*BTC::COIN
19
18
  fm.number_from_string("42").must_equal 42*BTC::COIN
20
19
  fm.number_from_string("42.123").must_equal 42*BTC::COIN + 12300000
@@ -35,7 +34,6 @@ describe BTC::CurrencyFormatter do
35
34
  fm.string_from_number(42000*BTC::COIN + BTC::COIN/2).must_equal("42000.50000000")
36
35
 
37
36
  fm.number_from_string("1").must_equal 1*BTC::COIN
38
- fm.number_from_string("1.").must_equal 1*BTC::COIN
39
37
  fm.number_from_string("1.0").must_equal 1*BTC::COIN
40
38
  fm.number_from_string("42").must_equal 42*BTC::COIN
41
39
  fm.number_from_string("42.123").must_equal 42*BTC::COIN + 12300000
@@ -258,4 +258,9 @@ describe BTC::Keychain do
258
258
  m0pub.extended_public_key.must_equal "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"
259
259
  m0pub.extended_private_key.must_equal nil
260
260
  end
261
+ it "should raise the ArgumentError when arguments are not passed" do
262
+ assert_raises ArgumentError do
263
+ BTC::Keychain.new
264
+ end
265
+ end
261
266
  end
@@ -22,6 +22,10 @@ describe BTC::ScriptNumber do
22
22
  BTC::ScriptNumber.new(data: "\x01").to_i.must_equal 1
23
23
  end
24
24
 
25
+ it "should parse 0x27 as 39" do
26
+ BTC::ScriptNumber.new(data: "\x27").to_i.must_equal 39
27
+ end
28
+
25
29
  it "should parse 0xff as -127" do
26
30
  BTC::ScriptNumber.new(data: "\xff").to_i.must_equal -127
27
31
  end
@@ -9,22 +9,34 @@ describe BTC::Secp256k1 do
9
9
  sig.to_hex.must_equal sighex
10
10
  end
11
11
 
12
- it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979" do
12
+ it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979 01" do
13
13
  verify_rfc6979_signature("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50",
14
14
  "sample",
15
15
  "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124")
16
+ end
17
+
18
+ it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979 02" do
16
19
  verify_rfc6979_signature("0000000000000000000000000000000000000000000000000000000000000001",
17
20
  "Satoshi Nakamoto",
18
21
  "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5")
22
+ end
23
+
24
+ it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979 03" do
19
25
  verify_rfc6979_signature("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
20
26
  "Satoshi Nakamoto",
21
27
  "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5")
28
+ end
29
+ it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979 04" do
22
30
  verify_rfc6979_signature("f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181",
23
31
  "Alan Turing",
24
32
  "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea")
33
+ end
34
+ it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979 05" do
25
35
  verify_rfc6979_signature("0000000000000000000000000000000000000000000000000000000000000001",
26
36
  "All those moments will be lost in time, like tears in rain. Time to die...",
27
37
  "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21")
38
+ end
39
+ it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979 06" do
28
40
  verify_rfc6979_signature("e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2",
29
41
  "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!",
30
42
  "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6")
@@ -68,6 +68,12 @@ describe BTC::TransactionBuilder do
68
68
  result.fee.must_be :<, 0.01 * BTC::COIN
69
69
  end
70
70
 
71
+ it "should be able to set mining fee" do
72
+ @builder.fee =50690
73
+ result = @builder.build()
74
+ result.fee.must_equal 50690
75
+ end
76
+
71
77
  it "should have valid amounts" do
72
78
  result = @builder.build
73
79
  result.inputs_amount.must_equal mock_utxos.inject(0){|sum, out| sum + out.value}
@@ -190,6 +196,12 @@ describe BTC::TransactionBuilder do
190
196
  result.fee.must_be :<, 0.01 * BTC::COIN
191
197
  end
192
198
 
199
+ it "should be able to set mining fee" do
200
+ @builder.fee =50690
201
+ result = @builder.build()
202
+ result.fee.must_equal 50690
203
+ end
204
+
193
205
  it "should have valid amounts" do
194
206
  result = @builder.build
195
207
  result.inputs_amount.must_equal 11*1000_00
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: btcruby
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.6'
4
+ version: '1.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Andreev
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-01-15 00:00:00.000000000 Z
12
+ date: 2017-09-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
@@ -115,10 +115,12 @@ files:
115
115
  - lib/btcruby/script/script_interpreter.rb
116
116
  - lib/btcruby/script/script_interpreter_extension.rb
117
117
  - lib/btcruby/script/script_number.rb
118
+ - lib/btcruby/script/script_version.rb
118
119
  - lib/btcruby/script/signature_checker.rb
119
120
  - lib/btcruby/script/signature_hashtype.rb
120
121
  - lib/btcruby/script/test_signature_checker.rb
121
122
  - lib/btcruby/script/transaction_signature_checker.rb
123
+ - lib/btcruby/script/versioned_script.rb
122
124
  - lib/btcruby/secp256k1.rb
123
125
  - lib/btcruby/ssss.rb
124
126
  - lib/btcruby/transaction.rb