bitcoinrb 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +1 -0
  4. data/README.md +40 -1
  5. data/bitcoinrb.gemspec +1 -0
  6. data/lib/bitcoin/base58.rb +2 -4
  7. data/lib/bitcoin/bloom_filter.rb +71 -0
  8. data/lib/bitcoin/chain_params.rb +8 -0
  9. data/lib/bitcoin/constants.rb +8 -1
  10. data/lib/bitcoin/ext_key.rb +0 -4
  11. data/lib/bitcoin/key.rb +31 -7
  12. data/lib/bitcoin/message/block_transaction_request.rb +45 -0
  13. data/lib/bitcoin/message/block_transactions.rb +31 -0
  14. data/lib/bitcoin/message/block_txn.rb +27 -0
  15. data/lib/bitcoin/message/cmpct_block.rb +42 -0
  16. data/lib/bitcoin/message/get_block_txn.rb +27 -0
  17. data/lib/bitcoin/message/header_and_short_ids.rb +57 -0
  18. data/lib/bitcoin/message/prefilled_tx.rb +29 -0
  19. data/lib/bitcoin/message/send_cmpct.rb +1 -1
  20. data/lib/bitcoin/message/version.rb +1 -1
  21. data/lib/bitcoin/message.rb +7 -0
  22. data/lib/bitcoin/network/message_handler.rb +7 -1
  23. data/lib/bitcoin/network/peer.rb +26 -4
  24. data/lib/bitcoin/network/pool.rb +17 -1
  25. data/lib/bitcoin/node/cli.rb +5 -0
  26. data/lib/bitcoin/node/configuration.rb +1 -0
  27. data/lib/bitcoin/node/spv.rb +21 -1
  28. data/lib/bitcoin/rpc/request_handler.rb +6 -0
  29. data/lib/bitcoin/script/script.rb +4 -1
  30. data/lib/bitcoin/script/script_interpreter.rb +5 -18
  31. data/lib/bitcoin/secp256k1/native.rb +9 -3
  32. data/lib/bitcoin/secp256k1/ruby.rb +51 -23
  33. data/lib/bitcoin/secp256k1.rb +2 -0
  34. data/lib/bitcoin/store/chain_entry.rb +1 -2
  35. data/lib/bitcoin/store/db/level_db.rb +2 -3
  36. data/lib/bitcoin/store/spv_chain.rb +1 -1
  37. data/lib/bitcoin/tx.rb +8 -4
  38. data/lib/bitcoin/tx_in.rb +3 -0
  39. data/lib/bitcoin/tx_out.rb +3 -0
  40. data/lib/bitcoin/util.rb +3 -0
  41. data/lib/bitcoin/version.rb +1 -1
  42. data/lib/bitcoin/wallet/account.rb +3 -3
  43. data/lib/bitcoin/wallet/base.rb +15 -1
  44. data/lib/bitcoin/wallet/db.rb +9 -2
  45. data/lib/bitcoin.rb +23 -3
  46. metadata +25 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3af358507bac7836acb65b028e77391acc664890
4
- data.tar.gz: a9bcb5f19f17b9a2ecd1e5c0a43b3aa29c0329ec
2
+ SHA256:
3
+ metadata.gz: 99f5168564a4d436b4a3a43ce30fc4cf0657f4feb0f96cfa57362de3a322846b
4
+ data.tar.gz: 0bf7749a29bfcebb5006a5a01f47dabeb766d98269476dfa75f2d524af6d6da2
5
5
  SHA512:
6
- metadata.gz: 32e8a8c8d0a1a80ec3ffcfa373f41a5d0987d83da9616a568acb5f9982bcc25a91b406f2163242e6e45d43c0f956e47913d4a280c821cc7f724da7836192b235
7
- data.tar.gz: b476e81be5caff178b14161f0873d770c91795d59b0e0b518fcc68b8f138b525c023002b3ab3846e5ae24a9b46d61eff3ff0a32fb1b37aea4386c08ade25296e
6
+ metadata.gz: c23353ea258a891d79fff2f91a0e8661f389dc6045ca0199955dfe3fb91cdb01be5dc857553c7073633c7f34f0603991f6761403f787aea9bf306586124ccea4
7
+ data.tar.gz: '0597bdd738e1ffc9b8189ec1aaf05245b2cc988bd4ce3a92ad35bf8182cfb3864b59209c7a4894cf0c6d10d5fabaf3a9f2e0da10c7afa25f595969274ca3f5e1'
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4.1
1
+ 2.5.0
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.3.0
4
4
  - 2.4.1
