Skip to content

Commit

Permalink
Add integration "ApproveChaincodeDefinitionForMyOrg"
Browse files Browse the repository at this point in the history
FAB-14017

Change-Id: Iac00ff8368f01c1553448fcd50f2840b5c16a180
Signed-off-by: Will Lahti <wtlahti@us.ibm.com>
Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
  • Loading branch information
wlahti committed Mar 5, 2019
1 parent ce4b38c commit faf1f99
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 37 deletions.
2 changes: 1 addition & 1 deletion integration/discovery/discovery_test.go
Expand Up @@ -180,7 +180,7 @@ var _ = Describe("DiscoveryService", func() {
currentConfig := nwo.GetConfig(network, network.Peer("org3", "peer0"), orderer, "testchannel")
updatedConfig := proto.Clone(currentConfig).(*common.Config)
updatedConfig.ChannelGroup.Groups["Application"].Groups["org3"].Policies["Writers"].Policy.Value = protoutil.MarshalOrPanic(cauthdsl.SignedByMspAdmin("Org3MSP"))
nwo.UpdateConfig(network, orderer, "testchannel", currentConfig, updatedConfig, network.Peer("org3", "peer0"))
nwo.UpdateConfig(network, orderer, "testchannel", currentConfig, updatedConfig, true, network.Peer("org3", "peer0"))

By("trying to discover peers as an org 3 member")
endorsers = commands.Endorsers{
Expand Down
2 changes: 1 addition & 1 deletion integration/e2e/acl_test.go
Expand Up @@ -261,7 +261,7 @@ func SetACLPolicy(network *nwo.Network, channel, policyName, policy string, orde
}),
}

nwo.UpdateConfig(network, orderer, channel, config, updatedConfig, submitter, signer)
nwo.UpdateConfig(network, orderer, channel, config, updatedConfig, true, submitter, signer)
}

// GetTxIDFromBlock gets a transaction id from a block that has been
Expand Down
53 changes: 53 additions & 0 deletions integration/nwo/commands/peer.go
Expand Up @@ -196,6 +196,59 @@ func (c ChaincodeInstall) Args() []string {
return args
}

type ChaincodeApproveForMyOrg struct {
ChannelID string
Orderer string
Name string
Version string
Hash string
Sequence string
EndorsementPlugin string
ValidationPlugin string
Policy string
InitRequired bool
CollectionsConfig string
PeerAddresses []string
WaitForEvent bool
}

func (c ChaincodeApproveForMyOrg) SessionName() string {
return "peer-chaincode-approveformyorg"
}

func (c ChaincodeApproveForMyOrg) Args() []string {
args := []string{
"chaincode", "approveformyorg",
"--channelID", c.ChannelID,
"--orderer", c.Orderer,
"--name", c.Name,
"--version", c.Version,
"--hash", c.Hash,
"--sequence", c.Sequence,
"--escc", c.EndorsementPlugin,
"--vscc", c.ValidationPlugin,
"--policy", c.Policy,
}

if c.InitRequired {
args = append(args, "--init-required")
}

if c.CollectionsConfig != "" {
args = append(args, "--collections-config", c.CollectionsConfig)
}

for _, p := range c.PeerAddresses {
args = append(args, "--peerAddresses", p)
}

if c.WaitForEvent {
args = append(args, "--waitForEvent")
}

return args
}

