bitcoinrb 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.ruby-version +1 -1
 - data/.travis.yml +1 -0
 - data/LICENSE.txt +1 -1
 - data/README.md +2 -0
 - data/lib/bitcoin.rb +4 -0
 - data/lib/bitcoin/bit_stream.rb +71 -0
 - data/lib/bitcoin/block_filter.rb +83 -0
 - data/lib/bitcoin/gcs_filter.rb +135 -0
 - data/lib/bitcoin/rpc/request_handler.rb +2 -2
 - data/lib/bitcoin/script/script.rb +7 -2
 - data/lib/bitcoin/version.rb +1 -1
 - data/lib/bitcoin/wallet/base.rb +13 -8
 - metadata +6 -4
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 895222030c0d0673f1524e112cf42d8cbb8e248558ba356e156a92b7482d4344
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: cca9f6a8777925fcf39c47a835549b1894554e2d3c67400ba330487731677a89
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: cbb089fdfa71ac6a9c60591789c18b78af3fac81e6ba82ac264a50cd1d464b814f8989ca62fdde78910640e241f2b7e8c516b20b9e67eb979efae86c43b9b0ab
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: bf0b6f27f6e4819569f3d814194b202f18d829bf315591ce8fa75db0846b2ef372ca45294537918ff7d161b37947f91be05562200d7028bc39b598ec83f01b26
         
     | 
    
        data/.ruby-version
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            2. 
     | 
| 
      
 1 
     | 
    
         
            +
            2.6.0
         
     | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/LICENSE.txt
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            The MIT License (MIT)
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            Copyright (c) 2017- 
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2017-2019 HAW International, Inc. / chaintope, Inc.
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
       6 
6 
     | 
    
         
             
            of this software and associated documentation files (the "Software"), to deal
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -13,7 +13,9 @@ Bitcoinrb supports following feature: 
     | 
|
| 
       13 
13 
     | 
    
         
             
            * De/serialization of Bitcoin protocol network messages
         
     | 
| 
       14 
14 
     | 
    
         
             
            * De/serialization of blocks and transactions
         
     | 
| 
       15 
15 
     | 
    
         
             
            * Key generation and verification for ECDSA, including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports.
         
     | 
| 
      
 16 
     | 
    
         
            +
            * ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
         
     | 
| 
       16 
17 
     | 
    
         
             
            * Segwit support (parsing segwit payload, Bech32 address, sign for segwit tx, etc..)
         
     | 
| 
      
 18 
     | 
    
         
            +
            * PSBT(Partially Signed Bitcoin Transaction) support
         
     | 
| 
       17 
19 
     | 
    
         
             
            * [WIP] SPV node
         
     | 
| 
       18 
20 
     | 
    
         
             
            * [WIP] 0ff-chain protocol
         
     | 
| 
       19 
21 
     | 
    
         | 
    
        data/lib/bitcoin.rb
    CHANGED
    
    | 
         @@ -47,6 +47,10 @@ module Bitcoin 
     | 
|
| 
       47 
47 
     | 
    
         
             
              autoload :BloomFilter, 'bitcoin/bloom_filter'
         
     | 
| 
       48 
48 
     | 
    
         
             
              autoload :Payments, 'bitcoin/payments'
         
     | 
| 
       49 
49 
     | 
    
         
             
              autoload :PSBT, 'bitcoin/psbt'
         
     | 
| 
      
 50 
     | 
    
         
            +
              autoload :GCSFilter, 'bitcoin/gcs_filter'
         
     | 
| 
      
 51 
     | 
    
         
            +
              autoload :BlockFilter, 'bitcoin/block_filter'
         
     | 
| 
      
 52 
     | 
    
         
            +
              autoload :BitStreamWriter, 'bitcoin/bit_stream'
         
     | 
| 
      
 53 
     | 
    
         
            +
              autoload :BitStreamReader, 'bitcoin/bit_stream'
         
     | 
