diff --git a/common/deliver/mock/block_reader.go b/common/deliver/mock/block_reader.go index 63b7e6a6e2b..5f71afe7061 100644 --- a/common/deliver/mock/block_reader.go +++ b/common/deliver/mock/block_reader.go @@ -4,6 +4,7 @@ package mock import ( "sync" + "github.com/hyperledger/fabric-protos-go/common" "github.com/hyperledger/fabric-protos-go/orderer" "github.com/hyperledger/fabric/common/ledger/blockledger" ) @@ -32,6 +33,19 @@ type BlockReader struct { result1 blockledger.Iterator result2 uint64 } + RetrieveBlockByNumberStub func(uint64) (*common.Block, error) + retrieveBlockByNumberMutex sync.RWMutex + retrieveBlockByNumberArgsForCall []struct { + arg1 uint64 + } + retrieveBlockByNumberReturns struct { + result1 *common.Block + result2 error + } + retrieveBlockByNumberReturnsOnCall map[int]struct { + result1 *common.Block + result2 error + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } @@ -41,15 +55,16 @@ func (fake *BlockReader) Height() uint64 { ret, specificReturn := fake.heightReturnsOnCall[len(fake.heightArgsForCall)] fake.heightArgsForCall = append(fake.heightArgsForCall, struct { }{}) + stub := fake.HeightStub + fakeReturns := fake.heightReturns fake.recordInvocation("Height", []interface{}{}) fake.heightMutex.Unlock() - if fake.HeightStub != nil { - return fake.HeightStub() + if stub != nil { + return stub() } if specificReturn { return ret.result1 } - fakeReturns := fake.heightReturns return fakeReturns.result1 } @@ -94,15 +109,16 @@ func (fake *BlockReader) Iterator(arg1 *orderer.SeekPosition) (blockledger.Itera fake.iteratorArgsForCall = append(fake.iteratorArgsForCall, struct { arg1 *orderer.SeekPosition }{arg1}) + stub := fake.IteratorStub + fakeReturns := fake.iteratorReturns fake.recordInvocation("Iterator", []interface{}{arg1}) fake.iteratorMutex.Unlock() - if fake.IteratorStub != nil { - return fake.IteratorStub(arg1) + if stub != nil { + return stub(arg1) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.iteratorReturns return fakeReturns.result1, fakeReturns.result2 } @@ -151,6 +167,70 @@ func (fake *BlockReader) IteratorReturnsOnCall(i int, result1 blockledger.Iterat }{result1, result2} } +func (fake *BlockReader) RetrieveBlockByNumber(arg1 uint64) (*common.Block, error) { + fake.retrieveBlockByNumberMutex.Lock() + ret, specificReturn := fake.retrieveBlockByNumberReturnsOnCall[len(fake.retrieveBlockByNumberArgsForCall)] + fake.retrieveBlockByNumberArgsForCall = append(fake.retrieveBlockByNumberArgsForCall, struct { + arg1 uint64 + }{arg1}) + stub := fake.RetrieveBlockByNumberStub + fakeReturns := fake.retrieveBlockByNumberReturns + fake.recordInvocation("RetrieveBlockByNumber", []interface{}{arg1}) + fake.retrieveBlockByNumberMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *BlockReader) RetrieveBlockByNumberCallCount() int { + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() + return len(fake.retrieveBlockByNumberArgsForCall) +} + +func (fake *BlockReader) RetrieveBlockByNumberCalls(stub func(uint64) (*common.Block, error)) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = stub +} + +func (fake *BlockReader) RetrieveBlockByNumberArgsForCall(i int) uint64 { + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() + argsForCall := fake.retrieveBlockByNumberArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *BlockReader) RetrieveBlockByNumberReturns(result1 *common.Block, result2 error) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = nil + fake.retrieveBlockByNumberReturns = struct { + result1 *common.Block + result2 error + }{result1, result2} +} + +func (fake *BlockReader) RetrieveBlockByNumberReturnsOnCall(i int, result1 *common.Block, result2 error) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = nil + if fake.retrieveBlockByNumberReturnsOnCall == nil { + fake.retrieveBlockByNumberReturnsOnCall = make(map[int]struct { + result1 *common.Block + result2 error + }) + } + fake.retrieveBlockByNumberReturnsOnCall[i] = struct { + result1 *common.Block + result2 error + }{result1, result2} +} + func (fake *BlockReader) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() @@ -158,6 +238,8 @@ func (fake *BlockReader) Invocations() map[string][][]interface{} { defer fake.heightMutex.RUnlock() fake.iteratorMutex.RLock() defer fake.iteratorMutex.RUnlock() + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value diff --git a/common/ledger/blockledger/fileledger/impl.go b/common/ledger/blockledger/fileledger/impl.go index 374f4957fbd..222b28fda69 100644 --- a/common/ledger/blockledger/fileledger/impl.go +++ b/common/ledger/blockledger/fileledger/impl.go @@ -28,6 +28,7 @@ type FileLedgerBlockStore interface { AddBlock(block *cb.Block) error GetBlockchainInfo() (*cb.BlockchainInfo, error) RetrieveBlocks(startBlockNumber uint64) (ledger.ResultsIterator, error) + RetrieveBlockByNumber(blockNum uint64) (*cb.Block, error) } // NewFileLedger creates a new FileLedger for interaction with the ledger @@ -87,6 +88,7 @@ func (fl *FileLedger) Iterator(startPosition *ab.SeekPosition) (blockledger.Iter iterator, err := fl.blockStore.RetrieveBlocks(startingBlockNumber) if err != nil { + logger.Warnw("Failed to initialize block iterator", "blockNum", startingBlockNumber, "error", err) return &blockledger.NotFoundErrorIterator{}, 0 } @@ -111,3 +113,7 @@ func (fl *FileLedger) Append(block *cb.Block) error { } return err } + +func (fl *FileLedger) RetrieveBlockByNumber(blockNumber uint64) (*cb.Block, error) { + return fl.blockStore.RetrieveBlockByNumber(blockNumber) +} diff --git a/common/ledger/blockledger/ledger.go b/common/ledger/blockledger/ledger.go index 5c6b66e87b7..6db81407e95 100644 --- a/common/ledger/blockledger/ledger.go +++ b/common/ledger/blockledger/ledger.go @@ -40,6 +40,8 @@ type Reader interface { Iterator(startType *ab.SeekPosition) (Iterator, uint64) // Height returns the number of blocks on the ledger Height() uint64 + // retrieve blockByNumber + RetrieveBlockByNumber(blockNumber uint64) (*cb.Block, error) } // Writer allows the caller to modify the ledger diff --git a/common/ledger/blockledger/util.go b/common/ledger/blockledger/util.go index 3edc736fc3f..98c03339cf4 100644 --- a/common/ledger/blockledger/util.go +++ b/common/ledger/blockledger/util.go @@ -10,9 +10,12 @@ import ( "github.com/golang/protobuf/proto" cb "github.com/hyperledger/fabric-protos-go/common" ab "github.com/hyperledger/fabric-protos-go/orderer" + "github.com/hyperledger/fabric/common/flogging" "github.com/hyperledger/fabric/protoutil" ) +var logger = flogging.MustGetLogger("common.ledger.blockledger.util") + var closedChan chan struct{} func init() { @@ -95,3 +98,8 @@ func GetBlock(rl Reader, index uint64) *cb.Block { } return block } + +func GetBlockByNumber(rl Reader, blockNum uint64) (*cb.Block, error) { + logger.Debugw("Retrieving block", "blockNum", blockNum) + return rl.RetrieveBlockByNumber(blockNum) +} diff --git a/core/peer/deliverevents_test.go b/core/peer/deliverevents_test.go index 4288b8b617f..7c493a2a3f5 100644 --- a/core/peer/deliverevents_test.go +++ b/core/peer/deliverevents_test.go @@ -96,6 +96,11 @@ func (m *mockReader) Height() uint64 { return args.Get(0).(uint64) } +func (m *mockReader) RetrieveBlockByNumber(blockNum uint64) (*common.Block, error) { + args := m.Called() + return args.Get(0).(*common.Block), args.Error(1) +} + // mockChainSupport type mockChainSupport struct { mock.Mock diff --git a/core/peer/peer.go b/core/peer/peer.go index cca65864579..4345470d102 100644 --- a/core/peer/peer.go +++ b/core/peer/peer.go @@ -148,6 +148,10 @@ func (flbs fileLedgerBlockStore) RetrieveBlocks(startBlockNumber uint64) (common return flbs.GetBlocksIterator(startBlockNumber) } +func (flbs fileLedgerBlockStore) RetrieveBlockByNumber(blockNum uint64) (*common.Block, error) { + return flbs.GetBlockByNumber(blockNum) +} + // NewConfigSupport returns func NewConfigSupport(peer *Peer) cc.Manager { return &configSupport{ diff --git a/orderer/common/multichannel/mocks/read_writer.go b/orderer/common/multichannel/mocks/read_writer.go index a82ab3cd5d2..be2768bc0c5 100644 --- a/orderer/common/multichannel/mocks/read_writer.go +++ b/orderer/common/multichannel/mocks/read_writer.go @@ -44,6 +44,19 @@ type ReadWriter struct { result1 blockledger.Iterator result2 uint64 } + RetrieveBlockByNumberStub func(uint64) (*common.Block, error) + retrieveBlockByNumberMutex sync.RWMutex + retrieveBlockByNumberArgsForCall []struct { + arg1 uint64 + } + retrieveBlockByNumberReturns struct { + result1 *common.Block + result2 error + } + retrieveBlockByNumberReturnsOnCall map[int]struct { + result1 *common.Block + result2 error + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } @@ -54,15 +67,16 @@ func (fake *ReadWriter) Append(arg1 *common.Block) error { fake.appendArgsForCall = append(fake.appendArgsForCall, struct { arg1 *common.Block }{arg1}) + stub := fake.AppendStub + fakeReturns := fake.appendReturns fake.recordInvocation("Append", []interface{}{arg1}) fake.appendMutex.Unlock() - if fake.AppendStub != nil { - return fake.AppendStub(arg1) + if stub != nil { + return stub(arg1) } if specificReturn { return ret.result1 } - fakeReturns := fake.appendReturns return fakeReturns.result1 } @@ -113,15 +127,16 @@ func (fake *ReadWriter) Height() uint64 { ret, specificReturn := fake.heightReturnsOnCall[len(fake.heightArgsForCall)] fake.heightArgsForCall = append(fake.heightArgsForCall, struct { }{}) + stub := fake.HeightStub + fakeReturns := fake.heightReturns fake.recordInvocation("Height", []interface{}{}) fake.heightMutex.Unlock() - if fake.HeightStub != nil { - return fake.HeightStub() + if stub != nil { + return stub() } if specificReturn { return ret.result1 } - fakeReturns := fake.heightReturns return fakeReturns.result1 } @@ -166,15 +181,16 @@ func (fake *ReadWriter) Iterator(arg1 *orderer.SeekPosition) (blockledger.Iterat fake.iteratorArgsForCall = append(fake.iteratorArgsForCall, struct { arg1 *orderer.SeekPosition }{arg1}) + stub := fake.IteratorStub + fakeReturns := fake.iteratorReturns fake.recordInvocation("Iterator", []interface{}{arg1}) fake.iteratorMutex.Unlock() - if fake.IteratorStub != nil { - return fake.IteratorStub(arg1) + if stub != nil { + return stub(arg1) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.iteratorReturns return fakeReturns.result1, fakeReturns.result2 } @@ -223,6 +239,70 @@ func (fake *ReadWriter) IteratorReturnsOnCall(i int, result1 blockledger.Iterato }{result1, result2} } +func (fake *ReadWriter) RetrieveBlockByNumber(arg1 uint64) (*common.Block, error) { + fake.retrieveBlockByNumberMutex.Lock() + ret, specificReturn := fake.retrieveBlockByNumberReturnsOnCall[len(fake.retrieveBlockByNumberArgsForCall)] + fake.retrieveBlockByNumberArgsForCall = append(fake.retrieveBlockByNumberArgsForCall, struct { + arg1 uint64 + }{arg1}) + stub := fake.RetrieveBlockByNumberStub + fakeReturns := fake.retrieveBlockByNumberReturns + fake.recordInvocation("RetrieveBlockByNumber", []interface{}{arg1}) + fake.retrieveBlockByNumberMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *ReadWriter) RetrieveBlockByNumberCallCount() int { + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() + return len(fake.retrieveBlockByNumberArgsForCall) +} + +func (fake *ReadWriter) RetrieveBlockByNumberCalls(stub func(uint64) (*common.Block, error)) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = stub +} + +func (fake *ReadWriter) RetrieveBlockByNumberArgsForCall(i int) uint64 { + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() + argsForCall := fake.retrieveBlockByNumberArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *ReadWriter) RetrieveBlockByNumberReturns(result1 *common.Block, result2 error) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = nil + fake.retrieveBlockByNumberReturns = struct { + result1 *common.Block + result2 error + }{result1, result2} +} + +func (fake *ReadWriter) RetrieveBlockByNumberReturnsOnCall(i int, result1 *common.Block, result2 error) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = nil + if fake.retrieveBlockByNumberReturnsOnCall == nil { + fake.retrieveBlockByNumberReturnsOnCall = make(map[int]struct { + result1 *common.Block + result2 error + }) + } + fake.retrieveBlockByNumberReturnsOnCall[i] = struct { + result1 *common.Block + result2 error + }{result1, result2} +} + func (fake *ReadWriter) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() @@ -232,6 +312,8 @@ func (fake *ReadWriter) Invocations() map[string][][]interface{} { defer fake.heightMutex.RUnlock() fake.iteratorMutex.RLock() defer fake.iteratorMutex.RUnlock() + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value diff --git a/orderer/common/multichannel/registrar.go b/orderer/common/multichannel/registrar.go index 12f3703e13a..15eb808cf40 100644 --- a/orderer/common/multichannel/registrar.go +++ b/orderer/common/multichannel/registrar.go @@ -113,16 +113,18 @@ type Registrar struct { // ConfigBlock retrieves the last configuration block from the given ledger. // Panics on failure. func ConfigBlock(reader blockledger.Reader) *cb.Block { - lastBlock := blockledger.GetBlock(reader, reader.Height()-1) + lastBlock, err := blockledger.GetBlockByNumber(reader, reader.Height()-1) + if err != nil { + logger.Panicw("Failed to retrieve block", "blockNum", reader.Height()-1, "error", err) + } index, err := protoutil.GetLastConfigIndexFromBlock(lastBlock) if err != nil { - logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err) + logger.Panicw("Chain did not have appropriately encoded last config in its latest block", "error", err) } - configBlock := blockledger.GetBlock(reader, index) - if configBlock == nil { - logger.Panicf("Config block does not exist") + configBlock, err := blockledger.GetBlockByNumber(reader, index) + if err != nil { + logger.Panicw("Failed to retrieve config block", "blockNum", index, "error", index, err) } - return configBlock } diff --git a/orderer/common/multichannel/registrar_test.go b/orderer/common/multichannel/registrar_test.go index bfd4468bc4e..7af4c4498f5 100644 --- a/orderer/common/multichannel/registrar_test.go +++ b/orderer/common/multichannel/registrar_test.go @@ -665,3 +665,67 @@ func generateCertificates(t *testing.T, confAppRaft *genesisconfig.Profile, tlsC c.ClientTlsCert = []byte(clnP) } } + +func TestRegistrar_ConfigBlock(t *testing.T) { + + t.Run("Panics when ledger is empty", func(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "file-ledger") + require.NoError(t, err) + defer os.RemoveAll(tmpdir) + + _, l := newLedgerAndFactory(tmpdir, "testchannelid", nil) + + require.PanicsWithValue(t, "Failed to retrieve block", func() { + ConfigBlock(l) + }) + }) + + t.Run("Panics when config block not complete", func(t *testing.T) { + block := protoutil.NewBlock(0, nil) + block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = []byte("bad metadata") + + tmpdir, err := ioutil.TempDir("", "file-ledger") + require.NoError(t, err) + defer os.RemoveAll(tmpdir) + + _, l := newLedgerAndFactory(tmpdir, "testchannelid", block) + + require.PanicsWithValue(t, "Chain did not have appropriately encoded last config in its latest block", func() { + ConfigBlock(l) + }) + }) + + t.Run("Panics when block referenes invalid config block", func(t *testing.T) { + block := protoutil.NewBlock(0, nil) + block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{ + Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ + LastConfig: &cb.LastConfig{Index: 2}, + }), + }) + + tmpdir, err := ioutil.TempDir("", "file-ledger") + require.NoError(t, err) + defer os.RemoveAll(tmpdir) + + _, l := newLedgerAndFactory(tmpdir, "testchannelid", block) + + require.PanicsWithValue(t, "Failed to retrieve config block", func() { + ConfigBlock(l) + }) + }) + + t.Run("Returns valid config block", func(t *testing.T) { + confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) + genesisBlockSys := encoder.New(confSys).GenesisBlock() + + tmpdir, err := ioutil.TempDir("", "file-ledger") + require.NoError(t, err) + defer os.RemoveAll(tmpdir) + + _, l := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys) + + cBlock := ConfigBlock(l) + assert.Equal(t, genesisBlockSys.Header, cBlock.Header) + assert.Equal(t, genesisBlockSys.Data, cBlock.Data) + }) +} diff --git a/orderer/common/onboarding/mocks/read_writer.go b/orderer/common/onboarding/mocks/read_writer.go index a82ab3cd5d2..be2768bc0c5 100644 --- a/orderer/common/onboarding/mocks/read_writer.go +++ b/orderer/common/onboarding/mocks/read_writer.go @@ -44,6 +44,19 @@ type ReadWriter struct { result1 blockledger.Iterator result2 uint64 } + RetrieveBlockByNumberStub func(uint64) (*common.Block, error) + retrieveBlockByNumberMutex sync.RWMutex + retrieveBlockByNumberArgsForCall []struct { + arg1 uint64 + } + retrieveBlockByNumberReturns struct { + result1 *common.Block + result2 error + } + retrieveBlockByNumberReturnsOnCall map[int]struct { + result1 *common.Block + result2 error + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } @@ -54,15 +67,16 @@ func (fake *ReadWriter) Append(arg1 *common.Block) error { fake.appendArgsForCall = append(fake.appendArgsForCall, struct { arg1 *common.Block }{arg1}) + stub := fake.AppendStub + fakeReturns := fake.appendReturns fake.recordInvocation("Append", []interface{}{arg1}) fake.appendMutex.Unlock() - if fake.AppendStub != nil { - return fake.AppendStub(arg1) + if stub != nil { + return stub(arg1) } if specificReturn { return ret.result1 } - fakeReturns := fake.appendReturns return fakeReturns.result1 } @@ -113,15 +127,16 @@ func (fake *ReadWriter) Height() uint64 { ret, specificReturn := fake.heightReturnsOnCall[len(fake.heightArgsForCall)] fake.heightArgsForCall = append(fake.heightArgsForCall, struct { }{}) + stub := fake.HeightStub + fakeReturns := fake.heightReturns fake.recordInvocation("Height", []interface{}{}) fake.heightMutex.Unlock() - if fake.HeightStub != nil { - return fake.HeightStub() + if stub != nil { + return stub() } if specificReturn { return ret.result1 } - fakeReturns := fake.heightReturns return fakeReturns.result1 } @@ -166,15 +181,16 @@ func (fake *ReadWriter) Iterator(arg1 *orderer.SeekPosition) (blockledger.Iterat fake.iteratorArgsForCall = append(fake.iteratorArgsForCall, struct { arg1 *orderer.SeekPosition }{arg1}) + stub := fake.IteratorStub + fakeReturns := fake.iteratorReturns fake.recordInvocation("Iterator", []interface{}{arg1}) fake.iteratorMutex.Unlock() - if fake.IteratorStub != nil { - return fake.IteratorStub(arg1) + if stub != nil { + return stub(arg1) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.iteratorReturns return fakeReturns.result1, fakeReturns.result2 } @@ -223,6 +239,70 @@ func (fake *ReadWriter) IteratorReturnsOnCall(i int, result1 blockledger.Iterato }{result1, result2} } +func (fake *ReadWriter) RetrieveBlockByNumber(arg1 uint64) (*common.Block, error) { + fake.retrieveBlockByNumberMutex.Lock() + ret, specificReturn := fake.retrieveBlockByNumberReturnsOnCall[len(fake.retrieveBlockByNumberArgsForCall)] + fake.retrieveBlockByNumberArgsForCall = append(fake.retrieveBlockByNumberArgsForCall, struct { + arg1 uint64 + }{arg1}) + stub := fake.RetrieveBlockByNumberStub + fakeReturns := fake.retrieveBlockByNumberReturns + fake.recordInvocation("RetrieveBlockByNumber", []interface{}{arg1}) + fake.retrieveBlockByNumberMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *ReadWriter) RetrieveBlockByNumberCallCount() int { + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() + return len(fake.retrieveBlockByNumberArgsForCall) +} + +func (fake *ReadWriter) RetrieveBlockByNumberCalls(stub func(uint64) (*common.Block, error)) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = stub +} + +func (fake *ReadWriter) RetrieveBlockByNumberArgsForCall(i int) uint64 { + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() + argsForCall := fake.retrieveBlockByNumberArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *ReadWriter) RetrieveBlockByNumberReturns(result1 *common.Block, result2 error) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = nil + fake.retrieveBlockByNumberReturns = struct { + result1 *common.Block + result2 error + }{result1, result2} +} + +func (fake *ReadWriter) RetrieveBlockByNumberReturnsOnCall(i int, result1 *common.Block, result2 error) { + fake.retrieveBlockByNumberMutex.Lock() + defer fake.retrieveBlockByNumberMutex.Unlock() + fake.RetrieveBlockByNumberStub = nil + if fake.retrieveBlockByNumberReturnsOnCall == nil { + fake.retrieveBlockByNumberReturnsOnCall = make(map[int]struct { + result1 *common.Block + result2 error + }) + } + fake.retrieveBlockByNumberReturnsOnCall[i] = struct { + result1 *common.Block + result2 error + }{result1, result2} +} + func (fake *ReadWriter) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() @@ -232,6 +312,8 @@ func (fake *ReadWriter) Invocations() map[string][][]interface{} { defer fake.heightMutex.RUnlock() fake.iteratorMutex.RLock() defer fake.iteratorMutex.RUnlock() + fake.retrieveBlockByNumberMutex.RLock() + defer fake.retrieveBlockByNumberMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value diff --git a/orderer/common/server/main.go b/orderer/common/server/main.go index 200f64e8ec8..1eb353af1db 100644 --- a/orderer/common/server/main.go +++ b/orderer/common/server/main.go @@ -334,6 +334,10 @@ func extractSystemChannel(lf blockledger.Factory, bccsp bccsp.BCCSP) *cb.Block { if err != nil { logger.Panicf("Failed getting channel %v's ledger: %v", cID, err) } + if channelLedger.Height() == 0 { + logger.Infof("Skipped channel %v's empty ledger", cID) + continue // skip empty ledger + } channelConfigBlock := multichannel.ConfigBlock(channelLedger) err = onboarding.ValidateBootstrapBlock(channelConfigBlock, bccsp)