diff --git a/common/deliver/deliver.go b/common/deliver/deliver.go index d42687edaaa..e87a85e2548 100644 --- a/common/deliver/deliver.go +++ b/common/deliver/deliver.go @@ -328,7 +328,7 @@ func (h *Handler) deliverBlocks(ctx context.Context, srv *Server, envelope *cb.E logger.Debugf("[channel: %s] Delivering block [%d] for (%p) for %s", chdr.ChannelId, block.Header.Number, seekInfo, addr) - if seekInfo.ContentType == ab.SeekInfo_HEADER_WITH_SIG { + if seekInfo.ContentType == ab.SeekInfo_HEADER_WITH_SIG && !protoutil.IsConfigBlock(block) { block.Data = nil } diff --git a/common/deliver/deliver_test.go b/common/deliver/deliver_test.go index ed8aba91d86..f3c67d570ae 100644 --- a/common/deliver/deliver_test.go +++ b/common/deliver/deliver_test.go @@ -541,6 +541,73 @@ var _ = Describe("Deliver", func() { }) }) + Context("when seek info is configured to header with sig content type and block can be a config block", func() { + BeforeEach(func() { + seekInfo = &ab.SeekInfo{ + Start: &ab.SeekPosition{}, + Stop: seekNewest, + ContentType: ab.SeekInfo_HEADER_WITH_SIG, + } + fakeBlockReader.HeightReturns(4) + fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) { + nxtCallCount := fakeBlockIterator.NextCallCount() + block := &cb.Block{ + Header: &cb.BlockHeader{Number: uint64(nxtCallCount)}, + Metadata: &cb.BlockMetadata{Metadata: [][]byte{{3}, {4}}}, + } + if nxtCallCount == 1 || nxtCallCount == 3 { + block.Data = &cb.BlockData{Data: [][]byte{{1}, {2}}} + } else { + channelHeader = protoutil.MakeChannelHeader(cb.HeaderType_CONFIG, int32(1), "chain-1", 0) + payloadSignatureHeader := protoutil.MakeSignatureHeader(nil, make([]byte, 24)) + protoutil.SetTxID(channelHeader, payloadSignatureHeader) + payloadHeader := protoutil.MakePayloadHeader(channelHeader, payloadSignatureHeader) + cg := protoutil.NewConfigGroup() + payload := &cb.Payload{Header: payloadHeader, Data: protoutil.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: cg}})} + envelope := &cb.Envelope{Payload: protoutil.MarshalOrPanic(payload), Signature: nil} + + block.Data = &cb.BlockData{Data: [][]byte{protoutil.MarshalOrPanic(envelope)}} + block.Header.DataHash = nil + } + return block, cb.Status_SUCCESS + } + }) + + It("sends blocks with non nil Data", func() { + err := handler.Handle(context.Background(), server) + Expect(err).NotTo(HaveOccurred()) + Expect(fakeBlockReader.IteratorCallCount()).To(Equal(1)) + start := fakeBlockReader.IteratorArgsForCall(0) + Expect(start).To(Equal(&ab.SeekPosition{})) + Expect(fakeBlockIterator.NextCallCount()).To(Equal(3)) + Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(3)) + for i := 0; i < fakeResponseSender.SendBlockResponseCallCount(); i++ { + b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(i) + if i+1 == 1 || i+1 == 3 { + Expect(b).To(Equal(&cb.Block{ + Header: &cb.BlockHeader{Number: uint64(i + 1)}, + Data: nil, + Metadata: &cb.BlockMetadata{Metadata: [][]byte{{3}, {4}}}, + })) + } else { + payloadSignatureHeader := protoutil.MakeSignatureHeader(nil, make([]byte, 24)) + protoutil.SetTxID(channelHeader, payloadSignatureHeader) + payloadHeader := protoutil.MakePayloadHeader(channelHeader, payloadSignatureHeader) + cg := protoutil.NewConfigGroup() + payload := &cb.Payload{Header: payloadHeader, Data: protoutil.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: cg}})} + envelope := &cb.Envelope{Payload: protoutil.MarshalOrPanic(payload), Signature: nil} + blk := &cb.Block{ + Header: &cb.BlockHeader{Number: uint64(i + 1)}, + Data: &cb.BlockData{Data: [][]byte{protoutil.MarshalOrPanic(envelope)}}, + Metadata: &cb.BlockMetadata{Metadata: [][]byte{{3}, {4}}}, + } + Expect(b).To(Equal(blk)) + Expect(b.Data.Data).NotTo(BeNil()) + } + } + }) + }) + Context("when filtered blocks are requested", func() { var fakeResponseSender *mock.FilteredResponseSender diff --git a/protoutil/commonutils.go b/protoutil/commonutils.go index 9a9bc964ebf..bd948e07ed1 100644 --- a/protoutil/commonutils.go +++ b/protoutil/commonutils.go @@ -188,7 +188,16 @@ func SignOrPanic(signer identity.Signer, msg []byte) []byte { // IsConfigBlock validates whenever given block contains configuration // update transaction func IsConfigBlock(block *cb.Block) bool { - envelope, err := ExtractEnvelope(block, 0) + if block.Data == nil { + return false + } + + if len(block.Data.Data) != 1 { + return false + } + + marshaledEnvelope := block.Data.Data[0] + envelope, err := GetEnvelopeFromBlock(marshaledEnvelope) if err != nil { return false } diff --git a/protoutil/commonutils_test.go b/protoutil/commonutils_test.go index 3abb286fa78..4c59e32daff 100644 --- a/protoutil/commonutils_test.go +++ b/protoutil/commonutils_test.go @@ -422,6 +422,22 @@ func TestIsConfigBlock(t *testing.T) { result = IsConfigBlock(block) require.False(t, result, "IsConfigBlock returns false for blocks with MESSAGE envelope") + + // scenario 4: Data with more than one tx + result = IsConfigBlock(&cb.Block{ + Header: nil, + Data: &cb.BlockData{Data: [][]byte{{1, 2, 3, 4}, {1, 2, 3, 4}}}, + Metadata: nil, + }) + require.False(t, result, "IsConfigBlock returns false for blocks with more than one transaction") + + // scenario 5: nil data + result = IsConfigBlock(&cb.Block{ + Header: nil, + Data: nil, + Metadata: nil, + }) + require.False(t, result, "IsConfigBlock returns false for blocks with no data") } func TestEnvelopeToConfigUpdate(t *testing.T) {