From f4c9da502322c4d868d48ca5e595f0fd8da434b9 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Wed, 6 Nov 2019 12:24:34 -0500 Subject: [PATCH 01/69] add SignedEnvelope type --- crypto/envelope.go | 79 +++++++ crypto/pb/crypto.pb.go | 493 ++++++++++++++++++++++++++++++++++++----- crypto/pb/crypto.proto | 7 + 3 files changed, 519 insertions(+), 60 deletions(-) create mode 100644 crypto/envelope.go diff --git a/crypto/envelope.go b/crypto/envelope.go new file mode 100644 index 00000000..a60a54c7 --- /dev/null +++ b/crypto/envelope.go @@ -0,0 +1,79 @@ +package crypto + +import ( + "bytes" + "encoding/binary" + "errors" + "github.com/golang/protobuf/proto" + pb "github.com/libp2p/go-libp2p-core/crypto/pb" +) + +func MakeEnvelope(privateKey PrivKey, domain string, typeHint []byte, contents []byte) (*pb.SignedEnvelope, error) { + pubKey, err := PublicKeyToProto(privateKey.GetPublic()) + if err != nil { + return nil, err + } + + toSign := makeSigBuffer(domain, typeHint, contents) + sig, err := privateKey.Sign(toSign) + if err != nil { + return nil, err + } + + return &pb.SignedEnvelope{ + PublicKey: pubKey, + TypeHint: typeHint, + Contents: contents, + Signature: sig, + }, nil +} + +func ValidateEnvelope(domain string, envelope *pb.SignedEnvelope) (bool, error) { + key, err := PublicKeyFromProto(envelope.PublicKey) + if err != nil { + return false, err + } + toVerify := makeSigBuffer(domain, envelope.TypeHint, envelope.Contents) + return key.Verify(toVerify, envelope.Signature) +} + +func MarshalEnvelope(envelope *pb.SignedEnvelope) ([]byte, error) { + return proto.Marshal(envelope) +} + +func UnmarshalEnvelope(serializedEnvelope []byte) (*pb.SignedEnvelope, error) { + e := pb.SignedEnvelope{} + if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { + return nil, err + } + return &e, nil +} + +func OpenEnvelope(domain string, envelope *pb.SignedEnvelope) ([]byte, error) { + valid, err := ValidateEnvelope(domain, envelope) + if err != nil { + return nil, err + } + if !valid { + return nil, errors.New("invalid signature") + } + return envelope.Contents, nil +} + +func makeSigBuffer(domain string, typeHint []byte, content []byte) []byte { + b := bytes.Buffer{} + domainBytes := []byte(domain) + b.Write(encodedSize(domainBytes)) + b.Write(domainBytes) + b.Write(encodedSize(typeHint)) + b.Write(typeHint) + b.Write(encodedSize(content)) + b.Write(content) + return b.Bytes() +} + +func encodedSize(content []byte) []byte { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(len(content))) + return b +} \ No newline at end of file diff --git a/crypto/pb/crypto.pb.go b/crypto/pb/crypto.pb.go index 072fad9c..9534add1 100644 --- a/crypto/pb/crypto.pb.go +++ b/crypto/pb/crypto.pb.go @@ -9,7 +9,6 @@ import ( proto "github.com/gogo/protobuf/proto" io "io" math "math" - math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -21,7 +20,7 @@ var _ = math.Inf // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type KeyType int32 @@ -88,7 +87,7 @@ func (m *PublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PublicKey.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) + n, err := m.MarshalTo(b) if err != nil { return nil, err } @@ -140,7 +139,7 @@ func (m *PrivateKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PrivateKey.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) + n, err := m.MarshalTo(b) if err != nil { return nil, err } @@ -173,35 +172,109 @@ func (m *PrivateKey) GetData() []byte { return nil } +type SignedEnvelope struct { + PublicKey *PublicKey `protobuf:"bytes,1,req,name=PublicKey" json:"PublicKey,omitempty"` + TypeHint []byte `protobuf:"bytes,2,req,name=TypeHint" json:"TypeHint"` + Contents []byte `protobuf:"bytes,3,req,name=Contents" json:"Contents"` + Signature []byte `protobuf:"bytes,4,req,name=Signature" json:"Signature"` +} + +func (m *SignedEnvelope) Reset() { *m = SignedEnvelope{} } +func (m *SignedEnvelope) String() string { return proto.CompactTextString(m) } +func (*SignedEnvelope) ProtoMessage() {} +func (*SignedEnvelope) Descriptor() ([]byte, []int) { + return fileDescriptor_527278fb02d03321, []int{2} +} +func (m *SignedEnvelope) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SignedEnvelope.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 *SignedEnvelope) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignedEnvelope.Merge(m, src) +} +func (m *SignedEnvelope) XXX_Size() int { + return m.Size() +} +func (m *SignedEnvelope) XXX_DiscardUnknown() { + xxx_messageInfo_SignedEnvelope.DiscardUnknown(m) +} + +var xxx_messageInfo_SignedEnvelope proto.InternalMessageInfo + +func (m *SignedEnvelope) GetPublicKey() *PublicKey { + if m != nil { + return m.PublicKey + } + return nil +} + +func (m *SignedEnvelope) GetTypeHint() []byte { + if m != nil { + return m.TypeHint + } + return nil +} + +func (m *SignedEnvelope) GetContents() []byte { + if m != nil { + return m.Contents + } + return nil +} + +func (m *SignedEnvelope) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + func init() { proto.RegisterEnum("crypto.pb.KeyType", KeyType_name, KeyType_value) proto.RegisterType((*PublicKey)(nil), "crypto.pb.PublicKey") proto.RegisterType((*PrivateKey)(nil), "crypto.pb.PrivateKey") + proto.RegisterType((*SignedEnvelope)(nil), "crypto.pb.SignedEnvelope") } func init() { proto.RegisterFile("crypto.proto", fileDescriptor_527278fb02d03321) } var fileDescriptor_527278fb02d03321 = []byte{ - // 203 bytes of a gzipped FileDescriptorProto + // 285 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0xf1, 0x92, 0x94, 0x82, 0xb9, 0x38, 0x03, 0x4a, 0x93, 0x72, 0x32, 0x93, 0xbd, 0x53, 0x2b, 0x85, 0x74, 0xb8, 0x58, 0x42, 0x2a, 0x0b, 0x52, 0x25, 0x18, 0x15, 0x98, 0x34, 0xf8, 0x8c, 0x84, 0xf4, 0xe0, 0xca, 0xf4, 0xbc, 0x53, 0x2b, 0x41, 0x32, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x81, 0x55, 0x09, 0x49, 0x70, 0xb1, 0xb8, 0x24, 0x96, 0x24, 0x4a, 0x30, 0x29, 0x30, 0x69, 0xf0, 0xc0, 0x64, 0x40, 0x22, 0x4a, 0x21, - 0x5c, 0x5c, 0x01, 0x45, 0x99, 0x65, 0x89, 0x25, 0xa9, 0x54, 0x34, 0x55, 0xcb, 0x92, 0x8b, 0x1d, - 0xaa, 0x41, 0x88, 0x9d, 0x8b, 0x39, 0x28, 0xd8, 0x51, 0x80, 0x41, 0x88, 0x9b, 0x8b, 0xdd, 0x35, - 0xc5, 0xc8, 0xd4, 0xd4, 0xd0, 0x52, 0x80, 0x51, 0x88, 0x97, 0x8b, 0x33, 0x38, 0x35, 0xb9, 0xc0, - 0xc8, 0xd4, 0x2c, 0xdb, 0x50, 0x80, 0x49, 0x88, 0x93, 0x8b, 0xd5, 0xd5, 0xd9, 0x25, 0xd8, 0x51, - 0x80, 0xd9, 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, 0xbe, 0xd4, 0xff, 0x19, 0x01, 0x00, 0x00, + 0x5c, 0x5c, 0x01, 0x45, 0x99, 0x65, 0x89, 0x25, 0xa9, 0xd4, 0x34, 0x75, 0x0d, 0x23, 0x17, 0x5f, + 0x70, 0x66, 0x7a, 0x5e, 0x6a, 0x8a, 0x6b, 0x5e, 0x59, 0x6a, 0x4e, 0x7e, 0x41, 0xaa, 0x90, 0x11, + 0x92, 0xeb, 0xc1, 0xe6, 0x73, 0x1b, 0x89, 0x20, 0x99, 0x0f, 0x97, 0x0b, 0x42, 0xf2, 0xa4, 0x02, + 0x17, 0x07, 0xc8, 0x22, 0x8f, 0xcc, 0xbc, 0x12, 0x14, 0x4b, 0xe0, 0xa2, 0x20, 0x15, 0xce, 0xf9, + 0x79, 0x25, 0xa9, 0x79, 0x25, 0xc5, 0x12, 0xcc, 0xc8, 0x2a, 0x60, 0xa2, 0x42, 0x4a, 0x5c, 0x9c, + 0x20, 0x97, 0x24, 0x96, 0x94, 0x16, 0xa5, 0x4a, 0xb0, 0x20, 0x29, 0x41, 0x08, 0x6b, 0x59, 0x72, + 0xb1, 0x43, 0xfd, 0x27, 0xc4, 0xce, 0xc5, 0x1c, 0x14, 0xec, 0x28, 0xc0, 0x20, 0xc4, 0xcd, 0xc5, + 0xee, 0x9a, 0x62, 0x64, 0x6a, 0x6a, 0x68, 0x29, 0xc0, 0x28, 0xc4, 0xcb, 0xc5, 0x19, 0x9c, 0x9a, + 0x5c, 0x60, 0x64, 0x6a, 0x96, 0x6d, 0x28, 0xc0, 0x24, 0xc4, 0xc9, 0xc5, 0xea, 0xea, 0xec, 0x12, + 0xec, 0x28, 0xc0, 0xec, 0x24, 0x71, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, + 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x80, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x9b, 0xc0, 0x25, 0x32, 0xc8, 0x01, 0x00, 0x00, } func (m *PublicKey) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -209,32 +282,26 @@ func (m *PublicKey) Marshal() (dAtA []byte, err error) { } func (m *PublicKey) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PublicKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0x8 + i++ + i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) if m.Data != nil { - i -= len(m.Data) - copy(dAtA[i:], m.Data) - i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) - i-- dAtA[i] = 0x12 + i++ + i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) + i += copy(dAtA[i:], m.Data) } - i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) - i-- - dAtA[i] = 0x8 - return len(dAtA) - i, nil + return i, nil } func (m *PrivateKey) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -242,38 +309,78 @@ func (m *PrivateKey) Marshal() (dAtA []byte, err error) { } func (m *PrivateKey) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0x8 + i++ + i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) + if m.Data != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) + i += copy(dAtA[i:], m.Data) + } + return i, nil +} + +func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil } -func (m *PrivateKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) +func (m *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { + var i int _ = i var l int _ = l - if m.Data != nil { - i -= len(m.Data) - copy(dAtA[i:], m.Data) - i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) - i-- + if m.PublicKey == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("PublicKey") + } else { + dAtA[i] = 0xa + i++ + i = encodeVarintCrypto(dAtA, i, uint64(m.PublicKey.Size())) + n1, err := m.PublicKey.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } + if m.TypeHint != nil { dAtA[i] = 0x12 + i++ + i = encodeVarintCrypto(dAtA, i, uint64(len(m.TypeHint))) + i += copy(dAtA[i:], m.TypeHint) } - i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) - i-- - dAtA[i] = 0x8 - return len(dAtA) - i, nil + if m.Contents != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintCrypto(dAtA, i, uint64(len(m.Contents))) + i += copy(dAtA[i:], m.Contents) + } + if m.Signature != nil { + dAtA[i] = 0x22 + i++ + i = encodeVarintCrypto(dAtA, i, uint64(len(m.Signature))) + i += copy(dAtA[i:], m.Signature) + } + return i, nil } func encodeVarintCrypto(dAtA []byte, offset int, v uint64) int { - offset -= sovCrypto(v) - base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return base + return offset + 1 } func (m *PublicKey) Size() (n int) { if m == nil { @@ -303,8 +410,40 @@ func (m *PrivateKey) Size() (n int) { return n } +func (m *SignedEnvelope) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PublicKey != nil { + l = m.PublicKey.Size() + n += 1 + l + sovCrypto(uint64(l)) + } + if m.TypeHint != nil { + l = len(m.TypeHint) + n += 1 + l + sovCrypto(uint64(l)) + } + if m.Contents != nil { + l = len(m.Contents) + n += 1 + l + sovCrypto(uint64(l)) + } + if m.Signature != nil { + l = len(m.Signature) + n += 1 + l + sovCrypto(uint64(l)) + } + return n +} + func sovCrypto(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n } func sozCrypto(x uint64) (n int) { return sovCrypto(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -539,10 +678,217 @@ func (m *PrivateKey) Unmarshal(dAtA []byte) error { } return nil } +func (m *SignedEnvelope) 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 ErrIntOverflowCrypto + } + 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: SignedEnvelope: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SignedEnvelope: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCrypto + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCrypto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PublicKey == nil { + m.PublicKey = &PublicKey{} + } + if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeHint", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCrypto + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCrypto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TypeHint = append(m.TypeHint[:0], dAtA[iNdEx:postIndex]...) + if m.TypeHint == nil { + m.TypeHint = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000002) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contents", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCrypto + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCrypto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contents = append(m.Contents[:0], dAtA[iNdEx:postIndex]...) + if m.Contents == nil { + m.Contents = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000004) + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCrypto + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCrypto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000008) + default: + iNdEx = preIndex + skippy, err := skipCrypto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCrypto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCrypto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("PublicKey") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("TypeHint") + } + if hasFields[0]&uint64(0x00000004) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Contents") + } + if hasFields[0]&uint64(0x00000008) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Signature") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipCrypto(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 - depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -574,8 +920,10 @@ func skipCrypto(dAtA []byte) (n int, err error) { break } } + return iNdEx, nil case 1: iNdEx += 8 + return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -596,30 +944,55 @@ func skipCrypto(dAtA []byte) (n int, err error) { return 0, ErrInvalidLengthCrypto } iNdEx += length + if iNdEx < 0 { + return 0, ErrInvalidLengthCrypto + } + return iNdEx, nil case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupCrypto + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrypto + } + 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 := skipCrypto(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + if iNdEx < 0 { + return 0, ErrInvalidLengthCrypto + } } - depth-- + 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) } - if iNdEx < 0 { - return 0, ErrInvalidLengthCrypto - } - if depth == 0 { - return iNdEx, nil - } } - return 0, io.ErrUnexpectedEOF + panic("unreachable") } var ( - ErrInvalidLengthCrypto = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowCrypto = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupCrypto = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthCrypto = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCrypto = fmt.Errorf("proto: integer overflow") ) diff --git a/crypto/pb/crypto.proto b/crypto/pb/crypto.proto index cb5cee8a..7960d7b5 100644 --- a/crypto/pb/crypto.proto +++ b/crypto/pb/crypto.proto @@ -18,3 +18,10 @@ message PrivateKey { required KeyType Type = 1; required bytes Data = 2; } + +message SignedEnvelope { + required PublicKey PublicKey = 1; + required bytes TypeHint = 2; + required bytes Contents = 3; + required bytes Signature = 4; +} \ No newline at end of file From 133f8915443041a039af0e305c978b16881200e6 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 7 Nov 2019 10:37:30 -0500 Subject: [PATCH 02/69] use struct for SignedEnvelope instead of exposing protobuf directly --- crypto/envelope.go | 72 ++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index a60a54c7..86181fdb 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -6,58 +6,80 @@ import ( "errors" "github.com/golang/protobuf/proto" pb "github.com/libp2p/go-libp2p-core/crypto/pb" + "github.com/libp2p/go-libp2p-core/peer" ) -func MakeEnvelope(privateKey PrivKey, domain string, typeHint []byte, contents []byte) (*pb.SignedEnvelope, error) { - pubKey, err := PublicKeyToProto(privateKey.GetPublic()) - if err != nil { - return nil, err - } +type SignedEnvelope struct { + PublicKey PubKey + TypeHint []byte + contents []byte + signature []byte +} +func MakeEnvelope(privateKey PrivKey, domain string, typeHint []byte, contents []byte) (*SignedEnvelope, error) { toSign := makeSigBuffer(domain, typeHint, contents) sig, err := privateKey.Sign(toSign) if err != nil { return nil, err } - return &pb.SignedEnvelope{ - PublicKey: pubKey, - TypeHint: typeHint, - Contents: contents, - Signature: sig, + return &SignedEnvelope{ + PublicKey: privateKey.GetPublic(), + TypeHint: typeHint, + contents: contents, + signature: sig, }, nil } -func ValidateEnvelope(domain string, envelope *pb.SignedEnvelope) (bool, error) { - key, err := PublicKeyFromProto(envelope.PublicKey) +func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { + e := pb.SignedEnvelope{} + if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { + return nil, err + } + key, err := PublicKeyFromProto(e.PublicKey) if err != nil { - return false, err + return nil, err } - toVerify := makeSigBuffer(domain, envelope.TypeHint, envelope.Contents) - return key.Verify(toVerify, envelope.Signature) + return &SignedEnvelope{ + PublicKey: key, + TypeHint: e.TypeHint, + contents: e.Contents, + signature: e.Signature, + }, nil } -func MarshalEnvelope(envelope *pb.SignedEnvelope) ([]byte, error) { - return proto.Marshal(envelope) +func (e *SignedEnvelope) SignerID() (peer.ID, error) { + return peer.IDFromPublicKey(e.PublicKey) } -func UnmarshalEnvelope(serializedEnvelope []byte) (*pb.SignedEnvelope, error) { - e := pb.SignedEnvelope{} - if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { +func (e *SignedEnvelope) Validate(domain string) (bool, error) { + toVerify := makeSigBuffer(domain, e.TypeHint, e.contents) + return e.PublicKey.Verify(toVerify, e.signature) +} + +func (e *SignedEnvelope) Marshal() ([]byte, error) { + key, err := PublicKeyToProto(e.PublicKey) + if err != nil { return nil, err } - return &e, nil + msg := pb.SignedEnvelope{ + PublicKey: key, + TypeHint: e.TypeHint, + Contents: e.contents, + Signature: e.signature, + } + return proto.Marshal(&msg) } -func OpenEnvelope(domain string, envelope *pb.SignedEnvelope) ([]byte, error) { - valid, err := ValidateEnvelope(domain, envelope) +func (e *SignedEnvelope) Open(domain string) ([]byte, error) { + valid, err := e.Validate(domain) if err != nil { return nil, err } if !valid { - return nil, errors.New("invalid signature") + return nil, errors.New("invalid signature or incorrect domain") } - return envelope.Contents, nil + return e.contents, nil } func makeSigBuffer(domain string, typeHint []byte, content []byte) []byte { From cc866a8a184207a3ced5543a9cbddb417c86c8c0 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 7 Nov 2019 10:56:28 -0500 Subject: [PATCH 03/69] doc comments for envelopes --- crypto/envelope.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crypto/envelope.go b/crypto/envelope.go index 86181fdb..1f9cf410 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -9,14 +9,40 @@ import ( "github.com/libp2p/go-libp2p-core/peer" ) +// SignedEnvelope contains an arbitrary []byte payload, signed by a libp2p peer. +// Envelopes are signed in the context of a particular "domain", which is a string +// specified when creating and verifying the envelope. You must know the domain +// string used to produce the envelope in order to verify the signature and +// access the contents. type SignedEnvelope struct { + + // The public key that can be used to verify the signature and derive the peer id of the signer. PublicKey PubKey + + // A binary identifier that indicates what kind of data is contained in the payload. + // TODO(yusef): enforce multicodec prefix TypeHint []byte + + // The envelope payload. This is private to discourage accessing the payload without verifying the signature. + // To access, use the Open method. contents []byte + + // The signature of the domain string, type hint, and contents. signature []byte } +var errEmptyDomain = errors.New("envelope domain must not be empty") + +// MakeEnvelope constructs a new SignedEnvelope using the given privateKey. +// +// The required 'domain' string contextualizes the envelope for a particular purpose, +// and must be supplied when verifying the signature. +// +// The 'typeHint' field indicates what kind of data is contained and may be empty. func MakeEnvelope(privateKey PrivKey, domain string, typeHint []byte, contents []byte) (*SignedEnvelope, error) { + if len(domain) == 0 { + return nil, errEmptyDomain + } toSign := makeSigBuffer(domain, typeHint, contents) sig, err := privateKey.Sign(toSign) if err != nil { @@ -31,6 +57,8 @@ func MakeEnvelope(privateKey PrivKey, domain string, typeHint []byte, contents [ }, nil } +// UnmarshalEnvelope converts a serialized protobuf representation of an envelope +// into a SignedEnvelope struct. func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { e := pb.SignedEnvelope{} if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { @@ -48,15 +76,20 @@ func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { }, nil } +// SignerID returns the peer.ID of the peer who produced the SignedEnvelope. func (e *SignedEnvelope) SignerID() (peer.ID, error) { return peer.IDFromPublicKey(e.PublicKey) } +// Validate returns true if the envelope signature is valid for the given 'domain', +// or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) Validate(domain string) (bool, error) { toVerify := makeSigBuffer(domain, e.TypeHint, e.contents) return e.PublicKey.Verify(toVerify, e.signature) } +// Marshal returns a []byte containing a serialized protobuf representation of +// the SignedEnvelope. func (e *SignedEnvelope) Marshal() ([]byte, error) { key, err := PublicKeyToProto(e.PublicKey) if err != nil { @@ -71,6 +104,9 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { return proto.Marshal(&msg) } +// Open validates the signature (within the given 'domain') and returns +// the contents of the envelope. Will fail with an error if the signature +// is invalid. func (e *SignedEnvelope) Open(domain string) ([]byte, error) { valid, err := e.Validate(domain) if err != nil { @@ -82,6 +118,7 @@ func (e *SignedEnvelope) Open(domain string) ([]byte, error) { return e.contents, nil } +// makeSigBuffer is a helper function that prepares a buffer to sign or verify. func makeSigBuffer(domain string, typeHint []byte, content []byte) []byte { b := bytes.Buffer{} domainBytes := []byte(domain) From 71be7ba804c299ba18929397cb7afa9154242d48 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 7 Nov 2019 12:01:00 -0500 Subject: [PATCH 04/69] tests for SignedEnvelopes --- crypto/envelope.go | 13 ++-- crypto/envelope_test.go | 150 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 crypto/envelope_test.go diff --git a/crypto/envelope.go b/crypto/envelope.go index 1f9cf410..daf891f7 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -6,7 +6,6 @@ import ( "errors" "github.com/golang/protobuf/proto" pb "github.com/libp2p/go-libp2p-core/crypto/pb" - "github.com/libp2p/go-libp2p-core/peer" ) // SignedEnvelope contains an arbitrary []byte payload, signed by a libp2p peer. @@ -76,11 +75,6 @@ func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { }, nil } -// SignerID returns the peer.ID of the peer who produced the SignedEnvelope. -func (e *SignedEnvelope) SignerID() (peer.ID, error) { - return peer.IDFromPublicKey(e.PublicKey) -} - // Validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) Validate(domain string) (bool, error) { @@ -118,6 +112,13 @@ func (e *SignedEnvelope) Open(domain string) ([]byte, error) { return e.contents, nil } +func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { + return e.PublicKey.Equals(other.PublicKey) && + bytes.Compare(e.TypeHint, other.TypeHint) == 0 && + bytes.Compare(e.contents, other.contents) == 0 && + bytes.Compare(e.signature, other.signature) == 0 +} + // makeSigBuffer is a helper function that prepares a buffer to sign or verify. func makeSigBuffer(domain string, typeHint []byte, content []byte) []byte { b := bytes.Buffer{} diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go new file mode 100644 index 00000000..860ade36 --- /dev/null +++ b/crypto/envelope_test.go @@ -0,0 +1,150 @@ +package crypto_test + +import ( + "bytes" + "github.com/gogo/protobuf/proto" + . "github.com/libp2p/go-libp2p-core/crypto" + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + "github.com/libp2p/go-libp2p-core/test" + "testing" +) + +// Make an envelope, verify & open it, marshal & unmarshal it +func TestEnvelopeHappyPath(t *testing.T) { + priv, pub, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + + if !envelope.PublicKey.Equals(pub) { + t.Error("envelope has unexpected public key") + } + + if bytes.Compare(typeHint, envelope.TypeHint) != 0 { + t.Error("TypeHint does not match typeHint used to construct envelope") + } + + valid, err := envelope.Validate(domain) + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if !valid { + t.Error("envelope should be valid, but Valid returns false") + } + + c, err := envelope.Open(domain) + if err != nil { + t.Errorf("error opening envelope: %v", err) + } + if bytes.Compare(c, contents) != 0 { + t.Error("contents of envelope do not match input") + } + + serialized, err := envelope.Marshal() + if err != nil { + t.Errorf("error serializing envelope: %v", err) + } + deserialized, err := UnmarshalEnvelope(serialized) + if err != nil { + t.Errorf("error deserializing envelope: %v", err) + } + + if !envelope.Equals(deserialized) { + t.Error("round-trip serde results in unequal envelope structures") + } +} + +func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + + valid, err := envelope.Validate("other-domain") + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if valid { + t.Error("envelope should be invalid, but Valid returns true") + } +} + +func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + envelope.TypeHint = []byte("foo") + valid, err := envelope.Validate("other-domain") + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if valid { + t.Error("envelope should be invalid, but Valid returns true") + } +} + +func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + + // since the contents field is private, we'll serialize and alter the + // serialized protobuf + serialized, err := envelope.Marshal() + if err != nil { + t.Errorf("error serializing envelope: %v", err) + } + + msg := pb.SignedEnvelope{} + err = proto.Unmarshal(serialized, &msg) + if err != nil { + t.Errorf("error deserializing envelope: %v", err) + } + msg.Contents = []byte("totally legit, trust me") + serialized, err = proto.Marshal(&msg) + + // unmarshal our altered envelope + deserialized, err := UnmarshalEnvelope(serialized) + if err != nil { + t.Errorf("error deserializing envelope: %v", err) + } + + // verify that it's now invalid + valid, err := deserialized.Validate(domain) + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if valid { + t.Error("envelope should be invalid, but Valid returns true") + } +} \ No newline at end of file From 8d61036c08982d678f0d8a9f4bab42fcabe8d42f Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 20 Dec 2019 16:13:11 -0500 Subject: [PATCH 05/69] add routing state records, extend peerstore API --- go.mod | 1 + go.sum | 1 + peerstore/peerstore.go | 11 +- routing/pb/Makefile | 11 + routing/pb/routing_state.pb.go | 621 +++++++++++++++++++++++++++++++++ routing/pb/routing_state.proto | 12 + routing/state.go | 116 ++++++ 7 files changed, 772 insertions(+), 1 deletion(-) create mode 100644 routing/pb/Makefile create mode 100644 routing/pb/routing_state.pb.go create mode 100644 routing/pb/routing_state.proto create mode 100644 routing/state.go diff --git a/go.mod b/go.mod index 36826c58..7e16549a 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 34f6f235..30ec683a 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 7f2c01c9..399b6fed 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 00000000..df34e54b --- /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 00000000..82b475a4 --- /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 00000000..0d6f63e7 --- /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 00000000..490f99cb --- /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 From 791e33fccedf8c751a2a6a50e1370f9137f0aec7 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 8 Nov 2019 11:09:02 -0500 Subject: [PATCH 06/69] add helpers to make routing records for Host --- host/helpers.go | 23 ++++++++++++++++++++++- routing/state.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/host/helpers.go b/host/helpers.go index a24beb1b..e0456314 100644 --- a/host/helpers.go +++ b/host/helpers.go @@ -1,6 +1,11 @@ package host -import "github.com/libp2p/go-libp2p-core/peer" +import ( + "errors" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/routing" +) // InfoFromHost returns a peer.AddrInfo struct with the Host's ID and all of its Addrs. func InfoFromHost(h Host) *peer.AddrInfo { @@ -9,3 +14,19 @@ func InfoFromHost(h Host) *peer.AddrInfo { Addrs: h.Addrs(), } } + +// RoutingStateFromHost returns a routing.RoutingState record that contains the Host's +// ID and all of its listen Addrs. +func RoutingStateFromHost(h Host) *routing.RoutingState { + return routing.RoutingStateFromAddrInfo(InfoFromHost(h)) +} + +// SignedRoutingStateFromHost +func SignedRoutingStateFromHost(h Host) (*crypto.SignedEnvelope, error) { + privKey := h.Peerstore().PrivKey(h.ID()) + if privKey == nil { + return nil, errors.New("unable to find host's private key in peerstore") + } + + return RoutingStateFromHost(h).ToSignedEnvelope(privKey) +} diff --git a/routing/state.go b/routing/state.go index 490f99cb..619b1b65 100644 --- a/routing/state.go +++ b/routing/state.go @@ -7,11 +7,16 @@ import ( "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" pb "github.com/libp2p/go-libp2p-core/routing/pb" + "time" ) // The domain string used for routing state records contained in a SignedEnvelope. const StateEnvelopeDomain = "libp2p-routing-record" +// The type hint used to identify routing state records in a SignedEnvelope. +// TODO: register multicodec +var StateEnvelopeTypeHint = []byte("/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. @@ -36,6 +41,18 @@ type RoutingState struct { Addresses []*AnnotatedAddr } +func RoutingStateFromAddrInfo(info *peer.AddrInfo) *RoutingState { + annotated := make([]*AnnotatedAddr, len(info.Addrs)) + for i, a := range info.Addrs { + annotated[i] = &AnnotatedAddr{Multiaddr: a} + } + return &RoutingState{ + PeerID: info.ID, + Seq: statelessSeqNo(), + Addresses: annotated, + } +} + // UnmarshalRoutingState unpacks a peer RoutingState record from a serialized protobuf representation. func UnmarshalRoutingState(serialized []byte) (*RoutingState, error) { msg := pb.RoutingStateRecord{} @@ -72,6 +89,16 @@ func RoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*RoutingState, e return state, nil } +// ToSignedEnvelope wraps a Marshal'd RoutingState record in a SignedEnvelope using the +// given private signing key. +func (s *RoutingState) ToSignedEnvelope(key crypto.PrivKey) (*crypto.SignedEnvelope, error) { + payload, err := s.Marshal() + if err != nil { + return nil, err + } + return crypto.MakeEnvelope(key, StateEnvelopeDomain, StateEnvelopeTypeHint, payload) +} + // Marshal serializes a RoutingState record to protobuf and returns its byte representation. func (s *RoutingState) Marshal() ([]byte, error) { id, err := s.PeerID.MarshalBinary() @@ -95,6 +122,13 @@ func (s *RoutingState) Multiaddrs() []ma.Multiaddr { return out } +func statelessSeqNo() uint64 { + // use current time in milliseconds as seq number + // nanoseconds would overflow in 2262, but millis gives us + // a few hundred thousand years + return uint64(time.Now().UnixNano() / 1e6) +} + func addrsFromProtobuf(addrs []*pb.RoutingStateRecord_AddressInfo) []*AnnotatedAddr { out := make([]*AnnotatedAddr, 0) for _, addr := range addrs { From 2ebfd9d4f2fc6c389e65d075696ef368ac8ee104 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 8 Nov 2019 11:12:14 -0500 Subject: [PATCH 07/69] fix doc comment --- host/helpers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host/helpers.go b/host/helpers.go index e0456314..aa834472 100644 --- a/host/helpers.go +++ b/host/helpers.go @@ -21,7 +21,8 @@ func RoutingStateFromHost(h Host) *routing.RoutingState { return routing.RoutingStateFromAddrInfo(InfoFromHost(h)) } -// SignedRoutingStateFromHost +// SignedRoutingStateFromHost wraps a routing.RoutingState record in a +// SignedEnvelope, signed with the Host's private key. func SignedRoutingStateFromHost(h Host) (*crypto.SignedEnvelope, error) { privKey := h.Peerstore().PrivKey(h.ID()) if privKey == nil { From c016eb5a8062117e54234086abbdb3fd2872391b Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 8 Nov 2019 11:42:36 -0500 Subject: [PATCH 08/69] go fmt --- crypto/envelope.go | 10 +++++----- crypto/envelope_test.go | 2 +- routing/state.go | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index daf891f7..df8e63bb 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -20,11 +20,11 @@ type SignedEnvelope struct { // A binary identifier that indicates what kind of data is contained in the payload. // TODO(yusef): enforce multicodec prefix - TypeHint []byte + TypeHint []byte // The envelope payload. This is private to discourage accessing the payload without verifying the signature. // To access, use the Open method. - contents []byte + contents []byte // The signature of the domain string, type hint, and contents. signature []byte @@ -91,8 +91,8 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { } msg := pb.SignedEnvelope{ PublicKey: key, - TypeHint: e.TypeHint, - Contents: e.contents, + TypeHint: e.TypeHint, + Contents: e.contents, Signature: e.signature, } return proto.Marshal(&msg) @@ -136,4 +136,4 @@ func encodedSize(content []byte) []byte { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(len(content))) return b -} \ No newline at end of file +} diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index 860ade36..f25a0734 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -147,4 +147,4 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { if valid { t.Error("envelope should be invalid, but Valid returns true") } -} \ No newline at end of file +} diff --git a/routing/state.go b/routing/state.go index 619b1b65..a32882dc 100644 --- a/routing/state.go +++ b/routing/state.go @@ -5,8 +5,8 @@ import ( "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" + ma "github.com/multiformats/go-multiaddr" "time" ) @@ -47,8 +47,8 @@ func RoutingStateFromAddrInfo(info *peer.AddrInfo) *RoutingState { annotated[i] = &AnnotatedAddr{Multiaddr: a} } return &RoutingState{ - PeerID: info.ID, - Seq: statelessSeqNo(), + PeerID: info.ID, + Seq: statelessSeqNo(), Addresses: annotated, } } @@ -106,8 +106,8 @@ func (s *RoutingState) Marshal() ([]byte, error) { return nil, err } msg := pb.RoutingStateRecord{ - PeerId: id, - Seq: s.Seq, + PeerId: id, + Seq: s.Seq, Addresses: addrsToProtobuf(s.Addresses), } return proto.Marshal(&msg) @@ -147,4 +147,4 @@ func addrsToProtobuf(addrs []*AnnotatedAddr) []*pb.RoutingStateRecord_AddressInf out = append(out, &pb.RoutingStateRecord_AddressInfo{Multiaddr: addr.Bytes()}) } return out -} \ No newline at end of file +} From f01458e2e6a45697fad748587545553042eaf4c3 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 8 Nov 2019 11:42:59 -0500 Subject: [PATCH 09/69] add method to peerstore to retrieve signed routing records --- peerstore/peerstore.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 399b6fed..ed45f389 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -96,8 +96,8 @@ 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 adds addresses from a routing.RoutingState record + // contained in the given SignedEnvelope. AddCertifiedAddrs(envelope *ic.SignedEnvelope, ttl time.Duration) error // SetAddr calls mgr.SetAddrs(p, addr, ttl) @@ -129,6 +129,10 @@ type AddrBook interface { // PeersWithAddrs returns all of the peer IDs stored in the AddrBook PeersWithAddrs() peer.IDSlice + + // SignedRoutingState returns a SignedEnvelope containing a RoutingState + // record, if one exists for the given peer. + SignedRoutingState(p peer.ID) *ic.SignedEnvelope } // KeyBook tracks the keys of Peers. From d75c257932ab4ac64927cb753d19d7607a842823 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 11 Nov 2019 09:07:46 -0500 Subject: [PATCH 10/69] update to match spec changes --- routing/state.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routing/state.go b/routing/state.go index a32882dc..3465eeea 100644 --- a/routing/state.go +++ b/routing/state.go @@ -11,11 +11,11 @@ import ( ) // The domain string used for routing state records contained in a SignedEnvelope. -const StateEnvelopeDomain = "libp2p-routing-record" +const StateEnvelopeDomain = "libp2p-routing-state" // The type hint used to identify routing state records in a SignedEnvelope. // TODO: register multicodec -var StateEnvelopeTypeHint = []byte("/libp2p/routing-record") +var StateEnvelopeTypeHint = []byte("/libp2p/routing-state-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 From f583d3c4ce4f3119d71ad6cf133b202dd212a928 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 11 Nov 2019 09:08:02 -0500 Subject: [PATCH 11/69] just use nanoseconds --- routing/state.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/routing/state.go b/routing/state.go index 3465eeea..d71034b1 100644 --- a/routing/state.go +++ b/routing/state.go @@ -123,10 +123,7 @@ func (s *RoutingState) Multiaddrs() []ma.Multiaddr { } func statelessSeqNo() uint64 { - // use current time in milliseconds as seq number - // nanoseconds would overflow in 2262, but millis gives us - // a few hundred thousand years - return uint64(time.Now().UnixNano() / 1e6) + return uint64(time.Now().UnixNano()) } func addrsFromProtobuf(addrs []*pb.RoutingStateRecord_AddressInfo) []*AnnotatedAddr { From cf0cfa5750414f46745368ab2d27a2729699bac9 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 15 Nov 2019 10:39:17 -0500 Subject: [PATCH 12/69] use proto3 & rename fields to match spec changes --- crypto/envelope.go | 48 ++-- crypto/envelope_test.go | 38 +-- crypto/pb/crypto.pb.go | 371 +--------------------------- crypto/pb/crypto.proto | 7 - crypto/pb/envelope.pb.go | 508 +++++++++++++++++++++++++++++++++++++++ crypto/pb/envelope.proto | 12 + 6 files changed, 571 insertions(+), 413 deletions(-) create mode 100644 crypto/pb/envelope.pb.go create mode 100644 crypto/pb/envelope.proto diff --git a/crypto/envelope.go b/crypto/envelope.go index df8e63bb..926d8eeb 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -12,7 +12,7 @@ import ( // Envelopes are signed in the context of a particular "domain", which is a string // specified when creating and verifying the envelope. You must know the domain // string used to produce the envelope in order to verify the signature and -// access the contents. +// access the payload. type SignedEnvelope struct { // The public key that can be used to verify the signature and derive the peer id of the signer. @@ -20,13 +20,13 @@ type SignedEnvelope struct { // A binary identifier that indicates what kind of data is contained in the payload. // TODO(yusef): enforce multicodec prefix - TypeHint []byte + PayloadType []byte // The envelope payload. This is private to discourage accessing the payload without verifying the signature. // To access, use the Open method. - contents []byte + payload []byte - // The signature of the domain string, type hint, and contents. + // The signature of the domain string, type hint, and payload. signature []byte } @@ -37,22 +37,22 @@ var errEmptyDomain = errors.New("envelope domain must not be empty") // The required 'domain' string contextualizes the envelope for a particular purpose, // and must be supplied when verifying the signature. // -// The 'typeHint' field indicates what kind of data is contained and may be empty. -func MakeEnvelope(privateKey PrivKey, domain string, typeHint []byte, contents []byte) (*SignedEnvelope, error) { +// The 'payloadType' field indicates what kind of data is contained and may be empty. +func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, contents []byte) (*SignedEnvelope, error) { if len(domain) == 0 { return nil, errEmptyDomain } - toSign := makeSigBuffer(domain, typeHint, contents) + toSign := makeSigBuffer(domain, payloadType, contents) sig, err := privateKey.Sign(toSign) if err != nil { return nil, err } return &SignedEnvelope{ - PublicKey: privateKey.GetPublic(), - TypeHint: typeHint, - contents: contents, - signature: sig, + PublicKey: privateKey.GetPublic(), + PayloadType: payloadType, + payload: contents, + signature: sig, }, nil } @@ -68,17 +68,17 @@ func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { return nil, err } return &SignedEnvelope{ - PublicKey: key, - TypeHint: e.TypeHint, - contents: e.Contents, - signature: e.Signature, + PublicKey: key, + PayloadType: e.PayloadType, + payload: e.Payload, + signature: e.Signature, }, nil } // Validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) Validate(domain string) (bool, error) { - toVerify := makeSigBuffer(domain, e.TypeHint, e.contents) + toVerify := makeSigBuffer(domain, e.PayloadType, e.payload) return e.PublicKey.Verify(toVerify, e.signature) } @@ -90,16 +90,16 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { return nil, err } msg := pb.SignedEnvelope{ - PublicKey: key, - TypeHint: e.TypeHint, - Contents: e.contents, - Signature: e.signature, + PublicKey: key, + PayloadType: e.PayloadType, + Payload: e.payload, + Signature: e.signature, } return proto.Marshal(&msg) } // Open validates the signature (within the given 'domain') and returns -// the contents of the envelope. Will fail with an error if the signature +// the payload of the envelope. Will fail with an error if the signature // is invalid. func (e *SignedEnvelope) Open(domain string) ([]byte, error) { valid, err := e.Validate(domain) @@ -109,13 +109,13 @@ func (e *SignedEnvelope) Open(domain string) ([]byte, error) { if !valid { return nil, errors.New("invalid signature or incorrect domain") } - return e.contents, nil + return e.payload, nil } func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { return e.PublicKey.Equals(other.PublicKey) && - bytes.Compare(e.TypeHint, other.TypeHint) == 0 && - bytes.Compare(e.contents, other.contents) == 0 && + bytes.Compare(e.PayloadType, other.PayloadType) == 0 && + bytes.Compare(e.payload, other.payload) == 0 && bytes.Compare(e.signature, other.signature) == 0 } diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index f25a0734..549f5bd9 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -15,10 +15,10 @@ func TestEnvelopeHappyPath(t *testing.T) { if err != nil { t.Error(err) } - contents := []byte("happy hacking") + payload := []byte("happy hacking") domain := "libp2p-testing" - typeHint := []byte("/libp2p/testdata") - envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) if err != nil { t.Errorf("error constructing envelope: %v", err) } @@ -27,8 +27,8 @@ func TestEnvelopeHappyPath(t *testing.T) { t.Error("envelope has unexpected public key") } - if bytes.Compare(typeHint, envelope.TypeHint) != 0 { - t.Error("TypeHint does not match typeHint used to construct envelope") + if bytes.Compare(payloadType, envelope.PayloadType) != 0 { + t.Error("PayloadType does not match payloadType used to construct envelope") } valid, err := envelope.Validate(domain) @@ -43,8 +43,8 @@ func TestEnvelopeHappyPath(t *testing.T) { if err != nil { t.Errorf("error opening envelope: %v", err) } - if bytes.Compare(c, contents) != 0 { - t.Error("contents of envelope do not match input") + if bytes.Compare(c, payload) != 0 { + t.Error("payload of envelope do not match input") } serialized, err := envelope.Marshal() @@ -66,10 +66,10 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { if err != nil { t.Error(err) } - contents := []byte("happy hacking") + payload := []byte("happy hacking") domain := "libp2p-testing" - typeHint := []byte("/libp2p/testdata") - envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) if err != nil { t.Errorf("error constructing envelope: %v", err) } @@ -88,14 +88,14 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { if err != nil { t.Error(err) } - contents := []byte("happy hacking") + payload := []byte("happy hacking") domain := "libp2p-testing" - typeHint := []byte("/libp2p/testdata") - envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) if err != nil { t.Errorf("error constructing envelope: %v", err) } - envelope.TypeHint = []byte("foo") + envelope.PayloadType = []byte("foo") valid, err := envelope.Validate("other-domain") if err != nil { t.Errorf("error validating envelope: %v", err) @@ -110,15 +110,15 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { if err != nil { t.Error(err) } - contents := []byte("happy hacking") + payload := []byte("happy hacking") domain := "libp2p-testing" - typeHint := []byte("/libp2p/testdata") - envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) if err != nil { t.Errorf("error constructing envelope: %v", err) } - // since the contents field is private, we'll serialize and alter the + // since the payload field is private, we'll serialize and alter the // serialized protobuf serialized, err := envelope.Marshal() if err != nil { @@ -130,7 +130,7 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { if err != nil { t.Errorf("error deserializing envelope: %v", err) } - msg.Contents = []byte("totally legit, trust me") + msg.Payload = []byte("totally legit, trust me") serialized, err = proto.Marshal(&msg) // unmarshal our altered envelope diff --git a/crypto/pb/crypto.pb.go b/crypto/pb/crypto.pb.go index 9534add1..5fa7aec7 100644 --- a/crypto/pb/crypto.pb.go +++ b/crypto/pb/crypto.pb.go @@ -172,103 +172,29 @@ func (m *PrivateKey) GetData() []byte { return nil } -type SignedEnvelope struct { - PublicKey *PublicKey `protobuf:"bytes,1,req,name=PublicKey" json:"PublicKey,omitempty"` - TypeHint []byte `protobuf:"bytes,2,req,name=TypeHint" json:"TypeHint"` - Contents []byte `protobuf:"bytes,3,req,name=Contents" json:"Contents"` - Signature []byte `protobuf:"bytes,4,req,name=Signature" json:"Signature"` -} - -func (m *SignedEnvelope) Reset() { *m = SignedEnvelope{} } -func (m *SignedEnvelope) String() string { return proto.CompactTextString(m) } -func (*SignedEnvelope) ProtoMessage() {} -func (*SignedEnvelope) Descriptor() ([]byte, []int) { - return fileDescriptor_527278fb02d03321, []int{2} -} -func (m *SignedEnvelope) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_SignedEnvelope.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 *SignedEnvelope) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignedEnvelope.Merge(m, src) -} -func (m *SignedEnvelope) XXX_Size() int { - return m.Size() -} -func (m *SignedEnvelope) XXX_DiscardUnknown() { - xxx_messageInfo_SignedEnvelope.DiscardUnknown(m) -} - -var xxx_messageInfo_SignedEnvelope proto.InternalMessageInfo - -func (m *SignedEnvelope) GetPublicKey() *PublicKey { - if m != nil { - return m.PublicKey - } - return nil -} - -func (m *SignedEnvelope) GetTypeHint() []byte { - if m != nil { - return m.TypeHint - } - return nil -} - -func (m *SignedEnvelope) GetContents() []byte { - if m != nil { - return m.Contents - } - return nil -} - -func (m *SignedEnvelope) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - func init() { proto.RegisterEnum("crypto.pb.KeyType", KeyType_name, KeyType_value) proto.RegisterType((*PublicKey)(nil), "crypto.pb.PublicKey") proto.RegisterType((*PrivateKey)(nil), "crypto.pb.PrivateKey") - proto.RegisterType((*SignedEnvelope)(nil), "crypto.pb.SignedEnvelope") } func init() { proto.RegisterFile("crypto.proto", fileDescriptor_527278fb02d03321) } var fileDescriptor_527278fb02d03321 = []byte{ - // 285 bytes of a gzipped FileDescriptorProto + // 203 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0xf1, 0x92, 0x94, 0x82, 0xb9, 0x38, 0x03, 0x4a, 0x93, 0x72, 0x32, 0x93, 0xbd, 0x53, 0x2b, 0x85, 0x74, 0xb8, 0x58, 0x42, 0x2a, 0x0b, 0x52, 0x25, 0x18, 0x15, 0x98, 0x34, 0xf8, 0x8c, 0x84, 0xf4, 0xe0, 0xca, 0xf4, 0xbc, 0x53, 0x2b, 0x41, 0x32, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x81, 0x55, 0x09, 0x49, 0x70, 0xb1, 0xb8, 0x24, 0x96, 0x24, 0x4a, 0x30, 0x29, 0x30, 0x69, 0xf0, 0xc0, 0x64, 0x40, 0x22, 0x4a, 0x21, - 0x5c, 0x5c, 0x01, 0x45, 0x99, 0x65, 0x89, 0x25, 0xa9, 0xd4, 0x34, 0x75, 0x0d, 0x23, 0x17, 0x5f, - 0x70, 0x66, 0x7a, 0x5e, 0x6a, 0x8a, 0x6b, 0x5e, 0x59, 0x6a, 0x4e, 0x7e, 0x41, 0xaa, 0x90, 0x11, - 0x92, 0xeb, 0xc1, 0xe6, 0x73, 0x1b, 0x89, 0x20, 0x99, 0x0f, 0x97, 0x0b, 0x42, 0xf2, 0xa4, 0x02, - 0x17, 0x07, 0xc8, 0x22, 0x8f, 0xcc, 0xbc, 0x12, 0x14, 0x4b, 0xe0, 0xa2, 0x20, 0x15, 0xce, 0xf9, - 0x79, 0x25, 0xa9, 0x79, 0x25, 0xc5, 0x12, 0xcc, 0xc8, 0x2a, 0x60, 0xa2, 0x42, 0x4a, 0x5c, 0x9c, - 0x20, 0x97, 0x24, 0x96, 0x94, 0x16, 0xa5, 0x4a, 0xb0, 0x20, 0x29, 0x41, 0x08, 0x6b, 0x59, 0x72, - 0xb1, 0x43, 0xfd, 0x27, 0xc4, 0xce, 0xc5, 0x1c, 0x14, 0xec, 0x28, 0xc0, 0x20, 0xc4, 0xcd, 0xc5, - 0xee, 0x9a, 0x62, 0x64, 0x6a, 0x6a, 0x68, 0x29, 0xc0, 0x28, 0xc4, 0xcb, 0xc5, 0x19, 0x9c, 0x9a, - 0x5c, 0x60, 0x64, 0x6a, 0x96, 0x6d, 0x28, 0xc0, 0x24, 0xc4, 0xc9, 0xc5, 0xea, 0xea, 0xec, 0x12, - 0xec, 0x28, 0xc0, 0xec, 0x24, 0x71, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, - 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x80, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x9b, 0xc0, 0x25, 0x32, 0xc8, 0x01, 0x00, 0x00, + 0x5c, 0x5c, 0x01, 0x45, 0x99, 0x65, 0x89, 0x25, 0xa9, 0x54, 0x34, 0x55, 0xcb, 0x92, 0x8b, 0x1d, + 0xaa, 0x41, 0x88, 0x9d, 0x8b, 0x39, 0x28, 0xd8, 0x51, 0x80, 0x41, 0x88, 0x9b, 0x8b, 0xdd, 0x35, + 0xc5, 0xc8, 0xd4, 0xd4, 0xd0, 0x52, 0x80, 0x51, 0x88, 0x97, 0x8b, 0x33, 0x38, 0x35, 0xb9, 0xc0, + 0xc8, 0xd4, 0x2c, 0xdb, 0x50, 0x80, 0x49, 0x88, 0x93, 0x8b, 0xd5, 0xd5, 0xd9, 0x25, 0xd8, 0x51, + 0x80, 0xd9, 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, 0xbe, 0xd4, 0xff, 0x19, 0x01, 0x00, 0x00, } func (m *PublicKey) Marshal() (dAtA []byte, err error) { @@ -325,54 +251,6 @@ func (m *PrivateKey) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *SignedEnvelope) 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 *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.PublicKey == nil { - return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("PublicKey") - } else { - dAtA[i] = 0xa - i++ - i = encodeVarintCrypto(dAtA, i, uint64(m.PublicKey.Size())) - n1, err := m.PublicKey.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - } - if m.TypeHint != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintCrypto(dAtA, i, uint64(len(m.TypeHint))) - i += copy(dAtA[i:], m.TypeHint) - } - if m.Contents != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintCrypto(dAtA, i, uint64(len(m.Contents))) - i += copy(dAtA[i:], m.Contents) - } - if m.Signature != nil { - dAtA[i] = 0x22 - i++ - i = encodeVarintCrypto(dAtA, i, uint64(len(m.Signature))) - i += copy(dAtA[i:], m.Signature) - } - return i, nil -} - func encodeVarintCrypto(dAtA []byte, offset int, v uint64) int { for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -410,31 +288,6 @@ func (m *PrivateKey) Size() (n int) { return n } -func (m *SignedEnvelope) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PublicKey != nil { - l = m.PublicKey.Size() - n += 1 + l + sovCrypto(uint64(l)) - } - if m.TypeHint != nil { - l = len(m.TypeHint) - n += 1 + l + sovCrypto(uint64(l)) - } - if m.Contents != nil { - l = len(m.Contents) - n += 1 + l + sovCrypto(uint64(l)) - } - if m.Signature != nil { - l = len(m.Signature) - n += 1 + l + sovCrypto(uint64(l)) - } - return n -} - func sovCrypto(x uint64) (n int) { for { n++ @@ -678,214 +531,6 @@ func (m *PrivateKey) Unmarshal(dAtA []byte) error { } return nil } -func (m *SignedEnvelope) 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 ErrIntOverflowCrypto - } - 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: SignedEnvelope: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SignedEnvelope: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrypto - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCrypto - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCrypto - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.PublicKey == nil { - m.PublicKey = &PublicKey{} - } - if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - hasFields[0] |= uint64(0x00000001) - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TypeHint", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrypto - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthCrypto - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthCrypto - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TypeHint = append(m.TypeHint[:0], dAtA[iNdEx:postIndex]...) - if m.TypeHint == nil { - m.TypeHint = []byte{} - } - iNdEx = postIndex - hasFields[0] |= uint64(0x00000002) - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Contents", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrypto - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthCrypto - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthCrypto - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Contents = append(m.Contents[:0], dAtA[iNdEx:postIndex]...) - if m.Contents == nil { - m.Contents = []byte{} - } - iNdEx = postIndex - hasFields[0] |= uint64(0x00000004) - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrypto - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthCrypto - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthCrypto - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) - if m.Signature == nil { - m.Signature = []byte{} - } - iNdEx = postIndex - hasFields[0] |= uint64(0x00000008) - default: - iNdEx = preIndex - skippy, err := skipCrypto(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthCrypto - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCrypto - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - if hasFields[0]&uint64(0x00000001) == 0 { - return github_com_gogo_protobuf_proto.NewRequiredNotSetError("PublicKey") - } - if hasFields[0]&uint64(0x00000002) == 0 { - return github_com_gogo_protobuf_proto.NewRequiredNotSetError("TypeHint") - } - if hasFields[0]&uint64(0x00000004) == 0 { - return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Contents") - } - if hasFields[0]&uint64(0x00000008) == 0 { - return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Signature") - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipCrypto(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/crypto/pb/crypto.proto b/crypto/pb/crypto.proto index 7960d7b5..cb5cee8a 100644 --- a/crypto/pb/crypto.proto +++ b/crypto/pb/crypto.proto @@ -18,10 +18,3 @@ message PrivateKey { required KeyType Type = 1; required bytes Data = 2; } - -message SignedEnvelope { - required PublicKey PublicKey = 1; - required bytes TypeHint = 2; - required bytes Contents = 3; - required bytes Signature = 4; -} \ No newline at end of file diff --git a/crypto/pb/envelope.pb.go b/crypto/pb/envelope.pb.go new file mode 100644 index 00000000..62687f06 --- /dev/null +++ b/crypto/pb/envelope.pb.go @@ -0,0 +1,508 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: envelope.proto + +package crypto_pb + +import ( + fmt "fmt" + 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 SignedEnvelope struct { + PublicKey *PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + PayloadType []byte `protobuf:"bytes,2,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"` + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (m *SignedEnvelope) Reset() { *m = SignedEnvelope{} } +func (m *SignedEnvelope) String() string { return proto.CompactTextString(m) } +func (*SignedEnvelope) ProtoMessage() {} +func (*SignedEnvelope) Descriptor() ([]byte, []int) { + return fileDescriptor_ee266e8c558e9dc5, []int{0} +} +func (m *SignedEnvelope) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SignedEnvelope.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 *SignedEnvelope) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignedEnvelope.Merge(m, src) +} +func (m *SignedEnvelope) XXX_Size() int { + return m.Size() +} +func (m *SignedEnvelope) XXX_DiscardUnknown() { + xxx_messageInfo_SignedEnvelope.DiscardUnknown(m) +} + +var xxx_messageInfo_SignedEnvelope proto.InternalMessageInfo + +func (m *SignedEnvelope) GetPublicKey() *PublicKey { + if m != nil { + return m.PublicKey + } + return nil +} + +func (m *SignedEnvelope) GetPayloadType() []byte { + if m != nil { + return m.PayloadType + } + return nil +} + +func (m *SignedEnvelope) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + +func (m *SignedEnvelope) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func init() { + proto.RegisterType((*SignedEnvelope)(nil), "crypto.pb.SignedEnvelope") +} + +func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } + +var fileDescriptor_ee266e8c558e9dc5 = []byte{ + // 200 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, + 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4c, 0x2e, 0xaa, 0x2c, + 0x28, 0xc9, 0xd7, 0x2b, 0x48, 0x92, 0xe2, 0x81, 0x31, 0x41, 0x12, 0x4a, 0x0b, 0x18, 0xb9, 0xf8, + 0x82, 0x33, 0xd3, 0xf3, 0x52, 0x53, 0x5c, 0xa1, 0x3a, 0x84, 0x8c, 0xb9, 0xb8, 0x0a, 0x4a, 0x93, + 0x72, 0x32, 0x93, 0xe3, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0x44, 0xf4, + 0xe0, 0x06, 0xe8, 0x05, 0x80, 0x25, 0xbd, 0x53, 0x2b, 0x83, 0x38, 0x0b, 0x60, 0x4c, 0x21, 0x45, + 0x2e, 0x9e, 0x82, 0xc4, 0xca, 0x9c, 0xfc, 0xc4, 0x94, 0xf8, 0x92, 0xca, 0x82, 0x54, 0x09, 0x26, + 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x6e, 0xa8, 0x58, 0x48, 0x65, 0x41, 0xaa, 0x90, 0x04, 0x17, 0x3b, + 0x94, 0x2b, 0xc1, 0x0c, 0x96, 0x85, 0x71, 0x85, 0x64, 0xb8, 0x38, 0x8b, 0x33, 0xd3, 0xf3, 0x12, + 0x4b, 0x4a, 0x8b, 0x52, 0x25, 0x58, 0xc0, 0x72, 0x08, 0x01, 0x27, 0x89, 0x13, 0x8f, 0xe4, 0x18, + 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, + 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xfb, 0xc1, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, + 0x40, 0xc9, 0x83, 0xba, 0xee, 0x00, 0x00, 0x00, +} + +func (m *SignedEnvelope) 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 *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.PublicKey != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(m.PublicKey.Size())) + n1, err := m.PublicKey.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } + if len(m.PayloadType) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) + i += copy(dAtA[i:], m.PayloadType) + } + if len(m.Payload) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Payload))) + i += copy(dAtA[i:], m.Payload) + } + if len(m.Signature) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) + i += copy(dAtA[i:], m.Signature) + } + return i, nil +} + +func encodeVarintEnvelope(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 *SignedEnvelope) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PublicKey != nil { + l = m.PublicKey.Size() + n += 1 + l + sovEnvelope(uint64(l)) + } + l = len(m.PayloadType) + if l > 0 { + n += 1 + l + sovEnvelope(uint64(l)) + } + l = len(m.Payload) + if l > 0 { + n += 1 + l + sovEnvelope(uint64(l)) + } + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovEnvelope(uint64(l)) + } + return n +} + +func sovEnvelope(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozEnvelope(x uint64) (n int) { + return sovEnvelope(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + 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: SignedEnvelope: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SignedEnvelope: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PublicKey == nil { + m.PublicKey = &PublicKey{} + } + if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PayloadType", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PayloadType = append(m.PayloadType[:0], dAtA[iNdEx:postIndex]...) + if m.PayloadType == nil { + m.PayloadType = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payload", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Payload = append(m.Payload[:0], dAtA[iNdEx:postIndex]...) + if m.Payload == nil { + m.Payload = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEnvelope(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEnvelope + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEnvelope + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEnvelope(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, ErrIntOverflowEnvelope + } + 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, ErrIntOverflowEnvelope + } + 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, ErrIntOverflowEnvelope + } + 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, ErrInvalidLengthEnvelope + } + iNdEx += length + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEnvelope + } + 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 := skipEnvelope(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } + } + 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 ( + ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") +) diff --git a/crypto/pb/envelope.proto b/crypto/pb/envelope.proto new file mode 100644 index 00000000..58e4d362 --- /dev/null +++ b/crypto/pb/envelope.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package crypto.pb; + +import "crypto.proto"; + +message SignedEnvelope { + PublicKey public_key = 1; + bytes payload_type = 2; + bytes payload = 3; + bytes signature = 4; +} \ No newline at end of file From a8a530e24fccf03ec6d235fa416e6e695761333a Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 15 Nov 2019 12:05:59 -0500 Subject: [PATCH 13/69] use proto3 for routing records --- routing/pb/routing_state.pb.go | 71 ++++++++++++++-------------------- routing/pb/routing_state.proto | 8 ++-- routing/state.go | 5 ++- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/routing/pb/routing_state.pb.go b/routing/pb/routing_state.pb.go index 82b475a4..28d216ca 100644 --- a/routing/pb/routing_state.pb.go +++ b/routing/pb/routing_state.pb.go @@ -5,7 +5,6 @@ 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" @@ -23,9 +22,9 @@ var _ = math.Inf 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"` + PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` + Addresses []*RoutingStateRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` } func (m *RoutingStateRecord) Reset() { *m = RoutingStateRecord{} } @@ -83,7 +82,7 @@ func (m *RoutingStateRecord) GetAddresses() []*RoutingStateRecord_AddressInfo { } type RoutingStateRecord_AddressInfo struct { - Multiaddr []byte `protobuf:"bytes,1,req,name=multiaddr" json:"multiaddr"` + Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` } func (m *RoutingStateRecord_AddressInfo) Reset() { *m = RoutingStateRecord_AddressInfo{} } @@ -134,20 +133,20 @@ func init() { func init() { proto.RegisterFile("routing_state.proto", fileDescriptor_2bc7f62bc26d3acc) } var fileDescriptor_2bc7f62bc26d3acc = []byte{ - // 198 bytes of a gzipped FileDescriptorProto + // 200 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, + 0xe2, 0x82, 0x0a, 0xea, 0x15, 0x24, 0x29, 0x6d, 0x63, 0xe4, 0x12, 0x0a, 0x82, 0x70, 0x83, 0x41, + 0x4a, 0x82, 0x52, 0x93, 0xf3, 0x8b, 0x52, 0x84, 0xc4, 0xb9, 0xd8, 0x0b, 0x52, 0x53, 0x8b, 0xe2, + 0x33, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xd8, 0x40, 0x5c, 0xcf, 0x14, 0x21, 0x01, + 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x10, 0x53, 0xc8, 0x83, + 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, + 0xdb, 0x48, 0x4b, 0x0f, 0x61, 0x83, 0x1e, 0xa6, 0xe9, 0x7a, 0x8e, 0x10, 0xf5, 0x9e, 0x79, 0x69, + 0xf9, 0x41, 0x08, 0xcd, 0x52, 0xda, 0x5c, 0xdc, 0x48, 0x32, 0x42, 0x32, 0x5c, 0x9c, 0xb9, 0xa5, + 0x39, 0x25, 0x99, 0x20, 0x05, 0x50, 0x57, 0x20, 0x04, 0x9c, 0x24, 0x4e, 0x3c, 0x92, 0x63, 0xbc, + 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, + 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, 0x0d, 0xec, 0x4b, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xdc, 0xd5, 0x32, 0xa1, 0xfc, 0x00, 0x00, 0x00, } func (m *RoutingStateRecord) Marshal() (dAtA []byte, err error) { @@ -165,15 +164,17 @@ func (m *RoutingStateRecord) MarshalTo(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.PeerId != nil { + if len(m.PeerId) > 0 { 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 m.Seq != 0 { + dAtA[i] = 0x10 + i++ + i = encodeVarintRoutingState(dAtA, i, uint64(m.Seq)) + } if len(m.Addresses) > 0 { for _, msg := range m.Addresses { dAtA[i] = 0x1a @@ -204,7 +205,7 @@ func (m *RoutingStateRecord_AddressInfo) MarshalTo(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Multiaddr != nil { + if len(m.Multiaddr) > 0 { dAtA[i] = 0xa i++ i = encodeVarintRoutingState(dAtA, i, uint64(len(m.Multiaddr))) @@ -228,11 +229,13 @@ func (m *RoutingStateRecord) Size() (n int) { } var l int _ = l - if m.PeerId != nil { - l = len(m.PeerId) + l = len(m.PeerId) + if l > 0 { n += 1 + l + sovRoutingState(uint64(l)) } - n += 1 + sovRoutingState(uint64(m.Seq)) + if m.Seq != 0 { + n += 1 + sovRoutingState(uint64(m.Seq)) + } if len(m.Addresses) > 0 { for _, e := range m.Addresses { l = e.Size() @@ -248,8 +251,8 @@ func (m *RoutingStateRecord_AddressInfo) Size() (n int) { } var l int _ = l - if m.Multiaddr != nil { - l = len(m.Multiaddr) + l = len(m.Multiaddr) + if l > 0 { n += 1 + l + sovRoutingState(uint64(l)) } return n @@ -269,7 +272,6 @@ 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 { @@ -332,7 +334,6 @@ func (m *RoutingStateRecord) Unmarshal(dAtA []byte) error { 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) @@ -352,7 +353,6 @@ func (m *RoutingStateRecord) Unmarshal(dAtA []byte) error { break } } - hasFields[0] |= uint64(0x00000002) case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) @@ -405,12 +405,6 @@ func (m *RoutingStateRecord) Unmarshal(dAtA []byte) error { 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 @@ -418,7 +412,6 @@ func (m *RoutingStateRecord) Unmarshal(dAtA []byte) error { return nil } func (m *RoutingStateRecord_AddressInfo) Unmarshal(dAtA []byte) error { - var hasFields [1]uint64 l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -481,7 +474,6 @@ func (m *RoutingStateRecord_AddressInfo) Unmarshal(dAtA []byte) error { m.Multiaddr = []byte{} } iNdEx = postIndex - hasFields[0] |= uint64(0x00000001) default: iNdEx = preIndex skippy, err := skipRoutingState(dAtA[iNdEx:]) @@ -500,9 +492,6 @@ func (m *RoutingStateRecord_AddressInfo) Unmarshal(dAtA []byte) error { iNdEx += skippy } } - if hasFields[0]&uint64(0x00000001) == 0 { - return github_com_gogo_protobuf_proto.NewRequiredNotSetError("multiaddr") - } if iNdEx > l { return io.ErrUnexpectedEOF diff --git a/routing/pb/routing_state.proto b/routing/pb/routing_state.proto index 0d6f63e7..f5604dc3 100644 --- a/routing/pb/routing_state.proto +++ b/routing/pb/routing_state.proto @@ -1,12 +1,12 @@ -syntax = "proto2"; +syntax = "proto3"; package routing.pb; message RoutingStateRecord { message AddressInfo { - required bytes multiaddr = 1; + bytes multiaddr = 1; } - required bytes peerId = 1; - required uint64 seq = 2; + bytes peer_id = 1; + uint64 seq = 2; repeated AddressInfo addresses = 3; } diff --git a/routing/state.go b/routing/state.go index d71034b1..91f4fa6a 100644 --- a/routing/state.go +++ b/routing/state.go @@ -1,6 +1,7 @@ package routing import ( + "bytes" "errors" "github.com/gogo/protobuf/proto" "github.com/libp2p/go-libp2p-core/crypto" @@ -15,7 +16,7 @@ const StateEnvelopeDomain = "libp2p-routing-state" // The type hint used to identify routing state records in a SignedEnvelope. // TODO: register multicodec -var StateEnvelopeTypeHint = []byte("/libp2p/routing-state-record") +var StateEnvelopePayloadType = []byte("/libp2p/routing-state-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 @@ -96,7 +97,7 @@ func (s *RoutingState) ToSignedEnvelope(key crypto.PrivKey) (*crypto.SignedEnvel if err != nil { return nil, err } - return crypto.MakeEnvelope(key, StateEnvelopeDomain, StateEnvelopeTypeHint, payload) + return crypto.MakeEnvelope(key, StateEnvelopeDomain, StateEnvelopePayloadType, payload) } // Marshal serializes a RoutingState record to protobuf and returns its byte representation. From 3724a31efe66b3f52b1fda76b02ee8cc8a291ec0 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 15 Nov 2019 13:11:04 -0500 Subject: [PATCH 14/69] make envelope fields private & validate on unmarshal --- crypto/envelope.go | 97 +++++++++++++++++++++++++---------------- crypto/envelope_test.go | 97 ++++++++++++++++++----------------------- peerstore/peerstore.go | 18 +++++--- routing/state.go | 11 +++-- 4 files changed, 122 insertions(+), 101 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index 926d8eeb..5474ee2a 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -16,14 +16,13 @@ import ( type SignedEnvelope struct { // The public key that can be used to verify the signature and derive the peer id of the signer. - PublicKey PubKey + publicKey PubKey // A binary identifier that indicates what kind of data is contained in the payload. // TODO(yusef): enforce multicodec prefix - PayloadType []byte + payloadType []byte - // The envelope payload. This is private to discourage accessing the payload without verifying the signature. - // To access, use the Open method. + // The envelope payload. payload []byte // The signature of the domain string, type hint, and payload. @@ -31,6 +30,7 @@ type SignedEnvelope struct { } var errEmptyDomain = errors.New("envelope domain must not be empty") +var errInvalidSignature = errors.New("invalid signature or incorrect domain") // MakeEnvelope constructs a new SignedEnvelope using the given privateKey. // @@ -38,27 +38,42 @@ var errEmptyDomain = errors.New("envelope domain must not be empty") // and must be supplied when verifying the signature. // // The 'payloadType' field indicates what kind of data is contained and may be empty. -func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, contents []byte) (*SignedEnvelope, error) { +func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload []byte) (*SignedEnvelope, error) { if len(domain) == 0 { return nil, errEmptyDomain } - toSign := makeSigBuffer(domain, payloadType, contents) + toSign := makeSigBuffer(domain, payloadType, payload) sig, err := privateKey.Sign(toSign) if err != nil { return nil, err } return &SignedEnvelope{ - PublicKey: privateKey.GetPublic(), - PayloadType: payloadType, - payload: contents, + publicKey: privateKey.GetPublic(), + payloadType: payloadType, + payload: payload, signature: sig, }, nil } -// UnmarshalEnvelope converts a serialized protobuf representation of an envelope -// into a SignedEnvelope struct. -func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { +// OpenEnvelope unmarshals a serialized SignedEnvelope, validating its signature +// using the provided 'domain' string. +func OpenEnvelope(envelopeBytes []byte, domain string) (*SignedEnvelope, error) { + e, err := UnmarshalEnvelopeWithoutValidating(envelopeBytes) + if err != nil { + return nil, err + } + err = e.validate(domain) + if err != nil { + return nil, err + } + return e, nil +} + +// UnmarshalEnvelopeWithoutValidating unmarshals a serialized SignedEnvelope protobuf message, +// without validating its contents. Should not be used unless you have a very good reason +// (e.g. testing)! +func UnmarshalEnvelopeWithoutValidating(serializedEnvelope []byte) (*SignedEnvelope, error) { e := pb.SignedEnvelope{} if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { return nil, err @@ -68,55 +83,61 @@ func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { return nil, err } return &SignedEnvelope{ - PublicKey: key, - PayloadType: e.PayloadType, + publicKey: key, + payloadType: e.PayloadType, payload: e.Payload, signature: e.Signature, }, nil } -// Validate returns true if the envelope signature is valid for the given 'domain', -// or false if it is invalid. May return an error if signature validation fails. -func (e *SignedEnvelope) Validate(domain string) (bool, error) { - toVerify := makeSigBuffer(domain, e.PayloadType, e.payload) - return e.PublicKey.Verify(toVerify, e.signature) +// PublicKey returns the public key that can be used to verify the signature and derive the peer id of the signer. +func (e *SignedEnvelope) PublicKey() PubKey { + return e.publicKey +} + +// PayloadType returns a binary identifier that indicates what kind of data is contained in the payload. +func (e *SignedEnvelope) PayloadType() []byte { + return e.payloadType +} + +// Payload returns the binary payload of a SignedEnvelope. +func (e *SignedEnvelope) Payload() []byte { + return e.payload } -// Marshal returns a []byte containing a serialized protobuf representation of -// the SignedEnvelope. func (e *SignedEnvelope) Marshal() ([]byte, error) { - key, err := PublicKeyToProto(e.PublicKey) + key, err := PublicKeyToProto(e.publicKey) if err != nil { return nil, err } msg := pb.SignedEnvelope{ PublicKey: key, - PayloadType: e.PayloadType, + PayloadType: e.payloadType, Payload: e.payload, Signature: e.signature, } return proto.Marshal(&msg) } -// Open validates the signature (within the given 'domain') and returns -// the payload of the envelope. Will fail with an error if the signature -// is invalid. -func (e *SignedEnvelope) Open(domain string) ([]byte, error) { - valid, err := e.Validate(domain) +func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { + return e.publicKey.Equals(other.publicKey) && + bytes.Compare(e.payloadType, other.payloadType) == 0 && + bytes.Compare(e.payload, other.payload) == 0 && + bytes.Compare(e.signature, other.signature) == 0 +} + +// validate returns true if the envelope signature is valid for the given 'domain', +// or false if it is invalid. May return an error if signature validation fails. +func (e *SignedEnvelope) validate(domain string) error { + toVerify := makeSigBuffer(domain, e.payloadType, e.payload) + valid, err := e.publicKey.Verify(toVerify, e.signature) if err != nil { - return nil, err + return err } if !valid { - return nil, errors.New("invalid signature or incorrect domain") + return errInvalidSignature } - return e.payload, nil -} - -func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { - return e.PublicKey.Equals(other.PublicKey) && - bytes.Compare(e.PayloadType, other.PayloadType) == 0 && - bytes.Compare(e.payload, other.payload) == 0 && - bytes.Compare(e.signature, other.signature) == 0 + return nil } // makeSigBuffer is a helper function that prepares a buffer to sign or verify. diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index 549f5bd9..e6d164ee 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -2,7 +2,8 @@ package crypto_test import ( "bytes" - "github.com/gogo/protobuf/proto" + "github.com/golang/protobuf/proto" + . "github.com/libp2p/go-libp2p-core/crypto" pb "github.com/libp2p/go-libp2p-core/crypto/pb" "github.com/libp2p/go-libp2p-core/test" @@ -23,39 +24,27 @@ func TestEnvelopeHappyPath(t *testing.T) { t.Errorf("error constructing envelope: %v", err) } - if !envelope.PublicKey.Equals(pub) { + if !envelope.PublicKey().Equals(pub) { t.Error("envelope has unexpected public key") } - if bytes.Compare(payloadType, envelope.PayloadType) != 0 { + if bytes.Compare(payloadType, envelope.PayloadType()) != 0 { t.Error("PayloadType does not match payloadType used to construct envelope") } - valid, err := envelope.Validate(domain) - if err != nil { - t.Errorf("error validating envelope: %v", err) - } - if !valid { - t.Error("envelope should be valid, but Valid returns false") - } - - c, err := envelope.Open(domain) - if err != nil { - t.Errorf("error opening envelope: %v", err) - } - if bytes.Compare(c, payload) != 0 { - t.Error("payload of envelope do not match input") - } - serialized, err := envelope.Marshal() if err != nil { t.Errorf("error serializing envelope: %v", err) } - deserialized, err := UnmarshalEnvelope(serialized) + deserialized, err := OpenEnvelope(serialized, domain) if err != nil { t.Errorf("error deserializing envelope: %v", err) } + if bytes.Compare(deserialized.Payload(), payload) != 0 { + t.Error("payload of envelope does not match input") + } + if !envelope.Equals(deserialized) { t.Error("round-trip serde results in unequal envelope structures") } @@ -73,13 +62,11 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { if err != nil { t.Errorf("error constructing envelope: %v", err) } - - valid, err := envelope.Validate("other-domain") - if err != nil { - t.Errorf("error validating envelope: %v", err) - } - if valid { - t.Error("envelope should be invalid, but Valid returns true") + serialized, err := envelope.Marshal() + // try to open our modified envelope + _, err = OpenEnvelope(serialized, "wrong-domain") + if err == nil { + t.Error("should not be able to open envelope with incorrect domain") } } @@ -95,13 +82,13 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { if err != nil { t.Errorf("error constructing envelope: %v", err) } - envelope.PayloadType = []byte("foo") - valid, err := envelope.Validate("other-domain") - if err != nil { - t.Errorf("error validating envelope: %v", err) - } - if valid { - t.Error("envelope should be invalid, but Valid returns true") + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { + msg.PayloadType = []byte("foo") + }) + // try to open our modified envelope + _, err = OpenEnvelope(serialized, domain) + if err == nil { + t.Error("should not be able to open envelope with modified payloadType") } } @@ -118,33 +105,35 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { t.Errorf("error constructing envelope: %v", err) } - // since the payload field is private, we'll serialize and alter the - // serialized protobuf + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { + msg.Payload = []byte("totally legit, trust me") + }) + // try to open our modified envelope + _, err = OpenEnvelope(serialized, domain) + if err == nil { + t.Error("should not be able to open envelope with modified payload") + } +} + +// Since we're outside of the crypto package (to avoid import cycles with test package), +// we can't alter the fields in a SignedEnvelope directly. This helper marshals +// the envelope to a protobuf and calls the alterMsg function, which should +// alter the protobuf message. +// Returns the serialized altered protobuf message. +func alterMessageAndMarshal(t *testing.T, envelope *SignedEnvelope, alterMsg func(*pb.SignedEnvelope)) []byte { serialized, err := envelope.Marshal() if err != nil { - t.Errorf("error serializing envelope: %v", err) + t.Errorf("error marshaling envelope: %v", err) } - msg := pb.SignedEnvelope{} err = proto.Unmarshal(serialized, &msg) if err != nil { - t.Errorf("error deserializing envelope: %v", err) + t.Errorf("error unmarshaling envelope: %v", err) } - msg.Payload = []byte("totally legit, trust me") - serialized, err = proto.Marshal(&msg) - - // unmarshal our altered envelope - deserialized, err := UnmarshalEnvelope(serialized) + alterMsg(&msg) + serialized, err = msg.Marshal() if err != nil { - t.Errorf("error deserializing envelope: %v", err) - } - - // verify that it's now invalid - valid, err := deserialized.Validate(domain) - if err != nil { - t.Errorf("error validating envelope: %v", err) - } - if valid { - t.Error("envelope should be invalid, but Valid returns true") + t.Errorf("error marshaling envelope: %v", err) } + return serialized } diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index ed45f389..b12b62f9 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -97,8 +97,8 @@ type AddrBook interface { AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) // AddCertifiedAddrs adds addresses from a routing.RoutingState record - // contained in the given SignedEnvelope. - AddCertifiedAddrs(envelope *ic.SignedEnvelope, ttl time.Duration) error + // contained in a serialized SignedEnvelope. + AddCertifiedAddrs(envelopeBytes []byte, ttl time.Duration) error // SetAddr calls mgr.SetAddrs(p, addr, ttl) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) @@ -130,9 +130,17 @@ type AddrBook interface { // PeersWithAddrs returns all of the peer IDs stored in the AddrBook PeersWithAddrs() peer.IDSlice - // SignedRoutingState returns a SignedEnvelope containing a RoutingState - // record, if one exists for the given peer. - SignedRoutingState(p peer.ID) *ic.SignedEnvelope + // SignedRoutingState returns a signed RoutingState record for the + // given peer id, if one exists in the peerstore. The record is + // returned as a byte slice containing a serialized SignedEnvelope. + // Returns nil if no routing state exists for the peer. + SignedRoutingState(p peer.ID) []byte + + // SignedRoutingStates returns signed RoutingState records for each of + // the given peer ids, if one exists in the peerstore. + // Returns a map of peer ids to serialized SignedEnvelope messages. If + // no routing state exists for a peer, their map entry will be nil. + SignedRoutingStates(peers ...peer.ID) map[peer.ID][]byte } // KeyBook tracks the keys of Peers. diff --git a/routing/state.go b/routing/state.go index 91f4fa6a..8bdb02ae 100644 --- a/routing/state.go +++ b/routing/state.go @@ -75,16 +75,19 @@ func UnmarshalRoutingState(serialized []byte) (*RoutingState, error) { // 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) +func RoutingStateFromEnvelope(envelopeBytes []byte) (*RoutingState, error) { + envelope, err := crypto.OpenEnvelope(envelopeBytes, StateEnvelopeDomain) if err != nil { return nil, err } - state, err := UnmarshalRoutingState(msgBytes) + if bytes.Compare(envelope.PayloadType(), StateEnvelopePayloadType) != 0 { + return nil, errors.New("unexpected envelope payload type") + } + state, err := UnmarshalRoutingState(envelope.Payload()) if err != nil { return nil, err } - if !state.PeerID.MatchesPublicKey(envelope.PublicKey) { + if !state.PeerID.MatchesPublicKey(envelope.PublicKey()) { return nil, errors.New("peer id in routing state record does not match signing key") } return state, nil From be36d83110eb65558639e4be598ff002d581557e Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 18 Nov 2019 09:18:06 -0500 Subject: [PATCH 15/69] use buffer pool for envelope signatures --- crypto/envelope.go | 49 +++++++++++++++++++++++++++++++++++----------- go.mod | 1 + 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index 5474ee2a..359cf18b 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "errors" "github.com/golang/protobuf/proto" + "github.com/libp2p/go-buffer-pool" pb "github.com/libp2p/go-libp2p-core/crypto/pb" ) @@ -42,7 +43,10 @@ func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload if len(domain) == 0 { return nil, errEmptyDomain } - toSign := makeSigBuffer(domain, payloadType, payload) + toSign, err := makeSigBuffer(domain, payloadType, payload) + if err != nil { + return nil, err + } sig, err := privateKey.Sign(toSign) if err != nil { return nil, err @@ -129,7 +133,10 @@ func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { // validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) validate(domain string) error { - toVerify := makeSigBuffer(domain, e.payloadType, e.payload) + toVerify, err := makeSigBuffer(domain, e.payloadType, e.payload) + if err != nil { + return err + } valid, err := e.publicKey.Verify(toVerify, e.signature) if err != nil { return err @@ -141,16 +148,36 @@ func (e *SignedEnvelope) validate(domain string) error { } // makeSigBuffer is a helper function that prepares a buffer to sign or verify. -func makeSigBuffer(domain string, typeHint []byte, content []byte) []byte { - b := bytes.Buffer{} +func makeSigBuffer(domain string, payloadType []byte, payload []byte) ([]byte, error) { domainBytes := []byte(domain) - b.Write(encodedSize(domainBytes)) - b.Write(domainBytes) - b.Write(encodedSize(typeHint)) - b.Write(typeHint) - b.Write(encodedSize(content)) - b.Write(content) - return b.Bytes() + fields := [][]byte{domainBytes, payloadType, payload} + + const lengthPrefixSize = 8 + size := 0 + for _, f := range fields { + size += len(f) + lengthPrefixSize + } + + b := pool.NewBuffer(nil) + b.Grow(size) + + for _, f := range fields { + err := writeField(b, f) + if err != nil { + return nil, err + } + } + + return b.Bytes(), nil +} + +func writeField(b *pool.Buffer, f []byte) error { + _, err := b.Write(encodedSize(f)) + if err != nil { + return err + } + _, err = b.Write(f) + return err } func encodedSize(content []byte) []byte { diff --git a/go.mod b/go.mod index 7e16549a..c2e6c887 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( 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-buffer-pool v0.0.1 github.com/libp2p/go-flow-metrics v0.0.3 github.com/libp2p/go-openssl v0.0.4 github.com/minio/sha256-simd v0.1.1 From 7d10658fce7614528992140abb4737d46952f8a3 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 18 Nov 2019 09:13:06 -0600 Subject: [PATCH 16/69] tests for RoutingState --- crypto/envelope_test.go | 13 +++++++ go.sum | 2 ++ routing/state.go | 40 ++++++++++++++++++--- routing/state_test.go | 78 +++++++++++++++++++++++++++++++++++++++++ test/utils.go | 57 ++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 routing/state_test.go create mode 100644 test/utils.go diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index e6d164ee..10ba8916 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -50,6 +50,19 @@ func TestEnvelopeHappyPath(t *testing.T) { } } +func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + payload := []byte("happy hacking") + payloadType := []byte("/libp2p/testdata") + _, err = MakeEnvelope(priv, "", payloadType, payload) + if err == nil { + t.Errorf("making an envelope with an empty domain should fail") + } +} + func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { priv, _, err := test.RandTestKeyPair(Ed25519, 256) if err != nil { diff --git a/go.sum b/go.sum index 30ec683a..542a7713 100644 --- a/go.sum +++ b/go.sum @@ -68,6 +68,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-buffer-pool v0.0.1 h1:9Rrn/H46cXjaA2HQ5Y8lyhOS1NhTkZ4yuEs2r3Eechg= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg= diff --git a/routing/state.go b/routing/state.go index 8bdb02ae..b1229a17 100644 --- a/routing/state.go +++ b/routing/state.go @@ -42,18 +42,26 @@ type RoutingState struct { Addresses []*AnnotatedAddr } -func RoutingStateFromAddrInfo(info *peer.AddrInfo) *RoutingState { - annotated := make([]*AnnotatedAddr, len(info.Addrs)) - for i, a := range info.Addrs { +// RoutingStateWithMultiaddrs returns a RoutingState record for the given peer id +// that contains the given multiaddrs. It generates a timestamp-based sequence number. +func RoutingStateWithMultiaddrs(p peer.ID, addrs []ma.Multiaddr) *RoutingState { + annotated := make([]*AnnotatedAddr, len(addrs)) + for i, a := range addrs { annotated[i] = &AnnotatedAddr{Multiaddr: a} } return &RoutingState{ - PeerID: info.ID, + PeerID: p, Seq: statelessSeqNo(), Addresses: annotated, } } +// RoutingStateFromAddrInfo converts a peer.AddrInfo into a RoutingState record. +// It generates a timestamp-based sequence number. +func RoutingStateFromAddrInfo(info *peer.AddrInfo) *RoutingState { + return RoutingStateWithMultiaddrs(info.ID, info.Addrs) +} + // UnmarshalRoutingState unpacks a peer RoutingState record from a serialized protobuf representation. func UnmarshalRoutingState(serialized []byte) (*RoutingState, error) { msg := pb.RoutingStateRecord{} @@ -72,7 +80,7 @@ func UnmarshalRoutingState(serialized []byte) (*RoutingState, error) { }, nil } -// RoutingStateFromEnvelope unwraps a peer RoutingState record from a SignedEnvelope. +// RoutingStateFromEnvelope unwraps a peer RoutingState record from a serialized 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(envelopeBytes []byte) (*RoutingState, error) { @@ -126,6 +134,28 @@ func (s *RoutingState) Multiaddrs() []ma.Multiaddr { return out } +func (s *RoutingState) Equal(other *RoutingState) bool { + if s.Seq != other.Seq { + return false + } + if s.PeerID != other.PeerID { + return false + } + if len(s.Addresses) != len(other.Addresses) { + return false + } + for i, _ := range s.Addresses { + if !s.Addresses[i].Equal(other.Addresses[i]) { + return false + } + } + return true +} + +func (a *AnnotatedAddr) Equal(other *AnnotatedAddr) bool { + return a.Multiaddr.Equal(other.Multiaddr) +} + func statelessSeqNo() uint64 { return uint64(time.Now().UnixNano()) } diff --git a/routing/state_test.go b/routing/state_test.go new file mode 100644 index 00000000..bb482103 --- /dev/null +++ b/routing/state_test.go @@ -0,0 +1,78 @@ +package routing + +import ( + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/test" + "testing" +) + +func TestRoutingStateFromAddrInfo(t *testing.T) { + id, _ := test.RandPeerID() + addrs := test.GenerateTestAddrs(10) + info := peer.AddrInfo{ + ID: id, + Addrs: addrs, + } + state := RoutingStateFromAddrInfo(&info) + if state.PeerID != info.ID { + t.Fatalf("expected routing state to have peer id %s, got %s", id.Pretty(), state.PeerID.Pretty()) + } + test.AssertAddressesEqual(t, addrs, state.Multiaddrs()) +} + +func TestRoutingStateFromEnvelope(t *testing.T) { + priv, pub, err := test.RandTestKeyPair(crypto.Ed25519, 256) + test.AssertNilError(t, err) + + id, err := peer.IDFromPublicKey(pub) + test.AssertNilError(t, err) + + addrs := test.GenerateTestAddrs(10) + state := RoutingStateWithMultiaddrs(id, addrs) + + t.Run("can unwrap a RoutingState from a serialized envelope", func(t *testing.T) { + env, err := state.ToSignedEnvelope(priv) + test.AssertNilError(t, err) + + envBytes, err := env.Marshal() + test.AssertNilError(t, err) + + state2, err := RoutingStateFromEnvelope(envBytes) + if !state.Equal(state2) { + t.Error("expected routing state to be unaltered after wrapping in signed envelope") + } + }) + + t.Run("unwrapping from signed envelope fails if peer id does not match signing key", func(t *testing.T) { + priv2, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) + test.AssertNilError(t, err) + env, err := state.ToSignedEnvelope(priv2) + test.AssertNilError(t, err) + envBytes, err := env.Marshal() + test.AssertNilError(t, err) + + _, err = RoutingStateFromEnvelope(envBytes) + test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if peer id does not match key used to sign envelope") + }) + + t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func (t *testing.T) { + stateBytes, err := state.Marshal() + test.AssertNilError(t, err) + + env, err := crypto.MakeEnvelope(priv, "wrong-domain", StateEnvelopePayloadType, stateBytes) + envBytes, err := env.Marshal() + _, err = RoutingStateFromEnvelope(envBytes) + test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong domain string") + }) + + t.Run("unwrapping from signed envelope fails if envelope has wrong payload type", func (t *testing.T) { + stateBytes, err := state.Marshal() + test.AssertNilError(t, err) + payloadType := []byte("wrong-payload-type") + env, err := crypto.MakeEnvelope(priv, StateEnvelopeDomain, payloadType, stateBytes) + envBytes, err := env.Marshal() + _, err = RoutingStateFromEnvelope(envBytes) + test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong payload type") + }) +} diff --git a/test/utils.go b/test/utils.go new file mode 100644 index 00000000..ee175eb8 --- /dev/null +++ b/test/utils.go @@ -0,0 +1,57 @@ +package test + +import ( + "fmt" + "testing" + + ma "github.com/multiformats/go-multiaddr" +) + +func AssertNilError(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Errorf("unexpected error: %v", err) + } +} + +func ExpectError(t *testing.T, err error, msg string) { + t.Helper() + if err == nil { + t.Error(msg) + } +} + +func GenerateTestAddrs(n int) []ma.Multiaddr { + out := make([]ma.Multiaddr, n) + for i := 0; i < n; i++ { + a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i)) + if err != nil { + continue + } + out[i] = a + } + return out +} + +func AssertAddressesEqual(t *testing.T, exp, act []ma.Multiaddr) { + t.Helper() + if len(exp) != len(act) { + t.Fatalf("lengths not the same. expected %d, got %d\n", len(exp), len(act)) + } + + for _, a := range exp { + found := false + + for _, b := range act { + if a.Equal(b) { + found = true + break + } + } + + if !found { + t.Fatalf("expected address %s not found", a) + } + } +} + From c8a9a5eafe87db52ebc615811445d6b6a124d6db Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 18 Nov 2019 09:26:53 -0600 Subject: [PATCH 17/69] go fmt --- routing/state_test.go | 4 ++-- test/utils.go | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/routing/state_test.go b/routing/state_test.go index bb482103..b4af56d6 100644 --- a/routing/state_test.go +++ b/routing/state_test.go @@ -56,7 +56,7 @@ func TestRoutingStateFromEnvelope(t *testing.T) { test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if peer id does not match key used to sign envelope") }) - t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func (t *testing.T) { + t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func(t *testing.T) { stateBytes, err := state.Marshal() test.AssertNilError(t, err) @@ -66,7 +66,7 @@ func TestRoutingStateFromEnvelope(t *testing.T) { test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong domain string") }) - t.Run("unwrapping from signed envelope fails if envelope has wrong payload type", func (t *testing.T) { + t.Run("unwrapping from signed envelope fails if envelope has wrong payload type", func(t *testing.T) { stateBytes, err := state.Marshal() test.AssertNilError(t, err) payloadType := []byte("wrong-payload-type") diff --git a/test/utils.go b/test/utils.go index ee175eb8..f4db700a 100644 --- a/test/utils.go +++ b/test/utils.go @@ -54,4 +54,3 @@ func AssertAddressesEqual(t *testing.T, exp, act []ma.Multiaddr) { } } } - From cf19665533e905c4429a41cda5669ed182114473 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 19 Nov 2019 09:19:17 -0600 Subject: [PATCH 18/69] rename Equals -> Equal, add some comments --- crypto/envelope.go | 6 +++++- crypto/envelope_test.go | 2 +- peerstore/peerstore.go | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index 359cf18b..6f11b12b 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -109,6 +109,7 @@ func (e *SignedEnvelope) Payload() []byte { return e.payload } +// Marshal returns a byte slice containing a serailized protobuf representation of a SignedEnvelope. func (e *SignedEnvelope) Marshal() ([]byte, error) { key, err := PublicKeyToProto(e.publicKey) if err != nil { @@ -123,7 +124,10 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { return proto.Marshal(&msg) } -func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { +// Equal returns true if the other SignedEnvelope has the same +// public key, payload, payload type, and signature. This +// implies that they were also created with the same domain string. +func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { return e.publicKey.Equals(other.publicKey) && bytes.Compare(e.payloadType, other.payloadType) == 0 && bytes.Compare(e.payload, other.payload) == 0 && diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index 10ba8916..552f6cf1 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -45,7 +45,7 @@ func TestEnvelopeHappyPath(t *testing.T) { t.Error("payload of envelope does not match input") } - if !envelope.Equals(deserialized) { + if !envelope.Equal(deserialized) { t.Error("round-trip serde results in unequal envelope structures") } } diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index b12b62f9..3e12a29d 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -98,7 +98,7 @@ type AddrBook interface { // AddCertifiedAddrs adds addresses from a routing.RoutingState record // contained in a serialized SignedEnvelope. - AddCertifiedAddrs(envelopeBytes []byte, ttl time.Duration) error + AddCertifiedAddrs(envelope []byte, ttl time.Duration) error // SetAddr calls mgr.SetAddrs(p, addr, ttl) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) From a56dc2cb5544a50a5adc2623c82599685c87dfa3 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 19 Nov 2019 11:43:47 -0600 Subject: [PATCH 19/69] use test helpers --- crypto/envelope_test.go | 69 +++++++++++------------------------------ routing/state_test.go | 2 ++ 2 files changed, 20 insertions(+), 51 deletions(-) diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index 552f6cf1..d2bf7f06 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -13,16 +13,12 @@ import ( // Make an envelope, verify & open it, marshal & unmarshal it func TestEnvelopeHappyPath(t *testing.T) { priv, pub, err := test.RandTestKeyPair(Ed25519, 256) - if err != nil { - t.Error(err) - } + test.AssertNilError(t, err) payload := []byte("happy hacking") domain := "libp2p-testing" payloadType := []byte("/libp2p/testdata") envelope, err := MakeEnvelope(priv, domain, payloadType, payload) - if err != nil { - t.Errorf("error constructing envelope: %v", err) - } + test.AssertNilError(t, err) if !envelope.PublicKey().Equals(pub) { t.Error("envelope has unexpected public key") @@ -33,13 +29,9 @@ func TestEnvelopeHappyPath(t *testing.T) { } serialized, err := envelope.Marshal() - if err != nil { - t.Errorf("error serializing envelope: %v", err) - } + test.AssertNilError(t, err) deserialized, err := OpenEnvelope(serialized, domain) - if err != nil { - t.Errorf("error deserializing envelope: %v", err) - } + test.AssertNilError(t, err) if bytes.Compare(deserialized.Payload(), payload) != 0 { t.Error("payload of envelope does not match input") @@ -58,74 +50,54 @@ func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { payload := []byte("happy hacking") payloadType := []byte("/libp2p/testdata") _, err = MakeEnvelope(priv, "", payloadType, payload) - if err == nil { - t.Errorf("making an envelope with an empty domain should fail") - } + test.ExpectError(t, err, "making an envelope with an empty domain should fail") } func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { priv, _, err := test.RandTestKeyPair(Ed25519, 256) - if err != nil { - t.Error(err) - } + test.AssertNilError(t, err) payload := []byte("happy hacking") domain := "libp2p-testing" payloadType := []byte("/libp2p/testdata") envelope, err := MakeEnvelope(priv, domain, payloadType, payload) - if err != nil { - t.Errorf("error constructing envelope: %v", err) - } + test.AssertNilError(t, err) serialized, err := envelope.Marshal() // try to open our modified envelope _, err = OpenEnvelope(serialized, "wrong-domain") - if err == nil { - t.Error("should not be able to open envelope with incorrect domain") - } + test.ExpectError(t, err, "should not be able to open envelope with incorrect domain") } func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { priv, _, err := test.RandTestKeyPair(Ed25519, 256) - if err != nil { - t.Error(err) - } + test.AssertNilError(t, err) payload := []byte("happy hacking") domain := "libp2p-testing" payloadType := []byte("/libp2p/testdata") envelope, err := MakeEnvelope(priv, domain, payloadType, payload) - if err != nil { - t.Errorf("error constructing envelope: %v", err) - } + test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { msg.PayloadType = []byte("foo") }) // try to open our modified envelope _, err = OpenEnvelope(serialized, domain) - if err == nil { - t.Error("should not be able to open envelope with modified payloadType") - } + test.ExpectError(t, err, "should not be able to open envelope with modified payloadType") } func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { priv, _, err := test.RandTestKeyPair(Ed25519, 256) - if err != nil { - t.Error(err) - } + test.AssertNilError(t, err) payload := []byte("happy hacking") domain := "libp2p-testing" payloadType := []byte("/libp2p/testdata") envelope, err := MakeEnvelope(priv, domain, payloadType, payload) - if err != nil { - t.Errorf("error constructing envelope: %v", err) - } + test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { msg.Payload = []byte("totally legit, trust me") }) // try to open our modified envelope _, err = OpenEnvelope(serialized, domain) - if err == nil { - t.Error("should not be able to open envelope with modified payload") - } + test.ExpectError(t, err, "should not be able to open envelope with modified payload") } // Since we're outside of the crypto package (to avoid import cycles with test package), @@ -134,19 +106,14 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { // alter the protobuf message. // Returns the serialized altered protobuf message. func alterMessageAndMarshal(t *testing.T, envelope *SignedEnvelope, alterMsg func(*pb.SignedEnvelope)) []byte { + t.Helper() serialized, err := envelope.Marshal() - if err != nil { - t.Errorf("error marshaling envelope: %v", err) - } + test.AssertNilError(t, err) msg := pb.SignedEnvelope{} err = proto.Unmarshal(serialized, &msg) - if err != nil { - t.Errorf("error unmarshaling envelope: %v", err) - } + test.AssertNilError(t, err) alterMsg(&msg) serialized, err = msg.Marshal() - if err != nil { - t.Errorf("error marshaling envelope: %v", err) - } + test.AssertNilError(t, err) return serialized } diff --git a/routing/state_test.go b/routing/state_test.go index b4af56d6..ba0abbed 100644 --- a/routing/state_test.go +++ b/routing/state_test.go @@ -61,6 +61,7 @@ func TestRoutingStateFromEnvelope(t *testing.T) { test.AssertNilError(t, err) env, err := crypto.MakeEnvelope(priv, "wrong-domain", StateEnvelopePayloadType, stateBytes) + test.AssertNilError(t, err) envBytes, err := env.Marshal() _, err = RoutingStateFromEnvelope(envBytes) test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong domain string") @@ -71,6 +72,7 @@ func TestRoutingStateFromEnvelope(t *testing.T) { test.AssertNilError(t, err) payloadType := []byte("wrong-payload-type") env, err := crypto.MakeEnvelope(priv, StateEnvelopeDomain, payloadType, stateBytes) + test.AssertNilError(t, err) envBytes, err := env.Marshal() _, err = RoutingStateFromEnvelope(envBytes) test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong payload type") From bf3693255b8d973ddb44d86e0b5e5eb224a48696 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 21 Nov 2019 09:09:31 -0600 Subject: [PATCH 20/69] get rid of unsigned RoutingState struct, only expose SignedRoutingState --- crypto/envelope.go | 2 +- host/helpers.go | 15 +--- peerstore/peerstore.go | 27 +++--- routing/state.go | 181 ++++++++++++++++++++--------------------- routing/state_test.go | 51 +++--------- 5 files changed, 116 insertions(+), 160 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index 6f11b12b..fc9df3e8 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -78,7 +78,7 @@ func OpenEnvelope(envelopeBytes []byte, domain string) (*SignedEnvelope, error) // without validating its contents. Should not be used unless you have a very good reason // (e.g. testing)! func UnmarshalEnvelopeWithoutValidating(serializedEnvelope []byte) (*SignedEnvelope, error) { - e := pb.SignedEnvelope{} + var e pb.SignedEnvelope if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { return nil, err } diff --git a/host/helpers.go b/host/helpers.go index aa834472..276eeaea 100644 --- a/host/helpers.go +++ b/host/helpers.go @@ -2,7 +2,6 @@ package host import ( "errors" - "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/routing" ) @@ -15,19 +14,13 @@ func InfoFromHost(h Host) *peer.AddrInfo { } } -// RoutingStateFromHost returns a routing.RoutingState record that contains the Host's -// ID and all of its listen Addrs. -func RoutingStateFromHost(h Host) *routing.RoutingState { - return routing.RoutingStateFromAddrInfo(InfoFromHost(h)) -} - -// SignedRoutingStateFromHost wraps a routing.RoutingState record in a -// SignedEnvelope, signed with the Host's private key. -func SignedRoutingStateFromHost(h Host) (*crypto.SignedEnvelope, error) { +// SignedRoutingStateFromHost returns a SignedRoutingState record containing +// the Host's listen addresses, signed with the Host's private key. +func SignedRoutingStateFromHost(h Host) (*routing.SignedRoutingState, error) { privKey := h.Peerstore().PrivKey(h.ID()) if privKey == nil { return nil, errors.New("unable to find host's private key in peerstore") } - return RoutingStateFromHost(h).ToSignedEnvelope(privKey) + return routing.MakeSignedRoutingState(privKey, h.Addrs()) } diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 3e12a29d..88b2c295 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -5,6 +5,7 @@ package peerstore import ( "context" "errors" + "github.com/libp2p/go-libp2p-core/routing" "io" "math" "time" @@ -96,9 +97,9 @@ 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 routing.RoutingState record - // contained in a serialized SignedEnvelope. - AddCertifiedAddrs(envelope []byte, ttl time.Duration) error + // AddCertifiedAddrs adds addresses from a routing.SignedRoutingState record. + // Certified addresses will be returned from both Addrs and CertifiedAddrs. + AddCertifiedAddrs(s *routing.SignedRoutingState, ttl time.Duration) error // SetAddr calls mgr.SetAddrs(p, addr, ttl) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) @@ -111,12 +112,13 @@ type AddrBook interface { // the given oldTTL to have the given newTTL. UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) - // Addrs returns all known (and valid) addresses for a given peer + // Addrs returns all known (and valid) addresses for a given peer, including + // both certified and uncertified addresses. 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. + // been certified by that peer and added to the peerstore using + // AddCertifiedAddrs. Note that certified addrs are also returned. CertifiedAddrs(p peer.ID) []ma.Multiaddr // AddrStream returns a channel that gets all addresses for a given @@ -130,17 +132,16 @@ type AddrBook interface { // PeersWithAddrs returns all of the peer IDs stored in the AddrBook PeersWithAddrs() peer.IDSlice - // SignedRoutingState returns a signed RoutingState record for the - // given peer id, if one exists in the peerstore. The record is - // returned as a byte slice containing a serialized SignedEnvelope. + // SignedRoutingState returns a SignedRoutingState record for the + // given peer id, if one exists in the peerstore. // Returns nil if no routing state exists for the peer. - SignedRoutingState(p peer.ID) []byte + SignedRoutingState(p peer.ID) *routing.SignedRoutingState - // SignedRoutingStates returns signed RoutingState records for each of + // SignedRoutingStates returns SignedRoutingState records for each of // the given peer ids, if one exists in the peerstore. - // Returns a map of peer ids to serialized SignedEnvelope messages. If + // Returns a map of peer ids to SignedRoutingState records. If // no routing state exists for a peer, their map entry will be nil. - SignedRoutingStates(peers ...peer.ID) map[peer.ID][]byte + SignedRoutingStates(peers ...peer.ID) map[peer.ID]*routing.SignedRoutingState } // KeyBook tracks the keys of Peers. diff --git a/routing/state.go b/routing/state.go index b1229a17..f9cf6de4 100644 --- a/routing/state.go +++ b/routing/state.go @@ -18,162 +18,155 @@ const StateEnvelopeDomain = "libp2p-routing-state" // TODO: register multicodec var StateEnvelopePayloadType = []byte("/libp2p/routing-state-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 { +type SignedRoutingState struct { // PeerID is the ID of the peer this record pertains to. - PeerID peer.ID + peerID peer.ID // Seq is an increment-only sequence counter used to order RoutingState records in time. - Seq uint64 + seq uint64 // Addresses contains the public addresses of the peer this record pertains to. - Addresses []*AnnotatedAddr -} + addresses []ma.Multiaddr -// RoutingStateWithMultiaddrs returns a RoutingState record for the given peer id -// that contains the given multiaddrs. It generates a timestamp-based sequence number. -func RoutingStateWithMultiaddrs(p peer.ID, addrs []ma.Multiaddr) *RoutingState { - annotated := make([]*AnnotatedAddr, len(addrs)) - for i, a := range addrs { - annotated[i] = &AnnotatedAddr{Multiaddr: a} - } - return &RoutingState{ - PeerID: p, - Seq: statelessSeqNo(), - Addresses: annotated, - } + envelope *crypto.SignedEnvelope } -// RoutingStateFromAddrInfo converts a peer.AddrInfo into a RoutingState record. +// MakeSignedRoutingState returns a SignedRoutingState record containing the given multiaddrs, +// signed with the given private key. // It generates a timestamp-based sequence number. -func RoutingStateFromAddrInfo(info *peer.AddrInfo) *RoutingState { - return RoutingStateWithMultiaddrs(info.ID, info.Addrs) -} - -// 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) +func MakeSignedRoutingState(privKey crypto.PrivKey, addrs []ma.Multiaddr) (*SignedRoutingState, error) { + p, err := peer.IDFromPrivateKey(privKey) if err != nil { return nil, err } - id, err := peer.IDFromBytes(msg.PeerId) + idBytes, err := p.MarshalBinary() + if err != nil { + return nil, err + } + seq := statelessSeqNo() + msg := pb.RoutingStateRecord{ + PeerId: idBytes, + Seq: seq, + Addresses: addrsToProtobuf(addrs), + } + payload, err := proto.Marshal(&msg) + if err != nil { + return nil, err + } + envelope, err := crypto.MakeEnvelope(privKey, StateEnvelopeDomain, StateEnvelopePayloadType, payload) if err != nil { return nil, err } - return &RoutingState{ - PeerID: id, - Seq: msg.Seq, - Addresses: addrsFromProtobuf(msg.Addresses), + return &SignedRoutingState{ + peerID: p, + seq: seq, + addresses: addrs, + envelope: envelope, }, nil } -// RoutingStateFromEnvelope unwraps a peer RoutingState record from a serialized 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(envelopeBytes []byte) (*RoutingState, error) { +// UnmarshalSignedRoutingState accepts a serialized SignedEnvelope message containing +// a RoutingStateRecord protobuf and returns a SignedRoutingState record. +// Fails if the signature is invalid, if the envelope has an unexpected payload type, +// if deserialization of the envelope or its inner payload fails. +func UnmarshalSignedRoutingState(envelopeBytes []byte) (*SignedRoutingState, error) { envelope, err := crypto.OpenEnvelope(envelopeBytes, StateEnvelopeDomain) if err != nil { return nil, err } + return SignedRoutingStateFromEnvelope(envelope) +} + +// SignedRoutingStateFromEnvelope accepts a SignedEnvelope struct containing +// a RoutingStateRecord protobuf and returns a SignedRoutingState record. +// Fails if the signature is invalid, if the envelope has an unexpected payload type, +// or if deserialization of the envelope payload fails. +func SignedRoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*SignedRoutingState, error) { if bytes.Compare(envelope.PayloadType(), StateEnvelopePayloadType) != 0 { return nil, errors.New("unexpected envelope payload type") } - state, err := UnmarshalRoutingState(envelope.Payload()) + var msg pb.RoutingStateRecord + err := proto.Unmarshal(envelope.Payload(), &msg) if err != nil { return nil, err } - if !state.PeerID.MatchesPublicKey(envelope.PublicKey()) { + id, err := peer.IDFromBytes(msg.PeerId) + if err != nil { + return nil, err + } + if !id.MatchesPublicKey(envelope.PublicKey()) { return nil, errors.New("peer id in routing state record does not match signing key") } - return state, nil + return &SignedRoutingState{ + peerID: id, + seq: msg.Seq, + addresses: addrsFromProtobuf(msg.Addresses), + envelope: envelope, + }, nil } -// ToSignedEnvelope wraps a Marshal'd RoutingState record in a SignedEnvelope using the -// given private signing key. -func (s *RoutingState) ToSignedEnvelope(key crypto.PrivKey) (*crypto.SignedEnvelope, error) { - payload, err := s.Marshal() - if err != nil { - return nil, err - } - return crypto.MakeEnvelope(key, StateEnvelopeDomain, StateEnvelopePayloadType, payload) +// Marshal returns a byte slice containing the SignedRoutingState as a serialized SignedEnvelope +// protobuf message. +func (s *SignedRoutingState) Marshal() ([]byte, error) { + return s.envelope.Marshal() } -// 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) +// PeerID is the ID of the peer this record pertains to. +func (s *SignedRoutingState) PeerID() peer.ID { + return s.peerID } -// 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 +// Seq is an increment-only sequence counter used to order RoutingState records in time. +func (s *SignedRoutingState) Seq() uint64 { + return s.seq +} + +// Multiaddrs contains the public addresses of the peer this record pertains to. +func (s *SignedRoutingState) Multiaddrs() []ma.Multiaddr { + return s.addresses } -func (s *RoutingState) Equal(other *RoutingState) bool { - if s.Seq != other.Seq { +// Equal returns true if the other SignedRoutingState is identical to this one. +func (s *SignedRoutingState) Equal(other *SignedRoutingState) bool { + if other == nil { return false } - if s.PeerID != other.PeerID { + if s.seq != other.seq { return false } - if len(s.Addresses) != len(other.Addresses) { + if s.peerID != other.peerID { return false } - for i, _ := range s.Addresses { - if !s.Addresses[i].Equal(other.Addresses[i]) { + if len(s.addresses) != len(other.addresses) { + return false + } + for i, _ := range s.addresses { + if !s.addresses[i].Equal(other.addresses[i]) { return false } } - return true -} - -func (a *AnnotatedAddr) Equal(other *AnnotatedAddr) bool { - return a.Multiaddr.Equal(other.Multiaddr) + return s.envelope.Equal(other.envelope) } +// statelessSeqNo is a helper to generate a timestamp-based sequence number. func statelessSeqNo() uint64 { return uint64(time.Now().UnixNano()) } -func addrsFromProtobuf(addrs []*pb.RoutingStateRecord_AddressInfo) []*AnnotatedAddr { - out := make([]*AnnotatedAddr, 0) +func addrsFromProtobuf(addrs []*pb.RoutingStateRecord_AddressInfo) []ma.Multiaddr { + var out []ma.Multiaddr for _, addr := range addrs { a, err := ma.NewMultiaddrBytes(addr.Multiaddr) if err != nil { continue } - out = append(out, &AnnotatedAddr{Multiaddr: a}) + out = append(out, a) } return out } -func addrsToProtobuf(addrs []*AnnotatedAddr) []*pb.RoutingStateRecord_AddressInfo { - out := make([]*pb.RoutingStateRecord_AddressInfo, 0) +func addrsToProtobuf(addrs []ma.Multiaddr) []*pb.RoutingStateRecord_AddressInfo { + var out []*pb.RoutingStateRecord_AddressInfo for _, addr := range addrs { out = append(out, &pb.RoutingStateRecord_AddressInfo{Multiaddr: addr.Bytes()}) } diff --git a/routing/state_test.go b/routing/state_test.go index ba0abbed..ea21588f 100644 --- a/routing/state_test.go +++ b/routing/state_test.go @@ -2,60 +2,29 @@ package routing import ( "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/test" "testing" ) -func TestRoutingStateFromAddrInfo(t *testing.T) { - id, _ := test.RandPeerID() - addrs := test.GenerateTestAddrs(10) - info := peer.AddrInfo{ - ID: id, - Addrs: addrs, - } - state := RoutingStateFromAddrInfo(&info) - if state.PeerID != info.ID { - t.Fatalf("expected routing state to have peer id %s, got %s", id.Pretty(), state.PeerID.Pretty()) - } - test.AssertAddressesEqual(t, addrs, state.Multiaddrs()) -} - -func TestRoutingStateFromEnvelope(t *testing.T) { - priv, pub, err := test.RandTestKeyPair(crypto.Ed25519, 256) - test.AssertNilError(t, err) - - id, err := peer.IDFromPublicKey(pub) +func TestSignedRoutingStateFromEnvelope(t *testing.T) { + priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) test.AssertNilError(t, err) addrs := test.GenerateTestAddrs(10) - state := RoutingStateWithMultiaddrs(id, addrs) + state, err := MakeSignedRoutingState(priv, addrs) + test.AssertNilError(t, err) - t.Run("can unwrap a RoutingState from a serialized envelope", func(t *testing.T) { - env, err := state.ToSignedEnvelope(priv) + t.Run("is unaltered after round-trip serde", func(t *testing.T) { + envBytes, err := state.Marshal() test.AssertNilError(t, err) - envBytes, err := env.Marshal() + state2, err := UnmarshalSignedRoutingState(envBytes) test.AssertNilError(t, err) - - state2, err := RoutingStateFromEnvelope(envBytes) if !state.Equal(state2) { - t.Error("expected routing state to be unaltered after wrapping in signed envelope") + t.Error("expected routing state to be unaltered after round-trip serde") } }) - t.Run("unwrapping from signed envelope fails if peer id does not match signing key", func(t *testing.T) { - priv2, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) - test.AssertNilError(t, err) - env, err := state.ToSignedEnvelope(priv2) - test.AssertNilError(t, err) - envBytes, err := env.Marshal() - test.AssertNilError(t, err) - - _, err = RoutingStateFromEnvelope(envBytes) - test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if peer id does not match key used to sign envelope") - }) - t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func(t *testing.T) { stateBytes, err := state.Marshal() test.AssertNilError(t, err) @@ -63,7 +32,7 @@ func TestRoutingStateFromEnvelope(t *testing.T) { env, err := crypto.MakeEnvelope(priv, "wrong-domain", StateEnvelopePayloadType, stateBytes) test.AssertNilError(t, err) envBytes, err := env.Marshal() - _, err = RoutingStateFromEnvelope(envBytes) + _, err = UnmarshalSignedRoutingState(envBytes) test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong domain string") }) @@ -74,7 +43,7 @@ func TestRoutingStateFromEnvelope(t *testing.T) { env, err := crypto.MakeEnvelope(priv, StateEnvelopeDomain, payloadType, stateBytes) test.AssertNilError(t, err) envBytes, err := env.Marshal() - _, err = RoutingStateFromEnvelope(envBytes) + _, err = UnmarshalSignedRoutingState(envBytes) test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong payload type") }) } From 00306a49031cd1459ef9ad9a9098bc17e29012a2 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 21 Nov 2019 09:10:56 -0600 Subject: [PATCH 21/69] rm batching SignedRoutingStates accessor in peerstore the datastore peerstore implementation doesn't support batched reads, so it's no more efficient to get a bunch of states at once than it is to call SignedRoutingState multiple times. --- peerstore/peerstore.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 88b2c295..eb01b928 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -136,12 +136,6 @@ type AddrBook interface { // given peer id, if one exists in the peerstore. // Returns nil if no routing state exists for the peer. SignedRoutingState(p peer.ID) *routing.SignedRoutingState - - // SignedRoutingStates returns SignedRoutingState records for each of - // the given peer ids, if one exists in the peerstore. - // Returns a map of peer ids to SignedRoutingState records. If - // no routing state exists for a peer, their map entry will be nil. - SignedRoutingStates(peers ...peer.ID) map[peer.ID]*routing.SignedRoutingState } // KeyBook tracks the keys of Peers. From 347316f262724557f507b848dc72729898ce342d Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 21 Nov 2019 10:00:38 -0600 Subject: [PATCH 22/69] whitespace --- crypto/envelope.go | 5 +++-- crypto/pb/envelope.proto | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index fc9df3e8..f34b368f 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -4,7 +4,9 @@ import ( "bytes" "encoding/binary" "errors" - "github.com/golang/protobuf/proto" + + "github.com/gogo/protobuf/proto" + "github.com/libp2p/go-buffer-pool" pb "github.com/libp2p/go-libp2p-core/crypto/pb" ) @@ -15,7 +17,6 @@ import ( // string used to produce the envelope in order to verify the signature and // access the payload. type SignedEnvelope struct { - // The public key that can be used to verify the signature and derive the peer id of the signer. publicKey PubKey diff --git a/crypto/pb/envelope.proto b/crypto/pb/envelope.proto index 58e4d362..b8abdebb 100644 --- a/crypto/pb/envelope.proto +++ b/crypto/pb/envelope.proto @@ -9,4 +9,4 @@ message SignedEnvelope { bytes payload_type = 2; bytes payload = 3; bytes signature = 4; -} \ No newline at end of file +} From 272731be608d04018e070309c2b96301ccc892a2 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 21 Nov 2019 11:55:14 -0600 Subject: [PATCH 23/69] expose struct fields & remove accessors --- crypto/envelope.go | 51 ++++++++++++--------------------- crypto/envelope_test.go | 10 +++---- routing/state.go | 63 ++++++++++++++++------------------------- 3 files changed, 48 insertions(+), 76 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index f34b368f..3a0c79fe 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -18,14 +18,14 @@ import ( // access the payload. type SignedEnvelope struct { // The public key that can be used to verify the signature and derive the peer id of the signer. - publicKey PubKey + PublicKey PubKey // A binary identifier that indicates what kind of data is contained in the payload. // TODO(yusef): enforce multicodec prefix - payloadType []byte + PayloadType []byte // The envelope payload. - payload []byte + Payload []byte // The signature of the domain string, type hint, and payload. signature []byte @@ -39,7 +39,7 @@ var errInvalidSignature = errors.New("invalid signature or incorrect domain") // The required 'domain' string contextualizes the envelope for a particular purpose, // and must be supplied when verifying the signature. // -// The 'payloadType' field indicates what kind of data is contained and may be empty. +// The 'PayloadType' field indicates what kind of data is contained and may be empty. func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload []byte) (*SignedEnvelope, error) { if len(domain) == 0 { return nil, errEmptyDomain @@ -54,9 +54,9 @@ func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload } return &SignedEnvelope{ - publicKey: privateKey.GetPublic(), - payloadType: payloadType, - payload: payload, + PublicKey: privateKey.GetPublic(), + PayloadType: payloadType, + Payload: payload, signature: sig, }, nil } @@ -88,38 +88,23 @@ func UnmarshalEnvelopeWithoutValidating(serializedEnvelope []byte) (*SignedEnvel return nil, err } return &SignedEnvelope{ - publicKey: key, - payloadType: e.PayloadType, - payload: e.Payload, + PublicKey: key, + PayloadType: e.PayloadType, + Payload: e.Payload, signature: e.Signature, }, nil } -// PublicKey returns the public key that can be used to verify the signature and derive the peer id of the signer. -func (e *SignedEnvelope) PublicKey() PubKey { - return e.publicKey -} - -// PayloadType returns a binary identifier that indicates what kind of data is contained in the payload. -func (e *SignedEnvelope) PayloadType() []byte { - return e.payloadType -} - -// Payload returns the binary payload of a SignedEnvelope. -func (e *SignedEnvelope) Payload() []byte { - return e.payload -} - // Marshal returns a byte slice containing a serailized protobuf representation of a SignedEnvelope. func (e *SignedEnvelope) Marshal() ([]byte, error) { - key, err := PublicKeyToProto(e.publicKey) + key, err := PublicKeyToProto(e.PublicKey) if err != nil { return nil, err } msg := pb.SignedEnvelope{ PublicKey: key, - PayloadType: e.payloadType, - Payload: e.payload, + PayloadType: e.PayloadType, + Payload: e.Payload, Signature: e.signature, } return proto.Marshal(&msg) @@ -129,20 +114,20 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { // public key, payload, payload type, and signature. This // implies that they were also created with the same domain string. func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { - return e.publicKey.Equals(other.publicKey) && - bytes.Compare(e.payloadType, other.payloadType) == 0 && - bytes.Compare(e.payload, other.payload) == 0 && + return e.PublicKey.Equals(other.PublicKey) && + bytes.Compare(e.PayloadType, other.PayloadType) == 0 && + bytes.Compare(e.Payload, other.Payload) == 0 && bytes.Compare(e.signature, other.signature) == 0 } // validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) validate(domain string) error { - toVerify, err := makeSigBuffer(domain, e.payloadType, e.payload) + toVerify, err := makeSigBuffer(domain, e.PayloadType, e.Payload) if err != nil { return err } - valid, err := e.publicKey.Verify(toVerify, e.signature) + valid, err := e.PublicKey.Verify(toVerify, e.signature) if err != nil { return err } diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index d2bf7f06..0e1c69b2 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -20,12 +20,12 @@ func TestEnvelopeHappyPath(t *testing.T) { envelope, err := MakeEnvelope(priv, domain, payloadType, payload) test.AssertNilError(t, err) - if !envelope.PublicKey().Equals(pub) { + if !envelope.PublicKey.Equals(pub) { t.Error("envelope has unexpected public key") } - if bytes.Compare(payloadType, envelope.PayloadType()) != 0 { - t.Error("PayloadType does not match payloadType used to construct envelope") + if bytes.Compare(payloadType, envelope.PayloadType) != 0 { + t.Error("PayloadType does not match PayloadType used to construct envelope") } serialized, err := envelope.Marshal() @@ -33,7 +33,7 @@ func TestEnvelopeHappyPath(t *testing.T) { deserialized, err := OpenEnvelope(serialized, domain) test.AssertNilError(t, err) - if bytes.Compare(deserialized.Payload(), payload) != 0 { + if bytes.Compare(deserialized.Payload, payload) != 0 { t.Error("payload of envelope does not match input") } @@ -80,7 +80,7 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { }) // try to open our modified envelope _, err = OpenEnvelope(serialized, domain) - test.ExpectError(t, err, "should not be able to open envelope with modified payloadType") + test.ExpectError(t, err, "should not be able to open envelope with modified PayloadType") } func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { diff --git a/routing/state.go b/routing/state.go index f9cf6de4..b9fc7592 100644 --- a/routing/state.go +++ b/routing/state.go @@ -20,15 +20,17 @@ var StateEnvelopePayloadType = []byte("/libp2p/routing-state-record") type SignedRoutingState struct { // PeerID is the ID of the peer this record pertains to. - peerID peer.ID + PeerID peer.ID // Seq is an increment-only sequence counter used to order RoutingState records in time. - seq uint64 + Seq uint64 - // Addresses contains the public addresses of the peer this record pertains to. - addresses []ma.Multiaddr + // Addrs contains the public addresses of the peer this record pertains to. + Addrs []ma.Multiaddr - envelope *crypto.SignedEnvelope + // Envelope contains the signature and serialized RoutingStateRecord protobuf. + // Although it uses a bit + Envelope *crypto.SignedEnvelope } // MakeSignedRoutingState returns a SignedRoutingState record containing the given multiaddrs, @@ -58,10 +60,10 @@ func MakeSignedRoutingState(privKey crypto.PrivKey, addrs []ma.Multiaddr) (*Sign return nil, err } return &SignedRoutingState{ - peerID: p, - seq: seq, - addresses: addrs, - envelope: envelope, + PeerID: p, + Seq: seq, + Addrs: addrs, + Envelope: envelope, }, nil } @@ -82,11 +84,11 @@ func UnmarshalSignedRoutingState(envelopeBytes []byte) (*SignedRoutingState, err // Fails if the signature is invalid, if the envelope has an unexpected payload type, // or if deserialization of the envelope payload fails. func SignedRoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*SignedRoutingState, error) { - if bytes.Compare(envelope.PayloadType(), StateEnvelopePayloadType) != 0 { + if bytes.Compare(envelope.PayloadType, StateEnvelopePayloadType) != 0 { return nil, errors.New("unexpected envelope payload type") } var msg pb.RoutingStateRecord - err := proto.Unmarshal(envelope.Payload(), &msg) + err := proto.Unmarshal(envelope.Payload, &msg) if err != nil { return nil, err } @@ -94,36 +96,21 @@ func SignedRoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*SignedRou if err != nil { return nil, err } - if !id.MatchesPublicKey(envelope.PublicKey()) { + if !id.MatchesPublicKey(envelope.PublicKey) { return nil, errors.New("peer id in routing state record does not match signing key") } return &SignedRoutingState{ - peerID: id, - seq: msg.Seq, - addresses: addrsFromProtobuf(msg.Addresses), - envelope: envelope, + PeerID: id, + Seq: msg.Seq, + Addrs: addrsFromProtobuf(msg.Addresses), + Envelope: envelope, }, nil } // Marshal returns a byte slice containing the SignedRoutingState as a serialized SignedEnvelope // protobuf message. func (s *SignedRoutingState) Marshal() ([]byte, error) { - return s.envelope.Marshal() -} - -// PeerID is the ID of the peer this record pertains to. -func (s *SignedRoutingState) PeerID() peer.ID { - return s.peerID -} - -// Seq is an increment-only sequence counter used to order RoutingState records in time. -func (s *SignedRoutingState) Seq() uint64 { - return s.seq -} - -// Multiaddrs contains the public addresses of the peer this record pertains to. -func (s *SignedRoutingState) Multiaddrs() []ma.Multiaddr { - return s.addresses + return s.Envelope.Marshal() } // Equal returns true if the other SignedRoutingState is identical to this one. @@ -131,21 +118,21 @@ func (s *SignedRoutingState) Equal(other *SignedRoutingState) bool { if other == nil { return false } - if s.seq != other.seq { + if s.Seq != other.Seq { return false } - if s.peerID != other.peerID { + if s.PeerID != other.PeerID { return false } - if len(s.addresses) != len(other.addresses) { + if len(s.Addrs) != len(other.Addrs) { return false } - for i, _ := range s.addresses { - if !s.addresses[i].Equal(other.addresses[i]) { + for i, _ := range s.Addrs { + if !s.Addrs[i].Equal(other.Addrs[i]) { return false } } - return s.envelope.Equal(other.envelope) + return s.Envelope.Equal(other.Envelope) } // statelessSeqNo is a helper to generate a timestamp-based sequence number. From ff5ddb384680525fd58db43652264e57bdfee99d Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Dec 2019 12:12:35 -0500 Subject: [PATCH 24/69] use multiformats uvarint for length-prefixes --- crypto/envelope.go | 40 ++++++++++++++------------------- go.mod | 1 + go.sum | 55 ---------------------------------------------- 3 files changed, 18 insertions(+), 78 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index 3a0c79fe..5bc2bdbd 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -2,13 +2,13 @@ package crypto import ( "bytes" - "encoding/binary" "errors" "github.com/gogo/protobuf/proto" "github.com/libp2p/go-buffer-pool" pb "github.com/libp2p/go-libp2p-core/crypto/pb" + "github.com/multiformats/go-varint" ) // SignedEnvelope contains an arbitrary []byte payload, signed by a libp2p peer. @@ -142,17 +142,26 @@ func makeSigBuffer(domain string, payloadType []byte, payload []byte) ([]byte, e domainBytes := []byte(domain) fields := [][]byte{domainBytes, payloadType, payload} - const lengthPrefixSize = 8 - size := 0 - for _, f := range fields { - size += len(f) + lengthPrefixSize + // fields are prefixed with their length as an unsigned varint. + // we compute the lengths before allocating the sig + // buffer so we know how much space to add for the lengths + fieldLengths := make([][]byte, len(fields)) + bufSize := 0 + for i, f := range fields { + l := len(f) + fieldLengths[i] = varint.ToUvarint(uint64(l)) + bufSize += l + len(fieldLengths[i]) } b := pool.NewBuffer(nil) - b.Grow(size) + b.Grow(bufSize) - for _, f := range fields { - err := writeField(b, f) + for i, f := range fields { + _, err := b.Write(fieldLengths[i]) + if err != nil { + return nil, err + } + _, err = b.Write(f) if err != nil { return nil, err } @@ -160,18 +169,3 @@ func makeSigBuffer(domain string, payloadType []byte, payload []byte) ([]byte, e return b.Bytes(), nil } - -func writeField(b *pool.Buffer, f []byte) error { - _, err := b.Write(encodedSize(f)) - if err != nil { - return err - } - _, err = b.Write(f) - return err -} - -func encodedSize(content []byte) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(len(content))) - return b -} diff --git a/go.mod b/go.mod index c2e6c887..45795ac5 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/mr-tron/base58 v1.1.3 github.com/multiformats/go-multiaddr v0.2.0 github.com/multiformats/go-multihash v0.0.10 + github.com/multiformats/go-varint v0.0.1 github.com/smola/gocompat v0.2.0 go.opencensus.io v0.22.2 ) diff --git a/go.sum b/go.sum index 542a7713..57e096a6 100644 --- a/go.sum +++ b/go.sum @@ -1,46 +1,31 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495 h1:6IyqGr3fnd0tM3YxipK27TUskaOVUjU2nG45yzwcQKY= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= 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= -github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= @@ -50,49 +35,33 @@ github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/libp2p/go-buffer-pool v0.0.1 h1:9Rrn/H46cXjaA2HQ5Y8lyhOS1NhTkZ4yuEs2r3Eechg= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg= -github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -104,9 +73,7 @@ github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5 github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -115,33 +82,23 @@ github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smola/gocompat v0.2.0 h1:6b1oIMlUXIpz//VKEDzPVBK8KG7beVwmHIUEBIs/Pns= github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/src-d/envconfig v1.0.0 h1:/AJi6DtjFhZKNx3OB2qMsq7y4yT5//AeSZIe7rk+PX8= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -153,9 +110,7 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -166,9 +121,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= @@ -179,9 +132,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c h1:vamGzbGri8IKo20MQncCuljcQ5uAO6kaCeawQPVblAI= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -189,18 +140,12 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d h1:mXa4inJUuWOoA4uEROxtJ3VMELMlVkIxIfcR0HBekAM= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1 h1:heWvX7J6qbGWbeFS/aRmiy1eYaT+QMV6wNvHDyMjQV4= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From fb521c6433b5aabe3ab13b2e31967cff0b5db9c7 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 25 Nov 2019 11:58:50 -0600 Subject: [PATCH 25/69] use camelCase in protos for consistency --- crypto/pb/envelope.proto | 4 ++-- routing/pb/routing_state.proto | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/pb/envelope.proto b/crypto/pb/envelope.proto index b8abdebb..1b96a3ae 100644 --- a/crypto/pb/envelope.proto +++ b/crypto/pb/envelope.proto @@ -5,8 +5,8 @@ package crypto.pb; import "crypto.proto"; message SignedEnvelope { - PublicKey public_key = 1; - bytes payload_type = 2; + PublicKey publicKey = 1; + bytes payloadType = 2; bytes payload = 3; bytes signature = 4; } diff --git a/routing/pb/routing_state.proto b/routing/pb/routing_state.proto index f5604dc3..8c761ac7 100644 --- a/routing/pb/routing_state.proto +++ b/routing/pb/routing_state.proto @@ -6,7 +6,7 @@ message RoutingStateRecord { bytes multiaddr = 1; } - bytes peer_id = 1; + bytes peerId = 1; uint64 seq = 2; repeated AddressInfo addresses = 3; } From 305fff1b3c97381c567b1db5e97193117de4b258 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 20 Dec 2019 16:14:10 -0500 Subject: [PATCH 26/69] fix: rebuild protos with new gogofaster generator --- crypto/pb/crypto.pb.go | 126 +++++++++++++----------------- crypto/pb/envelope.pb.go | 165 +++++++++++++++++---------------------- go.mod | 1 - 3 files changed, 126 insertions(+), 166 deletions(-) diff --git a/crypto/pb/crypto.pb.go b/crypto/pb/crypto.pb.go index 5fa7aec7..072fad9c 100644 --- a/crypto/pb/crypto.pb.go +++ b/crypto/pb/crypto.pb.go @@ -9,6 +9,7 @@ import ( proto "github.com/gogo/protobuf/proto" io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -20,7 +21,7 @@ var _ = math.Inf // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type KeyType int32 @@ -87,7 +88,7 @@ func (m *PublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PublicKey.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalTo(b) + n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } @@ -139,7 +140,7 @@ func (m *PrivateKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PrivateKey.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalTo(b) + n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } @@ -200,7 +201,7 @@ var fileDescriptor_527278fb02d03321 = []byte{ func (m *PublicKey) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -208,26 +209,32 @@ func (m *PublicKey) Marshal() (dAtA []byte, err error) { } func (m *PublicKey) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PublicKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0x8 - i++ - i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) if m.Data != nil { - dAtA[i] = 0x12 - i++ + i -= len(m.Data) + copy(dAtA[i:], m.Data) i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) - i += copy(dAtA[i:], m.Data) + i-- + dAtA[i] = 0x12 } - return i, nil + i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil } func (m *PrivateKey) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -235,30 +242,38 @@ func (m *PrivateKey) Marshal() (dAtA []byte, err error) { } func (m *PrivateKey) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PrivateKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0x8 - i++ - i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) if m.Data != nil { - dAtA[i] = 0x12 - i++ + i -= len(m.Data) + copy(dAtA[i:], m.Data) i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) - i += copy(dAtA[i:], m.Data) + i-- + dAtA[i] = 0x12 } - return i, nil + i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil } func encodeVarintCrypto(dAtA []byte, offset int, v uint64) int { + offset -= sovCrypto(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *PublicKey) Size() (n int) { if m == nil { @@ -289,14 +304,7 @@ func (m *PrivateKey) Size() (n int) { } func sovCrypto(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozCrypto(x uint64) (n int) { return sovCrypto(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -534,6 +542,7 @@ func (m *PrivateKey) Unmarshal(dAtA []byte) error { func skipCrypto(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -565,10 +574,8 @@ func skipCrypto(dAtA []byte) (n int, err error) { break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -589,55 +596,30 @@ func skipCrypto(dAtA []byte) (n int, err error) { return 0, ErrInvalidLengthCrypto } iNdEx += length - if iNdEx < 0 { - return 0, ErrInvalidLengthCrypto - } - return iNdEx, nil case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowCrypto - } - 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 := skipCrypto(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - if iNdEx < 0 { - return 0, ErrInvalidLengthCrypto - } - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCrypto + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthCrypto + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthCrypto = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowCrypto = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthCrypto = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCrypto = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCrypto = fmt.Errorf("proto: unexpected end of group") ) diff --git a/crypto/pb/envelope.pb.go b/crypto/pb/envelope.pb.go index 62687f06..d18436fb 100644 --- a/crypto/pb/envelope.pb.go +++ b/crypto/pb/envelope.pb.go @@ -8,6 +8,7 @@ import ( proto "github.com/gogo/protobuf/proto" io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -19,11 +20,11 @@ var _ = math.Inf // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type SignedEnvelope struct { - PublicKey *PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - PayloadType []byte `protobuf:"bytes,2,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"` + PublicKey *PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` + PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` } @@ -42,7 +43,7 @@ func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return xxx_messageInfo_SignedEnvelope.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalTo(b) + n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } @@ -96,26 +97,25 @@ func init() { func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } var fileDescriptor_ee266e8c558e9dc5 = []byte{ - // 200 bytes of a gzipped FileDescriptorProto + // 189 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4c, 0x2e, 0xaa, 0x2c, - 0x28, 0xc9, 0xd7, 0x2b, 0x48, 0x92, 0xe2, 0x81, 0x31, 0x41, 0x12, 0x4a, 0x0b, 0x18, 0xb9, 0xf8, - 0x82, 0x33, 0xd3, 0xf3, 0x52, 0x53, 0x5c, 0xa1, 0x3a, 0x84, 0x8c, 0xb9, 0xb8, 0x0a, 0x4a, 0x93, - 0x72, 0x32, 0x93, 0xe3, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0x44, 0xf4, - 0xe0, 0x06, 0xe8, 0x05, 0x80, 0x25, 0xbd, 0x53, 0x2b, 0x83, 0x38, 0x0b, 0x60, 0x4c, 0x21, 0x45, - 0x2e, 0x9e, 0x82, 0xc4, 0xca, 0x9c, 0xfc, 0xc4, 0x94, 0xf8, 0x92, 0xca, 0x82, 0x54, 0x09, 0x26, - 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x6e, 0xa8, 0x58, 0x48, 0x65, 0x41, 0xaa, 0x90, 0x04, 0x17, 0x3b, - 0x94, 0x2b, 0xc1, 0x0c, 0x96, 0x85, 0x71, 0x85, 0x64, 0xb8, 0x38, 0x8b, 0x33, 0xd3, 0xf3, 0x12, - 0x4b, 0x4a, 0x8b, 0x52, 0x25, 0x58, 0xc0, 0x72, 0x08, 0x01, 0x27, 0x89, 0x13, 0x8f, 0xe4, 0x18, - 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, - 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xfb, 0xc1, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, - 0x40, 0xc9, 0x83, 0xba, 0xee, 0x00, 0x00, 0x00, + 0x28, 0xc9, 0xd7, 0x2b, 0x48, 0x92, 0xe2, 0x81, 0x31, 0x41, 0x12, 0x4a, 0xf3, 0x18, 0xb9, 0xf8, + 0x82, 0x33, 0xd3, 0xf3, 0x52, 0x53, 0x5c, 0xa1, 0x3a, 0x84, 0x8c, 0xb8, 0x38, 0x0b, 0x4a, 0x93, + 0x72, 0x32, 0x93, 0xbd, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0x44, 0xf4, 0xe0, + 0xfa, 0xf5, 0x02, 0x60, 0x72, 0x41, 0x08, 0x65, 0x42, 0x0a, 0x5c, 0xdc, 0x05, 0x89, 0x95, 0x39, + 0xf9, 0x89, 0x29, 0x21, 0x95, 0x05, 0xa9, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0xc8, 0x42, + 0x42, 0x12, 0x5c, 0xec, 0x50, 0xae, 0x04, 0x33, 0x58, 0x16, 0xc6, 0x15, 0x92, 0xe1, 0xe2, 0x2c, + 0xce, 0x4c, 0xcf, 0x4b, 0x2c, 0x29, 0x2d, 0x4a, 0x95, 0x60, 0x01, 0xcb, 0x21, 0x04, 0x9c, 0x24, + 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, + 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, 0x0d, 0xec, 0x03, 0x63, 0x40, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x25, 0xd3, 0xde, 0xe5, 0xec, 0x00, 0x00, 0x00, } func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -123,49 +123,61 @@ func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { } func (m *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SignedEnvelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.PublicKey != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintEnvelope(dAtA, i, uint64(m.PublicKey.Size())) - n1, err := m.PublicKey.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - } - if len(m.PayloadType) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) - i += copy(dAtA[i:], m.PayloadType) + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x22 } if len(m.Payload) > 0 { - dAtA[i] = 0x1a - i++ + i -= len(m.Payload) + copy(dAtA[i:], m.Payload) i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Payload))) - i += copy(dAtA[i:], m.Payload) + i-- + dAtA[i] = 0x1a } - if len(m.Signature) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) - i += copy(dAtA[i:], m.Signature) + if len(m.PayloadType) > 0 { + i -= len(m.PayloadType) + copy(dAtA[i:], m.PayloadType) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) + i-- + dAtA[i] = 0x12 } - return i, nil + if m.PublicKey != nil { + { + size, err := m.PublicKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEnvelope(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func encodeVarintEnvelope(dAtA []byte, offset int, v uint64) int { + offset -= sovEnvelope(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *SignedEnvelope) Size() (n int) { if m == nil { @@ -193,14 +205,7 @@ func (m *SignedEnvelope) Size() (n int) { } func sovEnvelope(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozEnvelope(x uint64) (n int) { return sovEnvelope(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -399,6 +404,7 @@ func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { func skipEnvelope(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -430,10 +436,8 @@ func skipEnvelope(dAtA []byte) (n int, err error) { break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -454,55 +458,30 @@ func skipEnvelope(dAtA []byte) (n int, err error) { return 0, ErrInvalidLengthEnvelope } iNdEx += length - if iNdEx < 0 { - return 0, ErrInvalidLengthEnvelope - } - return iNdEx, nil case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowEnvelope - } - 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 := skipEnvelope(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - if iNdEx < 0 { - return 0, ErrInvalidLengthEnvelope - } - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEnvelope + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEnvelope = fmt.Errorf("proto: unexpected end of group") ) diff --git a/go.mod b/go.mod index 45795ac5..a7f87f02 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ 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-buffer-pool v0.0.1 From ae469c68016eab0b9e466ddd57e31af7ecd92cb3 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Dec 2019 12:24:34 -0500 Subject: [PATCH 27/69] remove payloadType check when unmarhaling --- routing/state.go | 4 ---- routing/state_test.go | 11 ----------- 2 files changed, 15 deletions(-) diff --git a/routing/state.go b/routing/state.go index b9fc7592..c626685e 100644 --- a/routing/state.go +++ b/routing/state.go @@ -1,7 +1,6 @@ package routing import ( - "bytes" "errors" "github.com/gogo/protobuf/proto" "github.com/libp2p/go-libp2p-core/crypto" @@ -84,9 +83,6 @@ func UnmarshalSignedRoutingState(envelopeBytes []byte) (*SignedRoutingState, err // Fails if the signature is invalid, if the envelope has an unexpected payload type, // or if deserialization of the envelope payload fails. func SignedRoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*SignedRoutingState, error) { - if bytes.Compare(envelope.PayloadType, StateEnvelopePayloadType) != 0 { - return nil, errors.New("unexpected envelope payload type") - } var msg pb.RoutingStateRecord err := proto.Unmarshal(envelope.Payload, &msg) if err != nil { diff --git a/routing/state_test.go b/routing/state_test.go index ea21588f..bc218a8f 100644 --- a/routing/state_test.go +++ b/routing/state_test.go @@ -35,15 +35,4 @@ func TestSignedRoutingStateFromEnvelope(t *testing.T) { _, err = UnmarshalSignedRoutingState(envBytes) test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong domain string") }) - - t.Run("unwrapping from signed envelope fails if envelope has wrong payload type", func(t *testing.T) { - stateBytes, err := state.Marshal() - test.AssertNilError(t, err) - payloadType := []byte("wrong-payload-type") - env, err := crypto.MakeEnvelope(priv, StateEnvelopeDomain, payloadType, stateBytes) - test.AssertNilError(t, err) - envBytes, err := env.Marshal() - _, err = UnmarshalSignedRoutingState(envBytes) - test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong payload type") - }) } From 1168b4d715376bd9f83c1cecec014b39dcfd8d44 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Dec 2019 15:42:05 -0500 Subject: [PATCH 28/69] rm stray ref to golang/protobuf --- crypto/envelope_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index 0e1c69b2..9e3964b3 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -2,7 +2,7 @@ package crypto_test import ( "bytes" - "github.com/golang/protobuf/proto" + "github.com/gogo/protobuf/proto" . "github.com/libp2p/go-libp2p-core/crypto" pb "github.com/libp2p/go-libp2p-core/crypto/pb" From 74bb6bbf1e4a6663ed2e1cc246e7a0ba4bf10b34 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 20 Dec 2019 16:15:01 -0500 Subject: [PATCH 29/69] filter private addrs from signed routing records --- go.mod | 1 + go.sum | 7 +-- host/helpers.go | 47 +++++++++++++++- host/helpers_test.go | 131 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 host/helpers_test.go diff --git a/go.mod b/go.mod index a7f87f02..07e0fec6 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/minio/sha256-simd v0.1.1 github.com/mr-tron/base58 v1.1.3 github.com/multiformats/go-multiaddr v0.2.0 + github.com/multiformats/go-multiaddr-net v0.1.1 github.com/multiformats/go-multihash v0.0.10 github.com/multiformats/go-varint v0.0.1 github.com/smola/gocompat v0.2.0 diff --git a/go.sum b/go.sum index 57e096a6..0b299001 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.4 h1:UlfXKrZx1DjZoBhQHmNHLC1fK1dUJDN20Y28A7s+gJ8= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= @@ -67,10 +65,11 @@ github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-multiaddr v0.1.2 h1:HWYHNSyyllbQopmVIF5K7JKJugiah+L9/kuZKHbmNdQ= -github.com/multiformats/go-multiaddr v0.1.2/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr-net v0.1.1 h1:jFFKUuXTXv+3ARyHZi3XUqQO+YWMKgBdhEvuGRfnL6s= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= diff --git a/host/helpers.go b/host/helpers.go index 276eeaea..aa7ae3a2 100644 --- a/host/helpers.go +++ b/host/helpers.go @@ -3,7 +3,10 @@ package host import ( "errors" "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" "github.com/libp2p/go-libp2p-core/routing" + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr-net" ) // InfoFromHost returns a peer.AddrInfo struct with the Host's ID and all of its Addrs. @@ -16,11 +19,51 @@ func InfoFromHost(h Host) *peer.AddrInfo { // SignedRoutingStateFromHost returns a SignedRoutingState record containing // the Host's listen addresses, signed with the Host's private key. -func SignedRoutingStateFromHost(h Host) (*routing.SignedRoutingState, error) { +// +// By default, only publicly routable addresses will be included. +// To include loopback and LAN addresses, pass in the IncludeLocalAddrs option: +// +// state := SignedRoutingStateFromHost(h, IncludeLocalAddrs) +func SignedRoutingStateFromHost(h minimalHost, opts ...Option) (*routing.SignedRoutingState, error) { + cfg := config{} + for _, opt := range opts { + opt(&cfg) + } + privKey := h.Peerstore().PrivKey(h.ID()) if privKey == nil { return nil, errors.New("unable to find host's private key in peerstore") } - return routing.MakeSignedRoutingState(privKey, h.Addrs()) + var addrs []ma.Multiaddr + if cfg.includeLocalAddrs { + addrs = h.Addrs() + } else { + for _, a := range h.Addrs() { + if manet.IsPublicAddr(a) { + addrs = append(addrs, a) + } + } + } + + return routing.MakeSignedRoutingState(privKey, addrs) +} + +// IncludeLocalAddrs can be passed into SignedRoutingStateFromHost to +// produce a routing record with LAN and loopback addresses included. +func IncludeLocalAddrs(cfg *config) { + cfg.includeLocalAddrs = true +} + +// minimalHost is the subset of the Host interface that's required by +// SignedRoutingStateFromHost. +type minimalHost interface { + ID() peer.ID + Peerstore() peerstore.Peerstore + Addrs() []ma.Multiaddr +} + +type Option func(cfg *config) +type config struct { + includeLocalAddrs bool } diff --git a/host/helpers_test.go b/host/helpers_test.go new file mode 100644 index 00000000..52cf261a --- /dev/null +++ b/host/helpers_test.go @@ -0,0 +1,131 @@ +package host + +import ( + "context" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/routing" + "github.com/libp2p/go-libp2p-core/test" + ma "github.com/multiformats/go-multiaddr" + "testing" + "time" +) + +type mockHost struct { + fixedPrivKey crypto.PrivKey + addrs []ma.Multiaddr +} + +func (h *mockHost) Addrs() []ma.Multiaddr { + return h.addrs +} + +func (h *mockHost) Peerstore() peerstore.Peerstore { + return mockPeerstore{fixedPrivKey: h.fixedPrivKey} +} + +func (*mockHost) ID() peer.ID { return "" } + +type mockPeerstore struct { + fixedPrivKey crypto.PrivKey +} + +// the one method I care about... +func (m mockPeerstore) PrivKey(peer.ID) crypto.PrivKey { + return m.fixedPrivKey +} + +// so many other things in the Peerstore interface... +func (m mockPeerstore) Close() error { return nil } +func (m mockPeerstore) AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) {} +func (m mockPeerstore) AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) {} +func (m mockPeerstore) AddCertifiedAddrs(s *routing.SignedRoutingState, ttl time.Duration) error { + return nil +} +func (m mockPeerstore) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) {} +func (m mockPeerstore) SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) {} +func (m mockPeerstore) UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) {} +func (m mockPeerstore) Addrs(p peer.ID) []ma.Multiaddr { return nil } +func (m mockPeerstore) CertifiedAddrs(p peer.ID) []ma.Multiaddr { return nil } +func (m mockPeerstore) AddrStream(context.Context, peer.ID) <-chan ma.Multiaddr { return nil } +func (m mockPeerstore) ClearAddrs(p peer.ID) {} +func (m mockPeerstore) PeersWithAddrs() peer.IDSlice { return nil } +func (m mockPeerstore) SignedRoutingState(p peer.ID) *routing.SignedRoutingState { return nil } +func (m mockPeerstore) Get(p peer.ID, key string) (interface{}, error) { return nil, nil } +func (m mockPeerstore) Put(p peer.ID, key string, val interface{}) error { return nil } +func (m mockPeerstore) RecordLatency(peer.ID, time.Duration) {} +func (m mockPeerstore) LatencyEWMA(peer.ID) time.Duration { return 0 } +func (m mockPeerstore) GetProtocols(peer.ID) ([]string, error) { return nil, nil } +func (m mockPeerstore) AddProtocols(peer.ID, ...string) error { return nil } +func (m mockPeerstore) SetProtocols(peer.ID, ...string) error { return nil } +func (m mockPeerstore) RemoveProtocols(peer.ID, ...string) error { return nil } +func (m mockPeerstore) SupportsProtocols(peer.ID, ...string) ([]string, error) { return nil, nil } +func (m mockPeerstore) PeerInfo(peer.ID) peer.AddrInfo { return peer.AddrInfo{} } +func (m mockPeerstore) Peers() peer.IDSlice { return nil } +func (m mockPeerstore) PubKey(peer.ID) crypto.PubKey { return nil } +func (m mockPeerstore) AddPubKey(peer.ID, crypto.PubKey) error { return nil } +func (m mockPeerstore) AddPrivKey(peer.ID, crypto.PrivKey) error { return nil } +func (m mockPeerstore) PeersWithKeys() peer.IDSlice { return nil } + +func TestSignedRoutingStateFromHost_FailsIfPrivKeyIsNil(t *testing.T) { + _, err := SignedRoutingStateFromHost(&mockHost{}) + test.ExpectError(t, err, "expected generating signed routing state to fail when host private key is nil") +} + +func TestSignedRoutingStateFromHost_AddrFiltering(t *testing.T) { + localAddrs := parseAddrs(t, + // loopback + "/ip4/127.0.0.1/tcp/42", + "/ip6/::1/tcp/9999", + + // ip4 LAN reserved + "/ip4/10.0.0.1/tcp/1234", + "/ip4/100.64.0.123/udp/10101", + "/ip4/172.16.0.254/tcp/2345", + "/ip4/192.168.1.4/udp/1600", + + // link local + "/ip4/169.254.0.1/udp/1234", + "/ip6/fe80::c001:37ff:fe6c:0/tcp/42", + ) + + wanAddrs := parseAddrs(t, + "/ip4/1.2.3.4/tcp/42", + "/ip4/8.8.8.8/udp/1234", + "/ip6/2607:f8b0:4002:c02::8a/udp/1234", + "/ip6/2a03:2880:f111:83:face:b00c:0:25de/udp/2345/quic", + ) + + priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) + if err != nil { + t.Fatal(err) + } + + host := &mockHost{ + fixedPrivKey: priv, + addrs: append(localAddrs, wanAddrs...), + } + + // test with local addrs + state, err := SignedRoutingStateFromHost(host, IncludeLocalAddrs) + if err != nil { + t.Fatalf("error generating routing state: %v", err) + } + test.AssertAddressesEqual(t, host.addrs, state.Addrs) + + // test filtering out local addrs + state, err = SignedRoutingStateFromHost(host) + if err != nil { + t.Fatalf("error generating routing state: %v", err) + } + test.AssertAddressesEqual(t, wanAddrs, state.Addrs) +} + +func parseAddrs(t *testing.T, addrStrings ...string) (out []ma.Multiaddr) { + t.Helper() + for _, s := range addrStrings { + out = append(out, ma.StringCast(s)) + } + return out +} From 8a8390e4f7d303faf21223238f5ccccd28e92c91 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 20 Dec 2019 15:59:54 -0500 Subject: [PATCH 30/69] add events for updated addresses and routing state --- event/addrs.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 event/addrs.go diff --git a/event/addrs.go b/event/addrs.go new file mode 100644 index 00000000..d39024eb --- /dev/null +++ b/event/addrs.go @@ -0,0 +1,25 @@ +package event + +import ( + "github.com/libp2p/go-libp2p-core/routing" + ma "github.com/multiformats/go-multiaddr" +) + +// EvtLocalAddressesUpdated should be emitted when the set of listen addresses for +// the local host changes. This may happen for a number of reasons. For example, +// we may have opened a new relay connection, established a new NAT mapping via +// UPnP, or been informed of our observed address by another peer. +type EvtLocalAddressesUpdated struct { + // Added enumerates the listen addresses that were added for the local peer. + Added []ma.Multiaddr + + // Removed enumerates listen addresses that were removed from the local peer. + Removed []ma.Multiaddr +} + +// EvtLocalPeerRoutingStateUpdated should be emitted when a new SignedRoutingState +// record for the local peer has been produced. This will happen whenever the set +// of listen addresses changes. +type EvtLocalPeerRoutingStateUpdated struct { + State *routing.SignedRoutingState +} From 0bcca67988b2b8b444036d280f81f0cbfd733d87 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 20 Dec 2019 16:00:27 -0500 Subject: [PATCH 31/69] remove SignedRoutingStateFromHost helper moving this to go-libp2p --- go.mod | 1 - host/helpers.go | 56 ------------------ host/helpers_test.go | 131 ------------------------------------------- 3 files changed, 188 deletions(-) delete mode 100644 host/helpers_test.go diff --git a/go.mod b/go.mod index 07e0fec6..a7f87f02 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/minio/sha256-simd v0.1.1 github.com/mr-tron/base58 v1.1.3 github.com/multiformats/go-multiaddr v0.2.0 - github.com/multiformats/go-multiaddr-net v0.1.1 github.com/multiformats/go-multihash v0.0.10 github.com/multiformats/go-varint v0.0.1 github.com/smola/gocompat v0.2.0 diff --git a/host/helpers.go b/host/helpers.go index aa7ae3a2..fd77cd1d 100644 --- a/host/helpers.go +++ b/host/helpers.go @@ -1,12 +1,7 @@ package host import ( - "errors" "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/peerstore" - "github.com/libp2p/go-libp2p-core/routing" - ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr-net" ) // InfoFromHost returns a peer.AddrInfo struct with the Host's ID and all of its Addrs. @@ -16,54 +11,3 @@ func InfoFromHost(h Host) *peer.AddrInfo { Addrs: h.Addrs(), } } - -// SignedRoutingStateFromHost returns a SignedRoutingState record containing -// the Host's listen addresses, signed with the Host's private key. -// -// By default, only publicly routable addresses will be included. -// To include loopback and LAN addresses, pass in the IncludeLocalAddrs option: -// -// state := SignedRoutingStateFromHost(h, IncludeLocalAddrs) -func SignedRoutingStateFromHost(h minimalHost, opts ...Option) (*routing.SignedRoutingState, error) { - cfg := config{} - for _, opt := range opts { - opt(&cfg) - } - - privKey := h.Peerstore().PrivKey(h.ID()) - if privKey == nil { - return nil, errors.New("unable to find host's private key in peerstore") - } - - var addrs []ma.Multiaddr - if cfg.includeLocalAddrs { - addrs = h.Addrs() - } else { - for _, a := range h.Addrs() { - if manet.IsPublicAddr(a) { - addrs = append(addrs, a) - } - } - } - - return routing.MakeSignedRoutingState(privKey, addrs) -} - -// IncludeLocalAddrs can be passed into SignedRoutingStateFromHost to -// produce a routing record with LAN and loopback addresses included. -func IncludeLocalAddrs(cfg *config) { - cfg.includeLocalAddrs = true -} - -// minimalHost is the subset of the Host interface that's required by -// SignedRoutingStateFromHost. -type minimalHost interface { - ID() peer.ID - Peerstore() peerstore.Peerstore - Addrs() []ma.Multiaddr -} - -type Option func(cfg *config) -type config struct { - includeLocalAddrs bool -} diff --git a/host/helpers_test.go b/host/helpers_test.go deleted file mode 100644 index 52cf261a..00000000 --- a/host/helpers_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package host - -import ( - "context" - "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/peerstore" - "github.com/libp2p/go-libp2p-core/routing" - "github.com/libp2p/go-libp2p-core/test" - ma "github.com/multiformats/go-multiaddr" - "testing" - "time" -) - -type mockHost struct { - fixedPrivKey crypto.PrivKey - addrs []ma.Multiaddr -} - -func (h *mockHost) Addrs() []ma.Multiaddr { - return h.addrs -} - -func (h *mockHost) Peerstore() peerstore.Peerstore { - return mockPeerstore{fixedPrivKey: h.fixedPrivKey} -} - -func (*mockHost) ID() peer.ID { return "" } - -type mockPeerstore struct { - fixedPrivKey crypto.PrivKey -} - -// the one method I care about... -func (m mockPeerstore) PrivKey(peer.ID) crypto.PrivKey { - return m.fixedPrivKey -} - -// so many other things in the Peerstore interface... -func (m mockPeerstore) Close() error { return nil } -func (m mockPeerstore) AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) {} -func (m mockPeerstore) AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) {} -func (m mockPeerstore) AddCertifiedAddrs(s *routing.SignedRoutingState, ttl time.Duration) error { - return nil -} -func (m mockPeerstore) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) {} -func (m mockPeerstore) SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) {} -func (m mockPeerstore) UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) {} -func (m mockPeerstore) Addrs(p peer.ID) []ma.Multiaddr { return nil } -func (m mockPeerstore) CertifiedAddrs(p peer.ID) []ma.Multiaddr { return nil } -func (m mockPeerstore) AddrStream(context.Context, peer.ID) <-chan ma.Multiaddr { return nil } -func (m mockPeerstore) ClearAddrs(p peer.ID) {} -func (m mockPeerstore) PeersWithAddrs() peer.IDSlice { return nil } -func (m mockPeerstore) SignedRoutingState(p peer.ID) *routing.SignedRoutingState { return nil } -func (m mockPeerstore) Get(p peer.ID, key string) (interface{}, error) { return nil, nil } -func (m mockPeerstore) Put(p peer.ID, key string, val interface{}) error { return nil } -func (m mockPeerstore) RecordLatency(peer.ID, time.Duration) {} -func (m mockPeerstore) LatencyEWMA(peer.ID) time.Duration { return 0 } -func (m mockPeerstore) GetProtocols(peer.ID) ([]string, error) { return nil, nil } -func (m mockPeerstore) AddProtocols(peer.ID, ...string) error { return nil } -func (m mockPeerstore) SetProtocols(peer.ID, ...string) error { return nil } -func (m mockPeerstore) RemoveProtocols(peer.ID, ...string) error { return nil } -func (m mockPeerstore) SupportsProtocols(peer.ID, ...string) ([]string, error) { return nil, nil } -func (m mockPeerstore) PeerInfo(peer.ID) peer.AddrInfo { return peer.AddrInfo{} } -func (m mockPeerstore) Peers() peer.IDSlice { return nil } -func (m mockPeerstore) PubKey(peer.ID) crypto.PubKey { return nil } -func (m mockPeerstore) AddPubKey(peer.ID, crypto.PubKey) error { return nil } -func (m mockPeerstore) AddPrivKey(peer.ID, crypto.PrivKey) error { return nil } -func (m mockPeerstore) PeersWithKeys() peer.IDSlice { return nil } - -func TestSignedRoutingStateFromHost_FailsIfPrivKeyIsNil(t *testing.T) { - _, err := SignedRoutingStateFromHost(&mockHost{}) - test.ExpectError(t, err, "expected generating signed routing state to fail when host private key is nil") -} - -func TestSignedRoutingStateFromHost_AddrFiltering(t *testing.T) { - localAddrs := parseAddrs(t, - // loopback - "/ip4/127.0.0.1/tcp/42", - "/ip6/::1/tcp/9999", - - // ip4 LAN reserved - "/ip4/10.0.0.1/tcp/1234", - "/ip4/100.64.0.123/udp/10101", - "/ip4/172.16.0.254/tcp/2345", - "/ip4/192.168.1.4/udp/1600", - - // link local - "/ip4/169.254.0.1/udp/1234", - "/ip6/fe80::c001:37ff:fe6c:0/tcp/42", - ) - - wanAddrs := parseAddrs(t, - "/ip4/1.2.3.4/tcp/42", - "/ip4/8.8.8.8/udp/1234", - "/ip6/2607:f8b0:4002:c02::8a/udp/1234", - "/ip6/2a03:2880:f111:83:face:b00c:0:25de/udp/2345/quic", - ) - - priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) - if err != nil { - t.Fatal(err) - } - - host := &mockHost{ - fixedPrivKey: priv, - addrs: append(localAddrs, wanAddrs...), - } - - // test with local addrs - state, err := SignedRoutingStateFromHost(host, IncludeLocalAddrs) - if err != nil { - t.Fatalf("error generating routing state: %v", err) - } - test.AssertAddressesEqual(t, host.addrs, state.Addrs) - - // test filtering out local addrs - state, err = SignedRoutingStateFromHost(host) - if err != nil { - t.Fatalf("error generating routing state: %v", err) - } - test.AssertAddressesEqual(t, wanAddrs, state.Addrs) -} - -func parseAddrs(t *testing.T, addrStrings ...string) (out []ma.Multiaddr) { - t.Helper() - for _, s := range addrStrings { - out = append(out, ma.StringCast(s)) - } - return out -} From 6028ba0bbafdb805dac34af1f0cc62156ecb7c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 27 Dec 2019 20:07:28 +0000 Subject: [PATCH 32/69] envelope: use byte slices from pool; adjust interface. --- crypto/envelope.go | 120 +++++++++++++++++++++------------------- crypto/envelope_test.go | 78 ++++++++++++++++++-------- 2 files changed, 117 insertions(+), 81 deletions(-) diff --git a/crypto/envelope.go b/crypto/envelope.go index 5bc2bdbd..9fb1770f 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -3,19 +3,21 @@ package crypto import ( "bytes" "errors" + "fmt" "github.com/gogo/protobuf/proto" - "github.com/libp2p/go-buffer-pool" + pool "github.com/libp2p/go-buffer-pool" pb "github.com/libp2p/go-libp2p-core/crypto/pb" "github.com/multiformats/go-varint" ) // SignedEnvelope contains an arbitrary []byte payload, signed by a libp2p peer. -// Envelopes are signed in the context of a particular "domain", which is a string -// specified when creating and verifying the envelope. You must know the domain -// string used to produce the envelope in order to verify the signature and -// access the payload. +// +// Envelopes are signed in the context of a particular "domain", which is a +// string specified when creating and verifying the envelope. You must know the +// domain string used to produce the envelope in order to verify the signature +// and access the payload. type SignedEnvelope struct { // The public key that can be used to verify the signature and derive the peer id of the signer. PublicKey PubKey @@ -27,12 +29,12 @@ type SignedEnvelope struct { // The envelope payload. Payload []byte - // The signature of the domain string, type hint, and payload. + // The signature of the domain string :: type hint :: payload. signature []byte } -var errEmptyDomain = errors.New("envelope domain must not be empty") -var errInvalidSignature = errors.New("invalid signature or incorrect domain") +var ErrEmptyDomain = errors.New("envelope domain must not be empty") +var ErrInvalidSignature = errors.New("invalid signature or incorrect domain") // MakeEnvelope constructs a new SignedEnvelope using the given privateKey. // @@ -41,14 +43,17 @@ var errInvalidSignature = errors.New("invalid signature or incorrect domain") // // The 'PayloadType' field indicates what kind of data is contained and may be empty. func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload []byte) (*SignedEnvelope, error) { - if len(domain) == 0 { - return nil, errEmptyDomain + if domain == "" { + return nil, ErrEmptyDomain } - toSign, err := makeSigBuffer(domain, payloadType, payload) + + unsigned, err := makeUnsigned(domain, payloadType, payload) if err != nil { return nil, err } - sig, err := privateKey.Sign(toSign) + defer pool.Put(unsigned) + + sig, err := privateKey.Sign(unsigned) if err != nil { return nil, err } @@ -61,32 +66,31 @@ func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload }, nil } -// OpenEnvelope unmarshals a serialized SignedEnvelope, validating its signature -// using the provided 'domain' string. -func OpenEnvelope(envelopeBytes []byte, domain string) (*SignedEnvelope, error) { - e, err := UnmarshalEnvelopeWithoutValidating(envelopeBytes) +// ConsumeEnvelope unmarshals a serialized SignedEnvelope, and validates its +// signature using the provided 'domain' string. If validation fails, an error +// is returned, along with the unmarshalled payload so it can be inspected. +func ConsumeEnvelope(data []byte, domain string) (*SignedEnvelope, error) { + e, err := UnmarshalEnvelope(data) if err != nil { - return nil, err - } - err = e.validate(domain) - if err != nil { - return nil, err + return nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) } - return e, nil + + return e, e.validate(domain) } -// UnmarshalEnvelopeWithoutValidating unmarshals a serialized SignedEnvelope protobuf message, -// without validating its contents. Should not be used unless you have a very good reason -// (e.g. testing)! -func UnmarshalEnvelopeWithoutValidating(serializedEnvelope []byte) (*SignedEnvelope, error) { +// UnmarshalEnvelope unmarshals a serialized SignedEnvelope protobuf message, +// without validating its contents. Most users should use ConsumeEnvelope. +func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { var e pb.SignedEnvelope - if err := proto.Unmarshal(serializedEnvelope, &e); err != nil { + if err := proto.Unmarshal(data, &e); err != nil { return nil, err } + key, err := PublicKeyFromProto(e.PublicKey) if err != nil { return nil, err } + return &SignedEnvelope{ PublicKey: key, PayloadType: e.PayloadType, @@ -95,12 +99,14 @@ func UnmarshalEnvelopeWithoutValidating(serializedEnvelope []byte) (*SignedEnvel }, nil } -// Marshal returns a byte slice containing a serailized protobuf representation of a SignedEnvelope. +// Marshal returns a byte slice containing a serialized protobuf representation +// of a SignedEnvelope. func (e *SignedEnvelope) Marshal() ([]byte, error) { key, err := PublicKeyToProto(e.PublicKey) if err != nil { return nil, err } + msg := pb.SignedEnvelope{ PublicKey: key, PayloadType: e.PayloadType, @@ -110,9 +116,9 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { return proto.Marshal(&msg) } -// Equal returns true if the other SignedEnvelope has the same -// public key, payload, payload type, and signature. This -// implies that they were also created with the same domain string. +// Equal returns true if the other SignedEnvelope has the same public key, +// payload, payload type, and signature. This implies that they were also +// created with the same domain string. func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { return e.PublicKey.Equals(other.PublicKey) && bytes.Compare(e.PayloadType, other.PayloadType) == 0 && @@ -123,49 +129,49 @@ func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { // validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) validate(domain string) error { - toVerify, err := makeSigBuffer(domain, e.PayloadType, e.Payload) + unsigned, err := makeUnsigned(domain, e.PayloadType, e.Payload) if err != nil { return err } - valid, err := e.PublicKey.Verify(toVerify, e.signature) + defer pool.Put(unsigned) + + valid, err := e.PublicKey.Verify(unsigned, e.signature) if err != nil { - return err + return fmt.Errorf("failed while verifying signature: %w", err) } if !valid { - return errInvalidSignature + return ErrInvalidSignature } return nil } -// makeSigBuffer is a helper function that prepares a buffer to sign or verify. -func makeSigBuffer(domain string, payloadType []byte, payload []byte) ([]byte, error) { - domainBytes := []byte(domain) - fields := [][]byte{domainBytes, payloadType, payload} +// makeUnsigned is a helper function that prepares a buffer to sign or verify. +// It returns a byte slice from a pool. The caller MUST return this slice to the +// pool. +func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, error) { + var ( + fields = [][]byte{[]byte(domain), payloadType, payload} + + // fields are prefixed with their length as an unsigned varint. we + // compute the lengths before allocating the sig buffer so we know how + // much space to add for the lengths + flen = make([][]byte, len(fields)) + size = 0 + ) - // fields are prefixed with their length as an unsigned varint. - // we compute the lengths before allocating the sig - // buffer so we know how much space to add for the lengths - fieldLengths := make([][]byte, len(fields)) - bufSize := 0 for i, f := range fields { l := len(f) - fieldLengths[i] = varint.ToUvarint(uint64(l)) - bufSize += l + len(fieldLengths[i]) + flen[i] = varint.ToUvarint(uint64(l)) + size += l + len(flen[i]) } - b := pool.NewBuffer(nil) - b.Grow(bufSize) + b := pool.Get(size) + var s int for i, f := range fields { - _, err := b.Write(fieldLengths[i]) - if err != nil { - return nil, err - } - _, err = b.Write(f) - if err != nil { - return nil, err - } + s += copy(b[s:], flen[i]) + s += copy(b[s:], f) } - return b.Bytes(), nil + return b[:s], nil } diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go index 9e3964b3..311b2b01 100644 --- a/crypto/envelope_test.go +++ b/crypto/envelope_test.go @@ -12,11 +12,15 @@ import ( // Make an envelope, verify & open it, marshal & unmarshal it func TestEnvelopeHappyPath(t *testing.T) { - priv, pub, err := test.RandTestKeyPair(Ed25519, 256) + var ( + payload = []byte("happy hacking") + domain = "libp2p-testing" + payloadType = []byte("/libp2p/testdata") + priv, pub, err = test.RandTestKeyPair(Ed25519, 256) + ) + test.AssertNilError(t, err) - payload := []byte("happy hacking") - domain := "libp2p-testing" - payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) test.AssertNilError(t, err) @@ -30,7 +34,8 @@ func TestEnvelopeHappyPath(t *testing.T) { serialized, err := envelope.Marshal() test.AssertNilError(t, err) - deserialized, err := OpenEnvelope(serialized, domain) + + deserialized, err := ConsumeEnvelope(serialized, domain) test.AssertNilError(t, err) if bytes.Compare(deserialized.Payload, payload) != 0 { @@ -43,60 +48,81 @@ func TestEnvelopeHappyPath(t *testing.T) { } func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { - priv, _, err := test.RandTestKeyPair(Ed25519, 256) + var ( + payload = []byte("happy hacking") + payloadType = []byte("/libp2p/testdata") + priv, _, err = test.RandTestKeyPair(Ed25519, 256) + ) + if err != nil { - t.Error(err) + t.Fatal(err) } - payload := []byte("happy hacking") - payloadType := []byte("/libp2p/testdata") + _, err = MakeEnvelope(priv, "", payloadType, payload) test.ExpectError(t, err, "making an envelope with an empty domain should fail") } func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { - priv, _, err := test.RandTestKeyPair(Ed25519, 256) + var ( + payload = []byte("happy hacking") + domain = "libp2p-testing" + payloadType = []byte("/libp2p/testdata") + priv, _, err = test.RandTestKeyPair(Ed25519, 256) + ) + test.AssertNilError(t, err) - payload := []byte("happy hacking") - domain := "libp2p-testing" - payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) test.AssertNilError(t, err) + serialized, err := envelope.Marshal() + // try to open our modified envelope - _, err = OpenEnvelope(serialized, "wrong-domain") + _, err = ConsumeEnvelope(serialized, "wrong-domain") test.ExpectError(t, err, "should not be able to open envelope with incorrect domain") } func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { - priv, _, err := test.RandTestKeyPair(Ed25519, 256) + var ( + payload = []byte("happy hacking") + domain = "libp2p-testing" + payloadType = []byte("/libp2p/testdata") + priv, _, err = test.RandTestKeyPair(Ed25519, 256) + ) + test.AssertNilError(t, err) - payload := []byte("happy hacking") - domain := "libp2p-testing" - payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) test.AssertNilError(t, err) + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { msg.PayloadType = []byte("foo") }) + // try to open our modified envelope - _, err = OpenEnvelope(serialized, domain) + _, err = ConsumeEnvelope(serialized, domain) test.ExpectError(t, err, "should not be able to open envelope with modified PayloadType") } func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { - priv, _, err := test.RandTestKeyPair(Ed25519, 256) + var ( + payload = []byte("happy hacking") + domain = "libp2p-testing" + payloadType = []byte("/libp2p/testdata") + priv, _, err = test.RandTestKeyPair(Ed25519, 256) + ) + test.AssertNilError(t, err) - payload := []byte("happy hacking") - domain := "libp2p-testing" - payloadType := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { msg.Payload = []byte("totally legit, trust me") }) + // try to open our modified envelope - _, err = OpenEnvelope(serialized, domain) + _, err = ConsumeEnvelope(serialized, domain) test.ExpectError(t, err, "should not be able to open envelope with modified payload") } @@ -107,13 +133,17 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { // Returns the serialized altered protobuf message. func alterMessageAndMarshal(t *testing.T, envelope *SignedEnvelope, alterMsg func(*pb.SignedEnvelope)) []byte { t.Helper() + serialized, err := envelope.Marshal() test.AssertNilError(t, err) + msg := pb.SignedEnvelope{} err = proto.Unmarshal(serialized, &msg) test.AssertNilError(t, err) + alterMsg(&msg) serialized, err = msg.Marshal() test.AssertNilError(t, err) + return serialized } From 123324dc1b2b3a2633b36288005db9e17006684b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 27 Dec 2019 20:09:43 +0000 Subject: [PATCH 33/69] move envelope to record package. --- {crypto => record}/envelope.go | 15 ++++++++------- {crypto => record}/envelope_test.go | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) rename {crypto => record}/envelope.go (94%) rename {crypto => record}/envelope_test.go (99%) diff --git a/crypto/envelope.go b/record/envelope.go similarity index 94% rename from crypto/envelope.go rename to record/envelope.go index 9fb1770f..a26c0019 100644 --- a/crypto/envelope.go +++ b/record/envelope.go @@ -1,14 +1,15 @@ -package crypto +package record import ( "bytes" "errors" "fmt" - "github.com/gogo/protobuf/proto" - pool "github.com/libp2p/go-buffer-pool" + "github.com/libp2p/go-libp2p-core/crypto" pb "github.com/libp2p/go-libp2p-core/crypto/pb" + + "github.com/gogo/protobuf/proto" "github.com/multiformats/go-varint" ) @@ -20,7 +21,7 @@ import ( // and access the payload. type SignedEnvelope struct { // The public key that can be used to verify the signature and derive the peer id of the signer. - PublicKey PubKey + PublicKey crypto.PubKey // A binary identifier that indicates what kind of data is contained in the payload. // TODO(yusef): enforce multicodec prefix @@ -42,7 +43,7 @@ var ErrInvalidSignature = errors.New("invalid signature or incorrect domain") // and must be supplied when verifying the signature. // // The 'PayloadType' field indicates what kind of data is contained and may be empty. -func MakeEnvelope(privateKey PrivKey, domain string, payloadType []byte, payload []byte) (*SignedEnvelope, error) { +func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, payload []byte) (*SignedEnvelope, error) { if domain == "" { return nil, ErrEmptyDomain } @@ -86,7 +87,7 @@ func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { return nil, err } - key, err := PublicKeyFromProto(e.PublicKey) + key, err := crypto.PublicKeyFromProto(e.PublicKey) if err != nil { return nil, err } @@ -102,7 +103,7 @@ func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { // Marshal returns a byte slice containing a serialized protobuf representation // of a SignedEnvelope. func (e *SignedEnvelope) Marshal() ([]byte, error) { - key, err := PublicKeyToProto(e.PublicKey) + key, err := crypto.PublicKeyToProto(e.PublicKey) if err != nil { return nil, err } diff --git a/crypto/envelope_test.go b/record/envelope_test.go similarity index 99% rename from crypto/envelope_test.go rename to record/envelope_test.go index 311b2b01..f2b44adc 100644 --- a/crypto/envelope_test.go +++ b/record/envelope_test.go @@ -1,4 +1,4 @@ -package crypto_test +package record import ( "bytes" From bb547efe8c3ccd48e8135ecc38166bb216e357ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 27 Dec 2019 20:26:08 +0000 Subject: [PATCH 34/69] move protobuf files; adjust imports everywhere. --- crypto/pb/Makefile | 2 +- crypto/pb/crypto.proto | 2 + record/envelope.go | 2 +- record/envelope_test.go | 22 ++-- record/pb/Makefile | 11 ++ {crypto => record}/pb/envelope.pb.go | 180 +++++++++++++++------------ {crypto => record}/pb/envelope.proto | 6 +- routing/state.go | 12 +- 8 files changed, 138 insertions(+), 99 deletions(-) create mode 100644 record/pb/Makefile rename {crypto => record}/pb/envelope.pb.go (73%) rename {crypto => record}/pb/envelope.proto (57%) diff --git a/crypto/pb/Makefile b/crypto/pb/Makefile index df34e54b..8af2dd81 100644 --- a/crypto/pb/Makefile +++ b/crypto/pb/Makefile @@ -4,7 +4,7 @@ GO = $(PB:.proto=.pb.go) all: $(GO) %.pb.go: %.proto - protoc --proto_path=$(GOPATH)/src:. --gogofaster_out=. $< + protoc --proto_path=$(PWD)/../..:. --gogofaster_out=. $< clean: rm -f *.pb.go diff --git a/crypto/pb/crypto.proto b/crypto/pb/crypto.proto index cb5cee8a..182b0d48 100644 --- a/crypto/pb/crypto.proto +++ b/crypto/pb/crypto.proto @@ -2,6 +2,8 @@ syntax = "proto2"; package crypto.pb; +option go_package = "github.com/libp2p/go-libp2p-core/crypto/pb"; + enum KeyType { RSA = 0; Ed25519 = 1; diff --git a/record/envelope.go b/record/envelope.go index a26c0019..4290c689 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -7,7 +7,7 @@ import ( pool "github.com/libp2p/go-buffer-pool" "github.com/libp2p/go-libp2p-core/crypto" - pb "github.com/libp2p/go-libp2p-core/crypto/pb" + pb "github.com/libp2p/go-libp2p-core/record/pb" "github.com/gogo/protobuf/proto" "github.com/multiformats/go-varint" diff --git a/record/envelope_test.go b/record/envelope_test.go index f2b44adc..b6e8aaf8 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -1,13 +1,15 @@ -package record +package record_test import ( "bytes" - "github.com/gogo/protobuf/proto" + "testing" - . "github.com/libp2p/go-libp2p-core/crypto" - pb "github.com/libp2p/go-libp2p-core/crypto/pb" + crypto "github.com/libp2p/go-libp2p-core/crypto" + . "github.com/libp2p/go-libp2p-core/record" + pb "github.com/libp2p/go-libp2p-core/record/pb" "github.com/libp2p/go-libp2p-core/test" - "testing" + + "github.com/gogo/protobuf/proto" ) // Make an envelope, verify & open it, marshal & unmarshal it @@ -16,7 +18,7 @@ func TestEnvelopeHappyPath(t *testing.T) { payload = []byte("happy hacking") domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") - priv, pub, err = test.RandTestKeyPair(Ed25519, 256) + priv, pub, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) @@ -51,7 +53,7 @@ func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { var ( payload = []byte("happy hacking") payloadType = []byte("/libp2p/testdata") - priv, _, err = test.RandTestKeyPair(Ed25519, 256) + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) if err != nil { @@ -67,7 +69,7 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { payload = []byte("happy hacking") domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") - priv, _, err = test.RandTestKeyPair(Ed25519, 256) + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) @@ -87,7 +89,7 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { payload = []byte("happy hacking") domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") - priv, _, err = test.RandTestKeyPair(Ed25519, 256) + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) @@ -109,7 +111,7 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { payload = []byte("happy hacking") domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") - priv, _, err = test.RandTestKeyPair(Ed25519, 256) + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) diff --git a/record/pb/Makefile b/record/pb/Makefile new file mode 100644 index 00000000..7cf8222f --- /dev/null +++ b/record/pb/Makefile @@ -0,0 +1,11 @@ +PB = $(wildcard *.proto) +GO = $(PB:.proto=.pb.go) + +all: $(GO) + +%.pb.go: %.proto + protoc --proto_path=$(PWD):$(PWD)/../.. --gogofaster_out=. $< + +clean: + rm -f *.pb.go + rm -f *.go diff --git a/crypto/pb/envelope.pb.go b/record/pb/envelope.pb.go similarity index 73% rename from crypto/pb/envelope.pb.go rename to record/pb/envelope.pb.go index d18436fb..10548a54 100644 --- a/crypto/pb/envelope.pb.go +++ b/record/pb/envelope.pb.go @@ -1,14 +1,14 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: envelope.proto -package crypto_pb +package record_pb import ( fmt "fmt" proto "github.com/gogo/protobuf/proto" + pb "github.com/libp2p/go-libp2p-core/crypto/pb" io "io" math "math" - math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -20,13 +20,13 @@ var _ = math.Inf // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type SignedEnvelope struct { - PublicKey *PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` - PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` - Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` - Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` + PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` + PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` } func (m *SignedEnvelope) Reset() { *m = SignedEnvelope{} } @@ -43,7 +43,7 @@ func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return xxx_messageInfo_SignedEnvelope.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) + n, err := m.MarshalTo(b) if err != nil { return nil, err } @@ -62,7 +62,7 @@ func (m *SignedEnvelope) XXX_DiscardUnknown() { var xxx_messageInfo_SignedEnvelope proto.InternalMessageInfo -func (m *SignedEnvelope) GetPublicKey() *PublicKey { +func (m *SignedEnvelope) GetPublicKey() *pb.PublicKey { if m != nil { return m.PublicKey } @@ -91,31 +91,32 @@ func (m *SignedEnvelope) GetSignature() []byte { } func init() { - proto.RegisterType((*SignedEnvelope)(nil), "crypto.pb.SignedEnvelope") + proto.RegisterType((*SignedEnvelope)(nil), "record.pb.SignedEnvelope") } func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } var fileDescriptor_ee266e8c558e9dc5 = []byte{ - // 189 bytes of a gzipped FileDescriptorProto + // 200 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, - 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4c, 0x2e, 0xaa, 0x2c, - 0x28, 0xc9, 0xd7, 0x2b, 0x48, 0x92, 0xe2, 0x81, 0x31, 0x41, 0x12, 0x4a, 0xf3, 0x18, 0xb9, 0xf8, - 0x82, 0x33, 0xd3, 0xf3, 0x52, 0x53, 0x5c, 0xa1, 0x3a, 0x84, 0x8c, 0xb8, 0x38, 0x0b, 0x4a, 0x93, - 0x72, 0x32, 0x93, 0xbd, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0x44, 0xf4, 0xe0, - 0xfa, 0xf5, 0x02, 0x60, 0x72, 0x41, 0x08, 0x65, 0x42, 0x0a, 0x5c, 0xdc, 0x05, 0x89, 0x95, 0x39, - 0xf9, 0x89, 0x29, 0x21, 0x95, 0x05, 0xa9, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0xc8, 0x42, - 0x42, 0x12, 0x5c, 0xec, 0x50, 0xae, 0x04, 0x33, 0x58, 0x16, 0xc6, 0x15, 0x92, 0xe1, 0xe2, 0x2c, - 0xce, 0x4c, 0xcf, 0x4b, 0x2c, 0x29, 0x2d, 0x4a, 0x95, 0x60, 0x01, 0xcb, 0x21, 0x04, 0x9c, 0x24, - 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, - 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, 0x0d, 0xec, 0x03, 0x63, 0x40, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x25, 0xd3, 0xde, 0xe5, 0xec, 0x00, 0x00, 0x00, + 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2c, 0x4a, 0x4d, 0xce, + 0x2f, 0x4a, 0xd1, 0x2b, 0x48, 0x92, 0x12, 0x4b, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x48, + 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0xe6, 0x31, 0x72, 0xf1, 0x05, 0x67, 0xa6, 0xe7, 0xa5, 0xa6, + 0xb8, 0x42, 0xf5, 0x0a, 0x19, 0x71, 0x71, 0x16, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, + 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x89, 0xe8, 0xc1, 0x34, 0x25, 0xe9, 0x05, 0xc0, 0xe4, + 0x82, 0x10, 0xca, 0x84, 0x14, 0xb8, 0xb8, 0x0b, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x42, 0x2a, + 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18, 0x35, 0x78, 0x82, 0x90, 0x85, 0x84, 0x24, 0xb8, 0xd8, 0xa1, + 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, 0x2b, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97, 0x58, + 0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x02, 0x96, 0x43, 0x08, 0x38, 0x49, 0x9c, 0x78, 0x24, 0xc7, 0x78, + 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, + 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x12, 0x1b, 0xd8, 0x07, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xfb, 0xd0, 0x77, 0x21, 0xf6, 0x00, 0x00, 0x00, } func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -123,61 +124,49 @@ func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { } func (m *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *SignedEnvelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.Signature) > 0 { - i -= len(m.Signature) - copy(dAtA[i:], m.Signature) - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) - i-- - dAtA[i] = 0x22 - } - if len(m.Payload) > 0 { - i -= len(m.Payload) - copy(dAtA[i:], m.Payload) - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Payload))) - i-- - dAtA[i] = 0x1a + if m.PublicKey != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(m.PublicKey.Size())) + n1, err := m.PublicKey.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 } if len(m.PayloadType) > 0 { - i -= len(m.PayloadType) - copy(dAtA[i:], m.PayloadType) - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) - i-- dAtA[i] = 0x12 + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) + i += copy(dAtA[i:], m.PayloadType) } - if m.PublicKey != nil { - { - size, err := m.PublicKey.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEnvelope(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa + if len(m.Payload) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Payload))) + i += copy(dAtA[i:], m.Payload) } - return len(dAtA) - i, nil + if len(m.Signature) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) + i += copy(dAtA[i:], m.Signature) + } + return i, nil } func encodeVarintEnvelope(dAtA []byte, offset int, v uint64) int { - offset -= sovEnvelope(v) - base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return base + return offset + 1 } func (m *SignedEnvelope) Size() (n int) { if m == nil { @@ -205,7 +194,14 @@ func (m *SignedEnvelope) Size() (n int) { } func sovEnvelope(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n } func sozEnvelope(x uint64) (n int) { return sovEnvelope(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -269,7 +265,7 @@ func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.PublicKey == nil { - m.PublicKey = &PublicKey{} + m.PublicKey = &pb.PublicKey{} } if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -404,7 +400,6 @@ func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { func skipEnvelope(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 - depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -436,8 +431,10 @@ func skipEnvelope(dAtA []byte) (n int, err error) { break } } + return iNdEx, nil case 1: iNdEx += 8 + return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -458,30 +455,55 @@ func skipEnvelope(dAtA []byte) (n int, err error) { return 0, ErrInvalidLengthEnvelope } iNdEx += length + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } + return iNdEx, nil case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupEnvelope + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEnvelope + } + 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 := skipEnvelope(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } } - depth-- + 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) } - if iNdEx < 0 { - return 0, ErrInvalidLengthEnvelope - } - if depth == 0 { - return iNdEx, nil - } } - return 0, io.ErrUnexpectedEOF + panic("unreachable") } var ( - ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupEnvelope = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") ) diff --git a/crypto/pb/envelope.proto b/record/pb/envelope.proto similarity index 57% rename from crypto/pb/envelope.proto rename to record/pb/envelope.proto index 1b96a3ae..a0fb2b83 100644 --- a/crypto/pb/envelope.proto +++ b/record/pb/envelope.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package crypto.pb; +package record.pb; -import "crypto.proto"; +import "crypto/pb/crypto.proto"; message SignedEnvelope { - PublicKey publicKey = 1; + crypto.pb.PublicKey publicKey = 1; bytes payloadType = 2; bytes payload = 3; bytes signature = 4; diff --git a/routing/state.go b/routing/state.go index c626685e..28d06db7 100644 --- a/routing/state.go +++ b/routing/state.go @@ -2,12 +2,14 @@ package routing import ( "errors" + "time" + "github.com/gogo/protobuf/proto" "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/record" pb "github.com/libp2p/go-libp2p-core/routing/pb" ma "github.com/multiformats/go-multiaddr" - "time" ) // The domain string used for routing state records contained in a SignedEnvelope. @@ -29,7 +31,7 @@ type SignedRoutingState struct { // Envelope contains the signature and serialized RoutingStateRecord protobuf. // Although it uses a bit - Envelope *crypto.SignedEnvelope + Envelope *record.SignedEnvelope } // MakeSignedRoutingState returns a SignedRoutingState record containing the given multiaddrs, @@ -54,7 +56,7 @@ func MakeSignedRoutingState(privKey crypto.PrivKey, addrs []ma.Multiaddr) (*Sign if err != nil { return nil, err } - envelope, err := crypto.MakeEnvelope(privKey, StateEnvelopeDomain, StateEnvelopePayloadType, payload) + envelope, err := record.MakeEnvelope(privKey, StateEnvelopeDomain, StateEnvelopePayloadType, payload) if err != nil { return nil, err } @@ -71,7 +73,7 @@ func MakeSignedRoutingState(privKey crypto.PrivKey, addrs []ma.Multiaddr) (*Sign // Fails if the signature is invalid, if the envelope has an unexpected payload type, // if deserialization of the envelope or its inner payload fails. func UnmarshalSignedRoutingState(envelopeBytes []byte) (*SignedRoutingState, error) { - envelope, err := crypto.OpenEnvelope(envelopeBytes, StateEnvelopeDomain) + envelope, err := record.ConsumeEnvelope(envelopeBytes, StateEnvelopeDomain) if err != nil { return nil, err } @@ -82,7 +84,7 @@ func UnmarshalSignedRoutingState(envelopeBytes []byte) (*SignedRoutingState, err // a RoutingStateRecord protobuf and returns a SignedRoutingState record. // Fails if the signature is invalid, if the envelope has an unexpected payload type, // or if deserialization of the envelope payload fails. -func SignedRoutingStateFromEnvelope(envelope *crypto.SignedEnvelope) (*SignedRoutingState, error) { +func SignedRoutingStateFromEnvelope(envelope *record.SignedEnvelope) (*SignedRoutingState, error) { var msg pb.RoutingStateRecord err := proto.Unmarshal(envelope.Payload, &msg) if err != nil { From ae465aa5b8aecb0d74f4a2f167b12ab2038c5be7 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 13 Dec 2019 09:27:27 -0500 Subject: [PATCH 35/69] define CertifiedAddrBook to avoid breaking API change --- peerstore/peerstore.go | 68 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index eb01b928..8c8dd5d8 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -97,10 +97,6 @@ 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 routing.SignedRoutingState record. - // Certified addresses will be returned from both Addrs and CertifiedAddrs. - AddCertifiedAddrs(s *routing.SignedRoutingState, ttl time.Duration) error - // SetAddr calls mgr.SetAddrs(p, addr, ttl) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) @@ -112,15 +108,9 @@ type AddrBook interface { // the given oldTTL to have the given newTTL. UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) - // Addrs returns all known (and valid) addresses for a given peer, including - // both certified and uncertified addresses. + // 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 and added to the peerstore using - // AddCertifiedAddrs. Note that certified addrs are also returned. - 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. @@ -131,13 +121,67 @@ type AddrBook interface { // PeersWithAddrs returns all of the peer IDs stored in the AddrBook PeersWithAddrs() peer.IDSlice +} + +// CertifiedAddrBook manages "self-certified" addresses for remote peers. +// Self-certified addresses are contained in routing.SignedRoutingState +// records that are signed by the peer to whom they belong. +// +// This interface is most useful when combined with AddrBook. +// To test whether a given AddrBook / Peerstore implementation supports +// certified addresses, callers should type-assert on the CertifiedAddrBook +// interface: +// +// if cab, ok := aPeerstore.(CertifiedAddrBook); ok { +// cab.AddCertifiedAddrs(aRoutingStateRecord, aTTL) +// } +// +type CertifiedAddrBook interface { + // AddCertifiedAddrs adds addresses from a routing.SignedRoutingState record, + // which will expire after the given TTL. + // + // SignedRoutingState records added via this method will be stored without + // alteration as long as the address TTLs remain valid. Records can be retrieved + // by calling SignedRoutingState(peerID). + // + // If the SignedRoutingState belongs to a peer that already has certified + // addresses in the CertifiedAddrBook, the new addresses will replace the + // older ones, iff the new record has a higher sequence number than the + // existing record. Attempting to add a SignedRoutingState record with a + // sequence number that's <= an existing record for the same peer will not + // result in an error, but the record will be ignored. + // + // If the CertifiedAddrBook is also an AddrBook (which is most likely the case), + // adding certified addresses for a peer will *replace* any + // existing non-certified addresses for that peer, and only the certified + // addresses will be returned from AddrBook.Addrs. + // + // Likewise, once certified addresses have been added for a given peer, + // any non-certified addresses added via AddrBook.AddAddrs or + // AddrBook.SetAddrs will be ignored. AddrBook.SetAddrs may still be used + // to update the TTL of certified addresses if they have previously been + // added via AddCertifiedAddrs. + AddCertifiedAddrs(s *routing.SignedRoutingState, ttl time.Duration) error // SignedRoutingState returns a SignedRoutingState record for the - // given peer id, if one exists in the peerstore. + // given peer id, if one exists. // Returns nil if no routing state exists for the peer. SignedRoutingState(p peer.ID) *routing.SignedRoutingState } +// GetCertifiedAddrBook is a helper to "upcast" an AddrBook to a +// CertifiedAddrBook by using type assertion. If the given AddrBook +// is also a CertifiedAddrBook, it will be returned, and the ok return +// value will be true. Returns (nil, false) if the AddrBook is not a +// CertifiedAddrBook. +// +// Note that since Peerstore embeds the AddrBook interface, you can also +// call GetCertifiedAddrBook(myPeerstore). +func GetCertifiedAddrBook(ab AddrBook) (cab CertifiedAddrBook, ok bool) { + cab, ok = ab.(CertifiedAddrBook) + return cab, ok +} + // KeyBook tracks the keys of Peers. type KeyBook interface { // PubKey stores the public key of a peer. From 2e8cabcc8722572e547292e6e354e49c9b01d513 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 7 Jan 2020 11:24:48 -0500 Subject: [PATCH 36/69] rename RoutingStateRecord -> PeerRecord also removes embedded reference to Envelope from the record, as that was confusing. as a result, the CertifiedAddrBook now accepts/returns record.SignedEnvelope instead of a specialized type. --- event/addrs.go | 12 +- {routing => peer}/pb/Makefile | 0 peer/pb/peer_record.pb.go | 593 +++++++++++++++++ .../pb/peer_record.proto | 4 +- peer/record.go | 203 ++++++ peer/record_test.go | 47 ++ peerstore/peerstore.go | 31 +- routing/pb/routing_state.pb.go | 610 ------------------ routing/state.go | 159 ----- routing/state_test.go | 38 -- 10 files changed, 867 insertions(+), 830 deletions(-) rename {routing => peer}/pb/Makefile (100%) create mode 100644 peer/pb/peer_record.pb.go rename routing/pb/routing_state.proto => peer/pb/peer_record.proto (77%) create mode 100644 peer/record.go create mode 100644 peer/record_test.go delete mode 100644 routing/pb/routing_state.pb.go delete mode 100644 routing/state.go delete mode 100644 routing/state_test.go diff --git a/event/addrs.go b/event/addrs.go index d39024eb..35c422d2 100644 --- a/event/addrs.go +++ b/event/addrs.go @@ -1,7 +1,7 @@ package event import ( - "github.com/libp2p/go-libp2p-core/routing" + "github.com/libp2p/go-libp2p-core/record" ma "github.com/multiformats/go-multiaddr" ) @@ -17,9 +17,9 @@ type EvtLocalAddressesUpdated struct { Removed []ma.Multiaddr } -// EvtLocalPeerRoutingStateUpdated should be emitted when a new SignedRoutingState -// record for the local peer has been produced. This will happen whenever the set -// of listen addresses changes. -type EvtLocalPeerRoutingStateUpdated struct { - State *routing.SignedRoutingState +// EvtLocalPeerRoutingStateUpdated should be emitted when a new signed PeerRecord +// for the local peer has been produced. This will happen whenever the set of listen +// addresses changes. +type EvtLocalPeerRecordUpdated struct { + SignedRecord *record.SignedEnvelope } diff --git a/routing/pb/Makefile b/peer/pb/Makefile similarity index 100% rename from routing/pb/Makefile rename to peer/pb/Makefile diff --git a/peer/pb/peer_record.pb.go b/peer/pb/peer_record.pb.go new file mode 100644 index 00000000..fddd4430 --- /dev/null +++ b/peer/pb/peer_record.pb.go @@ -0,0 +1,593 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: peer_record.proto + +package peer_pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type PeerRecord struct { + PeerId []byte `protobuf:"bytes,1,opt,name=peerId,proto3" json:"peerId,omitempty"` + Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` + Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (m *PeerRecord) Reset() { *m = PeerRecord{} } +func (m *PeerRecord) String() string { return proto.CompactTextString(m) } +func (*PeerRecord) ProtoMessage() {} +func (*PeerRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_dc0d8059ab0ad14d, []int{0} +} +func (m *PeerRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PeerRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PeerRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PeerRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeerRecord.Merge(m, src) +} +func (m *PeerRecord) XXX_Size() int { + return m.Size() +} +func (m *PeerRecord) XXX_DiscardUnknown() { + xxx_messageInfo_PeerRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_PeerRecord proto.InternalMessageInfo + +func (m *PeerRecord) GetPeerId() []byte { + if m != nil { + return m.PeerId + } + return nil +} + +func (m *PeerRecord) GetSeq() uint64 { + if m != nil { + return m.Seq + } + return 0 +} + +func (m *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo { + if m != nil { + return m.Addresses + } + return nil +} + +type PeerRecord_AddressInfo struct { + Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` +} + +func (m *PeerRecord_AddressInfo) Reset() { *m = PeerRecord_AddressInfo{} } +func (m *PeerRecord_AddressInfo) String() string { return proto.CompactTextString(m) } +func (*PeerRecord_AddressInfo) ProtoMessage() {} +func (*PeerRecord_AddressInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_dc0d8059ab0ad14d, []int{0, 0} +} +func (m *PeerRecord_AddressInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PeerRecord_AddressInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PeerRecord_AddressInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PeerRecord_AddressInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeerRecord_AddressInfo.Merge(m, src) +} +func (m *PeerRecord_AddressInfo) XXX_Size() int { + return m.Size() +} +func (m *PeerRecord_AddressInfo) XXX_DiscardUnknown() { + xxx_messageInfo_PeerRecord_AddressInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_PeerRecord_AddressInfo proto.InternalMessageInfo + +func (m *PeerRecord_AddressInfo) GetMultiaddr() []byte { + if m != nil { + return m.Multiaddr + } + return nil +} + +func init() { + proto.RegisterType((*PeerRecord)(nil), "peer.pb.PeerRecord") + proto.RegisterType((*PeerRecord_AddressInfo)(nil), "peer.pb.PeerRecord.AddressInfo") +} + +func init() { proto.RegisterFile("peer_record.proto", fileDescriptor_dc0d8059ab0ad14d) } + +var fileDescriptor_dc0d8059ab0ad14d = []byte{ + // 186 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x48, 0x4d, 0x2d, + 0x8a, 0x2f, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, + 0x09, 0xe9, 0x15, 0x24, 0x29, 0x2d, 0x62, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, + 0x0a, 0x89, 0x71, 0xb1, 0x81, 0x64, 0x3c, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xa0, + 0x3c, 0x21, 0x01, 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x10, + 0x53, 0xc8, 0x96, 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, 0x58, 0x82, 0x59, + 0x81, 0x59, 0x83, 0xdb, 0x48, 0x5e, 0x0f, 0x6a, 0xaa, 0x1e, 0xc2, 0x44, 0x3d, 0x47, 0x88, 0x22, + 0xcf, 0xbc, 0xb4, 0xfc, 0x20, 0x84, 0x0e, 0x29, 0x6d, 0x2e, 0x6e, 0x24, 0x19, 0x21, 0x19, 0x2e, + 0xce, 0xdc, 0xd2, 0x9c, 0x92, 0x4c, 0x90, 0x02, 0xa8, 0xd5, 0x08, 0x01, 0x27, 0x89, 0x13, 0x8f, + 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, + 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0x7b, 0xc7, 0x18, 0x10, 0x00, 0x00, + 0xff, 0xff, 0x85, 0x84, 0x12, 0xd0, 0xe3, 0x00, 0x00, 0x00, +} + +func (m *PeerRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PeerRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PeerRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Addresses) > 0 { + for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Addresses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPeerRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.Seq != 0 { + i = encodeVarintPeerRecord(dAtA, i, uint64(m.Seq)) + i-- + dAtA[i] = 0x10 + } + if len(m.PeerId) > 0 { + i -= len(m.PeerId) + copy(dAtA[i:], m.PeerId) + i = encodeVarintPeerRecord(dAtA, i, uint64(len(m.PeerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PeerRecord_AddressInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PeerRecord_AddressInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PeerRecord_AddressInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Multiaddr) > 0 { + i -= len(m.Multiaddr) + copy(dAtA[i:], m.Multiaddr) + i = encodeVarintPeerRecord(dAtA, i, uint64(len(m.Multiaddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintPeerRecord(dAtA []byte, offset int, v uint64) int { + offset -= sovPeerRecord(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PeerRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PeerId) + if l > 0 { + n += 1 + l + sovPeerRecord(uint64(l)) + } + if m.Seq != 0 { + n += 1 + sovPeerRecord(uint64(m.Seq)) + } + if len(m.Addresses) > 0 { + for _, e := range m.Addresses { + l = e.Size() + n += 1 + l + sovPeerRecord(uint64(l)) + } + } + return n +} + +func (m *PeerRecord_AddressInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Multiaddr) + if l > 0 { + n += 1 + l + sovPeerRecord(uint64(l)) + } + return n +} + +func sovPeerRecord(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPeerRecord(x uint64) (n int) { + return sovPeerRecord(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PeerRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + 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: PeerRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PeerRecord: 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 ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPeerRecord + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPeerRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PeerId = append(m.PeerId[:0], dAtA[iNdEx:postIndex]...) + if m.PeerId == nil { + m.PeerId = []byte{} + } + iNdEx = postIndex + 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 ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Seq |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPeerRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPeerRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addresses = append(m.Addresses, &PeerRecord_AddressInfo{}) + if err := m.Addresses[len(m.Addresses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPeerRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PeerRecord_AddressInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + 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 ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPeerRecord + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPeerRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Multiaddr = append(m.Multiaddr[:0], dAtA[iNdEx:postIndex]...) + if m.Multiaddr == nil { + m.Multiaddr = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPeerRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPeerRecord(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPeerRecord + } + 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, ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPeerRecord + } + 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, ErrInvalidLengthPeerRecord + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPeerRecord + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPeerRecord + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPeerRecord = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPeerRecord = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPeerRecord = fmt.Errorf("proto: unexpected end of group") +) diff --git a/routing/pb/routing_state.proto b/peer/pb/peer_record.proto similarity index 77% rename from routing/pb/routing_state.proto rename to peer/pb/peer_record.proto index 8c761ac7..6048d4b7 100644 --- a/routing/pb/routing_state.proto +++ b/peer/pb/peer_record.proto @@ -1,7 +1,7 @@ syntax = "proto3"; -package routing.pb; +package peer.pb; -message RoutingStateRecord { +message PeerRecord { message AddressInfo { bytes multiaddr = 1; } diff --git a/peer/record.go b/peer/record.go new file mode 100644 index 00000000..a5c5d256 --- /dev/null +++ b/peer/record.go @@ -0,0 +1,203 @@ +package peer + +import ( + "errors" + "time" + + "github.com/gogo/protobuf/proto" + "github.com/libp2p/go-libp2p-core/crypto" + pb "github.com/libp2p/go-libp2p-core/peer/pb" + "github.com/libp2p/go-libp2p-core/record" + ma "github.com/multiformats/go-multiaddr" +) + +// The domain string used for peer records contained in a SignedEnvelope. +const PeerRecordEnvelopeDomain = "libp2p-peer-record" + +// The type hint used to identify peer records in a SignedEnvelope. +// TODO: register multicodec +var PeerRecordEnvelopePayloadType = []byte("/libp2p/peer-record") + +// ErrPeerIdMismatch is returned when attempting to sign a PeerRecord using a key that +// does not match the PeerID contained in the record. +var ErrPeerIdMismatch = errors.New("unable to sign peer record: key does not match record.PeerID") + +// PeerRecord contains information that is broadly useful to share with other peers, +// either through a direct exchange (as in the libp2p identify protocol), or through +// a Peer Routing provider, such as a DHT. +// +// Currently, a PeerRecord contains the public listen addresses for a peer, but this +// is expected to expand to include other information in the future. +// +// PeerRecords are intended to be signed by the peer they describe, and there are no +// public methods for marshalling and unmarshalling unsigned PeerRecords. +// +// To share a PeerRecord, first call Sign to wrap the record in a SignedEnvelope +// and sign it with the local peer's private key: +// +// rec := NewPeerRecord(myPeerId, myAddrs) +// envelope, err := rec.Sign(myPrivateKey) +// +// The resulting record.SignedEnvelope can be marshalled to a []byte and shared +// publicly. As a convenience, the MarshalSigned method will produce the +// SignedEnvelope and marshal it to a []byte in one go: +// +// rec := NewPeerRecord(myPeerId, myAddrs) +// recordBytes, err := rec.MarshalSigned(myPrivateKey) +// +// To validate and unmarshal a signed PeerRecord from a remote peer, use the +// UnmarshalSignedPeerRecord function: +// +// rec, envelope, err := UnmarshalSignedPeerRecord(recordBytes) +// +// Note that UnmarshalSignedPeerRecord returns the record as well as the +// SignedEnvelope that wraps it, so that you can inspect any metadata +// from the envelope if you need it (for example, the remote peer's public key). +// If you already have an unmarshalled SignedEnvelope, you can call +// PeerRecordFromSignedEnvelope instead: +// +// rec, err := PeerRecordFromSignedEnvelope(envelope) +type PeerRecord struct { + // PeerID is the ID of the peer this record pertains to. + PeerID ID + + // Seq is an increment-only sequence counter used to order peer records in time. + Seq uint64 + + // Addrs contains the public addresses of the peer this record pertains to. + Addrs []ma.Multiaddr +} + +// NewPeerRecord creates a PeerRecord with the given ID and addresses. +// It generates a timestamp-based sequence number. +func NewPeerRecord(id ID, addrs []ma.Multiaddr) *PeerRecord { + return &PeerRecord{ + PeerID: id, + Addrs: addrs, + Seq: statelessSeqNo(), + } +} + +// PeerRecordFromAddrInfo creates a PeerRecord from an AddrInfo struct. +// It generates a timestamp-based sequence number. +func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord { + return NewPeerRecord(info.ID, info.Addrs) +} + +// UnmarshalSignedPeerRecord accepts a []byte containing a SignedEnvelope protobuf message. +// It will try to validate the envelope signature and unmarshal the payload as a PeerRecord. +// Returns the PeerRecord and the SignedEnvelope if successful. +func UnmarshalSignedPeerRecord(envelopeBytes []byte) (*PeerRecord, *record.SignedEnvelope, error) { + envelope, err := record.ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain) + if err != nil { + return nil, nil, err + } + rec, err := PeerRecordFromSignedEnvelope(envelope) + if err != nil { + return nil, nil, err + } + return rec, envelope, nil +} + +// PeerRecordFromSignedEnvelope accepts a SignedEnvelope struct and returns a PeerRecord struct. +// Fails if the signature is invalid, or if the payload cannot be unmarshaled as a PeerRecord. +func PeerRecordFromSignedEnvelope(envelope *record.SignedEnvelope) (*PeerRecord, error) { + var msg pb.PeerRecord + err := proto.Unmarshal(envelope.Payload, &msg) + if err != nil { + return nil, err + } + id, err := IDFromBytes(msg.PeerId) + if err != nil { + return nil, err + } + if !id.MatchesPublicKey(envelope.PublicKey) { + return nil, errors.New("peer id in peer record does not match signing key") + } + return &PeerRecord{ + PeerID: id, + Seq: msg.Seq, + Addrs: addrsFromProtobuf(msg.Addresses), + }, nil +} + +// Sign wraps the PeerRecord in a routing.SignedEnvelope, signed with the given +// private key. The private key must match the PeerID field of the PeerRecord. +func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.SignedEnvelope, error) { + p, err := IDFromPrivateKey(privKey) + if err != nil { + return nil, err + } + if p != r.PeerID { + return nil, ErrPeerIdMismatch + } + idBytes, err := p.MarshalBinary() + if err != nil { + return nil, err + } + msg := pb.PeerRecord{ + PeerId: idBytes, + Seq: r.Seq, + Addresses: addrsToProtobuf(r.Addrs), + } + payload, err := proto.Marshal(&msg) + if err != nil { + return nil, err + } + return record.MakeEnvelope(privKey, PeerRecordEnvelopeDomain, PeerRecordEnvelopePayloadType, payload) +} + +func (r *PeerRecord) MarshalSigned(privKey crypto.PrivKey) ([]byte, error) { + env, err := r.Sign(privKey) + if err != nil { + return nil, err + } + return env.Marshal() +} + +// Equal returns true if the other PeerRecord is identical to this one. +func (r *PeerRecord) Equal(other *PeerRecord) bool { + if other == nil { + return r == nil + } + if r.Seq != other.Seq { + return false + } + if r.PeerID != other.PeerID { + return false + } + if len(r.Addrs) != len(other.Addrs) { + return false + } + for i, _ := range r.Addrs { + if !r.Addrs[i].Equal(other.Addrs[i]) { + return false + } + } + return true +} + +// statelessSeqNo is a helper to generate a timestamp-based sequence number. +func statelessSeqNo() uint64 { + return uint64(time.Now().UnixNano()) +} + +func addrsFromProtobuf(addrs []*pb.PeerRecord_AddressInfo) []ma.Multiaddr { + var out []ma.Multiaddr + for _, addr := range addrs { + a, err := ma.NewMultiaddrBytes(addr.Multiaddr) + if err != nil { + continue + } + out = append(out, a) + } + return out +} + +func addrsToProtobuf(addrs []ma.Multiaddr) []*pb.PeerRecord_AddressInfo { + var out []*pb.PeerRecord_AddressInfo + for _, addr := range addrs { + out = append(out, &pb.PeerRecord_AddressInfo{Multiaddr: addr.Bytes()}) + } + return out +} diff --git a/peer/record_test.go b/peer/record_test.go new file mode 100644 index 00000000..d021b923 --- /dev/null +++ b/peer/record_test.go @@ -0,0 +1,47 @@ +package peer_test + +import ( + "github.com/libp2p/go-libp2p-core/crypto" + . "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/record" + "github.com/libp2p/go-libp2p-core/test" + "testing" +) + +func TestSignedPeerRecordFromEnvelope(t *testing.T) { + priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) + test.AssertNilError(t, err) + + addrs := test.GenerateTestAddrs(10) + id, err := IDFromPrivateKey(priv) + test.AssertNilError(t, err) + + rec := NewPeerRecord(id, addrs) + envelope, err := rec.Sign(priv) + test.AssertNilError(t, err) + + t.Run("is unaltered after round-trip serde", func(t *testing.T) { + envBytes, err := envelope.Marshal() + test.AssertNilError(t, err) + + rec2, env2, err := UnmarshalSignedPeerRecord(envBytes) + test.AssertNilError(t, err) + if !rec.Equal(rec2) { + t.Error("expected peer record to be unaltered after round-trip serde") + } + if !envelope.Equal(env2) { + t.Error("expected signed envelope to be unchanged after round-trip serde") + } + }) + + t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func(t *testing.T) { + payload := []byte("ignored") + test.AssertNilError(t, err) + + env, err := record.MakeEnvelope(priv, "wrong-domain", PeerRecordEnvelopePayloadType, payload) + test.AssertNilError(t, err) + envBytes, err := env.Marshal() + _, _, err = UnmarshalSignedPeerRecord(envBytes) + test.ExpectError(t, err, "unwrapping PeerRecord from envelope should fail if envelope was created with wrong domain string") + }) +} diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 8c8dd5d8..0e95e15d 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -5,7 +5,7 @@ package peerstore import ( "context" "errors" - "github.com/libp2p/go-libp2p-core/routing" + "github.com/libp2p/go-libp2p-core/record" "io" "math" "time" @@ -124,8 +124,9 @@ type AddrBook interface { } // CertifiedAddrBook manages "self-certified" addresses for remote peers. -// Self-certified addresses are contained in routing.SignedRoutingState -// records that are signed by the peer to whom they belong. +// Self-certified addresses are contained in peer.PeerRecords +// that are wraped in a record.SignedEnvelope and signed by the peer +// to whom they belong. // // This interface is most useful when combined with AddrBook. // To test whether a given AddrBook / Peerstore implementation supports @@ -133,21 +134,21 @@ type AddrBook interface { // interface: // // if cab, ok := aPeerstore.(CertifiedAddrBook); ok { -// cab.AddCertifiedAddrs(aRoutingStateRecord, aTTL) +// cab.AddCertifiedAddrs(signedPeerRecord, aTTL) // } // type CertifiedAddrBook interface { - // AddCertifiedAddrs adds addresses from a routing.SignedRoutingState record, - // which will expire after the given TTL. + // AddCertifiedAddrs adds addresses from a signed peer.PeerRecord (contained in + // a routing.SignedEnvelope), which will expire after the given TTL. // - // SignedRoutingState records added via this method will be stored without - // alteration as long as the address TTLs remain valid. Records can be retrieved - // by calling SignedRoutingState(peerID). + // Signed records added via this method will be stored without + // alteration as long as the address TTLs remain valid. The SignedEnvelopes + // containing the PeerRecords can be retrieved by calling SignedPeerRecord(peerID). // - // If the SignedRoutingState belongs to a peer that already has certified + // If the signed PeerRecord belongs to a peer that already has certified // addresses in the CertifiedAddrBook, the new addresses will replace the // older ones, iff the new record has a higher sequence number than the - // existing record. Attempting to add a SignedRoutingState record with a + // existing record. Attempting to add a peer record with a // sequence number that's <= an existing record for the same peer will not // result in an error, but the record will be ignored. // @@ -161,12 +162,12 @@ type CertifiedAddrBook interface { // AddrBook.SetAddrs will be ignored. AddrBook.SetAddrs may still be used // to update the TTL of certified addresses if they have previously been // added via AddCertifiedAddrs. - AddCertifiedAddrs(s *routing.SignedRoutingState, ttl time.Duration) error + AddCertifiedAddrs(s *record.SignedEnvelope, ttl time.Duration) error - // SignedRoutingState returns a SignedRoutingState record for the + // SignedPeerRecord returns a SignedEnvelope containing a PeerRecord for the // given peer id, if one exists. - // Returns nil if no routing state exists for the peer. - SignedRoutingState(p peer.ID) *routing.SignedRoutingState + // Returns nil if no signed PeerRecord exists for the peer. + SignedPeerRecord(p peer.ID) *record.SignedEnvelope } // GetCertifiedAddrBook is a helper to "upcast" an AddrBook to a diff --git a/routing/pb/routing_state.pb.go b/routing/pb/routing_state.pb.go deleted file mode 100644 index 28d216ca..00000000 --- a/routing/pb/routing_state.pb.go +++ /dev/null @@ -1,610 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: routing_state.proto - -package routing_pb - -import ( - fmt "fmt" - 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,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` - Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` - Addresses []*RoutingStateRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" 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,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` -} - -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{ - // 200 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, 0x6d, 0x63, 0xe4, 0x12, 0x0a, 0x82, 0x70, 0x83, 0x41, - 0x4a, 0x82, 0x52, 0x93, 0xf3, 0x8b, 0x52, 0x84, 0xc4, 0xb9, 0xd8, 0x0b, 0x52, 0x53, 0x8b, 0xe2, - 0x33, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xd8, 0x40, 0x5c, 0xcf, 0x14, 0x21, 0x01, - 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x10, 0x53, 0xc8, 0x83, - 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, - 0xdb, 0x48, 0x4b, 0x0f, 0x61, 0x83, 0x1e, 0xa6, 0xe9, 0x7a, 0x8e, 0x10, 0xf5, 0x9e, 0x79, 0x69, - 0xf9, 0x41, 0x08, 0xcd, 0x52, 0xda, 0x5c, 0xdc, 0x48, 0x32, 0x42, 0x32, 0x5c, 0x9c, 0xb9, 0xa5, - 0x39, 0x25, 0x99, 0x20, 0x05, 0x50, 0x57, 0x20, 0x04, 0x9c, 0x24, 0x4e, 0x3c, 0x92, 0x63, 0xbc, - 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, - 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, 0x0d, 0xec, 0x4b, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xdc, 0xd5, 0x32, 0xa1, 0xfc, 0x00, 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 len(m.PeerId) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintRoutingState(dAtA, i, uint64(len(m.PeerId))) - i += copy(dAtA[i:], m.PeerId) - } - if m.Seq != 0 { - 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 len(m.Multiaddr) > 0 { - 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 - l = len(m.PeerId) - if l > 0 { - n += 1 + l + sovRoutingState(uint64(l)) - } - if m.Seq != 0 { - 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 - l = len(m.Multiaddr) - if l > 0 { - 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 { - 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 - 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 - } - } - 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 iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *RoutingStateRecord_AddressInfo) Unmarshal(dAtA []byte) error { - 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 - 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 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/state.go b/routing/state.go deleted file mode 100644 index 28d06db7..00000000 --- a/routing/state.go +++ /dev/null @@ -1,159 +0,0 @@ -package routing - -import ( - "errors" - "time" - - "github.com/gogo/protobuf/proto" - "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/record" - pb "github.com/libp2p/go-libp2p-core/routing/pb" - ma "github.com/multiformats/go-multiaddr" -) - -// The domain string used for routing state records contained in a SignedEnvelope. -const StateEnvelopeDomain = "libp2p-routing-state" - -// The type hint used to identify routing state records in a SignedEnvelope. -// TODO: register multicodec -var StateEnvelopePayloadType = []byte("/libp2p/routing-state-record") - -type SignedRoutingState 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 - - // Addrs contains the public addresses of the peer this record pertains to. - Addrs []ma.Multiaddr - - // Envelope contains the signature and serialized RoutingStateRecord protobuf. - // Although it uses a bit - Envelope *record.SignedEnvelope -} - -// MakeSignedRoutingState returns a SignedRoutingState record containing the given multiaddrs, -// signed with the given private key. -// It generates a timestamp-based sequence number. -func MakeSignedRoutingState(privKey crypto.PrivKey, addrs []ma.Multiaddr) (*SignedRoutingState, error) { - p, err := peer.IDFromPrivateKey(privKey) - if err != nil { - return nil, err - } - idBytes, err := p.MarshalBinary() - if err != nil { - return nil, err - } - seq := statelessSeqNo() - msg := pb.RoutingStateRecord{ - PeerId: idBytes, - Seq: seq, - Addresses: addrsToProtobuf(addrs), - } - payload, err := proto.Marshal(&msg) - if err != nil { - return nil, err - } - envelope, err := record.MakeEnvelope(privKey, StateEnvelopeDomain, StateEnvelopePayloadType, payload) - if err != nil { - return nil, err - } - return &SignedRoutingState{ - PeerID: p, - Seq: seq, - Addrs: addrs, - Envelope: envelope, - }, nil -} - -// UnmarshalSignedRoutingState accepts a serialized SignedEnvelope message containing -// a RoutingStateRecord protobuf and returns a SignedRoutingState record. -// Fails if the signature is invalid, if the envelope has an unexpected payload type, -// if deserialization of the envelope or its inner payload fails. -func UnmarshalSignedRoutingState(envelopeBytes []byte) (*SignedRoutingState, error) { - envelope, err := record.ConsumeEnvelope(envelopeBytes, StateEnvelopeDomain) - if err != nil { - return nil, err - } - return SignedRoutingStateFromEnvelope(envelope) -} - -// SignedRoutingStateFromEnvelope accepts a SignedEnvelope struct containing -// a RoutingStateRecord protobuf and returns a SignedRoutingState record. -// Fails if the signature is invalid, if the envelope has an unexpected payload type, -// or if deserialization of the envelope payload fails. -func SignedRoutingStateFromEnvelope(envelope *record.SignedEnvelope) (*SignedRoutingState, error) { - var msg pb.RoutingStateRecord - err := proto.Unmarshal(envelope.Payload, &msg) - if err != nil { - return nil, err - } - id, err := peer.IDFromBytes(msg.PeerId) - if err != nil { - return nil, err - } - if !id.MatchesPublicKey(envelope.PublicKey) { - return nil, errors.New("peer id in routing state record does not match signing key") - } - return &SignedRoutingState{ - PeerID: id, - Seq: msg.Seq, - Addrs: addrsFromProtobuf(msg.Addresses), - Envelope: envelope, - }, nil -} - -// Marshal returns a byte slice containing the SignedRoutingState as a serialized SignedEnvelope -// protobuf message. -func (s *SignedRoutingState) Marshal() ([]byte, error) { - return s.Envelope.Marshal() -} - -// Equal returns true if the other SignedRoutingState is identical to this one. -func (s *SignedRoutingState) Equal(other *SignedRoutingState) bool { - if other == nil { - return false - } - if s.Seq != other.Seq { - return false - } - if s.PeerID != other.PeerID { - return false - } - if len(s.Addrs) != len(other.Addrs) { - return false - } - for i, _ := range s.Addrs { - if !s.Addrs[i].Equal(other.Addrs[i]) { - return false - } - } - return s.Envelope.Equal(other.Envelope) -} - -// statelessSeqNo is a helper to generate a timestamp-based sequence number. -func statelessSeqNo() uint64 { - return uint64(time.Now().UnixNano()) -} - -func addrsFromProtobuf(addrs []*pb.RoutingStateRecord_AddressInfo) []ma.Multiaddr { - var out []ma.Multiaddr - for _, addr := range addrs { - a, err := ma.NewMultiaddrBytes(addr.Multiaddr) - if err != nil { - continue - } - out = append(out, a) - } - return out -} - -func addrsToProtobuf(addrs []ma.Multiaddr) []*pb.RoutingStateRecord_AddressInfo { - var out []*pb.RoutingStateRecord_AddressInfo - for _, addr := range addrs { - out = append(out, &pb.RoutingStateRecord_AddressInfo{Multiaddr: addr.Bytes()}) - } - return out -} diff --git a/routing/state_test.go b/routing/state_test.go deleted file mode 100644 index bc218a8f..00000000 --- a/routing/state_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package routing - -import ( - "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/test" - "testing" -) - -func TestSignedRoutingStateFromEnvelope(t *testing.T) { - priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) - test.AssertNilError(t, err) - - addrs := test.GenerateTestAddrs(10) - state, err := MakeSignedRoutingState(priv, addrs) - test.AssertNilError(t, err) - - t.Run("is unaltered after round-trip serde", func(t *testing.T) { - envBytes, err := state.Marshal() - test.AssertNilError(t, err) - - state2, err := UnmarshalSignedRoutingState(envBytes) - test.AssertNilError(t, err) - if !state.Equal(state2) { - t.Error("expected routing state to be unaltered after round-trip serde") - } - }) - - t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func(t *testing.T) { - stateBytes, err := state.Marshal() - test.AssertNilError(t, err) - - env, err := crypto.MakeEnvelope(priv, "wrong-domain", StateEnvelopePayloadType, stateBytes) - test.AssertNilError(t, err) - envBytes, err := env.Marshal() - _, err = UnmarshalSignedRoutingState(envBytes) - test.ExpectError(t, err, "unwrapping RoutingState from envelope should fail if envelope was created with wrong domain string") - }) -} From 59348dea5aec0c18821e91a36e1a15e9d2b8c033 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 7 Jan 2020 13:01:24 -0500 Subject: [PATCH 37/69] test that PeerRecords can't be signed by wrong key --- peer/record_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/peer/record_test.go b/peer/record_test.go index d021b923..f4d926cd 100644 --- a/peer/record_test.go +++ b/peer/record_test.go @@ -34,6 +34,15 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) { } }) + t.Run("signing fails if signing key does not match peer id in record", func(t *testing.T) { + id = "some-other-peer-id" + rec := NewPeerRecord(id, addrs) + _, err := rec.Sign(priv) + if err != ErrPeerIdMismatch { + t.Error("expected signing with mismatched private key to fail") + } + }) + t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func(t *testing.T) { payload := []byte("ignored") test.AssertNilError(t, err) From 5f6b601ac96784f73c03b7ffbab1a5cb84fed6e4 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 7 Jan 2020 11:42:27 -0500 Subject: [PATCH 38/69] hoist Seq from PeerRecord to SignedEnvelope --- peer/record.go | 15 ---- record/envelope.go | 22 ++++- record/pb/envelope.pb.go | 188 +++++++++++++++++++++------------------ record/pb/envelope.proto | 3 +- 4 files changed, 123 insertions(+), 105 deletions(-) diff --git a/peer/record.go b/peer/record.go index a5c5d256..ccd1b5b4 100644 --- a/peer/record.go +++ b/peer/record.go @@ -2,7 +2,6 @@ package peer import ( "errors" - "time" "github.com/gogo/protobuf/proto" "github.com/libp2p/go-libp2p-core/crypto" @@ -61,9 +60,6 @@ type PeerRecord struct { // PeerID is the ID of the peer this record pertains to. PeerID ID - // Seq is an increment-only sequence counter used to order peer records in time. - Seq uint64 - // Addrs contains the public addresses of the peer this record pertains to. Addrs []ma.Multiaddr } @@ -74,7 +70,6 @@ func NewPeerRecord(id ID, addrs []ma.Multiaddr) *PeerRecord { return &PeerRecord{ PeerID: id, Addrs: addrs, - Seq: statelessSeqNo(), } } @@ -116,7 +111,6 @@ func PeerRecordFromSignedEnvelope(envelope *record.SignedEnvelope) (*PeerRecord, } return &PeerRecord{ PeerID: id, - Seq: msg.Seq, Addrs: addrsFromProtobuf(msg.Addresses), }, nil } @@ -137,7 +131,6 @@ func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.SignedEnvelope, error } msg := pb.PeerRecord{ PeerId: idBytes, - Seq: r.Seq, Addresses: addrsToProtobuf(r.Addrs), } payload, err := proto.Marshal(&msg) @@ -160,9 +153,6 @@ func (r *PeerRecord) Equal(other *PeerRecord) bool { if other == nil { return r == nil } - if r.Seq != other.Seq { - return false - } if r.PeerID != other.PeerID { return false } @@ -177,11 +167,6 @@ func (r *PeerRecord) Equal(other *PeerRecord) bool { return true } -// statelessSeqNo is a helper to generate a timestamp-based sequence number. -func statelessSeqNo() uint64 { - return uint64(time.Now().UnixNano()) -} - func addrsFromProtobuf(addrs []*pb.PeerRecord_AddressInfo) []ma.Multiaddr { var out []ma.Multiaddr for _, addr := range addrs { diff --git a/record/envelope.go b/record/envelope.go index 4290c689..27682aab 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "time" pool "github.com/libp2p/go-buffer-pool" "github.com/libp2p/go-libp2p-core/crypto" @@ -27,6 +28,9 @@ type SignedEnvelope struct { // TODO(yusef): enforce multicodec prefix PayloadType []byte + // A monotonically-increasing sequence counter for ordering SignedEnvelopes in time. + Seq uint64 + // The envelope payload. Payload []byte @@ -63,6 +67,7 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, PublicKey: privateKey.GetPublic(), PayloadType: payloadType, Payload: payload, + Seq: statelessSeqNo(), signature: sig, }, nil } @@ -96,6 +101,7 @@ func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { PublicKey: key, PayloadType: e.PayloadType, Payload: e.Payload, + Seq: e.Seq, signature: e.Signature, }, nil } @@ -112,6 +118,7 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { PublicKey: key, PayloadType: e.PayloadType, Payload: e.Payload, + Seq: e.Seq, Signature: e.signature, } return proto.Marshal(&msg) @@ -121,10 +128,14 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { // payload, payload type, and signature. This implies that they were also // created with the same domain string. func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { - return e.PublicKey.Equals(other.PublicKey) && + if other == nil { + return e == nil + } + return e.Seq == other.Seq && + e.PublicKey.Equals(other.PublicKey) && bytes.Compare(e.PayloadType, other.PayloadType) == 0 && - bytes.Compare(e.Payload, other.Payload) == 0 && - bytes.Compare(e.signature, other.signature) == 0 + bytes.Compare(e.signature, other.signature) == 0 && + bytes.Compare(e.Payload, other.Payload) == 0 } // validate returns true if the envelope signature is valid for the given 'domain', @@ -176,3 +187,8 @@ func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, er return b[:s], nil } + +// statelessSeqNo is a helper to generate a timestamp-based sequence number. +func statelessSeqNo() uint64 { + return uint64(time.Now().UnixNano()) +} diff --git a/record/pb/envelope.pb.go b/record/pb/envelope.pb.go index 10548a54..aa0984e6 100644 --- a/record/pb/envelope.pb.go +++ b/record/pb/envelope.pb.go @@ -9,6 +9,7 @@ import ( pb "github.com/libp2p/go-libp2p-core/crypto/pb" io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -20,13 +21,14 @@ var _ = math.Inf // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type SignedEnvelope struct { PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` - Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` + Seq uint64 `protobuf:"varint,4,opt,name=seq,proto3" json:"seq,omitempty"` + Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` } func (m *SignedEnvelope) Reset() { *m = SignedEnvelope{} } @@ -43,7 +45,7 @@ func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return xxx_messageInfo_SignedEnvelope.Marshal(b, m, deterministic) } else { b = b[:cap(b)] - n, err := m.MarshalTo(b) + n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } @@ -83,6 +85,13 @@ func (m *SignedEnvelope) GetPayload() []byte { return nil } +func (m *SignedEnvelope) GetSeq() uint64 { + if m != nil { + return m.Seq + } + return 0 +} + func (m *SignedEnvelope) GetSignature() []byte { if m != nil { return m.Signature @@ -97,26 +106,27 @@ func init() { func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } var fileDescriptor_ee266e8c558e9dc5 = []byte{ - // 200 bytes of a gzipped FileDescriptorProto + // 216 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2c, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x48, 0x92, 0x12, 0x4b, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x48, - 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0xe6, 0x31, 0x72, 0xf1, 0x05, 0x67, 0xa6, 0xe7, 0xa5, 0xa6, + 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x36, 0x30, 0x72, 0xf1, 0x05, 0x67, 0xa6, 0xe7, 0xa5, 0xa6, 0xb8, 0x42, 0xf5, 0x0a, 0x19, 0x71, 0x71, 0x16, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x89, 0xe8, 0xc1, 0x34, 0x25, 0xe9, 0x05, 0xc0, 0xe4, 0x82, 0x10, 0xca, 0x84, 0x14, 0xb8, 0xb8, 0x0b, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x42, 0x2a, 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18, 0x35, 0x78, 0x82, 0x90, 0x85, 0x84, 0x24, 0xb8, 0xd8, 0xa1, - 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, 0x2b, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97, 0x58, - 0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x02, 0x96, 0x43, 0x08, 0x38, 0x49, 0x9c, 0x78, 0x24, 0xc7, 0x78, - 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, - 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x12, 0x1b, 0xd8, 0x07, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xfb, 0xd0, 0x77, 0x21, 0xf6, 0x00, 0x00, 0x00, + 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, 0x2b, 0x24, 0xc0, 0xc5, 0x5c, 0x9c, 0x5a, 0x28, 0xc1, 0xa2, + 0xc0, 0xa8, 0xc1, 0x12, 0x04, 0x62, 0x0a, 0xc9, 0x70, 0x71, 0x16, 0x67, 0xa6, 0xe7, 0x25, 0x96, + 0x94, 0x16, 0xa5, 0x4a, 0xb0, 0x82, 0x55, 0x23, 0x04, 0x9c, 0x24, 0x4e, 0x3c, 0x92, 0x63, 0xbc, + 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, + 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, 0x0d, 0xec, 0x27, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x57, 0x41, 0x23, 0x95, 0x08, 0x01, 0x00, 0x00, } func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -124,49 +134,66 @@ func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { } func (m *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SignedEnvelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.PublicKey != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintEnvelope(dAtA, i, uint64(m.PublicKey.Size())) - n1, err := m.PublicKey.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x2a } - if len(m.PayloadType) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) - i += copy(dAtA[i:], m.PayloadType) + if m.Seq != 0 { + i = encodeVarintEnvelope(dAtA, i, uint64(m.Seq)) + i-- + dAtA[i] = 0x20 } if len(m.Payload) > 0 { - dAtA[i] = 0x1a - i++ + i -= len(m.Payload) + copy(dAtA[i:], m.Payload) i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Payload))) - i += copy(dAtA[i:], m.Payload) + i-- + dAtA[i] = 0x1a } - if len(m.Signature) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) - i += copy(dAtA[i:], m.Signature) + if len(m.PayloadType) > 0 { + i -= len(m.PayloadType) + copy(dAtA[i:], m.PayloadType) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) + i-- + dAtA[i] = 0x12 + } + if m.PublicKey != nil { + { + size, err := m.PublicKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEnvelope(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintEnvelope(dAtA []byte, offset int, v uint64) int { + offset -= sovEnvelope(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *SignedEnvelope) Size() (n int) { if m == nil { @@ -186,6 +213,9 @@ func (m *SignedEnvelope) Size() (n int) { if l > 0 { n += 1 + l + sovEnvelope(uint64(l)) } + if m.Seq != 0 { + n += 1 + sovEnvelope(uint64(m.Seq)) + } l = len(m.Signature) if l > 0 { n += 1 + l + sovEnvelope(uint64(l)) @@ -194,14 +224,7 @@ func (m *SignedEnvelope) Size() (n int) { } func sovEnvelope(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozEnvelope(x uint64) (n int) { return sovEnvelope(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -340,6 +363,25 @@ func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: + 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 ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Seq |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) } @@ -400,6 +442,7 @@ func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { func skipEnvelope(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -431,10 +474,8 @@ func skipEnvelope(dAtA []byte) (n int, err error) { break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -455,55 +496,30 @@ func skipEnvelope(dAtA []byte) (n int, err error) { return 0, ErrInvalidLengthEnvelope } iNdEx += length - if iNdEx < 0 { - return 0, ErrInvalidLengthEnvelope - } - return iNdEx, nil case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowEnvelope - } - 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 := skipEnvelope(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - if iNdEx < 0 { - return 0, ErrInvalidLengthEnvelope - } - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEnvelope + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEnvelope = fmt.Errorf("proto: unexpected end of group") ) diff --git a/record/pb/envelope.proto b/record/pb/envelope.proto index a0fb2b83..ab099085 100644 --- a/record/pb/envelope.proto +++ b/record/pb/envelope.proto @@ -8,5 +8,6 @@ message SignedEnvelope { crypto.pb.PublicKey publicKey = 1; bytes payloadType = 2; bytes payload = 3; - bytes signature = 4; + uint64 seq = 4; + bytes signature = 5; } From 25c1a5dcd2b9df88fbc1675b96a3c03d4b7b1f34 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 7 Jan 2020 13:38:09 -0500 Subject: [PATCH 39/69] commit go.sum --- go.sum | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/go.sum b/go.sum index 0b299001..aff4a008 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,7 @@ github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5D github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= @@ -49,9 +50,13 @@ github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= @@ -82,16 +87,20 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smola/gocompat v0.2.0 h1:6b1oIMlUXIpz//VKEDzPVBK8KG7beVwmHIUEBIs/Pns= github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/src-d/envconfig v1.0.0 h1:/AJi6DtjFhZKNx3OB2qMsq7y4yT5//AeSZIe7rk+PX8= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -132,6 +141,7 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -142,7 +152,9 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d h1:mXa4inJUuWOoA4uEROxtJ3VMELMlVkIxIfcR0HBekAM= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1 h1:heWvX7J6qbGWbeFS/aRmiy1eYaT+QMV6wNvHDyMjQV4= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From ce6885c21e7c63c8c7e6a5e19a2b0bde88d6146c Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 7 Jan 2020 13:49:44 -0500 Subject: [PATCH 40/69] add Seq field to envelope signature --- record/envelope.go | 12 +++++++----- record/envelope_test.go | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/record/envelope.go b/record/envelope.go index 27682aab..50661ea3 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -52,7 +52,8 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, return nil, ErrEmptyDomain } - unsigned, err := makeUnsigned(domain, payloadType, payload) + seq := statelessSeqNo() + unsigned, err := makeUnsigned(domain, payloadType, payload, seq) if err != nil { return nil, err } @@ -67,7 +68,7 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, PublicKey: privateKey.GetPublic(), PayloadType: payloadType, Payload: payload, - Seq: statelessSeqNo(), + Seq: seq, signature: sig, }, nil } @@ -141,7 +142,7 @@ func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { // validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) validate(domain string) error { - unsigned, err := makeUnsigned(domain, e.PayloadType, e.Payload) + unsigned, err := makeUnsigned(domain, e.PayloadType, e.Payload, e.Seq) if err != nil { return err } @@ -160,9 +161,10 @@ func (e *SignedEnvelope) validate(domain string) error { // makeUnsigned is a helper function that prepares a buffer to sign or verify. // It returns a byte slice from a pool. The caller MUST return this slice to the // pool. -func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, error) { +func makeUnsigned(domain string, payloadType []byte, payload []byte, seq uint64) ([]byte, error) { var ( - fields = [][]byte{[]byte(domain), payloadType, payload} + seqBytes = varint.ToUvarint(seq) + fields = [][]byte{[]byte(domain), payloadType, seqBytes, payload} // fields are prefixed with their length as an unsigned varint. we // compute the lengths before allocating the sig buffer so we know how diff --git a/record/envelope_test.go b/record/envelope_test.go index b6e8aaf8..2f0ac023 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -128,6 +128,28 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { test.ExpectError(t, err, "should not be able to open envelope with modified payload") } +func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { + var ( + payload = []byte("happy hacking") + domain = "libp2p-testing" + payloadType = []byte("/libp2p/testdata") + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) + ) + + test.AssertNilError(t, err) + + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + test.AssertNilError(t, err) + + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { + msg.Seq = envelope.Seq + 1 + }) + + // try to open our modified envelope + _, err = ConsumeEnvelope(serialized, domain) + test.ExpectError(t, err, "should not be able to open envelope with modified seq field") +} + // Since we're outside of the crypto package (to avoid import cycles with test package), // we can't alter the fields in a SignedEnvelope directly. This helper marshals // the envelope to a protobuf and calls the alterMsg function, which should From be3fa5fd3fc35958a5bad9a8cd3fff9aee7aaecb Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Wed, 15 Jan 2020 10:16:35 -0500 Subject: [PATCH 41/69] fix proto_path in Makefile --- peer/pb/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer/pb/Makefile b/peer/pb/Makefile index df34e54b..7cf8222f 100644 --- a/peer/pb/Makefile +++ b/peer/pb/Makefile @@ -4,7 +4,7 @@ GO = $(PB:.proto=.pb.go) all: $(GO) %.pb.go: %.proto - protoc --proto_path=$(GOPATH)/src:. --gogofaster_out=. $< + protoc --proto_path=$(PWD):$(PWD)/../.. --gogofaster_out=. $< clean: rm -f *.pb.go From 4b29ab4bbf41694eebe1fc18aa88e1f533fffc7b Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Wed, 15 Jan 2020 10:27:37 -0500 Subject: [PATCH 42/69] fix import ordering --- peerstore/peerstore.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 0e95e15d..0b2369c2 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -5,15 +5,13 @@ package peerstore import ( "context" "errors" - "github.com/libp2p/go-libp2p-core/record" "io" "math" "time" - "github.com/libp2p/go-libp2p-core/peer" - ic "github.com/libp2p/go-libp2p-core/crypto" - + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/record" ma "github.com/multiformats/go-multiaddr" ) From 1ff557877c02ae4e881760be3ce211575d4ad86a Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Wed, 15 Jan 2020 10:43:08 -0500 Subject: [PATCH 43/69] comments for PeerRecord proto message also removes the seq field from PeerMessage proto, since it was moved to the SignedEnvelope --- peer/pb/peer_record.pb.go | 68 +++++++++++++-------------------------- peer/pb/peer_record.proto | 15 ++++++++- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/peer/pb/peer_record.pb.go b/peer/pb/peer_record.pb.go index fddd4430..27832198 100644 --- a/peer/pb/peer_record.pb.go +++ b/peer/pb/peer_record.pb.go @@ -22,9 +22,18 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// PeerRecord messages contain information that is useful to share with other peers. +// Currently, a PeerRecord contains the public listen addresses for a peer, but this +// is expected to expand to include other information in the future. +// +// PeerRecords are designed to be serialized to bytes and placed inside of +// SignedEnvelopes before sharing with other peers. +// See https://github.com/libp2p/go-libp2p-core/record/pb/envelope.proto for +// the SignedEnvelope definition. type PeerRecord struct { - PeerId []byte `protobuf:"bytes,1,opt,name=peerId,proto3" json:"peerId,omitempty"` - Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` + // peerId contains a libp2p peer id in its binary representation. + PeerId []byte `protobuf:"bytes,1,opt,name=peerId,proto3" json:"peerId,omitempty"` + // addresses is a list of public listen addresses for the peer. Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` } @@ -68,13 +77,6 @@ func (m *PeerRecord) GetPeerId() []byte { return nil } -func (m *PeerRecord) GetSeq() uint64 { - if m != nil { - return m.Seq - } - return 0 -} - func (m *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo { if m != nil { return m.Addresses @@ -82,6 +84,8 @@ func (m *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo { return nil } +// AddressInfo is a wrapper around a binary multiaddr. It is defined as a +// separate message to allow us to add per-address metadata in the future. type PeerRecord_AddressInfo struct { Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` } @@ -134,19 +138,18 @@ func init() { func init() { proto.RegisterFile("peer_record.proto", fileDescriptor_dc0d8059ab0ad14d) } var fileDescriptor_dc0d8059ab0ad14d = []byte{ - // 186 bytes of a gzipped FileDescriptorProto + // 170 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x48, 0x4d, 0x2d, 0x8a, 0x2f, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, - 0x09, 0xe9, 0x15, 0x24, 0x29, 0x2d, 0x62, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, + 0x09, 0xe9, 0x15, 0x24, 0x29, 0x4d, 0x60, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, 0x0a, 0x89, 0x71, 0xb1, 0x81, 0x64, 0x3c, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xa0, - 0x3c, 0x21, 0x01, 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x10, - 0x53, 0xc8, 0x96, 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, 0x58, 0x82, 0x59, - 0x81, 0x59, 0x83, 0xdb, 0x48, 0x5e, 0x0f, 0x6a, 0xaa, 0x1e, 0xc2, 0x44, 0x3d, 0x47, 0x88, 0x22, - 0xcf, 0xbc, 0xb4, 0xfc, 0x20, 0x84, 0x0e, 0x29, 0x6d, 0x2e, 0x6e, 0x24, 0x19, 0x21, 0x19, 0x2e, - 0xce, 0xdc, 0xd2, 0x9c, 0x92, 0x4c, 0x90, 0x02, 0xa8, 0xd5, 0x08, 0x01, 0x27, 0x89, 0x13, 0x8f, - 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, - 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0x7b, 0xc7, 0x18, 0x10, 0x00, 0x00, - 0xff, 0xff, 0x85, 0x84, 0x12, 0xd0, 0xe3, 0x00, 0x00, 0x00, + 0x3c, 0x21, 0x5b, 0x2e, 0xce, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0xe2, 0xd4, 0x62, 0x09, 0x66, + 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x79, 0x3d, 0xa8, 0x19, 0x7a, 0x08, 0xfd, 0x7a, 0x8e, 0x10, 0x45, + 0x9e, 0x79, 0x69, 0xf9, 0x41, 0x08, 0x1d, 0x52, 0xda, 0x5c, 0xdc, 0x48, 0x32, 0x42, 0x32, 0x5c, + 0x9c, 0xb9, 0xa5, 0x39, 0x25, 0x99, 0x20, 0x05, 0x50, 0x8b, 0x10, 0x02, 0x4e, 0x12, 0x27, 0x1e, + 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, + 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x90, 0xc4, 0x06, 0x76, 0xbc, 0x31, 0x20, 0x00, 0x00, + 0xff, 0xff, 0x2a, 0x8e, 0x23, 0x44, 0xd1, 0x00, 0x00, 0x00, } func (m *PeerRecord) Marshal() (dAtA []byte, err error) { @@ -183,11 +186,6 @@ func (m *PeerRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } - if m.Seq != 0 { - i = encodeVarintPeerRecord(dAtA, i, uint64(m.Seq)) - i-- - dAtA[i] = 0x10 - } if len(m.PeerId) > 0 { i -= len(m.PeerId) copy(dAtA[i:], m.PeerId) @@ -249,9 +247,6 @@ func (m *PeerRecord) Size() (n int) { if l > 0 { n += 1 + l + sovPeerRecord(uint64(l)) } - if m.Seq != 0 { - n += 1 + sovPeerRecord(uint64(m.Seq)) - } if len(m.Addresses) > 0 { for _, e := range m.Addresses { l = e.Size() @@ -343,25 +338,6 @@ func (m *PeerRecord) Unmarshal(dAtA []byte) error { m.PeerId = []byte{} } iNdEx = postIndex - 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 ErrIntOverflowPeerRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Seq |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) diff --git a/peer/pb/peer_record.proto b/peer/pb/peer_record.proto index 6048d4b7..e3b36a95 100644 --- a/peer/pb/peer_record.proto +++ b/peer/pb/peer_record.proto @@ -1,12 +1,25 @@ syntax = "proto3"; package peer.pb; +// PeerRecord messages contain information that is useful to share with other peers. +// Currently, a PeerRecord contains the public listen addresses for a peer, but this +// is expected to expand to include other information in the future. +// +// PeerRecords are designed to be serialized to bytes and placed inside of +// SignedEnvelopes before sharing with other peers. +// See https://github.com/libp2p/go-libp2p-core/record/pb/envelope.proto for +// the SignedEnvelope definition. message PeerRecord { + + // AddressInfo is a wrapper around a binary multiaddr. It is defined as a + // separate message to allow us to add per-address metadata in the future. message AddressInfo { bytes multiaddr = 1; } + // peerId contains a libp2p peer id in its binary representation. bytes peerId = 1; - uint64 seq = 2; + + // addresses is a list of public listen addresses for the peer. repeated AddressInfo addresses = 3; } From 8dc249dddef25348ab30846a4782526d536c4828 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Wed, 15 Jan 2020 15:06:25 -0500 Subject: [PATCH 44/69] use Record type for envelope payloads --- peer/record.go | 106 +++++++++++++++++----------------------- peer/record_test.go | 25 +++++----- record/envelope.go | 65 +++++++++++++++++++----- record/envelope_test.go | 89 +++++++++++++++++++++++++++------ record/record.go | 64 ++++++++++++++++++++++++ record/record_test.go | 58 ++++++++++++++++++++++ 6 files changed, 307 insertions(+), 100 deletions(-) create mode 100644 record/record.go create mode 100644 record/record_test.go diff --git a/peer/record.go b/peer/record.go index ccd1b5b4..87f86a96 100644 --- a/peer/record.go +++ b/peer/record.go @@ -2,6 +2,7 @@ package peer import ( "errors" + "fmt" "github.com/gogo/protobuf/proto" "github.com/libp2p/go-libp2p-core/crypto" @@ -10,6 +11,10 @@ import ( ma "github.com/multiformats/go-multiaddr" ) +func init() { + record.RegisterPayloadType(PeerRecordEnvelopePayloadType, &PeerRecord{}) +} + // The domain string used for peer records contained in a SignedEnvelope. const PeerRecordEnvelopeDomain = "libp2p-peer-record" @@ -19,7 +24,7 @@ var PeerRecordEnvelopePayloadType = []byte("/libp2p/peer-record") // ErrPeerIdMismatch is returned when attempting to sign a PeerRecord using a key that // does not match the PeerID contained in the record. -var ErrPeerIdMismatch = errors.New("unable to sign peer record: key does not match record.PeerID") +var ErrPeerIdMismatch = errors.New("signing key does not match record.PeerID") // PeerRecord contains information that is broadly useful to share with other peers, // either through a direct exchange (as in the libp2p identify protocol), or through @@ -29,33 +34,35 @@ var ErrPeerIdMismatch = errors.New("unable to sign peer record: key does not mat // is expected to expand to include other information in the future. // // PeerRecords are intended to be signed by the peer they describe, and there are no -// public methods for marshalling and unmarshalling unsigned PeerRecords. +// public methods for marshalling unsigned PeerRecords. // // To share a PeerRecord, first call Sign to wrap the record in a SignedEnvelope // and sign it with the local peer's private key: // -// rec := NewPeerRecord(myPeerId, myAddrs) +// rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} // envelope, err := rec.Sign(myPrivateKey) // // The resulting record.SignedEnvelope can be marshalled to a []byte and shared // publicly. As a convenience, the MarshalSigned method will produce the // SignedEnvelope and marshal it to a []byte in one go: // -// rec := NewPeerRecord(myPeerId, myAddrs) +// rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} // recordBytes, err := rec.MarshalSigned(myPrivateKey) // -// To validate and unmarshal a signed PeerRecord from a remote peer, use the -// UnmarshalSignedPeerRecord function: +// To validate and unmarshal a signed PeerRecord from a remote peer, +// "consume" the containing envelope and unmarshal the payload using +// the Unmarshal method on an empty PeerRecord: // -// rec, envelope, err := UnmarshalSignedPeerRecord(recordBytes) +// envelope, err := record.ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain) +// if err != nil { +// doSomething(err) +// } +// var rec *PeerRecord +// err = rec.Unmarshal(envelope.Payload) // -// Note that UnmarshalSignedPeerRecord returns the record as well as the -// SignedEnvelope that wraps it, so that you can inspect any metadata -// from the envelope if you need it (for example, the remote peer's public key). -// If you already have an unmarshalled SignedEnvelope, you can call -// PeerRecordFromSignedEnvelope instead: +// You may also want to check that envelope.PayloadType matches PeerRecordEnvelopePayloadType +// before unmarshaling the payload. // -// rec, err := PeerRecordFromSignedEnvelope(envelope) type PeerRecord struct { // PeerID is the ID of the peer this record pertains to. PeerID ID @@ -64,55 +71,44 @@ type PeerRecord struct { Addrs []ma.Multiaddr } -// NewPeerRecord creates a PeerRecord with the given ID and addresses. -// It generates a timestamp-based sequence number. -func NewPeerRecord(id ID, addrs []ma.Multiaddr) *PeerRecord { - return &PeerRecord{ - PeerID: id, - Addrs: addrs, - } -} - // PeerRecordFromAddrInfo creates a PeerRecord from an AddrInfo struct. // It generates a timestamp-based sequence number. func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord { - return NewPeerRecord(info.ID, info.Addrs) + return &PeerRecord{PeerID: info.ID, Addrs: info.Addrs} } -// UnmarshalSignedPeerRecord accepts a []byte containing a SignedEnvelope protobuf message. -// It will try to validate the envelope signature and unmarshal the payload as a PeerRecord. -// Returns the PeerRecord and the SignedEnvelope if successful. -func UnmarshalSignedPeerRecord(envelopeBytes []byte) (*PeerRecord, *record.SignedEnvelope, error) { - envelope, err := record.ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain) +// TODO(yusef): doc comment +func (r *PeerRecord) UnmarshalRecord(bytes []byte) error { + if r == nil { + return fmt.Errorf("cannot unmarshal PeerRecord to nil receiver") + } + + var msg pb.PeerRecord + err := proto.Unmarshal(bytes, &msg) if err != nil { - return nil, nil, err + return err } - rec, err := PeerRecordFromSignedEnvelope(envelope) + var id ID + err = id.UnmarshalBinary(msg.PeerId) if err != nil { - return nil, nil, err + return err } - return rec, envelope, nil + r.PeerID = id + r.Addrs = addrsFromProtobuf(msg.Addresses) + return nil } -// PeerRecordFromSignedEnvelope accepts a SignedEnvelope struct and returns a PeerRecord struct. -// Fails if the signature is invalid, or if the payload cannot be unmarshaled as a PeerRecord. -func PeerRecordFromSignedEnvelope(envelope *record.SignedEnvelope) (*PeerRecord, error) { - var msg pb.PeerRecord - err := proto.Unmarshal(envelope.Payload, &msg) - if err != nil { - return nil, err - } - id, err := IDFromBytes(msg.PeerId) +// TODO(yusef): doc comment +func (r *PeerRecord) MarshalRecord() ([]byte, error) { + idBytes, err := r.PeerID.MarshalBinary() if err != nil { return nil, err } - if !id.MatchesPublicKey(envelope.PublicKey) { - return nil, errors.New("peer id in peer record does not match signing key") + msg := pb.PeerRecord{ + PeerId: idBytes, + Addresses: addrsToProtobuf(r.Addrs), } - return &PeerRecord{ - PeerID: id, - Addrs: addrsFromProtobuf(msg.Addresses), - }, nil + return proto.Marshal(&msg) } // Sign wraps the PeerRecord in a routing.SignedEnvelope, signed with the given @@ -125,21 +121,11 @@ func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.SignedEnvelope, error if p != r.PeerID { return nil, ErrPeerIdMismatch } - idBytes, err := p.MarshalBinary() - if err != nil { - return nil, err - } - msg := pb.PeerRecord{ - PeerId: idBytes, - Addresses: addrsToProtobuf(r.Addrs), - } - payload, err := proto.Marshal(&msg) - if err != nil { - return nil, err - } - return record.MakeEnvelope(privKey, PeerRecordEnvelopeDomain, PeerRecordEnvelopePayloadType, payload) + return record.MakeEnvelopeFromRecord(privKey, PeerRecordEnvelopeDomain, r) } +// MarshalSigned is a convenience method that wraps the PeerRecord in a routing.SignedEnvelope, +// and marshals the SignedEnvelope to a []byte. func (r *PeerRecord) MarshalSigned(privKey crypto.PrivKey) ([]byte, error) { env, err := r.Sign(privKey) if err != nil { diff --git a/peer/record_test.go b/peer/record_test.go index f4d926cd..b0a0c677 100644 --- a/peer/record_test.go +++ b/peer/record_test.go @@ -16,16 +16,24 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) { id, err := IDFromPrivateKey(priv) test.AssertNilError(t, err) - rec := NewPeerRecord(id, addrs) + rec := &PeerRecord{PeerID: id, Addrs: addrs} envelope, err := rec.Sign(priv) test.AssertNilError(t, err) + //t.Run("sanity check, don't push to remote", func(t *testing.T) { + // id.UnmarshalBinary() + //}) + t.Run("is unaltered after round-trip serde", func(t *testing.T) { envBytes, err := envelope.Marshal() test.AssertNilError(t, err) - rec2, env2, err := UnmarshalSignedPeerRecord(envBytes) + env2, untypedRecord, err := record.ConsumeEnvelope(envBytes, PeerRecordEnvelopeDomain) test.AssertNilError(t, err) + rec2, ok := untypedRecord.(*PeerRecord) + if !ok { + t.Error("unmarshaled record is not a *PeerRecord") + } if !rec.Equal(rec2) { t.Error("expected peer record to be unaltered after round-trip serde") } @@ -36,21 +44,10 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) { t.Run("signing fails if signing key does not match peer id in record", func(t *testing.T) { id = "some-other-peer-id" - rec := NewPeerRecord(id, addrs) + rec := &PeerRecord{PeerID: id, Addrs: addrs} _, err := rec.Sign(priv) if err != ErrPeerIdMismatch { t.Error("expected signing with mismatched private key to fail") } }) - - t.Run("unwrapping from signed envelope fails if envelope has wrong domain string", func(t *testing.T) { - payload := []byte("ignored") - test.AssertNilError(t, err) - - env, err := record.MakeEnvelope(priv, "wrong-domain", PeerRecordEnvelopePayloadType, payload) - test.AssertNilError(t, err) - envBytes, err := env.Marshal() - _, _, err = UnmarshalSignedPeerRecord(envBytes) - test.ExpectError(t, err, "unwrapping PeerRecord from envelope should fail if envelope was created with wrong domain string") - }) } diff --git a/record/envelope.go b/record/envelope.go index 50661ea3..27b6feb5 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -32,7 +32,7 @@ type SignedEnvelope struct { Seq uint64 // The envelope payload. - Payload []byte + RawPayload []byte // The signature of the domain string :: type hint :: payload. signature []byte @@ -67,22 +67,65 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, return &SignedEnvelope{ PublicKey: privateKey.GetPublic(), PayloadType: payloadType, - Payload: payload, + RawPayload: payload, Seq: seq, signature: sig, }, nil } +func MakeEnvelopeFromRecord(privateKey crypto.PrivKey, domain string, rec Record) (*SignedEnvelope, error) { + payloadType, ok := payloadTypeForRecord(rec) + if !ok { + return nil, fmt.Errorf("unable to determine value for PayloadType field") + } + payloadBytes, err := rec.MarshalRecord() + if err != nil { + return nil, fmt.Errorf("error marshaling record: %v", err) + } + return MakeEnvelope(privateKey, domain, payloadType, payloadBytes) +} + // ConsumeEnvelope unmarshals a serialized SignedEnvelope, and validates its // signature using the provided 'domain' string. If validation fails, an error -// is returned, along with the unmarshalled payload so it can be inspected. -func ConsumeEnvelope(data []byte, domain string) (*SignedEnvelope, error) { +// is returned, along with the unmarshalled envelope so it can be inspected. +// TODO(yusef): improve this doc comment before merge +func ConsumeEnvelope(data []byte, domain string) (envelope *SignedEnvelope, contents Record, err error) { + e, err := UnmarshalEnvelope(data) + if err != nil { + return nil, nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) + } + + err = e.validate(domain) + if err != nil { + return e, nil, fmt.Errorf("failed to validate envelope: %w", err) + } + + contents, err = unmarshalRecordPayload(e.PayloadType, e.RawPayload) + if err != nil { + return e, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err) + } + + return e, contents, nil +} + +// TODO(yusef): doc comment before merge +func ConsumeTypedEnvelope(data []byte, domain string, payloadDest Record) (envelope *SignedEnvelope, err error) { e, err := UnmarshalEnvelope(data) if err != nil { return nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) } - return e, e.validate(domain) + err = e.validate(domain) + if err != nil { + return e, fmt.Errorf("failed to validate envelope: %w", err) + } + + err = payloadDest.UnmarshalRecord(e.RawPayload) + if err != nil { + return e, fmt.Errorf("failed to unmarshal envelope payload: %w", err) + } + + return e, nil } // UnmarshalEnvelope unmarshals a serialized SignedEnvelope protobuf message, @@ -101,7 +144,7 @@ func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { return &SignedEnvelope{ PublicKey: key, PayloadType: e.PayloadType, - Payload: e.Payload, + RawPayload: e.Payload, Seq: e.Seq, signature: e.Signature, }, nil @@ -118,7 +161,7 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { msg := pb.SignedEnvelope{ PublicKey: key, PayloadType: e.PayloadType, - Payload: e.Payload, + Payload: e.RawPayload, Seq: e.Seq, Signature: e.signature, } @@ -136,13 +179,13 @@ func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { e.PublicKey.Equals(other.PublicKey) && bytes.Compare(e.PayloadType, other.PayloadType) == 0 && bytes.Compare(e.signature, other.signature) == 0 && - bytes.Compare(e.Payload, other.Payload) == 0 + bytes.Compare(e.RawPayload, other.RawPayload) == 0 } -// validate returns true if the envelope signature is valid for the given 'domain', -// or false if it is invalid. May return an error if signature validation fails. +// validate returns nil if the envelope signature is valid for the given 'domain', +// or an error if signature validation fails. func (e *SignedEnvelope) validate(domain string) error { - unsigned, err := makeUnsigned(domain, e.PayloadType, e.Payload, e.Seq) + unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload, e.Seq) if err != nil { return err } diff --git a/record/envelope_test.go b/record/envelope_test.go index 2f0ac023..ac009587 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -12,10 +12,23 @@ import ( "github.com/gogo/protobuf/proto" ) +type simpleRecord struct { + message string +} + +func (r *simpleRecord) MarshalRecord() ([]byte, error) { + return []byte(r.message), nil +} + +func (r *simpleRecord) UnmarshalRecord(buf []byte) error { + r.message = string(buf) + return nil +} + // Make an envelope, verify & open it, marshal & unmarshal it func TestEnvelopeHappyPath(t *testing.T) { var ( - payload = []byte("happy hacking") + rec = simpleRecord{"hello world!"} domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") priv, pub, err = test.RandTestKeyPair(crypto.Ed25519, 256) @@ -23,6 +36,9 @@ func TestEnvelopeHappyPath(t *testing.T) { test.AssertNilError(t, err) + payload, err := rec.MarshalRecord() + test.AssertNilError(t, err) + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) test.AssertNilError(t, err) @@ -37,16 +53,51 @@ func TestEnvelopeHappyPath(t *testing.T) { serialized, err := envelope.Marshal() test.AssertNilError(t, err) - deserialized, err := ConsumeEnvelope(serialized, domain) + RegisterPayloadType(payloadType, &simpleRecord{}) + deserialized, rec2, err := ConsumeEnvelope(serialized, domain) test.AssertNilError(t, err) - if bytes.Compare(deserialized.Payload, payload) != 0 { + if bytes.Compare(deserialized.RawPayload, payload) != 0 { t.Error("payload of envelope does not match input") } if !envelope.Equal(deserialized) { t.Error("round-trip serde results in unequal envelope structures") } + + typedRec, ok := rec2.(*simpleRecord) + if !ok { + t.Error("expected ConsumeEnvelope to return record with type registered for payloadType") + } + if typedRec.message != "hello world!" { + t.Error("unexpected alteration of record") + } +} + +func TestConsumeTypedEnvelope(t *testing.T) { + var ( + rec = simpleRecord{"hello world!"} + domain = "libp2p-testing" + payloadType = []byte("/libp2p/testdata") + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) + ) + + payload, err := rec.MarshalRecord() + test.AssertNilError(t, err) + + envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + test.AssertNilError(t, err) + + envelopeBytes, err := envelope.Marshal() + test.AssertNilError(t, err) + + rec2 := &simpleRecord{} + _, err = ConsumeTypedEnvelope(envelopeBytes, domain, rec2) + test.AssertNilError(t, err) + + if rec2.message != "hello world!" { + t.Error("unexpected alteration of record") + } } func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { @@ -66,7 +117,7 @@ func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { var ( - payload = []byte("happy hacking") + rec = &simpleRecord{"hello world"} domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) @@ -74,19 +125,21 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { test.AssertNilError(t, err) - envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + RegisterPayloadType(payloadType, &simpleRecord{}) + + envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) test.AssertNilError(t, err) serialized, err := envelope.Marshal() // try to open our modified envelope - _, err = ConsumeEnvelope(serialized, "wrong-domain") + _, _, err = ConsumeEnvelope(serialized, "wrong-domain") test.ExpectError(t, err, "should not be able to open envelope with incorrect domain") } func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { var ( - payload = []byte("happy hacking") + rec = &simpleRecord{"hello world!"} domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) @@ -94,7 +147,9 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { test.AssertNilError(t, err) - envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + RegisterPayloadType(payloadType, &simpleRecord{}) + + envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { @@ -102,13 +157,13 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { }) // try to open our modified envelope - _, err = ConsumeEnvelope(serialized, domain) + _, _, err = ConsumeEnvelope(serialized, domain) test.ExpectError(t, err, "should not be able to open envelope with modified PayloadType") } func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { var ( - payload = []byte("happy hacking") + rec = &simpleRecord{"hello world!"} domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) @@ -116,7 +171,9 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { test.AssertNilError(t, err) - envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + RegisterPayloadType(payloadType, &simpleRecord{}) + + envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { @@ -124,13 +181,13 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { }) // try to open our modified envelope - _, err = ConsumeEnvelope(serialized, domain) + _, _, err = ConsumeEnvelope(serialized, domain) test.ExpectError(t, err, "should not be able to open envelope with modified payload") } func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { var ( - payload = []byte("happy hacking") + rec = &simpleRecord{"hello world!"} domain = "libp2p-testing" payloadType = []byte("/libp2p/testdata") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) @@ -138,7 +195,9 @@ func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { test.AssertNilError(t, err) - envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + RegisterPayloadType(payloadType, &simpleRecord{}) + + envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { @@ -146,7 +205,7 @@ func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { }) // try to open our modified envelope - _, err = ConsumeEnvelope(serialized, domain) + _, _, err = ConsumeEnvelope(serialized, domain) test.ExpectError(t, err, "should not be able to open envelope with modified seq field") } diff --git a/record/record.go b/record/record.go new file mode 100644 index 00000000..749316b6 --- /dev/null +++ b/record/record.go @@ -0,0 +1,64 @@ +package record + +import ( + "errors" + "reflect" +) + +var ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") + +var payloadTypeRegistry = make(map[string]Record) + +type Record interface { + MarshalRecord() ([]byte, error) + + UnmarshalRecord([]byte) error +} + +func RegisterPayloadType(payloadType []byte, prototype Record) { + payloadTypeRegistry[string(payloadType)] = prototype +} + +func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, error) { + rec, err := blankRecordForPayloadType(payloadType) + if err != nil { + return nil, err + } + err = rec.UnmarshalRecord(payloadBytes) + if err != nil { + return nil, err + } + return rec, nil +} + +func blankRecordForPayloadType(payloadType []byte) (Record, error) { + prototype, ok := payloadTypeRegistry[string(payloadType)] + if !ok { + return nil, ErrPayloadTypeNotRegistered + } + + valueType := getValueType(prototype) + val := reflect.New(valueType) + asRecord := val.Interface().(Record) + return asRecord, nil +} + +func payloadTypeForRecord(rec Record) ([]byte, bool) { + valueType := getValueType(rec) + + for k, v := range payloadTypeRegistry { + t := getValueType(v) + if t.AssignableTo(valueType) { + return []byte(k), true + } + } + return []byte{}, false +} + +func getValueType(i interface{}) reflect.Type { + valueType := reflect.TypeOf(i) + if valueType.Kind() == reflect.Ptr { + valueType = valueType.Elem() + } + return valueType +} diff --git a/record/record_test.go b/record/record_test.go new file mode 100644 index 00000000..1e2b92aa --- /dev/null +++ b/record/record_test.go @@ -0,0 +1,58 @@ +package record + +import ( + "bytes" + "testing" +) + +var testPayloadType = []byte("/libp2p/test/record/payload-type") + +type testPayload struct { + unmarshalPayloadCalled bool +} + +func (p *testPayload) MarshalRecord() ([]byte, error) { + return []byte("hello"), nil +} + +func (p *testPayload) UnmarshalRecord(bytes []byte) error { + p.unmarshalPayloadCalled = true + return nil +} + +func TestUnmarshalPayload(t *testing.T) { + t.Run("fails if payload type is unregistered", func(t *testing.T) { + _, err := unmarshalRecordPayload([]byte("unknown type"), []byte{}) + if err != ErrPayloadTypeNotRegistered { + t.Error("Expected error when unmarshalling payload with unregistered payload type") + } + }) + + t.Run("calls UnmarshalRecord on concrete Record type", func(t *testing.T) { + RegisterPayloadType(testPayloadType, &testPayload{}) + + payload, err := unmarshalRecordPayload(testPayloadType, []byte{}) + if err != nil { + t.Errorf("unexpected error unmarshalling registered payload type: %v", err) + } + typedPayload, ok := payload.(*testPayload) + if !ok { + t.Error("expected unmarshalled payload to be of the correct type") + } + if !typedPayload.unmarshalPayloadCalled { + t.Error("expected UnmarshalRecord to be called on concrete Record instance") + } + }) +} + +func TestMulticodecForRecord(t *testing.T) { + RegisterPayloadType(testPayloadType, &testPayload{}) + rec := &testPayload{} + mc, ok := payloadTypeForRecord(rec) + if !ok { + t.Error("expected to get multicodec for registered payload type") + } + if !bytes.Equal(mc, testPayloadType) { + t.Error("got unexpected multicodec for registered Payload type") + } +} From 77a03aaf835466b7c37bf8b288881344c9f3c7bf Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 16 Jan 2020 09:45:48 -0500 Subject: [PATCH 45/69] rename SignedEnvelope -> Envelope, unmarshal payload in ConsumeEnvelope --- event/addrs.go | 2 +- peer/record.go | 20 +++++----- peerstore/peerstore.go | 10 ++--- record/envelope.go | 58 ++++++++++++++++------------- record/envelope_test.go | 20 +++++----- record/pb/envelope.pb.go | 79 ++++++++++++++++++++-------------------- record/pb/envelope.proto | 3 +- 7 files changed, 101 insertions(+), 91 deletions(-) diff --git a/event/addrs.go b/event/addrs.go index 35c422d2..e68faf89 100644 --- a/event/addrs.go +++ b/event/addrs.go @@ -21,5 +21,5 @@ type EvtLocalAddressesUpdated struct { // for the local peer has been produced. This will happen whenever the set of listen // addresses changes. type EvtLocalPeerRecordUpdated struct { - SignedRecord *record.SignedEnvelope + SignedRecord *record.Envelope } diff --git a/peer/record.go b/peer/record.go index 87f86a96..398ee3be 100644 --- a/peer/record.go +++ b/peer/record.go @@ -15,10 +15,10 @@ func init() { record.RegisterPayloadType(PeerRecordEnvelopePayloadType, &PeerRecord{}) } -// The domain string used for peer records contained in a SignedEnvelope. +// The domain string used for peer records contained in a Envelope. const PeerRecordEnvelopeDomain = "libp2p-peer-record" -// The type hint used to identify peer records in a SignedEnvelope. +// The type hint used to identify peer records in a Envelope. // TODO: register multicodec var PeerRecordEnvelopePayloadType = []byte("/libp2p/peer-record") @@ -36,15 +36,15 @@ var ErrPeerIdMismatch = errors.New("signing key does not match record.PeerID") // PeerRecords are intended to be signed by the peer they describe, and there are no // public methods for marshalling unsigned PeerRecords. // -// To share a PeerRecord, first call Sign to wrap the record in a SignedEnvelope +// To share a PeerRecord, first call Sign to wrap the record in a Envelope // and sign it with the local peer's private key: // // rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} // envelope, err := rec.Sign(myPrivateKey) // -// The resulting record.SignedEnvelope can be marshalled to a []byte and shared +// The resulting record.Envelope can be marshalled to a []byte and shared // publicly. As a convenience, the MarshalSigned method will produce the -// SignedEnvelope and marshal it to a []byte in one go: +// Envelope and marshal it to a []byte in one go: // // rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} // recordBytes, err := rec.MarshalSigned(myPrivateKey) @@ -111,9 +111,9 @@ func (r *PeerRecord) MarshalRecord() ([]byte, error) { return proto.Marshal(&msg) } -// Sign wraps the PeerRecord in a routing.SignedEnvelope, signed with the given +// Sign wraps the PeerRecord in a routing.Envelope, signed with the given // private key. The private key must match the PeerID field of the PeerRecord. -func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.SignedEnvelope, error) { +func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.Envelope, error) { p, err := IDFromPrivateKey(privKey) if err != nil { return nil, err @@ -121,11 +121,11 @@ func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.SignedEnvelope, error if p != r.PeerID { return nil, ErrPeerIdMismatch } - return record.MakeEnvelopeFromRecord(privKey, PeerRecordEnvelopeDomain, r) + return record.MakeEnvelopeWithRecord(privKey, PeerRecordEnvelopeDomain, r) } -// MarshalSigned is a convenience method that wraps the PeerRecord in a routing.SignedEnvelope, -// and marshals the SignedEnvelope to a []byte. +// MarshalSigned is a convenience method that wraps the PeerRecord in a routing.Envelope, +// and marshals the Envelope to a []byte. func (r *PeerRecord) MarshalSigned(privKey crypto.PrivKey) ([]byte, error) { env, err := r.Sign(privKey) if err != nil { diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 0b2369c2..3b384653 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -123,7 +123,7 @@ type AddrBook interface { // CertifiedAddrBook manages "self-certified" addresses for remote peers. // Self-certified addresses are contained in peer.PeerRecords -// that are wraped in a record.SignedEnvelope and signed by the peer +// that are wraped in a record.Envelope and signed by the peer // to whom they belong. // // This interface is most useful when combined with AddrBook. @@ -137,7 +137,7 @@ type AddrBook interface { // type CertifiedAddrBook interface { // AddCertifiedAddrs adds addresses from a signed peer.PeerRecord (contained in - // a routing.SignedEnvelope), which will expire after the given TTL. + // a routing.Envelope), which will expire after the given TTL. // // Signed records added via this method will be stored without // alteration as long as the address TTLs remain valid. The SignedEnvelopes @@ -160,12 +160,12 @@ type CertifiedAddrBook interface { // AddrBook.SetAddrs will be ignored. AddrBook.SetAddrs may still be used // to update the TTL of certified addresses if they have previously been // added via AddCertifiedAddrs. - AddCertifiedAddrs(s *record.SignedEnvelope, ttl time.Duration) error + AddCertifiedAddrs(s *record.Envelope, ttl time.Duration) error - // SignedPeerRecord returns a SignedEnvelope containing a PeerRecord for the + // SignedPeerRecord returns a Envelope containing a PeerRecord for the // given peer id, if one exists. // Returns nil if no signed PeerRecord exists for the peer. - SignedPeerRecord(p peer.ID) *record.SignedEnvelope + SignedPeerRecord(p peer.ID) *record.Envelope } // GetCertifiedAddrBook is a helper to "upcast" an AddrBook to a diff --git a/record/envelope.go b/record/envelope.go index 27b6feb5..880fcade 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -14,13 +14,13 @@ import ( "github.com/multiformats/go-varint" ) -// SignedEnvelope contains an arbitrary []byte payload, signed by a libp2p peer. +// Envelope contains an arbitrary []byte payload, signed by a libp2p peer. // // Envelopes are signed in the context of a particular "domain", which is a // string specified when creating and verifying the envelope. You must know the // domain string used to produce the envelope in order to verify the signature // and access the payload. -type SignedEnvelope struct { +type Envelope struct { // The public key that can be used to verify the signature and derive the peer id of the signer. PublicKey crypto.PubKey @@ -39,19 +39,24 @@ type SignedEnvelope struct { } var ErrEmptyDomain = errors.New("envelope domain must not be empty") +var ErrEmptyPayloadType = errors.New("payloadType must not be empty") var ErrInvalidSignature = errors.New("invalid signature or incorrect domain") -// MakeEnvelope constructs a new SignedEnvelope using the given privateKey. +// MakeEnvelope constructs a new Envelope using the given privateKey. // // The required 'domain' string contextualizes the envelope for a particular purpose, // and must be supplied when verifying the signature. // -// The 'PayloadType' field indicates what kind of data is contained and may be empty. -func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, payload []byte) (*SignedEnvelope, error) { +// The 'PayloadType' field indicates what kind of data is contained and must be non-empty. +func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, payload []byte) (*Envelope, error) { if domain == "" { return nil, ErrEmptyDomain } + if len(payloadType) == 0 { + return nil, ErrEmptyPayloadType + } + seq := statelessSeqNo() unsigned, err := makeUnsigned(domain, payloadType, payload, seq) if err != nil { @@ -64,7 +69,7 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, return nil, err } - return &SignedEnvelope{ + return &Envelope{ PublicKey: privateKey.GetPublic(), PayloadType: payloadType, RawPayload: payload, @@ -73,7 +78,12 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, }, nil } -func MakeEnvelopeFromRecord(privateKey crypto.PrivKey, domain string, rec Record) (*SignedEnvelope, error) { +// MakeEnvelopeWithRecord wraps the given Record in an Envelope, and signs it using the given key +// and domain string. +// +// The Record's concrete type must be associated with a multicodec payload type identifier +// (see record.RegisterPayloadType). +func MakeEnvelopeWithRecord(privateKey crypto.PrivKey, domain string, rec Record) (*Envelope, error) { payloadType, ok := payloadTypeForRecord(rec) if !ok { return nil, fmt.Errorf("unable to determine value for PayloadType field") @@ -85,11 +95,11 @@ func MakeEnvelopeFromRecord(privateKey crypto.PrivKey, domain string, rec Record return MakeEnvelope(privateKey, domain, payloadType, payloadBytes) } -// ConsumeEnvelope unmarshals a serialized SignedEnvelope, and validates its +// ConsumeEnvelope unmarshals a serialized Envelope, and validates its // signature using the provided 'domain' string. If validation fails, an error // is returned, along with the unmarshalled envelope so it can be inspected. // TODO(yusef): improve this doc comment before merge -func ConsumeEnvelope(data []byte, domain string) (envelope *SignedEnvelope, contents Record, err error) { +func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record, err error) { e, err := UnmarshalEnvelope(data) if err != nil { return nil, nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) @@ -100,16 +110,15 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *SignedEnvelope, cont return e, nil, fmt.Errorf("failed to validate envelope: %w", err) } - contents, err = unmarshalRecordPayload(e.PayloadType, e.RawPayload) + rec, err = unmarshalRecordPayload(e.PayloadType, e.RawPayload) if err != nil { return e, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err) } - - return e, contents, nil + return e, rec, nil } // TODO(yusef): doc comment before merge -func ConsumeTypedEnvelope(data []byte, domain string, payloadDest Record) (envelope *SignedEnvelope, err error) { +func ConsumeTypedEnvelope(data []byte, domain string, destRecord Record) (envelope *Envelope, err error) { e, err := UnmarshalEnvelope(data) if err != nil { return nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) @@ -120,18 +129,17 @@ func ConsumeTypedEnvelope(data []byte, domain string, payloadDest Record) (envel return e, fmt.Errorf("failed to validate envelope: %w", err) } - err = payloadDest.UnmarshalRecord(e.RawPayload) + err = destRecord.UnmarshalRecord(e.RawPayload) if err != nil { return e, fmt.Errorf("failed to unmarshal envelope payload: %w", err) } - return e, nil } -// UnmarshalEnvelope unmarshals a serialized SignedEnvelope protobuf message, +// UnmarshalEnvelope unmarshals a serialized Envelope protobuf message, // without validating its contents. Most users should use ConsumeEnvelope. -func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { - var e pb.SignedEnvelope +func UnmarshalEnvelope(data []byte) (*Envelope, error) { + var e pb.Envelope if err := proto.Unmarshal(data, &e); err != nil { return nil, err } @@ -141,7 +149,7 @@ func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { return nil, err } - return &SignedEnvelope{ + return &Envelope{ PublicKey: key, PayloadType: e.PayloadType, RawPayload: e.Payload, @@ -151,14 +159,14 @@ func UnmarshalEnvelope(data []byte) (*SignedEnvelope, error) { } // Marshal returns a byte slice containing a serialized protobuf representation -// of a SignedEnvelope. -func (e *SignedEnvelope) Marshal() ([]byte, error) { +// of a Envelope. +func (e *Envelope) Marshal() ([]byte, error) { key, err := crypto.PublicKeyToProto(e.PublicKey) if err != nil { return nil, err } - msg := pb.SignedEnvelope{ + msg := pb.Envelope{ PublicKey: key, PayloadType: e.PayloadType, Payload: e.RawPayload, @@ -168,10 +176,10 @@ func (e *SignedEnvelope) Marshal() ([]byte, error) { return proto.Marshal(&msg) } -// Equal returns true if the other SignedEnvelope has the same public key, +// Equal returns true if the other Envelope has the same public key, // payload, payload type, and signature. This implies that they were also // created with the same domain string. -func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { +func (e *Envelope) Equal(other *Envelope) bool { if other == nil { return e == nil } @@ -184,7 +192,7 @@ func (e *SignedEnvelope) Equal(other *SignedEnvelope) bool { // validate returns nil if the envelope signature is valid for the given 'domain', // or an error if signature validation fails. -func (e *SignedEnvelope) validate(domain string) error { +func (e *Envelope) validate(domain string) error { unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload, e.Seq) if err != nil { return err diff --git a/record/envelope_test.go b/record/envelope_test.go index ac009587..640bcab6 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -127,7 +127,7 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { RegisterPayloadType(payloadType, &simpleRecord{}) - envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) test.AssertNilError(t, err) serialized, err := envelope.Marshal() @@ -149,10 +149,10 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { RegisterPayloadType(payloadType, &simpleRecord{}) - envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) test.AssertNilError(t, err) - serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { msg.PayloadType = []byte("foo") }) @@ -173,10 +173,10 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { RegisterPayloadType(payloadType, &simpleRecord{}) - envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) test.AssertNilError(t, err) - serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { msg.Payload = []byte("totally legit, trust me") }) @@ -197,10 +197,10 @@ func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { RegisterPayloadType(payloadType, &simpleRecord{}) - envelope, err := MakeEnvelopeFromRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) test.AssertNilError(t, err) - serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.SignedEnvelope) { + serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { msg.Seq = envelope.Seq + 1 }) @@ -210,17 +210,17 @@ func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { } // Since we're outside of the crypto package (to avoid import cycles with test package), -// we can't alter the fields in a SignedEnvelope directly. This helper marshals +// we can't alter the fields in a Envelope directly. This helper marshals // the envelope to a protobuf and calls the alterMsg function, which should // alter the protobuf message. // Returns the serialized altered protobuf message. -func alterMessageAndMarshal(t *testing.T, envelope *SignedEnvelope, alterMsg func(*pb.SignedEnvelope)) []byte { +func alterMessageAndMarshal(t *testing.T, envelope *Envelope, alterMsg func(*pb.Envelope)) []byte { t.Helper() serialized, err := envelope.Marshal() test.AssertNilError(t, err) - msg := pb.SignedEnvelope{} + msg := pb.Envelope{} err = proto.Unmarshal(serialized, &msg) test.AssertNilError(t, err) diff --git a/record/pb/envelope.pb.go b/record/pb/envelope.pb.go index aa0984e6..8c7571c9 100644 --- a/record/pb/envelope.pb.go +++ b/record/pb/envelope.pb.go @@ -23,7 +23,8 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -type SignedEnvelope struct { +// TODO(yusef): doc comments before merge +type Envelope struct { PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` @@ -31,18 +32,18 @@ type SignedEnvelope struct { Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` } -func (m *SignedEnvelope) Reset() { *m = SignedEnvelope{} } -func (m *SignedEnvelope) String() string { return proto.CompactTextString(m) } -func (*SignedEnvelope) ProtoMessage() {} -func (*SignedEnvelope) Descriptor() ([]byte, []int) { +func (m *Envelope) Reset() { *m = Envelope{} } +func (m *Envelope) String() string { return proto.CompactTextString(m) } +func (*Envelope) ProtoMessage() {} +func (*Envelope) Descriptor() ([]byte, []int) { return fileDescriptor_ee266e8c558e9dc5, []int{0} } -func (m *SignedEnvelope) XXX_Unmarshal(b []byte) error { +func (m *Envelope) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Envelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_SignedEnvelope.Marshal(b, m, deterministic) + return xxx_messageInfo_Envelope.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -52,47 +53,47 @@ func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return b[:n], nil } } -func (m *SignedEnvelope) XXX_Merge(src proto.Message) { - xxx_messageInfo_SignedEnvelope.Merge(m, src) +func (m *Envelope) XXX_Merge(src proto.Message) { + xxx_messageInfo_Envelope.Merge(m, src) } -func (m *SignedEnvelope) XXX_Size() int { +func (m *Envelope) XXX_Size() int { return m.Size() } -func (m *SignedEnvelope) XXX_DiscardUnknown() { - xxx_messageInfo_SignedEnvelope.DiscardUnknown(m) +func (m *Envelope) XXX_DiscardUnknown() { + xxx_messageInfo_Envelope.DiscardUnknown(m) } -var xxx_messageInfo_SignedEnvelope proto.InternalMessageInfo +var xxx_messageInfo_Envelope proto.InternalMessageInfo -func (m *SignedEnvelope) GetPublicKey() *pb.PublicKey { +func (m *Envelope) GetPublicKey() *pb.PublicKey { if m != nil { return m.PublicKey } return nil } -func (m *SignedEnvelope) GetPayloadType() []byte { +func (m *Envelope) GetPayloadType() []byte { if m != nil { return m.PayloadType } return nil } -func (m *SignedEnvelope) GetPayload() []byte { +func (m *Envelope) GetPayload() []byte { if m != nil { return m.Payload } return nil } -func (m *SignedEnvelope) GetSeq() uint64 { +func (m *Envelope) GetSeq() uint64 { if m != nil { return m.Seq } return 0 } -func (m *SignedEnvelope) GetSignature() []byte { +func (m *Envelope) GetSignature() []byte { if m != nil { return m.Signature } @@ -100,30 +101,30 @@ func (m *SignedEnvelope) GetSignature() []byte { } func init() { - proto.RegisterType((*SignedEnvelope)(nil), "record.pb.SignedEnvelope") + proto.RegisterType((*Envelope)(nil), "record.pb.Envelope") } func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } var fileDescriptor_ee266e8c558e9dc5 = []byte{ - // 216 bytes of a gzipped FileDescriptorProto + // 210 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2c, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x48, 0x92, 0x12, 0x4b, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x48, - 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x36, 0x30, 0x72, 0xf1, 0x05, 0x67, 0xa6, 0xe7, 0xa5, 0xa6, - 0xb8, 0x42, 0xf5, 0x0a, 0x19, 0x71, 0x71, 0x16, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, - 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x89, 0xe8, 0xc1, 0x34, 0x25, 0xe9, 0x05, 0xc0, 0xe4, - 0x82, 0x10, 0xca, 0x84, 0x14, 0xb8, 0xb8, 0x0b, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x42, 0x2a, - 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18, 0x35, 0x78, 0x82, 0x90, 0x85, 0x84, 0x24, 0xb8, 0xd8, 0xa1, - 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, 0x2b, 0x24, 0xc0, 0xc5, 0x5c, 0x9c, 0x5a, 0x28, 0xc1, 0xa2, - 0xc0, 0xa8, 0xc1, 0x12, 0x04, 0x62, 0x0a, 0xc9, 0x70, 0x71, 0x16, 0x67, 0xa6, 0xe7, 0x25, 0x96, - 0x94, 0x16, 0xa5, 0x4a, 0xb0, 0x82, 0x55, 0x23, 0x04, 0x9c, 0x24, 0x4e, 0x3c, 0x92, 0x63, 0xbc, - 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, - 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, 0x0d, 0xec, 0x27, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x57, 0x41, 0x23, 0x95, 0x08, 0x01, 0x00, 0x00, + 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x56, 0x31, 0x72, 0x71, 0xb8, 0x42, 0x75, 0x09, 0x19, 0x71, + 0x71, 0x16, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, + 0x1b, 0x89, 0xe8, 0xc1, 0x94, 0x27, 0xe9, 0x05, 0xc0, 0xe4, 0x82, 0x10, 0xca, 0x84, 0x14, 0xb8, + 0xb8, 0x0b, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x42, 0x2a, 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18, + 0x35, 0x78, 0x82, 0x90, 0x85, 0x84, 0x24, 0xb8, 0xd8, 0xa1, 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, + 0x2b, 0x24, 0xc0, 0xc5, 0x5c, 0x9c, 0x5a, 0x28, 0xc1, 0xa2, 0xc0, 0xa8, 0xc1, 0x12, 0x04, 0x62, + 0x0a, 0xc9, 0x70, 0x71, 0x16, 0x67, 0xa6, 0xe7, 0x25, 0x96, 0x94, 0x16, 0xa5, 0x4a, 0xb0, 0x82, + 0x55, 0x23, 0x04, 0x9c, 0x24, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, + 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, + 0x0d, 0xec, 0x1b, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xa1, 0x77, 0xca, 0x02, 0x01, + 0x00, 0x00, } -func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { +func (m *Envelope) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -133,12 +134,12 @@ func (m *SignedEnvelope) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SignedEnvelope) MarshalTo(dAtA []byte) (int, error) { +func (m *Envelope) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *SignedEnvelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Envelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -195,7 +196,7 @@ func encodeVarintEnvelope(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *SignedEnvelope) Size() (n int) { +func (m *Envelope) Size() (n int) { if m == nil { return 0 } @@ -229,7 +230,7 @@ func sovEnvelope(x uint64) (n int) { func sozEnvelope(x uint64) (n int) { return sovEnvelope(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { +func (m *Envelope) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -252,10 +253,10 @@ func (m *SignedEnvelope) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SignedEnvelope: wiretype end group for non-group") + return fmt.Errorf("proto: Envelope: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SignedEnvelope: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Envelope: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/record/pb/envelope.proto b/record/pb/envelope.proto index ab099085..94675124 100644 --- a/record/pb/envelope.proto +++ b/record/pb/envelope.proto @@ -4,7 +4,8 @@ package record.pb; import "crypto/pb/crypto.proto"; -message SignedEnvelope { +// TODO(yusef): doc comments before merge +message Envelope { crypto.pb.PublicKey publicKey = 1; bytes payloadType = 2; bytes payload = 3; From 8d8da386f26482e06dc21989a6b5ade69f0a46d9 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 16 Jan 2020 09:50:08 -0500 Subject: [PATCH 46/69] return buffer to pool before early return --- record/envelope.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/record/envelope.go b/record/envelope.go index 880fcade..6e33e15e 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -59,10 +59,10 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, seq := statelessSeqNo() unsigned, err := makeUnsigned(domain, payloadType, payload, seq) + defer pool.Put(unsigned) if err != nil { return nil, err } - defer pool.Put(unsigned) sig, err := privateKey.Sign(unsigned) if err != nil { @@ -194,10 +194,10 @@ func (e *Envelope) Equal(other *Envelope) bool { // or an error if signature validation fails. func (e *Envelope) validate(domain string) error { unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload, e.Seq) + defer pool.Put(unsigned) if err != nil { return err } - defer pool.Put(unsigned) valid, err := e.PublicKey.Verify(unsigned, e.signature) if err != nil { From 39d8cbc7582a9037ee4fea1d15e0c2d04489d8f0 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 16 Jan 2020 10:32:17 -0500 Subject: [PATCH 47/69] doc comments --- peer/record.go | 30 +++++++++++++++++------------- record/envelope.go | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/peer/record.go b/peer/record.go index 398ee3be..b0b14823 100644 --- a/peer/record.go +++ b/peer/record.go @@ -33,8 +33,9 @@ var ErrPeerIdMismatch = errors.New("signing key does not match record.PeerID") // Currently, a PeerRecord contains the public listen addresses for a peer, but this // is expected to expand to include other information in the future. // -// PeerRecords are intended to be signed by the peer they describe, and there are no -// public methods for marshalling unsigned PeerRecords. +// PeerRecords are intended to be shared with other peers inside a signed +// routing.Envelope, and PeerRecord implements the routing.Record interface +// to facilitate this. // // To share a PeerRecord, first call Sign to wrap the record in a Envelope // and sign it with the local peer's private key: @@ -50,18 +51,16 @@ var ErrPeerIdMismatch = errors.New("signing key does not match record.PeerID") // recordBytes, err := rec.MarshalSigned(myPrivateKey) // // To validate and unmarshal a signed PeerRecord from a remote peer, -// "consume" the containing envelope and unmarshal the payload using -// the Unmarshal method on an empty PeerRecord: +// "consume" the containing envelope, which will return both the +// routing.Envelope and the inner Record. The Record must be cast to +// a PeerRecord pointer before use: // -// envelope, err := record.ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain) +// envelope, untypedRecord, err := ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain) // if err != nil { -// doSomething(err) +// handleError(err) +// return // } -// var rec *PeerRecord -// err = rec.Unmarshal(envelope.Payload) -// -// You may also want to check that envelope.PayloadType matches PeerRecordEnvelopePayloadType -// before unmarshaling the payload. +// peerRec := untypedRecord.(*PeerRecord) // type PeerRecord struct { // PeerID is the ID of the peer this record pertains to. @@ -77,7 +76,10 @@ func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord { return &PeerRecord{PeerID: info.ID, Addrs: info.Addrs} } -// TODO(yusef): doc comment +// UnmarshalRecord parses a PeerRecord from a byte slice. +// This method is called automatically when consuming a record.Envelope +// whose PayloadType indicates that it contains a PeerRecord. +// It is generally not necessary or recommended to call this method directly. func (r *PeerRecord) UnmarshalRecord(bytes []byte) error { if r == nil { return fmt.Errorf("cannot unmarshal PeerRecord to nil receiver") @@ -98,7 +100,9 @@ func (r *PeerRecord) UnmarshalRecord(bytes []byte) error { return nil } -// TODO(yusef): doc comment +// MarshalRecord serializes a PeerRecord to a byte slice. +// This method is called automatically when constructing a routing.Envelope +// using MakeEnvelopeWithRecord or PeerRecord.Sign. func (r *PeerRecord) MarshalRecord() ([]byte, error) { idBytes, err := r.PeerID.MarshalBinary() if err != nil { diff --git a/record/envelope.go b/record/envelope.go index 6e33e15e..3532009a 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -81,7 +81,7 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, // MakeEnvelopeWithRecord wraps the given Record in an Envelope, and signs it using the given key // and domain string. // -// The Record's concrete type must be associated with a multicodec payload type identifier +// The Record's concrete type must be associated with a payload type identifier // (see record.RegisterPayloadType). func MakeEnvelopeWithRecord(privateKey crypto.PrivKey, domain string, rec Record) (*Envelope, error) { payloadType, ok := payloadTypeForRecord(rec) From d567b244773bddfec380884f686620aa98b87684 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 10:14:21 -0500 Subject: [PATCH 48/69] rename CertifiedAddrBook methods, update comments --- peerstore/peerstore.go | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 3b384653..1087f9f6 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -123,25 +123,33 @@ type AddrBook interface { // CertifiedAddrBook manages "self-certified" addresses for remote peers. // Self-certified addresses are contained in peer.PeerRecords -// that are wraped in a record.Envelope and signed by the peer +// which are wrapped in a record.Envelope and signed by the peer // to whom they belong. // +// Certified addresses (CA) are generally more secure than uncertified +// addresses (UA). Consequently, CAs beat and displace UAs. When the +// peerstore learns CAs for a peer, it will reject UAs for the same peer +// (as long as the former haven't expired). +// Furthermore, peer records act like sequenced snapshots of CAs. Therefore, +// processing a peer record that's newer than the last one seen overwrites +// all addresses with the incoming ones. +// // This interface is most useful when combined with AddrBook. // To test whether a given AddrBook / Peerstore implementation supports -// certified addresses, callers should type-assert on the CertifiedAddrBook -// interface: +// certified addresses, callers should use the GetCertifiedAddrBook helper or +// type-assert on the CertifiedAddrBook interface: // // if cab, ok := aPeerstore.(CertifiedAddrBook); ok { -// cab.AddCertifiedAddrs(signedPeerRecord, aTTL) +// cab.ProcessPeerRecord(signedPeerRecord, aTTL) // } // type CertifiedAddrBook interface { - // AddCertifiedAddrs adds addresses from a signed peer.PeerRecord (contained in + // ProcessPeerRecord adds addresses from a signed peer.PeerRecord (contained in // a routing.Envelope), which will expire after the given TTL. // // Signed records added via this method will be stored without - // alteration as long as the address TTLs remain valid. The SignedEnvelopes - // containing the PeerRecords can be retrieved by calling SignedPeerRecord(peerID). + // alteration as long as the address TTLs remain valid. The Envelopes + // containing the PeerRecords can be retrieved by calling GetPeerRecord(peerID). // // If the signed PeerRecord belongs to a peer that already has certified // addresses in the CertifiedAddrBook, the new addresses will replace the @@ -153,19 +161,19 @@ type CertifiedAddrBook interface { // If the CertifiedAddrBook is also an AddrBook (which is most likely the case), // adding certified addresses for a peer will *replace* any // existing non-certified addresses for that peer, and only the certified - // addresses will be returned from AddrBook.Addrs. + // addresses will be returned from AddrBook.Addrs thereafter. // // Likewise, once certified addresses have been added for a given peer, // any non-certified addresses added via AddrBook.AddAddrs or // AddrBook.SetAddrs will be ignored. AddrBook.SetAddrs may still be used - // to update the TTL of certified addresses if they have previously been - // added via AddCertifiedAddrs. - AddCertifiedAddrs(s *record.Envelope, ttl time.Duration) error + // to update the TTL of certified addresses that have previously been + // added via ProcessPeerRecord. + ProcessPeerRecord(s *record.Envelope, ttl time.Duration) error - // SignedPeerRecord returns a Envelope containing a PeerRecord for the + // GetPeerRecord returns a Envelope containing a PeerRecord for the // given peer id, if one exists. // Returns nil if no signed PeerRecord exists for the peer. - SignedPeerRecord(p peer.ID) *record.Envelope + GetPeerRecord(p peer.ID) *record.Envelope } // GetCertifiedAddrBook is a helper to "upcast" an AddrBook to a From cf0122ad8c258fd83e0a163f85aab11ab583068c Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 10:15:48 -0500 Subject: [PATCH 49/69] cache unmarshalled Record payload inside Envelope --- record/envelope.go | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/record/envelope.go b/record/envelope.go index 3532009a..e5b1f33b 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "sync" "time" pool "github.com/libp2p/go-buffer-pool" @@ -36,6 +37,11 @@ type Envelope struct { // The signature of the domain string :: type hint :: payload. signature []byte + + // the unmarshalled payload as a Record, cached on first access via the Record accessor method + cached Record + unmarshalError error + unmarshalOnce sync.Once } var ErrEmptyDomain = errors.New("envelope domain must not be empty") @@ -110,7 +116,7 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record return e, nil, fmt.Errorf("failed to validate envelope: %w", err) } - rec, err = unmarshalRecordPayload(e.PayloadType, e.RawPayload) + rec, err = e.Record() if err != nil { return e, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err) } @@ -190,6 +196,32 @@ func (e *Envelope) Equal(other *Envelope) bool { bytes.Compare(e.RawPayload, other.RawPayload) == 0 } +// Record returns the Envelope's payload unmarshalled as a Record. +// The concrete type of the returned Record depends on which Record +// type was registered for the Envelope's PayloadType - see record.RegisterPayloadType. +// +// Once unmarshalled, the Record is cached for future access. +func (e *Envelope) Record() (Record, error) { + e.unmarshalOnce.Do(func() { + if e.cached != nil { + return + } + e.cached, e.unmarshalError = unmarshalRecordPayload(e.PayloadType, e.RawPayload) + }) + return e.cached, e.unmarshalError +} + +// TypedRecord unmarshals the Envelope's payload to the given Record instance. +// It is the caller's responsibility to ensure that the Record type is capable +// of unmarshalling the Envelope payload. Callers can inspect the Envelope's +// PayloadType field to determine the correct type of Record to use. +// +// This method will always unmarshal the Envelope payload even if a cached record +// exists. +func (e *Envelope) TypedRecord(dest Record) error { + return dest.UnmarshalRecord(e.RawPayload) +} + // validate returns nil if the envelope signature is valid for the given 'domain', // or an error if signature validation fails. func (e *Envelope) validate(domain string) error { From 972454490a885d7803660c53b13e4b6f4f54e94f Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 10:37:35 -0500 Subject: [PATCH 50/69] doc comments --- peer/record.go | 1 - record/record.go | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/peer/record.go b/peer/record.go index b0b14823..63141de1 100644 --- a/peer/record.go +++ b/peer/record.go @@ -71,7 +71,6 @@ type PeerRecord struct { } // PeerRecordFromAddrInfo creates a PeerRecord from an AddrInfo struct. -// It generates a timestamp-based sequence number. func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord { return &PeerRecord{PeerID: info.ID, Addrs: info.Addrs} } diff --git a/record/record.go b/record/record.go index 749316b6..fe0cd543 100644 --- a/record/record.go +++ b/record/record.go @@ -5,16 +5,52 @@ import ( "reflect" ) -var ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") +var ( + // ErrPayloadTypeNotRegistered is returned from ConsumeEnvelope when the Envelope's + // PayloadType does not match any registered Record types. + ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") -var payloadTypeRegistry = make(map[string]Record) + payloadTypeRegistry = make(map[string]Record) +) +// Record represents a data type that can be used as the payload of an Envelope. +// The Record interface defines the methods used to marshal and unmarshal a Record +// type to a byte slice. +// +// Record types may be "registered" as the default for a given Envelope.PayloadType +// using the RegisterPayloadType function. Once a Record type has been registered, +// an instance of that type will be created and used to unmarshal the payload of +// any Envelope with the registered PayloadType when the Envelope is opened using +// the ConsumeEnvelope function. +// +// To use an unregistered Record type instead, use ConsumeTypedEnvelope and pass in +// an instance of the Record type that you'd like the Envelope's payload to be +// unmarshaled into. type Record interface { MarshalRecord() ([]byte, error) UnmarshalRecord([]byte) error } +// RegisterPayloadType associates a binary payload type identifier with a concrete +// Record type. This is used to automatically unmarshal Record payloads from Envelopes +// when using ConsumeEnvelope, and to automatically marshal Records and determine the +// correct PayloadType when calling MakeEnvelopeWithRecord. +// +// Callers must provide an instance of the record type to be registered, which must be +// a pointer type. Registration should be done in the init function of the package +// where the Record type is defined: +// +// package hello_record +// +// var HelloRecordPayloadType = []byte("/libp2p/hello-record") +// +// func init() { +// RegisterPayloadType(HelloRecordPayloadType, &HelloRecord{}) +// } +// +// type HelloRecord struct { } // etc.. +// func RegisterPayloadType(payloadType []byte, prototype Record) { payloadTypeRegistry[string(payloadType)] = prototype } From 7ee4611788babbfb410135f03a22f23b5f1db3a5 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 10:48:37 -0500 Subject: [PATCH 51/69] store reflect.Type when registering Record --- record/record.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/record/record.go b/record/record.go index fe0cd543..cb645fe8 100644 --- a/record/record.go +++ b/record/record.go @@ -10,7 +10,7 @@ var ( // PayloadType does not match any registered Record types. ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") - payloadTypeRegistry = make(map[string]Record) + payloadTypeRegistry = make(map[string]reflect.Type) ) // Record represents a data type that can be used as the payload of an Envelope. @@ -52,7 +52,7 @@ type Record interface { // type HelloRecord struct { } // etc.. // func RegisterPayloadType(payloadType []byte, prototype Record) { - payloadTypeRegistry[string(payloadType)] = prototype + payloadTypeRegistry[string(payloadType)] = getValueType(prototype) } func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, error) { @@ -68,12 +68,11 @@ func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, er } func blankRecordForPayloadType(payloadType []byte) (Record, error) { - prototype, ok := payloadTypeRegistry[string(payloadType)] + valueType, ok := payloadTypeRegistry[string(payloadType)] if !ok { return nil, ErrPayloadTypeNotRegistered } - valueType := getValueType(prototype) val := reflect.New(valueType) asRecord := val.Interface().(Record) return asRecord, nil @@ -82,8 +81,7 @@ func blankRecordForPayloadType(payloadType []byte) (Record, error) { func payloadTypeForRecord(rec Record) ([]byte, bool) { valueType := getValueType(rec) - for k, v := range payloadTypeRegistry { - t := getValueType(v) + for k, t := range payloadTypeRegistry { if t.AssignableTo(valueType) { return []byte(k), true } From 3c208b0d26b2348cb02f7feddf72893872ab7c60 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 15:43:33 -0500 Subject: [PATCH 52/69] Revert "return buffer to pool before early return" 8d8da386f26482e06dc21989a6b5ade69f0a46d9 misread this - unsigned will be nil if there's an error, so it was right the way it was --- record/envelope.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/record/envelope.go b/record/envelope.go index e5b1f33b..5d395fd9 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -65,10 +65,10 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, seq := statelessSeqNo() unsigned, err := makeUnsigned(domain, payloadType, payload, seq) - defer pool.Put(unsigned) if err != nil { return nil, err } + defer pool.Put(unsigned) sig, err := privateKey.Sign(unsigned) if err != nil { @@ -226,10 +226,10 @@ func (e *Envelope) TypedRecord(dest Record) error { // or an error if signature validation fails. func (e *Envelope) validate(domain string) error { unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload, e.Seq) - defer pool.Put(unsigned) if err != nil { return err } + defer pool.Put(unsigned) valid, err := e.PublicKey.Verify(unsigned, e.signature) if err != nil { From a26c845a766b45ceabd87c17c0801d191650f0d4 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 16:43:55 -0500 Subject: [PATCH 53/69] use a DefaultRecord for unregistered PayloadTypes instead of returning an error if we don't have a registered Record for a given PayloadType, we can have a catch-all DefaultRecord type that just preserves the original payload as a []byte --- record/record.go | 40 +++++++++++++++++++++++++--------------- record/record_test.go | 15 +++++++++++---- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/record/record.go b/record/record.go index cb645fe8..5a489de1 100644 --- a/record/record.go +++ b/record/record.go @@ -1,17 +1,8 @@ package record -import ( - "errors" - "reflect" -) +import "reflect" -var ( - // ErrPayloadTypeNotRegistered is returned from ConsumeEnvelope when the Envelope's - // PayloadType does not match any registered Record types. - ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") - - payloadTypeRegistry = make(map[string]reflect.Type) -) +var payloadTypeRegistry = make(map[string]reflect.Type) // Record represents a data type that can be used as the payload of an Envelope. // The Record interface defines the methods used to marshal and unmarshal a Record @@ -32,14 +23,33 @@ type Record interface { UnmarshalRecord([]byte) error } +// DefaultRecord contains the payload of an Envelope whose PayloadType field +// does not match any registered Record type. The Contents field contains +// the unprocessed Envelope payload. +type DefaultRecord struct { + Contents []byte +} + +func (r *DefaultRecord) MarshalRecord() ([]byte, error) { + return r.Contents, nil +} + +func (r *DefaultRecord) UnmarshalRecord(data []byte) error { + r.Contents = make([]byte, len(data)) + copy(r.Contents, data) + return nil +} + // RegisterPayloadType associates a binary payload type identifier with a concrete // Record type. This is used to automatically unmarshal Record payloads from Envelopes // when using ConsumeEnvelope, and to automatically marshal Records and determine the // correct PayloadType when calling MakeEnvelopeWithRecord. // -// Callers must provide an instance of the record type to be registered, which must be -// a pointer type. Registration should be done in the init function of the package -// where the Record type is defined: +// To register a Record type, provide the payload type identifier and an +// empty instance of the Record type. +// +// Registration should be done in the init function of the package where the +// Record type is defined: // // package hello_record // @@ -70,7 +80,7 @@ func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, er func blankRecordForPayloadType(payloadType []byte) (Record, error) { valueType, ok := payloadTypeRegistry[string(payloadType)] if !ok { - return nil, ErrPayloadTypeNotRegistered + return &DefaultRecord{}, nil } val := reflect.New(valueType) diff --git a/record/record_test.go b/record/record_test.go index 1e2b92aa..62c1036c 100644 --- a/record/record_test.go +++ b/record/record_test.go @@ -21,10 +21,17 @@ func (p *testPayload) UnmarshalRecord(bytes []byte) error { } func TestUnmarshalPayload(t *testing.T) { - t.Run("fails if payload type is unregistered", func(t *testing.T) { - _, err := unmarshalRecordPayload([]byte("unknown type"), []byte{}) - if err != ErrPayloadTypeNotRegistered { - t.Error("Expected error when unmarshalling payload with unregistered payload type") + t.Run("returns DefaultRecord if payload type is unregistered", func(t *testing.T) { + rec, err := unmarshalRecordPayload([]byte("unknown type"), []byte("hello world")) + if err != nil { + t.Error(err) + } + defaultRec, ok := rec.(*DefaultRecord) + if !ok { + t.Error("expected unregistered PayloadType to be unmarshalled as DefaultRecord") + } + if !bytes.Equal(defaultRec.Contents, []byte("hello world")) { + t.Error("unexpected alteration of record") } }) From ae3bc7bdfb657c232229229706854a56effca80b Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Fri, 17 Jan 2020 16:50:45 -0500 Subject: [PATCH 54/69] cleanup DefaultRecord code a bit - removes unused error return from blankRecordForPayloadType - just references instead of copying in DefaultRecord.UnmarshalRecord I figure this is likely safe, since we'll be unmarshalling from the payload of an Envelope, which shouldn't get altered after it's created. --- record/record.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/record/record.go b/record/record.go index 5a489de1..8efb3ec9 100644 --- a/record/record.go +++ b/record/record.go @@ -35,8 +35,7 @@ func (r *DefaultRecord) MarshalRecord() ([]byte, error) { } func (r *DefaultRecord) UnmarshalRecord(data []byte) error { - r.Contents = make([]byte, len(data)) - copy(r.Contents, data) + r.Contents = data return nil } @@ -66,26 +65,23 @@ func RegisterPayloadType(payloadType []byte, prototype Record) { } func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, error) { - rec, err := blankRecordForPayloadType(payloadType) - if err != nil { - return nil, err - } - err = rec.UnmarshalRecord(payloadBytes) + rec := blankRecordForPayloadType(payloadType) + err := rec.UnmarshalRecord(payloadBytes) if err != nil { return nil, err } return rec, nil } -func blankRecordForPayloadType(payloadType []byte) (Record, error) { +func blankRecordForPayloadType(payloadType []byte) Record { valueType, ok := payloadTypeRegistry[string(payloadType)] if !ok { - return &DefaultRecord{}, nil + return &DefaultRecord{} } val := reflect.New(valueType) asRecord := val.Interface().(Record) - return asRecord, nil + return asRecord } func payloadTypeForRecord(rec Record) ([]byte, bool) { From 7a0522306530facfb1a08e2a4cb5251dce013c56 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 20 Jan 2020 11:47:42 -0500 Subject: [PATCH 55/69] use explicit payloadType in MakeEnvelopeWithRecord --- peer/record.go | 2 +- record/envelope.go | 12 ++---------- record/record.go | 14 ++------------ record/record_test.go | 12 ------------ 4 files changed, 5 insertions(+), 35 deletions(-) diff --git a/peer/record.go b/peer/record.go index 63141de1..c5974b4b 100644 --- a/peer/record.go +++ b/peer/record.go @@ -124,7 +124,7 @@ func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.Envelope, error) { if p != r.PeerID { return nil, ErrPeerIdMismatch } - return record.MakeEnvelopeWithRecord(privKey, PeerRecordEnvelopeDomain, r) + return record.MakeEnvelopeWithRecord(privKey, PeerRecordEnvelopeDomain, PeerRecordEnvelopePayloadType, r) } // MarshalSigned is a convenience method that wraps the PeerRecord in a routing.Envelope, diff --git a/record/envelope.go b/record/envelope.go index 5d395fd9..c1a4399e 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -84,16 +84,8 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, }, nil } -// MakeEnvelopeWithRecord wraps the given Record in an Envelope, and signs it using the given key -// and domain string. -// -// The Record's concrete type must be associated with a payload type identifier -// (see record.RegisterPayloadType). -func MakeEnvelopeWithRecord(privateKey crypto.PrivKey, domain string, rec Record) (*Envelope, error) { - payloadType, ok := payloadTypeForRecord(rec) - if !ok { - return nil, fmt.Errorf("unable to determine value for PayloadType field") - } +// MakeEnvelopeWithRecord marshals the given Record to bytes, then wraps it in an envelope using MakeEnvelope. +func MakeEnvelopeWithRecord(privateKey crypto.PrivKey, domain string, payloadType []byte, rec Record) (*Envelope, error) { payloadBytes, err := rec.MarshalRecord() if err != nil { return nil, fmt.Errorf("error marshaling record: %v", err) diff --git a/record/record.go b/record/record.go index 8efb3ec9..df61c1e2 100644 --- a/record/record.go +++ b/record/record.go @@ -51,11 +51,12 @@ func (r *DefaultRecord) UnmarshalRecord(data []byte) error { // Record type is defined: // // package hello_record +// import record "github.com/libp2p/go-libp2p-core/record" // // var HelloRecordPayloadType = []byte("/libp2p/hello-record") // // func init() { -// RegisterPayloadType(HelloRecordPayloadType, &HelloRecord{}) +// record.RegisterPayloadType(HelloRecordPayloadType, &HelloRecord{}) // } // // type HelloRecord struct { } // etc.. @@ -84,17 +85,6 @@ func blankRecordForPayloadType(payloadType []byte) Record { return asRecord } -func payloadTypeForRecord(rec Record) ([]byte, bool) { - valueType := getValueType(rec) - - for k, t := range payloadTypeRegistry { - if t.AssignableTo(valueType) { - return []byte(k), true - } - } - return []byte{}, false -} - func getValueType(i interface{}) reflect.Type { valueType := reflect.TypeOf(i) if valueType.Kind() == reflect.Ptr { diff --git a/record/record_test.go b/record/record_test.go index 62c1036c..77ea02e6 100644 --- a/record/record_test.go +++ b/record/record_test.go @@ -51,15 +51,3 @@ func TestUnmarshalPayload(t *testing.T) { } }) } - -func TestMulticodecForRecord(t *testing.T) { - RegisterPayloadType(testPayloadType, &testPayload{}) - rec := &testPayload{} - mc, ok := payloadTypeForRecord(rec) - if !ok { - t.Error("expected to get multicodec for registered payload type") - } - if !bytes.Equal(mc, testPayloadType) { - t.Error("got unexpected multicodec for registered Payload type") - } -} From 1de3d24c0cf219236250cb382150597b83dc1b6d Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 20 Jan 2020 11:51:17 -0500 Subject: [PATCH 56/69] Revert DefaultRecord commits ae3bc7bdfb657c232229229706854a56effca80b a26c845a766b45ceabd87c17c0801d191650f0d4 --- record/record.go | 50 +++++++++++++++++++------------------------ record/record_test.go | 15 ++++--------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/record/record.go b/record/record.go index df61c1e2..21b4b69f 100644 --- a/record/record.go +++ b/record/record.go @@ -1,8 +1,17 @@ package record -import "reflect" +import ( + "errors" + "reflect" +) -var payloadTypeRegistry = make(map[string]reflect.Type) +var ( + // ErrPayloadTypeNotRegistered is returned from ConsumeEnvelope when the Envelope's + // PayloadType does not match any registered Record types. + ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") + + payloadTypeRegistry = make(map[string]reflect.Type) +) // Record represents a data type that can be used as the payload of an Envelope. // The Record interface defines the methods used to marshal and unmarshal a Record @@ -23,32 +32,14 @@ type Record interface { UnmarshalRecord([]byte) error } -// DefaultRecord contains the payload of an Envelope whose PayloadType field -// does not match any registered Record type. The Contents field contains -// the unprocessed Envelope payload. -type DefaultRecord struct { - Contents []byte -} - -func (r *DefaultRecord) MarshalRecord() ([]byte, error) { - return r.Contents, nil -} - -func (r *DefaultRecord) UnmarshalRecord(data []byte) error { - r.Contents = data - return nil -} - // RegisterPayloadType associates a binary payload type identifier with a concrete // Record type. This is used to automatically unmarshal Record payloads from Envelopes // when using ConsumeEnvelope, and to automatically marshal Records and determine the // correct PayloadType when calling MakeEnvelopeWithRecord. // -// To register a Record type, provide the payload type identifier and an -// empty instance of the Record type. -// -// Registration should be done in the init function of the package where the -// Record type is defined: +// Callers must provide an instance of the record type to be registered, which must be +// a pointer type. Registration should be done in the init function of the package +// where the Record type is defined: // // package hello_record // import record "github.com/libp2p/go-libp2p-core/record" @@ -66,23 +57,26 @@ func RegisterPayloadType(payloadType []byte, prototype Record) { } func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, error) { - rec := blankRecordForPayloadType(payloadType) - err := rec.UnmarshalRecord(payloadBytes) + rec, err := blankRecordForPayloadType(payloadType) + if err != nil { + return nil, err + } + err = rec.UnmarshalRecord(payloadBytes) if err != nil { return nil, err } return rec, nil } -func blankRecordForPayloadType(payloadType []byte) Record { +func blankRecordForPayloadType(payloadType []byte) (Record, error) { valueType, ok := payloadTypeRegistry[string(payloadType)] if !ok { - return &DefaultRecord{} + return nil, ErrPayloadTypeNotRegistered } val := reflect.New(valueType) asRecord := val.Interface().(Record) - return asRecord + return asRecord, nil } func getValueType(i interface{}) reflect.Type { diff --git a/record/record_test.go b/record/record_test.go index 77ea02e6..262992c3 100644 --- a/record/record_test.go +++ b/record/record_test.go @@ -21,17 +21,10 @@ func (p *testPayload) UnmarshalRecord(bytes []byte) error { } func TestUnmarshalPayload(t *testing.T) { - t.Run("returns DefaultRecord if payload type is unregistered", func(t *testing.T) { - rec, err := unmarshalRecordPayload([]byte("unknown type"), []byte("hello world")) - if err != nil { - t.Error(err) - } - defaultRec, ok := rec.(*DefaultRecord) - if !ok { - t.Error("expected unregistered PayloadType to be unmarshalled as DefaultRecord") - } - if !bytes.Equal(defaultRec.Contents, []byte("hello world")) { - t.Error("unexpected alteration of record") + t.Run("fails if payload type is unregistered", func(t *testing.T) { + _, err := unmarshalRecordPayload([]byte("unknown type"), []byte{}) + if err != ErrPayloadTypeNotRegistered { + t.Error("Expected error when unmarshalling payload with unregistered payload type") } }) From b203ce3a5001bb1797126c9f5fccd9c838ad174f Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 20 Jan 2020 12:21:06 -0500 Subject: [PATCH 57/69] doc comments --- record/envelope.go | 52 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/record/envelope.go b/record/envelope.go index c1a4399e..0703c864 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -93,10 +93,35 @@ func MakeEnvelopeWithRecord(privateKey crypto.PrivKey, domain string, payloadTyp return MakeEnvelope(privateKey, domain, payloadType, payloadBytes) } -// ConsumeEnvelope unmarshals a serialized Envelope, and validates its +// ConsumeEnvelope unmarshals a serialized Envelope and validates its // signature using the provided 'domain' string. If validation fails, an error // is returned, along with the unmarshalled envelope so it can be inspected. -// TODO(yusef): improve this doc comment before merge +// +// On success, ConsumeEnvelope returns the Envelope itself, as well as the inner payload, +// unmarshalled into a concrete Record type. The actual type of the returned Record depends +// on what has been registered for the Envelope's PayloadType (see RegisterPayloadType for details). +// +// You can type assert on the returned Record to convert it to an instance of the concrete +// Record type: +// +// envelope, rec, err := ConsumeEnvelope(envelopeBytes, peer.PeerRecordEnvelopeDomain) +// if err != nil { +// handleError(envelope, err) // envelope may be non-nil, even if errors occur! +// return +// } +// peerRec, ok := rec.(*peer.PeerRecord) +// if ok { +// doSomethingWithPeerRecord(peerRec) +// } +// +// Important: you MUST check the error value before using the returned Envelope. In some error +// cases, including when the envelope signature is invalid, both the Envelope and an error will +// be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result, +// you must not assume that any non-nil Envelope returned from this function is valid. +// +// If the Envelope signature is valid, but no Record type is registered for the Envelope's +// PayloadType, ErrPayloadTypeNotRegistered will be returned, along with the Envelope and +// a nil Record. func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record, err error) { e, err := UnmarshalEnvelope(data) if err != nil { @@ -115,7 +140,27 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record return e, rec, nil } -// TODO(yusef): doc comment before merge +// ConsumeTypedEnvelope unmarshals a serialized Envelope and validates its +// signature using the provided 'domain' string. If validation fails, an error +// is returned, along with the unmarshalled envelope so it can be inspected. +// +// Unlike ConsumeEnvelope, ConsumeTypedEnvelope does not try to automatically determine +// the type of Record to unmarshal the Envelope's payload into. Instead, the caller provides +// a destination Record instance, which will unmarshal the Envelope payload. It is the caller's +// responsibility to determine whether the given Record type is able to unmarshal the payload +// correctly. +// +// rec := &MyRecordType{} +// envelope, err := ConsumeTypedEnvelope(envelopeBytes, MyRecordEnvelopeDomain, rec) +// if err != nil { +// handleError(envelope, err) +// } +// doSomethingWithRecord(rec) +// +// Important: you MUST check the error value before using the returned Envelope. In some error +// cases, including when the envelope signature is invalid, both the Envelope and an error will +// be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result, +// you must not assume that any non-nil Envelope returned from this function is valid. func ConsumeTypedEnvelope(data []byte, domain string, destRecord Record) (envelope *Envelope, err error) { e, err := UnmarshalEnvelope(data) if err != nil { @@ -131,6 +176,7 @@ func ConsumeTypedEnvelope(data []byte, domain string, destRecord Record) (envelo if err != nil { return e, fmt.Errorf("failed to unmarshal envelope payload: %w", err) } + e.cached = destRecord return e, nil } From 25ff0748d240d00c1c0e4c21a32af556f82d232c Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 20 Jan 2020 12:41:40 -0500 Subject: [PATCH 58/69] move Seq field back to PeerRecord --- peer/pb/peer_record.pb.go | 55 ++++++++++++++++++++++++++++++++------- peer/pb/peer_record.proto | 3 +++ peer/record.go | 46 +++++++++++++++++++++++++++++++- peer/record_test.go | 2 +- record/envelope.go | 25 ++++-------------- record/envelope_test.go | 36 +++---------------------- record/pb/envelope.pb.go | 48 +++++----------------------------- record/pb/envelope.proto | 1 - record/record_test.go | 5 +--- 9 files changed, 110 insertions(+), 111 deletions(-) diff --git a/peer/pb/peer_record.pb.go b/peer/pb/peer_record.pb.go index 27832198..9e84ad16 100644 --- a/peer/pb/peer_record.pb.go +++ b/peer/pb/peer_record.pb.go @@ -33,6 +33,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type PeerRecord struct { // peerId contains a libp2p peer id in its binary representation. PeerId []byte `protobuf:"bytes,1,opt,name=peerId,proto3" json:"peerId,omitempty"` + // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. + Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` // addresses is a list of public listen addresses for the peer. Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` } @@ -77,6 +79,13 @@ func (m *PeerRecord) GetPeerId() []byte { return nil } +func (m *PeerRecord) GetSeq() uint64 { + if m != nil { + return m.Seq + } + return 0 +} + func (m *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo { if m != nil { return m.Addresses @@ -138,18 +147,19 @@ func init() { func init() { proto.RegisterFile("peer_record.proto", fileDescriptor_dc0d8059ab0ad14d) } var fileDescriptor_dc0d8059ab0ad14d = []byte{ - // 170 bytes of a gzipped FileDescriptorProto + // 186 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x48, 0x4d, 0x2d, 0x8a, 0x2f, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, - 0x09, 0xe9, 0x15, 0x24, 0x29, 0x4d, 0x60, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, + 0x09, 0xe9, 0x15, 0x24, 0x29, 0x2d, 0x62, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, 0x0a, 0x89, 0x71, 0xb1, 0x81, 0x64, 0x3c, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xa0, - 0x3c, 0x21, 0x5b, 0x2e, 0xce, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0xe2, 0xd4, 0x62, 0x09, 0x66, - 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x79, 0x3d, 0xa8, 0x19, 0x7a, 0x08, 0xfd, 0x7a, 0x8e, 0x10, 0x45, - 0x9e, 0x79, 0x69, 0xf9, 0x41, 0x08, 0x1d, 0x52, 0xda, 0x5c, 0xdc, 0x48, 0x32, 0x42, 0x32, 0x5c, - 0x9c, 0xb9, 0xa5, 0x39, 0x25, 0x99, 0x20, 0x05, 0x50, 0x8b, 0x10, 0x02, 0x4e, 0x12, 0x27, 0x1e, - 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, - 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x90, 0xc4, 0x06, 0x76, 0xbc, 0x31, 0x20, 0x00, 0x00, - 0xff, 0xff, 0x2a, 0x8e, 0x23, 0x44, 0xd1, 0x00, 0x00, 0x00, + 0x3c, 0x21, 0x01, 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x10, + 0x53, 0xc8, 0x96, 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, 0x58, 0x82, 0x59, + 0x81, 0x59, 0x83, 0xdb, 0x48, 0x5e, 0x0f, 0x6a, 0xaa, 0x1e, 0xc2, 0x44, 0x3d, 0x47, 0x88, 0x22, + 0xcf, 0xbc, 0xb4, 0xfc, 0x20, 0x84, 0x0e, 0x29, 0x6d, 0x2e, 0x6e, 0x24, 0x19, 0x21, 0x19, 0x2e, + 0xce, 0xdc, 0xd2, 0x9c, 0x92, 0x4c, 0x90, 0x02, 0xa8, 0xd5, 0x08, 0x01, 0x27, 0x89, 0x13, 0x8f, + 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, + 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0x7b, 0xc7, 0x18, 0x10, 0x00, 0x00, + 0xff, 0xff, 0x85, 0x84, 0x12, 0xd0, 0xe3, 0x00, 0x00, 0x00, } func (m *PeerRecord) Marshal() (dAtA []byte, err error) { @@ -186,6 +196,11 @@ func (m *PeerRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } + if m.Seq != 0 { + i = encodeVarintPeerRecord(dAtA, i, uint64(m.Seq)) + i-- + dAtA[i] = 0x10 + } if len(m.PeerId) > 0 { i -= len(m.PeerId) copy(dAtA[i:], m.PeerId) @@ -247,6 +262,9 @@ func (m *PeerRecord) Size() (n int) { if l > 0 { n += 1 + l + sovPeerRecord(uint64(l)) } + if m.Seq != 0 { + n += 1 + sovPeerRecord(uint64(m.Seq)) + } if len(m.Addresses) > 0 { for _, e := range m.Addresses { l = e.Size() @@ -338,6 +356,25 @@ func (m *PeerRecord) Unmarshal(dAtA []byte) error { m.PeerId = []byte{} } iNdEx = postIndex + 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 ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Seq |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) diff --git a/peer/pb/peer_record.proto b/peer/pb/peer_record.proto index e3b36a95..f85eac49 100644 --- a/peer/pb/peer_record.proto +++ b/peer/pb/peer_record.proto @@ -20,6 +20,9 @@ message PeerRecord { // peerId contains a libp2p peer id in its binary representation. bytes peerId = 1; + // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. + uint64 seq = 2; + // addresses is a list of public listen addresses for the peer. repeated AddressInfo addresses = 3; } diff --git a/peer/record.go b/peer/record.go index c5974b4b..32b7c613 100644 --- a/peer/record.go +++ b/peer/record.go @@ -3,6 +3,7 @@ package peer import ( "errors" "fmt" + "time" "github.com/gogo/protobuf/proto" "github.com/libp2p/go-libp2p-core/crypto" @@ -33,6 +34,23 @@ var ErrPeerIdMismatch = errors.New("signing key does not match record.PeerID") // Currently, a PeerRecord contains the public listen addresses for a peer, but this // is expected to expand to include other information in the future. // +// PeerRecords are ordered in time by their Seq field. Newer PeerRecords must have +// greater Seq values than older records. The NewPeerRecord function will create +// a PeerRecord with a timestamp-based Seq value. The other PeerRecord fields should +// be set by the caller: +// +// rec := peer.NewPeerRecord() +// rec.PeerID = aPeerID +// rec.Addrs = someAddrs +// +// Alternatively, you can construct a PeerRecord struct directly and use the TimestampSeq +// helper to set the Seq field: +// +// rec := peer.PeerRecord{PeerID: aPeerID, Addrs: someAddrs, Seq: peer.TimestampSeq()} +// +// Failing to set the Seq field will not result in an error, however, a PeerRecord with a +// Seq value of zero may be ignored or rejected by other peers. +// // PeerRecords are intended to be shared with other peers inside a signed // routing.Envelope, and PeerRecord implements the routing.Record interface // to facilitate this. @@ -68,11 +86,32 @@ type PeerRecord struct { // Addrs contains the public addresses of the peer this record pertains to. Addrs []ma.Multiaddr + + // Seq is a monotonically-increasing sequence counter that's used to order + // PeerRecords in time. The interval between Seq values is unspecified, + // but newer PeerRecords MUST have a greater Seq value than older records + // for the same peer. + Seq uint64 +} + +// NewPeerRecord returns a PeerRecord with a timestamp-based sequence number. +// The returned record is otherwise empty and should be populated by the caller. +func NewPeerRecord() *PeerRecord { + return &PeerRecord{Seq: TimestampSeq()} } // PeerRecordFromAddrInfo creates a PeerRecord from an AddrInfo struct. +// The returned record will have a timestamp-based sequence number. func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord { - return &PeerRecord{PeerID: info.ID, Addrs: info.Addrs} + rec := NewPeerRecord() + rec.PeerID = info.ID + rec.Addrs = info.Addrs + return rec +} + +// TimestampSeq is a helper to generate a timestamp-based sequence number for a PeerRecord. +func TimestampSeq() uint64 { + return uint64(time.Now().UnixNano()) } // UnmarshalRecord parses a PeerRecord from a byte slice. @@ -96,6 +135,7 @@ func (r *PeerRecord) UnmarshalRecord(bytes []byte) error { } r.PeerID = id r.Addrs = addrsFromProtobuf(msg.Addresses) + r.Seq = msg.Seq return nil } @@ -110,6 +150,7 @@ func (r *PeerRecord) MarshalRecord() ([]byte, error) { msg := pb.PeerRecord{ PeerId: idBytes, Addresses: addrsToProtobuf(r.Addrs), + Seq: r.Seq, } return proto.Marshal(&msg) } @@ -145,6 +186,9 @@ func (r *PeerRecord) Equal(other *PeerRecord) bool { if r.PeerID != other.PeerID { return false } + if r.Seq != other.Seq { + return false + } if len(r.Addrs) != len(other.Addrs) { return false } diff --git a/peer/record_test.go b/peer/record_test.go index b0a0c677..bab7743a 100644 --- a/peer/record_test.go +++ b/peer/record_test.go @@ -16,7 +16,7 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) { id, err := IDFromPrivateKey(priv) test.AssertNilError(t, err) - rec := &PeerRecord{PeerID: id, Addrs: addrs} + rec := &PeerRecord{PeerID: id, Addrs: addrs, Seq: TimestampSeq()} envelope, err := rec.Sign(priv) test.AssertNilError(t, err) diff --git a/record/envelope.go b/record/envelope.go index 0703c864..686bfc82 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "sync" - "time" pool "github.com/libp2p/go-buffer-pool" "github.com/libp2p/go-libp2p-core/crypto" @@ -29,9 +28,6 @@ type Envelope struct { // TODO(yusef): enforce multicodec prefix PayloadType []byte - // A monotonically-increasing sequence counter for ordering SignedEnvelopes in time. - Seq uint64 - // The envelope payload. RawPayload []byte @@ -63,8 +59,7 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, return nil, ErrEmptyPayloadType } - seq := statelessSeqNo() - unsigned, err := makeUnsigned(domain, payloadType, payload, seq) + unsigned, err := makeUnsigned(domain, payloadType, payload) if err != nil { return nil, err } @@ -79,7 +74,6 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, PublicKey: privateKey.GetPublic(), PayloadType: payloadType, RawPayload: payload, - Seq: seq, signature: sig, }, nil } @@ -197,7 +191,6 @@ func UnmarshalEnvelope(data []byte) (*Envelope, error) { PublicKey: key, PayloadType: e.PayloadType, RawPayload: e.Payload, - Seq: e.Seq, signature: e.Signature, }, nil } @@ -214,7 +207,6 @@ func (e *Envelope) Marshal() ([]byte, error) { PublicKey: key, PayloadType: e.PayloadType, Payload: e.RawPayload, - Seq: e.Seq, Signature: e.signature, } return proto.Marshal(&msg) @@ -227,8 +219,7 @@ func (e *Envelope) Equal(other *Envelope) bool { if other == nil { return e == nil } - return e.Seq == other.Seq && - e.PublicKey.Equals(other.PublicKey) && + return e.PublicKey.Equals(other.PublicKey) && bytes.Compare(e.PayloadType, other.PayloadType) == 0 && bytes.Compare(e.signature, other.signature) == 0 && bytes.Compare(e.RawPayload, other.RawPayload) == 0 @@ -263,7 +254,7 @@ func (e *Envelope) TypedRecord(dest Record) error { // validate returns nil if the envelope signature is valid for the given 'domain', // or an error if signature validation fails. func (e *Envelope) validate(domain string) error { - unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload, e.Seq) + unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload) if err != nil { return err } @@ -282,10 +273,9 @@ func (e *Envelope) validate(domain string) error { // makeUnsigned is a helper function that prepares a buffer to sign or verify. // It returns a byte slice from a pool. The caller MUST return this slice to the // pool. -func makeUnsigned(domain string, payloadType []byte, payload []byte, seq uint64) ([]byte, error) { +func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, error) { var ( - seqBytes = varint.ToUvarint(seq) - fields = [][]byte{[]byte(domain), payloadType, seqBytes, payload} + fields = [][]byte{[]byte(domain), payloadType, payload} // fields are prefixed with their length as an unsigned varint. we // compute the lengths before allocating the sig buffer so we know how @@ -310,8 +300,3 @@ func makeUnsigned(domain string, payloadType []byte, payload []byte, seq uint64) return b[:s], nil } - -// statelessSeqNo is a helper to generate a timestamp-based sequence number. -func statelessSeqNo() uint64 { - return uint64(time.Now().UnixNano()) -} diff --git a/record/envelope_test.go b/record/envelope_test.go index 640bcab6..ac14de43 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -125,9 +125,7 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { test.AssertNilError(t, err) - RegisterPayloadType(payloadType, &simpleRecord{}) - - envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, payloadType, rec) test.AssertNilError(t, err) serialized, err := envelope.Marshal() @@ -147,9 +145,7 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { test.AssertNilError(t, err) - RegisterPayloadType(payloadType, &simpleRecord{}) - - envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, payloadType, rec) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { @@ -171,9 +167,7 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { test.AssertNilError(t, err) - RegisterPayloadType(payloadType, &simpleRecord{}) - - envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) + envelope, err := MakeEnvelopeWithRecord(priv, domain, payloadType, rec) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { @@ -185,30 +179,6 @@ func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { test.ExpectError(t, err, "should not be able to open envelope with modified payload") } -func TestEnvelopeValidateFailsIfSeqIsAltered(t *testing.T) { - var ( - rec = &simpleRecord{"hello world!"} - domain = "libp2p-testing" - payloadType = []byte("/libp2p/testdata") - priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) - ) - - test.AssertNilError(t, err) - - RegisterPayloadType(payloadType, &simpleRecord{}) - - envelope, err := MakeEnvelopeWithRecord(priv, domain, rec) - test.AssertNilError(t, err) - - serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { - msg.Seq = envelope.Seq + 1 - }) - - // try to open our modified envelope - _, _, err = ConsumeEnvelope(serialized, domain) - test.ExpectError(t, err, "should not be able to open envelope with modified seq field") -} - // Since we're outside of the crypto package (to avoid import cycles with test package), // we can't alter the fields in a Envelope directly. This helper marshals // the envelope to a protobuf and calls the alterMsg function, which should diff --git a/record/pb/envelope.pb.go b/record/pb/envelope.pb.go index 8c7571c9..6840ec51 100644 --- a/record/pb/envelope.pb.go +++ b/record/pb/envelope.pb.go @@ -28,7 +28,6 @@ type Envelope struct { PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` - Seq uint64 `protobuf:"varint,4,opt,name=seq,proto3" json:"seq,omitempty"` Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` } @@ -86,13 +85,6 @@ func (m *Envelope) GetPayload() []byte { return nil } -func (m *Envelope) GetSeq() uint64 { - if m != nil { - return m.Seq - } - return 0 -} - func (m *Envelope) GetSignature() []byte { if m != nil { return m.Signature @@ -107,20 +99,19 @@ func init() { func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } var fileDescriptor_ee266e8c558e9dc5 = []byte{ - // 210 bytes of a gzipped FileDescriptorProto + // 194 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2c, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x48, 0x92, 0x12, 0x4b, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x48, - 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x56, 0x31, 0x72, 0x71, 0xb8, 0x42, 0x75, 0x09, 0x19, 0x71, + 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x66, 0x30, 0x72, 0x71, 0xb8, 0x42, 0x75, 0x09, 0x19, 0x71, 0x71, 0x16, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x89, 0xe8, 0xc1, 0x94, 0x27, 0xe9, 0x05, 0xc0, 0xe4, 0x82, 0x10, 0xca, 0x84, 0x14, 0xb8, 0xb8, 0x0b, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x42, 0x2a, 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18, 0x35, 0x78, 0x82, 0x90, 0x85, 0x84, 0x24, 0xb8, 0xd8, 0xa1, 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, - 0x2b, 0x24, 0xc0, 0xc5, 0x5c, 0x9c, 0x5a, 0x28, 0xc1, 0xa2, 0xc0, 0xa8, 0xc1, 0x12, 0x04, 0x62, - 0x0a, 0xc9, 0x70, 0x71, 0x16, 0x67, 0xa6, 0xe7, 0x25, 0x96, 0x94, 0x16, 0xa5, 0x4a, 0xb0, 0x82, - 0x55, 0x23, 0x04, 0x9c, 0x24, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, - 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x89, - 0x0d, 0xec, 0x1b, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xa1, 0x77, 0xca, 0x02, 0x01, + 0x2b, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97, 0x58, 0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x0a, + 0x96, 0x43, 0x08, 0x38, 0x49, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, + 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x12, + 0x1b, 0xd8, 0xed, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0xe9, 0x3f, 0x76, 0xf0, 0x00, 0x00, 0x00, } @@ -151,11 +142,6 @@ func (m *Envelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x2a } - if m.Seq != 0 { - i = encodeVarintEnvelope(dAtA, i, uint64(m.Seq)) - i-- - dAtA[i] = 0x20 - } if len(m.Payload) > 0 { i -= len(m.Payload) copy(dAtA[i:], m.Payload) @@ -214,9 +200,6 @@ func (m *Envelope) Size() (n int) { if l > 0 { n += 1 + l + sovEnvelope(uint64(l)) } - if m.Seq != 0 { - n += 1 + sovEnvelope(uint64(m.Seq)) - } l = len(m.Signature) if l > 0 { n += 1 + l + sovEnvelope(uint64(l)) @@ -363,25 +346,6 @@ func (m *Envelope) Unmarshal(dAtA []byte) error { m.Payload = []byte{} } iNdEx = postIndex - case 4: - 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 ErrIntOverflowEnvelope - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Seq |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) diff --git a/record/pb/envelope.proto b/record/pb/envelope.proto index 94675124..ab20a35b 100644 --- a/record/pb/envelope.proto +++ b/record/pb/envelope.proto @@ -9,6 +9,5 @@ message Envelope { crypto.pb.PublicKey publicKey = 1; bytes payloadType = 2; bytes payload = 3; - uint64 seq = 4; bytes signature = 5; } diff --git a/record/record_test.go b/record/record_test.go index 262992c3..f6a33919 100644 --- a/record/record_test.go +++ b/record/record_test.go @@ -1,9 +1,6 @@ package record -import ( - "bytes" - "testing" -) +import "testing" var testPayloadType = []byte("/libp2p/test/record/payload-type") From 5a523a102629fc6915c2eb0d360c42fdb0f143a2 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 21 Jan 2020 10:24:15 -0500 Subject: [PATCH 59/69] make diffs optional in EvtLocalAddressesUpdated --- event/addrs.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/event/addrs.go b/event/addrs.go index e68faf89..fd31a231 100644 --- a/event/addrs.go +++ b/event/addrs.go @@ -5,16 +5,71 @@ import ( ma "github.com/multiformats/go-multiaddr" ) +// AddrAction represents an action taken on one of a Host's listen addresses. +// It is used to add context to address change events in EvtLocalAddressesUpdated. +type AddrAction int + +const ( + // Unknown means that the event producer was unable to determine why the address + // is in the current state. + Unknown AddrAction = iota + + // Added means that the address is new and was not present prior to the event. + Added + + // Maintained means that the address was not altered between the current and + // previous states. + Maintained + + // Removed means that the address was removed from the Host. + Removed +) + +// UpdatedAddress is used in the EvtLocalAddressesUpdated event to convey +// address change information. +type UpdatedAddress struct { + // Address contains the address that was updated. + Address ma.Multiaddr + + // Action indicates what action was taken on the address during the + // event. May be Unknown if the event producer cannot produce diffs. + Action AddrAction +} + // EvtLocalAddressesUpdated should be emitted when the set of listen addresses for // the local host changes. This may happen for a number of reasons. For example, // we may have opened a new relay connection, established a new NAT mapping via // UPnP, or been informed of our observed address by another peer. +// +// EvtLocalAddressesUpdated contains a snapshot of the current listen addresses, +// and may also contain a diff between the current state and the previous state. +// If the event producer is capable of creating a diff, the Diffs field will be +// true, and event consumers can inspect the Action field of each UpdatedAddress +// to see how each address was modified. +// +// For example, the Action will tell you whether an address in +// the Current list was Added by the event producer, or was Maintained without +// changes. Addresses that were removed from the Host will have the AddrAction +// of Removed, and will be in the Removed list. +// +// If the event producer is not capable or producing diffs, the Diffs field will +// be false, the Removed list will always be empty, and the Action for each +// UpdatedAddress in the Current list will be Unknown. type EvtLocalAddressesUpdated struct { - // Added enumerates the listen addresses that were added for the local peer. - Added []ma.Multiaddr - // Removed enumerates listen addresses that were removed from the local peer. - Removed []ma.Multiaddr + // Diffs indicates whether this event contains a diff of the Host's previous + // address set. + Diffs bool + + // Current contains all current listen addresses for the Host. + // If Diffs == true, the Action field of each UpdatedAddress will tell + // you whether an address was Added, or was Maintained from the previous + // state. + Current []UpdatedAddress + + // Removed contains addresses that were removed from the Host. + // This field is only set when Diffs == true. + Removed []UpdatedAddress } // EvtLocalPeerRoutingStateUpdated should be emitted when a new signed PeerRecord From 33890dd418451a915932c54cb7236e4113516ede Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Wed, 22 Jan 2020 14:03:21 -0500 Subject: [PATCH 60/69] more envelope tests --- record/envelope_test.go | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/record/envelope_test.go b/record/envelope_test.go index ac14de43..578320bf 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -2,6 +2,7 @@ package record_test import ( "bytes" + "errors" "testing" crypto "github.com/libp2p/go-libp2p-core/crypto" @@ -115,6 +116,90 @@ func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { test.ExpectError(t, err, "making an envelope with an empty domain should fail") } +func TestMakeEnvelopeFailsWithEmptyPayloadType(t *testing.T) { + var ( + payload = []byte("happy hacking") + payloadType = []byte{} + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) + ) + + if err != nil { + t.Fatal(err) + } + + _, err = MakeEnvelope(priv, "test-domain", payloadType, payload) + test.ExpectError(t, err, "making an envelope with an empty payloadType should fail") +} + +type failingRecord struct{} + +func (r failingRecord) MarshalRecord() ([]byte, error) { + return nil, errors.New("marshal failed") +} +func (r failingRecord) UnmarshalRecord(data []byte) error { + return errors.New("unmarshal failed") +} + +func TestMakeEnvelopeWithRecordFailsIfRecordMarshalFails(t *testing.T) { + var ( + payloadType = []byte("/libp2p/test/failing-record") + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) + ) + + if err != nil { + t.Fatal(err) + } + rec := failingRecord{} + _, err = MakeEnvelopeWithRecord(priv, "test-domain", payloadType, rec) + test.ExpectError(t, err, "MakeEnvelopeWithRecord should fail if Record fails to marshal") +} + +func TestConsumeEnvelopeFailsIfEnvelopeUnmarshalFails(t *testing.T) { + _, _, err := ConsumeEnvelope([]byte("not an Envelope protobuf"), "doesn't-matter") + test.ExpectError(t, err, "ConsumeEnvelope should fail if Envelope fails to unmarshal") +} + +func TestConsumeEnvelopeFailsIfRecordUnmarshalFails(t *testing.T) { + var ( + payloadType = []byte("/libp2p/test/failing-record") + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) + ) + + if err != nil { + t.Fatal(err) + } + + RegisterPayloadType(payloadType, failingRecord{}) + env, err := MakeEnvelope(priv, "test-domain", payloadType, []byte("doesn't matter")) + test.AssertNilError(t, err) + envBytes, err := env.Marshal() + test.AssertNilError(t, err) + + _, _, err = ConsumeEnvelope(envBytes, "test-domain") + test.ExpectError(t, err, "ConsumeEnvelope should fail if Record fails to unmarshal") +} + +func TestConsumeTypedEnvelopeFailsIfRecordUnmarshalFails(t *testing.T) { + var ( + payloadType = []byte("/libp2p/test/failing-record") + priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) + ) + + if err != nil { + t.Fatal(err) + } + + RegisterPayloadType(payloadType, failingRecord{}) + env, err := MakeEnvelope(priv, "test-domain", payloadType, []byte("doesn't matter")) + test.AssertNilError(t, err) + envBytes, err := env.Marshal() + test.AssertNilError(t, err) + + rec := failingRecord{} + _, err = ConsumeTypedEnvelope(envBytes, "test-domain", rec) + test.ExpectError(t, err, "ConsumeTypedEnvelope should fail if Record fails to unmarshal") +} + func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { var ( rec = &simpleRecord{"hello world"} From 3e293ba6286db1110828b2e6eaa9173205ef683b Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 3 Feb 2020 16:48:22 -0500 Subject: [PATCH 61/69] replace MakeEnvelope with record.Seal also: - add Domain and Codec fields to Record interface --- peer/record.go | 49 ++++++---------- peer/record_test.go | 31 +++++----- record/envelope.go | 40 ++++++------- record/envelope_test.go | 122 ++++++++++++++++++++++++---------------- record/record.go | 30 +++++++--- record/record_test.go | 10 +++- 6 files changed, 154 insertions(+), 128 deletions(-) diff --git a/peer/record.go b/peer/record.go index 32b7c613..188554f2 100644 --- a/peer/record.go +++ b/peer/record.go @@ -1,31 +1,26 @@ package peer import ( - "errors" "fmt" "time" "github.com/gogo/protobuf/proto" - "github.com/libp2p/go-libp2p-core/crypto" pb "github.com/libp2p/go-libp2p-core/peer/pb" "github.com/libp2p/go-libp2p-core/record" ma "github.com/multiformats/go-multiaddr" ) func init() { - record.RegisterPayloadType(PeerRecordEnvelopePayloadType, &PeerRecord{}) + record.RegisterType(&PeerRecord{}) } // The domain string used for peer records contained in a Envelope. const PeerRecordEnvelopeDomain = "libp2p-peer-record" // The type hint used to identify peer records in a Envelope. -// TODO: register multicodec -var PeerRecordEnvelopePayloadType = []byte("/libp2p/peer-record") - -// ErrPeerIdMismatch is returned when attempting to sign a PeerRecord using a key that -// does not match the PeerID contained in the record. -var ErrPeerIdMismatch = errors.New("signing key does not match record.PeerID") +// Defined in https://github.com/multiformats/multicodec/blob/master/table.csv +// with name "libp2p-peer-record" +var PeerRecordEnvelopePayloadType = []byte{0x03, 0x01} // PeerRecord contains information that is broadly useful to share with other peers, // either through a direct exchange (as in the libp2p identify protocol), or through @@ -114,6 +109,17 @@ func TimestampSeq() uint64 { return uint64(time.Now().UnixNano()) } +// Domain is used when signing and validating PeerRecords contained in Envelopes. +// It is constant for all PeerRecord instances. +func (r *PeerRecord) Domain() string { + return PeerRecordEnvelopeDomain +} + +// Codec is a binary identifier for the PeerRecord type. It is constant for all PeerRecord instances. +func (r *PeerRecord) Codec() []byte { + return PeerRecordEnvelopePayloadType +} + // UnmarshalRecord parses a PeerRecord from a byte slice. // This method is called automatically when consuming a record.Envelope // whose PayloadType indicates that it contains a PeerRecord. @@ -141,7 +147,7 @@ func (r *PeerRecord) UnmarshalRecord(bytes []byte) error { // MarshalRecord serializes a PeerRecord to a byte slice. // This method is called automatically when constructing a routing.Envelope -// using MakeEnvelopeWithRecord or PeerRecord.Sign. +// using Seal or PeerRecord.Sign. func (r *PeerRecord) MarshalRecord() ([]byte, error) { idBytes, err := r.PeerID.MarshalBinary() if err != nil { @@ -155,29 +161,6 @@ func (r *PeerRecord) MarshalRecord() ([]byte, error) { return proto.Marshal(&msg) } -// Sign wraps the PeerRecord in a routing.Envelope, signed with the given -// private key. The private key must match the PeerID field of the PeerRecord. -func (r *PeerRecord) Sign(privKey crypto.PrivKey) (*record.Envelope, error) { - p, err := IDFromPrivateKey(privKey) - if err != nil { - return nil, err - } - if p != r.PeerID { - return nil, ErrPeerIdMismatch - } - return record.MakeEnvelopeWithRecord(privKey, PeerRecordEnvelopeDomain, PeerRecordEnvelopePayloadType, r) -} - -// MarshalSigned is a convenience method that wraps the PeerRecord in a routing.Envelope, -// and marshals the Envelope to a []byte. -func (r *PeerRecord) MarshalSigned(privKey crypto.PrivKey) ([]byte, error) { - env, err := r.Sign(privKey) - if err != nil { - return nil, err - } - return env.Marshal() -} - // Equal returns true if the other PeerRecord is identical to this one. func (r *PeerRecord) Equal(other *PeerRecord) bool { if other == nil { diff --git a/peer/record_test.go b/peer/record_test.go index bab7743a..adbe03ae 100644 --- a/peer/record_test.go +++ b/peer/record_test.go @@ -1,13 +1,27 @@ package peer_test import ( + "bytes" + "testing" + "github.com/libp2p/go-libp2p-core/crypto" . "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/record" "github.com/libp2p/go-libp2p-core/test" - "testing" ) +func TestPeerRecordConstants(t *testing.T) { + msgf := "Changing the %s may cause peer records to be incompatible with older versions. " + + "If you've already thought that through, please update this test so that it passes with the new values." + rec := PeerRecord{} + if rec.Domain() != "libp2p-peer-record" { + t.Errorf(msgf, "signing domain") + } + if !bytes.Equal(rec.Codec(), []byte{0x03, 0x01}) { + t.Errorf(msgf, "codec value") + } +} + func TestSignedPeerRecordFromEnvelope(t *testing.T) { priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256) test.AssertNilError(t, err) @@ -17,13 +31,9 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) { test.AssertNilError(t, err) rec := &PeerRecord{PeerID: id, Addrs: addrs, Seq: TimestampSeq()} - envelope, err := rec.Sign(priv) + envelope, err := record.Seal(rec, priv) test.AssertNilError(t, err) - //t.Run("sanity check, don't push to remote", func(t *testing.T) { - // id.UnmarshalBinary() - //}) - t.Run("is unaltered after round-trip serde", func(t *testing.T) { envBytes, err := envelope.Marshal() test.AssertNilError(t, err) @@ -41,13 +51,4 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) { t.Error("expected signed envelope to be unchanged after round-trip serde") } }) - - t.Run("signing fails if signing key does not match peer id in record", func(t *testing.T) { - id = "some-other-peer-id" - rec := &PeerRecord{PeerID: id, Addrs: addrs} - _, err := rec.Sign(priv) - if err != ErrPeerIdMismatch { - t.Error("expected signing with mismatched private key to fail") - } - }) } diff --git a/record/envelope.go b/record/envelope.go index 686bfc82..e674ec9d 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -44,13 +44,16 @@ var ErrEmptyDomain = errors.New("envelope domain must not be empty") var ErrEmptyPayloadType = errors.New("payloadType must not be empty") var ErrInvalidSignature = errors.New("invalid signature or incorrect domain") -// MakeEnvelope constructs a new Envelope using the given privateKey. -// -// The required 'domain' string contextualizes the envelope for a particular purpose, -// and must be supplied when verifying the signature. -// -// The 'PayloadType' field indicates what kind of data is contained and must be non-empty. -func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, payload []byte) (*Envelope, error) { +// Seal marshals the given Record, places the marshaled bytes inside an Envelope, +// and signs with the given private key. +func Seal(rec Record, privateKey crypto.PrivKey) (*Envelope, error) { + payload, err := rec.MarshalRecord() + if err != nil { + return nil, fmt.Errorf("error marshaling record: %v", err) + } + + domain := rec.Domain() + payloadType := rec.Codec() if domain == "" { return nil, ErrEmptyDomain } @@ -78,22 +81,13 @@ func MakeEnvelope(privateKey crypto.PrivKey, domain string, payloadType []byte, }, nil } -// MakeEnvelopeWithRecord marshals the given Record to bytes, then wraps it in an envelope using MakeEnvelope. -func MakeEnvelopeWithRecord(privateKey crypto.PrivKey, domain string, payloadType []byte, rec Record) (*Envelope, error) { - payloadBytes, err := rec.MarshalRecord() - if err != nil { - return nil, fmt.Errorf("error marshaling record: %v", err) - } - return MakeEnvelope(privateKey, domain, payloadType, payloadBytes) -} - // ConsumeEnvelope unmarshals a serialized Envelope and validates its // signature using the provided 'domain' string. If validation fails, an error // is returned, along with the unmarshalled envelope so it can be inspected. // // On success, ConsumeEnvelope returns the Envelope itself, as well as the inner payload, // unmarshalled into a concrete Record type. The actual type of the returned Record depends -// on what has been registered for the Envelope's PayloadType (see RegisterPayloadType for details). +// on what has been registered for the Envelope's PayloadType (see RegisterType for details). // // You can type assert on the returned Record to convert it to an instance of the concrete // Record type: @@ -135,8 +129,8 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record } // ConsumeTypedEnvelope unmarshals a serialized Envelope and validates its -// signature using the provided 'domain' string. If validation fails, an error -// is returned, along with the unmarshalled envelope so it can be inspected. +// signature. If validation fails, an error is returned, along with the unmarshalled +// envelope so it can be inspected. // // Unlike ConsumeEnvelope, ConsumeTypedEnvelope does not try to automatically determine // the type of Record to unmarshal the Envelope's payload into. Instead, the caller provides @@ -145,7 +139,7 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record // correctly. // // rec := &MyRecordType{} -// envelope, err := ConsumeTypedEnvelope(envelopeBytes, MyRecordEnvelopeDomain, rec) +// envelope, err := ConsumeTypedEnvelope(envelopeBytes, rec) // if err != nil { // handleError(envelope, err) // } @@ -155,13 +149,13 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record // cases, including when the envelope signature is invalid, both the Envelope and an error will // be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result, // you must not assume that any non-nil Envelope returned from this function is valid. -func ConsumeTypedEnvelope(data []byte, domain string, destRecord Record) (envelope *Envelope, err error) { +func ConsumeTypedEnvelope(data []byte, destRecord Record) (envelope *Envelope, err error) { e, err := UnmarshalEnvelope(data) if err != nil { return nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) } - err = e.validate(domain) + err = e.validate(destRecord.Domain()) if err != nil { return e, fmt.Errorf("failed to validate envelope: %w", err) } @@ -227,7 +221,7 @@ func (e *Envelope) Equal(other *Envelope) bool { // Record returns the Envelope's payload unmarshalled as a Record. // The concrete type of the returned Record depends on which Record -// type was registered for the Envelope's PayloadType - see record.RegisterPayloadType. +// type was registered for the Envelope's PayloadType - see record.RegisterType. // // Once unmarshalled, the Record is cached for future access. func (e *Envelope) Record() (Record, error) { diff --git a/record/envelope_test.go b/record/envelope_test.go index 578320bf..3946a572 100644 --- a/record/envelope_test.go +++ b/record/envelope_test.go @@ -14,7 +14,23 @@ import ( ) type simpleRecord struct { - message string + testDomain *string + testCodec []byte + message string +} + +func (r *simpleRecord) Domain() string { + if r.testDomain != nil { + return *r.testDomain + } + return "libp2p-testing" +} + +func (r *simpleRecord) Codec() []byte { + if r.testCodec != nil { + return r.testCodec + } + return []byte("/libp2p/testdata") } func (r *simpleRecord) MarshalRecord() ([]byte, error) { @@ -29,9 +45,7 @@ func (r *simpleRecord) UnmarshalRecord(buf []byte) error { // Make an envelope, verify & open it, marshal & unmarshal it func TestEnvelopeHappyPath(t *testing.T) { var ( - rec = simpleRecord{"hello world!"} - domain = "libp2p-testing" - payloadType = []byte("/libp2p/testdata") + rec = &simpleRecord{message: "hello world!"} priv, pub, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) @@ -40,22 +54,22 @@ func TestEnvelopeHappyPath(t *testing.T) { payload, err := rec.MarshalRecord() test.AssertNilError(t, err) - envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + envelope, err := Seal(rec, priv) test.AssertNilError(t, err) if !envelope.PublicKey.Equals(pub) { t.Error("envelope has unexpected public key") } - if bytes.Compare(payloadType, envelope.PayloadType) != 0 { - t.Error("PayloadType does not match PayloadType used to construct envelope") + if bytes.Compare(rec.Codec(), envelope.PayloadType) != 0 { + t.Error("PayloadType does not match record Codec") } serialized, err := envelope.Marshal() test.AssertNilError(t, err) - RegisterPayloadType(payloadType, &simpleRecord{}) - deserialized, rec2, err := ConsumeEnvelope(serialized, domain) + RegisterType(&simpleRecord{}) + deserialized, rec2, err := ConsumeEnvelope(serialized, rec.Domain()) test.AssertNilError(t, err) if bytes.Compare(deserialized.RawPayload, payload) != 0 { @@ -77,23 +91,18 @@ func TestEnvelopeHappyPath(t *testing.T) { func TestConsumeTypedEnvelope(t *testing.T) { var ( - rec = simpleRecord{"hello world!"} - domain = "libp2p-testing" - payloadType = []byte("/libp2p/testdata") + rec = simpleRecord{message: "hello world!"} priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) - payload, err := rec.MarshalRecord() - test.AssertNilError(t, err) - - envelope, err := MakeEnvelope(priv, domain, payloadType, payload) + envelope, err := Seal(&rec, priv) test.AssertNilError(t, err) envelopeBytes, err := envelope.Marshal() test.AssertNilError(t, err) rec2 := &simpleRecord{} - _, err = ConsumeTypedEnvelope(envelopeBytes, domain, rec2) + _, err = ConsumeTypedEnvelope(envelopeBytes, rec2) test.AssertNilError(t, err) if rec2.message != "hello world!" { @@ -103,8 +112,8 @@ func TestConsumeTypedEnvelope(t *testing.T) { func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { var ( - payload = []byte("happy hacking") - payloadType = []byte("/libp2p/testdata") + rec = simpleRecord{message: "hello world!"} + domain = "" priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) @@ -112,14 +121,16 @@ func TestMakeEnvelopeFailsWithEmptyDomain(t *testing.T) { t.Fatal(err) } - _, err = MakeEnvelope(priv, "", payloadType, payload) + // override domain with empty string + rec.testDomain = &domain + + _, err = Seal(&rec, priv) test.ExpectError(t, err, "making an envelope with an empty domain should fail") } func TestMakeEnvelopeFailsWithEmptyPayloadType(t *testing.T) { var ( - payload = []byte("happy hacking") - payloadType = []byte{} + rec = simpleRecord{message: "hello world!"} priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) @@ -127,22 +138,41 @@ func TestMakeEnvelopeFailsWithEmptyPayloadType(t *testing.T) { t.Fatal(err) } - _, err = MakeEnvelope(priv, "test-domain", payloadType, payload) + // override payload with empty slice + rec.testCodec = []byte{} + + _, err = Seal(&rec, priv) test.ExpectError(t, err, "making an envelope with an empty payloadType should fail") } -type failingRecord struct{} +type failingRecord struct { + allowMarshal bool + allowUnmarshal bool +} + +func (r failingRecord) Domain() string { + return "testing" +} + +func (r failingRecord) Codec() []byte { + return []byte("doesn't matter") +} func (r failingRecord) MarshalRecord() ([]byte, error) { + if r.allowMarshal { + return []byte{}, nil + } return nil, errors.New("marshal failed") } func (r failingRecord) UnmarshalRecord(data []byte) error { + if r.allowUnmarshal { + return nil + } return errors.New("unmarshal failed") } -func TestMakeEnvelopeWithRecordFailsIfRecordMarshalFails(t *testing.T) { +func TestSealFailsIfRecordMarshalFails(t *testing.T) { var ( - payloadType = []byte("/libp2p/test/failing-record") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) @@ -150,8 +180,8 @@ func TestMakeEnvelopeWithRecordFailsIfRecordMarshalFails(t *testing.T) { t.Fatal(err) } rec := failingRecord{} - _, err = MakeEnvelopeWithRecord(priv, "test-domain", payloadType, rec) - test.ExpectError(t, err, "MakeEnvelopeWithRecord should fail if Record fails to marshal") + _, err = Seal(rec, priv) + test.ExpectError(t, err, "Seal should fail if Record fails to marshal") } func TestConsumeEnvelopeFailsIfEnvelopeUnmarshalFails(t *testing.T) { @@ -161,7 +191,6 @@ func TestConsumeEnvelopeFailsIfEnvelopeUnmarshalFails(t *testing.T) { func TestConsumeEnvelopeFailsIfRecordUnmarshalFails(t *testing.T) { var ( - payloadType = []byte("/libp2p/test/failing-record") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) @@ -169,19 +198,19 @@ func TestConsumeEnvelopeFailsIfRecordUnmarshalFails(t *testing.T) { t.Fatal(err) } - RegisterPayloadType(payloadType, failingRecord{}) - env, err := MakeEnvelope(priv, "test-domain", payloadType, []byte("doesn't matter")) + RegisterType(failingRecord{}) + rec := failingRecord{allowMarshal: true} + env, err := Seal(rec, priv) test.AssertNilError(t, err) envBytes, err := env.Marshal() test.AssertNilError(t, err) - _, _, err = ConsumeEnvelope(envBytes, "test-domain") + _, _, err = ConsumeEnvelope(envBytes, rec.Domain()) test.ExpectError(t, err, "ConsumeEnvelope should fail if Record fails to unmarshal") } func TestConsumeTypedEnvelopeFailsIfRecordUnmarshalFails(t *testing.T) { var ( - payloadType = []byte("/libp2p/test/failing-record") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) @@ -189,28 +218,27 @@ func TestConsumeTypedEnvelopeFailsIfRecordUnmarshalFails(t *testing.T) { t.Fatal(err) } - RegisterPayloadType(payloadType, failingRecord{}) - env, err := MakeEnvelope(priv, "test-domain", payloadType, []byte("doesn't matter")) + RegisterType(failingRecord{}) + rec := failingRecord{allowMarshal: true} + env, err := Seal(rec, priv) test.AssertNilError(t, err) envBytes, err := env.Marshal() test.AssertNilError(t, err) - rec := failingRecord{} - _, err = ConsumeTypedEnvelope(envBytes, "test-domain", rec) + rec2 := failingRecord{} + _, err = ConsumeTypedEnvelope(envBytes, rec2) test.ExpectError(t, err, "ConsumeTypedEnvelope should fail if Record fails to unmarshal") } func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { var ( - rec = &simpleRecord{"hello world"} - domain = "libp2p-testing" - payloadType = []byte("/libp2p/testdata") + rec = &simpleRecord{message: "hello world"} priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) - envelope, err := MakeEnvelopeWithRecord(priv, domain, payloadType, rec) + envelope, err := Seal(rec, priv) test.AssertNilError(t, err) serialized, err := envelope.Marshal() @@ -220,17 +248,16 @@ func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { test.ExpectError(t, err, "should not be able to open envelope with incorrect domain") } -func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { +func TestEnvelopeValidateFailsIfPayloadTypeIsAltered(t *testing.T) { var ( - rec = &simpleRecord{"hello world!"} + rec = &simpleRecord{message: "hello world!"} domain = "libp2p-testing" - payloadType = []byte("/libp2p/testdata") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) - envelope, err := MakeEnvelopeWithRecord(priv, domain, payloadType, rec) + envelope, err := Seal(rec, priv) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { @@ -244,15 +271,14 @@ func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { var ( - rec = &simpleRecord{"hello world!"} + rec = &simpleRecord{message: "hello world!"} domain = "libp2p-testing" - payloadType = []byte("/libp2p/testdata") priv, _, err = test.RandTestKeyPair(crypto.Ed25519, 256) ) test.AssertNilError(t, err) - envelope, err := MakeEnvelopeWithRecord(priv, domain, payloadType, rec) + envelope, err := Seal(rec, priv) test.AssertNilError(t, err) serialized := alterMessageAndMarshal(t, envelope, func(msg *pb.Envelope) { diff --git a/record/record.go b/record/record.go index 21b4b69f..21200578 100644 --- a/record/record.go +++ b/record/record.go @@ -18,7 +18,7 @@ var ( // type to a byte slice. // // Record types may be "registered" as the default for a given Envelope.PayloadType -// using the RegisterPayloadType function. Once a Record type has been registered, +// using the RegisterType function. Once a Record type has been registered, // an instance of that type will be created and used to unmarshal the payload of // any Envelope with the registered PayloadType when the Envelope is opened using // the ConsumeEnvelope function. @@ -27,15 +27,31 @@ var ( // an instance of the Record type that you'd like the Envelope's payload to be // unmarshaled into. type Record interface { + + // Domain is the "signature domain" used when signing and verifying a particular + // Record type. The Domain string should be unique to your Record type, and all + // instances of the Record type must have the same Domain string. + Domain() string + + // Codec is a binary identifier for this type of record, ideally a registered multicodec + // (see https://github.com/multiformats/multicodec). + // When a Record is put into an Envelope (see record.Seal), the Codec value will be used + // as the Envelope's PayloadType. When the Envelope is later unsealed, the PayloadType + // will be used to lookup the correct Record type to unmarshal the Envelope payload into. + Codec() []byte + + // MarshalRecord converts a Record instance to a []byte, so that it can be used as an + // Envelope payload. MarshalRecord() ([]byte, error) + // UnmarshalRecord unmarshals a []byte payload into an instance of a particular Record type. UnmarshalRecord([]byte) error } -// RegisterPayloadType associates a binary payload type identifier with a concrete +// RegisterType associates a binary payload type identifier with a concrete // Record type. This is used to automatically unmarshal Record payloads from Envelopes // when using ConsumeEnvelope, and to automatically marshal Records and determine the -// correct PayloadType when calling MakeEnvelopeWithRecord. +// correct PayloadType when calling Seal. // // Callers must provide an instance of the record type to be registered, which must be // a pointer type. Registration should be done in the init function of the package @@ -44,16 +60,14 @@ type Record interface { // package hello_record // import record "github.com/libp2p/go-libp2p-core/record" // -// var HelloRecordPayloadType = []byte("/libp2p/hello-record") -// // func init() { -// record.RegisterPayloadType(HelloRecordPayloadType, &HelloRecord{}) +// record.RegisterType(&HelloRecord{}) // } // // type HelloRecord struct { } // etc.. // -func RegisterPayloadType(payloadType []byte, prototype Record) { - payloadTypeRegistry[string(payloadType)] = getValueType(prototype) +func RegisterType(prototype Record) { + payloadTypeRegistry[string(prototype.Codec())] = getValueType(prototype) } func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, error) { diff --git a/record/record_test.go b/record/record_test.go index f6a33919..63796402 100644 --- a/record/record_test.go +++ b/record/record_test.go @@ -8,6 +8,14 @@ type testPayload struct { unmarshalPayloadCalled bool } +func (p *testPayload) Domain() string { + return "testing" +} + +func (p *testPayload) Codec() []byte { + return testPayloadType +} + func (p *testPayload) MarshalRecord() ([]byte, error) { return []byte("hello"), nil } @@ -26,7 +34,7 @@ func TestUnmarshalPayload(t *testing.T) { }) t.Run("calls UnmarshalRecord on concrete Record type", func(t *testing.T) { - RegisterPayloadType(testPayloadType, &testPayload{}) + RegisterType(&testPayload{}) payload, err := unmarshalRecordPayload(testPayloadType, []byte{}) if err != nil { From 1a439d73e7b757c1301dc75315a99e4f94b299c9 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 3 Feb 2020 16:50:13 -0500 Subject: [PATCH 62/69] fix import --- host/helpers.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/host/helpers.go b/host/helpers.go index fd77cd1d..a24beb1b 100644 --- a/host/helpers.go +++ b/host/helpers.go @@ -1,8 +1,6 @@ package host -import ( - "github.com/libp2p/go-libp2p-core/peer" -) +import "github.com/libp2p/go-libp2p-core/peer" // InfoFromHost returns a peer.AddrInfo struct with the Host's ID and all of its Addrs. func InfoFromHost(h Host) *peer.AddrInfo { From 04ce1442bf4c2c5421445e910a77a6147ecce7e7 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 3 Feb 2020 16:54:06 -0500 Subject: [PATCH 63/69] add interface check --- peer/record.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/peer/record.go b/peer/record.go index 188554f2..fec13203 100644 --- a/peer/record.go +++ b/peer/record.go @@ -10,6 +10,8 @@ import ( ma "github.com/multiformats/go-multiaddr" ) +var _ record.Record = (*PeerRecord)(nil) + func init() { record.RegisterType(&PeerRecord{}) } From c29b681222c6f82fd774742283a4e684640104d4 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 4 Feb 2020 15:11:46 -0500 Subject: [PATCH 64/69] rename ProcessPeerRecord -> ConsumePeerRecord also, adds bool `accepted` return value --- peerstore/peerstore.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 1087f9f6..178f9492 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -140,12 +140,17 @@ type AddrBook interface { // type-assert on the CertifiedAddrBook interface: // // if cab, ok := aPeerstore.(CertifiedAddrBook); ok { -// cab.ProcessPeerRecord(signedPeerRecord, aTTL) +// cab.ConsumePeerRecord(signedPeerRecord, aTTL) // } // type CertifiedAddrBook interface { - // ProcessPeerRecord adds addresses from a signed peer.PeerRecord (contained in - // a routing.Envelope), which will expire after the given TTL. + // ConsumePeerRecord adds addresses from a signed peer.PeerRecord (contained in + // a record.Envelope), which will expire after the given TTL. + // + // The 'accepted' return value indicates that the record was successfully processed + // and integrated into the CertifiedAddrBook state. If 'accepted' is false but no + // error is returned, it means that the record was ignored, most likely because + // a newer record exists for the same peer. // // Signed records added via this method will be stored without // alteration as long as the address TTLs remain valid. The Envelopes @@ -156,7 +161,8 @@ type CertifiedAddrBook interface { // older ones, iff the new record has a higher sequence number than the // existing record. Attempting to add a peer record with a // sequence number that's <= an existing record for the same peer will not - // result in an error, but the record will be ignored. + // result in an error, but the record will be ignored, and the 'accepted' + // bool return value will be false. // // If the CertifiedAddrBook is also an AddrBook (which is most likely the case), // adding certified addresses for a peer will *replace* any @@ -167,8 +173,8 @@ type CertifiedAddrBook interface { // any non-certified addresses added via AddrBook.AddAddrs or // AddrBook.SetAddrs will be ignored. AddrBook.SetAddrs may still be used // to update the TTL of certified addresses that have previously been - // added via ProcessPeerRecord. - ProcessPeerRecord(s *record.Envelope, ttl time.Duration) error + // added via ConsumePeerRecord. + ConsumePeerRecord(s *record.Envelope, ttl time.Duration) (accepted bool, err error) // GetPeerRecord returns a Envelope containing a PeerRecord for the // given peer id, if one exists. From 97eee5a8dabfb0eae308f31c240b393f89db550b Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 4 Feb 2020 16:15:56 -0500 Subject: [PATCH 65/69] rename event field, add doc comment --- event/addrs.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/event/addrs.go b/event/addrs.go index fd31a231..f260d149 100644 --- a/event/addrs.go +++ b/event/addrs.go @@ -76,5 +76,7 @@ type EvtLocalAddressesUpdated struct { // for the local peer has been produced. This will happen whenever the set of listen // addresses changes. type EvtLocalPeerRecordUpdated struct { - SignedRecord *record.Envelope + // Record contains the updated peer.PeerRecord, wrapped in a record.Envelope and + // signed by the Host's private key. + Record *record.Envelope } From dfb8a63c013f2620720a17c3277b176cabc6bcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 10 Feb 2020 19:43:42 +0000 Subject: [PATCH 66/69] peer record protobuf: fix field casing. --- peer/pb/peer_record.pb.go | 26 +++++++++++++------------- peer/pb/peer_record.proto | 5 +++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/peer/pb/peer_record.pb.go b/peer/pb/peer_record.pb.go index 9e84ad16..dd0755ef 100644 --- a/peer/pb/peer_record.pb.go +++ b/peer/pb/peer_record.pb.go @@ -31,8 +31,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // See https://github.com/libp2p/go-libp2p-core/record/pb/envelope.proto for // the SignedEnvelope definition. type PeerRecord struct { - // peerId contains a libp2p peer id in its binary representation. - PeerId []byte `protobuf:"bytes,1,opt,name=peerId,proto3" json:"peerId,omitempty"` + // peer_id contains a libp2p peer id in its binary representation. + PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` // addresses is a list of public listen addresses for the peer. @@ -147,19 +147,19 @@ func init() { func init() { proto.RegisterFile("peer_record.proto", fileDescriptor_dc0d8059ab0ad14d) } var fileDescriptor_dc0d8059ab0ad14d = []byte{ - // 186 bytes of a gzipped FileDescriptorProto + // 189 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x48, 0x4d, 0x2d, 0x8a, 0x2f, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, - 0x09, 0xe9, 0x15, 0x24, 0x29, 0x2d, 0x62, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, - 0x0a, 0x89, 0x71, 0xb1, 0x81, 0x64, 0x3c, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xa0, - 0x3c, 0x21, 0x01, 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x10, - 0x53, 0xc8, 0x96, 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, 0x58, 0x82, 0x59, - 0x81, 0x59, 0x83, 0xdb, 0x48, 0x5e, 0x0f, 0x6a, 0xaa, 0x1e, 0xc2, 0x44, 0x3d, 0x47, 0x88, 0x22, - 0xcf, 0xbc, 0xb4, 0xfc, 0x20, 0x84, 0x0e, 0x29, 0x6d, 0x2e, 0x6e, 0x24, 0x19, 0x21, 0x19, 0x2e, - 0xce, 0xdc, 0xd2, 0x9c, 0x92, 0x4c, 0x90, 0x02, 0xa8, 0xd5, 0x08, 0x01, 0x27, 0x89, 0x13, 0x8f, - 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, - 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0x7b, 0xc7, 0x18, 0x10, 0x00, 0x00, - 0xff, 0xff, 0x85, 0x84, 0x12, 0xd0, 0xe3, 0x00, 0x00, 0x00, + 0x09, 0xe9, 0x15, 0x24, 0x29, 0x2d, 0x66, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, + 0x0a, 0x89, 0x73, 0x81, 0x65, 0xe2, 0x33, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xd8, + 0x40, 0x5c, 0xcf, 0x14, 0x21, 0x01, 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, + 0x96, 0x20, 0x10, 0x53, 0xc8, 0x96, 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, + 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x5e, 0x0f, 0x6a, 0xac, 0x1e, 0xc2, 0x48, 0x3d, + 0x47, 0x88, 0x22, 0xcf, 0xbc, 0xb4, 0xfc, 0x20, 0x84, 0x0e, 0x29, 0x6d, 0x2e, 0x6e, 0x24, 0x19, + 0x21, 0x19, 0x2e, 0xce, 0xdc, 0xd2, 0x9c, 0x92, 0x4c, 0x90, 0x02, 0xa8, 0xd5, 0x08, 0x01, 0x27, + 0x89, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, + 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xfb, 0xc7, 0x18, + 0x10, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0x56, 0x19, 0xe4, 0x00, 0x00, 0x00, } func (m *PeerRecord) Marshal() (dAtA []byte, err error) { diff --git a/peer/pb/peer_record.proto b/peer/pb/peer_record.proto index f85eac49..fb2835d8 100644 --- a/peer/pb/peer_record.proto +++ b/peer/pb/peer_record.proto @@ -1,4 +1,5 @@ syntax = "proto3"; + package peer.pb; // PeerRecord messages contain information that is useful to share with other peers. @@ -17,8 +18,8 @@ message PeerRecord { bytes multiaddr = 1; } - // peerId contains a libp2p peer id in its binary representation. - bytes peerId = 1; + // peer_id contains a libp2p peer id in its binary representation. + bytes peer_id = 1; // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. uint64 seq = 2; From 4a3c9dd05528872c2931227d3fa0b236c8fba971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 10 Feb 2020 19:44:18 +0000 Subject: [PATCH 67/69] record protobuf: add docs and fix casing. --- record/pb/envelope.pb.go | 46 ++++++++++++++++++++++++++-------------- record/pb/envelope.proto | 23 +++++++++++++++++--- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/record/pb/envelope.pb.go b/record/pb/envelope.pb.go index 6840ec51..412809f1 100644 --- a/record/pb/envelope.pb.go +++ b/record/pb/envelope.pb.go @@ -23,12 +23,26 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// TODO(yusef): doc comments before merge +// Envelope encloses a signed payload produced by a peer, along with the public +// key of the keypair it was signed with so that it can be statelessly validated +// by the receiver. +// +// The payload is prefixed with a byte string that determines the type, so it +// can be deserialized deterministically. Often, this byte string is a +// multicodec. type Envelope struct { - PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` - PayloadType []byte `protobuf:"bytes,2,opt,name=payloadType,proto3" json:"payloadType,omitempty"` - Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` - Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` + // public_key is the public key of the keypair the enclosed payload was + // signed with. + PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + // payload_type encodes the type of payload, so that it can be deserialized + // deterministically. + PayloadType []byte `protobuf:"bytes,2,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"` + // payload is the actual payload carried inside this envelope. + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + // signature is the signature produced by the private key corresponding to + // the enclosed public key, over the payload, prefixing a domain string for + // additional security. + Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` } func (m *Envelope) Reset() { *m = Envelope{} } @@ -99,20 +113,20 @@ func init() { func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } var fileDescriptor_ee266e8c558e9dc5 = []byte{ - // 194 bytes of a gzipped FileDescriptorProto + // 205 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2c, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x48, 0x92, 0x12, 0x4b, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x48, - 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x66, 0x30, 0x72, 0x71, 0xb8, 0x42, 0x75, 0x09, 0x19, 0x71, - 0x71, 0x16, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, - 0x1b, 0x89, 0xe8, 0xc1, 0x94, 0x27, 0xe9, 0x05, 0xc0, 0xe4, 0x82, 0x10, 0xca, 0x84, 0x14, 0xb8, - 0xb8, 0x0b, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x42, 0x2a, 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18, - 0x35, 0x78, 0x82, 0x90, 0x85, 0x84, 0x24, 0xb8, 0xd8, 0xa1, 0x5c, 0x09, 0x66, 0xb0, 0x2c, 0x8c, - 0x2b, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97, 0x58, 0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x0a, - 0x96, 0x43, 0x08, 0x38, 0x49, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, - 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x12, - 0x1b, 0xd8, 0xed, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0xe9, 0x3f, 0x76, 0xf0, 0x00, - 0x00, 0x00, + 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x66, 0x31, 0x72, 0x71, 0xb8, 0x42, 0x75, 0x09, 0x19, 0x73, + 0x71, 0x15, 0x94, 0x26, 0xe5, 0x64, 0x26, 0xc7, 0x67, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, + 0x70, 0x1b, 0x89, 0xe8, 0xc1, 0xd4, 0x27, 0xe9, 0x05, 0x80, 0x25, 0xbd, 0x53, 0x2b, 0x83, 0x38, + 0x0b, 0x60, 0x4c, 0x21, 0x45, 0x2e, 0x9e, 0x82, 0xc4, 0xca, 0x9c, 0xfc, 0xc4, 0x94, 0xf8, 0x92, + 0xca, 0x82, 0x54, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x6e, 0xa8, 0x58, 0x48, 0x65, 0x41, + 0xaa, 0x90, 0x04, 0x17, 0x3b, 0x94, 0x2b, 0xc1, 0x0c, 0x96, 0x85, 0x71, 0x85, 0x64, 0xb8, 0x38, + 0x8b, 0x33, 0xd3, 0xf3, 0x12, 0x4b, 0x4a, 0x8b, 0x52, 0x25, 0x58, 0xc1, 0x72, 0x08, 0x01, 0x27, + 0x89, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, + 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xbb, 0xde, 0x18, + 0x10, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x0b, 0xd9, 0x6d, 0xf2, 0x00, 0x00, 0x00, } func (m *Envelope) Marshal() (dAtA []byte, err error) { diff --git a/record/pb/envelope.proto b/record/pb/envelope.proto index ab20a35b..ca3555fb 100644 --- a/record/pb/envelope.proto +++ b/record/pb/envelope.proto @@ -4,10 +4,27 @@ package record.pb; import "crypto/pb/crypto.proto"; -// TODO(yusef): doc comments before merge +// Envelope encloses a signed payload produced by a peer, along with the public +// key of the keypair it was signed with so that it can be statelessly validated +// by the receiver. +// +// The payload is prefixed with a byte string that determines the type, so it +// can be deserialized deterministically. Often, this byte string is a +// multicodec. message Envelope { - crypto.pb.PublicKey publicKey = 1; - bytes payloadType = 2; + // public_key is the public key of the keypair the enclosed payload was + // signed with. + crypto.pb.PublicKey public_key = 1; + + // payload_type encodes the type of payload, so that it can be deserialized + // deterministically. + bytes payload_type = 2; + + // payload is the actual payload carried inside this envelope. bytes payload = 3; + + // signature is the signature produced by the private key corresponding to + // the enclosed public key, over the payload, prefixing a domain string for + // additional security. bytes signature = 5; } From 68fa5dcbf0e3ecf292a7e93415a7976a3c8ef2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 10 Feb 2020 19:44:54 +0000 Subject: [PATCH 68/69] cleanup: group imports. --- peer/record.go | 4 +++- peerstore/peerstore.go | 1 + record/envelope.go | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/peer/record.go b/peer/record.go index fec13203..76c4e672 100644 --- a/peer/record.go +++ b/peer/record.go @@ -4,10 +4,12 @@ import ( "fmt" "time" - "github.com/gogo/protobuf/proto" pb "github.com/libp2p/go-libp2p-core/peer/pb" "github.com/libp2p/go-libp2p-core/record" + ma "github.com/multiformats/go-multiaddr" + + "github.com/gogo/protobuf/proto" ) var _ record.Record = (*PeerRecord)(nil) diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index 178f9492..e77b3c13 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -12,6 +12,7 @@ import ( ic "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/record" + ma "github.com/multiformats/go-multiaddr" ) diff --git a/record/envelope.go b/record/envelope.go index e674ec9d..bdc33abd 100644 --- a/record/envelope.go +++ b/record/envelope.go @@ -6,10 +6,11 @@ import ( "fmt" "sync" - pool "github.com/libp2p/go-buffer-pool" "github.com/libp2p/go-libp2p-core/crypto" pb "github.com/libp2p/go-libp2p-core/record/pb" + pool "github.com/libp2p/go-buffer-pool" + "github.com/gogo/protobuf/proto" "github.com/multiformats/go-varint" ) From 541a648eed2fe9dc9cfe835af7f8cafbd5b18cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 10 Feb 2020 19:50:04 +0000 Subject: [PATCH 69/69] nit: split test/utils.go => test/{addrs,errors}.go. --- test/{utils.go => addrs.go} | 14 -------------- test/errors.go | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 14 deletions(-) rename test/{utils.go => addrs.go} (75%) create mode 100644 test/errors.go diff --git a/test/utils.go b/test/addrs.go similarity index 75% rename from test/utils.go rename to test/addrs.go index f4db700a..e18849c4 100644 --- a/test/utils.go +++ b/test/addrs.go @@ -7,20 +7,6 @@ import ( ma "github.com/multiformats/go-multiaddr" ) -func AssertNilError(t *testing.T, err error) { - t.Helper() - if err != nil { - t.Errorf("unexpected error: %v", err) - } -} - -func ExpectError(t *testing.T, err error, msg string) { - t.Helper() - if err == nil { - t.Error(msg) - } -} - func GenerateTestAddrs(n int) []ma.Multiaddr { out := make([]ma.Multiaddr, n) for i := 0; i < n; i++ { diff --git a/test/errors.go b/test/errors.go new file mode 100644 index 00000000..82a3e696 --- /dev/null +++ b/test/errors.go @@ -0,0 +1,19 @@ +package test + +import ( + "testing" +) + +func AssertNilError(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Errorf("unexpected error: %v", err) + } +} + +func ExpectError(t *testing.T, err error, msg string) { + t.Helper() + if err == nil { + t.Error(msg) + } +}