2011-06-04 22:53:33 +01:00
|
|
|
require 'spec_helper'
|
|
|
|
require 'btc_wire_proto'
|
|
|
|
|
|
|
|
# Fixtures data. Taken from: https://en.bitcoin.it/wiki/Protocol_specification
|
|
|
|
|
|
|
|
include ::BtcWireProto
|
|
|
|
|
|
|
|
describe ::BtcWireProto do
|
|
|
|
|
|
|
|
# Payload fragments
|
|
|
|
describe ServicesMask do
|
|
|
|
it "should have node_network set to false when its bit is 0" do
|
|
|
|
s = ServicesMask::read("\x00" * 8) # All 64 bits unset
|
|
|
|
s.node_network.should == 0
|
|
|
|
|
|
|
|
s = ServicesMask::read(binary(%w{01 00 00 00 00 00 00 00}))
|
|
|
|
s.node_network.should == 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe NetAddr do
|
|
|
|
it "should have all fields set to 0 when the input data is all zeroes" do
|
|
|
|
na = NetAddr::read("\x00" * 26)
|
|
|
|
|
|
|
|
na.services.node_network.should == 0
|
|
|
|
na.ip.to_u128.should == 0
|
|
|
|
na.port.should == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
it "Should allow the Ip field to be set with Ruby native types" do
|
|
|
|
na = NetAddr::read("\x00" * 26)
|
|
|
|
mip = IPAddress("::ffff:0.0.0.1")
|
|
|
|
na.ip = mip
|
|
|
|
na.ip.to_u128.should == mip.to_u128
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should have the fields set appropriately when fed binary data" do
|
|
|
|
na = NetAddr::read(
|
|
|
|
binary(%w{
|
|
|
|
01 00 00 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 00 FF FF 0A 00 00 01 20 8D
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
na.services.node_network.should == 1
|
|
|
|
na.ip.to_s.should == "::ffff:10.0.0.1"
|
|
|
|
na.port.should == 8333
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
describe TimestampedNetAddr do
|
|
|
|
it "should leverage NetAddr" do
|
|
|
|
tna = TimestampedNetAddr::read("\x00" * 30)
|
|
|
|
tna.net_addr.class.should == BtcWireProto::NetAddr
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should have all fields set to 0 when the input data is all zeroes" do
|
|
|
|
tna = TimestampedNetAddr::read("\x00" * 30)
|
|
|
|
tna.timestamp.should == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should have the fields set appropriately when fed binary data" do
|
|
|
|
tna = TimestampedNetAddr::read(
|
|
|
|
binary(%w{
|
|
|
|
E2 15 10 4D 01 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 00 00 00 FF FF 0A 00 00 01 20 8D
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
tna.timestamp.should == 1292899810
|
|
|
|
|
|
|
|
tna.net_addr.services.node_network.should == 1
|
|
|
|
tna.net_addr.ip.to_s.should == "::ffff:10.0.0.1"
|
|
|
|
tna.net_addr.port.should == 8333
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
describe VarInt do
|
|
|
|
it "should hold numbers < 0x00000000 in nine bytes" do
|
|
|
|
bin_minus_1 = "\xff" + "\x00\x00\x00\x00" + "\x01\x00\x00\x00"
|
|
|
|
a = VarInt::read(bin_minus_1)
|
|
|
|
a.should == -1
|
|
|
|
a.num_bytes.should == 9
|
|
|
|
a.to_binary_s.should == bin_minus_1
|
|
|
|
|
|
|
|
a = VarInt::read("\xff" * 9)
|
|
|
|
a.should == -(2**64 - 1)
|
|
|
|
a.num_bytes.should == 9
|
|
|
|
a.to_binary_s.should == "\xff" * 9
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should hold numbers >= 0x00000000 and < 0x000000fd in one byte" do
|
|
|
|
a = VarInt::read("\x00")
|
|
|
|
a.should == 0x00
|
|
|
|
a.num_bytes.should == 1
|
|
|
|
a.to_binary_s.should == "\x00"
|
|
|
|
|
|
|
|
a = VarInt::read("\xFC")
|
|
|
|
a.should == 0xFC
|
|
|
|
a.num_bytes.should == 1
|
|
|
|
a.to_binary_s.should == "\xFC"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should hold numbers >= 0x000000fd and < 0x00010000 in three bytes" do
|
|
|
|
a = VarInt::read("\xFD\xFD\x00")
|
|
|
|
a.should == 0xFD
|
|
|
|
a.num_bytes.should == 3
|
|
|
|
a.to_binary_s.should == "\xFD\xFD\x00"
|
|
|
|
|
|
|
|
a = VarInt::read("\xFD\xFF\xFF")
|
|
|
|
a.should == 0xFFFF
|
|
|
|
a.num_bytes.should == 3
|
|
|
|
a.to_binary_s.should == "\xFD\xFF\xFF"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should hold numbers >= 0x00010000 and < 0xffffffff in five bytes" do
|
|
|
|
a = VarInt::read("\xFE\x00\x00\x01\x00")
|
|
|
|
a.should == 0x10000
|
|
|
|
a.num_bytes.should == 5
|
|
|
|
a.to_binary_s.should == "\xFE\x00\x00\x01\x00"
|
|
|
|
|
|
|
|
a = VarInt::read("\xFE\xFF\xFF\xFF\xFF")
|
|
|
|
a.should == 0xFFFFFFFF
|
|
|
|
a.num_bytes.should == 5
|
|
|
|
a.to_binary_s.should == "\xFE\xFF\xFF\xFF\xFF"
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe VarStr do
|
|
|
|
it "should store string length in a var_int" do
|
|
|
|
a = VarStr::read("\x04abcd")
|
|
|
|
a.should == "abcd"
|
|
|
|
a.num_bytes.should == 5
|
|
|
|
a.to_binary_s.should == "\x04abcd"
|
|
|
|
|
|
|
|
a = VarStr::read("\xFD\xFF\xFF" + "A" * 0xFFFF)
|
|
|
|
a.should == "A" * 0xFFFF
|
|
|
|
a.num_bytes.should == 0xFFFF + 3
|
|
|
|
a.to_binary_s.should == "\xFD\xFF\xFF" + "A" * 0xFFFF
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe InventoryVector do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Sha256 do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe TransactionIn do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe TransactionOut do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe BlockHdr do
|
|
|
|
end
|
|
|
|
|
|
|
|
# Payloads
|
|
|
|
|
|
|
|
describe Version do
|
|
|
|
it "should interpret binary data correctly" do
|
|
|
|
ver = Version::read(binary(%w{
|
|
|
|
9C 7C 00 00 01 00 00 00 00 00 00 00 E6 15 10 4D 00 00 00 00
|
|
|
|
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF
|
|
|
|
0A 00 00 01 DA F6 01 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 FF FF 0A 00 00 02 20 8D DD 9D 20 2C 3A B4 57 13
|
|
|
|
00 55 81 01 00
|
|
|
|
}))
|
|
|
|
|
|
|
|
ver.version.should == 31900
|
|
|
|
ver.services.node_network.should == 1
|
|
|
|
ver.timestamp.should == 1292899814
|
|
|
|
ver.addr_me.class.should == NetAddr
|
|
|
|
ver.addr_you.class.should == NetAddr
|
|
|
|
ver.nonce.should == 0x1357B43A2C209DDD
|
|
|
|
ver.sub_version.should == ""
|
|
|
|
ver.start_height.should == 98645
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should exclude some fields by version" do
|
|
|
|
v = Version::read([1].pack("V") + "\x00" * 42)
|
|
|
|
v.num_bytes.should == 46
|
|
|
|
v = Version::read([106].pack("V") + "\x00" * 77)
|
|
|
|
v.num_bytes.should == 81
|
|
|
|
v = Version::read([209].pack("V") + "\x00" * 81)
|
|
|
|
v.num_bytes.should == 85
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe AddrPre31402 do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe AddrFrom31402 do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Inventory do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe BlockSpec do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Transaction do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Block do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Headers do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe CheckOrder do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe SubmitOrder do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Reply do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Alert do
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Messages
|
|
|
|
describe MessageHdr do
|
|
|
|
end
|
|
|
|
|
|
|
|
describe Message do
|
|
|
|
context "Version message" do
|
|
|
|
it "should have a Version payload" do
|
|
|
|
m = Message::new(:header => {:command => 'version'})
|
|
|
|
m.payload.selection.should == "version"
|
|
|
|
end
|
|
|
|
|
2011-06-09 22:03:57 +01:00
|
|
|
it "should have a :version command symbol" do
|
|
|
|
m = Message::new(:header => {:command => 'version'})
|
|
|
|
m.cmd_sym.should == :version
|
|
|
|
end
|
|
|
|
|
2011-06-04 22:53:33 +01:00
|
|
|
it "should parse binary data correctly" do
|
|
|
|
m = Message::read(binary(%w{
|
|
|
|
F9 BE B4 D9 76 65 72 73 69 6F 6E 00 00 00 00 00 55 00 00
|
|
|
|
00 9C 7C 00 00 01 00 00 00 00 00 00 00 E6 15 10 4D 00 00
|
|
|
|
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 FF FF 0A 00 00 01 DA F6 01 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 00 00 00 00 FF FF 0A 00 00 02 20 8D DD 9D 20
|
|
|
|
2C 3A B4 57 13 00 55 81 01 00
|
|
|
|
}))
|
|
|
|
m.header.magic.should == BtcWireProto::NETWORKS[:main]
|
|
|
|
m.header.command.should == "version\x00\x00\x00\x00\x00"
|
|
|
|
m.header.payload_len.should == 85
|
|
|
|
m.header.has_parameter?(:checksum).should be_false
|
|
|
|
m.payload.version.should == 31900
|
|
|
|
m.payload.services.node_network.should == 1
|
|
|
|
m.payload.timestamp.should == 1292899814
|
|
|
|
m.payload.addr_me.class.should == NetAddr
|
|
|
|
m.payload.addr_you.class.should == NetAddr
|
|
|
|
m.payload.nonce.should == 0x1357B43A2C209DDD
|
|
|
|
m.payload.sub_version.should == ""
|
|
|
|
m.payload.start_height.should == 98645
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "Verack message" do
|
|
|
|
it "should have no payload" do
|
|
|
|
m = Message.new(:header => {:command => "verack"})
|
|
|
|
m.payload.selection.should == "null"
|
|
|
|
end
|
2011-06-09 22:03:57 +01:00
|
|
|
|
|
|
|
it "should have a :verack command symbol" do
|
|
|
|
m = Message.new(:header => {:command => "verack"})
|
|
|
|
m.cmd_sym.should == :verack
|
|
|
|
end
|
2011-06-04 22:53:33 +01:00
|
|
|
|
|
|
|
it "should parse the binary data correctly" do
|
|
|
|
m = Message::read(binary(%w{
|
|
|
|
F9 BE B4 D9 76 65 72 61 63 6B 00 00 00 00 00 00 00 00 00 00
|
|
|
|
}))
|
|
|
|
m.header.magic.should == BtcWireProto::NETWORKS[:main]
|
|
|
|
m.header.command.should == "verack\x00\x00\x00\x00\x00\x00"
|
|
|
|
m.header.payload_len.should == 0
|
|
|
|
m.header.has_parameter?(:chcksum).should be_false
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|