5
+ - 2.5.0
5
6
  addons:
6
7
  apt:
7
8
  packages:
data/README.md CHANGED
@@ -50,7 +50,46 @@ Or install it yourself as:
50
50
 
51
51
  ## Usage
52
52
 
53
- TODO: Write usage instructions here
53
+ ### Chain selection
54
+
55
+ The parameters of the blockchain are managed by `Bitcoin::ChainParams`. Switch chain parameters as follows:
56
+
57
+ * mainnet
58
+
59
+ ```ruby
60
+ Bitcoin.chain_params = :mainnet
61
+ ```
62
+
63
+ This parameter is described in https://github.com/haw-itn/bitcoinrb/blob/master/lib/bitcoin/chainparams/mainnet.yml.
64
+
65
+ * testnet
66
+
67
+ ```ruby
68
+ Bitcoin.chain_params = :testnet
69
+ ```
70
+
71
+ This parameter is described in https://github.com/haw-itn/bitcoinrb/blob/master/lib/bitcoin/chainparams/testnet.yml.
72
+
73
+ * regtest
74
+
75
+ ```ruby
76
+ Bitcoin.chain_params = :regtest
77
+ ```
78
+
79
+ This parameter is described in https://github.com/haw-itn/bitcoinrb/blob/master/lib/bitcoin/chainparams/regtest.yml.
80
+
81
+ #### Fork coin
82
+
83
+ When using with fork coin, please specify the fork_id of the coin as follows.
84
+
85
+ ```ruby
86
+ Bitcoin.chain_params.fork_id = 0 # 0 is bch fork id
87
+ ```
88
+
89
+ Currently bitcoinrb supports only support and verification of transaction replay protection using `SIGHASH_FORK_ID`.
90
+ For details of `SIGHASH_FORK_ID`, refer to the following.
91
+
92
+ https://github.com/Bitcoin-UAHF/spec/blob/master/replay-protected-sighash.md
54
93
 
55
94
  ## Contributing
56
95
 
data/bitcoinrb.gemspec CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_runtime_dependency 'eventmachine_httpserver'
33
33
  spec.add_runtime_dependency 'rest-client'
34
34
  spec.add_runtime_dependency 'iniparse'
35
+ spec.add_runtime_dependency 'siphash'
35
36
 
36
37
  spec.add_development_dependency 'bundler', '~> 1.11'
37
38
  spec.add_development_dependency 'rake', '~> 10.0'
@@ -3,7 +3,6 @@ module Bitcoin
3
3
  # Base58Check encoding
4
4
  # https://en.bitcoin.it/wiki/Base58Check_encoding
5
5
  module Base58
6
-
7
6
  module_function
8
7
 
9
8
  ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
@@ -28,8 +27,7 @@ module Bitcoin
28
27
  raise ArgumentError, 'Value passed not a valid Base58 String.' if (char_index = ALPHABET.index(char)).nil?
29
28
  int_val += char_index * (SIZE**index)
30
29
  end
31
- s = int_val.to_s(16)
32
- s = (s.bytesize.odd? ? '0' + s : s)
30
+ s = int_val.to_even_length_hex
33
31
  s = '' if s == '00'
34
32
  leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : '').size
35
33
  s = ('00' * leading_zero_bytes) + s if leading_zero_bytes > 0
@@ -37,4 +35,4 @@ module Bitcoin
37
35
  end
38
36
 
39
37
  end