type ChaincodeInstantiate struct {
ChannelID string
Orderer string
Expand Down
42 changes: 38 additions & 4 deletions integration/nwo/configblock.go
Expand Up @@ -71,7 +71,7 @@ func GetConfig(n *Network, peer *Peer, orderer *Orderer, channel string) *common

// UpdateConfig computes, signs, and submits a configuration update and waits
// for the update to complete.
func UpdateConfig(n *Network, orderer *Orderer, channel string, current, updated *common.Config, submitter *Peer, additionalSigners ...*Peer) {
func UpdateConfig(n *Network, orderer *Orderer, channel string, current, updated *common.Config, getConfigBlockFromOrderer bool, submitter *Peer, additionalSigners ...*Peer) {
tempDir, err := ioutil.TempDir("", "updateConfig")
Expect(err).NotTo(HaveOccurred())
defer os.RemoveAll(tempDir)
Expand Down Expand Up @@ -102,8 +102,13 @@ func UpdateConfig(n *Network, orderer *Orderer, channel string, current, updated
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
}

var currentBlockNumber uint64
// get current configuration block number
currentBlockNumber := CurrentConfigBlockNumber(n, submitter, orderer, channel)
if getConfigBlockFromOrderer {
currentBlockNumber = CurrentConfigBlockNumber(n, submitter, orderer, channel)
} else {
currentBlockNumber = CurrentConfigBlockNumber(n, submitter, nil, channel)
}

sess, err := n.PeerAdminSession(submitter, commands.ChannelUpdate{
ChannelID: channel,
Expand All @@ -114,10 +119,15 @@ func UpdateConfig(n *Network, orderer *Orderer, channel string, current, updated
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
Expect(sess.Err).To(gbytes.Say("Successfully submitted channel update"))

if getConfigBlockFromOrderer {
ccb := func() uint64 { return CurrentConfigBlockNumber(n, submitter, orderer, channel) }
Eventually(ccb, n.EventuallyTimeout).Should(BeNumerically(">", currentBlockNumber))
return
}
// wait for the block to be committed to all peers that
// have joined the channel
for _, peer := range n.PeersWithChannel(channel) {
ccb := func() uint64 { return CurrentConfigBlockNumber(n, peer, orderer, channel) }
ccb := func() uint64 { return CurrentConfigBlockNumber(n, peer, nil, channel) }
Eventually(ccb, n.EventuallyTimeout).Should(BeNumerically(">", currentBlockNumber))
}
}
Expand Down Expand Up @@ -160,14 +170,20 @@ func UpdateOrdererConfig(n *Network, orderer *Orderer, channel string, current,

// CurrentConfigBlockNumber retrieves the block number from the header of the
// current config block. This can be used to detect when configuration change
// has completed.
// has completed. If an orderer is not provided, the current config block will
// be fetched from the peer.
func CurrentConfigBlockNumber(n *Network, peer *Peer, orderer *Orderer, channel string) uint64 {
tempDir, err := ioutil.TempDir("", "currentConfigBlock")
Expect(err).NotTo(HaveOccurred())
defer os.RemoveAll(tempDir)

// fetch the config block
output := filepath.Join(tempDir, "config_block.pb")

if orderer == nil {
return CurrentConfigBlockNumberFromPeer(n, peer, channel, output)
}

sess, err := n.OrdererAdminSession(orderer, peer, commands.ChannelFetch{
ChannelID: channel,
Block: "config",
Expand All @@ -180,6 +196,24 @@ func CurrentConfigBlockNumber(n *Network, peer *Peer, orderer *Orderer, channel

// unmarshal the config block bytes
configBlock := UnmarshalBlockFromFile(output)

return configBlock.Header.Number
}

// CurrentConfigBlockNumberFromPeer retrieves the block number from the header
// of the peer's current config block.
func CurrentConfigBlockNumberFromPeer(n *Network, peer *Peer, channel, output string) uint64 {
sess, err := n.PeerAdminSession(peer, commands.ChannelFetch{
ChannelID: channel,
Block: "config",
OutputFile: output,
})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
Expect(sess.Err).To(gbytes.Say("Received block: "))

configBlock := UnmarshalBlockFromFile(output)

return configBlock.Header.Number
}

Expand Down
2 changes: 1 addition & 1 deletion integration/nwo/core_template.go
Expand Up @@ -59,7 +59,7 @@ peer:
leaderAliveThreshold: 10s
leaderElectionDuration: 5s
pvtData:
pullRetryThreshold: 60s
pullRetryThreshold: 15s
transientstoreMaxBlockRetention: 1000
pushAckTimeout: 3s
reconcileBatchSize: 10
Expand Down
107 changes: 93 additions & 14 deletions integration/nwo/deploy.go
Expand Up @@ -7,11 +7,16 @@ SPDX-License-Identifier: Apache-2.0
package nwo

import (
"encoding/hex"
"fmt"
"io/ioutil"
"os"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/integration/nwo/commands"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protoutil"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec"
Expand All @@ -26,15 +31,22 @@ type Chaincode struct {
Lang string
CollectionsConfig string // optional
PackageFile string
Hash string
Sequence string
EndorsementPlugin string
ValidationPlugin string
InitRequired bool
}

// DeployChaincodePlusLifecycle is a helper that will install chaincode to all
// peers that are connected to the specified channel, instantiate the chaincode
// on one of the peers, and wait for the instantiation to complete on all of
// the peers. It uses the _lifecycle implementation.
// TODO: add _lifecycle DefineChaincode functionality once it has been
// be implemented server-side
func DeployChaincodePlusLifecycle(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) {
// DeployChaincodeNewLifecycle is a helper that will install chaincode to all
// peers that are connected to the specified channel, approve the chaincode
// on one of the peers of each organization in the network, commit the chaincode
// definition on the channel using one of the peers, and wait for the chaincode
// commit to complete on all of the peers. It uses the _lifecycle implementation.
// NOTE V2_0 capabilities must be enabled for this functionality to work.
// TODO add _lifecycle CommitChaincode functionality once it has been
// implemented server-side
func DeployChaincodeNewLifecycle(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) {
if len(peers) == 0 {
peers = n.PeersWithChannel(channel)
}
Expand All @@ -52,13 +64,18 @@ func DeployChaincodePlusLifecycle(n *Network, channel string, orderer *Orderer,
}

// package using the first peer
PackageChaincodePlusLifecycle(n, chaincode, peers[0])
PackageChaincodeNewLifecycle(n, chaincode, peers[0])

// install on all peers
InstallChaincodePlusLifecycle(n, chaincode, peers...)
InstallChaincodeNewLifecycle(n, chaincode, peers...)

// define using the first peer
// DefineChaincode(n, channel, orderer, chaincode, peers[0], peers...)
// approve for each org
for _, org := range n.PeerOrgs() {
ApproveChaincodeForMyOrgNewLifecycle(n, channel, orderer, chaincode, n.PeersInOrg(org.Name)...)
}

// commit using the first peer
// CommitChaincode(n, channel, orderer, chaincode, peers[0], peers...)
}

// DeployChaincode is a helper that will install chaincode to all peers
Expand Down Expand Up @@ -96,7 +113,7 @@ func DeployChaincode(n *Network, channel string, orderer *Orderer, chaincode Cha
InstantiateChaincode(n, channel, orderer, chaincode, peers[0], peers...)
}

func PackageChaincodePlusLifecycle(n *Network, chaincode Chaincode, peer *Peer) {
func PackageChaincodeNewLifecycle(n *Network, chaincode Chaincode, peer *Peer) {
sess, err := n.PeerAdminSession(peer, commands.ChaincodePackagePlusLifecycle{
Path: chaincode.Path,
Lang: chaincode.Lang,
Expand All @@ -118,7 +135,7 @@ func PackageChaincode(n *Network, chaincode Chaincode, peer *Peer) {
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
}

func InstallChaincodePlusLifecycle(n *Network, chaincode Chaincode, peers ...*Peer) {
func InstallChaincodeNewLifecycle(n *Network, chaincode Chaincode, peers ...*Peer) {
for _, p := range peers {
sess, err := n.PeerAdminSession(p, commands.ChaincodeInstallPlusLifecycle{
Name: chaincode.Name,
Expand All @@ -131,7 +148,7 @@ func InstallChaincodePlusLifecycle(n *Network, chaincode Chaincode, peers ...*Pe
sess, err = n.PeerAdminSession(p, commands.ChaincodeListInstalledPlusLifecycle{})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
Expect(sess).To(gbytes.Say(fmt.Sprintf("Name: %s, Version: %s,", chaincode.Name, chaincode.Version)))
Expect(sess).To(gbytes.Say(fmt.Sprintf("Name: %s, Version: %s, Hash:", chaincode.Name, chaincode.Version)))
}
}

Expand All @@ -154,6 +171,41 @@ func InstallChaincode(n *Network, chaincode Chaincode, peers ...*Peer) {
}
}

func ApproveChaincodeForMyOrgNewLifecycle(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) {
if chaincode.Hash == "" {
pkgBytes, err := ioutil.ReadFile(chaincode.PackageFile)
Expect(err).NotTo(HaveOccurred())
hash := util.ComputeSHA256(pkgBytes)
chaincode.Hash = hex.EncodeToString(hash)
}

// TODO Figure out why private data is unable to be fetched by the
// other peers for the org. For now, we will have each peer in the
// org endorse the proposal.
peerAddresses := []string{}
for _, p := range peers {
peerAddresses = append(peerAddresses, n.PeerAddress(p, ListenPort))
}

sess, err := n.PeerAdminSession(peers[0], commands.ChaincodeApproveForMyOrg{
ChannelID: channel,
Orderer: n.OrdererAddress(orderer, ListenPort),
Name: chaincode.Name,
Version: chaincode.Version,
Hash: chaincode.Hash,
Sequence: chaincode.Sequence,
EndorsementPlugin: chaincode.EndorsementPlugin,
ValidationPlugin: chaincode.ValidationPlugin,
Policy: chaincode.Policy,
InitRequired: chaincode.InitRequired,
PeerAddresses: peerAddresses,
WaitForEvent: true,
})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
Eventually(sess.Err, n.EventuallyTimeout).Should(gbytes.Say(`\Qcommitted with status (VALID)\E`))
}

func InstantiateChaincode(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peer *Peer, checkPeers ...*Peer) {
sess, err := n.PeerAdminSession(peer, commands.ChaincodeInstantiate{
ChannelID: channel,
Expand Down Expand Up @@ -216,3 +268,30 @@ func listInstantiated(n *Network, peer *Peer, channel string) func() *gbytes.Buf
return sess.Buffer()
}
}

// EnableV2_0Capabilities enables the V2_0 capabilities for a running network.
// It generates the config update using the first peer, signs the configuration
// with the subsequent peers, and then submits the config update using the
// first peer.
func EnableV2_0Capabilities(network *Network, channel string, orderer *Orderer, peers ...*Peer) {
if len(peers) == 0 {
return
}

config := GetConfig(network, peers[0], orderer, channel)
updatedConfig := proto.Clone(config).(*common.Config)

// include the V2_0 capability in the config
updatedConfig.ChannelGroup.Groups["Application"].Values["Capabilities"] = &common.ConfigValue{
ModPolicy: "Admins",
Value: protoutil.MarshalOrPanic(
&common.Capabilities{
Capabilities: map[string]*common.Capability{
"V2_0": {},
},
},
),
}

UpdateConfig(network, orderer, channel, config, updatedConfig, false, peers[0], peers...)
}

0 comments on commit faf1f99

Please sign in to comment.