352 lines
10 KiB
Go
352 lines
10 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package peer
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hyperledger/fabric/common/channelconfig"
|
|
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
pb "github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric/bccsp/sw"
|
|
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
|
|
"github.com/hyperledger/fabric/common/crypto/tlsgen"
|
|
"github.com/hyperledger/fabric/common/metrics/disabled"
|
|
"github.com/hyperledger/fabric/core/committer/txvalidator/plugin"
|
|
"github.com/hyperledger/fabric/core/deliverservice"
|
|
validation "github.com/hyperledger/fabric/core/handlers/validation/api"
|
|
"github.com/hyperledger/fabric/core/ledger"
|
|
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
|
|
"github.com/hyperledger/fabric/core/ledger/ledgermgmt/ledgermgmttest"
|
|
ledgermocks "github.com/hyperledger/fabric/core/ledger/mock"
|
|
"github.com/hyperledger/fabric/core/transientstore"
|
|
"github.com/hyperledger/fabric/gossip/gossip"
|
|
gossipmetrics "github.com/hyperledger/fabric/gossip/metrics"
|
|
"github.com/hyperledger/fabric/gossip/privdata"
|
|
gossipservice "github.com/hyperledger/fabric/gossip/service"
|
|
peergossip "github.com/hyperledger/fabric/internal/peer/gossip"
|
|
"github.com/hyperledger/fabric/internal/peer/gossip/mocks"
|
|
"github.com/hyperledger/fabric/internal/pkg/comm"
|
|
"github.com/hyperledger/fabric/msp/mgmt"
|
|
msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
msptesttools.LoadMSPSetupForTesting()
|
|
rc := m.Run()
|
|
os.Exit(rc)
|
|
}
|
|
|
|
func NewTestPeer(t *testing.T) (*Peer, func()) {
|
|
tempdir := t.TempDir()
|
|
|
|
// Initialize gossip service
|
|
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
|
|
require.NoError(t, err)
|
|
signer, err := mgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity()
|
|
require.NoError(t, err)
|
|
|
|
localMSP := mgmt.GetLocalMSP(cryptoProvider)
|
|
deserManager := peergossip.NewDeserializersManager(localMSP)
|
|
messageCryptoService := peergossip.NewMCS(
|
|
&mocks.ChannelPolicyManagerGetter{},
|
|
signer,
|
|
deserManager,
|
|
cryptoProvider,
|
|
nil,
|
|
)
|
|
secAdv := peergossip.NewSecurityAdvisor(deserManager)
|
|
defaultSecureDialOpts := func() []grpc.DialOption { return []grpc.DialOption{grpc.WithInsecure()} }
|
|
gossipConfig, err := gossip.GlobalConfig("localhost:0", nil)
|
|
require.NoError(t, err)
|
|
|
|
gossipService, err := gossipservice.New(
|
|
signer,
|
|
gossipmetrics.NewGossipMetrics(&disabled.Provider{}),
|
|
"localhost:0",
|
|
grpc.NewServer(),
|
|
messageCryptoService,
|
|
secAdv,
|
|
defaultSecureDialOpts,
|
|
nil,
|
|
gossipConfig,
|
|
&gossipservice.ServiceConfig{},
|
|
&privdata.PrivdataConfig{},
|
|
&deliverservice.DeliverServiceConfig{
|
|
ReConnectBackoffThreshold: deliverservice.DefaultReConnectBackoffThreshold,
|
|
ReconnectTotalTimeThreshold: deliverservice.DefaultReConnectTotalTimeThreshold,
|
|
},
|
|
)
|
|
require.NoError(t, err, "failed to create gossip service")
|
|
|
|
ledgerMgr, err := constructLedgerMgrWithTestDefaults(filepath.Join(tempdir, "ledgersData"))
|
|
require.NoError(t, err, "failed to create ledger manager")
|
|
|
|
require.NoError(t, err)
|
|
transientStoreProvider, err := transientstore.NewStoreProvider(
|
|
filepath.Join(tempdir, "transientstore"),
|
|
)
|
|
require.NoError(t, err)
|
|
peerInstance := &Peer{
|
|
GossipService: gossipService,
|
|
StoreProvider: transientStoreProvider,
|
|
LedgerMgr: ledgerMgr,
|
|
CryptoProvider: cryptoProvider,
|
|
}
|
|
|
|
cleanup := func() {
|
|
ledgerMgr.Close()
|
|
}
|
|
return peerInstance, cleanup
|
|
}
|
|
|
|
func TestInitialize(t *testing.T) {
|
|
peerInstance, cleanup := NewTestPeer(t)
|
|
defer cleanup()
|
|
|
|
org1CA, err := tlsgen.NewCA()
|
|
require.NoError(t, err)
|
|
org1Server1KeyPair, err := org1CA.NewServerCertKeyPair("localhost", "127.0.0.1", "::1")
|
|
require.NoError(t, err)
|
|
|
|
serverConfig := comm.ServerConfig{
|
|
SecOpts: comm.SecureOptions{
|
|
UseTLS: true,
|
|
Certificate: org1Server1KeyPair.Cert,
|
|
Key: org1Server1KeyPair.Key,
|
|
ServerRootCAs: [][]byte{org1CA.CertBytes()},
|
|
RequireClientCert: true,
|
|
},
|
|
}
|
|
|
|
server, err := comm.NewGRPCServer("localhost:0", serverConfig)
|
|
require.NoError(t, err, "failed to create gRPC server")
|
|
|
|
peerInstance.Initialize(
|
|
nil,
|
|
server,
|
|
plugin.MapBasedMapper(map[string]validation.PluginFactory{}),
|
|
&ledgermocks.DeployedChaincodeInfoProvider{},
|
|
nil,
|
|
nil,
|
|
runtime.NumCPU(),
|
|
)
|
|
require.Equal(t, peerInstance.server, server)
|
|
}
|
|
|
|
func TestCreateChannel(t *testing.T) {
|
|
peerInstance, cleanup := NewTestPeer(t)
|
|
defer cleanup()
|
|
|
|
var initArg string
|
|
peerInstance.Initialize(
|
|
func(cid string) { initArg = cid },
|
|
nil,
|
|
plugin.MapBasedMapper(map[string]validation.PluginFactory{}),
|
|
&ledgermocks.DeployedChaincodeInfoProvider{},
|
|
nil,
|
|
nil,
|
|
runtime.NumCPU(),
|
|
)
|
|
|
|
testChannelID := fmt.Sprintf("mytestchannelid-%d", rand.Int())
|
|
block, err := configtxtest.MakeGenesisBlock(testChannelID)
|
|
if err != nil {
|
|
fmt.Printf("Failed to create a config block, err %s\n", err)
|
|
t.FailNow()
|
|
}
|
|
|
|
err = peerInstance.CreateChannel(testChannelID, block, &ledgermocks.DeployedChaincodeInfoProvider{}, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to create chain %s", err)
|
|
}
|
|
|
|
require.Equal(t, testChannelID, initArg)
|
|
|
|
// Correct ledger
|
|
ledger := peerInstance.GetLedger(testChannelID)
|
|
if ledger == nil {
|
|
t.Fatalf("failed to get correct ledger")
|
|
}
|
|
|
|
// Get config block from ledger
|
|
block, err = ConfigBlockFromLedger(ledger)
|
|
require.NoError(t, err, "Failed to get config block from ledger")
|
|
require.NotNil(t, block, "Config block should not be nil")
|
|
require.Equal(t, uint64(0), block.Header.Number, "config block should have been block 0")
|
|
|
|
// Bad ledger
|
|
ledger = peerInstance.GetLedger("BogusChain")
|
|
if ledger != nil {
|
|
t.Fatalf("got a bogus ledger")
|
|
}
|
|
|
|
// Correct PolicyManager
|
|
pmgr := peerInstance.GetPolicyManager(testChannelID)
|
|
if pmgr == nil {
|
|
t.Fatal("failed to get PolicyManager")
|
|
}
|
|
|
|
// Bad PolicyManager
|
|
pmgr = peerInstance.GetPolicyManager("BogusChain")
|
|
if pmgr != nil {
|
|
t.Fatal("got a bogus PolicyManager")
|
|
}
|
|
|
|
channels := peerInstance.GetChannelsInfo()
|
|
if len(channels) != 1 {
|
|
t.Fatalf("incorrect number of channels")
|
|
}
|
|
}
|
|
|
|
func TestCreateChannelBySnapshot(t *testing.T) {
|
|
peerInstance, cleanup := NewTestPeer(t)
|
|
defer cleanup()
|
|
|
|
var initArg string
|
|
waitCh := make(chan struct{})
|
|
peerInstance.Initialize(
|
|
func(cid string) {
|
|
<-waitCh
|
|
initArg = cid
|
|
},
|
|
nil,
|
|
plugin.MapBasedMapper(map[string]validation.PluginFactory{}),
|
|
&ledgermocks.DeployedChaincodeInfoProvider{},
|
|
nil,
|
|
nil,
|
|
runtime.NumCPU(),
|
|
)
|
|
|
|
testChannelID := "createchannelbysnapshot"
|
|
|
|
// create a temp dir to store snapshot
|
|
tempdir := t.TempDir()
|
|
|
|
snapshotDir := ledgermgmttest.CreateSnapshotWithGenesisBlock(t, tempdir, testChannelID, &ConfigTxProcessor{})
|
|
err := peerInstance.CreateChannelFromSnapshot(snapshotDir, &ledgermocks.DeployedChaincodeInfoProvider{}, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
expectedStatus := &pb.JoinBySnapshotStatus{InProgress: true, BootstrappingSnapshotDir: snapshotDir}
|
|
require.Equal(t, expectedStatus, peerInstance.JoinBySnaphotStatus())
|
|
|
|
// write a msg to waitCh to unblock channel init func
|
|
waitCh <- struct{}{}
|
|
|
|
// wait until ledger creation is done
|
|
ledgerCreationDone := func() bool {
|
|
return !peerInstance.JoinBySnaphotStatus().InProgress
|
|
}
|
|
require.Eventually(t, ledgerCreationDone, time.Minute, time.Second)
|
|
|
|
// verify channel init func is called
|
|
require.Equal(t, testChannelID, initArg)
|
|
|
|
// verify ledger created
|
|
ledger := peerInstance.GetLedger(testChannelID)
|
|
require.NotNil(t, ledger)
|
|
|
|
bcInfo, err := ledger.GetBlockchainInfo()
|
|
require.NoError(t, err)
|
|
require.Equal(t, uint64(1), bcInfo.GetHeight())
|
|
|
|
expectedStatus = &pb.JoinBySnapshotStatus{InProgress: false, BootstrappingSnapshotDir: ""}
|
|
require.Equal(t, expectedStatus, peerInstance.JoinBySnaphotStatus())
|
|
|
|
// Bad ledger
|
|
ledger = peerInstance.GetLedger("BogusChain")
|
|
require.Nil(t, ledger)
|
|
|
|
// Correct PolicyManager
|
|
pmgr := peerInstance.GetPolicyManager(testChannelID)
|
|
require.NotNil(t, pmgr)
|
|
|
|
// Bad PolicyManager
|
|
pmgr = peerInstance.GetPolicyManager("BogusChain")
|
|
require.Nil(t, pmgr)
|
|
|
|
channels := peerInstance.GetChannelsInfo()
|
|
require.Equal(t, 1, len(channels))
|
|
}
|
|
|
|
func TestDeliverSupportManager(t *testing.T) {
|
|
peerInstance, cleanup := NewTestPeer(t)
|
|
defer cleanup()
|
|
|
|
manager := &DeliverChainManager{Peer: peerInstance}
|
|
|
|
chainSupport := manager.GetChain("fake")
|
|
require.Nil(t, chainSupport, "chain support should be nil")
|
|
|
|
peerInstance.channels = map[string]*Channel{"testchain": {}}
|
|
chainSupport = manager.GetChain("testchain")
|
|
require.NotNil(t, chainSupport, "chain support should not be nil")
|
|
}
|
|
|
|
func TestConfigCallback(t *testing.T) {
|
|
peerInstance, cleanup := NewTestPeer(t)
|
|
defer cleanup()
|
|
|
|
var callbackInvoked bool
|
|
peerInstance.AddConfigCallbacks(func(bundle *channelconfig.Bundle) {
|
|
callbackInvoked = true
|
|
orderer, exists := bundle.OrdererConfig()
|
|
require.True(t, exists)
|
|
require.NotEmpty(t, orderer.Organizations()["SampleOrg"].Endpoints)
|
|
})
|
|
|
|
peerInstance.Initialize(
|
|
nil,
|
|
nil,
|
|
plugin.MapBasedMapper(map[string]validation.PluginFactory{}),
|
|
&ledgermocks.DeployedChaincodeInfoProvider{},
|
|
nil,
|
|
nil,
|
|
runtime.NumCPU(),
|
|
)
|
|
|
|
testChannelID := fmt.Sprintf("mytestchannelid-%d", rand.Int())
|
|
block, err := configtxtest.MakeGenesisBlock(testChannelID)
|
|
require.NoError(t, err)
|
|
|
|
// We expect the callback to be invoked when the channel is created
|
|
require.False(t, callbackInvoked)
|
|
|
|
err = peerInstance.CreateChannel(testChannelID, block, &ledgermocks.DeployedChaincodeInfoProvider{}, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
// the callback should have been invoked
|
|
require.True(t, callbackInvoked)
|
|
}
|
|
|
|
func constructLedgerMgrWithTestDefaults(ledgersDataDir string) (*ledgermgmt.LedgerMgr, error) {
|
|
ledgerInitializer := ledgermgmttest.NewInitializer(ledgersDataDir)
|
|
|
|
ledgerInitializer.CustomTxProcessors = map[common.HeaderType]ledger.CustomTxProcessor{
|
|
common.HeaderType_CONFIG: &ConfigTxProcessor{},
|
|
}
|
|
ledgerInitializer.Config.HistoryDBConfig = &ledger.HistoryDBConfig{
|
|
Enabled: true,
|
|
}
|
|
return ledgermgmt.NewLedgerMgr(ledgerInitializer), nil
|
|
}
|
|
|
|
// SetServer sets the gRPC server for the peer.
|
|
// It should only be used in peer/pkg_test.
|
|
func (p *Peer) SetServer(server *comm.GRPCServer) {
|
|
p.server = server
|
|
}
|