40
- end
38
+ end
@@ -0,0 +1,71 @@
1
+ require "murmurhash3"
2
+ module Bitcoin
3
+ class BloomFilter
4
+ LN2_SQUARED = 0.4804530139182014246671025263266649717305529515945455 # log(2) ** 2
5
+ LN2 = 0.6931471805599453094172321214581765680755001343602552 # log(2)
6
+
7
+ MAX_BLOOM_FILTER_SIZE = 36_000 # bytes
8
+ MAX_HASH_FUNCS = 50
9
+
10
+ attr_reader :hash_funcs, :tweak
11
+
12
+ # @param [Integer] elements_length the number of elements
13
+ # @param [Float] fp_rate the false positive rate chosen by the client
14
+ # @param [Integer] tweak A random value to add to the seed value in the hash function used by the bloom filter
15
+ def initialize(elements_length, fp_rate, tweak=0)
16
+ # The size S of the filter in bytes is given by (-1 / pow(log(2), 2) * N * log(P)) / 8
17
+ len = [[(-elements_length * Math.log(fp_rate) / (LN2_SQUARED * 8)).to_i, MAX_BLOOM_FILTER_SIZE].min, 1].max
18
+ @filter = Array.new(len, 0)
19
+ # The number of hash functions required is given by S * 8 / N * log(2)
20
+ @hash_funcs = [[(@filter.size * 8 * LN2 / elements_length).to_i, MAX_HASH_FUNCS].min, 1].max
21
+ @tweak = tweak
22
+ end
23
+
24
+ # @param [String] data The data element to add to the current filter.
25
+ def add(data)
26
+ return if full?
27
+ @hash_funcs.times do |i|
28
+ hash = to_hash(data, i)
29
+ set_bit(hash)
30
+ end
31
+ end
32
+
33
+ # Returns true if the given data matches the filter
34
+ # @param [String] data The data to check the current filter
35
+ # @return [Boolean] true if the given data matches the filter
36
+ def contains?(data)
37
+ return true if full?
38
+ @hash_funcs.times do |i|
39
+ hash = to_hash(data, i)
40
+ return false unless check_bit(hash)
41
+ end
42
+ true
43
+ end
44
+
45
+ def clear
46
+ @filter.fill(0)
47
+ @full = false
48
+ end
49
+
50
+ def to_a
51
+ @filter
52
+ end
53
+
54
+ private
55
+ def to_hash(data, i)
56
+ MurmurHash3::V32.str_hash(data, (i * 0xfba4c795 + @tweak) & 0xffffffff) % (@filter.length * 8)
57
+ end
58
+
59
+ def set_bit(data)
60
+ @filter[data >> 3] |= (1 << (7 & data))
61
+ end
62
+
63
+ def check_bit(data)
64
+ @filter[data >> 3] & (1 << (7 & data)) != 0
65
+ end
66
+
67
+ def full?
68
+ @full |= @filter.all? {|byte| byte == 0xff}
69
+ end
70
+ end
71
+ end
@@ -26,6 +26,9 @@ module Bitcoin
26
26
  attr_reader :genesis
27
27
  attr_reader :bip44_coin_type
28
28
 
29
+ # fork coin id.
30
+ attr_accessor :fork_id
31
+
29
32
  # mainnet genesis
30
33
  def self.mainnet
31
34
  YAML.load(File.open("#{__dir__}/chainparams/mainnet.yml"))
@@ -60,6 +63,11 @@ module Bitcoin
60
63
  Bitcoin::Block.new(header)
61
64
  end
62
65
 
66
+ # whether fork coin.
67
+ def fork_chain?
68
+ !fork_id.nil?
69
+ end
70
+
63
71
  end
64
72
 
65
73
  end
@@ -56,7 +56,7 @@ module Bitcoin
56
56
  SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
57
57
  SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
58
58
  SCRIPT_VERIFY_LOW_S,
59
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM]
59
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM].inject(SCRIPT_VERIFY_NONE){|flags, f| flags |= f}
60
60
 
61
61
  # for script
62
62
 
@@ -84,6 +84,13 @@ module Bitcoin
84
84
  # Signature hash types/flags
85
85
  SIGHASH_TYPE = { all: 1, none: 2, single: 3, anyonecanpay: 128 }
86
86
 
87
+ # SIGHASH_FORK_ID for replay protection of the fork coin
88
+ SIGHASH_FORK_ID = 0x40
89
+
90
+ # fork coin id.
91
+ FORK_ID_CASH = 0
92
+ FORK_ID_GOLD = 79
93
+
87
94
  # Maximum number length in bytes
