Skip to content

Commit f806802

Browse files
author
Jason Yellick
committed
[FAB-1521] Fix rawledger to support restart
https://jira.hyperledger.org/browse/FAB-1521 The rawledger interface was originally implemented as a single chain initialized with a genesis block. This causes problems on restart because a newer genesis block may already exist and passing the genesis block becomes nonsensical. This changeset changes this behavior to intialize no ledgers on factory creation, and to allow the use of Append for blocks, rather than transaction sets. This satisfies a secondary goal of allowing block creation without block commit, as is required by the SBFT flow of consenting on blocks, rather than on transactions. Change-Id: Icbb0bb1a80f9e04861f4302966709f1752068961 Signed-off-by: Jason Yellick <[email protected]>
1 parent 4896a04 commit f806802

17 files changed

+295
-162
lines changed

orderer/common/deliver/deliver_test.go

+22-8
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,15 @@ func (mcs *mockSupport) Reader() rawledger.Reader {
9191
return mcs.ledger
9292
}
9393

94+
func NewRAMLedger() rawledger.ReadWriter {
95+
rlf := ramledger.New(ledgerSize + 1)
96+
rl, _ := rlf.GetOrCreate(provisional.TestChainID)
97+
rl.Append(genesisBlock)
98+
return rl
99+
}
100+
94101
func newMockMultichainManager() *mockSupportManager {
95-
_, rl := ramledger.New(ledgerSize+1, genesisBlock)
102+
rl := NewRAMLedger()
96103
mm := &mockSupportManager{
97104
chains: make(map[string]*mockSupport),
98105
}
@@ -112,7 +119,8 @@ func seekSpecified(number uint64) *ab.SeekPosition {
112119
func TestOldestSeek(t *testing.T) {
113120
mm := newMockMultichainManager()
114121
for i := 1; i < ledgerSize; i++ {
115-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil)
122+
ledger := mm.chains[string(systemChainID)].ledger
123+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
116124
}
117125

118126
m := newMockD()
@@ -150,7 +158,8 @@ func TestOldestSeek(t *testing.T) {
150158
func TestNewestSeek(t *testing.T) {
151159
mm := newMockMultichainManager()
152160
for i := 1; i < ledgerSize; i++ {
153-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil)
161+
ledger := mm.chains[string(systemChainID)].ledger
162+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
154163
}
155164

156165
m := newMockD()
@@ -181,7 +190,8 @@ func TestNewestSeek(t *testing.T) {
181190
func TestSpecificSeek(t *testing.T) {
182191
mm := newMockMultichainManager()
183192
for i := 1; i < ledgerSize; i++ {
184-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil)
193+
ledger := mm.chains[string(systemChainID)].ledger
194+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
185195
}
186196

187197
m := newMockD()
@@ -218,7 +228,8 @@ func TestSpecificSeek(t *testing.T) {
218228
func TestBadSeek(t *testing.T) {
219229
mm := newMockMultichainManager()
220230
for i := 1; i < ledgerSize; i++ {
221-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil)
231+
ledger := mm.chains[string(systemChainID)].ledger
232+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
222233
}
223234

224235
m := newMockD()
@@ -242,7 +253,8 @@ func TestBadSeek(t *testing.T) {
242253
func TestFailFastSeek(t *testing.T) {
243254
mm := newMockMultichainManager()
244255
for i := 1; i < ledgerSize; i++ {
245-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil)
256+
ledger := mm.chains[string(systemChainID)].ledger
257+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
246258
}
247259

248260
m := newMockD()
@@ -275,7 +287,8 @@ func TestFailFastSeek(t *testing.T) {
275287
func TestBlockingSeek(t *testing.T) {
276288
mm := newMockMultichainManager()
277289
for i := 1; i < ledgerSize; i++ {
278-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil)
290+
ledger := mm.chains[string(systemChainID)].ledger
291+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
279292
}
280293

281294
m := newMockD()
@@ -301,7 +314,8 @@ func TestBlockingSeek(t *testing.T) {
301314
case <-time.After(50 * time.Millisecond):
302315
}
303316

304-
mm.chains[string(systemChainID)].ledger.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", ledgerSize+1))}}, nil)
317+
ledger := mm.chains[string(systemChainID)].ledger
318+
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", ledgerSize+1))}}, nil))
305319

306320
select {
307321
case deliverReply := <-m.sendChan:

orderer/main.go

+40-16
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ import (
3737
"github.com/hyperledger/fabric/orderer/solo"
3838
cb "github.com/hyperledger/fabric/protos/common"
3939
ab "github.com/hyperledger/fabric/protos/orderer"
40+
"github.com/hyperledger/fabric/protos/utils"
4041

4142
"github.com/Shopify/sarama"
42-
"github.com/op/go-logging"
43-
43+
logging "github.com/op/go-logging"
4444
"google.golang.org/grpc"
4545
)
4646

@@ -67,18 +67,6 @@ func main() {
6767
return
6868
}
6969

70-
var genesisBlock *cb.Block
71-
72-
// Select the bootstrapping mechanism
73-
switch conf.General.GenesisMethod {
74-
case "provisional":
75-
genesisBlock = provisional.New(conf).GenesisBlock()
76-
case "file":
77-
genesisBlock = file.New(conf.General.GenesisFile).GenesisBlock()
78-
default:
79-
panic(fmt.Errorf("Unknown genesis method %s", conf.General.GenesisMethod))
80-
}
81-
8270
var lf rawledger.Factory
8371
switch conf.General.LedgerType {
8472
case "file":
@@ -90,11 +78,47 @@ func main() {
9078
panic(fmt.Errorf("Error creating temp dir: %s", err))
9179
}
9280
}
93-
lf, _ = fileledger.New(location, genesisBlock)
81+
lf = fileledger.New(location)
9482
case "ram":
9583
fallthrough
9684
default:
97-
lf, _ = ramledger.New(int(conf.RAMLedger.HistorySize), genesisBlock)
85+
lf = ramledger.New(int(conf.RAMLedger.HistorySize))
86+
}
87+
88+
// Are we bootstrapping
89+
if len(lf.ChainIDs()) == 0 {
90+
var genesisBlock *cb.Block
91+
92+
// Select the bootstrapping mechanism
93+
switch conf.General.GenesisMethod {
94+
case "provisional":
95+
genesisBlock = provisional.New(conf).GenesisBlock()
96+
case "file":
97+
genesisBlock = file.New(conf.General.GenesisFile).GenesisBlock()
98+
default:
99+
panic(fmt.Errorf("Unknown genesis method %s", conf.General.GenesisMethod))
100+
}
101+
102+
chainID, err := utils.GetChainIDFromBlock(genesisBlock)
103+
if err != nil {
104+
logger.Errorf("Failed to parse chain ID from genesis block: %s", err)
105+
return
106+
}
107+
gl, err := lf.GetOrCreate(chainID)
108+
if err != nil {
109+
logger.Errorf("Failed to create the genesis chain: %s", err)
110+
return
111+
}
112+
113+
err = gl.Append(genesisBlock)
114+
if err != nil {
115+
logger.Errorf("Could not write genesis block to ledger: %s", err)
116+
return
117+
}
118+
} else {
119+
logger.Infof("Not bootstrapping because of existing chains")
120+
logger.Warningf("XXXXXXX RESTART IS NOT CURRENTLY SUPPORTED XXXXXXXXX")
121+
// XXX Remove this once restart is supported
98122
}
99123

100124
if conf.Kafka.Verbose {

orderer/multichain/chainsupport.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,5 +178,5 @@ func (cs *chainSupport) WriteBlock(data []*cb.Envelope, metadata [][]byte, commi
178178
committer.Commit()
179179
}
180180

181-
cs.ledger.Append(data, metadata)
181+
cs.ledger.Append(rawledger.CreateNextBlock(cs.ledger, data, metadata))
182182
}

orderer/multichain/chainsupport_test.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,19 @@ import (
2424
"github.com/hyperledger/fabric/orderer/rawledger"
2525
cb "github.com/hyperledger/fabric/protos/common"
2626
ab "github.com/hyperledger/fabric/protos/orderer"
27+
"github.com/hyperledger/fabric/protos/utils"
2728
)
2829

2930
type mockLedgerReadWriter struct {
30-
data []*cb.Envelope
31+
data [][]byte
3132
metadata [][]byte
33+
height uint64
3234
}
3335

34-
func (mlw *mockLedgerReadWriter) Append(data []*cb.Envelope, metadata [][]byte) *cb.Block {
35-
mlw.data = data
36-
mlw.metadata = metadata
36+
func (mlw *mockLedgerReadWriter) Append(block *cb.Block) error {
37+
mlw.data = block.Data.Data
38+
mlw.metadata = block.Metadata.Metadata
39+
mlw.height++
3740
return nil
3841
}
3942

@@ -42,7 +45,7 @@ func (mlw *mockLedgerReadWriter) Iterator(startType *ab.SeekPosition) (rawledger
4245
}
4346

4447
func (mlw *mockLedgerReadWriter) Height() uint64 {
45-
panic("Unimplemented")
48+
return mlw.height
4649
}
4750

4851
type mockCommitter struct {
@@ -65,7 +68,12 @@ func TestCommitConfig(t *testing.T) {
6568
committers := []filter.Committer{&mockCommitter{}, &mockCommitter{}}
6669
cs.WriteBlock(txs, md, committers)
6770

68-
if !reflect.DeepEqual(ml.data, txs) {
71+
blockTXs := make([]*cb.Envelope, len(ml.data))
72+
for i := range ml.data {
73+
blockTXs[i] = utils.UnmarshalEnvelopeOrPanic(ml.data[i])
74+
}
75+
76+
if !reflect.DeepEqual(blockTXs, txs) {
6977
t.Errorf("Should have written input data to ledger but did not")
7078
}
7179

orderer/multichain/manager.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ func (ml *multiLedger) systemChain() *systemChain {
230230

231231
func (ml *multiLedger) newChain(configtx *cb.Envelope) {
232232
configManager, policyManager, backingLedger, sharedConfig := ml.newResources(configtx)
233-
backingLedger.Append([]*cb.Envelope{configtx}, nil)
233+
backingLedger.Append(rawledger.CreateNextBlock(backingLedger, []*cb.Envelope{configtx}, nil))
234234

235235
// Copy the map to allow concurrent reads from broadcast/deliver while the new chainSupport is
236236
newChains := make(map[string]*chainSupport)

orderer/multichain/manager_test.go

+30-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/hyperledger/fabric/orderer/common/bootstrap/provisional"
2626
"github.com/hyperledger/fabric/orderer/localconfig"
27+
"github.com/hyperledger/fabric/orderer/rawledger"
2728
"github.com/hyperledger/fabric/orderer/rawledger/ramledger"
2829
cb "github.com/hyperledger/fabric/protos/common"
2930
ab "github.com/hyperledger/fabric/protos/orderer"
@@ -57,16 +58,34 @@ func makeNormalTx(chainID string, i int) *cb.Envelope {
5758
}
5859
}
5960

61+
func NewRAMLedgerAndFactory(maxSize int) (rawledger.Factory, rawledger.ReadWriter) {
62+
rlf := ramledger.New(10)
63+
rl, err := rlf.GetOrCreate(provisional.TestChainID)
64+
if err != nil {
65+
panic(err)
66+
}
67+
err = rl.Append(genesisBlock)
68+
if err != nil {
69+
panic(err)
70+
}
71+
return rlf, rl
72+
}
73+
74+
func NewRAMLedger(maxSize int) rawledger.ReadWriter {
75+
_, rl := NewRAMLedgerAndFactory(maxSize)
76+
return rl
77+
}
78+
6079
// Tests for a normal chain which contains 3 config transactions and other normal transactions to make sure the right one returned
6180
func TestGetConfigTx(t *testing.T) {
62-
_, rl := ramledger.New(10, genesisBlock)
81+
rl := NewRAMLedger(10)
6382
for i := 0; i < 5; i++ {
64-
rl.Append([]*cb.Envelope{makeNormalTx(provisional.TestChainID, i)}, nil)
83+
rl.Append(rawledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, i)}, nil))
6584
}
66-
rl.Append([]*cb.Envelope{makeConfigTx(provisional.TestChainID, 5)}, nil)
85+
rl.Append(rawledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx(provisional.TestChainID, 5)}, nil))
6786
ctx := makeConfigTx(provisional.TestChainID, 6)
68-
rl.Append([]*cb.Envelope{ctx}, nil)
69-
rl.Append([]*cb.Envelope{makeNormalTx(provisional.TestChainID, 7)}, nil)
87+
rl.Append(rawledger.CreateNextBlock(rl, []*cb.Envelope{ctx}, nil))
88+
rl.Append(rawledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 7)}, nil))
7089

7190
pctx := getConfigTx(rl)
7291

@@ -77,14 +96,14 @@ func TestGetConfigTx(t *testing.T) {
7796

7897
// Tests a chain which contains blocks with multi-transactions mixed with config txs, and a single tx which is not a config tx, none count as config blocks so nil should return
7998
func TestGetConfigTxFailure(t *testing.T) {
80-
_, rl := ramledger.New(10, genesisBlock)
99+
rl := NewRAMLedger(10)
81100
for i := 0; i < 10; i++ {
82-
rl.Append([]*cb.Envelope{
101+
rl.Append(rawledger.CreateNextBlock(rl, []*cb.Envelope{
83102
makeNormalTx(provisional.TestChainID, i),
84103
makeConfigTx(provisional.TestChainID, i),
85-
}, nil)
104+
}, nil))
86105
}
87-
rl.Append([]*cb.Envelope{makeNormalTx(provisional.TestChainID, 11)}, nil)
106+
rl.Append(rawledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 11)}, nil))
88107
pctx := getConfigTx(rl)
89108

90109
if pctx != nil {
@@ -94,7 +113,7 @@ func TestGetConfigTxFailure(t *testing.T) {
94113

95114
// This test essentially brings the entire system up and is ultimately what main.go will replicate
96115
func TestManagerImpl(t *testing.T) {
97-
lf, rl := ramledger.New(10, genesisBlock)
116+
lf, rl := NewRAMLedgerAndFactory(10)
98117

99118
consenters := make(map[string]Consenter)
100119
consenters[conf.General.OrdererType] = &mockConsenter{}
@@ -141,7 +160,7 @@ func TestManagerImpl(t *testing.T) {
141160
// This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain
142161
func TestNewChain(t *testing.T) {
143162
conf := config.Load()
144-
lf, rl := ramledger.New(10, genesisBlock)
163+
lf, rl := NewRAMLedgerAndFactory(10)
145164

146165
consenters := make(map[string]Consenter)
147166
consenters[conf.General.OrdererType] = &mockConsenter{}

orderer/rawledger/blackbox_test.go

+13-7
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ func testReinitialization(lf ledgerTestFactory, t *testing.T) {
9999
return
100100
}
101101
_, oli := lf.New()
102-
aBlock := oli.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil)
102+
aBlock := CreateNextBlock(oli, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil)
103+
err := oli.Append(aBlock)
104+
if err != nil {
105+
t.Fatalf("Error appending block: %s", err)
106+
}
107+
103108
_, li := lf.New()
104109
if li.Height() != 2 {
105110
t.Fatalf("Block height should be 2")
@@ -125,7 +130,7 @@ func testAddition(lf ledgerTestFactory, t *testing.T) {
125130
}
126131
prevHash := genesis.Header.Hash()
127132

128-
li.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil)
133+
li.Append(CreateNextBlock(li, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil))
129134
if li.Height() != 2 {
130135
t.Fatalf("Block height should be 2")
131136
}
@@ -144,7 +149,7 @@ func TestRetrieval(t *testing.T) {
144149

145150
func testRetrieval(lf ledgerTestFactory, t *testing.T) {
146151
_, li := lf.New()
147-
li.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil)
152+
li.Append(CreateNextBlock(li, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil))
148153
it, num := li.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{}})
149154
if num != 0 {
150155
t.Fatalf("Expected genesis block iterator, but got %d", num)
@@ -193,7 +198,7 @@ func testBlockedRetrieval(lf ledgerTestFactory, t *testing.T) {
193198
t.Fatalf("Should not be ready for block read")
194199
default:
195200
}
196-
li.Append([]*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil)
201+
li.Append(CreateNextBlock(li, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}, nil))
197202
select {
198203
case <-signal:
199204
default:
@@ -227,8 +232,9 @@ func testMultichain(lf ledgerTestFactory, t *testing.T) {
227232
t.Fatalf("Error creating chain1: %s", err)
228233
}
229234

230-
c1.Append([]*cb.Envelope{&cb.Envelope{Payload: c1p1}}, nil)
231-
c1b1 := c1.Append([]*cb.Envelope{&cb.Envelope{Payload: c1p2}}, nil)
235+
c1.Append(CreateNextBlock(c1, []*cb.Envelope{&cb.Envelope{Payload: c1p1}}, nil))
236+
c1b1 := CreateNextBlock(c1, []*cb.Envelope{&cb.Envelope{Payload: c1p2}}, nil)
237+
c1.Append(c1b1)
232238

233239
if c1.Height() != 2 {
234240
t.Fatalf("Block height for c1 should be 2")
@@ -238,7 +244,7 @@ func testMultichain(lf ledgerTestFactory, t *testing.T) {
238244
if err != nil {
239245
t.Fatalf("Error creating chain2: %s", err)
240246
}
241-
c2b0 := c2.Append([]*cb.Envelope{&cb.Envelope{Payload: c2p1}}, nil)
247+
c2b0 := c2.Append(CreateNextBlock(c2, []*cb.Envelope{&cb.Envelope{Payload: c2p1}}, nil))
242248

243249
if c2.Height() != 1 {
244250
t.Fatalf("Block height for c2 should be 1")

0 commit comments

Comments
 (0)