190 lines
6.3 KiB
Go
190 lines
6.3 KiB
Go
/*
|
|
Copyright IBM Corp All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/hyperledger/fabric/common/crypto/tlsgen"
|
|
"github.com/hyperledger/fabric/core/container/externalbuilder"
|
|
"github.com/hyperledger/fabric/integration/channelparticipation"
|
|
"github.com/hyperledger/fabric/integration/nwo"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/tedsuo/ifrit"
|
|
ginkgomon "github.com/tedsuo/ifrit/ginkgomon_v2"
|
|
)
|
|
|
|
var _ = Describe("ChaincodeAsExternalServer", func() {
|
|
var (
|
|
testDir string
|
|
network *nwo.Network
|
|
chaincode nwo.Chaincode
|
|
chaincodeServerAddress string
|
|
assetDir string
|
|
ordererRunner *ginkgomon.Runner
|
|
ordererProcess, peerProcess ifrit.Process
|
|
ccserver ifrit.Process
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
var err error
|
|
testDir, err = ioutil.TempDir("", "external-chaincode-server")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
network = nwo.New(nwo.BasicEtcdRaft(), testDir, nil, StartPort(), components)
|
|
network.GenerateConfigTree()
|
|
network.Bootstrap()
|
|
|
|
// Create the configuration
|
|
chaincodeServerAddress = fmt.Sprintf("127.0.0.1:%d", network.ReservePort())
|
|
connData, serverKeyPair := generateChaincodeConfig(chaincodeServerAddress)
|
|
|
|
// Create directory for configuration files
|
|
assetDir, err = ioutil.TempDir(testDir, "assets")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Write the config files
|
|
connJSON, err := json.Marshal(connData)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
err = ioutil.WriteFile(filepath.Join(assetDir, "connection.json"), connJSON, 0o644)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
configJSON, err := json.Marshal(serverKeyPair)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
err = ioutil.WriteFile(filepath.Join(assetDir, "config.json"), configJSON, 0o644)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Setup the network
|
|
ordererRunner, ordererProcess, peerProcess = network.StartSingleOrdererNetwork("orderer")
|
|
|
|
channelparticipation.JoinOrdererJoinPeersAppChannel(network, "testchannel", network.Orderer("orderer"), ordererRunner)
|
|
|
|
nwo.EnableCapabilities(
|
|
network,
|
|
"testchannel",
|
|
"Application", "V2_0",
|
|
network.Orderer("orderer"),
|
|
network.Peer("Org1", "peer0"), network.Peer("Org2", "peer0"),
|
|
)
|
|
|
|
// set to use the 'ccaas' builder rathern than binary
|
|
// binary build remains as an example of a scripted approach
|
|
chaincode = nwo.Chaincode{
|
|
Name: "mycc",
|
|
Version: "0.0",
|
|
Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/server"),
|
|
Lang: "ccaas",
|
|
PackageFile: filepath.Join(testDir, "server.tar.gz"),
|
|
Ctor: `{"Args":["init","a","100","b","200"]}`,
|
|
InitRequired: true,
|
|
SignaturePolicy: `AND ('Org1MSP.member','Org2MSP.member')`,
|
|
Sequence: "1",
|
|
Label: "my_server_chaincode",
|
|
CodeFiles: map[string]string{
|
|
filepath.Join(assetDir, "connection.json"): "connection.json",
|
|
filepath.Join(assetDir, "config.json"): "config.json",
|
|
},
|
|
}
|
|
})
|
|
|
|
AfterEach(func() {
|
|
if ccserver != nil {
|
|
ccserver.Signal(syscall.SIGTERM)
|
|
Eventually(ccserver.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
if peerProcess != nil {
|
|
peerProcess.Signal(syscall.SIGTERM)
|
|
Eventually(peerProcess.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
if ordererProcess != nil {
|
|
ordererProcess.Signal(syscall.SIGTERM)
|
|
Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
if network != nil {
|
|
network.Cleanup()
|
|
}
|
|
os.RemoveAll(testDir)
|
|
})
|
|
|
|
It("executes a basic etcdraft network with 2 orgs and external chaincode server", func() {
|
|
orderer := network.Orderer("orderer")
|
|
peer := network.Peer("Org1", "peer0")
|
|
peers := network.PeersWithChannel("testchannel")
|
|
|
|
By("packaging and installing the chaincode")
|
|
nwo.PackageAndInstallChaincode(network, chaincode, peers...)
|
|
chaincode.SetPackageIDFromPackageFile()
|
|
|
|
By("approving and committing the chaincode")
|
|
nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, peers...)
|
|
nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), peers...)
|
|
nwo.CommitChaincode(network, "testchannel", orderer, chaincode, peer, peers...)
|
|
|
|
By("starting the chaincode server")
|
|
ccserver = ifrit.Invoke(ginkgomon.New(ginkgomon.Config{
|
|
Name: chaincode.PackageID,
|
|
Command: &exec.Cmd{
|
|
Path: chaincode.Path,
|
|
Args: []string{chaincode.Path, chaincode.PackageID, chaincodeServerAddress},
|
|
Dir: assetDir,
|
|
},
|
|
StartCheck: `Starting chaincode ` + chaincode.PackageID + ` at ` + chaincodeServerAddress,
|
|
StartCheckTimeout: 15 * time.Second,
|
|
}))
|
|
Eventually(ccserver.Ready(), network.EventuallyTimeout).Should(BeClosed())
|
|
|
|
By("exercising the chaincode")
|
|
nwo.InitChaincode(network, "testchannel", orderer, chaincode, network.PeersWithChannel("testchannel")...)
|
|
RunQueryInvokeQuery(network, orderer, peer, "testchannel")
|
|
RunRespondWith(network, orderer, peer, "testchannel")
|
|
})
|
|
})
|
|
|
|
type chaincodeConfig struct {
|
|
ListenAddress string `json:"listen_address,omitempty"`
|
|
Key string `json:"key,omitempty"` // PEM encoded key
|
|
Cert string `json:"cert,omitempty"` // PEM encoded certificate
|
|
CA string `json:"ca,omitempty"` // PEM encode CA certificate
|
|
}
|
|
|
|
func generateChaincodeConfig(chaincodeAddress string) (externalbuilder.ChaincodeServerUserData, chaincodeConfig) {
|
|
tlsCA, err := tlsgen.NewCA()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
serverPair, err := tlsCA.NewServerCertKeyPair("127.0.0.1")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
clientPair, err := tlsCA.NewClientCertKeyPair()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
config := chaincodeConfig{
|
|
ListenAddress: chaincodeAddress,
|
|
Key: string(serverPair.Key),
|
|
Cert: string(serverPair.Cert),
|
|
CA: string(tlsCA.CertBytes()),
|
|
}
|
|
|
|
connData := externalbuilder.ChaincodeServerUserData{
|
|
Address: chaincodeAddress,
|
|
DialTimeout: externalbuilder.Duration(10 * time.Second),
|
|
TLSRequired: true,
|
|
ClientAuthRequired: true,
|
|
ClientKey: string(clientPair.Key),
|
|
ClientCert: string(clientPair.Cert),
|
|
RootCert: string(tlsCA.CertBytes()),
|
|
}
|
|
|
|
return connData, config
|
|
}
|