88
95
  DEFAULT_MAX_NUM_SIZE = 4
89
96
 
@@ -1,9 +1,5 @@
1
1
  module Bitcoin
2
2
 
3
- def self.hmac_sha512(key, data)
4
- OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA512'), key, data)
5
- end
6
-
7
3
  # Integers modulo the order of the curve(secp256k1)
8
4
  CURVE_ORDER = 115792089237316195423570985008687907852837564279074904382605163141518161494337
9
5
 
data/lib/bitcoin/key.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # Porting part of the code from bitcoin-ruby. see the license.
2
+ # https://github.com/lian/bitcoin-ruby/blob/master/COPYING
3
+
1
4
  module Bitcoin
2
5
 
3
6
  # bitcoin key class
@@ -64,13 +67,10 @@ module Bitcoin
64
67
  end
65
68
 
66
69
  # sign +data+ with private key
70
+ # @param [String] data a data to be signed with binary format
71
+ # @return [String] signature data with binary format
67
72
  def sign(data)
68
- sig = nil
69
- until sig
70
- signature = secp256k1_module.sign_data(data, priv_key)
71
- sig = signature if Key.low_signature?(signature)
72
- end
73
- sig
73
+ secp256k1_module.sign_data(data, priv_key)
74
74
  end
75
75
 
76
76
  # verify signature using public key
@@ -78,7 +78,13 @@ module Bitcoin
78
78
  # @param [String] origin original message
79
79
  # @return [Boolean] verify result
80
80
  def verify(sig, origin)
81
- secp256k1_module.verify_sig(origin, sig, pubkey)
81
+ return false unless valid_pubkey?
82
+ begin
83
+ sig = ecdsa_signature_parse_der_lax(sig)
84
+ secp256k1_module.verify_sig(origin, sig, pubkey)
85
+ rescue Exception
86
+ false
87
+ end
82
88
  end
83
89
 
84
90
  # get pay to pubkey hash address
@@ -209,6 +215,24 @@ module Bitcoin
209
215
  MIN_PRIV_KEy_MOD_ORDER <= value && value <= MAX_PRIV_KEY_MOD_ORDER
210
216
  end
211
217
 
218
+ # Supported violations include negative integers, excessive padding, garbage
219
+ # at the end, and overly long length descriptors. This is safe to use in
220
+ # Bitcoin because since the activation of BIP66, signatures are verified to be
221
+ # strict DER before being passed to this module, and we know it supports all
222
+ # violations present in the blockchain before that point.
223
+ def ecdsa_signature_parse_der_lax(sig)
224
+ sig_array = sig.unpack('C*')
225
+ len_r = sig_array[3]
226
+ r = sig_array[4...(len_r+4)].pack('C*').bth
227
+ len_s = sig_array[len_r + 5]
228
+ s = sig_array[(len_r + 6)...(len_r + 6 + len_s)].pack('C*').bth
229
+ ECDSA::Format::SignatureDerString.encode(ECDSA::Signature.new(r.to_i(16), s.to_i(16)))
230
+ end
231
+
232
+ def valid_pubkey?
233
+ !pubkey.nil? && pubkey.size > 0
234
+ end
235
+
212
236
  end
213
237
 
214
238
  end