| 
       50 
54 
     | 
    
         | 
| 
       51 
55 
     | 
    
         
             
              require_relative 'bitcoin/constants'
         
     | 
| 
       52 
56 
     | 
    
         | 
| 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Bitcoin
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              class BitStreamWriter
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                MAX_BIT = 2**64
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :stream
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :buffer
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_accessor :offset
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @stream = ''
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @buffer = 0
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @offset = 0
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def write(data, nbits)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  raise "nbits must be between 0 and 64" if nbits < 0 || nbits > 64
         
     | 
| 
      
 19 
     | 
    
         
            +
                  while nbits > 0
         
     | 
| 
      
 20 
     | 
    
         
            +
                    bits = [8 - offset, nbits].min
         
     | 
| 
      
 21 
     | 
    
         
            +
                    tmp = (data << (64 - nbits)) & 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
         
     | 
| 
      
 22 
     | 
    
         
            +
                    self.buffer |= (tmp >> (64 - 8 + offset))
         
     | 
| 
      
 23 
     | 
    
         
            +
                    self.offset += bits
         
     | 
| 
      
 24 
     | 
    
         
            +
                    nbits -= bits
         
     | 
| 
      
 25 
     | 
    
         
            +
                    flush if offset == 8
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def flush
         
     | 
| 
      
 30 
     | 
    
         
            +
                  return if offset == 0
         
     | 
| 
      
 31 
     | 
    
         
            +
                  self.stream << [buffer.to_even_length_hex].pack('H*')
         
     | 
| 
      
 32 
     | 
    
         
            +
                  self.offset = 0
         
     | 
| 
      
 33 
     | 
    
         
            +
                  self.buffer = 0
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              class BitStreamReader
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                attr_reader :stream
         
     | 
| 
      
 41 
     | 
    
         
            +
                attr_accessor :buffer
         
     | 
| 
      
 42 
     | 
    
         
            +
                attr_accessor :offset
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def initialize(payload)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @offset = 8
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @buffer = 0
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @stream = StringIO.new(payload)
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                # offset
         
     | 
| 
      
 51 
     | 
    
         
            +
                def read(nbits)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  raise 'nbits must be between 0 and 64' if nbits < 0 || nbits > 64
         
     | 
| 
      
 53 
     | 
    
         
            +
                  data = 0
         
     | 
| 
      
 54 
     | 
    
         
            +
                  while nbits > 0
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if offset == 8
         
     | 
| 
      
 56 
     | 
    
         
            +
                      self.buffer = stream.read(1).bth.to_i(16)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      self.offset = 0
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
                    bits = [8 - offset, nbits].min
         
     | 
| 
      
 60 
     | 
    
         
            +
                    data <<= bits
         
     | 
| 
      
 61 
     | 
    
         
            +
                    tmp = (buffer << offset) & 255
         
     | 
| 
      
 62 
     | 
    
         
            +
                    data = data | (tmp >> (8 - bits))
         
     | 
| 
      
 63 
     | 
    
         
            +
                    self.offset += bits
         
     | 
| 
      
 64 
     | 
    
         
            +
                    nbits -= bits
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                  data
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,83 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Bitcoin
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # Compact Block Filter
         
     | 
| 
      
 4 
     | 
    
         
            +
              # https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki
         
     | 
| 
      
 5 
     | 
    
         
            +
              # This implementation ported the implementation of Bitcoin Core's blockfilter.cpp.
         
     | 
| 
      
 6 
     | 
    
         
            +
              # https://github.com/bitcoin/bitcoin/blob/master/src/blockfilter.cpp
         
     | 
| 
      
 7 
     | 
    
         
            +
              class BlockFilter
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                TYPE = {basic: 0}
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # basic filter params
         
     | 
| 
      
 12 
     | 
    
         
            +
                BASIC_FILTER_P = 19
         
     | 
