bitcoin-ruby 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -7
- data/README.rdoc +1 -1
- data/examples/simple_network_monitor_and_util.rb +8 -0
- data/lib/bitcoin.rb +57 -17
- data/lib/bitcoin/builder.rb +15 -10
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +3 -2
- data/lib/bitcoin/ffi/secp256k1.rb +143 -81
- data/lib/bitcoin/key.rb +4 -6
- data/lib/bitcoin/logger.rb +11 -0
- data/lib/bitcoin/protocol.rb +19 -6
- data/lib/bitcoin/protocol/aux_pow.rb +62 -62
- data/lib/bitcoin/protocol/block.rb +20 -15
- data/lib/bitcoin/protocol/handler.rb +4 -0
- data/lib/bitcoin/protocol/parser.rb +30 -29
- data/lib/bitcoin/protocol/reject.rb +38 -0
- data/lib/bitcoin/protocol/tx.rb +19 -3
- data/lib/bitcoin/protocol/txin.rb +14 -8
- data/lib/bitcoin/script.rb +6 -1
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bitcoin_spec.rb +4 -0
- data/spec/bitcoin/builder_spec.rb +11 -0
- data/spec/bitcoin/dogecoin_spec.rb +6 -6
- data/spec/bitcoin/protocol/addr_spec.rb +11 -1
- data/spec/bitcoin/protocol/aux_pow_spec.rb +9 -9
- data/spec/bitcoin/protocol/block_spec.rb +1 -0
- data/spec/bitcoin/protocol/inv_spec.rb +10 -2
- data/spec/bitcoin/protocol/parser_spec.rb +50 -0
- data/spec/bitcoin/protocol/reject.rb +17 -0
- data/spec/bitcoin/protocol/tx_spec.rb +5 -1
- data/spec/bitcoin/script/script_spec.rb +1 -1
- data/spec/bitcoin/secp256k1_spec.rb +8 -0
- data/spec/bitcoin/spec_helper.rb +6 -0
- metadata +8 -3
data/lib/bitcoin/key.rb
CHANGED
@@ -5,6 +5,8 @@ module Bitcoin
|
|
5
5
|
# Elliptic Curve key as used in bitcoin.
|
6
6
|
class Key
|
7
7
|
|
8
|
+
attr_reader :key
|
9
|
+
|
8
10
|
# Generate a new keypair.
|
9
11
|
# Bitcoin::Key.generate
|
10
12
|
def self.generate(opts={compressed: true})
|
@@ -54,6 +56,7 @@ module Bitcoin
|
|
54
56
|
# Set the private key to +priv+ (in hex).
|
55
57
|
def priv= priv
|
56
58
|
set_priv(priv)
|
59
|
+
regenerate_pubkey
|
57
60
|
end
|
58
61
|
|
59
62
|
# Get the public key (in hex).
|
@@ -98,12 +101,7 @@ module Bitcoin
|
|
98
101
|
# key1 = Bitcoin::Key.generate
|
99
102
|
# sig = key1.sign("some data")
|
100
103
|
def sign(data)
|
101
|
-
|
102
|
-
if Script::is_low_der_signature?(sig)
|
103
|
-
sig
|
104
|
-
else
|
105
|
-
Bitcoin::OpenSSL_EC.signature_to_low_s(sig)
|
106
|
-
end
|
104
|
+
Bitcoin.sign_data(key, data)
|
107
105
|
end
|
108
106
|
|
109
107
|
# Verify signature +sig+ for +data+.
|
data/lib/bitcoin/logger.rb
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'log4r'
|
5
|
+
# monkey-patch Log4r to accept level names as symbols
|
6
|
+
class Log4r::Logger
|
7
|
+
def level= l = 0
|
8
|
+
_level = l.is_a?(Fixnum) ? l : Log4r::LNAMES.index(l.to_s.upcase)
|
9
|
+
Log4r::Log4rTools.validate_level(_level)
|
10
|
+
@level = _level
|
11
|
+
LoggerFactory.define_methods(self)
|
12
|
+
Log4r::Logger.log_internal {"Logger '#{@fullname}' set to #{LNAMES[@level]}"}
|
13
|
+
@level
|
14
|
+
end
|
15
|
+
end
|
5
16
|
rescue LoadError
|
6
17
|
end
|
7
18
|
|
data/lib/bitcoin/protocol.rb
CHANGED
@@ -19,6 +19,7 @@ module Bitcoin
|
|
19
19
|
autoload :Block, 'bitcoin/protocol/block'
|
20
20
|
autoload :Addr, 'bitcoin/protocol/address'
|
21
21
|
autoload :Alert, 'bitcoin/protocol/alert'
|
22
|
+
autoload :Reject, 'bitcoin/protocol/reject'
|
22
23
|
autoload :Version, 'bitcoin/protocol/version'
|
23
24
|
autoload :AuxPow, 'bitcoin/protocol/aux_pow'
|
24
25
|
|
@@ -72,15 +73,27 @@ module Bitcoin
|
|
72
73
|
end
|
73
74
|
|
74
75
|
def self.unpack_var_string_array(payload) # unpacks set<string>
|
75
|
-
|
76
|
-
|
77
|
-
[
|
76
|
+
buf = StringIO.new(payload)
|
77
|
+
size = unpack_var_int_from_io(buf)
|
78
|
+
return [nil, buf.read] if size == 0
|
79
|
+
strings = []
|
80
|
+
size.times{
|
81
|
+
break if buf.eof?
|
82
|
+
strings << unpack_var_string_from_io(buf)
|
83
|
+
}
|
84
|
+
[strings, buf.read]
|
78
85
|
end
|
79
86
|
|
80
87
|
def self.unpack_var_int_array(payload) # unpacks set<int>
|
81
|
-
|
82
|
-
|
83
|
-
[
|
88
|
+
buf = StringIO.new(payload)
|
89
|
+
size = unpack_var_int_from_io(buf)
|
90
|
+
return [nil, buf.read] if size == 0
|
91
|
+
ints = []
|
92
|
+
size.times{
|
93
|
+
break if buf.eof?
|
94
|
+
ints << unpack_var_int_from_io(buf)
|
95
|
+
}
|
96
|
+
[ints, buf.read]
|
84
97
|
end
|
85
98
|
|
86
99
|
def self.unpack_boolean(payload)
|
@@ -4,25 +4,40 @@ module Bitcoin
|
|
4
4
|
module Protocol
|
5
5
|
|
6
6
|
# Auxiliary Proof-of-Work for merge-mined blockchains
|
7
|
+
# See https://en.bitcoin.it/wiki/Merged_mining_specification.
|
8
|
+
#
|
9
|
+
# The AuxPow contains all data needed to verify that the child
|
10
|
+
# block was included in the parents coinbase transaction, and
|
11
|
+
# the parent satisfies the difficulty target.
|
12
|
+
#
|
13
|
+
# It encodes the +parent_block+ header, and its +coinbase_tx+.
|
14
|
+
# The +coinbase_branch+ and +coinbase_index+ can be used to recalculate
|
15
|
+
# the parent blocks merkle root and prove the coinbase transaction is
|
16
|
+
# really included in it.
|
17
|
+
# The +chain_branch+ and +chain_index+ are used to link the child block
|
18
|
+
# to the merkle root contained in the +coinbase_tx+. (So there can be
|
19
|
+
# more than one merge-mined chain)
|
20
|
+
#
|
21
|
+
# TODO: decode merged-mining data from +coinbase_tx+
|
7
22
|
class AuxPow
|
8
23
|
|
9
|
-
# Coinbase transaction
|
10
|
-
attr_accessor :
|
24
|
+
# Coinbase transaction of the parent block, linking to the child block
|
25
|
+
attr_accessor :coinbase_tx
|
11
26
|
|
12
|
-
# Hash of the block header
|
27
|
+
# Hash of the parent block header
|
13
28
|
attr_accessor :block_hash
|
14
29
|
|
15
|
-
# Merkle
|
16
|
-
attr_accessor :
|
30
|
+
# Merkle branch linking the +coinbase_tx+ to the +parent_block+
|
31
|
+
attr_accessor :coinbase_branch
|
17
32
|
|
18
|
-
# Index of
|
19
|
-
attr_accessor :
|
33
|
+
# Index of the +coinbase_tx+ in the parent blocks merkle tree
|
34
|
+
attr_accessor :coinbase_index
|
20
35
|
|
21
|
-
# Merkle
|
22
|
-
attr_accessor :
|
36
|
+
# Merkle branch linking the child block to the +coinbase_tx+
|
37
|
+
attr_accessor :chain_branch
|
23
38
|
|
24
|
-
# Index of
|
25
|
-
attr_accessor :
|
39
|
+
# Index of the child block in the chain merkle tree
|
40
|
+
attr_accessor :chain_index
|
26
41
|
|
27
42
|
# Parent block header
|
28
43
|
attr_accessor :parent_block
|
@@ -32,47 +47,32 @@ module Bitcoin
|
|
32
47
|
end
|
33
48
|
|
34
49
|
def parse_data(data)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
branch_count, payload = P.unpack_var_int(payload)
|
40
|
-
@branch = []
|
41
|
-
branch_count.times {
|
42
|
-
b, payload = payload.unpack("a32a*")
|
43
|
-
@branch << b
|
44
|
-
}
|
45
|
-
@mrkl_index, payload = payload.unpack("Ia*")
|
46
|
-
|
47
|
-
@aux_branch = []
|
48
|
-
aux_branch_count, payload = P.unpack_var_int(payload)
|
49
|
-
aux_branch_count.times {
|
50
|
-
b, payload = payload.unpack("a32a*")
|
51
|
-
@aux_branch << b
|
52
|
-
}
|
53
|
-
|
54
|
-
@aux_index, payload = payload.unpack("Ia*")
|
55
|
-
block, payload = payload.unpack("a80a*")
|
56
|
-
@parent_block = P::Block.new(block)
|
57
|
-
|
58
|
-
payload
|
50
|
+
buf = StringIO.new(data)
|
51
|
+
parse_data_from_io(buf)
|
52
|
+
buf.eof? ? '' : buf.read
|
59
53
|
end
|
60
54
|
|
61
55
|
def parse_data_from_io(data)
|
62
|
-
@
|
63
|
-
@
|
56
|
+
@coinbase_tx = P::Tx.new(nil)
|
57
|
+
@coinbase_tx.parse_data_from_io(data)
|
64
58
|
|
65
59
|
@block_hash = data.read(32)
|
66
|
-
|
67
|
-
@
|
68
|
-
|
69
|
-
|
60
|
+
coinbase_branch_count = P.unpack_var_int_from_io(data)
|
61
|
+
@coinbase_branch = []
|
62
|
+
coinbase_branch_count.times{
|
63
|
+
break if data.eof?
|
64
|
+
@coinbase_branch << data.read(32).reverse.hth
|
65
|
+
}
|
66
|
+
@coinbase_index = data.read(4).unpack("I")[0]
|
70
67
|
|
71
|
-
@
|
72
|
-
|
73
|
-
|
68
|
+
@chain_branch = []
|
69
|
+
chain_branch_count = P.unpack_var_int_from_io(data)
|
70
|
+
chain_branch_count.times{
|
71
|
+
break if data.eof?
|
72
|
+
@chain_branch << data.read(32).reverse.hth
|
73
|
+
}
|
74
74
|
|
75
|
-
@
|
75
|
+
@chain_index = data.read(4).unpack("I")[0]
|
76
76
|
block = data.read(80)
|
77
77
|
@parent_block = P::Block.new(block)
|
78
78
|
|
@@ -81,14 +81,14 @@ module Bitcoin
|
|
81
81
|
|
82
82
|
|
83
83
|
def to_payload
|
84
|
-
payload = @
|
84
|
+
payload = @coinbase_tx.to_payload
|
85
85
|
payload << @block_hash
|
86
|
-
payload << P.pack_var_int(@
|
87
|
-
payload << @
|
88
|
-
payload << [@
|
89
|
-
payload << P.pack_var_int(@
|
90
|
-
payload << @
|
91
|
-
payload << [@
|
86
|
+
payload << P.pack_var_int(@coinbase_branch.count)
|
87
|
+
payload << @coinbase_branch.map(&:htb).map(&:reverse).join
|
88
|
+
payload << [@coinbase_index].pack("I")
|
89
|
+
payload << P.pack_var_int(@chain_branch.count)
|
90
|
+
payload << @chain_branch.map(&:htb).map(&:reverse).join
|
91
|
+
payload << [@chain_index].pack("I")
|
92
92
|
payload << @parent_block.to_payload
|
93
93
|
payload
|
94
94
|
end
|
@@ -96,24 +96,24 @@ module Bitcoin
|
|
96
96
|
def self.from_hash h
|
97
97
|
aux_pow = new(nil)
|
98
98
|
aux_pow.instance_eval do
|
99
|
-
@
|
99
|
+
@coinbase_tx = P::Tx.from_hash(h['coinbase_tx'])
|
100
100
|
@block_hash = h['block_hash'].htb
|
101
|
-
@
|
102
|
-
@
|
103
|
-
@
|
104
|
-
@
|
101
|
+
@coinbase_branch = h['coinbase_branch']
|
102
|
+
@coinbase_index = h['coinbase_index']
|
103
|
+
@chain_branch = h['chain_branch']
|
104
|
+
@chain_index = h['chain_index']
|
105
105
|
@parent_block = P::Block.from_hash(h['parent_block'])
|
106
106
|
end
|
107
107
|
aux_pow
|
108
108
|
end
|
109
109
|
|
110
110
|
def to_hash
|
111
|
-
{ '
|
111
|
+
{ 'coinbase_tx' => @coinbase_tx.to_hash,
|
112
112
|
'block_hash' => @block_hash.hth,
|
113
|
-
'
|
114
|
-
'
|
115
|
-
'
|
116
|
-
'
|
113
|
+
'coinbase_branch' => @coinbase_branch,
|
114
|
+
'coinbase_index' => @coinbase_index,
|
115
|
+
'chain_branch' => @chain_branch,
|
116
|
+
'chain_index' => @chain_index,
|
117
117
|
'parent_block' => @parent_block.to_hash }
|
118
118
|
end
|
119
119
|
|
@@ -14,7 +14,9 @@ module Bitcoin
|
|
14
14
|
attr_accessor :hash
|
15
15
|
|
16
16
|
# previous block hash
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :prev_block_hash
|
18
|
+
alias :prev_block :prev_block_hash
|
19
|
+
def prev_block=(hash); @prev_block_hash = hash; end
|
18
20
|
|
19
21
|
# transactions (Array of Tx)
|
20
22
|
attr_accessor :tx
|
@@ -52,7 +54,7 @@ module Bitcoin
|
|
52
54
|
end
|
53
55
|
|
54
56
|
def prev_block_hex
|
55
|
-
@prev_block_hex ||= @
|
57
|
+
@prev_block_hex ||= @prev_block_hash.reverse.unpack("H*")[0]
|
56
58
|
end
|
57
59
|
|
58
60
|
# create block from raw binary +data+
|
@@ -70,7 +72,7 @@ module Bitcoin
|
|
70
72
|
# parse raw binary data
|
71
73
|
def parse_data_from_io(buf, header_only=false)
|
72
74
|
buf = buf.is_a?(String) ? StringIO.new(buf) : buf
|
73
|
-
@ver, @
|
75
|
+
@ver, @prev_block_hash, @mrkl_root, @time, @bits, @nonce = buf.read(80).unpack("Va32a32VVV")
|
74
76
|
recalc_block_hash
|
75
77
|
|
76
78
|
if Bitcoin.network[:auxpow_chain_id] != nil && (@ver & BLOCK_VERSION_AUXPOW) > 0
|
@@ -84,7 +86,10 @@ module Bitcoin
|
|
84
86
|
@tx_count = tx_size
|
85
87
|
return buf if header_only
|
86
88
|
|
87
|
-
tx_size.times{
|
89
|
+
tx_size.times{
|
90
|
+
break if payload == true
|
91
|
+
return buf if buf.eof?
|
92
|
+
|
88
93
|
t = Tx.new(nil)
|
89
94
|
payload = t.parse_data_from_io(buf)
|
90
95
|
@tx << t
|
@@ -96,11 +101,11 @@ module Bitcoin
|
|
96
101
|
|
97
102
|
# recalculate the block hash
|
98
103
|
def recalc_block_hash
|
99
|
-
@hash = Bitcoin.block_hash(@
|
104
|
+
@hash = Bitcoin.block_hash(@prev_block_hash.reverse_hth, @mrkl_root.reverse_hth, @time, @bits, @nonce, @ver)
|
100
105
|
end
|
101
106
|
|
102
107
|
def recalc_block_scrypt_hash
|
103
|
-
@scrypt_hash = Bitcoin.block_scrypt_hash(@
|
108
|
+
@scrypt_hash = Bitcoin.block_scrypt_hash(@prev_block_hash.reverse_hth, @mrkl_root.reverse_hth, @time, @bits, @nonce, @ver)
|
104
109
|
end
|
105
110
|
|
106
111
|
def recalc_mrkl_root
|
@@ -115,12 +120,12 @@ module Bitcoin
|
|
115
120
|
# get the block header info
|
116
121
|
# [<version>, <prev_block>, <merkle_root>, <time>, <bits>, <nonce>, <txcount>, <size>]
|
117
122
|
def header_info
|
118
|
-
[@ver, @
|
123
|
+
[@ver, @prev_block_hash.reverse_hth, @mrkl_root.reverse_hth, Time.at(@time), @bits, @nonce, @tx.size, @payload.size]
|
119
124
|
end
|
120
125
|
|
121
126
|
# convert to raw binary format
|
122
127
|
def to_payload
|
123
|
-
head = [@ver, @
|
128
|
+
head = [@ver, @prev_block_hash, @mrkl_root, @time, @bits, @nonce].pack("Va32a32VVV")
|
124
129
|
head << @aux_pow.to_payload if @aux_pow
|
125
130
|
return head if @tx.size == 0
|
126
131
|
head << Protocol.pack_var_int(@tx.size)
|
@@ -129,13 +134,13 @@ module Bitcoin
|
|
129
134
|
end
|
130
135
|
|
131
136
|
# convert to ruby hash (see also #from_hash)
|
132
|
-
def to_hash
|
137
|
+
def to_hash(options = {})
|
133
138
|
h = {
|
134
139
|
'hash' => @hash, 'ver' => @ver,
|
135
|
-
'prev_block' => @
|
140
|
+
'prev_block' => @prev_block_hash.reverse_hth, 'mrkl_root' => @mrkl_root.reverse_hth,
|
136
141
|
'time' => @time, 'bits' => @bits, 'nonce' => @nonce,
|
137
142
|
'n_tx' => @tx.size, 'size' => (@payload||to_payload).bytesize,
|
138
|
-
'tx' => @tx.map{|i| i.to_hash },
|
143
|
+
'tx' => @tx.map{|i| i.to_hash(options) },
|
139
144
|
'mrkl_tree' => Bitcoin.hash_mrkl_tree( @tx.map{|i| i.hash } )
|
140
145
|
}
|
141
146
|
h['aux_pow'] = @aux_pow.to_hash if @aux_pow
|
@@ -177,7 +182,7 @@ module Bitcoin
|
|
177
182
|
# convert to json representation as seen in the block explorer.
|
178
183
|
# (see also #from_json)
|
179
184
|
def to_json(options = {:space => ''}, *a)
|
180
|
-
JSON.pretty_generate( to_hash, options )
|
185
|
+
JSON.pretty_generate( to_hash(options), options )
|
181
186
|
end
|
182
187
|
|
183
188
|
# write json representation to a file
|
@@ -191,12 +196,12 @@ module Bitcoin
|
|
191
196
|
blk = new(nil)
|
192
197
|
blk.instance_eval{
|
193
198
|
@ver, @time, @bits, @nonce = h.values_at('ver', 'time', 'bits', 'nonce')
|
194
|
-
@
|
199
|
+
@prev_block_hash, @mrkl_root = h.values_at('prev_block', 'mrkl_root').map{|i| i.htb_reverse }
|
195
200
|
unless h['hash'] == recalc_block_hash
|
196
201
|
raise "Block hash mismatch! Claimed: #{h['hash']}, Actual: #{@hash}" if do_raise
|
197
202
|
end
|
198
203
|
@aux_pow = AuxPow.from_hash(h['aux_pow']) if h['aux_pow']
|
199
|
-
h['tx'].each{|tx| @tx << Tx.from_hash(tx) }
|
204
|
+
h['tx'].each{|tx| @tx << Tx.from_hash(tx, do_raise) }
|
200
205
|
if h['tx'].any?
|
201
206
|
(raise "Block merkle root mismatch! Block: #{h['hash']}" unless verify_mrkl_root) if do_raise
|
202
207
|
end
|
@@ -222,7 +227,7 @@ module Bitcoin
|
|
222
227
|
|
223
228
|
# block header binary output
|
224
229
|
def block_header
|
225
|
-
[@ver, @
|
230
|
+
[@ver, @prev_block_hash, @mrkl_root, @time, @bits, @nonce, Protocol.pack_var_int(0)].pack("Va32a32VVVa*")
|
226
231
|
end
|
227
232
|
|
228
233
|
# read binary block from a file
|
@@ -9,29 +9,19 @@ module Bitcoin
|
|
9
9
|
def initialize(handler=nil)
|
10
10
|
@h = handler || Handler.new
|
11
11
|
@buf = ""
|
12
|
-
@stats = {
|
13
|
-
'total_packets' => 0,
|
14
|
-
'total_bytes' => 0
|
15
|
-
}
|
12
|
+
@stats = { 'total_packets' => 0, 'total_bytes' => 0, 'total_errors' => 0 }
|
16
13
|
end
|
17
14
|
|
18
|
-
def log
|
19
|
-
@log ||= Bitcoin::Logger.create("parser")
|
20
|
-
end
|
15
|
+
def log; @log ||= Bitcoin::Logger.create("parser"); end
|
21
16
|
|
22
17
|
# handles inv/getdata packets
|
23
|
-
#
|
24
18
|
def parse_inv(payload, type=:put)
|
25
19
|
count, payload = Protocol.unpack_var_int(payload)
|
26
|
-
payload.each_byte.each_slice(36).with_index
|
20
|
+
payload.each_byte.each_slice(36).with_index do |i, idx|
|
27
21
|
hash = i[4..-1].reverse.pack("C32")
|
28
22
|
case i[0]
|
29
23
|
when 1
|
30
|
-
|
31
|
-
@h.on_inv_transaction(hash)
|
32
|
-
else
|
33
|
-
@h.on_get_transaction(hash)
|
34
|
-
end
|
24
|
+
type == :put ? @h.on_inv_transaction(hash) : @h.on_get_transaction(hash)
|
35
25
|
when 2
|
36
26
|
if type == :put
|
37
27
|
if @h.respond_to?(:on_inv_block_v2)
|
@@ -43,28 +33,26 @@ module Bitcoin
|
|
43
33
|
@h.on_get_block(hash)
|
44
34
|
end
|
45
35
|
else
|
46
|
-
|
36
|
+
parse_error :parse_inv, i.pack("C*")
|
47
37
|
end
|
48
|
-
|
38
|
+
end
|
49
39
|
end
|
50
40
|
|
51
41
|
def parse_addr(payload)
|
52
42
|
count, payload = Protocol.unpack_var_int(payload)
|
53
|
-
payload.each_byte.each_slice(30)
|
54
|
-
|
55
|
-
|
56
|
-
rescue
|
57
|
-
puts "Error parsing addr: #{i.inspect}"
|
58
|
-
end
|
59
|
-
@h.on_addr( addr )
|
60
|
-
}
|
43
|
+
payload.each_byte.each_slice(30) do |i|
|
44
|
+
@h.on_addr(Addr.new(i.pack("C*"))) rescue parse_error(:addr, i.pack("C*"))
|
45
|
+
end
|
61
46
|
end
|
62
47
|
|
63
48
|
def parse_headers(payload)
|
64
49
|
return unless @h.respond_to?(:on_headers)
|
65
50
|
buf = StringIO.new(payload)
|
66
51
|
count = Protocol.unpack_var_int_from_io(buf)
|
67
|
-
headers = count.times.map{
|
52
|
+
headers = count.times.map{
|
53
|
+
break if buf.eof?
|
54
|
+
b = Block.new; b.parse_data_from_io(buf, header_only=true); b
|
55
|
+
}
|
68
56
|
@h.on_headers(headers)
|
69
57
|
end
|
70
58
|
|
@@ -98,8 +86,9 @@ module Bitcoin
|
|
98
86
|
when 'getheaders'; @h.on_getheaders(*parse_getblocks(payload)) if @h.respond_to?(:on_getheaders)
|
99
87
|
when 'mempool'; handle_mempool_request(payload)
|
100
88
|
when 'notfound'; handle_notfound_reply(payload)
|
89
|
+
when 'reject'; handle_reject(payload)
|
101
90
|
else
|
102
|
-
|
91
|
+
parse_error :unknown_packet, [command, payload.hth]
|
103
92
|
end
|
104
93
|
end
|
105
94
|
|
@@ -113,6 +102,11 @@ module Bitcoin
|
|
113
102
|
@h.on_alert Bitcoin::Protocol::Alert.parse(payload)
|
114
103
|
end
|
115
104
|
|
105
|
+
def handle_reject(payload)
|
106
|
+
return unless @h.respond_to?(:on_reject)
|
107
|
+
@h.on_reject Bitcoin::Protocol::Reject.parse(payload)
|
108
|
+
end
|
109
|
+
|
116
110
|
# https://en.bitcoin.it/wiki/BIP_0035
|
117
111
|
def handle_mempool_request(payload)
|
118
112
|
return unless @version.fields[:version] >= 60002 # Protocol version >= 60002
|
@@ -123,15 +117,15 @@ module Bitcoin
|
|
123
117
|
def handle_notfound_reply(payload)
|
124
118
|
return unless @h.respond_to?(:on_notfound)
|
125
119
|
count, payload = Protocol.unpack_var_int(payload)
|
126
|
-
payload.each_byte.each_slice(36)
|
120
|
+
payload.each_byte.each_slice(36) do |i|
|
127
121
|
hash = i[4..-1].reverse.pack("C32")
|
128
122
|
case i[0]
|
129
123
|
when 1; @h.on_notfound(:tx, hash)
|
130
124
|
when 2; @h.on_notfound(:block, hash)
|
131
125
|
else
|
132
|
-
|
126
|
+
parse_error(:notfound, [i.pack("C*"), hash])
|
133
127
|
end
|
134
|
-
|
128
|
+
end
|
135
129
|
end
|
136
130
|
|
137
131
|
def parse(buf)
|
@@ -179,6 +173,13 @@ module Bitcoin
|
|
179
173
|
log.debug { [type, msg] }
|
180
174
|
end
|
181
175
|
end
|
176
|
+
|
177
|
+
def parse_error *err
|
178
|
+
@stats['total_errors'] += 1
|
179
|
+
return unless @h.respond_to?(:on_error)
|
180
|
+
@h.on_error *err
|
181
|
+
end
|
182
|
+
|
182
183
|
end # Parser
|
183
184
|
|
184
185
|
end
|