@@ -0,0 +1,45 @@
1
+ module Bitcoin
2
+ module Message
3
+
4
+ # BIP-152 Compact Block's data format.
5
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#BlockTransactionsRequest
6
+ class BlockTransactionRequest
7
+
8
+ attr_accessor :block_hash # When matching with Bitcoin::BlockHeader#hash It is necessary to reverse the byte order.
9
+ attr_accessor :indexes
10
+
11
+ def initialize(block_hash, indexes)
12
+ @block_hash = block_hash
13
+ @indexes = indexes
14
+ end
15
+
16
+ def self.parse_from_payload(payload)
17
+ buf = StringIO.new(payload)
18
+ block_hash = buf.read(32).bth
19
+ index_len = Bitcoin.unpack_var_int_from_io(buf)
20
+ indexes = index_len.times.map{Bitcoin.unpack_var_int_from_io(buf)}
21
+ # index data differentially encoded
22
+ offset = 0
23
+ index_len.times do |i|
24
+ index = indexes[i]
25
+ index += offset
26
+ indexes[i] = index
27
+ offset = index + 1
28
+ end
29
+ self.new(block_hash, indexes)
30
+ end
31
+
32
+ def to_payload
33
+ p = block_hash.htb << Bitcoin.pack_var_int(indexes.size)
34
+ indexes.size.times do |i|
35
+ index = indexes[i]
36
+ index -= indexes[i-1] + 1 if i > 0
37
+ p << Bitcoin.pack_var_int(index)
38
+ end
39
+ p
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ module Bitcoin
2
+ module Message
3
+
4
+ # BIP-152 Compact Block's data format.
5
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#BlockTransactions
6
+ class BlockTransactions
7
+
8
+ attr_accessor :block_hash
9
+ attr_accessor :transactions
10
+
11
+ def initialize(block_hash, transactions)
12
+ @block_hash = block_hash
13
+ @transactions = transactions
14
+ end
15
+
16
+ def self.parse_from_payload(payload)
17
+ buf = StringIO.new(payload)
18
+ block_hash = buf.read(32).bth
19
+ tx_count = Bitcoin.unpack_var_int_from_io(buf)
20
+ txn = tx_count.times.map{Bitcoin::Tx.parse_from_payload(buf)}
21
+ self.new(block_hash, txn)
22
+ end
23
+
24
+ def to_payload
25
+ block_hash.htb << Bitcoin.pack_var_int(transactions.size) << transactions.map(&:to_payload).join
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ module Bitcoin
2
+ module Message
3
+
4
+ # blocktxn message.
5
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#blocktxn
6
+ class BlockTxn < Base
7
+
8
+ COMMAND = 'blocktxn'
9
+
10
+ attr_accessor :block_transactions
11
+
12
+ def initialize(block_transactions)
13
+ @block_transactions = block_transactions
14
+ end
15
+
16
+ def self.parse_from_payload(payload)
17
+ self.new(BlockTransactions.parse_from_payload(payload))
18
+ end
19
+
20
+ def to_payload
21
+ block_transactions.to_payload
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ module Bitcoin
2
+ module Message
3
+
4
+ # cmpctblock message
5
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
6
+ class CmpctBlock < Base
7
+
8
+ COMMAND = 'cmpctblock'
9
+
10
+ attr_accessor :header_and_short_ids
11
+
12
+ def initialize(header_and_short_ids)
13
+ @header_and_short_ids = header_and_short_ids
14
+ end
15
+
16
+ # generate CmpctBlock from Block data.
17
+ # @param [Bitcoin::Block] block the block to generate CmpctBlock.
18
+ # @param [Integer] version Compact Block version specified by sendcmpct message.
19
+ # @param [Integer] nonce
20
+ # @return [Bitcoin::Message::CmpctBlock]
21
+ def self.from_block(block, version, nonce = SecureRandom.hex(8).to_i(16))
22
+ raise 'Unsupported version.' unless [1, 2].include?(version)
23
+ h = HeaderAndShortIDs.new(block.header, nonce)
24
+ block.transactions[1..-1].each do |tx|
25
+ h.short_ids << h.short_id(version == 1 ? tx.txid : tx.wtxid)
26
+ end
27
+ h.prefilled_txn << PrefilledTx.new(0, block.transactions.first)
28
+ self.new(h)
29
+ end
30
+
31
+ def self.parse_from_payload(payload)
32
+ self.new(HeaderAndShortIDs.parse_from_payload(payload))
33
+ end
34
+
35
+ def to_payload
36
+ header_and_short_ids.to_payload
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ module Bitcoin
2
+ module Message
3
+
4
+ # getblocktxn message.
5
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
6
+ class GetBlockTxn < Base
7
+
8
+ COMMAND = 'getblocktxn'
9
+
10
+ attr_accessor :request
11
+
12
+ def initialize(request)
13
+ @request = request
14
+ end
15
+
16
+ def self.parse_from_payload(payload)
17
+ self.new(BlockTransactionRequest.parse_from_payload(payload))
18
+ end
19
+
20
+ def to_payload
21
+ request.to_payload
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ require 'siphash'
2
+ module Bitcoin
3
+ module Message
4
+
5
+ # BIP-152 Compact Block's data format.
6
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#HeaderAndShortIDs
7
+ class HeaderAndShortIDs
8
+ attr_accessor :header
9
+ attr_accessor :nonce
10
+ attr_accessor :short_ids
11
+ attr_accessor :prefilled_txn
12
+ attr_accessor :siphash_key
13
+
14
+ def initialize(header, nonce, short_ids = [], prefilled_txn = [])
15
+ @header = header
16
+ @nonce = nonce
17
+ @short_ids = short_ids
18
+ @prefilled_txn = prefilled_txn
19
+ @siphash_key = Bitcoin.sha256(header.to_payload << [nonce].pack('q*'))[0...16]
20
+ end
21
+
22
+ def self.parse_from_payload(payload)
23
+ buf = StringIO.new(payload)
24
+ header = Bitcoin::BlockHeader.parse_from_payload(buf.read(80))
25
+ nonce = buf.read(8).unpack('q*').first
26
+ short_ids_len = Bitcoin.unpack_var_int_from_io(buf)
27
+ short_ids = short_ids_len.times.map do
28
+ buf.read(6).reverse.bth.to_i(16)
29
+ end
30
+ prefilled_txn_len = Bitcoin.unpack_var_int_from_io(buf)
31
+ prefilled_txn = prefilled_txn_len.times.map do
32
+ PrefilledTx.parse_from_io(buf)
33
+ end
34
+ self.new(header, nonce, short_ids, prefilled_txn)
35
+ end
36
+
37
+ def to_payload
38
+ p = header.to_payload
39
+ p << [nonce].pack('q*')
40
+ p << Bitcoin.pack_var_int(short_ids.size)
41
+ p << short_ids.map{|id|sprintf('%12x', id).htb.reverse}.join
42
+ p << Bitcoin.pack_var_int(prefilled_txn.size)
43
+ p << prefilled_txn.map(&:to_payload).join
44
+ p
45
+ end
46
+
47
+ # calculate short transaction id which specified by BIP-152.
48
+ # @param [String] txid a transaction id
49
+ # @return [Integer] 6 bytes short transaction id.
50
+ def short_id(txid)
51
+ hash = SipHash.digest(siphash_key, txid.htb.reverse).to_even_length_hex
52
+ [hash].pack('H*')[2...8].bth.to_i(16)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,29 @@
1
+ module Bitcoin
2
+ module Message
3
+
4
+ # A PrefilledTransaction structure is used in HeaderAndShortIDs to provide a list of a few transactions explicitly.
5
+ # https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
6
+ class PrefilledTx
7
+
8
+ attr_accessor :index
9
+ attr_accessor :tx
10
+
11
+ def initialize(index, tx)
12
+ @index = index
13
+ @tx = tx
14
+ end
15
+
16
+ def self.parse_from_io(io)
17
+ index = Bitcoin.unpack_var_int_from_io(io)
18
+ tx = Bitcoin::Tx.parse_from_payload(io)
19
+ self.new(index, tx)
20
+ end
21
+
22
+ def to_payload
23
+ Bitcoin.pack_var_int(index) << tx.to_payload
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -14,7 +14,7 @@ module Bitcoin
14
14
  attr_accessor :version