| 
      
 13 
     | 
    
         
            +
                BASIC_FILTER_M = 784931
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                attr_accessor :filter_type
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_accessor :filter
         
     | 
| 
      
 17 
     | 
    
         
            +
                attr_accessor :block_hash
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                # Constructor
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @param [Integer] filter_type
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @param [Bitcoin::GCSFilter] filter a GCS filter.
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @param [String] block_hash a block hash with hex format.
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @return [Bitcoin::BlockFilter]
         
     | 
| 
      
 24 
     | 
    
         
            +
                def initialize(filter_type, filter, block_hash)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @filter_type = filter_type
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @filter = filter
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @block_hash = block_hash
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                # Build BlockFilter from the block data.
         
     | 
| 
      
 31 
     | 
    
         
            +
                # @param [Integer] filter_type a filter type(basic or extended).
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @param [Bitcoin::Block] block target block object.
         
     | 
| 
      
 33 
     | 
    
         
            +
                # @param [Array[Bitcoin::Script]] prev_out_scripts The previous output script (the script being spent) for each input, except for the coinbase transaction.
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @return [Bitcoin::BlockFilter] block filter object.
         
     | 
| 
      
 35 
     | 
    
         
            +
                def self.build_from_block(filter_type, block, prev_out_scripts)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  block_hash = block.block_hash.htb[0...16]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  filter = case filter_type
         
     | 
| 
      
 38 
     | 
    
         
            +
                           when TYPE[:basic]
         
     | 
| 
      
 39 
     | 
    
         
            +
                             GCSFilter.new(block_hash, BASIC_FILTER_P, BASIC_FILTER_M, elements: build_basic_filter_elements(block, prev_out_scripts))
         
     | 
| 
      
 40 
     | 
    
         
            +
                           else
         
     | 
| 
      
 41 
     | 
    
         
            +
                             raise "unknown filter type: #{filter_type}."
         
     | 
| 
      
 42 
     | 
    
         
            +
                           end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  BlockFilter.new(filter_type, filter, block.block_hash)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # calculate filter hash.
         
     | 
| 
      
 48 
     | 
    
         
            +
                # @return [String] this filter hash with hex format.
         
     | 
| 
      
 49 
     | 
    
         
            +
                def filter_hash
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Bitcoin.double_sha256(encoded_filter.htb).bth
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # calculate filter header which calculates from previous filter header and current filter hash.
         
     | 
| 
      
 54 
     | 
    
         
            +
                # @param [String] prev_header a previous header with hex format.
         
     | 
| 
      
 55 
     | 
    
         
            +
                # @return [String] header of this filter with hex format.
         
     | 
| 
      
 56 
     | 
    
         
            +
                def header(prev_header)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  Bitcoin.double_sha256(filter_hash.htb + prev_header.htb).bth
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                # get encoded filter.
         
     | 
| 
      
 61 
     | 
    
         
            +
                def encoded_filter
         
     | 
| 
      
 62 
     | 
    
         
            +
                  filter.encoded
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                # build basic filter elements
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @param [Bitcoin::Block] block current block
         
     | 
| 
      
 67 
     | 
    
         
            +
                # @param [Array[Bitcoin::Script]] prev_out_scripts The previous output script (the script being spent) for each input, except for the coinbase transaction.
         
     | 
| 
      
 68 
     | 
    
         
            +
                # @return [Array[String]] basic filter elements
         
     | 
| 
      
 69 
     | 
    
         
            +
                def self.build_basic_filter_elements(block, prev_out_scripts)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  elements = []
         
     | 
| 
      
 71 
     | 
    
         
            +
                  block.transactions.each do |tx|
         
     | 
| 
      
 72 
     | 
    
         
            +
                    elements += tx.outputs.select{|o|
         
     | 
| 
      
 73 
     | 
    
         
            +
                      !o.script_pubkey.empty? && !o.script_pubkey.op_return?}.map{|o| o.script_pubkey.to_payload}
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  elements += prev_out_scripts.select{|s|!s.empty? && !s.op_return?}.map(&:to_payload)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  elements.uniq
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                private_class_method :build_basic_filter_elements
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,135 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'siphash'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Bitcoin
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # Golomb-coded set filter
         
     | 
