bitcoinrb 0.1.5 → 0.1.6

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.
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