15
15
  # TODO support version 2
16
16
 
17
- def initialize(mode, version)
17
+ def initialize(mode = MODE_HIGH, version = 1)
18
18
  @mode = mode
19
19
  @version = version
20
20
  end
@@ -27,8 +27,8 @@ module Bitcoin
27
27
  @nonce = SecureRandom.random_number(0xffffffffffffffff)
28
28
  @user_agent = Bitcoin::Message::USER_AGENT
29
29
  @start_height = 0
30
- @relay = true
31
30
  opts.each { |k, v| send "#{k}=", v }
31
+ @relay = opts[:relay] || false
32
32
  end
33
33
 
34
34
  def self.parse_from_payload(payload)
@@ -30,6 +30,13 @@ module Bitcoin
30
30
  autoload :Error, 'bitcoin/message/error'
31
31
  autoload :Reject, 'bitcoin/message/reject'
32
32
  autoload :SendCmpct, 'bitcoin/message/send_cmpct'
33
+ autoload :CmpctBlock, 'bitcoin/message/cmpct_block'
34
+ autoload :HeaderAndShortIDs, 'bitcoin/message/header_and_short_ids'
35
+ autoload :PrefilledTx, 'bitcoin/message/prefilled_tx'
36
+ autoload :GetBlockTxn, 'bitcoin/message/get_block_txn'
37
+ autoload :BlockTransactionRequest, 'bitcoin/message/block_transaction_request'
38
+ autoload :BlockTxn, 'bitcoin/message/block_txn'
39
+ autoload :BlockTransactions, 'bitcoin/message/block_transactions'
33
40
 