| 
      
 6 
     | 
    
         
            +
              # see https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki
         
     | 
| 
      
 7 
     | 
    
         
            +
              class GCSFilter
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :p # Golomb-Rice coding parameter
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_reader :m # Inverse false positive rate
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :n # Number of elements in the filter
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_reader :key # SipHash key
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :encoded # encoded filter with hex format.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # initialize Filter object.
         
     | 
| 
      
 16 
     | 
    
         
            +
                # @param [String] key the 128-bit key used to randomize the SipHash outputs.
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @param [Integer] p the bit parameter of the Golomb-Rice coding.
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @param [Integer] m which determines the false positive rate.
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @param [Array] elements the filter elements.
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @param [String] encoded_filter encoded filter with hex format.
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @return [Bitcoin::GCSFilter]
         
     | 
| 
      
 22 
     | 
    
         
            +
                def initialize(key, p, m, elements: nil, encoded_filter: nil)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  raise 'specify either elements or encoded_filter.' if elements.nil? && encoded_filter.nil?
         
     | 
| 
      
 24 
     | 
    
         
            +
                  raise 'p must be <= 32' if p > 32
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @key = key
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @p = p
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @m = m
         
     | 
| 
      
 28 
     | 
    
         
            +
                  if elements
         
     | 
| 
      
 29 
     | 
    
         
            +
                    raise 'elements size must be < 2**32.' if elements.size >= (2**32)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @n = elements.size
         
     | 
| 
      
 31 
     | 
    
         
            +
                    encoded = Bitcoin.pack_var_int(@n)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    bit_writer = Bitcoin::BitStreamWriter.new
         
     | 
| 
      
 33 
     | 
    
         
            +
                    unless elements.empty?
         
     | 
| 
      
 34 
     | 
    
         
            +
                      last_value = 0
         
     | 
| 
      
 35 
     | 
    
         
            +
                      hashed_set = elements.map{|e| hash_to_range(e) }.sort
         
     | 
| 
      
 36 
     | 
    
         
            +
                      hashed_set.each do |v|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        delta = v - last_value
         
     | 
| 
      
 38 
     | 
    
         
            +
                        golomb_rice_encode(bit_writer, p, delta)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        last_value = v
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    bit_writer.flush
         
     | 
| 
      
 43 
     | 
    
         
            +
                    encoded << bit_writer.stream
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @encoded = encoded.bth
         
     | 
| 
      
 45 
     | 
    
         
            +
                  else
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @encoded = encoded_filter
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @n, payload = Bitcoin.unpack_var_int(encoded_filter.htb)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                # Range of element hashes, F = N * M
         
     | 
| 
      
 52 
     | 
    
         
            +
                def f
         
     | 
| 
      
 53 
     | 
    
         
            +
                  n * m
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                # Hash a data element to an integer in the range [0, F).
         
     | 
| 
      
 57 
     | 
    
         
            +
                # @param [String] element with binary format.
         
     | 
| 
      
 58 
     | 
    
         
            +
                # @return [Integer]
         
     | 
| 
      
 59 
     | 
    
         
            +
                def hash_to_range(element)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  hash = SipHash.digest(key, element)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  map_into_range(hash, f)
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                # Checks if the element may be in the set. False positives are possible with probability 1/M.
         
     | 
| 
      
 65 
     | 
    
         
            +
                # @param [String] element with binary format
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @return [Boolean] whether element in set.
         
     | 
| 
      
 67 
     | 
    
         
            +
                def match?(element)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  query = hash_to_range(element)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  match_internal?([query], 1)
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                # Checks if any of the given elements may be in the set. False positives are possible with probability 1/M per element checked.
         
     | 
