Files
btc_wire_proto/spec/btc_wire_proto_spec.rb

365 lines
10 KiB
Ruby
Raw Normal View History

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 Ipv6Address do
it "should read IPv6 strings into IPv6 addresses" do
ex_obj = IPAddress("fea1:fea1:fea1:fea1:fea1:fea1:fea1:fea1")
ex = ex_obj.data
ip = Ipv6Address::read(ex)
ip.should == ex_obj
ip.to_binary_s.should == ex
ip = Ipv6Address.new(ex_obj)
ip.to_binary_s.should == ex
end
it "should read IPv4 strings into IPv6-mapped addresses" do
ip = Ipv6Address.new("127.0.0.1")
ip.should == IPAddress("::ffff:127.0.0.1")
end
it "should read IPAddress objects into IPv6/mapped addresses" do
ip = Ipv6Address.new(IPAddress("127.0.0.1"))
ip.should == (ip_m = IPAddress("::ffff:127.0.0.1"))
ip.to_binary_s.should == ip_m.data
end
it "should read arbitrary objects with #to_u128 into IPv6/mapped addresses" do
o = Object.new
class << o ; def to_u128 ; 0xffffffffffff ; end ; end
ip = Ipv6Address.new(o)
ip.should == IPAddress("::ffff:ffff:ffff")
end
it "should read Fixnums and Bignums into IPv6/mapped addresses" do
ipv4 = IPAddress("127.0.0.1") # Should still be mapped
ipv6 = IPAddress("fe80::1")
ip = Ipv6Address.new(ipv4.to_u32)
ip.should == IPAddress("::ffff:127.0.0.1")
ip = Ipv6Address.new(ipv6.to_u128)
ip.should == ipv6
end
it "should raise ArgumentError for unparseable objects" do
lambda { Ipv6Address.new("bad IP") }.should raise_error(ArgumentError)
end
end
2011-06-04 22:53:33 +01:00
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
GOOD_VERSION_DATA = 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
})
2011-06-04 22:53:33 +01:00
SRV = { :node_network => 1 }
2011-06-04 22:53:33 +01:00
describe Message do
context "Version message" do
it "should have a Version payload" do
m = Message::new(:command => 'version')
2011-06-04 22:53:33 +01:00
m.payload.selection.should == "version"
end
it "should have a :version command symbol" do
m = Message::new(: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(GOOD_VERSION_DATA)
m.magic.should == BtcWireProto::NETWORKS[:main]
m.network_name.should == :main
m.command.should == "version\x00\x00\x00\x00\x00"
m.payload_len.should == 85
m.has_parameter?(:checksum).should be_false
2011-06-04 22:53:33 +01:00
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
m.to_binary_s.should == GOOD_VERSION_DATA
end
it "should generate binary data correctly" do
m = Message::read(GOOD_VERSION_DATA)
ex = Message::new(
:magic => BtcWireProto::NETWORKS[:main], :command => 'version',
:payload => {
:version => 31900, :services => {:node_network => 1},
:timestamp => 1292899814, :nonce => 0x1357B43A2C209DDD,
:sub_version => "", :start_height => 98645,
:addr_me => { :services => SRV, :ip => "10.0.0.1", :port => 56054 },
:addr_you => { :services => SRV, :ip => "10.0.0.2", :port => 8333 }
}
)
m.should == ex
ex.to_binary_s.should == GOOD_VERSION_DATA
2011-06-04 22:53:33 +01:00
end
end
GOOD_VERACK_DATA = binary(%w{
F9 BE B4 D9 76 65 72 61 63 6B 00 00 00 00 00 00 00 00 00 00
})
2011-06-04 22:53:33 +01:00
context "Verack message" do
2011-06-04 22:53:33 +01:00
it "should have no payload" do
m = Message.new(:command => "verack")
2011-06-04 22:53:33 +01:00
m.payload.selection.should == "null"
end
it "should have a :verack command symbol" do
m = Message.new(: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(GOOD_VERACK_DATA)
m.magic.should == BtcWireProto::NETWORKS[:main]
m.command.should == "verack\x00\x00\x00\x00\x00\x00"
m.payload_len.should == 0
m.has_parameter?(:chcksum).should be_false
m.to_binary_s.should == GOOD_VERACK_DATA
2011-06-04 22:53:33 +01:00
end
end
end
end