Skip to content

Commit c1e6fb4

Browse files
committed
[FAB-1161] Push genesis block upon orderer init
Before this changeset, the genesis block would be pushed with the first broadcast request. A side-effect of this is that any deliver requests reaching the orderer before the first broadcast request would panic. This changeset fixes that by having the orderer push the genesis block (and create the respective Kafka topic) upon initialization. Change-Id: Ice5d84b45bcd1565f916f8ac13073380090e6036 Signed-off-by: Kostas Christidis <[email protected]>
1 parent 5ce0d90 commit c1e6fb4

File tree

3 files changed

+46
-55
lines changed

3 files changed

+46
-55
lines changed

orderer/kafka/broadcast.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,32 @@ type broadcasterImpl struct {
4646
prevHash []byte
4747
}
4848

49-
type broadcastSessionResponder struct {
50-
queue chan *ab.BroadcastResponse
51-
}
52-
5349
func newBroadcaster(conf *config.TopLevel) Broadcaster {
5450
genesisBlock, _ := static.New().GenesisBlock()
55-
return &broadcasterImpl{
51+
52+
b := &broadcasterImpl{
5653
producer: newProducer(conf),
5754
config: conf,
5855
batchChan: make(chan *cb.Envelope, conf.General.BatchSize),
5956
messages: genesisBlock.GetData().Data,
6057
nextNumber: 0,
6158
}
62-
}
6359

64-
// Broadcast receives ordering requests by clients and sends back an
65-
// acknowledgement for each received message in order, indicating
66-
// success or type of failure
67-
func (b *broadcasterImpl) Broadcast(stream ab.AtomicBroadcast_BroadcastServer) error {
6860
b.once.Do(func() {
6961
// Send the genesis block to create the topic
7062
// otherwise consumers will throw an exception.
7163
b.sendBlock()
7264
// Spawn the goroutine that cuts blocks
7365
go b.cutBlock(b.config.General.BatchTimeout, b.config.General.BatchSize)
7466
})
67+
68+
return b
69+
}
70+
71+
// Broadcast receives ordering requests by clients and sends back an
72+
// acknowledgement for each received message in order, indicating
73+
// success or type of failure
74+
func (b *broadcasterImpl) Broadcast(stream ab.AtomicBroadcast_BroadcastServer) error {
7575
return b.recvRequests(stream)
7676
}
7777

orderer/kafka/broadcast_mock_test.go

+29-1
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,47 @@ limitations under the License.
1717
package kafka
1818

1919
import (
20+
"fmt"
2021
"testing"
2122

23+
"github.com/golang/protobuf/proto"
24+
"github.com/hyperledger/fabric/orderer/common/bootstrap/static"
2225
"github.com/hyperledger/fabric/orderer/config"
2326
cb "github.com/hyperledger/fabric/protos/common"
2427
)
2528

2629
func mockNewBroadcaster(t *testing.T, conf *config.TopLevel, seek int64, disk chan []byte) Broadcaster {
30+
genesisBlock, _ := static.New().GenesisBlock()
31+
wait := make(chan struct{})
32+
2733
mb := &broadcasterImpl{
2834
producer: mockNewProducer(t, conf, seek, disk),
2935
config: conf,
3036
batchChan: make(chan *cb.Envelope, conf.General.BatchSize),
31-
messages: [][]byte{[]byte("checkpoint")},
37+
messages: genesisBlock.GetData().Data,
3238
nextNumber: uint64(seek),
3339
}
40+
41+
go func() {
42+
rxBlockBytes := <-disk
43+
rxBlock := &cb.Block{}
44+
if err := proto.Unmarshal(rxBlockBytes, rxBlock); err != nil {
45+
panic(err)
46+
}
47+
if !proto.Equal(rxBlock.GetData(), genesisBlock.GetData()) {
48+
panic(fmt.Errorf("Broadcaster not functioning as expected"))
49+
}
50+
close(wait)
51+
}()
52+
53+
mb.once.Do(func() {
54+
// Send the genesis block to create the topic
55+
// otherwise consumers will throw an exception.
56+
mb.sendBlock()
57+
// Spawn the goroutine that cuts blocks
58+
go mb.cutBlock(mb.config.General.BatchTimeout, mb.config.General.BatchSize)
59+
})
60+
<-wait
61+
3462
return mb
3563
}

orderer/kafka/broadcast_test.go

+7-44
Original file line numberDiff line numberDiff line change
@@ -17,46 +17,15 @@ limitations under the License.
1717
package kafka
1818

1919
import (
20-
"bytes"
2120
"strconv"
21+
"sync"
2222
"testing"
2323
"time"
2424

2525
"github.com/golang/protobuf/proto"
2626
cb "github.com/hyperledger/fabric/protos/common"
2727
)
2828

29-
func TestBroadcastInit(t *testing.T) {
30-
disk := make(chan []byte)
31-
32-
mb := mockNewBroadcaster(t, testConf, oldestOffset, disk)
33-
defer testClose(t, mb)
34-
35-
mbs := newMockBroadcastStream(t)
36-
go func() {
37-
if err := mb.Broadcast(mbs); err != nil {
38-
t.Fatal("Broadcast error:", err)
39-
}
40-
}()
41-
42-
for {
43-
select {
44-
case in := <-disk:
45-
block := new(cb.Block)
46-
err := proto.Unmarshal(in, block)
47-
if err != nil {
48-
t.Fatal("Expected a block on the broker's disk")
49-
}
50-
if !(bytes.Equal(block.Data.Data[0], []byte("checkpoint"))) {
51-
t.Fatal("Expected first block to be a checkpoint")
52-
}
53-
return
54-
case <-time.After(500 * time.Millisecond):
55-
t.Fatal("Should have received the initialization block by now")
56-
}
57-
}
58-
}
59-
6029
func TestBroadcastResponse(t *testing.T) {
6130
disk := make(chan []byte)
6231

@@ -70,8 +39,6 @@ func TestBroadcastResponse(t *testing.T) {
7039
}
7140
}()
7241

73-
<-disk // We tested the checkpoint block in a previous test, so we can ignore it now
74-
7542
// Send a message to the orderer
7643
go func() {
7744
mbs.incoming <- &cb.Envelope{Payload: []byte("single message")}
@@ -103,8 +70,6 @@ func TestBroadcastBatch(t *testing.T) {
10370
}
10471
}()
10572

106-
<-disk // We tested the checkpoint block in a previous test, so we can ignore it now
107-
10873
// Pump a batch's worth of messages into the system
10974
go func() {
11075
for i := 0; i < int(testConf.General.BatchSize); i++ {
@@ -158,8 +123,6 @@ func TestBroadcastBatch(t *testing.T) {
158123
}
159124
}()
160125
161-
<-disk // We tested the checkpoint block in a previous test, so we can ignore it now
162-
163126
// Force the response queue to overflow by blocking the broadcast stream's Send() method
164127
mbs.closed = true
165128
defer func() { mbs.closed = false }()
@@ -201,8 +164,6 @@ func TestBroadcastIncompleteBatch(t *testing.T) {
201164
}
202165
}()
203166

204-
<-disk // We tested the checkpoint block in a previous test, so we can ignore it now
205-
206167
// Pump less than batchSize messages into the system
207168
go func() {
208169
for i := 0; i < messageCount; i++ {
@@ -239,6 +200,8 @@ func TestBroadcastConsecutiveIncompleteBatches(t *testing.T) {
239200
t.Skip("Skipping test as it requires a batchsize > 1")
240201
}
241202

203+
var once sync.Once
204+
242205
messageCount := int(testConf.General.BatchSize) - 1
243206

244207
disk := make(chan []byte)
@@ -254,8 +217,6 @@ func TestBroadcastConsecutiveIncompleteBatches(t *testing.T) {
254217
}()
255218

256219
for i := 0; i < 2; i++ {
257-
<-disk // Checkpoint block in first pass, first incomplete block in second pass -- both tested elsewhere
258-
259220
// Pump less than batchSize messages into the system
260221
go func() {
261222
for i := 0; i < messageCount; i++ {
@@ -268,6 +229,10 @@ func TestBroadcastConsecutiveIncompleteBatches(t *testing.T) {
268229
for i := 0; i < messageCount; i++ {
269230
<-mbs.outgoing
270231
}
232+
233+
once.Do(func() {
234+
<-disk // First incomplete block, tested elsewhere
235+
})
271236
}
272237

273238
for {
@@ -301,8 +266,6 @@ func TestBroadcastBatchAndQuitEarly(t *testing.T) {
301266
}
302267
}()
303268

304-
<-disk // We tested the checkpoint block in a previous test, so we can ignore it now
305-
306269
// Pump a batch's worth of messages into the system
307270
go func() {
308271
for i := 0; i < int(testConf.General.BatchSize); i++ {

0 commit comments

Comments
 (0)