| 
      
 73 
     | 
    
         
            +
                # This is more efficient that checking Match on multiple elements separately.
         
     | 
| 
      
 74 
     | 
    
         
            +
                # @param [Array] elements list of elements with binary format.
         
     | 
| 
      
 75 
     | 
    
         
            +
                # @return [Boolean] whether element in set.
         
     | 
| 
      
 76 
     | 
    
         
            +
                def match_any?(elements)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  queries = elements.map{|e| hash_to_range(e) }.sort
         
     | 
| 
      
 78 
     | 
    
         
            +
                  match_internal?(queries, queries.size)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                private
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                # hash are then mapped uniformly over the desired range by multiplying with F and taking the top 64 bits of the 128-bit result.
         
     | 
| 
      
 84 
     | 
    
         
            +
                # https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
         
     | 
| 
      
 85 
     | 
    
         
            +
                # https://stackoverflow.com/a/26855440
         
     | 
| 
      
 86 
     | 
    
         
            +
                def map_into_range(x, y)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  (x * y) >> 64
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                # Checks if the elements may be in the set.
         
     | 
| 
      
 91 
     | 
    
         
            +
                # @param [Array[Integer]] hashes the query hash list.
         
     | 
| 
      
 92 
     | 
    
         
            +
                # @param [Integer] size query size.
         
     | 
| 
      
 93 
     | 
    
         
            +
                # @return [Boolean] whether elements in set.
         
     | 
| 
      
 94 
     | 
    
         
            +
                def match_internal?(hashes, size)
         
     | 
| 
      
 95 
     | 
    
         
            +
                  n, payload = Bitcoin.unpack_var_int(encoded.htb)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  bit_reader = Bitcoin::BitStreamReader.new(payload)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  value = 0
         
     | 
| 
      
 98 
     | 
    
         
            +
                  hashes_index = 0
         
     | 
| 
      
 99 
     | 
    
         
            +
                  n.times do
         
     | 
| 
      
 100 
     | 
    
         
            +
                    delta = golomb_rice_decode(bit_reader, p)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    value += delta
         
     | 
| 
      
 102 
     | 
    
         
            +
                    loop do
         
     | 
| 
      
 103 
     | 
    
         
            +
                      return false if hashes_index == size
         
     | 
| 
      
 104 
     | 
    
         
            +
                      return true if hashes[hashes_index] == value
         
     | 
| 
      
 105 
     | 
    
         
            +
                      break if hashes[hashes_index] > value
         
     | 
| 
      
 106 
     | 
    
         
            +
                      hashes_index += 1
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                  false
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                # encode golomb rice
         
     | 
| 
      
 113 
     | 
    
         
            +
                def golomb_rice_encode(bit_writer, p, x)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  q = x >> p
         
     | 
| 
      
 115 
     | 
    
         
            +
                  while q > 0
         
     | 
| 
      
 116 
     | 
    
         
            +
                    nbits = q <= 64 ? q : 64
         
     | 
| 
      
 117 
     | 
    
         
            +
                    bit_writer.write(-1, nbits) # 18446744073709551615 is 2**64 - 1 = ~0ULL in cpp.
         
     | 
| 
      
 118 
     | 
    
         
            +
                    q -= nbits
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  bit_writer.write(0, 1)
         
     | 
| 
      
 121 
     | 
    
         
            +
                  bit_writer.write(x, p)
         
     | 
| 
      
 122 
     | 
    
         
            +
                end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                # decode golomb rice
         
     | 
| 
      
 125 
     | 
    
         
            +
                def golomb_rice_decode(bit_reader, p)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  q = 0
         
     | 
| 
      
 127 
     | 
    
         
            +
                  while bit_reader.read(1) == 1
         
     | 
| 
      
 128 
     | 
    
         
            +
                    q +=1
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  r = bit_reader.read(p)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  (q << p) + r
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
              end
         
     | 
| 
      
 135 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -105,14 +105,14 @@ module Bitcoin 
     | 
