go_study/fabric-main/orderer/common/follower/block_puller_test.go

223 lines
7.4 KiB
Go

/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package follower_test
import (
"fmt"
"io/ioutil"
"path"
"sync/atomic"
"testing"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/sw"
"github.com/hyperledger/fabric/common/crypto/tlsgen"
"github.com/hyperledger/fabric/core/config/configtest"
"github.com/hyperledger/fabric/internal/configtxgen/encoder"
"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
"github.com/hyperledger/fabric/internal/pkg/comm"
"github.com/hyperledger/fabric/internal/pkg/identity"
"github.com/hyperledger/fabric/orderer/common/cluster"
"github.com/hyperledger/fabric/orderer/common/follower"
"github.com/hyperledger/fabric/orderer/common/follower/mocks"
"github.com/hyperledger/fabric/orderer/common/localconfig"
"github.com/hyperledger/fabric/protoutil"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
//go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer
type signerSerializer interface {
identity.SignerSerializer
}
var (
channelID string
mockSigner *mocks.SignerSerializer
tlsCA tlsgen.CA
dialer *cluster.PredicateDialer
cryptoProv bccsp.BCCSP
)
func setupBlockPullerTest(t *testing.T) {
channelID = "my-raft-channel"
mockSigner = &mocks.SignerSerializer{}
var err error
tlsCA, err = tlsgen.NewCA()
require.NoError(t, err)
dialer = &cluster.PredicateDialer{
Config: comm.ClientConfig{
SecOpts: comm.SecureOptions{
Certificate: tlsCA.CertBytes(),
},
},
}
cryptoProv, err = sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
require.NoError(t, err)
}
func TestNewBlockPullerFactory(t *testing.T) {
setupBlockPullerTest(t)
t.Run("good", func(t *testing.T) {
bpf, err := follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, dialer, localconfig.Cluster{}, cryptoProv)
require.NoError(t, err)
require.NotNil(t, bpf)
})
t.Run("dialer is nil", func(t *testing.T) {
require.Panics(t, func() {
follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, nil, localconfig.Cluster{}, cryptoProv)
})
})
t.Run("dialer has bad cert", func(t *testing.T) {
badDialer := &cluster.PredicateDialer{
Config: dialer.Config,
}
badDialer.Config.SecOpts.Certificate = []byte("not-a-certificate")
bpf, err := follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, badDialer, localconfig.Cluster{}, cryptoProv)
require.EqualError(t, err, "client certificate isn't in PEM format: not-a-certificate")
require.Nil(t, bpf)
})
}
func TestBlockPullerFactory_BlockPuller(t *testing.T) {
setupBlockPullerTest(t)
factory, err := follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, dialer, localconfig.Cluster{}, cryptoProv)
require.NotNil(t, factory)
require.NoError(t, err)
t.Run("good", func(t *testing.T) {
joinBlockAppRaft := generateJoinBlock(t, tlsCA, channelID, 10)
require.NotNil(t, joinBlockAppRaft)
bp, err := factory.BlockPuller(joinBlockAppRaft, make(chan struct{}))
require.NoError(t, err)
require.NotNil(t, bp)
})
t.Run("bad join block", func(t *testing.T) {
bp, err := factory.BlockPuller(&cb.Block{Header: &cb.BlockHeader{}}, make(chan struct{}))
require.EqualError(t, err, "error extracting endpoints from config block: block data is nil")
require.Nil(t, bp)
})
}
func TestBlockPullerFactory_VerifyBlockSequence(t *testing.T) {
// replaces cluster.VerifyBlocks, count blocks
var numBlocks int32
altVerifyBlocks := func(blockBuff []*cb.Block, signatureVerifier protoutil.BlockVerifierFunc, vb protoutil.VerifierBuilder) error { // replaces cluster.VerifyBlocks, count invocations
if len(blockBuff) == 0 {
return errors.New("buffer is empty")
}
require.NotNil(t, signatureVerifier)
atomic.StoreInt32(&numBlocks, int32(len(blockBuff)))
return nil
}
t.Run("skip genesis block, alone", func(t *testing.T) {
setupBlockPullerTest(t)
atomic.StoreInt32(&numBlocks, 0)
creator, err := follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, dialer, localconfig.Cluster{}, cryptoProv)
require.NotNil(t, creator)
require.NoError(t, err)
creator.ClusterVerifyBlocks = altVerifyBlocks
blocks := []*cb.Block{
generateJoinBlock(t, tlsCA, channelID, 0),
}
err = creator.VerifyBlockSequence(blocks, "")
require.NoError(t, err)
require.Equal(t, int32(0), atomic.LoadInt32(&numBlocks))
})
t.Run("skip genesis block as part of a slice", func(t *testing.T) {
gb := generateJoinBlock(t, tlsCA, channelID, 0)
setupBlockPullerTest(t)
atomic.StoreInt32(&numBlocks, 0)
creator, err := follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, dialer, localconfig.Cluster{}, cryptoProv)
require.NotNil(t, creator)
require.NoError(t, err)
creator.JoinBlock = gb
creator.ClusterVerifyBlocks = altVerifyBlocks
blocks := []*cb.Block{
gb,
protoutil.NewBlock(1, nil),
protoutil.NewBlock(2, nil),
}
tx, err := protoutil.CreateSignedEnvelopeWithTLSBinding(0, "mychannel", nil, &cb.Payload{}, 0, 0, nil)
require.NoError(t, err)
blocks[1].Data.Data = [][]byte{protoutil.MarshalOrPanic(tx)}
blocks[2].Data.Data = [][]byte{protoutil.MarshalOrPanic(tx)}
err = creator.VerifyBlockSequence(blocks, "")
require.NoError(t, err)
require.Equal(t, int32(2), atomic.LoadInt32(&numBlocks))
})
t.Run("verify all blocks in slice", func(t *testing.T) {
setupBlockPullerTest(t)
atomic.StoreInt32(&numBlocks, 0)
creator, err := follower.NewBlockPullerCreator(channelID, testLogger, mockSigner, dialer, localconfig.Cluster{}, cryptoProv)
require.NotNil(t, creator)
require.NoError(t, err)
creator.ClusterVerifyBlocks = altVerifyBlocks
blocks := []*cb.Block{protoutil.NewBlock(4, []byte{}), protoutil.NewBlock(5, []byte{}), protoutil.NewBlock(6, []byte{})}
err = creator.VerifyBlockSequence(blocks, "")
require.EqualError(t, err, "nil block signature verifier")
creator.UpdateVerifierFromConfigBlock(generateJoinBlock(t, tlsCA, channelID, 0))
err = creator.VerifyBlockSequence(blocks, "")
require.NoError(t, err)
require.Equal(t, int32(3), atomic.LoadInt32(&numBlocks))
})
}
func generateJoinBlock(t *testing.T, tlsCA tlsgen.CA, channelID string, number uint64) *cb.Block {
tmpdir := t.TempDir()
confAppRaft := genesisconfig.Load(genesisconfig.SampleDevModeEtcdRaftProfile, configtest.GetDevConfigDir())
confAppRaft.Consortiums = nil
confAppRaft.Consortium = ""
generateCertificates(t, confAppRaft, tlsCA, tmpdir)
bootstrapper, err := encoder.NewBootstrapper(confAppRaft)
require.NoError(t, err, "cannot create bootstrapper")
joinBlockAppRaft := bootstrapper.GenesisBlockForChannel(channelID)
joinBlockAppRaft.Header.Number = number
return joinBlockAppRaft
}
func generateCertificates(t *testing.T, confAppRaft *genesisconfig.Profile, tlsCA tlsgen.CA, certDir string) {
for i, c := range confAppRaft.Orderer.EtcdRaft.Consenters {
srvC, err := tlsCA.NewServerCertKeyPair(c.Host)
require.NoError(t, err)
srvP := path.Join(certDir, fmt.Sprintf("server%d.crt", i))
err = ioutil.WriteFile(srvP, srvC.Cert, 0o644)
require.NoError(t, err)
clnC, err := tlsCA.NewClientCertKeyPair()
require.NoError(t, err)
clnP := path.Join(certDir, fmt.Sprintf("client%d.crt", i))
err = ioutil.WriteFile(clnP, clnC.Cert, 0o644)
require.NoError(t, err)
c.ServerTlsCert = []byte(srvP)
c.ClientTlsCert = []byte(clnP)
}
}