diff --git a/go.mod b/go.mod index 36826c5..7e16549 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ require ( github.com/btcsuite/btcd v0.20.1-beta github.com/coreos/go-semver v0.3.0 github.com/gogo/protobuf v1.3.1 + github.com/golang/protobuf v1.3.1 github.com/ipfs/go-cid v0.0.4 github.com/jbenet/goprocess v0.1.3 github.com/libp2p/go-flow-metrics v0.0.3 diff --git a/go.sum b/go.sum index 34f6f23..30ec683 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,7 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 7f2c01c..399b6fe 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -96,6 +96,10 @@ type AddrBook interface { // If the manager has a longer TTL, the operation is a no-op for that address AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) + // AddCertifiedAddrs adds addresses from a PeerStateRecord contained + // in the given SignedEnvelope. + AddCertifiedAddrs(envelope *ic.SignedEnvelope, ttl time.Duration) error + // SetAddr calls mgr.SetAddrs(p, addr, ttl) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) @@ -107,9 +111,14 @@ type AddrBook interface { // the given oldTTL to have the given newTTL. UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) - // Addresses returns all known (and valid) addresses for a given peer + // Addrs returns all known (and valid) addresses for a given peer Addrs(p peer.ID) []ma.Multiaddr + // CertifiedAddrs returns all known addresses for a peer that have + // been certified by that peer. CertifiedAddrs are contained in + // a SignedEnvelope and added to the Peerstore using AddCertifiedAddrs. + CertifiedAddrs(p peer.ID) []ma.Multiaddr + // AddrStream returns a channel that gets all addresses for a given // peer sent on it. If new addresses are added after the call is made // they will be sent along through the channel as well. diff --git a/routing/pb/Makefile b/routing/pb/Makefile new file mode 100644 index 0000000..df34e54 --- /dev/null +++ b/routing/pb/Makefile @@ -0,0 +1,11 @@ +PB = $(wildcard *.proto) +GO = $(PB:.proto=.pb.go) + +all: $(GO) + +%.pb.go: %.proto + protoc --proto_path=$(GOPATH)/src:. --gogofaster_out=. $< + +clean: + rm -f *.pb.go + rm -f *.go diff --git a/routing/pb/routing_state.pb.go b/routing/pb/routing_state.pb.go new file mode 100644 index 0000000..82b475a --- /dev/null +++ b/routing/pb/routing_state.pb.go @@ -0,0 +1,621 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: routing_state.proto + +package routing_pb + +import ( + fmt "fmt" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +type RoutingStateRecord struct { + PeerId []byte `protobuf:"bytes,1,req,name=peerId" json:"peerId"` + Seq uint64 `protobuf:"varint,2,req,name=seq" json:"seq"` + Addresses []*RoutingStateRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses" json:"addresses,omitempty"` +} + +func (m *RoutingStateRecord) Reset() { *m = RoutingStateRecord{} } +func (m *RoutingStateRecord) String() string { return proto.CompactTextString(m) } +func (*RoutingStateRecord) ProtoMessage() {} +func (*RoutingStateRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_2bc7f62bc26d3acc, []int{0} +} +func (m *RoutingStateRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RoutingStateRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RoutingStateRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RoutingStateRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutingStateRecord.Merge(m, src) +} +func (m *RoutingStateRecord) XXX_Size() int { + return m.Size() +} +func (m *RoutingStateRecord) XXX_DiscardUnknown() { + xxx_messageInfo_RoutingStateRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutingStateRecord proto.InternalMessageInfo + +func (m *RoutingStateRecord) GetPeerId() []byte { + if m != nil { + return m.PeerId + } + return nil +} + +func (m *RoutingStateRecord) GetSeq() uint64 { + if m != nil { + return m.Seq + } + return 0 +} + +func (m *RoutingStateRecord) GetAddresses() []*RoutingStateRecord_AddressInfo { + if m != nil { + return m.Addresses + } + return nil +} + +type RoutingStateRecord_AddressInfo struct { + Multiaddr []byte `protobuf:"bytes,1,req,name=multiaddr" json:"multiaddr"` +} + +func (m *RoutingStateRecord_AddressInfo) Reset() { *m = RoutingStateRecord_AddressInfo{} } +func (m *RoutingStateRecord_AddressInfo) String() string { return proto.CompactTextString(m) } +func (*RoutingStateRecord_AddressInfo) ProtoMessage() {} +func (*RoutingStateRecord_AddressInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_2bc7f62bc26d3acc, []int{0, 0} +} +func (m *RoutingStateRecord_AddressInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RoutingStateRecord_AddressInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RoutingStateRecord_AddressInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RoutingStateRecord_AddressInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutingStateRecord_AddressInfo.Merge(m, src) +} +func (m *RoutingStateRecord_AddressInfo) XXX_Size() int { + return m.Size() +} +func (m *RoutingStateRecord_AddressInfo) XXX_DiscardUnknown() { + xxx_messageInfo_RoutingStateRecord_AddressInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutingStateRecord_AddressInfo proto.InternalMessageInfo + +func (m *RoutingStateRecord_AddressInfo) GetMultiaddr() []byte { + if m != nil { + return m.Multiaddr + } + return nil +} + +func init() { + proto.RegisterType((*RoutingStateRecord)(nil), "routing.pb.RoutingStateRecord") + proto.RegisterType((*RoutingStateRecord_AddressInfo)(nil), "routing.pb.RoutingStateRecord.AddressInfo") +} + +func init() { proto.RegisterFile("routing_state.proto", fileDescriptor_2bc7f62bc26d3acc) } + +var fileDescriptor_2bc7f62bc26d3acc = []byte{ + // 198 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2e, 0xca, 0x2f, 0x2d, + 0xc9, 0xcc, 0x4b, 0x8f, 0x2f, 0x2e, 0x49, 0x2c, 0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, + 0xe2, 0x82, 0x0a, 0xea, 0x15, 0x24, 0x29, 0x1d, 0x67, 0xe4, 0x12, 0x0a, 0x82, 0x70, 0x83, 0x41, + 0x4a, 0x82, 0x52, 0x93, 0xf3, 0x8b, 0x52, 0x84, 0x64, 0xb8, 0xd8, 0x0a, 0x52, 0x53, 0x8b, 0x3c, + 0x53, 0x24, 0x18, 0x15, 0x98, 0x34, 0x78, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0x8a, + 0x09, 0x89, 0x71, 0x31, 0x17, 0xa7, 0x16, 0x4a, 0x30, 0x29, 0x30, 0x69, 0xb0, 0x40, 0xa5, 0x40, + 0x02, 0x42, 0x1e, 0x5c, 0x9c, 0x89, 0x29, 0x29, 0x45, 0xa9, 0xc5, 0xc5, 0xa9, 0xc5, 0x12, 0xcc, + 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x5a, 0x7a, 0x08, 0xcb, 0xf4, 0x30, 0x2d, 0xd2, 0x73, 0x84, 0xa8, + 0xf7, 0xcc, 0x4b, 0xcb, 0x0f, 0x42, 0x68, 0x96, 0x32, 0xe4, 0xe2, 0x46, 0x92, 0x11, 0x52, 0xe2, + 0xe2, 0xcc, 0x2d, 0xcd, 0x29, 0xc9, 0x04, 0x29, 0x40, 0x71, 0x11, 0x42, 0xd8, 0x49, 0xe2, 0xc4, + 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, + 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0x00, 0x01, 0x00, 0x00, 0xff, 0xff, 0x13, 0x14, + 0xbe, 0xc4, 0x05, 0x01, 0x00, 0x00, +} + +func (m *RoutingStateRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoutingStateRecord) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.PeerId != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintRoutingState(dAtA, i, uint64(len(m.PeerId))) + i += copy(dAtA[i:], m.PeerId) + } + dAtA[i] = 0x10 + i++ + i = encodeVarintRoutingState(dAtA, i, uint64(m.Seq)) + if len(m.Addresses) > 0 { + for _, msg := range m.Addresses { + dAtA[i] = 0x1a + i++ + i = encodeVarintRoutingState(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + +func (m *RoutingStateRecord_AddressInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoutingStateRecord_AddressInfo) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Multiaddr != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintRoutingState(dAtA, i, uint64(len(m.Multiaddr))) + i += copy(dAtA[i:], m.Multiaddr) + } + return i, nil +} + +func encodeVarintRoutingState(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *RoutingStateRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PeerId != nil { + l = len(m.PeerId) + n += 1 + l + sovRoutingState(uint64(l)) + } + n += 1 + sovRoutingState(uint64(m.Seq)) + if len(m.Addresses) > 0 { + for _, e := range m.Addresses { + l = e.Size() + n += 1 + l + sovRoutingState(uint64(l)) + } + } + return n +} + +func (m *RoutingStateRecord_AddressInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Multiaddr != nil { + l = len(m.Multiaddr) + n += 1 + l + sovRoutingState(uint64(l)) + } + return n +} + +func sovRoutingState(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozRoutingState(x uint64) (n int) { + return sovRoutingState(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *RoutingStateRecord) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRoutingState + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RoutingStateRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RoutingStateRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PeerId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRoutingState + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRoutingState + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthRoutingState + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PeerId = append(m.PeerId[:0], dAtA[iNdEx:postIndex]...) + if m.PeerId == nil { + m.PeerId = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Seq", wireType) + } + m.Seq = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRoutingState + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Seq |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000002) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRoutingState + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRoutingState + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRoutingState + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addresses = append(m.Addresses, &RoutingStateRecord_AddressInfo{}) + if err := m.Addresses[len(m.Addresses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRoutingState(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRoutingState + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthRoutingState + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("peerId") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("seq") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RoutingStateRecord_AddressInfo) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRoutingState + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddressInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddressInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Multiaddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRoutingState + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRoutingState + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthRoutingState + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Multiaddr = append(m.Multiaddr[:0], dAtA[iNdEx:postIndex]...) + if m.Multiaddr == nil { + m.Multiaddr = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + default: + iNdEx = preIndex + skippy, err := skipRoutingState(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRoutingState + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthRoutingState + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("multiaddr") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRoutingState(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRoutingState + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRoutingState + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRoutingState + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthRoutingState + } + iNdEx += length + if iNdEx < 0 { + return 0, ErrInvalidLengthRoutingState + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRoutingState + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipRoutingState(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + if iNdEx < 0 { + return 0, ErrInvalidLengthRoutingState + } + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthRoutingState = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRoutingState = fmt.Errorf("proto: integer overflow") +) diff --git a/routing/pb/routing_state.proto b/routing/pb/routing_state.proto new file mode 100644 index 0000000..0d6f63e --- /dev/null +++ b/routing/pb/routing_state.proto @@ -0,0 +1,12 @@ +syntax = "proto2"; +package routing.pb; + +message RoutingStateRecord { + message AddressInfo { + required bytes multiaddr = 1; + } + + required bytes peerId = 1; + required uint64 seq = 2; + repeated AddressInfo addresses = 3; +} diff --git a/routing/state.go b/routing/state.go new file mode 100644 index 0000000..490f99c --- /dev/null +++ b/routing/state.go @@ -0,0 +1,116 @@ +package routing + +import ( + "errors" + "github.com/gogo/protobuf/proto" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + ma "github.com/multiformats/go-multiaddr" + pb "github.com/libp2p/go-libp2p-core/routing/pb" +) + +// The domain string used for routing state records contained in a SignedEnvelope. +const StateEnvelopeDomain = "libp2p-routing-record" + +// AnnotatedAddr will extend the Multiaddr type with additional metadata, as +// extensions are added to the routing state record spec. It's defined now to +// make refactoring simpler in the future. +type AnnotatedAddr struct { + ma.Multiaddr +} + +// RoutingState contains a snapshot of public, transient state (e.g. addresses, supported protocols) +// for a peer at a given point in time, where "time" is defined by the sequence counter +// field Seq. Greater Seq values are later in time than lesser values, but there are no +// guarantees about the wall-clock time between any two Seq values. +// +// Note that Seq values are peer-specific and can only be compared for records with equal PeerIDs. +type RoutingState struct { + // PeerID is the ID of the peer this record pertains to. + PeerID peer.ID + + // Seq is an increment-only sequence counter used to order RoutingState records in time. + Seq uint64 + + // Addresses contains the public addresses of the peer this record pertains to. + Addresses []*AnnotatedAddr +} + +// UnmarshalRoutingState unpacks a peer RoutingState record from a serialized protobuf representation. +func UnmarshalRoutingState(serialized []byte) (*RoutingState, error) { + msg := pb.RoutingStateRecord{} + err := proto.Unmarshal(serialized, &msg) + if err != nil { + return nil, err + } + id, err := peer.IDFromBytes(msg.PeerId) + if err != nil { + return nil, err + } + return &RoutingState{ + PeerID: id, + Seq: msg.Seq, + Addresses: addrsFromProtobuf(msg.Addresses), + }, nil +} + +// RoutingStateFromEnvelope unwraps a peer RoutingState record from a SignedEnvelope. +// This method will fail if the signature is invalid, or if the record +// belongs to a peer other than the one that signed the envelope. +func RoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*RoutingState, error) { + msgBytes, err := envelope.Open(StateEnvelopeDomain) + if err != nil { + return nil, err + } + state, err := UnmarshalRoutingState(msgBytes) + if err != nil { + return nil, err + } + if !state.PeerID.MatchesPublicKey(envelope.PublicKey) { + return nil, errors.New("peer id in routing state record does not match signing key") + } + return state, nil +} + +// Marshal serializes a RoutingState record to protobuf and returns its byte representation. +func (s *RoutingState) Marshal() ([]byte, error) { + id, err := s.PeerID.MarshalBinary() + if err != nil { + return nil, err + } + msg := pb.RoutingStateRecord{ + PeerId: id, + Seq: s.Seq, + Addresses: addrsToProtobuf(s.Addresses), + } + return proto.Marshal(&msg) +} + +// Multiaddrs returns the addresses from a RoutingState record without any metadata annotations. +func (s *RoutingState) Multiaddrs() []ma.Multiaddr { + out := make([]ma.Multiaddr, len(s.Addresses)) + for i, addr := range s.Addresses { + out[i] = addr.Multiaddr + } + return out +} + +func addrsFromProtobuf(addrs []*pb.RoutingStateRecord_AddressInfo) []*AnnotatedAddr { + out := make([]*AnnotatedAddr, 0) + for _, addr := range addrs { + a, err := ma.NewMultiaddrBytes(addr.Multiaddr) + if err != nil { + continue + } + out = append(out, &AnnotatedAddr{Multiaddr: a}) + } + return out +} + +func addrsToProtobuf(addrs []*AnnotatedAddr) []*pb.RoutingStateRecord_AddressInfo { + out := make([]*pb.RoutingStateRecord_AddressInfo, 0) + for _, addr := range addrs { + out = append(out, &pb.RoutingStateRecord_AddressInfo{Multiaddr: addr.Bytes()}) + } + return out +} \ No newline at end of file