From 2f6433f946362e7fa0c2bafcc868b757203d194c Mon Sep 17 00:00:00 2001 From: "Binh Q. Nguyen" Date: Fri, 16 Dec 2016 20:22:22 -0500 Subject: [PATCH] FAB-1022 Call gossip when a peer join channel 1/06/17 Fixing cscc and lscc path uniqueness 12/21 Fixing MSP config path to work in both CI and local test 12/19 Fixing PEER_CFG_PATH and config builder loader of certs to avoid CI failures 12/19 Adding port to peer local IP Beside integrating gossip, this commit also includes: - changing the package of cscc to avoid import cycle - calling MSP to set up security configuration for chains - initializing system chaincodes for each chain - more unit tests. Change-Id: I62b3532e3c18ff95567cf5f80450286b63a1e959 Signed-off-by: Binh Q. Nguyen --- .../configer.go} | 28 ++++++----- .../configer_test.go} | 46 +++++++++++++++---- core/chaincode/importsysccs.go | 7 ++- core/peer/peer.go | 17 +++---- core/peer/peer_test.go | 2 +- msp/configbuilder.go | 8 ++-- protos/utils/blockutils.go | 29 ++++++++++++ 7 files changed, 98 insertions(+), 39 deletions(-) rename core/{system_chaincode/cscc/peer_configer.go => chaincode/configer.go} (87%) rename core/{system_chaincode/cscc/peer_configer_test.go => chaincode/configer_test.go} (80%) diff --git a/core/system_chaincode/cscc/peer_configer.go b/core/chaincode/configer.go similarity index 87% rename from core/system_chaincode/cscc/peer_configer.go rename to core/chaincode/configer.go index a94b81e66a1..159da89574d 100644 --- a/core/system_chaincode/cscc/peer_configer.go +++ b/core/chaincode/configer.go @@ -14,18 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package cscc (configuration system chaincode) provides functions to manage +// Package chaincode configer provides functions to manage // configuration transactions as the network is being reconfigured. The // configuration transactions arrive from the ordering service to the committer // who calls this chaincode. The chaincode also provides peer configuration // services such as joining a chain or getting configuration data. -package cscc +package chaincode import ( "errors" "fmt" - // "github.com/golang/protobuf/proto" "github.com/op/go-logging" "github.com/hyperledger/fabric/core/chaincode/shim" @@ -39,7 +38,7 @@ import ( type PeerConfiger struct { } -var logger = logging.MustGetLogger("cscc") +var cnflogger = logging.MustGetLogger("chaincode") // These are function names from Invoke first parameter const ( @@ -52,7 +51,7 @@ const ( // This allows the chaincode to initialize any variables on the ledger prior // to any transaction execution on the chain. func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) ([]byte, error) { - logger.Info("Init CSCC") + cnflogger.Info("Init CSCC") return nil, nil } @@ -75,7 +74,7 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error) } fname := string(args[0]) - logger.Debugf("Invoke function: %s", fname) + cnflogger.Debugf("Invoke function: %s", fname) // TODO: Handle ACL @@ -103,11 +102,20 @@ func joinChain(blockBytes []byte) ([]byte, error) { return nil, fmt.Errorf("Failed to reconstruct the genesis block, %s", err) } - if err := peer.CreateChainFromBlock(block); err != nil { + if err = peer.CreateChainFromBlock(block); err != nil { return nil, err } - return nil, nil + chainID, err := utils.GetChainIDFromBlock(block) + if err != nil { + return nil, fmt.Errorf("Failed to get the chain ID from the configuration block, %s", err) + } + + // Initialize all system chainodes on this chain + // TODO: Fix this code to initialize instead of deploy chaincodes + DeploySysCCs(chainID) + + return []byte("200"), nil } func updateConfigBlock(blockBytes []byte) ([]byte, error) { @@ -127,9 +135,7 @@ func updateConfigBlock(blockBytes []byte) ([]byte, error) { return nil, err } - // TODO: would committer get ledger and update ? - - return nil, nil + return []byte("200"), nil } // Return the current configuration block for the specified chainID. If the diff --git a/core/system_chaincode/cscc/peer_configer_test.go b/core/chaincode/configer_test.go similarity index 80% rename from core/system_chaincode/cscc/peer_configer_test.go rename to core/chaincode/configer_test.go index 3681380879c..871758130be 100644 --- a/core/system_chaincode/cscc/peer_configer_test.go +++ b/core/chaincode/configer_test.go @@ -13,13 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package cscc +package chaincode import ( "fmt" "net" "os" "testing" + "time" "github.com/spf13/viper" "github.com/stretchr/testify/assert" @@ -27,12 +28,14 @@ import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/core/chaincode/shim" + "github.com/hyperledger/fabric/core/peer" "github.com/hyperledger/fabric/gossip/service" "github.com/hyperledger/fabric/protos/common" + pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" ) -func TestInit(t *testing.T) { +func TestConfigerInit(t *testing.T) { e := new(PeerConfiger) stub := shim.NewMockStub("PeerConfiger", e) @@ -42,13 +45,31 @@ func TestInit(t *testing.T) { } } -func TestInvokeJoinChainMissingParams(t *testing.T) { +func setupEndpoint(t *testing.T) { + peerAddress := peer.GetLocalIP() + if peerAddress == "" { + peerAddress = "0.0.0.0" + } + peerAddress = peerAddress + ":21213" + t.Logf("Local peer IP address: %s", peerAddress) + var opts []grpc.ServerOption + grpcServer := grpc.NewServer(opts...) + getPeerEndpoint := func() (*pb.PeerEndpoint, error) { + return &pb.PeerEndpoint{ID: &pb.PeerID{Name: "cscctestpeer"}, Address: peerAddress}, nil + } + ccStartupTimeout := time.Duration(30000) * time.Millisecond + pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(getPeerEndpoint, false, ccStartupTimeout)) +} + +func TestConfigerInvokeJoinChainMissingParams(t *testing.T) { + //t.Skip("Test CI build") viper.Set("peer.fileSystemPath", "/var/hyperledger/test/") defer os.RemoveAll("/var/hyperledger/test/") e := new(PeerConfiger) stub := shim.NewMockStub("PeerConfiger", e) + setupEndpoint(t) // Failed path: Not enough parameters args := [][]byte{[]byte("JoinChain")} if _, err := stub.MockInvoke("1", args); err == nil { @@ -56,13 +77,16 @@ func TestInvokeJoinChainMissingParams(t *testing.T) { } } -func TestInvokeJoinChainWrongParams(t *testing.T) { +func TestConfigerInvokeJoinChainWrongParams(t *testing.T) { + //t.Skip("Test CI build") viper.Set("peer.fileSystemPath", "/var/hyperledger/test/") defer os.RemoveAll("/var/hyperledger/test/") e := new(PeerConfiger) stub := shim.NewMockStub("PeerConfiger", e) + setupEndpoint(t) + // Failed path: wrong parameter type args := [][]byte{[]byte("JoinChain"), []byte("action")} if _, err := stub.MockInvoke("1", args); err == nil { @@ -71,13 +95,16 @@ func TestInvokeJoinChainWrongParams(t *testing.T) { } } -func TestInvokeJoinChainCorrectParams(t *testing.T) { +func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) { + //t.Skip("Test CI build") viper.Set("peer.fileSystemPath", "/var/hyperledger/test/") defer os.RemoveAll("/var/hyperledger/test/") e := new(PeerConfiger) stub := shim.NewMockStub("PeerConfiger", e) + setupEndpoint(t) + // Initialize gossip service grpcServer := grpc.NewServer() socket, err := net.Listen("tcp", fmt.Sprintf("%s:%d", "", 13611)) @@ -92,7 +119,7 @@ func TestInvokeJoinChainCorrectParams(t *testing.T) { t.Fatalf("cscc invoke JoinChain failed because invalid block") } args := [][]byte{[]byte("JoinChain"), blockBytes} - if _, err := stub.MockInvoke("1", args); err != nil { + if _, err = stub.MockInvoke("1", args); err != nil { t.Fatalf("cscc invoke JoinChain failed with: %v", err) } @@ -103,15 +130,18 @@ func TestInvokeJoinChainCorrectParams(t *testing.T) { t.Fatalf("cscc invoke JoinChain failed with: %v", err) } args = [][]byte{[]byte("GetConfigBlock"), []byte(chainID)} - if _, err := stub.MockInvoke("1", args); err != nil { + if _, err = stub.MockInvoke("1", args); err != nil { t.Fatalf("cscc invoke GetConfigBlock failed with: %v", err) } } -func TestInvokeUpdateConfigBlock(t *testing.T) { +func TestConfigerInvokeUpdateConfigBlock(t *testing.T) { + //t.Skip("Test CI build") e := new(PeerConfiger) stub := shim.NewMockStub("PeerConfiger", e) + setupEndpoint(t) + // Failed path: Not enough parameters args := [][]byte{[]byte("UpdateConfigBlock")} if _, err := stub.MockInvoke("1", args); err == nil { diff --git a/core/chaincode/importsysccs.go b/core/chaincode/importsysccs.go index 2406d23d79b..0668cf1f964 100644 --- a/core/chaincode/importsysccs.go +++ b/core/chaincode/importsysccs.go @@ -18,7 +18,6 @@ package chaincode import ( //import system chain codes here - "github.com/hyperledger/fabric/core/system_chaincode/cscc" "github.com/hyperledger/fabric/core/system_chaincode/escc" "github.com/hyperledger/fabric/core/system_chaincode/vscc" ) @@ -29,15 +28,15 @@ var systemChaincodes = []*SystemChaincode{ ChainlessCC: true, Enabled: true, Name: "cscc", - Path: "github.com/hyperledger/fabric/core/system_chaincode/cscc", + Path: "github.com/hyperledger/fabric/core/chaincode/cscc", InitArgs: [][]byte{[]byte("")}, - Chaincode: &cscc.PeerConfiger{}, + Chaincode: &PeerConfiger{}, }, { ChainlessCC: false, Enabled: true, Name: "lccc", - Path: "github.com/hyperledger/fabric/core/chaincode", + Path: "github.com/hyperledger/fabric/core/chaincode/lscc", InitArgs: [][]byte{[]byte("")}, Chaincode: &LifeCycleSysCC{}, }, diff --git a/core/peer/peer.go b/core/peer/peer.go index eb140ecb15a..2834f66c8ba 100644 --- a/core/peer/peer.go +++ b/core/peer/peer.go @@ -29,11 +29,10 @@ import ( "github.com/op/go-logging" "github.com/spf13/viper" - // "github.com/hyperledger/fabric/core/chaincode" "github.com/hyperledger/fabric/core/comm" "github.com/hyperledger/fabric/core/committer" "github.com/hyperledger/fabric/core/ledger/kvledger" - // "github.com/hyperledger/fabric/core/peer/msp" + "github.com/hyperledger/fabric/core/peer/msp" "github.com/hyperledger/fabric/gossip/service" "github.com/hyperledger/fabric/msp" "github.com/hyperledger/fabric/protos/common" @@ -139,22 +138,18 @@ func getCurrConfigBlockFromLedger(ledger *kvledger.KVLedger) (*common.Block, err func createChain(cid string, ledger *kvledger.KVLedger, cb *common.Block) error { c := committer.NewLedgerCommitter(ledger) - // TODO: Call MSP to load from config block - // mgr, err := mspmgmt.GetMSPManagerFromBlock(cb) - // if err != nil { - // return err - // } + mgr, err := mspmgmt.GetMSPManagerFromBlock(cb) + if err != nil { + return err + } if err := service.GetGossipService().JoinChannel(c, cb); err != nil { return err } - // Initialize all system chaincodes on this chain - // chaincode.DeploySysCCs(cid) - chains.Lock() defer chains.Unlock() - chains.list[cid] = &chain{cb: cb, ledger: ledger, mspmgr: nil, committer: c} + chains.list[cid] = &chain{cb: cb, ledger: ledger, mspmgr: mgr, committer: c} return nil } diff --git a/core/peer/peer_test.go b/core/peer/peer_test.go index f9d0f5f12ae..0b3e7b84435 100644 --- a/core/peer/peer_test.go +++ b/core/peer/peer_test.go @@ -56,7 +56,7 @@ func TestCreateChainFromBlock(t *testing.T) { err = CreateChainFromBlock(block) if err != nil { - t.Fatalf("failed to create chain") + t.Fatalf("failed to create chain %s", err) } // Correct ledger diff --git a/msp/configbuilder.go b/msp/configbuilder.go index 30f10e2e4a4..028ef2b2e6c 100644 --- a/msp/configbuilder.go +++ b/msp/configbuilder.go @@ -70,10 +70,10 @@ const ( ) func GetLocalMspConfig(dir string) (*msp.MSPConfig, error) { - cacertDir := dir + string(filepath.Separator) + cacerts - signcertDir := dir + string(filepath.Separator) + signcerts - admincertDir := dir + string(filepath.Separator) + admincerts - keystoreDir := dir + string(filepath.Separator) + keystore + cacertDir := filepath.Join(dir, cacerts) + signcertDir := filepath.Join(dir, signcerts) + admincertDir := filepath.Join(dir, admincerts) + keystoreDir := filepath.Join(dir, keystore) cacerts, err := getPemMaterialFromDir(cacertDir) if err != nil || len(cacerts) == 0 { diff --git a/protos/utils/blockutils.go b/protos/utils/blockutils.go index 45dc453632b..2d88f46fbf2 100644 --- a/protos/utils/blockutils.go +++ b/protos/utils/blockutils.go @@ -18,11 +18,14 @@ package utils import ( "fmt" + "io/ioutil" + "os" "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" "github.com/hyperledger/fabric/common/configtx" + "github.com/hyperledger/fabric/msp" cb "github.com/hyperledger/fabric/protos/common" ab "github.com/hyperledger/fabric/protos/orderer" ) @@ -82,6 +85,7 @@ func MakeConfigurationBlock(testChainID string) (*cb.Block, error) { encodeConsensusType(testChainID), encodeBatchSize(testChainID), lockDefaultModificationPolicy(testChainID), + encodeMSP(testChainID), ) payloadChainHeader := MakeChainHeader(cb.HeaderType_CONFIGURATION_TRANSACTION, configItemChainHeader.Version, testChainID, epoch) @@ -111,6 +115,7 @@ const ( lastModified = uint64(0) consensusTypeKey = "ConsensusType" batchSizeKey = "BatchSize" + mspKey = "MSP" ) func createSignedConfigItem(chainID string, @@ -149,3 +154,27 @@ func lockDefaultModificationPolicy(testChainID string) *cb.SignedConfigurationIt MarshalOrPanic(MakePolicyOrPanic(cauthdsl.RejectAllPolicy)), configtx.DefaultModificationPolicyID) } + +// This function is needed to locate the MSP test configuration when running +// in CI build env or local with "make unit-test". A better way to manage this +// is to define a config path in yaml that may point to test or production +// location of the config +func getTESTMSPConfigPath() string { + cfgPath := os.Getenv("PEER_CFG_PATH") + "/msp/sampleconfig/" + if _, err := ioutil.ReadDir(cfgPath); err != nil { + cfgPath = os.Getenv("GOPATH") + "/src/github.com/hyperledger/fabric/msp/sampleconfig/" + } + return cfgPath +} + +func encodeMSP(testChainID string) *cb.SignedConfigurationItem { + cfgPath := getTESTMSPConfigPath() + conf, err := msp.GetLocalMspConfig(cfgPath) + if err != nil { + panic(fmt.Sprintf("GetLocalMspConfig failed, err %s", err)) + } + return createSignedConfigItem(testChainID, + mspKey, + MarshalOrPanic(conf), + configtx.DefaultModificationPolicyID) +}