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 +4 -4
 - data/RELEASE_NOTES.md +6 -0
 - data/lib/btcruby/address.rb +1 -1
 - data/lib/btcruby/keychain.rb +13 -13
 - data/lib/btcruby/mnemonic.rb +1 -1
 - data/lib/btcruby/script/script.rb +17 -9
 - data/lib/btcruby/script/script_interpreter.rb +19 -19
 - data/lib/btcruby/script/script_version.rb +54 -0
 - data/lib/btcruby/script/versioned_script.rb +64 -0
 - data/lib/btcruby/secp256k1.rb +5 -3
 - data/lib/btcruby/transaction_builder.rb +10 -5
 - data/lib/btcruby/transaction_builder/errors.rb +6 -1
 - data/lib/btcruby/version.rb +1 -1
 - data/spec/currency_formatter_spec.rb +0 -2
 - data/spec/keychain_spec.rb +5 -0
 - data/spec/script_number_spec.rb +4 -0
 - data/spec/secp256k1_spec.rb +13 -1
 - data/spec/transaction_builder_spec.rb +12 -0
 - metadata +4 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: ffee95a66b5f287235a52944ff6f92e3335b22df
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 550a1d62ecea9b95a15294f3b65477566c9baa90
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 517e12449e58e4866826c6f28230f854bc26b04e788f9d7d3bd864dd15aeb60ccc948da70a4c2d69bfdeef84bd1475f5ac5d78aee599ea67ba52674a30703cb0
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e175176b5a85c1eb40e17134179bf29acc04b2077228c26089b308321d17f94e29960a4f66f0c216e124c108173e40f353125b2e596cef0117687f82098b31bb
         
     | 
    
        data/RELEASE_NOTES.md
    CHANGED
    
    
    
        data/lib/btcruby/address.rb
    CHANGED
    
    
    
        data/lib/btcruby/keychain.rb
    CHANGED
    
    | 
         @@ -24,7 +24,7 @@ module BTC 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                PUBLIC_MAINNET_VERSION  = 0x0488B21E # xpub
         
     | 
| 
       26 
26 
     | 
    
         
             
                PRIVATE_MAINNET_VERSION = 0x0488ADE4 # xprv
         
     | 
| 
       27 
     | 
    
         
            -
                 
     | 
| 
      
 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 :  
     | 
| 
      
 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  
     | 
| 
      
 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 ==  
     | 
| 
      
 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 ==  
     | 
| 
      
 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
         
     | 
    
        data/lib/btcruby/mnemonic.rb
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # BTC::Mnemonic implements  
     | 
| 
      
 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  
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
      
 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  
     | 
| 
      
 347 
     | 
    
         
            +
                    return Script.new << Script.simulated_signature(hashtype: SIGHASH_ALL) << Script.simulated_uncompressed_pubkey
         
     | 
| 
       340 
348 
     | 
    
         | 
| 
       341 
349 
     | 
    
         
             
                  elsif public_key_script?
         
     | 
| 
       342 
     | 
    
         
            -
                    return  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
      
 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 =  
     | 
| 
      
 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: 
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
    
        data/lib/btcruby/secp256k1.rb
    CHANGED
    
    | 
         @@ -10,8 +10,10 @@ module BTC 
     | 
|
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                ffi_lib 'secp256k1'
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                 
     | 
| 
       14 
     | 
    
         
            -
                 
     | 
| 
      
 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,  
     | 
| 
      
 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 
     | 
| 
      
 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
         
     | 
    
        data/lib/btcruby/version.rb
    CHANGED
    
    
| 
         @@ -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
         
     | 
    
        data/spec/keychain_spec.rb
    CHANGED
    
    | 
         @@ -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
         
     | 
    
        data/spec/script_number_spec.rb
    CHANGED
    
    | 
         @@ -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
         
     | 
    
        data/spec/secp256k1_spec.rb
    CHANGED
    
    | 
         @@ -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. 
     | 
| 
      
 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:  
     | 
| 
      
 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
         
     |