229 lines
6.4 KiB
Go
229 lines
6.4 KiB
Go
/*
|
|
Copyright IBM Corp All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package lifecycle
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
|
|
pcommon "github.com/hyperledger/fabric-protos-go/common"
|
|
ab "github.com/hyperledger/fabric-protos-go/orderer"
|
|
pb "github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric/common/flogging"
|
|
"github.com/hyperledger/fabric/integration"
|
|
"github.com/hyperledger/fabric/integration/nwo"
|
|
"github.com/hyperledger/fabric/integration/nwo/commands"
|
|
"github.com/hyperledger/fabric/integration/nwo/template"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/onsi/gomega/gbytes"
|
|
"github.com/onsi/gomega/gexec"
|
|
)
|
|
|
|
func TestLifecycle(t *testing.T) {
|
|
RegisterFailHandler(Fail)
|
|
RunSpecs(t, "Lifecycle Suite")
|
|
}
|
|
|
|
var (
|
|
buildServer *nwo.BuildServer
|
|
components *nwo.Components
|
|
)
|
|
|
|
var _ = SynchronizedBeforeSuite(func() []byte {
|
|
buildServer = nwo.NewBuildServer()
|
|
buildServer.Serve()
|
|
|
|
components = buildServer.Components()
|
|
payload, err := json.Marshal(components)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
return payload
|
|
}, func(payload []byte) {
|
|
err := json.Unmarshal(payload, &components)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
flogging.SetWriter(GinkgoWriter)
|
|
})
|
|
|
|
var _ = SynchronizedAfterSuite(func() {
|
|
}, func() {
|
|
buildServer.Shutdown()
|
|
})
|
|
|
|
func StartPort() int {
|
|
return integration.LifecyclePort.StartPortForNode()
|
|
}
|
|
|
|
func RunQueryInvokeQuery(n *nwo.Network, orderer *nwo.Orderer, chaincodeName string, initialQueryResult int, peers ...*nwo.Peer) {
|
|
if len(peers) == 0 {
|
|
peers = n.PeersWithChannel("testchannel")
|
|
}
|
|
|
|
addresses := make([]string, len(peers))
|
|
for i, peer := range peers {
|
|
addresses[i] = n.PeerAddress(peer, nwo.ListenPort)
|
|
}
|
|
|
|
By("querying the chaincode")
|
|
sess, err := n.PeerUserSession(peers[0], "User1", commands.ChaincodeQuery{
|
|
ChannelID: "testchannel",
|
|
Name: chaincodeName,
|
|
Ctor: `{"Args":["query","a"]}`,
|
|
})
|
|
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
|
EventuallyWithOffset(1, sess, n.EventuallyTimeout).Should(gexec.Exit(0))
|
|
ExpectWithOffset(1, sess).To(gbytes.Say(fmt.Sprint(initialQueryResult)))
|
|
|
|
By("invoking the chaincode")
|
|
sess, err = n.PeerUserSession(peers[0], "User1", commands.ChaincodeInvoke{
|
|
ChannelID: "testchannel",
|
|
Orderer: n.OrdererAddress(orderer, nwo.ListenPort),
|
|
Name: chaincodeName,
|
|
Ctor: `{"Args":["invoke","a","b","10"]}`,
|
|
PeerAddresses: addresses,
|
|
WaitForEvent: true,
|
|
})
|
|
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
|
EventuallyWithOffset(1, sess, n.EventuallyTimeout).Should(gexec.Exit(0))
|
|
ExpectWithOffset(1, sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
|
|
|
|
By("querying the chaincode")
|
|
sess, err = n.PeerUserSession(peers[0], "User1", commands.ChaincodeQuery{
|
|
ChannelID: "testchannel",
|
|
Name: chaincodeName,
|
|
Ctor: `{"Args":["query","a"]}`,
|
|
})
|
|
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
|
EventuallyWithOffset(1, sess, n.EventuallyTimeout).Should(gexec.Exit(0))
|
|
ExpectWithOffset(1, sess).To(gbytes.Say(fmt.Sprint(initialQueryResult - 10)))
|
|
}
|
|
|
|
func SignedProposal(channel, chaincode string, signer *nwo.SigningIdentity, args ...string) (*pb.SignedProposal, *pb.Proposal, string) {
|
|
byteArgs := make([][]byte, 0, len(args))
|
|
for _, arg := range args {
|
|
byteArgs = append(byteArgs, []byte(arg))
|
|
}
|
|
serializedSigner, err := signer.Serialize()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
prop, txid, err := protoutil.CreateChaincodeProposalWithTxIDAndTransient(
|
|
pcommon.HeaderType_ENDORSER_TRANSACTION,
|
|
channel,
|
|
&pb.ChaincodeInvocationSpec{
|
|
ChaincodeSpec: &pb.ChaincodeSpec{
|
|
Type: pb.ChaincodeSpec_GOLANG,
|
|
ChaincodeId: &pb.ChaincodeID{
|
|
Name: chaincode,
|
|
},
|
|
Input: &pb.ChaincodeInput{
|
|
Args: byteArgs,
|
|
},
|
|
},
|
|
},
|
|
serializedSigner,
|
|
"",
|
|
nil,
|
|
)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(prop).NotTo(BeNil())
|
|
|
|
signedProp, err := protoutil.GetSignedProposal(prop, signer)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(signedProp).NotTo(BeNil())
|
|
|
|
return signedProp, prop, txid
|
|
}
|
|
|
|
func CommitTx(nw *nwo.Network, tx *pcommon.Envelope, peer *nwo.Peer, dc pb.DeliverClient, oc ab.AtomicBroadcast_BroadcastClient, signer *nwo.SigningIdentity, txid string) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
df, err := dc.DeliverFiltered(ctx)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
defer df.CloseSend()
|
|
|
|
deliverEnvelope, err := protoutil.CreateSignedEnvelope(
|
|
pcommon.HeaderType_DELIVER_SEEK_INFO,
|
|
"testchannel",
|
|
signer,
|
|
&ab.SeekInfo{
|
|
Behavior: ab.SeekInfo_BLOCK_UNTIL_READY,
|
|
Start: &ab.SeekPosition{
|
|
Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}},
|
|
},
|
|
Stop: &ab.SeekPosition{
|
|
Type: &ab.SeekPosition_Specified{
|
|
Specified: &ab.SeekSpecified{Number: math.MaxUint64},
|
|
},
|
|
},
|
|
},
|
|
0,
|
|
0,
|
|
)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
err = df.Send(deliverEnvelope)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
err = oc.Send(tx)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
for {
|
|
resp, err := df.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fb, ok := resp.Type.(*pb.DeliverResponse_FilteredBlock)
|
|
if !ok {
|
|
return fmt.Errorf("unexpected filtered block, received %T", resp.Type)
|
|
}
|
|
for _, tx := range fb.FilteredBlock.FilteredTransactions {
|
|
if tx.Txid != txid {
|
|
continue
|
|
}
|
|
if tx.TxValidationCode != pb.TxValidationCode_VALID {
|
|
return fmt.Errorf("transaction invalidated with status (%s)", tx.TxValidationCode)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// GenerateOrgUpdateMeterials generates the necessary configtx and
|
|
// crypto materials for a new org's peers to join a network
|
|
func GenerateOrgUpdateMaterials(n *nwo.Network, peers ...*nwo.Peer) {
|
|
orgUpdateNetwork := *n
|
|
orgUpdateNetwork.Peers = peers
|
|
orgUpdateNetwork.Templates = &nwo.Templates{
|
|
ConfigTx: template.OrgUpdateConfigTxTemplate,
|
|
Crypto: template.OrgUpdateCryptoTemplate,
|
|
Core: n.Templates.CoreTemplate(),
|
|
}
|
|
|
|
orgUpdateNetwork.GenerateConfigTxConfig()
|
|
for _, peer := range peers {
|
|
orgUpdateNetwork.GenerateCoreConfig(peer)
|
|
}
|
|
|
|
orgUpdateNetwork.GenerateCryptoConfig()
|
|
sess, err := orgUpdateNetwork.Cryptogen(commands.Generate{
|
|
Config: orgUpdateNetwork.CryptoConfigPath(),
|
|
Output: orgUpdateNetwork.CryptoPath(),
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, orgUpdateNetwork.EventuallyTimeout).Should(gexec.Exit(0))
|
|
|
|
// refresh TLSCACertificates ca-certs.pem so that it includes
|
|
// the newly generated cert
|
|
n.ConcatenateTLSCACertificates()
|
|
}
|