34
41
  USER_AGENT = "/bitcoinrb:#{Bitcoin::VERSION}/"
35
42
 
@@ -92,8 +92,10 @@ module Bitcoin
92
92
  on_inv(Bitcoin::Message::Inv.parse_from_payload(payload))
93
93
  when Bitcoin::Message::MerkleBlock::COMMAND
94
94
  on_merkle_block(Bitcoin::Message::MerkleBlock.parse_from_payload(payload))
95
+ when Bitcoin::Message::CmpctBlock::COMMAND
96
+ on_cmpct_block(Bitcoin::Message::CmpctBlock.parse_from_payload(payload))
95
97
  else
96
- logger.warn("unsupported command received. #{command}")
98
+ logger.warn("unsupported command received. command: #{command}, payload: #{payload.bth}")
97
99
  close("with command #{command}")
98
100
  end
99
101
  end
@@ -224,6 +226,10 @@ module Bitcoin
224
226
  logger.info("receive merkle block message. #{merkle_block.build_json}")
225
227
  end
226
228
 
229
+ def on_cmpct_block(cmpct_block)
230
+ logger.info("receive cmpct_block message. #{cmpct_block.build_json}")
231
+ end
232
+
227
233
  end
228
234
  end
229
235
  end
@@ -5,7 +5,7 @@ module Bitcoin
5
5
  class Peer
6
6
 
7
7
  # Interval for pinging peers.
8
- PING_INTERVAL = 30
8
+ PING_INTERVAL = 2 * 60
9
9
 
10
10
  attr_reader :logger
11
11
  attr_accessor :id
@@ -34,7 +34,7 @@ module Bitcoin
34
34
  attr_reader :chain
35
35
  attr_accessor :fee_rate
36
36
 
37
- def initialize(host, port, pool)
37
+ def initialize(host, port, pool, configuration)
38
38
  @host = host
39
39
  @port = port
40
40
  @pool = pool
@@ -48,8 +48,9 @@ module Bitcoin
48
48
  @min_ping = -1
49
49
  @bytes_sent = 0
50
50
  @bytes_recv = 0
51
+ @relay = configuration.conf[:relay]
51
52
  current_height = @chain.latest_block.height
52
- @local_version = Bitcoin::Message::Version.new(remote_addr: addr, start_height: current_height)
53
+ @local_version = Bitcoin::Message::Version.new(remote_addr: addr, start_height: current_height, relay: @relay)
53
54
  end
54
55
 
55
56
  def connect
@@ -186,7 +187,28 @@ module Bitcoin
186
187
  conn.send_message(ping)
187
188
  end
188
189
 
189
- end
190
+ # send filterload message.
191
+ def send_filter_load(bloom)
192
+ filter_load = Bitcoin::Message::FilterLoad.new(
193
+ bloom.to_a,
194
+ bloom.hash_funcs,
195
+ bloom.tweak,
196
+ Bitcoin::Message::FilterLoad::BLOOM_UPDATE_ALL
197
+ )
198
+ conn.send_message(filter_load)
199
+ end
200
+
201
+ # send filteradd message.
202
+ def send_filter_add(element)
203
+ filter_add = Bitcoin::Message::FilterAdd.new(element)
204
+ conn.send_message(filter_add)
205
+ end
190
206
 
207
+ # send filterclear message.
208
+ def send_filter_clear
209
+ filter_clear = Bitcoin::Message::FilterClear.new
210
+ conn.send_message(filter_clear)
211
+ end
212
+ end
191
213
  end
192
214
  end