From ec669bbf3b849fbcc880e57ebddc4d41accacc83 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Mon, 13 Dec 2021 22:36:01 +1100 Subject: [PATCH 1/6] feat(requestid): use uuids for requestids Ref: https://github.com/ipfs/go-graphsync/issues/278 Closes: https://github.com/ipfs/go-graphsync/issues/279 Closes: https://github.com/ipfs/go-graphsync/issues/281 --- go.mod | 1 + graphsync.go | 15 ++++++-- impl/graphsync_test.go | 3 +- linktracker/linktracker_test.go | 7 ++-- message/builder_test.go | 10 +++--- message/message.go | 19 +++++++--- message/message_test.go | 16 ++++----- message/pb/message.pb.go | 18 +++++----- message/pb/message.proto | 4 +-- messagequeue/messagequeue_test.go | 16 ++++----- network/libp2p_impl_test.go | 2 +- peermanager/peermessagemanager_test.go | 2 +- peerstate/peerstate_test.go | 3 +- .../asyncloader/asyncloader_test.go | 35 +++++++++---------- .../loadattemptqueue/loadattemptqueue_test.go | 11 +++--- .../responsecache/responsecache_test.go | 5 ++- requestmanager/client.go | 1 - requestmanager/executor/executor_test.go | 2 +- requestmanager/hooks/hooks_test.go | 7 ++-- requestmanager/requestmanager_test.go | 10 +++--- requestmanager/server.go | 5 ++- responsemanager/hooks/hooks_test.go | 7 ++-- .../queryexecutor/queryexecutor_test.go | 2 +- .../responseassembler_test.go | 27 +++++++------- responsemanager/responsemanager_test.go | 2 +- responsemanager/server.go | 4 +-- 26 files changed, 124 insertions(+), 110 deletions(-) diff --git a/go.mod b/go.mod index 641b1177..39f7bee5 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/ipfs/go-graphsync go 1.16 require ( + github.com/google/uuid v1.3.0 github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1 github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e github.com/ipfs/go-block-format v0.0.3 diff --git a/graphsync.go b/graphsync.go index 75756c88..90d53de7 100644 --- a/graphsync.go +++ b/graphsync.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/google/uuid" "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime/traversal" @@ -12,11 +13,21 @@ import ( ) // RequestID is a unique identifier for a GraphSync request. -type RequestID int32 +type RequestID uuid.UUID // Tag returns an easy way to identify this request id as a graphsync request (for libp2p connections) func (r RequestID) Tag() string { - return fmt.Sprintf("graphsync-request-%d", r) + return r.String() +} + +// String form of a RequestID (should be a well-formed UUIDv4 string) +func (r RequestID) String() string { + return uuid.UUID(r).String() +} + +// Create a new, random RequestID (should be a UUIDv4) +func NewRequestID() RequestID { + return RequestID(uuid.New()) } // Priority a priority for a GraphSync request. diff --git a/impl/graphsync_test.go b/impl/graphsync_test.go index d9c93cec..a6bfc5c1 100644 --- a/impl/graphsync_test.go +++ b/impl/graphsync_test.go @@ -8,7 +8,6 @@ import ( "io" "io/ioutil" "math" - "math/rand" "os" "path/filepath" "testing" @@ -134,7 +133,7 @@ func TestSendResponseToIncomingRequest(t *testing.T) { blockChainLength := 100 blockChain := testutil.SetupBlockChain(ctx, t, td.persistence2, 100, blockChainLength) - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() builder := gsmsg.NewBuilder() builder.AddRequest(gsmsg.NewRequest(requestID, blockChain.TipLink.(cidlink.Link).Cid, blockChain.Selector(), graphsync.Priority(math.MaxInt32), td.extension)) diff --git a/linktracker/linktracker_test.go b/linktracker/linktracker_test.go index af9745c9..4ba4c336 100644 --- a/linktracker/linktracker_test.go +++ b/linktracker/linktracker_test.go @@ -1,7 +1,6 @@ package linktracker import ( - "math/rand" "testing" "github.com/ipld/go-ipld-prime" @@ -74,7 +73,7 @@ func TestBlockRefCount(t *testing.T) { linkTracker := New() link := testutil.NewTestLink() for _, rq := range data.requests { - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() for _, present := range rq.traversals { linkTracker.RecordLinkTraversal(requestID, link, present) } @@ -116,7 +115,7 @@ func TestFinishRequest(t *testing.T) { for testCase, data := range testCases { t.Run(testCase, func(t *testing.T) { linkTracker := New() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() for _, lt := range data.linksTraversed { linkTracker.RecordLinkTraversal(requestID, lt.link, lt.blockPresent) } @@ -151,7 +150,7 @@ func TestIsKnownMissingLink(t *testing.T) { t.Run(testCase, func(t *testing.T) { linkTracker := New() link := testutil.NewTestLink() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() for _, present := range data.traversals { linkTracker.RecordLinkTraversal(requestID, link, present) } diff --git a/message/builder_test.go b/message/builder_test.go index b9722c84..fa2403a6 100644 --- a/message/builder_test.go +++ b/message/builder_test.go @@ -2,7 +2,6 @@ package message import ( "io" - "math/rand" "testing" "github.com/ipld/go-ipld-prime" @@ -20,6 +19,7 @@ func TestMessageBuilding(t *testing.T) { for _, block := range blocks { links = append(links, cidlink.Link{Cid: block.Cid()}) } + extensionData1 := testutil.RandomBytes(100) extensionName1 := graphsync.ExtensionName("AppleSauce/McGee") extension1 := graphsync.ExtensionData{ @@ -32,10 +32,10 @@ func TestMessageBuilding(t *testing.T) { Name: extensionName2, Data: extensionData2, } - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) - requestID3 := graphsync.RequestID(rand.Int31()) - requestID4 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() + requestID3 := graphsync.NewRequestID() + requestID4 := graphsync.NewRequestID() closer := io.NopCloser(nil) testCases := map[string]struct { build func(*Builder) diff --git a/message/message.go b/message/message.go index 6e818847..2a180529 100644 --- a/message/message.go +++ b/message/message.go @@ -6,6 +6,7 @@ import ( "fmt" "io" + "github.com/google/uuid" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime" @@ -162,7 +163,12 @@ func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { if exts == nil { exts = make(map[string][]byte) } - requests[graphsync.RequestID(req.Id)] = newRequest(graphsync.RequestID(req.Id), root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) + uid, err := uuid.FromBytes(req.Id) + if err != nil { + return GraphSyncMessage{}, err + } + id := graphsync.RequestID(uid) + requests[id] = newRequest(id, root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) } responses := make(map[graphsync.RequestID]GraphSyncResponse, len(pbm.GetResponses())) @@ -174,7 +180,12 @@ func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { if exts == nil { exts = make(map[string][]byte) } - responses[graphsync.RequestID(res.Id)] = newResponse(graphsync.RequestID(res.Id), graphsync.ResponseStatusCode(res.Status), exts) + uid, err := uuid.FromBytes(res.Id) + if err != nil { + return GraphSyncMessage{}, err + } + id := graphsync.RequestID(uid) + responses[id] = newResponse(id, graphsync.ResponseStatusCode(res.Status), exts) } blks := make(map[cid.Cid]blocks.Block, len(pbm.GetData())) @@ -278,7 +289,7 @@ func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { } } pbm.Requests = append(pbm.Requests, &pb.Message_Request{ - Id: int32(request.id), + Id: request.id[:], Root: request.root.Bytes(), Selector: selector, Priority: int32(request.priority), @@ -291,7 +302,7 @@ func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { pbm.Responses = make([]*pb.Message_Response, 0, len(gsm.responses)) for _, response := range gsm.responses { pbm.Responses = append(pbm.Responses, &pb.Message_Response{ - Id: int32(response.requestID), + Id: response.requestID[:], Status: int32(response.status), Extensions: response.extensions, }) diff --git a/message/message_test.go b/message/message_test.go index 135342d3..bc59978c 100644 --- a/message/message_test.go +++ b/message/message_test.go @@ -26,7 +26,7 @@ func TestAppendingRequests(t *testing.T) { root := testutil.GenerateCids(1)[0] ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) selector := ssb.Matcher().Node() - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) builder := NewBuilder() @@ -51,7 +51,7 @@ func TestAppendingRequests(t *testing.T) { require.NoError(t, err) pbRequest := pbMessage.Requests[0] - require.Equal(t, int32(id), pbRequest.Id) + require.Equal(t, id[:], pbRequest.Id) require.Equal(t, int32(priority), pbRequest.Priority) require.False(t, pbRequest.Cancel) require.False(t, pbRequest.Update) @@ -82,7 +82,7 @@ func TestAppendingResponses(t *testing.T) { Name: extensionName, Data: testutil.RandomBytes(100), } - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() status := graphsync.RequestAcknowledged builder := NewBuilder() @@ -102,7 +102,7 @@ func TestAppendingResponses(t *testing.T) { pbMessage, err := gsm.ToProto() require.NoError(t, err, "serialize to protobuf errored") pbResponse := pbMessage.Responses[0] - require.Equal(t, int32(requestID), pbResponse.Id) + require.Equal(t, requestID[:], pbResponse.Id) require.Equal(t, int32(status), pbResponse.Status) require.Equal(t, extension.Data, pbResponse.Extensions["graphsync/awesome"]) @@ -154,7 +154,7 @@ func contains(strs []string, x string) bool { func TestRequestCancel(t *testing.T) { ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) selector := ssb.Matcher().Node() - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) root := testutil.GenerateCids(1)[0] @@ -184,7 +184,7 @@ func TestRequestCancel(t *testing.T) { func TestRequestUpdate(t *testing.T) { - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() extensionName := graphsync.ExtensionName("graphsync/awesome") extension := graphsync.ExtensionData{ Name: extensionName, @@ -235,7 +235,7 @@ func TestToNetFromNetEquivalency(t *testing.T) { Name: extensionName, Data: testutil.RandomBytes(100), } - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) status := graphsync.RequestAcknowledged @@ -325,7 +325,7 @@ func TestMergeExtensions(t *testing.T) { root := testutil.GenerateCids(1)[0] ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) selector := ssb.Matcher().Node() - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) defaultRequest := NewRequest(id, root, selector, priority, initialExtensions...) t.Run("when merging into empty", func(t *testing.T) { diff --git a/message/pb/message.pb.go b/message/pb/message.pb.go index 7110c0b1..897027eb 100644 --- a/message/pb/message.pb.go +++ b/message/pb/message.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.1 -// protoc v3.17.3 +// protoc v3.19.1 // source: message.proto package graphsync_message_pb @@ -98,7 +98,7 @@ type Message_Request struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // unique id set on the requester side + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // unique id set on the requester side Root []byte `protobuf:"bytes,2,opt,name=root,proto3" json:"root,omitempty"` // a CID for the root node in the query Selector []byte `protobuf:"bytes,3,opt,name=selector,proto3" json:"selector,omitempty"` // ipld selector to retrieve Extensions map[string][]byte `protobuf:"bytes,4,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // aux information. useful for other protocols @@ -139,11 +139,11 @@ func (*Message_Request) Descriptor() ([]byte, []int) { return file_message_proto_rawDescGZIP(), []int{0, 0} } -func (x *Message_Request) GetId() int32 { +func (x *Message_Request) GetId() []byte { if x != nil { return x.Id } - return 0 + return nil } func (x *Message_Request) GetRoot() []byte { @@ -193,7 +193,7 @@ type Message_Response struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // the request id + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // the request id Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` // a status code. Extensions map[string][]byte `protobuf:"bytes,3,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // additional data } @@ -230,11 +230,11 @@ func (*Message_Response) Descriptor() ([]byte, []int) { return file_message_proto_rawDescGZIP(), []int{0, 1} } -func (x *Message_Response) GetId() int32 { +func (x *Message_Response) GetId() []byte { if x != nil { return x.Id } - return 0 + return nil } func (x *Message_Response) GetStatus() int32 { @@ -328,7 +328,7 @@ var file_message_proto_rawDesc = []byte{ 0x70, 0x68, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xab, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, @@ -347,7 +347,7 @@ var file_message_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xc9, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x56, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x67, diff --git a/message/pb/message.proto b/message/pb/message.proto index ed6d561d..0703e50a 100644 --- a/message/pb/message.proto +++ b/message/pb/message.proto @@ -7,7 +7,7 @@ option go_package = ".;graphsync_message_pb"; message Message { message Request { - int32 id = 1; // unique id set on the requester side + bytes id = 1; // unique id set on the requester side bytes root = 2; // a CID for the root node in the query bytes selector = 3; // ipld selector to retrieve map extensions = 4; // aux information. useful for other protocols @@ -17,7 +17,7 @@ message Message { } message Response { - int32 id = 1; // the request id + bytes id = 1; // the request id int32 status = 2; // a status code. map extensions = 3; // additional data } diff --git a/messagequeue/messagequeue_test.go b/messagequeue/messagequeue_test.go index 60d5fb8b..219db099 100644 --- a/messagequeue/messagequeue_test.go +++ b/messagequeue/messagequeue_test.go @@ -39,7 +39,7 @@ func TestStartupAndShutdown(t *testing.T) { messageQueue := New(ctx, peer, messageNetwork, allocator, messageSendRetries, sendMessageTimeout) messageQueue.Startup() - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) selector := ssb.Matcher().Node() @@ -77,7 +77,7 @@ func TestShutdownDuringMessageSend(t *testing.T) { messageQueue := New(ctx, peer, messageNetwork, allocator, messageSendRetries, sendMessageTimeout) messageQueue.Startup() - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) selector := ssb.Matcher().Node() @@ -128,7 +128,7 @@ func TestProcessingNotification(t *testing.T) { waitGroup.Add(1) blks := testutil.GenerateBlocksOfSize(3, 128) - responseID := graphsync.RequestID(rand.Int31()) + responseID := graphsync.NewRequestID() extensionName := graphsync.ExtensionName("graphsync/awesome") extension := graphsync.ExtensionData{ Name: extensionName, @@ -199,7 +199,7 @@ func TestDedupingMessages(t *testing.T) { messageQueue := New(ctx, peer, messageNetwork, allocator, messageSendRetries, sendMessageTimeout) messageQueue.Startup() waitGroup.Add(1) - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) selector := ssb.Matcher().Node() @@ -210,11 +210,11 @@ func TestDedupingMessages(t *testing.T) { }) // wait for send attempt waitGroup.Wait() - id2 := graphsync.RequestID(rand.Int31()) + id2 := graphsync.NewRequestID() priority2 := graphsync.Priority(rand.Int31()) selector2 := ssb.ExploreAll(ssb.Matcher()).Node() root2 := testutil.GenerateCids(1)[0] - id3 := graphsync.RequestID(rand.Int31()) + id3 := graphsync.NewRequestID() priority3 := graphsync.Priority(rand.Int31()) selector3 := ssb.ExploreIndex(0, ssb.Matcher()).Node() root3 := testutil.GenerateCids(1)[0] @@ -385,8 +385,8 @@ func TestNetworkErrorClearResponses(t *testing.T) { messagesSent := make(chan gsmsg.GraphSyncMessage) resetChan := make(chan struct{}, 1) fullClosedChan := make(chan struct{}, 1) - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() messageSender := &fakeMessageSender{nil, fullClosedChan, resetChan, messagesSent} var waitGroup sync.WaitGroup messageNetwork := &fakeMessageNetwork{nil, nil, messageSender, &waitGroup} diff --git a/network/libp2p_impl_test.go b/network/libp2p_impl_test.go index da7d2225..2cdf0938 100644 --- a/network/libp2p_impl_test.go +++ b/network/libp2p_impl_test.go @@ -77,7 +77,7 @@ func TestMessageSendAndReceive(t *testing.T) { Name: extensionName, Data: testutil.RandomBytes(100), } - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) status := graphsync.RequestAcknowledged diff --git a/peermanager/peermessagemanager_test.go b/peermanager/peermessagemanager_test.go index 6d55c936..5b1223dd 100644 --- a/peermanager/peermessagemanager_test.go +++ b/peermanager/peermessagemanager_test.go @@ -67,7 +67,7 @@ func TestSendingMessagesToPeers(t *testing.T) { tp := testutil.GeneratePeers(5) - id := graphsync.RequestID(rand.Int31()) + id := graphsync.NewRequestID() priority := graphsync.Priority(rand.Int31()) root := testutil.GenerateCids(1)[0] ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) diff --git a/peerstate/peerstate_test.go b/peerstate/peerstate_test.go index 4519555f..aa4e860a 100644 --- a/peerstate/peerstate_test.go +++ b/peerstate/peerstate_test.go @@ -2,7 +2,6 @@ package peerstate_test import ( "fmt" - "math/rand" "testing" "github.com/stretchr/testify/require" @@ -14,7 +13,7 @@ import ( func TestDiagnostics(t *testing.T) { requestIDs := make([]graphsync.RequestID, 0, 5) for i := 0; i < 5; i++ { - requestIDs = append(requestIDs, graphsync.RequestID(rand.Int31())) + requestIDs = append(requestIDs, graphsync.NewRequestID()) } testCases := map[string]struct { requestStates graphsync.RequestStates diff --git a/requestmanager/asyncloader/asyncloader_test.go b/requestmanager/asyncloader/asyncloader_test.go index 63255d53..8b6717fa 100644 --- a/requestmanager/asyncloader/asyncloader_test.go +++ b/requestmanager/asyncloader/asyncloader_test.go @@ -3,7 +3,6 @@ package asyncloader import ( "context" "io" - "math/rand" "testing" "time" @@ -23,7 +22,7 @@ func TestAsyncLoadInitialLoadSucceedsLocallyPresent(t *testing.T) { st := newStore() link := st.Store(t, block) withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() p := testutil.GeneratePeers(1)[0] resultChan := asyncLoader.AsyncLoad(p, requestID, link, ipld.LinkContext{}) assertSuccessResponse(ctx, t, resultChan) @@ -38,7 +37,7 @@ func TestAsyncLoadInitialLoadSucceedsResponsePresent(t *testing.T) { st := newStore() withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() responses := map[graphsync.RequestID]metadata.Metadata{ requestID: { metadata.Item{ @@ -61,7 +60,7 @@ func TestAsyncLoadInitialLoadFails(t *testing.T) { st := newStore() withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { link := testutil.NewTestLink() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() responses := map[graphsync.RequestID]metadata.Metadata{ requestID: { @@ -84,7 +83,7 @@ func TestAsyncLoadInitialLoadIndeterminateWhenRequestNotInProgress(t *testing.T) st := newStore() withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { link := testutil.NewTestLink() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() p := testutil.GeneratePeers(1)[0] resultChan := asyncLoader.AsyncLoad(p, requestID, link, ipld.LinkContext{}) assertFailResponse(ctx, t, resultChan) @@ -100,7 +99,7 @@ func TestAsyncLoadInitialLoadIndeterminateThenSucceeds(t *testing.T) { st := newStore() withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() err := asyncLoader.StartRequest(requestID, "") require.NoError(t, err) p := testutil.GeneratePeers(1)[0] @@ -128,7 +127,7 @@ func TestAsyncLoadInitialLoadIndeterminateThenFails(t *testing.T) { withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { link := testutil.NewTestLink() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() err := asyncLoader.StartRequest(requestID, "") require.NoError(t, err) p := testutil.GeneratePeers(1)[0] @@ -154,7 +153,7 @@ func TestAsyncLoadInitialLoadIndeterminateThenRequestFinishes(t *testing.T) { st := newStore() withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { link := testutil.NewTestLink() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() err := asyncLoader.StartRequest(requestID, "") require.NoError(t, err) p := testutil.GeneratePeers(1)[0] @@ -172,7 +171,7 @@ func TestAsyncLoadTwiceLoadsLocallySecondTime(t *testing.T) { link := cidlink.Link{Cid: block.Cid()} st := newStore() withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() responses := map[graphsync.RequestID]metadata.Metadata{ requestID: { metadata.Item{ @@ -203,13 +202,13 @@ func TestRegisterUnregister(t *testing.T) { link1 := otherSt.Store(t, blocks[0]) withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { - requestID1 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() err := asyncLoader.StartRequest(requestID1, "other") require.EqualError(t, err, "unknown persistence option") err = asyncLoader.RegisterPersistenceOption("other", otherSt.lsys) require.NoError(t, err) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID2 := graphsync.NewRequestID() err = asyncLoader.StartRequest(requestID2, "other") require.NoError(t, err) p := testutil.GeneratePeers(1)[0] @@ -222,7 +221,7 @@ func TestRegisterUnregister(t *testing.T) { err = asyncLoader.UnregisterPersistenceOption("other") require.NoError(t, err) - requestID3 := graphsync.RequestID(rand.Int31()) + requestID3 := graphsync.NewRequestID() err = asyncLoader.StartRequest(requestID3, "other") require.EqualError(t, err, "unknown persistence option") }) @@ -235,11 +234,11 @@ func TestRequestSplittingLoadLocallyFromBlockstore(t *testing.T) { withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { err := asyncLoader.RegisterPersistenceOption("other", otherSt.lsys) require.NoError(t, err) - requestID1 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() p := testutil.GeneratePeers(1)[0] resultChan1 := asyncLoader.AsyncLoad(p, requestID1, link, ipld.LinkContext{}) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID2 := graphsync.NewRequestID() err = asyncLoader.StartRequest(requestID2, "other") require.NoError(t, err) resultChan2 := asyncLoader.AsyncLoad(p, requestID2, link, ipld.LinkContext{}) @@ -259,8 +258,8 @@ func TestRequestSplittingSameBlockTwoStores(t *testing.T) { withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { err := asyncLoader.RegisterPersistenceOption("other", otherSt.lsys) require.NoError(t, err) - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() err = asyncLoader.StartRequest(requestID1, "") require.NoError(t, err) err = asyncLoader.StartRequest(requestID2, "other") @@ -300,8 +299,8 @@ func TestRequestSplittingSameBlockOnlyOneResponse(t *testing.T) { withLoader(st, func(ctx context.Context, asyncLoader *AsyncLoader) { err := asyncLoader.RegisterPersistenceOption("other", otherSt.lsys) require.NoError(t, err) - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() err = asyncLoader.StartRequest(requestID1, "") require.NoError(t, err) err = asyncLoader.StartRequest(requestID2, "other") diff --git a/requestmanager/asyncloader/loadattemptqueue/loadattemptqueue_test.go b/requestmanager/asyncloader/loadattemptqueue/loadattemptqueue_test.go index ae992711..9c83a426 100644 --- a/requestmanager/asyncloader/loadattemptqueue/loadattemptqueue_test.go +++ b/requestmanager/asyncloader/loadattemptqueue/loadattemptqueue_test.go @@ -3,7 +3,6 @@ package loadattemptqueue import ( "context" "fmt" - "math/rand" "testing" "time" @@ -31,7 +30,7 @@ func TestAsyncLoadInitialLoadSucceeds(t *testing.T) { link := testutil.NewTestLink() linkContext := ipld.LinkContext{} - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() p := testutil.GeneratePeers(1)[0] resultChan := make(chan types.AsyncLoadResult, 1) @@ -61,7 +60,7 @@ func TestAsyncLoadInitialLoadFails(t *testing.T) { link := testutil.NewTestLink() linkContext := ipld.LinkContext{} - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() resultChan := make(chan types.AsyncLoadResult, 1) p := testutil.GeneratePeers(1)[0] @@ -95,7 +94,7 @@ func TestAsyncLoadInitialLoadIndeterminateRetryFalse(t *testing.T) { link := testutil.NewTestLink() linkContext := ipld.LinkContext{} - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() p := testutil.GeneratePeers(1)[0] resultChan := make(chan types.AsyncLoadResult, 1) @@ -130,7 +129,7 @@ func TestAsyncLoadInitialLoadIndeterminateRetryTrueThenRetriedSuccess(t *testing link := testutil.NewTestLink() linkContext := ipld.LinkContext{} - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() resultChan := make(chan types.AsyncLoadResult, 1) p := testutil.GeneratePeers(1)[0] lr := NewLoadRequest(p, requestID, link, linkContext, resultChan) @@ -167,7 +166,7 @@ func TestAsyncLoadInitialLoadIndeterminateThenRequestFinishes(t *testing.T) { link := testutil.NewTestLink() linkContext := ipld.LinkContext{} - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() resultChan := make(chan types.AsyncLoadResult, 1) p := testutil.GeneratePeers(1)[0] lr := NewLoadRequest(p, requestID, link, linkContext, resultChan) diff --git a/requestmanager/asyncloader/responsecache/responsecache_test.go b/requestmanager/asyncloader/responsecache/responsecache_test.go index 438fdc30..7034c13a 100644 --- a/requestmanager/asyncloader/responsecache/responsecache_test.go +++ b/requestmanager/asyncloader/responsecache/responsecache_test.go @@ -3,7 +3,6 @@ package responsecache import ( "context" "fmt" - "math/rand" "testing" blocks "github.com/ipfs/go-block-format" @@ -59,8 +58,8 @@ func (ubs *fakeUnverifiedBlockStore) blocks() []blocks.Block { func TestResponseCacheManagingLinks(t *testing.T) { blks := testutil.GenerateBlocksOfSize(5, 100) - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() request1Metadata := metadata.Metadata{ metadata.Item{ diff --git a/requestmanager/client.go b/requestmanager/client.go index c18d7bfe..351159dc 100644 --- a/requestmanager/client.go +++ b/requestmanager/client.go @@ -97,7 +97,6 @@ type RequestManager struct { maxLinksPerRequest uint64 // dont touch out side of run loop - nextRequestID graphsync.RequestID inProgressRequestStatuses map[graphsync.RequestID]*inProgressRequestStatus requestHooks RequestHooks responseHooks ResponseHooks diff --git a/requestmanager/executor/executor_test.go b/requestmanager/executor/executor_test.go index 8b737e3e..34321f2e 100644 --- a/requestmanager/executor/executor_test.go +++ b/requestmanager/executor/executor_test.go @@ -179,7 +179,7 @@ func TestRequestExecutionBlockChain(t *testing.T) { persistence := testutil.NewTestStore(make(map[ipld.Link][]byte)) tbc := testutil.SetupBlockChain(ctx, t, persistence, 100, 10) fal := testloader.NewFakeAsyncLoader() - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() p := testutil.GeneratePeers(1)[0] configureLoader := data.configureLoader if configureLoader == nil { diff --git a/requestmanager/hooks/hooks_test.go b/requestmanager/hooks/hooks_test.go index 4f008f09..2df87541 100644 --- a/requestmanager/hooks/hooks_test.go +++ b/requestmanager/hooks/hooks_test.go @@ -2,7 +2,6 @@ package hooks_test import ( "errors" - "math/rand" "testing" "github.com/ipld/go-ipld-prime" @@ -29,7 +28,7 @@ func TestRequestHookProcessing(t *testing.T) { } root := testutil.GenerateCids(1)[0] - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) request := gsmsg.NewRequest(requestID, root, ssb.Matcher().Node(), graphsync.Priority(0), extension) p := testutil.GeneratePeers(1)[0] @@ -111,7 +110,7 @@ func TestBlockHookProcessing(t *testing.T) { Name: extensionName, Data: extensionUpdateData, } - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() response := gsmsg.NewResponse(requestID, graphsync.PartialResponse, extensionResponse) p := testutil.GeneratePeers(1)[0] @@ -208,7 +207,7 @@ func TestResponseHookProcessing(t *testing.T) { Name: extensionName, Data: extensionUpdateData, } - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() response := gsmsg.NewResponse(requestID, graphsync.PartialResponse, extensionResponse) p := testutil.GeneratePeers(1)[0] diff --git a/requestmanager/requestmanager_test.go b/requestmanager/requestmanager_test.go index ee5dcbf2..777136fe 100644 --- a/requestmanager/requestmanager_test.go +++ b/requestmanager/requestmanager_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "sort" "testing" "time" @@ -1039,9 +1038,12 @@ func readNNetworkRequests(ctx context.Context, } // because of the simultaneous request queues it's possible for the requests to go to the network layer out of order // if the requests are queued at a near identical time - sort.Slice(requestRecords, func(i, j int) bool { - return requestRecords[i].gsr.ID() < requestRecords[j].gsr.ID() - }) + // TODO: howdo? + /* + sort.Slice(requestRecords, func(i, j int) bool { + return requestRecords[i].gsr.ID() < requestRecords[j].gsr.ID() + }) + */ return requestRecords } diff --git a/requestmanager/server.go b/requestmanager/server.go index f8cc47db..02ea7019 100644 --- a/requestmanager/server.go +++ b/requestmanager/server.go @@ -56,10 +56,9 @@ func (rm *RequestManager) cleanupInProcessRequests() { } func (rm *RequestManager) newRequest(parentSpan trace.Span, p peer.ID, root ipld.Link, selector ipld.Node, extensions []graphsync.ExtensionData) (gsmsg.GraphSyncRequest, chan graphsync.ResponseProgress, chan error) { - requestID := rm.nextRequestID - rm.nextRequestID++ + requestID := graphsync.NewRequestID() - parentSpan.SetAttributes(attribute.Int("requestID", int(requestID))) + parentSpan.SetAttributes(attribute.String("requestID", requestID.String())) ctx, span := otel.Tracer("graphsync").Start(trace.ContextWithSpan(rm.ctx, parentSpan), "newRequest") defer span.End() diff --git a/responsemanager/hooks/hooks_test.go b/responsemanager/hooks/hooks_test.go index e8a56903..3d0e7812 100644 --- a/responsemanager/hooks/hooks_test.go +++ b/responsemanager/hooks/hooks_test.go @@ -3,7 +3,6 @@ package hooks_test import ( "errors" "io" - "math/rand" "testing" "github.com/ipld/go-ipld-prime" @@ -54,7 +53,7 @@ func TestRequestHookProcessing(t *testing.T) { } root := testutil.GenerateCids(1)[0] - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) request := gsmsg.NewRequest(requestID, root, ssb.Matcher().Node(), graphsync.Priority(0), extension) p := testutil.GeneratePeers(1)[0] @@ -232,7 +231,7 @@ func TestBlockHookProcessing(t *testing.T) { } root := testutil.GenerateCids(1)[0] - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) request := gsmsg.NewRequest(requestID, root, ssb.Matcher().Node(), graphsync.Priority(0), extension) p := testutil.GeneratePeers(1)[0] @@ -315,7 +314,7 @@ func TestUpdateHookProcessing(t *testing.T) { } root := testutil.GenerateCids(1)[0] - requestID := graphsync.RequestID(rand.Int31()) + requestID := graphsync.NewRequestID() ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) request := gsmsg.NewRequest(requestID, root, ssb.Matcher().Node(), graphsync.Priority(0), extension) update := gsmsg.UpdateRequest(requestID, extensionUpdate) diff --git a/responsemanager/queryexecutor/queryexecutor_test.go b/responsemanager/queryexecutor/queryexecutor_test.go index 3711b5b9..937bc79c 100644 --- a/responsemanager/queryexecutor/queryexecutor_test.go +++ b/responsemanager/queryexecutor/queryexecutor_test.go @@ -274,7 +274,7 @@ func newTestData(t *testing.T, blockCount int, expectedTraverse int) (*testData, td.manager = &fauxManager{ctx: ctx, t: t, expectedStartTask: td.task} td.blockHooks = hooks.NewBlockHooks() td.updateHooks = hooks.NewUpdateHooks() - td.requestID = graphsync.RequestID(rand.Int31()) + td.requestID = graphsync.NewRequestID() td.requestCid, _ = cid.Decode("bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi") td.requestSelector = basicnode.NewInt(rand.Int63()) td.extensionData = testutil.RandomBytes(100) diff --git a/responsemanager/responseassembler/responseassembler_test.go b/responsemanager/responseassembler/responseassembler_test.go index b9f26c6b..e8cc1f03 100644 --- a/responsemanager/responseassembler/responseassembler_test.go +++ b/responsemanager/responseassembler/responseassembler_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "math/rand" "testing" "time" @@ -27,9 +26,9 @@ func TestResponseAssemblerSendsResponses(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) - requestID3 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() + requestID3 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) @@ -139,7 +138,7 @@ func TestResponseAssemblerCloseStream(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) for _, block := range blks { @@ -175,7 +174,7 @@ func TestResponseAssemblerSendsExtensionData(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) for _, block := range blks { @@ -222,7 +221,7 @@ func TestResponseAssemblerSendsResponsesInTransaction(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) for _, block := range blks { @@ -261,8 +260,8 @@ func TestResponseAssemblerIgnoreBlocks(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) for _, block := range blks { @@ -336,8 +335,8 @@ func TestResponseAssemblerSkipFirstBlocks(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) for _, block := range blks { @@ -427,9 +426,9 @@ func TestResponseAssemblerDupKeys(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() p := testutil.GeneratePeers(1)[0] - requestID1 := graphsync.RequestID(rand.Int31()) - requestID2 := graphsync.RequestID(rand.Int31()) - requestID3 := graphsync.RequestID(rand.Int31()) + requestID1 := graphsync.NewRequestID() + requestID2 := graphsync.NewRequestID() + requestID3 := graphsync.NewRequestID() blks := testutil.GenerateBlocksOfSize(5, 100) links := make([]ipld.Link, 0, len(blks)) for _, block := range blks { diff --git a/responsemanager/responsemanager_test.go b/responsemanager/responsemanager_test.go index 443e2408..9328bea4 100644 --- a/responsemanager/responsemanager_test.go +++ b/responsemanager/responsemanager_test.go @@ -1142,7 +1142,7 @@ func newTestData(t *testing.T) testData { Name: td.extensionName, Data: td.extensionUpdateData, } - td.requestID = graphsync.RequestID(rand.Int31()) + td.requestID = graphsync.NewRequestID() td.requests = []gsmsg.GraphSyncRequest{ gsmsg.NewRequest(td.requestID, td.blockChain.TipLink.(cidlink.Link).Cid, td.blockChain.Selector(), graphsync.Priority(0), td.extension), } diff --git a/responsemanager/server.go b/responsemanager/server.go index 16b8c889..56456866 100644 --- a/responsemanager/server.go +++ b/responsemanager/server.go @@ -68,7 +68,7 @@ func (rm *ResponseManager) processUpdate(ctx context.Context, key responseKey, u "processUpdate", trace.WithLinks(trace.LinkFromContext(ctx)), trace.WithAttributes( - attribute.Int("id", int(update.ID())), + attribute.String("id", update.ID().String()), attribute.StringSlice("extensions", update.ExtensionNames()), )) @@ -200,7 +200,7 @@ func (rm *ResponseManager) processRequests(p peer.ID, requests []gsmsg.GraphSync "response", trace.WithLinks(trace.LinkFromContext(ctx)), trace.WithAttributes( - attribute.Int("id", int(request.ID())), + attribute.String("id", request.ID().String()), attribute.Int("priority", int(request.Priority())), attribute.String("root", request.Root().String()), attribute.StringSlice("extensions", request.ExtensionNames()), From 9d929b5357c6984182e9914977c91a640cfe04d9 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 14 Dec 2021 15:40:43 +1100 Subject: [PATCH 2/6] fix(requestmanager): make collect test requests with uuids sortable --- requestmanager/requestmanager_test.go | 79 ++++++++++++++------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/requestmanager/requestmanager_test.go b/requestmanager/requestmanager_test.go index 777136fe..d762bb55 100644 --- a/requestmanager/requestmanager_test.go +++ b/requestmanager/requestmanager_test.go @@ -41,7 +41,7 @@ func TestNormalSimultaneousFetch(t *testing.T) { returnedResponseChan1, returnedErrorChan1 := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) returnedResponseChan2, returnedErrorChan2 := td.requestManager.NewRequest(requestCtx, peers[0], blockChain2.TipLink, blockChain2.Selector()) - requestRecords := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 2) + requestRecords := readNNetworkRequests(requestCtx, t, td, 2) td.tcm.AssertProtected(t, peers[0]) td.tcm.AssertProtectedWithTags(t, peers[0], requestRecords[0].gsr.ID().Tag(), requestRecords[1].gsr.ID().Tag()) @@ -130,7 +130,7 @@ func TestCancelRequestInProgress(t *testing.T) { returnedResponseChan1, returnedErrorChan1 := td.requestManager.NewRequest(requestCtx1, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) returnedResponseChan2, returnedErrorChan2 := td.requestManager.NewRequest(requestCtx2, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - requestRecords := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 2) + requestRecords := readNNetworkRequests(requestCtx, t, td, 2) td.tcm.AssertProtected(t, peers[0]) td.tcm.AssertProtectedWithTags(t, peers[0], requestRecords[0].gsr.ID().Tag(), requestRecords[1].gsr.ID().Tag()) @@ -148,7 +148,7 @@ func TestCancelRequestInProgress(t *testing.T) { td.fal.SuccessResponseOn(peers[0], requestRecords[1].gsr.ID(), firstBlocks) td.blockChain.VerifyResponseRange(requestCtx1, returnedResponseChan1, 0, 3) cancel1() - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] require.True(t, rr.gsr.IsCancel()) require.Equal(t, requestRecords[0].gsr.ID(), rr.gsr.ID()) @@ -194,7 +194,7 @@ func TestCancelRequestImperativeNoMoreBlocks(t *testing.T) { _, returnedErrorChan1 := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - requestRecords := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1) + requestRecords := readNNetworkRequests(requestCtx, t, td, 1) td.tcm.AssertProtected(t, peers[0]) td.tcm.AssertProtectedWithTags(t, peers[0], requestRecords[0].gsr.ID().Tag()) @@ -215,7 +215,7 @@ func TestCancelRequestImperativeNoMoreBlocks(t *testing.T) { require.NoError(t, err) postCancel <- struct{}{} - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] require.True(t, rr.gsr.IsCancel()) require.Equal(t, requestRecords[0].gsr.ID(), rr.gsr.ID()) @@ -243,7 +243,7 @@ func TestCancelManagerExitsGracefully(t *testing.T) { returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] firstBlocks := td.blockChain.Blocks(0, 3) firstMetadata := encodedMetadataForBlocks(t, firstBlocks, true) @@ -275,7 +275,7 @@ func TestFailedRequest(t *testing.T) { returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] td.tcm.AssertProtected(t, peers[0]) td.tcm.AssertProtectedWithTags(t, peers[0], rr.gsr.ID().Tag()) @@ -299,7 +299,7 @@ func TestLocallyFulfilledFirstRequestFailsLater(t *testing.T) { returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] // async loaded response responds immediately td.fal.SuccessResponseOn(peers[0], rr.gsr.ID(), td.blockChain.AllBlocks()) @@ -330,7 +330,7 @@ func TestLocallyFulfilledFirstRequestSucceedsLater(t *testing.T) { }) returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] // async loaded response responds immediately td.fal.SuccessResponseOn(peers[0], rr.gsr.ID(), td.blockChain.AllBlocks()) @@ -358,7 +358,7 @@ func TestRequestReturnsMissingBlocks(t *testing.T) { returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] md := encodedMetadataForBlocks(t, td.blockChain.AllBlocks(), false) firstResponses := []gsmsg.GraphSyncResponse{ @@ -436,7 +436,7 @@ func TestEncodingExtensions(t *testing.T) { td.responseHooks.Register(hook) returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector(), td.extension1, td.extension2) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] gsr := rr.gsr returnedData1, found := gsr.Extension(td.extensionName1) @@ -474,7 +474,7 @@ func TestEncodingExtensions(t *testing.T) { testutil.AssertReceive(ctx, t, receivedExtensionData, &received, "did not receive extension data") require.Equal(t, expectedData, received, "did not receive correct extension data from resposne") - rr = readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr = readNNetworkRequests(requestCtx, t, td, 1)[0] receivedUpdateData, has := rr.gsr.Extension(td.extensionName1) require.True(t, has) require.Equal(t, expectedUpdate, receivedUpdateData, "should have updated with correct extension") @@ -510,7 +510,7 @@ func TestEncodingExtensions(t *testing.T) { testutil.AssertReceive(ctx, t, receivedExtensionData, &received, "did not receive extension data") require.Equal(t, nextExpectedData, received, "did not receive correct extension data from resposne") - rr = readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr = readNNetworkRequests(requestCtx, t, td, 1)[0] receivedUpdateData, has = rr.gsr.Extension(td.extensionName1) require.True(t, has) require.Equal(t, nextExpectedUpdate1, receivedUpdateData, "should have updated with correct extension") @@ -550,7 +550,7 @@ func TestBlockHooks(t *testing.T) { td.blockHooks.Register(hook) returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector(), td.extension1, td.extension2) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] gsr := rr.gsr returnedData1, found := gsr.Extension(td.extensionName1) @@ -602,7 +602,7 @@ func TestBlockHooks(t *testing.T) { }) td.fal.SuccessResponseOn(peers[0], rr.gsr.ID(), firstBlocks) - ur := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + ur := readNNetworkRequests(requestCtx, t, td, 1)[0] receivedUpdateData, has := ur.gsr.Extension(td.extensionName1) require.True(t, has) require.Equal(t, expectedUpdate, receivedUpdateData, "should have updated with correct extension") @@ -666,7 +666,7 @@ func TestBlockHooks(t *testing.T) { }) td.fal.SuccessResponseOn(peers[0], rr.gsr.ID(), nextBlocks) - ur = readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + ur = readNNetworkRequests(requestCtx, t, td, 1)[0] receivedUpdateData, has = ur.gsr.Extension(td.extensionName1) require.True(t, has) require.Equal(t, nextExpectedUpdate1, receivedUpdateData, "should have updated with correct extension") @@ -715,7 +715,7 @@ func TestOutgoingRequestHooks(t *testing.T) { returnedResponseChan1, returnedErrorChan1 := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector(), td.extension1) returnedResponseChan2, returnedErrorChan2 := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - requestRecords := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 2) + requestRecords := readNNetworkRequests(requestCtx, t, td, 2) dedupData, has := requestRecords[0].gsr.Extension(graphsync.ExtensionDeDupByKey) require.True(t, has) @@ -773,7 +773,7 @@ func TestOutgoingRequestListeners(t *testing.T) { returnedResponseChan1, returnedErrorChan1 := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector(), td.extension1) - requestRecords := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1) + requestRecords := readNNetworkRequests(requestCtx, t, td, 1) // Should have fired by now select { @@ -836,7 +836,7 @@ func TestPauseResume(t *testing.T) { // Start request returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] // Start processing responses md := metadataForBlocks(td.blockChain.AllBlocks(), true) @@ -862,7 +862,7 @@ func TestPauseResume(t *testing.T) { <-holdForPause // read the outgoing cancel request - pauseCancel := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + pauseCancel := readNNetworkRequests(requestCtx, t, td, 1)[0] require.True(t, pauseCancel.gsr.IsCancel()) // verify no further responses come through @@ -875,7 +875,7 @@ func TestPauseResume(t *testing.T) { require.NoError(t, err) // verify the correct new request with Do-no-send-cids & other extensions - resumedRequest := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + resumedRequest := readNNetworkRequests(requestCtx, t, td, 1)[0] doNotSendCidsData, has := resumedRequest.gsr.Extension(graphsync.ExtensionDoNotSendCIDs) doNotSendCids, err := cidset.DecodeCidSet(doNotSendCidsData) require.NoError(t, err) @@ -922,7 +922,7 @@ func TestPauseResumeExternal(t *testing.T) { // Start request returnedResponseChan, returnedErrorChan := td.requestManager.NewRequest(requestCtx, peers[0], td.blockChain.TipLink, td.blockChain.Selector()) - rr := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + rr := readNNetworkRequests(requestCtx, t, td, 1)[0] // Start processing responses md := metadataForBlocks(td.blockChain.AllBlocks(), true) @@ -942,7 +942,7 @@ func TestPauseResumeExternal(t *testing.T) { <-holdForPause // read the outgoing cancel request - pauseCancel := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + pauseCancel := readNNetworkRequests(requestCtx, t, td, 1)[0] require.True(t, pauseCancel.gsr.IsCancel()) // verify no further responses come through @@ -955,7 +955,7 @@ func TestPauseResumeExternal(t *testing.T) { require.NoError(t, err) // verify the correct new request with Do-no-send-cids & other extensions - resumedRequest := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 1)[0] + resumedRequest := readNNetworkRequests(requestCtx, t, td, 1)[0] doNotSendCidsData, has := resumedRequest.gsr.Extension(graphsync.ExtensionDoNotSendCIDs) doNotSendCids, err := cidset.DecodeCidSet(doNotSendCidsData) require.NoError(t, err) @@ -991,7 +991,7 @@ func TestStats(t *testing.T) { _, _ = td.requestManager.NewRequest(requestCtx, peers[0], blockChain2.TipLink, blockChain2.Selector()) _, _ = td.requestManager.NewRequest(requestCtx, peers[1], td.blockChain.TipLink, td.blockChain.Selector()) - requestRecords := readNNetworkRequests(requestCtx, t, td.requestRecordChan, 3) + requestRecords := readNNetworkRequests(requestCtx, t, td, 3) peerState := td.requestManager.PeerState(peers[0]) require.Len(t, peerState.RequestStates, 2) @@ -1026,25 +1026,22 @@ func (fph *fakePeerHandler) AllocateAndBuildMessage(p peer.ID, blkSize uint64, } } -func readNNetworkRequests(ctx context.Context, - t *testing.T, - requestRecordChan <-chan requestRecord, - count int) []requestRecord { - requestRecords := make([]requestRecord, 0, count) +func readNNetworkRequests(ctx context.Context, t *testing.T, td *testData, count int) []requestRecord { + requestRecords := make(map[graphsync.RequestID]requestRecord, count) for i := 0; i < count; i++ { var rr requestRecord - testutil.AssertReceive(ctx, t, requestRecordChan, &rr, fmt.Sprintf("did not receive request %d", i)) - requestRecords = append(requestRecords, rr) + testutil.AssertReceive(ctx, t, td.requestRecordChan, &rr, fmt.Sprintf("did not receive request %d", i)) + requestRecords[rr.gsr.ID()] = rr } // because of the simultaneous request queues it's possible for the requests to go to the network layer out of order // if the requests are queued at a near identical time - // TODO: howdo? - /* - sort.Slice(requestRecords, func(i, j int) bool { - return requestRecords[i].gsr.ID() < requestRecords[j].gsr.ID() - }) - */ - return requestRecords + sorted := make([]requestRecord, 0, len(requestRecords)) + for _, id := range td.requestIds { + if rr, ok := requestRecords[id]; ok { + sorted = append(sorted, rr) + } + } + return sorted } func metadataForBlocks(blks []blocks.Block, present bool) metadata.Metadata { @@ -1091,6 +1088,7 @@ type testData struct { outgoingRequestProcessingListeners *listeners.OutgoingRequestProcessingListeners taskqueue *taskqueue.WorkerTaskQueue executor *executor.Executor + requestIds []graphsync.RequestID } func newTestData(ctx context.Context, t *testing.T) *testData { @@ -1127,5 +1125,8 @@ func newTestData(ctx context.Context, t *testing.T) *testData { Name: td.extensionName2, Data: td.extensionData2, } + td.requestHooks.Register(func(p peer.ID, request graphsync.RequestData, hookActions graphsync.OutgoingRequestHookActions) { + td.requestIds = append(td.requestIds, request.ID()) + }) return td } From e3e9fe8e4ab31c11da20dd0b0cc1a794644739f2 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 14 Dec 2021 17:16:19 +1100 Subject: [PATCH 3/6] fix(requestid): print requestids as string uuids in logs --- impl/graphsync_test.go | 4 ++-- requestmanager/asyncloader/asyncloader.go | 6 +++--- .../asyncloader/responsecache/responsecache.go | 2 +- requestmanager/server.go | 12 ++++++------ requestmanager/utils.go | 4 ++-- responsemanager/server.go | 10 +++++----- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/impl/graphsync_test.go b/impl/graphsync_test.go index a6bfc5c1..8047c4da 100644 --- a/impl/graphsync_test.go +++ b/impl/graphsync_test.go @@ -1783,8 +1783,8 @@ func processResponsesTraces(t *testing.T, tracing *testutil.Collector, responseC traces := testutil.RepeatTraceStrings("processResponses({})->loaderProcess(0)->cacheProcess(0)", responseCount-1) finalStub := tracing.FindSpanByTraceString(fmt.Sprintf("processResponses(%d)->loaderProcess(0)", responseCount-1)) require.NotNil(t, finalStub) - if len(testutil.AttributeValueInTraceSpan(t, *finalStub, "requestIDs").AsInt64Slice()) == 0 { - return append(traces, fmt.Sprintf("processResponses(%d)->loaderProcess(0)", responseCount-1)) + if len(testutil.AttributeValueInTraceSpan(t, *finalStub, "requestIDs").AsStringSlice()) == 0 { + return append(traces, fmt.Sprintf("responseMessage(%d)->loaderProcess(0)", responseCount-1)) } return append(traces, fmt.Sprintf("processResponses(%d)->loaderProcess(0)->cacheProcess(0)", responseCount-1)) } diff --git a/requestmanager/asyncloader/asyncloader.go b/requestmanager/asyncloader/asyncloader.go index 5609b4e1..ea478099 100644 --- a/requestmanager/asyncloader/asyncloader.go +++ b/requestmanager/asyncloader/asyncloader.go @@ -111,12 +111,12 @@ func (al *AsyncLoader) ProcessResponse( responses map[graphsync.RequestID]metadata.Metadata, blks []blocks.Block) { - requestIds := make([]int, 0, len(responses)) + requestIds := make([]string, 0, len(responses)) for requestID := range responses { - requestIds = append(requestIds, int(requestID)) + requestIds = append(requestIds, requestID.String()) } ctx, span := otel.Tracer("graphsync").Start(ctx, "loaderProcess", trace.WithAttributes( - attribute.IntSlice("requestIDs", requestIds), + attribute.StringSlice("requestIDs", requestIds), )) defer span.End() diff --git a/requestmanager/asyncloader/responsecache/responsecache.go b/requestmanager/asyncloader/responsecache/responsecache.go index 69c3e902..a490178b 100644 --- a/requestmanager/asyncloader/responsecache/responsecache.go +++ b/requestmanager/asyncloader/responsecache/responsecache.go @@ -91,7 +91,7 @@ func (rc *ResponseCache) ProcessResponse( for requestID, md := range responses { for _, item := range md { - log.Debugf("Traverse link %s on request ID %d", item.Link.String(), requestID) + log.Debugf("Traverse link %s on request ID %s", item.Link.String(), requestID.String()) rc.linkTracker.RecordLinkTraversal(requestID, cidlink.Link{Cid: item.Link}, item.BlockPresent) } } diff --git a/requestmanager/server.go b/requestmanager/server.go index 02ea7019..2eb8dad0 100644 --- a/requestmanager/server.go +++ b/requestmanager/server.go @@ -62,7 +62,7 @@ func (rm *RequestManager) newRequest(parentSpan trace.Span, p peer.ID, root ipld ctx, span := otel.Tracer("graphsync").Start(trace.ContextWithSpan(rm.ctx, parentSpan), "newRequest") defer span.End() - log.Infow("graphsync request initiated", "request id", requestID, "peer", p, "root", root) + log.Infow("graphsync request initiated", "request id", requestID.String(), "peer", p, "root", root) request, hooksResult, err := rm.validateRequest(requestID, p, root, selector, extensions) if err != nil { @@ -114,7 +114,7 @@ func (rm *RequestManager) requestTask(requestID graphsync.RequestID) executor.Re if !ok { return executor.RequestTask{Empty: true} } - log.Infow("graphsync request processing begins", "request id", requestID, "peer", ipr.p, "total time", time.Since(ipr.startTime)) + log.Infow("graphsync request processing begins", "request id", requestID.String(), "peer", ipr.p, "total time", time.Since(ipr.startTime)) var initialRequest bool if ipr.traverser == nil { @@ -227,7 +227,7 @@ func (rm *RequestManager) releaseRequestTask(p peer.ID, task *peertask.Task, err ipr.state = graphsync.Paused return } - log.Infow("graphsync request complete", "request id", requestID, "peer", ipr.p, "total time", time.Since(ipr.startTime)) + log.Infow("graphsync request complete", "request id", requestID.String(), "peer", ipr.p, "total time", time.Since(ipr.startTime)) rm.terminateRequest(requestID, ipr) } @@ -263,13 +263,13 @@ func (rm *RequestManager) cancelOnError(requestID graphsync.RequestID, ipr *inPr func (rm *RequestManager) processResponses(p peer.ID, responses []gsmsg.GraphSyncResponse, blks []blocks.Block) { log.Debugf("beginning processing responses for peer %s", p) - requestIds := make([]int, 0, len(responses)) + requestIds := make([]string, 0, len(responses)) for _, r := range responses { - requestIds = append(requestIds, int(r.RequestID())) + requestIds = append(requestIds, r.RequestID().String()) } ctx, span := otel.Tracer("graphsync").Start(rm.ctx, "processResponses", trace.WithAttributes( attribute.String("peerID", p.Pretty()), - attribute.IntSlice("requestIDs", requestIds), + attribute.StringSlice("requestIDs", requestIds), )) defer span.End() filteredResponses := rm.processExtensions(responses, p) diff --git a/requestmanager/utils.go b/requestmanager/utils.go index dc2a3102..60a94190 100644 --- a/requestmanager/utils.go +++ b/requestmanager/utils.go @@ -13,12 +13,12 @@ func metadataForResponses(responses []gsmsg.GraphSyncResponse) map[graphsync.Req for _, response := range responses { mdRaw, found := response.Extension(graphsync.ExtensionMetadata) if !found { - log.Warnf("Unable to decode metadata in response for request id: %d", response.RequestID()) + log.Warnf("Unable to decode metadata in response for request id: %s", response.RequestID().String()) continue } md, err := metadata.DecodeMetadata(mdRaw) if err != nil { - log.Warnf("Unable to decode metadata in response for request id: %d", response.RequestID()) + log.Warnf("Unable to decode metadata in response for request id: %s", response.RequestID().String()) continue } responseMetadata[response.RequestID()] = md diff --git a/responsemanager/server.go b/responsemanager/server.go index 56456866..1c0b45c2 100644 --- a/responsemanager/server.go +++ b/responsemanager/server.go @@ -59,7 +59,7 @@ func (rm *ResponseManager) terminateRequest(key responseKey) { func (rm *ResponseManager) processUpdate(ctx context.Context, key responseKey, update gsmsg.GraphSyncRequest) { response, ok := rm.inProgressResponses[key] if !ok || response.state == graphsync.CompletingSend { - log.Warnf("received update for non existent request, peer %s, request ID %d", key.p.Pretty(), key.requestID) + log.Warnf("received update for non existent request, peer %s, request ID %s", key.p.Pretty(), key.requestID.String()) return } @@ -215,10 +215,10 @@ func (rm *ResponseManager) processRequests(p peer.ID, requests []gsmsg.GraphSync networkErrorListeners: rm.networkErrorListeners, connManager: rm.connManager, } - log.Infow("graphsync request initiated", "request id", request.ID(), "peer", p, "root", request.Root()) + log.Infow("graphsync request initiated", "request id", request.ID().String(), "peer", p, "root", request.Root()) ipr, ok := rm.inProgressResponses[key] if ok && ipr.state == graphsync.Running { - log.Warnf("there is an identical request already in progress", "request id", request.ID(), "peer", p) + log.Warnf("there is an identical request already in progress", "request id", request.ID().String(), "peer", p) } rm.inProgressResponses[key] = @@ -247,7 +247,7 @@ func (rm *ResponseManager) taskDataForKey(key responseKey) queryexecutor.Respons if !hasResponse || response.state == graphsync.CompletingSend { return queryexecutor.ResponseTask{Empty: true} } - log.Infow("graphsync response processing begins", "request id", key.requestID, "peer", key.p, "total time", time.Since(response.startTime)) + log.Infow("graphsync response processing begins", "request id", key.requestID.String(), "peer", key.p, "total time", time.Since(response.startTime)) if response.loader == nil || response.traverser == nil { loader, traverser, isPaused, err := (&queryPreparer{rm.requestHooks, rm.linkSystem, rm.maxLinksPerRequest}).prepareQuery(response.ctx, key.p, response.request, response.responseStream, response.signals) @@ -298,7 +298,7 @@ func (rm *ResponseManager) finishTask(task *peertask.Task, err error) { response.state = graphsync.Paused return } - log.Infow("graphsync response processing complete (messages stil sending)", "request id", key.requestID, "peer", key.p, "total time", time.Since(response.startTime)) + log.Infow("graphsync response processing complete (messages stil sending)", "request id", key.requestID.String(), "peer", key.p, "total time", time.Since(response.startTime)) if err != nil { response.span.RecordError(err) From 52b33da94faf7503a0ab9207dd788f8da085ff4d Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Wed, 15 Dec 2021 17:11:02 +1100 Subject: [PATCH 4/6] fix(requestid): use string as base type for RequestId --- graphsync.go | 7 ++++--- message/message.go | 13 ++++++------- message/message_test.go | 4 ++-- peerstate/peerstate.go | 12 ++++++------ peerstate/peerstate_test.go | 16 ++++++++-------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/graphsync.go b/graphsync.go index 90d53de7..3e1f2ff1 100644 --- a/graphsync.go +++ b/graphsync.go @@ -13,7 +13,7 @@ import ( ) // RequestID is a unique identifier for a GraphSync request. -type RequestID uuid.UUID +type RequestID string // Tag returns an easy way to identify this request id as a graphsync request (for libp2p connections) func (r RequestID) Tag() string { @@ -22,12 +22,13 @@ func (r RequestID) Tag() string { // String form of a RequestID (should be a well-formed UUIDv4 string) func (r RequestID) String() string { - return uuid.UUID(r).String() + return uuid.Must(uuid.FromBytes([]byte(r))).String() } // Create a new, random RequestID (should be a UUIDv4) func NewRequestID() RequestID { - return RequestID(uuid.New()) + u := uuid.New() + return RequestID(u[:]) } // Priority a priority for a GraphSync request. diff --git a/message/message.go b/message/message.go index 2a180529..15b45ea5 100644 --- a/message/message.go +++ b/message/message.go @@ -3,7 +3,6 @@ package message import ( "encoding/binary" "errors" - "fmt" "io" "github.com/google/uuid" @@ -167,7 +166,7 @@ func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { if err != nil { return GraphSyncMessage{}, err } - id := graphsync.RequestID(uid) + id := graphsync.RequestID(uid[:]) requests[id] = newRequest(id, root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) } @@ -184,7 +183,7 @@ func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { if err != nil { return GraphSyncMessage{}, err } - id := graphsync.RequestID(uid) + id := graphsync.RequestID(uid[:]) responses[id] = newResponse(id, graphsync.ResponseStatusCode(res.Status), exts) } @@ -289,7 +288,7 @@ func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { } } pbm.Requests = append(pbm.Requests, &pb.Message_Request{ - Id: request.id[:], + Id: []byte(request.id), Root: request.root.Bytes(), Selector: selector, Priority: int32(request.priority), @@ -302,7 +301,7 @@ func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { pbm.Responses = make([]*pb.Message_Response, 0, len(gsm.responses)) for _, response := range gsm.responses { pbm.Responses = append(pbm.Responses, &pb.Message_Response{ - Id: response.requestID[:], + Id: []byte(response.requestID), Status: int32(response.status), Extensions: response.extensions, }) @@ -341,11 +340,11 @@ func (gsm GraphSyncMessage) ToNet(w io.Writer) error { func (gsm GraphSyncMessage) Loggable() map[string]interface{} { requests := make([]string, 0, len(gsm.requests)) for _, request := range gsm.requests { - requests = append(requests, fmt.Sprintf("%d", request.id)) + requests = append(requests, request.id.String()) } responses := make([]string, 0, len(gsm.responses)) for _, response := range gsm.responses { - responses = append(responses, fmt.Sprintf("%d", response.requestID)) + responses = append(responses, response.requestID.String()) } return map[string]interface{}{ "requests": requests, diff --git a/message/message_test.go b/message/message_test.go index bc59978c..bda0deae 100644 --- a/message/message_test.go +++ b/message/message_test.go @@ -51,7 +51,7 @@ func TestAppendingRequests(t *testing.T) { require.NoError(t, err) pbRequest := pbMessage.Requests[0] - require.Equal(t, id[:], pbRequest.Id) + require.Equal(t, []byte(id), pbRequest.Id) require.Equal(t, int32(priority), pbRequest.Priority) require.False(t, pbRequest.Cancel) require.False(t, pbRequest.Update) @@ -102,7 +102,7 @@ func TestAppendingResponses(t *testing.T) { pbMessage, err := gsm.ToProto() require.NoError(t, err, "serialize to protobuf errored") pbResponse := pbMessage.Responses[0] - require.Equal(t, requestID[:], pbResponse.Id) + require.Equal(t, []byte(requestID), pbResponse.Id) require.Equal(t, int32(status), pbResponse.Status) require.Equal(t, extension.Data, pbResponse.Extensions["graphsync/awesome"]) diff --git a/peerstate/peerstate.go b/peerstate/peerstate.go index 17c4f9d7..36622f1e 100644 --- a/peerstate/peerstate.go +++ b/peerstate/peerstate.go @@ -30,10 +30,10 @@ func (ps PeerState) Diagnostics() map[graphsync.RequestID][]string { if ok { matchedActiveQueue[id] = struct{}{} if status != graphsync.Running { - diagnostics[id] = append(diagnostics[id], fmt.Sprintf("expected request with id %d in active task queue to be in running state, but was %s", id, status)) + diagnostics[id] = append(diagnostics[id], fmt.Sprintf("expected request with id %s in active task queue to be in running state, but was %s", id.String(), status)) } } else { - diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %d in active task queue but appears to have no tracked state", id)) + diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %s in active task queue but appears to have no tracked state", id.String())) } } for _, id := range ps.TaskQueueState.Pending { @@ -41,21 +41,21 @@ func (ps PeerState) Diagnostics() map[graphsync.RequestID][]string { if ok { matchedPendingQueue[id] = struct{}{} if status != graphsync.Queued { - diagnostics[id] = append(diagnostics[id], fmt.Sprintf("expected request with id %d in pending task queue to be in queued state, but was %s", id, status)) + diagnostics[id] = append(diagnostics[id], fmt.Sprintf("expected request with id %s in pending task queue to be in queued state, but was %s", id.String(), status)) } } else { - diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %d in pending task queue but appears to have no tracked state", id)) + diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %s in pending task queue but appears to have no tracked state", id.String())) } } for id, state := range ps.RequestStates { if state == graphsync.Running { if _, ok := matchedActiveQueue[id]; !ok { - diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %d in running state is not in the active task queue", id)) + diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %s in running state is not in the active task queue", id.String())) } } if state == graphsync.Queued { if _, ok := matchedPendingQueue[id]; !ok { - diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %d in queued state is not in the pending task queue", id)) + diagnostics[id] = append(diagnostics[id], fmt.Sprintf("request with id %s in queued state is not in the pending task queue", id.String())) } } } diff --git a/peerstate/peerstate_test.go b/peerstate/peerstate_test.go index aa4e860a..46e8efd7 100644 --- a/peerstate/peerstate_test.go +++ b/peerstate/peerstate_test.go @@ -47,8 +47,8 @@ func TestDiagnostics(t *testing.T) { Pending: []graphsync.RequestID{requestIDs[2], requestIDs[3]}, }, expectedDiagnostics: map[graphsync.RequestID][]string{ - requestIDs[1]: {fmt.Sprintf("expected request with id %d in active task queue to be in running state, but was queued", requestIDs[1]), fmt.Sprintf("request with id %d in queued state is not in the pending task queue", requestIDs[1])}, - requestIDs[4]: {fmt.Sprintf("expected request with id %d in active task queue to be in running state, but was paused", requestIDs[4])}, + requestIDs[1]: {fmt.Sprintf("expected request with id %s in active task queue to be in running state, but was queued", requestIDs[1].String()), fmt.Sprintf("request with id %s in queued state is not in the pending task queue", requestIDs[1].String())}, + requestIDs[4]: {fmt.Sprintf("expected request with id %s in active task queue to be in running state, but was paused", requestIDs[4].String())}, }, }, "active task with no state": { @@ -63,7 +63,7 @@ func TestDiagnostics(t *testing.T) { Pending: []graphsync.RequestID{requestIDs[2], requestIDs[3]}, }, expectedDiagnostics: map[graphsync.RequestID][]string{ - requestIDs[1]: {fmt.Sprintf("request with id %d in active task queue but appears to have no tracked state", requestIDs[1])}, + requestIDs[1]: {fmt.Sprintf("request with id %s in active task queue but appears to have no tracked state", requestIDs[1].String())}, }, }, "pending task with with incorrect state": { @@ -79,8 +79,8 @@ func TestDiagnostics(t *testing.T) { Pending: []graphsync.RequestID{requestIDs[2], requestIDs[3], requestIDs[4]}, }, expectedDiagnostics: map[graphsync.RequestID][]string{ - requestIDs[3]: {fmt.Sprintf("expected request with id %d in pending task queue to be in queued state, but was running", requestIDs[3]), fmt.Sprintf("request with id %d in running state is not in the active task queue", requestIDs[3])}, - requestIDs[4]: {fmt.Sprintf("expected request with id %d in pending task queue to be in queued state, but was paused", requestIDs[4])}, + requestIDs[3]: {fmt.Sprintf("expected request with id %s in pending task queue to be in queued state, but was running", requestIDs[3].String()), fmt.Sprintf("request with id %s in running state is not in the active task queue", requestIDs[3].String())}, + requestIDs[4]: {fmt.Sprintf("expected request with id %s in pending task queue to be in queued state, but was paused", requestIDs[4].String())}, }, }, "pending task with no state": { @@ -95,7 +95,7 @@ func TestDiagnostics(t *testing.T) { Pending: []graphsync.RequestID{requestIDs[2], requestIDs[3]}, }, expectedDiagnostics: map[graphsync.RequestID][]string{ - requestIDs[3]: {fmt.Sprintf("request with id %d in pending task queue but appears to have no tracked state", requestIDs[3])}, + requestIDs[3]: {fmt.Sprintf("request with id %s in pending task queue but appears to have no tracked state", requestIDs[3].String())}, }, }, "request state running with no active task": { @@ -111,7 +111,7 @@ func TestDiagnostics(t *testing.T) { Pending: []graphsync.RequestID{requestIDs[2], requestIDs[3]}, }, expectedDiagnostics: map[graphsync.RequestID][]string{ - requestIDs[1]: {fmt.Sprintf("request with id %d in running state is not in the active task queue", requestIDs[1])}, + requestIDs[1]: {fmt.Sprintf("request with id %s in running state is not in the active task queue", requestIDs[1].String())}, }, }, "request state queued with no pending task": { @@ -127,7 +127,7 @@ func TestDiagnostics(t *testing.T) { Pending: []graphsync.RequestID{requestIDs[2]}, }, expectedDiagnostics: map[graphsync.RequestID][]string{ - requestIDs[3]: {fmt.Sprintf("request with id %d in queued state is not in the pending task queue", requestIDs[3])}, + requestIDs[3]: {fmt.Sprintf("request with id %s in queued state is not in the pending task queue", requestIDs[3].String())}, }, }, } From d354eff1b4b197e76a1124e483d88743734dcdf7 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Thu, 16 Dec 2021 12:27:39 +1100 Subject: [PATCH 5/6] chore(requestid): wrap requestid string in a struct --- graphsync.go | 20 +++++++++++++++++--- message/message.go | 11 ++++------- message/message_test.go | 4 ++-- responsemanager/responsemanager_test.go | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/graphsync.go b/graphsync.go index 3e1f2ff1..f79463f6 100644 --- a/graphsync.go +++ b/graphsync.go @@ -13,7 +13,7 @@ import ( ) // RequestID is a unique identifier for a GraphSync request. -type RequestID string +type RequestID struct{ string } // Tag returns an easy way to identify this request id as a graphsync request (for libp2p connections) func (r RequestID) Tag() string { @@ -22,13 +22,27 @@ func (r RequestID) Tag() string { // String form of a RequestID (should be a well-formed UUIDv4 string) func (r RequestID) String() string { - return uuid.Must(uuid.FromBytes([]byte(r))).String() + return uuid.Must(uuid.FromBytes([]byte(r.string))).String() +} + +// Byte form of a RequestID +func (r RequestID) Bytes() []byte { + return []byte(r.string) } // Create a new, random RequestID (should be a UUIDv4) func NewRequestID() RequestID { u := uuid.New() - return RequestID(u[:]) + return RequestID{string(u[:])} +} + +// Create a RequestID from a byte slice +func ParseRequestID(b []byte) (RequestID, error) { + _, err := uuid.FromBytes(b) + if err != nil { + return RequestID{}, err + } + return RequestID{string(b)}, nil } // Priority a priority for a GraphSync request. diff --git a/message/message.go b/message/message.go index 15b45ea5..d6a18b80 100644 --- a/message/message.go +++ b/message/message.go @@ -5,7 +5,6 @@ import ( "errors" "io" - "github.com/google/uuid" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime" @@ -162,11 +161,10 @@ func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { if exts == nil { exts = make(map[string][]byte) } - uid, err := uuid.FromBytes(req.Id) + id, err := graphsync.ParseRequestID(req.Id) if err != nil { return GraphSyncMessage{}, err } - id := graphsync.RequestID(uid[:]) requests[id] = newRequest(id, root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) } @@ -179,11 +177,10 @@ func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { if exts == nil { exts = make(map[string][]byte) } - uid, err := uuid.FromBytes(res.Id) + id, err := graphsync.ParseRequestID(res.Id) if err != nil { return GraphSyncMessage{}, err } - id := graphsync.RequestID(uid[:]) responses[id] = newResponse(id, graphsync.ResponseStatusCode(res.Status), exts) } @@ -288,7 +285,7 @@ func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { } } pbm.Requests = append(pbm.Requests, &pb.Message_Request{ - Id: []byte(request.id), + Id: request.id.Bytes(), Root: request.root.Bytes(), Selector: selector, Priority: int32(request.priority), @@ -301,7 +298,7 @@ func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { pbm.Responses = make([]*pb.Message_Response, 0, len(gsm.responses)) for _, response := range gsm.responses { pbm.Responses = append(pbm.Responses, &pb.Message_Response{ - Id: []byte(response.requestID), + Id: response.requestID.Bytes(), Status: int32(response.status), Extensions: response.extensions, }) diff --git a/message/message_test.go b/message/message_test.go index bda0deae..f6bf4d8c 100644 --- a/message/message_test.go +++ b/message/message_test.go @@ -51,7 +51,7 @@ func TestAppendingRequests(t *testing.T) { require.NoError(t, err) pbRequest := pbMessage.Requests[0] - require.Equal(t, []byte(id), pbRequest.Id) + require.Equal(t, id.Bytes(), pbRequest.Id) require.Equal(t, int32(priority), pbRequest.Priority) require.False(t, pbRequest.Cancel) require.False(t, pbRequest.Update) @@ -102,7 +102,7 @@ func TestAppendingResponses(t *testing.T) { pbMessage, err := gsm.ToProto() require.NoError(t, err, "serialize to protobuf errored") pbResponse := pbMessage.Responses[0] - require.Equal(t, []byte(requestID), pbResponse.Id) + require.Equal(t, requestID.Bytes(), pbResponse.Id) require.Equal(t, int32(status), pbResponse.Status) require.Equal(t, extension.Data, pbResponse.Extensions["graphsync/awesome"]) diff --git a/responsemanager/responsemanager_test.go b/responsemanager/responsemanager_test.go index 9328bea4..045512a6 100644 --- a/responsemanager/responsemanager_test.go +++ b/responsemanager/responsemanager_test.go @@ -1321,7 +1321,7 @@ func (td *testData) notifyStatusMessagesSent() { func (td *testData) notifyBlockSendsSent() { td.transactionLk.Lock() - td.notifeePublisher.PublishEvents(notifications.Topic(rand.Int31), []notifications.Event{ + td.notifeePublisher.PublishEvents(notifications.Topic(graphsync.NewRequestID), []notifications.Event{ messagequeue.Event{Name: messagequeue.Sent, Metadata: messagequeue.Metadata{BlockData: td.blkNotifications}}, }) td.blkNotifications = make(map[graphsync.RequestID][]graphsync.BlockData) From 9d9b198a3a490ad3aa1dfd51c8c34d37fe5dc8be Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 11 Jan 2022 13:31:00 +1100 Subject: [PATCH 6/6] feat(libp2p): add v1.0.0 network compatibility --- benchmarks/testnet/virtual.go | 2 +- impl/graphsync_test.go | 243 +++++++++------- message/message.go | 234 +++++----------- message/message_test.go | 28 +- message/messagehandler.go | 413 +++++++++++++++++++++++++++ message/pb/message.pb.go | 5 +- message/pb/message_v1_0_0.pb.go | 479 ++++++++++++++++++++++++++++++++ message/pb/message_v1_0_0.proto | 36 +++ network/interface.go | 3 +- network/libp2p_impl.go | 80 +++++- 10 files changed, 1214 insertions(+), 309 deletions(-) create mode 100644 message/messagehandler.go create mode 100644 message/pb/message_v1_0_0.pb.go create mode 100644 message/pb/message_v1_0_0.proto diff --git a/benchmarks/testnet/virtual.go b/benchmarks/testnet/virtual.go index 024f4dc9..063feca8 100644 --- a/benchmarks/testnet/virtual.go +++ b/benchmarks/testnet/virtual.go @@ -137,7 +137,7 @@ func (n *network) SendMessage( rateLimiters[to] = rateLimiter } - pbMsg, err := mes.ToProto() + pbMsg, err := gsmsg.NewMessageHandler().ToProto(mes) if err != nil { return err } diff --git a/impl/graphsync_test.go b/impl/graphsync_test.go index 8047c4da..18952d27 100644 --- a/impl/graphsync_test.go +++ b/impl/graphsync_test.go @@ -34,6 +34,7 @@ import ( "github.com/ipld/go-ipld-prime/traversal/selector/builder" "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/stretchr/testify/require" @@ -49,6 +50,22 @@ import ( "github.com/ipfs/go-graphsync/testutil" ) +// nil means use the default protocols +// tests data transfer for the following protocol combinations: +// default protocol -> default protocols +// old protocol -> default protocols +// default protocols -> old protocol +// old protocol -> old protocol +var protocolsForTest = map[string]struct { + host1Protocols []protocol.ID + host2Protocols []protocol.ID +}{ + "(v1.1 -> v1.1)": {nil, nil}, + "(v1.0 -> v1.1)": {[]protocol.ID{gsnet.ProtocolGraphsync_1_0_0}, nil}, + "(v1.1 -> v1.0)": {nil, []protocol.ID{gsnet.ProtocolGraphsync_1_0_0}}, + "(v1.0 -> v1.0)": {[]protocol.ID{gsnet.ProtocolGraphsync_1_0_0}, []protocol.ID{gsnet.ProtocolGraphsync_1_0_0}}, +} + func TestMakeRequestToNetwork(t *testing.T) { // create network @@ -269,7 +286,6 @@ func TestGraphsyncRoundTripRequestBudgetRequestor(t *testing.T) { } func TestGraphsyncRoundTripRequestBudgetResponder(t *testing.T) { - // create network ctx := context.Background() ctx, collectTracing := testutil.SetupTracing(ctx) @@ -317,112 +333,115 @@ func TestGraphsyncRoundTripRequestBudgetResponder(t *testing.T) { } func TestGraphsyncRoundTrip(t *testing.T) { - - // create network - ctx := context.Background() - ctx, collectTracing := testutil.SetupTracing(ctx) - ctx, cancel := context.WithTimeout(ctx, 3*time.Second) - defer cancel() - td := newGsTestData(ctx, t) - - // initialize graphsync on first node to make requests - requestor := td.GraphSyncHost1() - - // setup receiving peer to just record message coming in - blockChainLength := 100 - blockChain := testutil.SetupBlockChain(ctx, t, td.persistence2, 100, blockChainLength) - - // initialize graphsync on second node to response to requests - responder := td.GraphSyncHost2() - assertComplete := assertCompletionFunction(responder, 1) - - var receivedResponseData []byte - var receivedRequestData []byte - - requestor.RegisterIncomingResponseHook( - func(p peer.ID, responseData graphsync.ResponseData, hookActions graphsync.IncomingResponseHookActions) { - data, has := responseData.Extension(td.extensionName) - if has { - receivedResponseData = data + for pname, ps := range protocolsForTest { + t.Run(pname, func(t *testing.T) { + // create network + ctx := context.Background() + ctx, collectTracing := testutil.SetupTracing(ctx) + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + td := newOptionalGsTestData(ctx, t, ps.host1Protocols, ps.host2Protocols) + + // initialize graphsync on first node to make requests + requestor := td.GraphSyncHost1() + + // setup receiving peer to just record message coming in + blockChainLength := 100 + blockChain := testutil.SetupBlockChain(ctx, t, td.persistence2, 100, blockChainLength) + + // initialize graphsync on second node to response to requests + responder := td.GraphSyncHost2() + assertComplete := assertCompletionFunction(responder, 1) + + var receivedResponseData []byte + var receivedRequestData []byte + + requestor.RegisterIncomingResponseHook( + func(p peer.ID, responseData graphsync.ResponseData, hookActions graphsync.IncomingResponseHookActions) { + data, has := responseData.Extension(td.extensionName) + if has { + receivedResponseData = data + } + }) + + responder.RegisterIncomingRequestHook(func(p peer.ID, requestData graphsync.RequestData, hookActions graphsync.IncomingRequestHookActions) { + var has bool + receivedRequestData, has = requestData.Extension(td.extensionName) + if !has { + hookActions.TerminateWithError(errors.New("Missing extension")) + } else { + hookActions.SendExtensionData(td.extensionResponse) + } + }) + + finalResponseStatusChan := make(chan graphsync.ResponseStatusCode, 1) + responder.RegisterCompletedResponseListener(func(p peer.ID, request graphsync.RequestData, status graphsync.ResponseStatusCode) { + select { + case finalResponseStatusChan <- status: + default: + } + }) + progressChan, errChan := requestor.Request(ctx, td.host2.ID(), blockChain.TipLink, blockChain.Selector(), td.extension) + + blockChain.VerifyWholeChain(ctx, progressChan) + testutil.VerifyEmptyErrors(ctx, t, errChan) + require.Len(t, td.blockStore1, blockChainLength, "did not store all blocks") + + // verify extension roundtrip + require.Equal(t, td.extensionData, receivedRequestData, "did not receive correct extension request data") + require.Equal(t, td.extensionResponseData, receivedResponseData, "did not receive correct extension response data") + + // verify listener + var finalResponseStatus graphsync.ResponseStatusCode + testutil.AssertReceive(ctx, t, finalResponseStatusChan, &finalResponseStatus, "should receive status") + require.Equal(t, graphsync.RequestCompletedFull, finalResponseStatus) + + drain(requestor) + drain(responder) + assertComplete(ctx, t) + + tracing := collectTracing(t) + + traceStrings := tracing.TracesToStrings() + require.Contains(t, traceStrings, "response(0)->executeTask(0)->processBlock(0)->loadBlock(0)") + require.Contains(t, traceStrings, "response(0)->executeTask(0)->processBlock(0)->sendBlock(0)->processBlockHooks(0)") + require.Contains(t, traceStrings, "request(0)->newRequest(0)") + require.Contains(t, traceStrings, "request(0)->executeTask(0)") + require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") + require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response + require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block + + processUpdateSpan := tracing.FindSpanByTraceString("response(0)") + require.Equal(t, int64(0), testutil.AttributeValueInTraceSpan(t, *processUpdateSpan, "priority").AsInt64()) + require.Equal(t, []string{string(td.extensionName)}, testutil.AttributeValueInTraceSpan(t, *processUpdateSpan, "extensions").AsStringSlice()) + + // each verifyBlock span should link to a cacheProcess span that stored it + + cacheProcessSpans := tracing.FindSpans("cacheProcess") + cacheProcessLinks := make(map[string]int64) + verifyBlockSpans := tracing.FindSpans("verifyBlock") + + for _, verifyBlockSpan := range verifyBlockSpans { + require.Len(t, verifyBlockSpan.Links, 1, "verifyBlock span should have one link") + found := false + for _, cacheProcessSpan := range cacheProcessSpans { + sid := cacheProcessSpan.SpanContext.SpanID().String() + if verifyBlockSpan.Links[0].SpanContext.SpanID().String() == sid { + found = true + cacheProcessLinks[sid] = cacheProcessLinks[sid] + 1 + break + } + } + require.True(t, found, "verifyBlock should link to a known cacheProcess span") } - }) - responder.RegisterIncomingRequestHook(func(p peer.ID, requestData graphsync.RequestData, hookActions graphsync.IncomingRequestHookActions) { - var has bool - receivedRequestData, has = requestData.Extension(td.extensionName) - if !has { - hookActions.TerminateWithError(errors.New("Missing extension")) - } else { - hookActions.SendExtensionData(td.extensionResponse) - } - }) + // each cacheProcess span should be linked to one verifyBlock span per block it stored - finalResponseStatusChan := make(chan graphsync.ResponseStatusCode, 1) - responder.RegisterCompletedResponseListener(func(p peer.ID, request graphsync.RequestData, status graphsync.ResponseStatusCode) { - select { - case finalResponseStatusChan <- status: - default: - } - }) - progressChan, errChan := requestor.Request(ctx, td.host2.ID(), blockChain.TipLink, blockChain.Selector(), td.extension) - - blockChain.VerifyWholeChain(ctx, progressChan) - testutil.VerifyEmptyErrors(ctx, t, errChan) - require.Len(t, td.blockStore1, blockChainLength, "did not store all blocks") - - // verify extension roundtrip - require.Equal(t, td.extensionData, receivedRequestData, "did not receive correct extension request data") - require.Equal(t, td.extensionResponseData, receivedResponseData, "did not receive correct extension response data") - - // verify listener - var finalResponseStatus graphsync.ResponseStatusCode - testutil.AssertReceive(ctx, t, finalResponseStatusChan, &finalResponseStatus, "should receive status") - require.Equal(t, graphsync.RequestCompletedFull, finalResponseStatus) - - drain(requestor) - drain(responder) - assertComplete(ctx, t) - - tracing := collectTracing(t) - - traceStrings := tracing.TracesToStrings() - require.Contains(t, traceStrings, "response(0)->executeTask(0)->processBlock(0)->loadBlock(0)") - require.Contains(t, traceStrings, "response(0)->executeTask(0)->processBlock(0)->sendBlock(0)->processBlockHooks(0)") - require.Contains(t, traceStrings, "request(0)->newRequest(0)") - require.Contains(t, traceStrings, "request(0)->executeTask(0)") - require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") - require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response - require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block - - processUpdateSpan := tracing.FindSpanByTraceString("response(0)") - require.Equal(t, int64(0), testutil.AttributeValueInTraceSpan(t, *processUpdateSpan, "priority").AsInt64()) - require.Equal(t, []string{string(td.extensionName)}, testutil.AttributeValueInTraceSpan(t, *processUpdateSpan, "extensions").AsStringSlice()) - - // each verifyBlock span should link to a cacheProcess span that stored it - - cacheProcessSpans := tracing.FindSpans("cacheProcess") - cacheProcessLinks := make(map[string]int64) - verifyBlockSpans := tracing.FindSpans("verifyBlock") - - for _, verifyBlockSpan := range verifyBlockSpans { - require.Len(t, verifyBlockSpan.Links, 1, "verifyBlock span should have one link") - found := false - for _, cacheProcessSpan := range cacheProcessSpans { - sid := cacheProcessSpan.SpanContext.SpanID().String() - if verifyBlockSpan.Links[0].SpanContext.SpanID().String() == sid { - found = true - cacheProcessLinks[sid] = cacheProcessLinks[sid] + 1 - break + for _, cacheProcessSpan := range cacheProcessSpans { + blockCount := testutil.AttributeValueInTraceSpan(t, cacheProcessSpan, "blockCount").AsInt64() + require.Equal(t, cacheProcessLinks[cacheProcessSpan.SpanContext.SpanID().String()], blockCount, "cacheProcess span should be linked to one verifyBlock span per block it processed") } - } - require.True(t, found, "verifyBlock should link to a known cacheProcess span") - } - - // each cacheProcess span should be linked to one verifyBlock span per block it stored - - for _, cacheProcessSpan := range cacheProcessSpans { - blockCount := testutil.AttributeValueInTraceSpan(t, cacheProcessSpan, "blockCount").AsInt64() - require.Equal(t, cacheProcessLinks[cacheProcessSpan.SpanContext.SpanID().String()], blockCount, "cacheProcess span should be linked to one verifyBlock span per block it processed") + }) } } @@ -1701,6 +1720,10 @@ func assertCancelOrCompleteFunction(gs graphsync.GraphExchange, requestCount int } func newGsTestData(ctx context.Context, t *testing.T) *gsTestData { + return newOptionalGsTestData(ctx, t, nil, nil) +} + +func newOptionalGsTestData(ctx context.Context, t *testing.T, network1Protocols []protocol.ID, network2Protocols []protocol.ID) *gsTestData { t.Helper() td := &gsTestData{ctx: ctx} td.mn = mocknet.New(ctx) @@ -1713,8 +1736,16 @@ func newGsTestData(ctx context.Context, t *testing.T) *gsTestData { err = td.mn.LinkAll() require.NoError(t, err, "error linking hosts") - td.gsnet1 = gsnet.NewFromLibp2pHost(td.host1) - td.gsnet2 = gsnet.NewFromLibp2pHost(td.host2) + opts := make([]gsnet.Option, 0) + if network1Protocols != nil { + opts = append(opts, gsnet.GraphsyncProtocols(network1Protocols)) + } + td.gsnet1 = gsnet.NewFromLibp2pHost(td.host1, opts...) + opts = make([]gsnet.Option, 0) + if network2Protocols != nil { + opts = append(opts, gsnet.GraphsyncProtocols(network2Protocols)) + } + td.gsnet2 = gsnet.NewFromLibp2pHost(td.host2, opts...) td.blockStore1 = make(map[ipld.Link][]byte) td.persistence1 = testutil.NewTestStore(td.blockStore1) td.blockStore2 = make(map[ipld.Link][]byte) @@ -1784,7 +1815,7 @@ func processResponsesTraces(t *testing.T, tracing *testutil.Collector, responseC finalStub := tracing.FindSpanByTraceString(fmt.Sprintf("processResponses(%d)->loaderProcess(0)", responseCount-1)) require.NotNil(t, finalStub) if len(testutil.AttributeValueInTraceSpan(t, *finalStub, "requestIDs").AsStringSlice()) == 0 { - return append(traces, fmt.Sprintf("responseMessage(%d)->loaderProcess(0)", responseCount-1)) + return append(traces, fmt.Sprintf("processResponses(%d)->loaderProcess(0)", responseCount-1)) } return append(traces, fmt.Sprintf("processResponses(%d)->loaderProcess(0)->cacheProcess(0)", responseCount-1)) } diff --git a/message/message.go b/message/message.go index d6a18b80..cdfe3583 100644 --- a/message/message.go +++ b/message/message.go @@ -1,20 +1,17 @@ package message import ( - "encoding/binary" - "errors" + "bytes" + "fmt" "io" + "strings" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime" - pool "github.com/libp2p/go-buffer-pool" - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-msgio" - "google.golang.org/protobuf/proto" + "github.com/ipld/go-ipld-prime/codec/dagjson" "github.com/ipfs/go-graphsync" - "github.com/ipfs/go-graphsync/ipldutil" pb "github.com/ipfs/go-graphsync/message/pb" ) @@ -57,6 +54,25 @@ type GraphSyncRequest struct { isUpdate bool } +// String returns a human-readable form of a GraphSyncRequest +func (gsr GraphSyncRequest) String() string { + var buf bytes.Buffer + dagjson.Encode(gsr.selector, &buf) + ext := make([]string, 0) + for s := range gsr.extensions { + ext = append(ext, s) + } + return fmt.Sprintf("GraphSyncRequest", + gsr.root.String(), + buf.String(), + gsr.priority, + gsr.id.String(), + gsr.isCancel, + gsr.isUpdate, + strings.Join(ext, "|"), + ) +} + // GraphSyncResponse is an struct to capture data on a response sent back // in a GraphSyncMessage. type GraphSyncResponse struct { @@ -65,12 +81,43 @@ type GraphSyncResponse struct { extensions map[string][]byte } +// String returns a human-readable form of a GraphSyncResponse +func (gsr GraphSyncResponse) String() string { + ext := make([]string, 0) + for s := range gsr.extensions { + ext = append(ext, s) + } + return fmt.Sprintf("GraphSyncResponse", + gsr.requestID.String(), + gsr.status, + strings.Join(ext, "|"), + ) +} + +// GraphSyncMessage is the internal representation form of a message sent or +// received over the wire type GraphSyncMessage struct { requests map[graphsync.RequestID]GraphSyncRequest responses map[graphsync.RequestID]GraphSyncResponse blocks map[cid.Cid]blocks.Block } +// String returns a human-readable (multi-line) form of a GraphSyncMessage and +// its contents +func (gsm GraphSyncMessage) String() string { + cts := make([]string, 0) + for _, req := range gsm.requests { + cts = append(cts, req.String()) + } + for _, resp := range gsm.responses { + cts = append(cts, resp.String()) + } + for c := range gsm.blocks { + cts = append(cts, fmt.Sprintf("Block<%s>", c.String())) + } + return fmt.Sprintf("GraphSyncMessage<\n\t%s\n>", strings.Join(cts, ",\n\t")) +} + // NewRequest builds a new Graphsync request func NewRequest(id graphsync.RequestID, root cid.Cid, @@ -135,88 +182,13 @@ func newResponse(requestID graphsync.RequestID, } } -func newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { - requests := make(map[graphsync.RequestID]GraphSyncRequest, len(pbm.GetRequests())) - for _, req := range pbm.Requests { - if req == nil { - return GraphSyncMessage{}, errors.New("request is nil") - } - var root cid.Cid - var err error - if !req.Cancel && !req.Update { - root, err = cid.Cast(req.Root) - if err != nil { - return GraphSyncMessage{}, err - } - } - - var selector ipld.Node - if !req.Cancel && !req.Update { - selector, err = ipldutil.DecodeNode(req.Selector) - if err != nil { - return GraphSyncMessage{}, err - } - } - exts := req.GetExtensions() - if exts == nil { - exts = make(map[string][]byte) - } - id, err := graphsync.ParseRequestID(req.Id) - if err != nil { - return GraphSyncMessage{}, err - } - requests[id] = newRequest(id, root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) - } - - responses := make(map[graphsync.RequestID]GraphSyncResponse, len(pbm.GetResponses())) - for _, res := range pbm.Responses { - if res == nil { - return GraphSyncMessage{}, errors.New("response is nil") - } - exts := res.GetExtensions() - if exts == nil { - exts = make(map[string][]byte) - } - id, err := graphsync.ParseRequestID(res.Id) - if err != nil { - return GraphSyncMessage{}, err - } - responses[id] = newResponse(id, graphsync.ResponseStatusCode(res.Status), exts) - } - - blks := make(map[cid.Cid]blocks.Block, len(pbm.GetData())) - for _, b := range pbm.GetData() { - if b == nil { - return GraphSyncMessage{}, errors.New("block is nil") - } - - pref, err := cid.PrefixFromBytes(b.GetPrefix()) - if err != nil { - return GraphSyncMessage{}, err - } - - c, err := pref.Sum(b.GetData()) - if err != nil { - return GraphSyncMessage{}, err - } - - blk, err := blocks.NewBlockWithCid(b.GetData(), c) - if err != nil { - return GraphSyncMessage{}, err - } - - blks[blk.Cid()] = blk - } - - return GraphSyncMessage{ - requests, responses, blks, - }, nil -} - +// Empty returns true if this message has no actionable content func (gsm GraphSyncMessage) Empty() bool { return len(gsm.blocks) == 0 && len(gsm.requests) == 0 && len(gsm.responses) == 0 } +// Requests returns a copy of the list of GraphSyncRequests in this +// GraphSyncMessage func (gsm GraphSyncMessage) Requests() []GraphSyncRequest { requests := make([]GraphSyncRequest, 0, len(gsm.requests)) for _, request := range gsm.requests { @@ -225,6 +197,8 @@ func (gsm GraphSyncMessage) Requests() []GraphSyncRequest { return requests } +// ResponseCodes returns a list of ResponseStatusCodes contained in the +// responses in this GraphSyncMessage func (gsm GraphSyncMessage) ResponseCodes() map[graphsync.RequestID]graphsync.ResponseStatusCode { codes := make(map[graphsync.RequestID]graphsync.ResponseStatusCode, len(gsm.responses)) for id, response := range gsm.responses { @@ -233,6 +207,8 @@ func (gsm GraphSyncMessage) ResponseCodes() map[graphsync.RequestID]graphsync.Re return codes } +// Responses returns a copy of the list of GraphSyncResponses in this +// GraphSyncMessage func (gsm GraphSyncMessage) Responses() []GraphSyncResponse { responses := make([]GraphSyncResponse, 0, len(gsm.responses)) for _, response := range gsm.responses { @@ -241,6 +217,7 @@ func (gsm GraphSyncMessage) Responses() []GraphSyncResponse { return responses } +// Blocks returns a copy of the list of Blocks in this GraphSyncMessage func (gsm GraphSyncMessage) Blocks() []blocks.Block { bs := make([]blocks.Block, 0, len(gsm.blocks)) for _, block := range gsm.blocks { @@ -249,91 +226,7 @@ func (gsm GraphSyncMessage) Blocks() []blocks.Block { return bs } -// FromNet can read a network stream to deserialized a GraphSyncMessage -func FromNet(r io.Reader) (GraphSyncMessage, error) { - reader := msgio.NewVarintReaderSize(r, network.MessageSizeMax) - return FromMsgReader(reader) -} - -// FromMsgReader can deserialize a protobuf message into a GraphySyncMessage. -func FromMsgReader(r msgio.Reader) (GraphSyncMessage, error) { - msg, err := r.ReadMsg() - if err != nil { - return GraphSyncMessage{}, err - } - - var pb pb.Message - err = proto.Unmarshal(msg, &pb) - r.ReleaseMsg(msg) - if err != nil { - return GraphSyncMessage{}, err - } - - return newMessageFromProto(&pb) -} - -func (gsm GraphSyncMessage) ToProto() (*pb.Message, error) { - pbm := new(pb.Message) - pbm.Requests = make([]*pb.Message_Request, 0, len(gsm.requests)) - for _, request := range gsm.requests { - var selector []byte - var err error - if request.selector != nil { - selector, err = ipldutil.EncodeNode(request.selector) - if err != nil { - return nil, err - } - } - pbm.Requests = append(pbm.Requests, &pb.Message_Request{ - Id: request.id.Bytes(), - Root: request.root.Bytes(), - Selector: selector, - Priority: int32(request.priority), - Cancel: request.isCancel, - Update: request.isUpdate, - Extensions: request.extensions, - }) - } - - pbm.Responses = make([]*pb.Message_Response, 0, len(gsm.responses)) - for _, response := range gsm.responses { - pbm.Responses = append(pbm.Responses, &pb.Message_Response{ - Id: response.requestID.Bytes(), - Status: int32(response.status), - Extensions: response.extensions, - }) - } - - blocks := gsm.Blocks() - pbm.Data = make([]*pb.Message_Block, 0, len(blocks)) - for _, b := range blocks { - pbm.Data = append(pbm.Data, &pb.Message_Block{ - Data: b.RawData(), - Prefix: b.Cid().Prefix().Bytes(), - }) - } - return pbm, nil -} - -func (gsm GraphSyncMessage) ToNet(w io.Writer) error { - msg, err := gsm.ToProto() - if err != nil { - return err - } - size := proto.Size(msg) - buf := pool.Get(size + binary.MaxVarintLen64) - defer pool.Put(buf) - - n := binary.PutUvarint(buf, uint64(size)) - - out, err := proto.MarshalOptions{}.MarshalAppend(buf[:n], msg) - if err != nil { - return err - } - _, err = w.Write(out) - return err -} - +// Loggable returns a simplified, single-line log form of this GraphSyncMessage func (gsm GraphSyncMessage) Loggable() map[string]interface{} { requests := make([]string, 0, len(gsm.requests)) for _, request := range gsm.requests { @@ -349,6 +242,7 @@ func (gsm GraphSyncMessage) Loggable() map[string]interface{} { } } +// Clone returns a shallow copy of this GraphSyncMessage func (gsm GraphSyncMessage) Clone() GraphSyncMessage { requests := make(map[graphsync.RequestID]GraphSyncRequest, len(gsm.requests)) for id, request := range gsm.requests { diff --git a/message/message_test.go b/message/message_test.go index f6bf4d8c..20f73aee 100644 --- a/message/message_test.go +++ b/message/message_test.go @@ -45,7 +45,7 @@ func TestAppendingRequests(t *testing.T) { require.True(t, found) require.Equal(t, extension.Data, extensionData) - pbMessage, err := gsm.ToProto() + pbMessage, err := NewMessageHandler().ToProto(gsm) require.NoError(t, err, "serialize to protobuf errored") selectorEncoded, err := ipldutil.EncodeNode(selector) require.NoError(t, err) @@ -59,7 +59,7 @@ func TestAppendingRequests(t *testing.T) { require.Equal(t, selectorEncoded, pbRequest.Selector) require.Equal(t, map[string][]byte{"graphsync/awesome": extension.Data}, pbRequest.Extensions) - deserialized, err := newMessageFromProto(pbMessage) + deserialized, err := NewMessageHandler().newMessageFromProto(pbMessage) require.NoError(t, err, "deserializing protobuf message errored") deserializedRequests := deserialized.Requests() require.Len(t, deserializedRequests, 1, "did not add request to deserialized message") @@ -99,14 +99,14 @@ func TestAppendingResponses(t *testing.T) { require.True(t, found) require.Equal(t, extension.Data, extensionData) - pbMessage, err := gsm.ToProto() + pbMessage, err := NewMessageHandler().ToProto(gsm) require.NoError(t, err, "serialize to protobuf errored") pbResponse := pbMessage.Responses[0] require.Equal(t, requestID.Bytes(), pbResponse.Id) require.Equal(t, int32(status), pbResponse.Status) require.Equal(t, extension.Data, pbResponse.Extensions["graphsync/awesome"]) - deserialized, err := newMessageFromProto(pbMessage) + deserialized, err := NewMessageHandler().newMessageFromProto(pbMessage) require.NoError(t, err, "deserializing protobuf message errored") deserializedResponses := deserialized.Responses() require.Len(t, deserializedResponses, 1, "did not add response to deserialized message") @@ -132,7 +132,7 @@ func TestAppendBlock(t *testing.T) { m, err := builder.Build() require.NoError(t, err) - pbMessage, err := m.ToProto() + pbMessage, err := NewMessageHandler().ToProto(m) require.NoError(t, err, "serializing to protobuf errored") // assert strings are in proto message @@ -171,9 +171,9 @@ func TestRequestCancel(t *testing.T) { require.True(t, request.IsCancel()) buf := new(bytes.Buffer) - err = gsm.ToNet(buf) + err = NewMessageHandler().ToNet(gsm, buf) require.NoError(t, err, "did not serialize protobuf message") - deserialized, err := FromNet(buf) + deserialized, err := NewMessageHandler().FromNet(buf) require.NoError(t, err, "did not deserialize protobuf message") deserializedRequests := deserialized.Requests() require.Len(t, deserializedRequests, 1, "did not add request to deserialized message") @@ -207,9 +207,9 @@ func TestRequestUpdate(t *testing.T) { require.Equal(t, extension.Data, extensionData) buf := new(bytes.Buffer) - err = gsm.ToNet(buf) + err = NewMessageHandler().ToNet(gsm, buf) require.NoError(t, err, "did not serialize protobuf message") - deserialized, err := FromNet(buf) + deserialized, err := NewMessageHandler().FromNet(buf) require.NoError(t, err, "did not deserialize protobuf message") deserializedRequests := deserialized.Requests() @@ -251,9 +251,9 @@ func TestToNetFromNetEquivalency(t *testing.T) { require.NoError(t, err) buf := new(bytes.Buffer) - err = gsm.ToNet(buf) + err = NewMessageHandler().ToNet(gsm, buf) require.NoError(t, err, "did not serialize protobuf message") - deserialized, err := FromNet(buf) + deserialized, err := NewMessageHandler().FromNet(buf) require.NoError(t, err, "did not deserialize protobuf message") requests := gsm.Requests() @@ -404,15 +404,15 @@ func TestKnownFuzzIssues(t *testing.T) { for _, input := range inputs { //inputAsBytes, err := hex.DecodeString(input) ///require.NoError(t, err) - msg1, err := FromNet(bytes.NewReader([]byte(input))) + msg1, err := NewMessageHandler().FromNet(bytes.NewReader([]byte(input))) if err != nil { continue } buf2 := new(bytes.Buffer) - err = msg1.ToNet(buf2) + err = NewMessageHandler().ToNet(msg1, buf2) require.NoError(t, err) - msg2, err := FromNet(buf2) + msg2, err := NewMessageHandler().FromNet(buf2) require.NoError(t, err) require.Equal(t, msg1, msg2) diff --git a/message/messagehandler.go b/message/messagehandler.go new file mode 100644 index 00000000..cdd6cd11 --- /dev/null +++ b/message/messagehandler.go @@ -0,0 +1,413 @@ +package message + +import ( + "encoding/binary" + "errors" + "io" + "sync" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-graphsync" + "github.com/ipfs/go-graphsync/ipldutil" + pb "github.com/ipfs/go-graphsync/message/pb" + "github.com/ipld/go-ipld-prime" + pool "github.com/libp2p/go-buffer-pool" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-msgio" + "google.golang.org/protobuf/proto" +) + +type v1RequestKey struct { + p peer.ID + id int32 +} + +type MessageHandler struct { + mapLock sync.Mutex + // each host can have multiple peerIDs, so our integer requestID mapping for + // protocol v1.0.0 needs to be a combo of peerID and requestID + fromV1Map map[v1RequestKey]graphsync.RequestID + toV1Map map[graphsync.RequestID]int32 + nextIntId int32 +} + +// NewMessageHandler instantiates a new MessageHandler instance +func NewMessageHandler() *MessageHandler { + return &MessageHandler{ + fromV1Map: make(map[v1RequestKey]graphsync.RequestID), + toV1Map: make(map[graphsync.RequestID]int32), + } +} + +// FromNet can read a network stream to deserialized a GraphSyncMessage +func (mh *MessageHandler) FromNet(r io.Reader) (GraphSyncMessage, error) { + reader := msgio.NewVarintReaderSize(r, network.MessageSizeMax) + return mh.FromMsgReader(reader) +} + +// FromMsgReader can deserialize a protobuf message into a GraphySyncMessage. +func (mh *MessageHandler) FromMsgReader(r msgio.Reader) (GraphSyncMessage, error) { + msg, err := r.ReadMsg() + if err != nil { + return GraphSyncMessage{}, err + } + + var pb pb.Message + err = proto.Unmarshal(msg, &pb) + r.ReleaseMsg(msg) + if err != nil { + return GraphSyncMessage{}, err + } + + return mh.newMessageFromProto(&pb) +} + +// FromMsgReaderV1 can deserialize a v1.0.0 protobuf message into a GraphySyncMessage. +func (mh *MessageHandler) FromMsgReaderV1(p peer.ID, r msgio.Reader) (GraphSyncMessage, error) { + msg, err := r.ReadMsg() + if err != nil { + return GraphSyncMessage{}, err + } + + var pb pb.Message_V1_0_0 + err = proto.Unmarshal(msg, &pb) + r.ReleaseMsg(msg) + if err != nil { + return GraphSyncMessage{}, err + } + + return mh.newMessageFromProtoV1(p, &pb) +} + +// ToProto converts a GraphSyncMessage to its pb.Message equivalent +func (mh *MessageHandler) ToProto(gsm GraphSyncMessage) (*pb.Message, error) { + pbm := new(pb.Message) + pbm.Requests = make([]*pb.Message_Request, 0, len(gsm.requests)) + for _, request := range gsm.requests { + var selector []byte + var err error + if request.selector != nil { + selector, err = ipldutil.EncodeNode(request.selector) + if err != nil { + return nil, err + } + } + pbm.Requests = append(pbm.Requests, &pb.Message_Request{ + Id: request.id.Bytes(), + Root: request.root.Bytes(), + Selector: selector, + Priority: int32(request.priority), + Cancel: request.isCancel, + Update: request.isUpdate, + Extensions: request.extensions, + }) + } + + pbm.Responses = make([]*pb.Message_Response, 0, len(gsm.responses)) + for _, response := range gsm.responses { + pbm.Responses = append(pbm.Responses, &pb.Message_Response{ + Id: response.requestID.Bytes(), + Status: int32(response.status), + Extensions: response.extensions, + }) + } + + blocks := gsm.Blocks() + pbm.Data = make([]*pb.Message_Block, 0, len(blocks)) + for _, b := range blocks { + pbm.Data = append(pbm.Data, &pb.Message_Block{ + Data: b.RawData(), + Prefix: b.Cid().Prefix().Bytes(), + }) + } + return pbm, nil +} + +// ToProtoV1 converts a GraphSyncMessage to its pb.Message_V1_0_0 equivalent +func (mh *MessageHandler) ToProtoV1(p peer.ID, gsm GraphSyncMessage) (*pb.Message_V1_0_0, error) { + mh.mapLock.Lock() + defer mh.mapLock.Unlock() + + pbm := new(pb.Message_V1_0_0) + pbm.Requests = make([]*pb.Message_V1_0_0_Request, 0, len(gsm.requests)) + for _, request := range gsm.requests { + var selector []byte + var err error + if request.selector != nil { + selector, err = ipldutil.EncodeNode(request.selector) + if err != nil { + return nil, err + } + } + rid, err := bytesIdToInt(p, mh.fromV1Map, mh.toV1Map, &mh.nextIntId, request.id.Bytes()) + if err != nil { + return nil, err + } + pbm.Requests = append(pbm.Requests, &pb.Message_V1_0_0_Request{ + Id: rid, + Root: request.root.Bytes(), + Selector: selector, + Priority: int32(request.priority), + Cancel: request.isCancel, + Update: request.isUpdate, + Extensions: request.extensions, + }) + } + + pbm.Responses = make([]*pb.Message_V1_0_0_Response, 0, len(gsm.responses)) + for _, response := range gsm.responses { + rid, err := bytesIdToInt(p, mh.fromV1Map, mh.toV1Map, &mh.nextIntId, response.requestID.Bytes()) + if err != nil { + return nil, err + } + pbm.Responses = append(pbm.Responses, &pb.Message_V1_0_0_Response{ + Id: rid, + Status: int32(response.status), + Extensions: response.extensions, + }) + } + + blocks := gsm.Blocks() + pbm.Data = make([]*pb.Message_V1_0_0_Block, 0, len(blocks)) + for _, b := range blocks { + pbm.Data = append(pbm.Data, &pb.Message_V1_0_0_Block{ + Data: b.RawData(), + Prefix: b.Cid().Prefix().Bytes(), + }) + } + return pbm, nil +} + +// ToNet writes a GraphSyncMessage in its protobuf format to a writer +func (mh *MessageHandler) ToNet(gsm GraphSyncMessage, w io.Writer) error { + msg, err := mh.ToProto(gsm) + if err != nil { + return err + } + size := proto.Size(msg) + buf := pool.Get(size + binary.MaxVarintLen64) + defer pool.Put(buf) + + n := binary.PutUvarint(buf, uint64(size)) + + out, err := proto.MarshalOptions{}.MarshalAppend(buf[:n], msg) + if err != nil { + return err + } + _, err = w.Write(out) + return err +} + +// ToNet writes a GraphSyncMessage in its v1.0.0 protobuf format to a writer +func (mh *MessageHandler) ToNetV1(p peer.ID, gsm GraphSyncMessage, w io.Writer) error { + msg, err := mh.ToProtoV1(p, gsm) + if err != nil { + return err + } + size := proto.Size(msg) + buf := pool.Get(size + binary.MaxVarintLen64) + defer pool.Put(buf) + + n := binary.PutUvarint(buf, uint64(size)) + + out, err := proto.MarshalOptions{}.MarshalAppend(buf[:n], msg) + if err != nil { + return err + } + _, err = w.Write(out) + return err +} + +// Maps a []byte slice form of a RequestID (uuid) to an integer format as used +// by a v1 peer. Inverse of intIdToRequestId() +func bytesIdToInt(p peer.ID, fromV1Map map[v1RequestKey]graphsync.RequestID, toV1Map map[graphsync.RequestID]int32, nextIntId *int32, id []byte) (int32, error) { + rid, err := graphsync.ParseRequestID(id) + if err != nil { + return 0, err + } + iid, ok := toV1Map[rid] + if !ok { + iid = *nextIntId + *nextIntId++ + toV1Map[rid] = iid + fromV1Map[v1RequestKey{p, iid}] = rid + } + return iid, nil +} + +// Maps an integer form of a RequestID as used by a v1 peer to a native (uuid) form. +// Inverse of bytesIdToInt(). +func intIdToRequestId(p peer.ID, fromV1Map map[v1RequestKey]graphsync.RequestID, toV1Map map[graphsync.RequestID]int32, iid int32) (graphsync.RequestID, error) { + key := v1RequestKey{p, iid} + rid, ok := fromV1Map[key] + if !ok { + rid = graphsync.NewRequestID() + fromV1Map[key] = rid + toV1Map[rid] = iid + } + return rid, nil +} + +// Mapping from a pb.Message object to a GraphSyncMessage object +func (mh *MessageHandler) newMessageFromProto(pbm *pb.Message) (GraphSyncMessage, error) { + requests := make(map[graphsync.RequestID]GraphSyncRequest, len(pbm.Requests)) + for _, req := range pbm.Requests { + if req == nil { + return GraphSyncMessage{}, errors.New("request is nil") + } + var root cid.Cid + var err error + if !req.Cancel && !req.Update { + root, err = cid.Cast(req.Root) + if err != nil { + return GraphSyncMessage{}, err + } + } + + var selector ipld.Node + if !req.Cancel && !req.Update { + selector, err = ipldutil.DecodeNode(req.Selector) + if err != nil { + return GraphSyncMessage{}, err + } + } + exts := req.Extensions + if exts == nil { + exts = make(map[string][]byte) + } + id, err := graphsync.ParseRequestID(req.Id) + if err != nil { + return GraphSyncMessage{}, err + } + requests[id] = newRequest(id, root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) + } + + responses := make(map[graphsync.RequestID]GraphSyncResponse, len(pbm.Responses)) + for _, res := range pbm.Responses { + if res == nil { + return GraphSyncMessage{}, errors.New("response is nil") + } + exts := res.Extensions + if exts == nil { + exts = make(map[string][]byte) + } + id, err := graphsync.ParseRequestID(res.Id) + if err != nil { + return GraphSyncMessage{}, err + } + responses[id] = newResponse(id, graphsync.ResponseStatusCode(res.Status), exts) + } + + blks := make(map[cid.Cid]blocks.Block, len(pbm.Data)) + for _, b := range pbm.Data { + if b == nil { + return GraphSyncMessage{}, errors.New("block is nil") + } + + pref, err := cid.PrefixFromBytes(b.GetPrefix()) + if err != nil { + return GraphSyncMessage{}, err + } + + c, err := pref.Sum(b.GetData()) + if err != nil { + return GraphSyncMessage{}, err + } + + blk, err := blocks.NewBlockWithCid(b.GetData(), c) + if err != nil { + return GraphSyncMessage{}, err + } + + blks[blk.Cid()] = blk + } + + return GraphSyncMessage{ + requests, responses, blks, + }, nil +} + +// Mapping from a pb.Message_V1_0_0 object to a GraphSyncMessage object, including +// RequestID (int / uuid) mapping. +func (mh *MessageHandler) newMessageFromProtoV1(p peer.ID, pbm *pb.Message_V1_0_0) (GraphSyncMessage, error) { + mh.mapLock.Lock() + defer mh.mapLock.Unlock() + + requests := make(map[graphsync.RequestID]GraphSyncRequest, len(pbm.Requests)) + for _, req := range pbm.Requests { + if req == nil { + return GraphSyncMessage{}, errors.New("request is nil") + } + var root cid.Cid + var err error + if !req.Cancel && !req.Update { + root, err = cid.Cast(req.Root) + if err != nil { + return GraphSyncMessage{}, err + } + } + + var selector ipld.Node + if !req.Cancel && !req.Update { + selector, err = ipldutil.DecodeNode(req.Selector) + if err != nil { + return GraphSyncMessage{}, err + } + } + exts := req.Extensions + if exts == nil { + exts = make(map[string][]byte) + } + id, err := intIdToRequestId(p, mh.fromV1Map, mh.toV1Map, req.Id) + if err != nil { + return GraphSyncMessage{}, err + } + requests[id] = newRequest(id, root, selector, graphsync.Priority(req.Priority), req.Cancel, req.Update, exts) + } + + responses := make(map[graphsync.RequestID]GraphSyncResponse, len(pbm.Responses)) + for _, res := range pbm.Responses { + if res == nil { + return GraphSyncMessage{}, errors.New("response is nil") + } + exts := res.Extensions + if exts == nil { + exts = make(map[string][]byte) + } + id, err := intIdToRequestId(p, mh.fromV1Map, mh.toV1Map, res.Id) + if err != nil { + return GraphSyncMessage{}, err + } + responses[id] = newResponse(id, graphsync.ResponseStatusCode(res.Status), exts) + } + + blks := make(map[cid.Cid]blocks.Block, len(pbm.Data)) + for _, b := range pbm.Data { + if b == nil { + return GraphSyncMessage{}, errors.New("block is nil") + } + + pref, err := cid.PrefixFromBytes(b.GetPrefix()) + if err != nil { + return GraphSyncMessage{}, err + } + + c, err := pref.Sum(b.GetData()) + if err != nil { + return GraphSyncMessage{}, err + } + + blk, err := blocks.NewBlockWithCid(b.GetData(), c) + if err != nil { + return GraphSyncMessage{}, err + } + + blks[blk.Cid()] = blk + } + + return GraphSyncMessage{ + requests, responses, blks, + }, nil +} diff --git a/message/pb/message.pb.go b/message/pb/message.pb.go index 897027eb..7a55b06f 100644 --- a/message/pb/message.pb.go +++ b/message/pb/message.pb.go @@ -7,11 +7,10 @@ package graphsync_message_pb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/message/pb/message_v1_0_0.pb.go b/message/pb/message_v1_0_0.pb.go new file mode 100644 index 00000000..6cacd3ec --- /dev/null +++ b/message/pb/message_v1_0_0.pb.go @@ -0,0 +1,479 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.1 +// source: message_V1_0_0.proto + +package graphsync_message_pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Message_V1_0_0 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the actual data included in this message + CompleteRequestList bool `protobuf:"varint,1,opt,name=completeRequestList,proto3" json:"completeRequestList,omitempty"` // This request list includes *all* requests, replacing outstanding requests. + Requests []*Message_V1_0_0_Request `protobuf:"bytes,2,rep,name=requests,proto3" json:"requests,omitempty"` // The list of requests. + Responses []*Message_V1_0_0_Response `protobuf:"bytes,3,rep,name=responses,proto3" json:"responses,omitempty"` // The list of responses. + Data []*Message_V1_0_0_Block `protobuf:"bytes,4,rep,name=data,proto3" json:"data,omitempty"` // Blocks related to the responses +} + +func (x *Message_V1_0_0) Reset() { + *x = Message_V1_0_0{} + if protoimpl.UnsafeEnabled { + mi := &file_message_V1_0_0_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message_V1_0_0) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message_V1_0_0) ProtoMessage() {} + +func (x *Message_V1_0_0) ProtoReflect() protoreflect.Message { + mi := &file_message_V1_0_0_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message_V1_0_0.ProtoReflect.Descriptor instead. +func (*Message_V1_0_0) Descriptor() ([]byte, []int) { + return file_message_V1_0_0_proto_rawDescGZIP(), []int{0} +} + +func (x *Message_V1_0_0) GetCompleteRequestList() bool { + if x != nil { + return x.CompleteRequestList + } + return false +} + +func (x *Message_V1_0_0) GetRequests() []*Message_V1_0_0_Request { + if x != nil { + return x.Requests + } + return nil +} + +func (x *Message_V1_0_0) GetResponses() []*Message_V1_0_0_Response { + if x != nil { + return x.Responses + } + return nil +} + +func (x *Message_V1_0_0) GetData() []*Message_V1_0_0_Block { + if x != nil { + return x.Data + } + return nil +} + +type Message_V1_0_0_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // unique id set on the requester side + Root []byte `protobuf:"bytes,2,opt,name=root,proto3" json:"root,omitempty"` // a CID for the root node in the query + Selector []byte `protobuf:"bytes,3,opt,name=selector,proto3" json:"selector,omitempty"` // ipld selector to retrieve + Extensions map[string][]byte `protobuf:"bytes,4,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // aux information. useful for other protocols + Priority int32 `protobuf:"varint,5,opt,name=priority,proto3" json:"priority,omitempty"` // the priority (normalized). default to 1 + Cancel bool `protobuf:"varint,6,opt,name=cancel,proto3" json:"cancel,omitempty"` // whether this cancels a request + Update bool `protobuf:"varint,7,opt,name=update,proto3" json:"update,omitempty"` // whether this requests resumes a previous request +} + +func (x *Message_V1_0_0_Request) Reset() { + *x = Message_V1_0_0_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_message_V1_0_0_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message_V1_0_0_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message_V1_0_0_Request) ProtoMessage() {} + +func (x *Message_V1_0_0_Request) ProtoReflect() protoreflect.Message { + mi := &file_message_V1_0_0_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message_V1_0_0_Request.ProtoReflect.Descriptor instead. +func (*Message_V1_0_0_Request) Descriptor() ([]byte, []int) { + return file_message_V1_0_0_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Message_V1_0_0_Request) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Message_V1_0_0_Request) GetRoot() []byte { + if x != nil { + return x.Root + } + return nil +} + +func (x *Message_V1_0_0_Request) GetSelector() []byte { + if x != nil { + return x.Selector + } + return nil +} + +func (x *Message_V1_0_0_Request) GetExtensions() map[string][]byte { + if x != nil { + return x.Extensions + } + return nil +} + +func (x *Message_V1_0_0_Request) GetPriority() int32 { + if x != nil { + return x.Priority + } + return 0 +} + +func (x *Message_V1_0_0_Request) GetCancel() bool { + if x != nil { + return x.Cancel + } + return false +} + +func (x *Message_V1_0_0_Request) GetUpdate() bool { + if x != nil { + return x.Update + } + return false +} + +type Message_V1_0_0_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // the request id + Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` // a status code. + Extensions map[string][]byte `protobuf:"bytes,3,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // additional data +} + +func (x *Message_V1_0_0_Response) Reset() { + *x = Message_V1_0_0_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_message_V1_0_0_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message_V1_0_0_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message_V1_0_0_Response) ProtoMessage() {} + +func (x *Message_V1_0_0_Response) ProtoReflect() protoreflect.Message { + mi := &file_message_V1_0_0_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message_V1_0_0_Response.ProtoReflect.Descriptor instead. +func (*Message_V1_0_0_Response) Descriptor() ([]byte, []int) { + return file_message_V1_0_0_proto_rawDescGZIP(), []int{0, 1} +} + +func (x *Message_V1_0_0_Response) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Message_V1_0_0_Response) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *Message_V1_0_0_Response) GetExtensions() map[string][]byte { + if x != nil { + return x.Extensions + } + return nil +} + +type Message_V1_0_0_Block struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Prefix []byte `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` // CID prefix (cid version, multicodec and multihash prefix (type + length) + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Message_V1_0_0_Block) Reset() { + *x = Message_V1_0_0_Block{} + if protoimpl.UnsafeEnabled { + mi := &file_message_V1_0_0_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message_V1_0_0_Block) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message_V1_0_0_Block) ProtoMessage() {} + +func (x *Message_V1_0_0_Block) ProtoReflect() protoreflect.Message { + mi := &file_message_V1_0_0_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message_V1_0_0_Block.ProtoReflect.Descriptor instead. +func (*Message_V1_0_0_Block) Descriptor() ([]byte, []int) { + return file_message_V1_0_0_proto_rawDescGZIP(), []int{0, 2} +} + +func (x *Message_V1_0_0_Block) GetPrefix() []byte { + if x != nil { + return x.Prefix + } + return nil +} + +func (x *Message_V1_0_0_Block) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +var File_message_V1_0_0_proto protoreflect.FileDescriptor + +var file_message_V1_0_0_proto_rawDesc = []byte{ + 0x0a, 0x14, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x79, 0x6e, + 0x63, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x62, 0x22, 0xd6, 0x06, 0x0a, + 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x12, + 0x30, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x63, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, + 0x74, 0x12, 0x48, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x4b, 0x0a, 0x09, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x56, 0x31, + 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x79, + 0x6e, 0x63, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xb2, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x12, 0x5c, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x16, + 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x3d, + 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xd0, 0x01, + 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x5d, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x79, + 0x6e, 0x63, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x33, 0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x18, 0x5a, 0x16, 0x2e, 0x3b, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x62, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_message_V1_0_0_proto_rawDescOnce sync.Once + file_message_V1_0_0_proto_rawDescData = file_message_V1_0_0_proto_rawDesc +) + +func file_message_V1_0_0_proto_rawDescGZIP() []byte { + file_message_V1_0_0_proto_rawDescOnce.Do(func() { + file_message_V1_0_0_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_V1_0_0_proto_rawDescData) + }) + return file_message_V1_0_0_proto_rawDescData +} + +var file_message_V1_0_0_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_message_V1_0_0_proto_goTypes = []interface{}{ + (*Message_V1_0_0)(nil), // 0: graphsync.message.pb.Message_V1_0_0 + (*Message_V1_0_0_Request)(nil), // 1: graphsync.message.pb.Message_V1_0_0.Request + (*Message_V1_0_0_Response)(nil), // 2: graphsync.message.pb.Message_V1_0_0.Response + (*Message_V1_0_0_Block)(nil), // 3: graphsync.message.pb.Message_V1_0_0.Block + nil, // 4: graphsync.message.pb.Message_V1_0_0.Request.ExtensionsEntry + nil, // 5: graphsync.message.pb.Message_V1_0_0.Response.ExtensionsEntry +} +var file_message_V1_0_0_proto_depIdxs = []int32{ + 1, // 0: graphsync.message.pb.Message_V1_0_0.requests:type_name -> graphsync.message.pb.Message_V1_0_0.Request + 2, // 1: graphsync.message.pb.Message_V1_0_0.responses:type_name -> graphsync.message.pb.Message_V1_0_0.Response + 3, // 2: graphsync.message.pb.Message_V1_0_0.data:type_name -> graphsync.message.pb.Message_V1_0_0.Block + 4, // 3: graphsync.message.pb.Message_V1_0_0.Request.extensions:type_name -> graphsync.message.pb.Message_V1_0_0.Request.ExtensionsEntry + 5, // 4: graphsync.message.pb.Message_V1_0_0.Response.extensions:type_name -> graphsync.message.pb.Message_V1_0_0.Response.ExtensionsEntry + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_message_V1_0_0_proto_init() } +func file_message_V1_0_0_proto_init() { + if File_message_V1_0_0_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_message_V1_0_0_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message_V1_0_0); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_V1_0_0_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message_V1_0_0_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_V1_0_0_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message_V1_0_0_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_V1_0_0_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message_V1_0_0_Block); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_message_V1_0_0_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_message_V1_0_0_proto_goTypes, + DependencyIndexes: file_message_V1_0_0_proto_depIdxs, + MessageInfos: file_message_V1_0_0_proto_msgTypes, + }.Build() + File_message_V1_0_0_proto = out.File + file_message_V1_0_0_proto_rawDesc = nil + file_message_V1_0_0_proto_goTypes = nil + file_message_V1_0_0_proto_depIdxs = nil +} diff --git a/message/pb/message_v1_0_0.proto b/message/pb/message_v1_0_0.proto new file mode 100644 index 00000000..81f26699 --- /dev/null +++ b/message/pb/message_v1_0_0.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +package graphsync.message.pb; + +option go_package = ".;graphsync_message_pb"; + +message Message_V1_0_0 { + + message Request { + int32 id = 1; // unique id set on the requester side + bytes root = 2; // a CID for the root node in the query + bytes selector = 3; // ipld selector to retrieve + map extensions = 4; // aux information. useful for other protocols + int32 priority = 5; // the priority (normalized). default to 1 + bool cancel = 6; // whether this cancels a request + bool update = 7; // whether this requests resumes a previous request + } + + message Response { + int32 id = 1; // the request id + int32 status = 2; // a status code. + map extensions = 3; // additional data + } + + message Block { + bytes prefix = 1; // CID prefix (cid version, multicodec and multihash prefix (type + length) + bytes data = 2; + } + + // the actual data included in this message + bool completeRequestList = 1; // This request list includes *all* requests, replacing outstanding requests. + repeated Request requests = 2; // The list of requests. + repeated Response responses = 3; // The list of responses. + repeated Block data = 4; // Blocks related to the responses + +} diff --git a/network/interface.go b/network/interface.go index 2277cc08..413050d7 100644 --- a/network/interface.go +++ b/network/interface.go @@ -12,7 +12,8 @@ import ( var ( // ProtocolGraphsync is the protocol identifier for graphsync messages - ProtocolGraphsync protocol.ID = "/ipfs/graphsync/1.0.0" + ProtocolGraphsync_1_0_0 protocol.ID = "/ipfs/graphsync/1.0.0" + ProtocolGraphsync_1_1_0 protocol.ID = "/ipfs/graphsync/1.1.0" ) // GraphSyncNetwork provides network connectivity for GraphSync. diff --git a/network/libp2p_impl.go b/network/libp2p_impl.go index 0b6a9a6c..12e7b891 100644 --- a/network/libp2p_impl.go +++ b/network/libp2p_impl.go @@ -10,6 +10,7 @@ import ( "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" "github.com/libp2p/go-msgio" ma "github.com/multiformats/go-multiaddr" @@ -20,10 +21,27 @@ var log = logging.Logger("graphsync_network") var sendMessageTimeout = time.Minute * 10 +// Option is an option for configuring the libp2p storage market network +type Option func(*libp2pGraphSyncNetwork) + +// DataTransferProtocols OVERWRITES the default libp2p protocols we use for +// graphsync with the specified protocols +func GraphsyncProtocols(protocols []protocol.ID) Option { + return func(gsnet *libp2pGraphSyncNetwork) { + gsnet.setProtocols(protocols) + } +} + // NewFromLibp2pHost returns a GraphSyncNetwork supported by underlying Libp2p host. -func NewFromLibp2pHost(host host.Host) GraphSyncNetwork { +func NewFromLibp2pHost(host host.Host, options ...Option) GraphSyncNetwork { graphSyncNetwork := libp2pGraphSyncNetwork{ - host: host, + host: host, + messageHandler: gsmsg.NewMessageHandler(), + protocols: []protocol.ID{ProtocolGraphsync_1_1_0, ProtocolGraphsync_1_0_0}, + } + + for _, option := range options { + option(&graphSyncNetwork) } return &graphSyncNetwork @@ -34,12 +52,15 @@ func NewFromLibp2pHost(host host.Host) GraphSyncNetwork { type libp2pGraphSyncNetwork struct { host host.Host // inbound messages from the network are forwarded to the receiver - receiver Receiver + receiver Receiver + messageHandler *gsmsg.MessageHandler + protocols []protocol.ID } type streamMessageSender struct { - s network.Stream - opts MessageSenderOpts + s network.Stream + opts MessageSenderOpts + messageHandler *gsmsg.MessageHandler } func (s *streamMessageSender) Close() error { @@ -51,10 +72,10 @@ func (s *streamMessageSender) Reset() error { } func (s *streamMessageSender) SendMsg(ctx context.Context, msg gsmsg.GraphSyncMessage) error { - return msgToStream(ctx, s.s, msg, s.opts.SendTimeout) + return msgToStream(ctx, s.s, s.messageHandler, msg, s.opts.SendTimeout) } -func msgToStream(ctx context.Context, s network.Stream, msg gsmsg.GraphSyncMessage, timeout time.Duration) error { +func msgToStream(ctx context.Context, s network.Stream, mh *gsmsg.MessageHandler, msg gsmsg.GraphSyncMessage, timeout time.Duration) error { log.Debugf("Outgoing message with %d requests, %d responses, and %d blocks", len(msg.Requests()), len(msg.Responses()), len(msg.Blocks())) @@ -67,8 +88,13 @@ func msgToStream(ctx context.Context, s network.Stream, msg gsmsg.GraphSyncMessa } switch s.Protocol() { - case ProtocolGraphsync: - if err := msg.ToNet(s); err != nil { + case ProtocolGraphsync_1_0_0: + if err := mh.ToNetV1(s.Conn().RemotePeer(), msg, s); err != nil { + log.Debugf("error: %s", err) + return err + } + case ProtocolGraphsync_1_1_0: + if err := mh.ToNet(msg, s); err != nil { log.Debugf("error: %s", err) return err } @@ -88,11 +114,15 @@ func (gsnet *libp2pGraphSyncNetwork) NewMessageSender(ctx context.Context, p pee return nil, err } - return &streamMessageSender{s: s, opts: setDefaults(opts)}, nil + return &streamMessageSender{ + s: s, + opts: setDefaults(opts), + messageHandler: gsnet.messageHandler, + }, nil } func (gsnet *libp2pGraphSyncNetwork) newStreamToPeer(ctx context.Context, p peer.ID) (network.Stream, error) { - return gsnet.host.NewStream(ctx, p, ProtocolGraphsync) + return gsnet.host.NewStream(ctx, p, gsnet.protocols...) } func (gsnet *libp2pGraphSyncNetwork) SendMessage( @@ -105,7 +135,7 @@ func (gsnet *libp2pGraphSyncNetwork) SendMessage( return err } - if err = msgToStream(ctx, s, outgoing, sendMessageTimeout); err != nil { + if err = msgToStream(ctx, s, gsnet.messageHandler, outgoing, sendMessageTimeout); err != nil { _ = s.Reset() return err } @@ -115,7 +145,9 @@ func (gsnet *libp2pGraphSyncNetwork) SendMessage( func (gsnet *libp2pGraphSyncNetwork) SetDelegate(r Receiver) { gsnet.receiver = r - gsnet.host.SetStreamHandler(ProtocolGraphsync, gsnet.handleNewStream) + for _, p := range gsnet.protocols { + gsnet.host.SetStreamHandler(p, gsnet.handleNewStream) + } gsnet.host.Network().Notify((*libp2pGraphSyncNotifee)(gsnet)) } @@ -134,7 +166,16 @@ func (gsnet *libp2pGraphSyncNetwork) handleNewStream(s network.Stream) { reader := msgio.NewVarintReaderSize(s, network.MessageSizeMax) for { - received, err := gsmsg.FromMsgReader(reader) + var received gsmsg.GraphSyncMessage + var err error + switch s.Protocol() { + case ProtocolGraphsync_1_0_0: + received, err = gsnet.messageHandler.FromMsgReaderV1(s.Conn().RemotePeer(), reader) + case ProtocolGraphsync_1_1_0: + received, err = gsnet.messageHandler.FromMsgReader(reader) + default: + err = fmt.Errorf("unexpected protocol version %s", s.Protocol()) + } p := s.Conn().RemotePeer() if err != nil { @@ -148,6 +189,7 @@ func (gsnet *libp2pGraphSyncNetwork) handleNewStream(s network.Stream) { ctx := context.Background() log.Debugf("graphsync net handleNewStream from %s", s.Conn().RemotePeer()) + gsnet.receiver.ReceiveMessage(ctx, p, received) } } @@ -156,6 +198,16 @@ func (gsnet *libp2pGraphSyncNetwork) ConnectionManager() ConnManager { return gsnet.host.ConnManager() } +func (gsnet *libp2pGraphSyncNetwork) setProtocols(protocols []protocol.ID) { + gsnet.protocols = make([]protocol.ID, 0) + for _, proto := range protocols { + switch proto { + case ProtocolGraphsync_1_0_0, ProtocolGraphsync_1_1_0: + gsnet.protocols = append([]protocol.ID{}, proto) + } + } +} + type libp2pGraphSyncNotifee libp2pGraphSyncNetwork func (nn *libp2pGraphSyncNotifee) libp2pGraphSyncNetwork() *libp2pGraphSyncNetwork {