Module: Bitcoin::Protocol
- Defined in:
- lib/bitcoin/protocol.rb,
lib/bitcoin/protocol/tx.rb,
lib/bitcoin/protocol/txin.rb,
lib/bitcoin/protocol/block.rb,
lib/bitcoin/protocol/txout.rb,
lib/bitcoin/protocol/parser.rb,
lib/bitcoin/protocol/reject.rb,
lib/bitcoin/protocol/address.rb,
lib/bitcoin/protocol/aux_pow.rb,
lib/bitcoin/protocol/handler.rb,
lib/bitcoin/protocol/version.rb,
lib/bitcoin/protocol/script_witness.rb,
lib/bitcoin/protocol/partial_merkle_tree.rb
Defined Under Namespace
Classes: Addr, AuxPow, Block, Handler, Parser, PartialMerkleTree, Reject, ScriptWitness, Tx, TxIn, TxOut, Version
Constant Summary
collapse
- MAX_INV_SZ =
50000
- BIP0031_VERSION =
BIP 0031, pong message, is enabled for all versions AFTER this one
60000
- Uniq =
rand(0xffffffffffffffff)
- BINARY =
Encoding.find('ASCII-8BIT')
- TypeLookup =
- DEFAULT_STOP_HASH =
"00"*32
Class Method Summary
collapse
-
.getblocks_pkt(version, locator_hashes, stop_hash = DEFAULT_STOP_HASH) ⇒ Object
-
.getdata_pkt(type, hashes) ⇒ Object
-
.getheaders_pkt(version, locator_hashes, stop_hash = DEFAULT_STOP_HASH) ⇒ Object
-
.headers_pkt(version, blocks) ⇒ Object
-
.inv_pkt(type, hashes) ⇒ Object
-
.locator_payload(version, locator_hashes, stop_hash) ⇒ Object
-
.pack_boolean(b) ⇒ Object
-
.pack_var_int(i) ⇒ Object
-
.pack_var_string(payload) ⇒ Object
-
.ping_pkt(nonce = rand(0xffffffff)) ⇒ Object
-
.pkt(command, payload) ⇒ Object
-
.pong_pkt(nonce) ⇒ Object
-
.read_binary_file(path) ⇒ Object
-
.unpack_boolean(payload) ⇒ Object
-
.unpack_var_int(payload) ⇒ Object
-
.unpack_var_int_array(payload) ⇒ Object
-
.unpack_var_int_from_io(io) ⇒ Object
-
.unpack_var_string(payload) ⇒ Object
-
.unpack_var_string_array(payload) ⇒ Object
-
.unpack_var_string_from_io(buf) ⇒ Object
-
.verack_pkt ⇒ Object
-
.version_pkt(from_id, from = nil, to = nil, last_block = nil, time = nil, user_agent = nil, version = nil) ⇒ Object
Class Method Details
.getblocks_pkt(version, locator_hashes, stop_hash = DEFAULT_STOP_HASH) ⇒ Object
174
175
176
|
# File 'lib/bitcoin/protocol.rb', line 174
def self.getblocks_pkt(version, locator_hashes, stop_hash=DEFAULT_STOP_HASH)
pkt "getblocks", locator_payload(version, locator_hashes, stop_hash)
end
|
.getdata_pkt(type, hashes) ⇒ Object
151
152
153
154
155
|
# File 'lib/bitcoin/protocol.rb', line 151
def self.getdata_pkt(type, hashes)
return if hashes.size > MAX_INV_SZ
t = [ TypeLookup[type] ].pack("V")
pkt("getdata", pack_var_int(hashes.size) + hashes.map{|hash| t + hash[0..32].reverse }.join)
end
|
178
179
180
|
# File 'lib/bitcoin/protocol.rb', line 178
def self.(version, locator_hashes, stop_hash=DEFAULT_STOP_HASH)
pkt "getheaders", locator_payload(version, locator_hashes, stop_hash)
end
|
182
183
184
|
# File 'lib/bitcoin/protocol.rb', line 182
def self.(version, blocks)
pkt "headers", [pack_var_int(blocks.size), blocks.map{|block| block.}.join].join
end
|
.inv_pkt(type, hashes) ⇒ Object
157
158
159
160
161
|
# File 'lib/bitcoin/protocol.rb', line 157
def self.inv_pkt(type, hashes)
return if hashes.size > MAX_INV_SZ
t = [ TypeLookup[type] ].pack("V")
pkt("inv", pack_var_int(hashes.size) + hashes.map{|hash| t + hash[0..32].reverse }.join)
end
|
.locator_payload(version, locator_hashes, stop_hash) ⇒ Object
165
166
167
168
169
170
171
172
|
# File 'lib/bitcoin/protocol.rb', line 165
def self.locator_payload(version, locator_hashes, stop_hash)
[
[version].pack("V"),
pack_var_int(locator_hashes.size),
locator_hashes.map{|l| l.htb_reverse }.join,
stop_hash.htb_reverse
].join
end
|
.pack_boolean(b) ⇒ Object
105
106
107
|
# File 'lib/bitcoin/protocol.rb', line 105
def self.pack_boolean(b)
(b == true) ? [0xFF].pack("C") : [0x00].pack("C")
end
|
.pack_var_int(i) ⇒ Object
53
54
55
56
57
58
59
60
|
# File 'lib/bitcoin/protocol.rb', line 53
def self.pack_var_int(i)
if i < 0xfd; [ i].pack("C")
elsif i <= 0xffff; [0xfd, i].pack("Cv")
elsif i <= 0xffffffff; [0xfe, i].pack("CV")
elsif i <= 0xffffffffffffffff; [0xff, i].pack("CQ")
else raise "int(#{i}) too large!"
end
end
|
.pack_var_string(payload) ⇒ Object
72
73
74
|
# File 'lib/bitcoin/protocol.rb', line 72
def self.pack_var_string(payload)
pack_var_int(payload.bytesize) + payload
end
|
.ping_pkt(nonce = rand(0xffffffff)) ⇒ Object
137
138
139
|
# File 'lib/bitcoin/protocol.rb', line 137
def self.ping_pkt(nonce = rand(0xffffffff))
pkt("ping", [nonce].pack("Q"))
end
|
.pkt(command, payload) ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/bitcoin/protocol.rb', line 111
def self.pkt(command, payload)
cmd = command.ljust(12, "\x00")[0...12]
length = [payload.bytesize].pack("V")
checksum = Digest::SHA256.digest(Digest::SHA256.digest(payload))[0...4]
pkt = "".force_encoding(BINARY)
pkt << Bitcoin.network[:magic_head].force_encoding(BINARY)
pkt << cmd.force_encoding(BINARY)
pkt << length
pkt << checksum
pkt << payload.dup.force_encoding(BINARY)
end
|
.pong_pkt(nonce) ⇒ Object
141
142
143
|
# File 'lib/bitcoin/protocol.rb', line 141
def self.pong_pkt(nonce)
pkt("pong", [nonce].pack("Q"))
end
|
.read_binary_file(path) ⇒ Object
186
187
188
|
# File 'lib/bitcoin/protocol.rb', line 186
def self.read_binary_file(path)
File.open(path, 'rb'){|f| f.read }
end
|
.unpack_boolean(payload) ⇒ Object
100
101
102
103
|
# File 'lib/bitcoin/protocol.rb', line 100
def self.unpack_boolean(payload)
bdata, payload = payload.unpack("Ca*")
[ (bdata == 0 ? false : true), payload ]
end
|
.unpack_var_int(payload) ⇒ Object
34
35
36
37
38
39
40
41
|
# File 'lib/bitcoin/protocol.rb', line 34
def self.unpack_var_int(payload)
case payload.unpack("C")[0] when 0xfd; payload.unpack("xva*")
when 0xfe; payload.unpack("xVa*")
when 0xff; payload.unpack("xQa*") else; payload.unpack("Ca*")
end
end
|
.unpack_var_int_array(payload) ⇒ Object
88
89
90
91
92
93
94
95
96
97
98
|
# File 'lib/bitcoin/protocol.rb', line 88
def self.unpack_var_int_array(payload) buf = StringIO.new(payload)
size = unpack_var_int_from_io(buf)
return [nil, buf.read] if size == 0
ints = []
size.times{
break if buf.eof?
ints << unpack_var_int_from_io(buf)
}
[ints, buf.read]
end
|
.unpack_var_int_from_io(io) ⇒ Object
43
44
45
46
47
48
49
50
51
|
# File 'lib/bitcoin/protocol.rb', line 43
def self.unpack_var_int_from_io(io)
uchar = io.read(1).unpack("C")[0]
case uchar
when 0xfd; io.read(2).unpack("v")[0]
when 0xfe; io.read(4).unpack("V")[0]
when 0xff; io.read(8).unpack("Q")[0]
else; uchar
end
end
|
.unpack_var_string(payload) ⇒ Object
62
63
64
65
|
# File 'lib/bitcoin/protocol.rb', line 62
def self.unpack_var_string(payload)
size, payload = unpack_var_int(payload)
size > 0 ? (_, payload = payload.unpack("a#{size}a*")) : [nil, payload]
end
|
.unpack_var_string_array(payload) ⇒ Object
76
77
78
79
80
81
82
83
84
85
86
|
# File 'lib/bitcoin/protocol.rb', line 76
def self.unpack_var_string_array(payload) buf = StringIO.new(payload)
size = unpack_var_int_from_io(buf)
return [nil, buf.read] if size == 0
strings = []
size.times{
break if buf.eof?
strings << unpack_var_string_from_io(buf)
}
[strings, buf.read]
end
|
.unpack_var_string_from_io(buf) ⇒ Object
67
68
69
70
|
# File 'lib/bitcoin/protocol.rb', line 67
def self.unpack_var_string_from_io(buf)
size = unpack_var_int_from_io(buf)
size > 0 ? buf.read(size) : nil
end
|
.verack_pkt ⇒ Object
145
146
147
|
# File 'lib/bitcoin/protocol.rb', line 145
def self.verack_pkt
pkt("verack", "")
end
|
.version_pkt(from_id, from = nil, to = nil, last_block = nil, time = nil, user_agent = nil, version = nil) ⇒ Object
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/bitcoin/protocol.rb', line 123
def self.version_pkt(from_id, from=nil, to=nil, last_block=nil, time=nil, user_agent=nil, version=nil)
opts = if from_id.is_a?(Hash)
from_id
else
STDERR.puts "Bitcoin::Protocol.version_pkt - API deprecated. please change it soon.."
{
:nonce => from_id, :from => from, :to => to, :last_block => last_block,
:time => time, :user_agent => user_agent, :version => version
}
end
version = Protocol::Version.new(opts)
version.to_pkt
end
|