bitcoinrb 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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."
|