Skip to content

Commit e1c5a1f

Browse files
authored
added to OSN new handler for fetch a block of channel (#5280)
part 1 Signed-off-by: Fedor Partanskiy <fredprtnsk@gmail.com>
1 parent 7908f5b commit e1c5a1f

File tree

2 files changed

+257
-0
lines changed

2 files changed

+257
-0
lines changed

orderer/common/multichannel/registrar.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package multichannel
1111

1212
import (
1313
"path/filepath"
14+
"strconv"
1415
"sync"
1516

1617
"github.com/hyperledger/fabric-lib-go/bccsp"
@@ -619,6 +620,53 @@ func (r *Registrar) ChannelInfo(channelID string) (types.ChannelInfo, error) {
619620
return types.ChannelInfo{}, types.ErrChannelNotExist
620621
}
621622

623+
// FetchBlock instructs the orderer to send a block of channel.
624+
func (r *Registrar) FetchBlock(channelID string, blockID string) (*cb.Block, error) {
625+
r.lock.RLock()
626+
defer r.lock.RUnlock()
627+
628+
if status, ok := r.pendingRemoval[channelID]; ok {
629+
if status.Status == types.StatusFailed {
630+
return nil, types.ErrChannelRemovalFailure
631+
}
632+
return nil, types.ErrChannelPendingRemoval
633+
}
634+
635+
if _, ok := r.followers[channelID]; ok {
636+
return nil, types.ErrChannelNotReady
637+
}
638+
639+
cs, ok := r.chains[channelID]
640+
if !ok {
641+
return nil, types.ErrChannelNotExist
642+
}
643+
644+
switch blockID {
645+
case "oldest":
646+
return cs.RetrieveBlockByNumber(0)
647+
case "newest":
648+
return cs.RetrieveBlockByNumber(cs.Height() - 1)
649+
case "config":
650+
b, err := cs.RetrieveBlockByNumber(cs.Height() - 1)
651+
if err != nil {
652+
return nil, err
653+
}
654+
lc, err := protoutil.GetLastConfigIndexFromBlock(b)
655+
if err != nil {
656+
return nil, err
657+
}
658+
return cs.RetrieveBlockByNumber(lc)
659+
default:
660+
}
661+
662+
nb, err := strconv.Atoi(blockID)
663+
if err != nil {
664+
return nil, err
665+
}
666+
667+
return cs.RetrieveBlockByNumber(uint64(nb))
668+
}
669+
622670
// JoinChannel instructs the orderer to create a channel and join it with the provided config block.
623671
// The URL field is empty, and is to be completed by the caller.
624672
func (r *Registrar) JoinChannel(channelID string, configBlock *cb.Block) (info types.ChannelInfo, err error) {

orderer/common/multichannel/registrar_test.go

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,215 @@ func TestRegistrar_UpdateChannel(t *testing.T) {
13311331
})
13321332
}
13331333

1334+
func TestRegistrar_FetchBlock(t *testing.T) {
1335+
var (
1336+
tmpdir string
1337+
tlsCA tlsgen.CA
1338+
confAppRaft *genesisconfig.Profile
1339+
genesisBlockAppRaft *cb.Block
1340+
cryptoProvider bccsp.BCCSP
1341+
config localconfig.TopLevel
1342+
ledgerFactory blockledger.Factory
1343+
consenter *mocks.Consenter
1344+
mockConsenters map[string]consensus.Consenter
1345+
signer msp.SigningIdentity
1346+
)
1347+
1348+
setup := func(t *testing.T) {
1349+
var err error
1350+
tmpdir = t.TempDir()
1351+
1352+
tlsCA, err = tlsgen.NewCA()
1353+
require.NoError(t, err)
1354+
1355+
confAppRaft = genesisconfig.Load(genesisconfig.SampleDevModeEtcdRaftProfile, configtest.GetDevConfigDir())
1356+
confAppRaft.Consortiums = nil
1357+
confAppRaft.Consortium = ""
1358+
generateCertificates(t, confAppRaft, tlsCA, tmpdir)
1359+
bootstrapper, err := encoder.NewBootstrapper(confAppRaft)
1360+
require.NoError(t, err, "cannot create bootstrapper")
1361+
genesisBlockAppRaft = bootstrapper.GenesisBlockForChannel("my-raft-channel")
1362+
require.NotNil(t, genesisBlockAppRaft)
1363+
1364+
cryptoProvider, err = sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
1365+
require.NoError(t, err)
1366+
1367+
config = localconfig.TopLevel{
1368+
General: localconfig.General{
1369+
BootstrapMethod: "none",
1370+
Cluster: localconfig.Cluster{
1371+
ReplicationBufferSize: 1,
1372+
ReplicationPullTimeout: time.Microsecond,
1373+
ReplicationRetryTimeout: time.Microsecond,
1374+
ReplicationMaxRetries: 2,
1375+
},
1376+
},
1377+
ChannelParticipation: localconfig.ChannelParticipation{
1378+
Enabled: true,
1379+
},
1380+
FileLedger: localconfig.FileLedger{
1381+
Location: tmpdir,
1382+
},
1383+
}
1384+
1385+
ledgerFactory = newFactory(tmpdir)
1386+
consenter = &mocks.Consenter{}
1387+
consenter.HandleChainCalls(handleChainCluster)
1388+
mockConsenters = map[string]consensus.Consenter{confAppRaft.Orderer.OrdererType: consenter}
1389+
1390+
mspDir := configtest.GetDevMspDir()
1391+
mspConfig, err := msp.GetLocalMspConfig(mspDir, nil, "SampleOrg")
1392+
require.NoError(t, err)
1393+
err = mspmgmt.GetLocalMSP(factory.GetDefault()).Setup(mspConfig)
1394+
require.NoError(t, err)
1395+
signer, err = mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity()
1396+
require.NoError(t, err)
1397+
}
1398+
1399+
cleanup := func() {
1400+
ledgerFactory.Close()
1401+
}
1402+
1403+
t.Run("Reject fetch block when removal is occurring", func(t *testing.T) {
1404+
setup(t)
1405+
defer cleanup()
1406+
1407+
registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider, nil)
1408+
registrar.Initialize(mockConsenters)
1409+
1410+
registrar.pendingRemoval["some-app-channel"] = consensus.StaticStatusReporter{ConsensusRelation: types.ConsensusRelationFollower, Status: types.StatusInactive}
1411+
1412+
block, err := registrar.FetchBlock("some-app-channel", "oldest")
1413+
require.Equal(t, err, types.ErrChannelPendingRemoval)
1414+
require.Nil(t, block)
1415+
})
1416+
1417+
t.Run("Reject fetch block when removal previously failed", func(t *testing.T) {
1418+
setup(t)
1419+
defer cleanup()
1420+
1421+
registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider, nil)
1422+
registrar.Initialize(mockConsenters)
1423+
1424+
registrar.pendingRemoval["some-app-channel"] = consensus.StaticStatusReporter{ConsensusRelation: types.ConsensusRelationFollower, Status: types.StatusFailed}
1425+
1426+
block, err := registrar.FetchBlock("some-app-channel", "oldest")
1427+
require.Equal(t, types.ErrChannelRemovalFailure, err)
1428+
require.Nil(t, block)
1429+
})
1430+
1431+
t.Run("Reject fetch block when channel is follower", func(t *testing.T) {
1432+
setup(t)
1433+
defer cleanup()
1434+
1435+
registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider, nil)
1436+
registrar.Initialize(mockConsenters)
1437+
1438+
registrar.followers["some-app-channel"] = &follower.Chain{}
1439+
1440+
block, err := registrar.FetchBlock("some-app-channel", "oldest")
1441+
require.Equal(t, types.ErrChannelNotReady, err)
1442+
require.Nil(t, block)
1443+
})
1444+
1445+
t.Run("Reject fetch block when channel is not exist", func(t *testing.T) {
1446+
setup(t)
1447+
defer cleanup()
1448+
1449+
registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider, nil)
1450+
registrar.Initialize(mockConsenters)
1451+
1452+
block, err := registrar.FetchBlock("some-app-channel", "oldest")
1453+
require.Equal(t, types.ErrChannelNotExist, err)
1454+
require.Nil(t, block)
1455+
})
1456+
1457+
t.Run("Reject fetch block when RetrieveBlockByNumber return error", func(t *testing.T) {
1458+
setup(t)
1459+
defer cleanup()
1460+
1461+
registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider, nil)
1462+
registrar.Initialize(mockConsenters)
1463+
1464+
ledger := &mocks.ReadWriter{}
1465+
ledger.RetrieveBlockByNumberReturns(nil, errors.New("some error"))
1466+
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
1467+
require.NoError(t, err)
1468+
cs := &ChainSupport{
1469+
ledgerResources: &ledgerResources{ReadWriter: ledger},
1470+
BCCSP: cryptoProvider,
1471+
}
1472+
registrar.chains["some-app-channel"] = cs
1473+
1474+
block, err := registrar.FetchBlock("some-app-channel", "oldest")
1475+
require.EqualError(t, err, "some error")
1476+
require.Nil(t, block)
1477+
})
1478+
1479+
t.Run("Reject fetch block when blockId is failed", func(t *testing.T) {
1480+
setup(t)
1481+
defer cleanup()
1482+
1483+
registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider, nil)
1484+
registrar.Initialize(mockConsenters)
1485+
1486+
ledger := &mocks.ReadWriter{}
1487+
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
1488+
require.NoError(t, err)
1489+
cs := &ChainSupport{
1490+
ledgerResources: &ledgerResources{ReadWriter: ledger},
1491+
BCCSP: cryptoProvider,
1492+
}
1493+
registrar.chains["some-app-channel"] = cs
1494+
1495+
block, err := registrar.FetchBlock("some-app-channel", "blabla")
1496+
require.EqualError(t, err, "strconv.Atoi: parsing \"blabla\": invalid syntax")
1497+
require.Nil(t, block)
1498+
1499+
block, err = registrar.FetchBlock("some-app-channel", "1q1")
1500+
require.EqualError(t, err, "strconv.Atoi: parsing \"1q1\": invalid syntax")
1501+
require.Nil(t, block)
1502+
})
1503+
1504+
t.Run("Fetch block - OK", func(t *testing.T) {
1505+
setup(t)
1506+
defer cleanup()
1507+
1508+
serNode := mockCrypto()
1509+
serNode.SerializeCalls(signer.Serialize)
1510+
serNode.SignCalls(signer.Sign)
1511+
1512+
consenter.IsChannelMemberReturns(true, nil)
1513+
registrar := NewRegistrar(config, ledgerFactory, serNode, &disabled.Provider{}, cryptoProvider, nil)
1514+
fakeFields := newFakeMetricsFields()
1515+
registrar.channelParticipationMetrics = newFakeMetrics(fakeFields)
1516+
1517+
registrar.Initialize(mockConsenters)
1518+
_, err := registrar.JoinChannel("my-raft-channel", genesisBlockAppRaft)
1519+
require.NoError(t, err)
1520+
1521+
cs := registrar.GetChain("my-raft-channel")
1522+
fakeCS := &mocks.ChannelSupport{}
1523+
cs.Chain = fakeCS
1524+
1525+
b, err := registrar.FetchBlock("my-raft-channel", "oldest")
1526+
require.NoError(t, err)
1527+
require.NotNil(t, b)
1528+
1529+
b, err = registrar.FetchBlock("my-raft-channel", "newest")
1530+
require.NoError(t, err)
1531+
require.NotNil(t, b)
1532+
1533+
b, err = registrar.FetchBlock("my-raft-channel", "config")
1534+
require.NoError(t, err)
1535+
require.NotNil(t, b)
1536+
1537+
b, err = registrar.FetchBlock("my-raft-channel", "0")
1538+
require.NoError(t, err)
1539+
require.NotNil(t, b)
1540+
})
1541+
}
1542+
13341543
func checkMetrics(t *testing.T, fakeFields *fakeMetricsFields, expectedLabels []string, expectedRelation, expectedStatus, expectedCallCount int) {
13351544
require.Equal(t, expectedCallCount, fakeFields.fakeConsensusRelation.SetCallCount())
13361545
require.Equal(t, float64(expectedRelation), fakeFields.fakeConsensusRelation.SetArgsForCall(expectedCallCount-1))

0 commit comments

Comments
 (0)