|
| 
       105 
105 
     | 
    
         
             
                  # wallet api
         
     | 
| 
       106 
106 
     | 
    
         | 
| 
       107 
107 
     | 
    
         
             
                  # create wallet
         
     | 
| 
       108 
     | 
    
         
            -
                  def createwallet(wallet_id = 1, wallet_path_prefix = Bitcoin::Wallet::Base 
     | 
| 
      
 108 
     | 
    
         
            +
                  def createwallet(wallet_id = 1, wallet_path_prefix = Bitcoin::Wallet::Base.default_path_prefix)
         
     | 
| 
       109 
109 
     | 
    
         
             
                    wallet = Bitcoin::Wallet::Base.create(wallet_id, wallet_path_prefix)
         
     | 
| 
       110 
110 
     | 
    
         
             
                    node.wallet = wallet unless node.wallet
         
     | 
| 
       111 
111 
     | 
    
         
             
                    {wallet_id: wallet.wallet_id, mnemonic: wallet.master_key.mnemonic}
         
     | 
| 
       112 
112 
     | 
    
         
             
                  end
         
     | 
| 
       113 
113 
     | 
    
         | 
| 
       114 
114 
     | 
    
         
             
                  # get wallet list.
         
     | 
| 
       115 
     | 
    
         
            -
                  def listwallets(wallet_path_prefix = Bitcoin::Wallet::Base 
     | 
| 
      
 115 
     | 
    
         
            +
                  def listwallets(wallet_path_prefix = Bitcoin::Wallet::Base.default_path_prefix)
         
     | 
| 
       116 
116 
     | 
    
         
             
                    Bitcoin::Wallet::Base.wallet_paths(wallet_path_prefix)
         
     | 
| 
       117 
117 
     | 
    
         
             
                  end
         
     | 
| 
       118 
118 
     | 
    
         | 
| 
         @@ -130,7 +130,11 @@ module Bitcoin 
     | 
|
| 
       130 
130 
     | 
    
         
             
                        end
         
     | 
| 
       131 
131 
     | 
    
         
             
                      end
         
     | 
| 
       132 
132 
     | 
    
         
             
                    else
         
     | 
| 
       133 
     | 
    
         
            -
                       
     | 
| 
      
 133 
     | 
    
         
            +
                      if Opcodes.defined?(opcode.ord)
         
     | 
| 
      
 134 
     | 
    
         
            +
                        s << opcode.ord
         
     | 
| 
      
 135 
     | 
    
         
            +
                      else
         
     | 
| 
      
 136 
     | 
    
         
            +
                        s.chunks << (opcode + buf.read) # If opcode is invalid, put all remaining data in last chunk.
         
     | 
| 
      
 137 
     | 
    
         
            +
                      end
         
     | 
| 
       134 
138 
     | 
    
         
             
                    end
         
     | 
| 
       135 
139 
     | 
    
         
             
                  end
         
     | 
| 
       136 
140 
     | 
    
         
             
                  s
         
     | 
| 
         @@ -331,7 +335,8 @@ module Bitcoin 
     | 
|
| 
       331 
335 
     | 
    
         
             
                          end
         
     | 
| 
       332 
336 
     | 
    
         
             
                        end
         
     | 
| 
       333 
337 
     | 
    
         
             
                      else
         
     | 
| 
       334 
     | 
    
         
            -
                        Opcodes.opcode_to_name(c.ord)
         
     | 
| 
      
 338 
     | 
    
         
            +
                        opcode = Opcodes.opcode_to_name(c.ord)
         
     | 
| 
      
 339 
     | 
    
         
            +
                        opcode ? opcode : 'OP_UNKNOWN [error]'
         
     | 
| 
       335 
340 
     | 
    
         
             
                      end
         
     | 
| 
       336 
341 
     | 
    
         
             
                    end
         
     | 
| 
       337 
342 
     | 
    
         
             
                  }.join(' ')
         
     | 
    
        data/lib/bitcoin/version.rb
    CHANGED
    
    
    
        data/lib/bitcoin/wallet/base.rb
    CHANGED
    
    | 
         @@ -8,15 +8,19 @@ module Bitcoin 
     | 
|
| 
       8 
8 
     | 
    
         
             
                  attr_reader :db
         
     | 
| 
       9 
9 
     | 
    
         
             
                  attr_reader :path
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                  DEFAULT_PATH_PREFIX = "#{Bitcoin.base_dir}/db/wallet/"
         
     | 
| 
       12 
11 
     | 
    
         
             
                  VERSION = 1
         
     | 
| 
       13 
12 
     | 
    
         | 
| 
      
 13 
     | 
    
         
            +
                  # get wallet dir path
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def self.default_path_prefix
         
     | 
| 
      
 15 
     | 
    
         
            +
                    "#{Bitcoin.base_dir}/db/wallet/"
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       14 
18 
     | 
    
         
             
                  # Create new wallet. If wallet already exist, throw error.
         
     | 
| 
       15 
19 
     | 
    
         
             
                  # The wallet generates a seed using SecureRandom and store to db at initialization.
         
     | 
| 
       16 
20 
     | 
    
         
             
                  # @param [String] wallet_id new wallet id.
         
     | 
| 
       17 
21 
     | 
    
         
             
                  # @param [String] path_prefix wallet file path prefix.
         
     | 
| 
       18 
22 
     | 
    
         
             
                  # @return [Bitcoin::Wallet::Base] the wallet
         
     | 
| 
       19 
     | 
    
         
            -
                  def self.create(wallet_id = 1, path_prefix =  
     | 
| 
      
 23 
     | 
    
         
            +
                  def self.create(wallet_id = 1, path_prefix = default_path_prefix)
         
     | 
| 
       20 
24 
     | 
    
         
             
                    raise ArgumentError, "wallet_id : #{wallet_id} already exist." if self.exist?(wallet_id, path_prefix)
         
     | 
| 
       21 
25 
     | 
    
         
             
                    w = self.new(wallet_id, path_prefix)
         
     | 
| 
       22 
26 
     | 
    
         
             
                    # generate seed
         
     | 
| 
         @@ -29,23 +33,24 @@ module Bitcoin 
     | 
|
| 
       29 
33 
     | 
    
         | 
| 
       30 
34 
     | 
    
         
             
                  # load wallet with specified +wallet_id+
         
     | 
| 
       31 
35 
     | 
    
         
             
                  # @return [Bitcoin::Wallet::Base] the wallet
         
     | 
| 
       32 
     | 
    
         
            -
                  def self.load(wallet_id, path_prefix =  
     | 
| 
      
 36 
     | 
    
         
            +
                  def self.load(wallet_id, path_prefix = default_path_prefix)
         
     | 
| 
       33 
37 
     | 
    
         
             
                    raise ArgumentError, "wallet_id : #{wallet_id} dose not exist." unless self.exist?(wallet_id, path_prefix)
         
     | 
| 
       34 
38 
     | 
    
         
             
                    self.new(wallet_id, path_prefix)
         
     | 
| 
       35 
39 
     | 
    
         
             
                  end
         
     | 
| 
       36 
40 
     | 
    
         | 
| 
       37 
41 
     | 
    
         
             
                  # get wallets path
         
     | 
| 
       38 
42 
     | 
    
         
             
                  # @return [Array] Array of paths for each wallet dir.
         
     | 
| 
       39 
     | 
    
         
            -
                  def self.wallet_paths(path_prefix =  
     | 
| 
      
 43 
     | 
    
         
            +
                  def self.wallet_paths(path_prefix = default_path_prefix)
         
     | 
| 
       40 
44 
     | 
    
         
             
                    Dir.glob("#{path_prefix}wallet*/").sort
         
     | 
| 
       41 
45 
     | 
    
         
             
                  end
         
     | 
| 
       42 
46 
     | 
    
         | 
| 
       43 
47 
     | 
    
         
             
                  # get current wallet
         
     | 
| 
       44 
     | 
    
         
            -
                  def self.current_wallet(path_prefix =  
     | 
| 
       45 
     | 
    
         
            -
                    path = wallet_paths.first # TODO default wallet selection
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def self.current_wallet(path_prefix = default_path_prefix)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    path = wallet_paths(path_prefix).first # TODO default wallet selection
         
     | 
| 
       46 
50 
     | 
    
         
             
                    return nil unless path
         
     | 
| 
       47 
     | 
    
         
            -
                     
     | 
| 
       48 
     | 
    
         
            -
                     
     | 
| 
      
 51 
     | 
    
         
            +
                    path.slice!(path_prefix + 'wallet')
         
     | 
| 
      
 52 
     | 
    
         
            +
                    path.slice!('/')
         
     | 
| 
      
 53 
     | 
    
         
            +
                    self.load(path.to_i, path_prefix)
         
     | 
| 
       49 
54 
     | 
    
         
             
                  end
         
     | 
| 
       50 
55 
     | 
    
         | 
| 
       51 
56 
     | 
    
         
             
                  # get account list based on BIP-44
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: bitcoinrb
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.2. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.5
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - azuchi
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2019-01-14 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: ecdsa
         
     | 
| 
         @@ -303,7 +303,9 @@ files: 
     | 
|
| 
       303 
303 
     | 
    
         
             
            - exe/bitcoinrbd
         
     | 
| 
       304 
304 
     | 
    
         
             
            - lib/bitcoin.rb
         
     | 
| 
       305 
305 
     | 
    
         
             
            - lib/bitcoin/base58.rb
         
     | 
| 
      
 306 
     | 
    
         
            +
            - lib/bitcoin/bit_stream.rb
         
     | 
| 
       306 
307 
     | 
    
         
             
            - lib/bitcoin/block.rb
         
     | 
| 
      
 308 
     | 
    
         
            +
            - lib/bitcoin/block_filter.rb
         
     | 
| 
       307 
309 
     | 
    
         
             
            - lib/bitcoin/block_header.rb
         
     | 
| 
       308 
310 
     | 
    
         
             
            - lib/bitcoin/bloom_filter.rb
         
     | 
| 
       309 
311 
     | 
    
         
             
            - lib/bitcoin/chain_params.rb
         
     | 
| 
         @@ -312,6 +314,7 @@ files: 
     | 
|
| 
       312 
314 
     | 
    
         
             
            - lib/bitcoin/chainparams/testnet.yml
         
     | 
| 
       313 
315 
     | 
    
         
             
            - lib/bitcoin/constants.rb
         
     | 
| 
       314 
316 
     | 
    
         
             
            - lib/bitcoin/ext_key.rb
         
     | 
| 
      
 317 
     | 
    
         
            +
            - lib/bitcoin/gcs_filter.rb
         
     | 
| 
       315 
318 
     | 
    
         
             
            - lib/bitcoin/key.rb
         
     | 
| 
       316 
319 
     | 
    
         
             
            - lib/bitcoin/logger.rb
         
     | 
| 
       317 
320 
     | 
    
         
             
            - lib/bitcoin/merkle_tree.rb
         
     | 
| 
         @@ -436,8 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       436 
439 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       437 
440 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       438 
441 
     | 
    
         
             
            requirements: []
         
     | 
| 
       439 
     | 
    
         
            -
             
     | 
| 
       440 
     | 
    
         
            -
            rubygems_version: 2.7.8
         
     | 
| 
      
 442 
     | 
    
         
            +
            rubygems_version: 3.0.1
         
     | 
| 
       441 
443 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       442 
444 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       443 
445 
     | 
    
         
             
            summary: "[WIP]The implementation of Bitcoin Protocol for Ruby."
         
     |