func (n *Network) UpdateChannelAnchors(o *topology.Orderer, channelName string) {
	tempFile, err := ioutil.TempFile("", "update-anchors")
	Expect(err).NotTo(HaveOccurred())
	tempFile.Close()
	defer os.Remove(tempFile.Name())
	peersByOrg := map[string]*topology.Peer{}
	for _, p := range n.AnchorsForChannel(channelName) {
		peersByOrg[p.Organization] = p
	}
	for orgName, p := range peersByOrg {
		anchorUpdate := commands.OutputAnchorPeersUpdate{
			NetworkPrefix:           n.Prefix,
			OutputAnchorPeersUpdate: tempFile.Name(),
			ChannelID:               channelName,
			Profile:                 n.ProfileForChannel(channelName),
			ConfigPath:              filepath.Join(n.Context.RootDir(), n.Prefix),
			AsOrg:                   orgName,
		}
		sess, err := n.ConfigTxGen(anchorUpdate)
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
		sess, err = n.PeerAdminSession(p, commands.ChannelUpdate{
			NetworkPrefix: n.Prefix,
			ChannelID:     channelName,
			Orderer:       n.OrdererAddress(o, ListenPort),
			File:          tempFile.Name(),
			ClientAuth:    n.ClientAuthRequired,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
	}
}
UpdateChannelAnchors determines the anchor peers for the specified channel,
creates an anchor peer update transaction for each organization, and submits
the update transactions to the orderer.
package network
import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"text/template"
	"time"
	"github.com/hyperledger/fabric/integration/runner"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	. "github.com/onsi/gomega/gstruct"
	"github.com/onsi/gomega/matchers"
	"github.com/onsi/gomega/types"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
	"gopkg.in/yaml.v2"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/api"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/common"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/commands"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/fabricconfig"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/opts"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/topology"
	"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fsc"
)
func (n *Network) LogSpec() string {
	if len(n.Logging.Spec) == 0 {
		return "info:fscnode=debug"
	}
	return n.Logging.Spec
}
func (n *Network) LogFormat() string {
	if len(n.Logging.Format) == 0 {
		return "'%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'"
	}
	return n.Logging.Format
}
func (n *Network) AddOrg(o *topology.Organization, peers ...*topology.Peer) {
	for _, p := range peers {
		ports := api.Ports{}
		for _, portName := range PeerPortNames() {
			ports[portName] = n.Context.ReservePort()
		}
		n.Context.SetPortsByPeerID(n.Prefix, p.ID(), ports)
		n.Peers = append(n.Peers, p)
	}
	n.Organizations = append(n.Organizations, o)
	n.Consortiums[0].Organizations = append(n.Consortiums[0].Organizations, o.Name)
}
func (n *Network) ConfigTxConfigPath() string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, "configtx.yaml")
}
func (n *Network) CryptoPath() string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, "crypto")
}
func (n *Network) CryptoConfigPath() string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, "crypto-config.yaml")
}
func (n *Network) OutputBlockPath(channelName string) string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, fmt.Sprintf("%s_block.pb", channelName))
}
func (n *Network) CreateChannelTxPath(channelName string) string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, fmt.Sprintf("%s_tx.pb", channelName))
}
func (n *Network) OrdererDir(o *topology.Orderer) string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, "orderers", o.ID())
}
func (n *Network) OrdererConfigPath(o *topology.Orderer) string {
	return filepath.Join(n.OrdererDir(o), "orderer.yaml")
}
func (n *Network) ReadOrdererConfig(o *topology.Orderer) *fabricconfig.Orderer {
	var orderer fabricconfig.Orderer
	ordererBytes, err := ioutil.ReadFile(n.OrdererConfigPath(o))
	Expect(err).NotTo(HaveOccurred())
	err = yaml.Unmarshal(ordererBytes, &orderer)
	Expect(err).NotTo(HaveOccurred())
	return &orderer
}
func (n *Network) WriteOrdererConfig(o *topology.Orderer, config *fabricconfig.Orderer) {
	ordererBytes, err := yaml.Marshal(config)
	Expect(err).NotTo(HaveOccurred())
	err = ioutil.WriteFile(n.OrdererConfigPath(o), ordererBytes, 0644)
	Expect(err).NotTo(HaveOccurred())
}
func (n *Network) ReadConfigTxConfig() *fabricconfig.ConfigTx {
	var configtx fabricconfig.ConfigTx
	configtxBytes, err := ioutil.ReadFile(n.ConfigTxConfigPath())
	Expect(err).NotTo(HaveOccurred())
	err = yaml.Unmarshal(configtxBytes, &configtx)
	Expect(err).NotTo(HaveOccurred())
	return &configtx
}
func (n *Network) WriteConfigTxConfig(config *fabricconfig.ConfigTx) {
	configtxBytes, err := yaml.Marshal(config)
	Expect(err).NotTo(HaveOccurred())
	err = ioutil.WriteFile(n.ConfigTxConfigPath(), configtxBytes, 0644)
	Expect(err).NotTo(HaveOccurred())
}
func (n *Network) PeerDir(p *topology.Peer) string {
	return filepath.Join(n.Context.RootDir(), n.Prefix, "peers", p.ID())
}
func (n *Network) PeerConfigPath(p *topology.Peer) string {
	return filepath.Join(n.PeerDir(p), "core.yaml")
}
func (n *Network) PeerLedgerDir(p *topology.Peer) string {
	return filepath.Join(n.PeerDir(p), "filesystem/ledgersData")
}
func (n *Network) ReadPeerConfig(p *topology.Peer) *fabricconfig.Core {
	var core fabricconfig.Core
	coreBytes, err := ioutil.ReadFile(n.PeerConfigPath(p))
	Expect(err).NotTo(HaveOccurred())
	err = yaml.Unmarshal(coreBytes, &core)
	Expect(err).NotTo(HaveOccurred())
	return &core
}
func (n *Network) WritePeerConfig(p *topology.Peer, config *fabricconfig.Core) {
	coreBytes, err := yaml.Marshal(config)
	Expect(err).NotTo(HaveOccurred())
	err = ioutil.WriteFile(n.PeerConfigPath(p), coreBytes, 0644)
	Expect(err).NotTo(HaveOccurred())
}
func (n *Network) peerUserCryptoDir(p *topology.Peer, user, cryptoMaterialType string) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return n.userCryptoDir(org, "peerOrganizations", user, cryptoMaterialType)
}
func (n *Network) ordererUserCryptoDir(o *topology.Orderer, user, cryptoMaterialType string) string {
	org := n.Organization(o.Organization)
	Expect(org).NotTo(BeNil())
	return n.userCryptoDir(org, "ordererOrganizations", user, cryptoMaterialType)
}
func (n *Network) userCryptoDir(org *topology.Organization, nodeOrganizationType, user, cryptoMaterialType string) string {
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		nodeOrganizationType,
		org.Domain,
		"users",
		fmt.Sprintf("%s@%s", user, org.Domain),
		cryptoMaterialType,
	)
}
func (n *Network) OrgPeerCACertificatePath(org *topology.Organization) string {
	return n.orgCACertificatePath(org, "peerOrganizations")
}
func (n *Network) orgCACertificatePath(org *topology.Organization, nodeOrganizationType string) string {
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		nodeOrganizationType,
		org.Domain,
		"ca",
		fmt.Sprintf("ca.%s-cert.pem", org.Domain),
	)
}
func (n *Network) PeerUserMSPDir(p *topology.Peer, user string) string {
	return n.peerUserCryptoDir(p, user, "msp")
}
func (n *Network) ViewNodeMSPDir(p *topology.Peer) string {
	switch {
	case n.topology.NodeOUs:
		switch p.Role {
		case "":
			return n.PeerUserMSPDir(p, p.Name)
		case "client":
			return n.PeerUserMSPDir(p, p.Name)
		default:
			return n.PeerLocalMSPDir(p)
		}
	default:
		return n.PeerLocalMSPDir(p)
	}
}
func (n *Network) FSCNodeLocalTLSDir(p *topology.Peer) string {
	switch {
	case n.topology.NodeOUs:
		switch p.Role {
		case "":
			return n.peerUserCryptoDir(p, p.Name, "tls")
		case "client":
			return n.peerUserCryptoDir(p, p.Name, "tls")
		default:
			return n.peerLocalCryptoDir(p, "tls")
		}
	default:
		return n.peerLocalCryptoDir(p, "tls")
	}
}
func (n *Network) IdemixUserMSPDir(o *topology.Organization, user string) string {
	return n.userCryptoDir(o, "peerOrganizations", user, "")
}
func (n *Network) OrdererUserMSPDir(o *topology.Orderer, user string) string {
	return n.ordererUserCryptoDir(o, user, "msp")
}
func (n *Network) PeerUserTLSDir(p *topology.Peer, user string) string {
	return n.peerUserCryptoDir(p, user, "tls")
}
func (n *Network) PeerUserCert(p *topology.Peer, user string) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.PeerUserMSPDir(p, user),
		"signcerts",
		fmt.Sprintf("%s@%s-cert.pem", user, org.Domain),
	)
}
func (n *Network) OrdererUserCert(o *topology.Orderer, user string) string {
	org := n.Organization(o.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.OrdererUserMSPDir(o, user),
		"signcerts",
		fmt.Sprintf("%s@%s-cert.pem", user, org.Domain),
	)
}
func (n *Network) PeerUserKey(p *topology.Peer, user string) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.PeerUserMSPDir(p, user),
		"keystore",
		"priv_sk",
	)
}
func (n *Network) PeerKey(p *topology.Peer) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.PeerLocalMSPDir(p),
		"keystore",
		"priv_sk",
	)
}
func (n *Network) OrdererUserKey(o *topology.Orderer, user string) string {
	org := n.Organization(o.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.OrdererUserMSPDir(o, user),
		"keystore",
		"priv_sk",
	)
}
func (n *Network) peerLocalCryptoDir(p *topology.Peer, cryptoType string) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"peerOrganizations",
		org.Domain,
		"peers",
		fmt.Sprintf("%s.%s", p.Name, org.Domain),
		cryptoType,
	)
}
func (n *Network) peerUserLocalCryptoDir(p *topology.Peer, user, cryptoType string) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"peerOrganizations",
		org.Domain,
		"users",
		fmt.Sprintf("%s@%s", user, org.Domain),
		cryptoType,
	)
}
func (n *Network) PeerLocalMSPDir(p *topology.Peer) string {
	return n.peerLocalCryptoDir(p, "msp")
}
func (n *Network) PeerLocalMSPIdentityCert(p *topology.Peer) string {
	return filepath.Join(
		n.peerLocalCryptoDir(p, "msp"),
		"signcerts",
		p.Name+"."+n.Organization(p.Organization).Domain+"-cert.pem",
	)
}
func (n *Network) PeerUserLocalMSPIdentityCert(p *topology.Peer, user string) string {
	return filepath.Join(
		n.peerUserLocalCryptoDir(p, user, "msp"),
		"signcerts",
		p.Name+"@"+n.Organization(p.Organization).Domain+"-cert.pem",
	)
}
func (n *Network) PeerLocalIdemixExtraIdentitiesDir(p *topology.Peer) string {
	return n.peerLocalCryptoDir(p, "extraids")
}
func (n *Network) PeerLocalExtraIdentityDir(p *topology.Peer, id string) string {
	index := 1
	for _, identity := range p.ExtraIdentities {
		if identity.ID == id {
			switch identity.MSPType {
			case "idemix":
				return n.peerLocalCryptoDir(p, filepath.Join("extraids", id))
			case "bccsp":
				return n.peerUserCryptoDir(p, identity.ID, "msp")
			}
		}
		if identity.MSPType == "bccsp" {
			index++
		}
	}
	panic("id not found")
}
func (n *Network) PeerLocalTLSDir(p *topology.Peer) string {
	return n.peerLocalCryptoDir(p, "tls")
}
func (n *Network) PeerCert(p *topology.Peer) string {
	org := n.Organization(p.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.PeerLocalMSPDir(p),
		"signcerts",
		fmt.Sprintf("%s.%s-cert.pem", p.Name, org.Domain),
	)
}
func (n *Network) PeerOrgMSPDir(org *topology.Organization) string {
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"peerOrganizations",
		org.Domain,
		"msp",
	)
}
func (n *Network) Topology() *topology.Topology {
	return n.topology
}
func (n *Network) DefaultIdemixOrgMSPDir() string {
	for _, organization := range n.Organizations {
		if organization.MSPType == "idemix" {
			return filepath.Join(
				n.Context.RootDir(),
				n.Prefix,
				"crypto",
				"peerOrganizations",
				organization.Domain,
			)
		}
	}
	return ""
}
func (n *Network) IdemixOrgMSPDir(org *topology.Organization) string {
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"peerOrganizations",
		org.Domain,
	)
}
func (n *Network) OrdererOrgMSPDir(o *topology.Organization) string {
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"ordererOrganizations",
		o.Domain,
		"msp",
	)
}
func (n *Network) OrdererLocalCryptoDir(o *topology.Orderer, cryptoType string) string {
	org := n.Organization(o.Organization)
	Expect(org).NotTo(BeNil())
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"ordererOrganizations",
		org.Domain,
		"orderers",
		fmt.Sprintf("%s.%s", o.Name, org.Domain),
		cryptoType,
	)
}
func (n *Network) OrdererLocalMSPDir(o *topology.Orderer) string {
	return n.OrdererLocalCryptoDir(o, "msp")
}
func (n *Network) OrdererLocalTLSDir(o *topology.Orderer) string {
	return n.OrdererLocalCryptoDir(o, "tls")
}
func (n *Network) ProfileForChannel(channelName string) string {
	for _, ch := range n.Channels {
		if ch.Name == channelName {
			return ch.Profile
		}
	}
	return ""
}
func (n *Network) CACertsBundlePath() string {
	return filepath.Join(
		n.Context.RootDir(),
		n.Prefix,
		"crypto",
		"ca-certs.pem",
	)
}
func (n *Network) bootstrapIdemix() {
	for _, org := range n.IdemixOrgs() {
		output := n.IdemixOrgMSPDir(org)
		sess, err := n.Idemixgen(commands.CAKeyGen{
			NetworkPrefix: n.Prefix,
			Output:        output,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
	}
}
func (n *Network) bootstrapExtraIdentities() {
	for i, peer := range n.Peers {
		for j, identity := range peer.ExtraIdentities {
			switch identity.MSPType {
			case "idemix":
				org := n.Organization(identity.Org)
				output := n.IdemixOrgMSPDir(org)
				userOutput := filepath.Join(n.PeerLocalIdemixExtraIdentitiesDir(peer), identity.ID)
				sess, err := n.Idemixgen(commands.SignerConfig{
					NetworkPrefix:    n.Prefix,
					CAInput:          output,
					Output:           userOutput,
					OrgUnit:          org.Domain,
					EnrollmentID:     identity.EnrollmentID,
					RevocationHandle: fmt.Sprintf("1%d%d", i, j),
				})
				Expect(err).NotTo(HaveOccurred())
				Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
			case "bccsp":
			default:
				Expect(identity.MSPType).To(Equal("idemix"))
			}
		}
	}
}
func (n *Network) CheckTopology() {
	if n.Templates == nil {
		n.Templates = &topology.Templates{}
	}
	if n.Logging == nil {
		n.Logging = &topology.Logging{
			Spec:   "debug",
			Format: "'%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'",
		}
	}
	for i := 0; i < n.Consensus.Brokers; i++ {
		ports := api.Ports{}
		for _, portName := range BrokerPortNames() {
			ports[portName] = n.Context.ReservePort()
		}
		n.PortsByBrokerID[strconv.Itoa(i)] = ports
	}
	for _, o := range n.Orderers {
		ports := api.Ports{}
		for _, portName := range OrdererPortNames() {
			ports[portName] = n.Context.ReservePort()
		}
		n.PortsByOrdererID[o.ID()] = ports
	}
	fscTopology := n.Context.TopologyByName("fsc").(*fsc.Topology)
	users := map[string]int{}
	userNames := map[string][]string{}
	for _, node := range fscTopology.Nodes {
		var extraIdentities []*topology.PeerIdentity
		po := node.PlatformOpts()
		nodeOpts := opts.Get(po)
		orgs := nodeOpts.Organizations()
		Expect(orgs).NotTo(BeEmpty())
		var org opts.Organization
		found := false
		for _, o := range orgs {
			if o.Network != "" && o.Network == n.topology.TopologyName {
				found = true
				org = o
			}
		}
		if !found {
			for _, o := range orgs {
				if o.Network == "" {
					found = true
					org = o
				}
			}
		}
		if !found {
			continue
		}
		userNames[org.Org] = append(userNames[org.Org], node.Name)
		if nodeOpts.AnonymousIdentity() {
			extraIdentities = append(extraIdentities, &topology.PeerIdentity{
				ID:           "idemix",
				EnrollmentID: node.Name,
				MSPType:      "idemix",
				MSPID:        "IdemixOrgMSP",
				Org:          "IdemixOrg",
			})
			n.Context.AddIdentityAlias(node.Name, "idemix")
		}
		for _, label := range nodeOpts.IdemixIdentities() {
			extraIdentities = append(extraIdentities, &topology.PeerIdentity{
				ID:           label,
				EnrollmentID: label,
				MSPType:      "idemix",
				MSPID:        "IdemixOrgMSP",
				Org:          "IdemixOrg",
			})
			n.Context.AddIdentityAlias(node.Name, label)
		}
		for _, label := range nodeOpts.X509Identities() {
			extraIdentities = append(extraIdentities, &topology.PeerIdentity{
				ID:           label,
				MSPType:      "bccsp",
				EnrollmentID: label,
				MSPID:        org.Org + "MSP",
				Org:          org.Org,
			})
			users[org.Org] = users[org.Org] + 1
			userNames[org.Org] = append(userNames[org.Org], label)
			n.Context.AddIdentityAlias(node.Name, label)
		}
		var defaultNetwork bool
		switch {
		case nodeOpts.DefaultNetwork() == "":
			defaultNetwork = n.topology.Default
		case n.topology.TopologyName == nodeOpts.DefaultNetwork():
			defaultNetwork = true
		default:
			defaultNetwork = false
		}
		p := &topology.Peer{
			Name:            node.Name,
			Organization:    org.Org,
			Type:            topology.FSCPeer,
			Role:            nodeOpts.Role(),
			Bootstrap:       node.Bootstrap,
			ExecutablePath:  node.ExecutablePath,
			ExtraIdentities: extraIdentities,
			DefaultNetwork:  defaultNetwork,
		}
		n.Peers = append(n.Peers, p)
		n.Context.SetPortsByPeerID("fsc", p.ID(), n.Context.PortsByPeerID(n.Prefix, node.Name))
	}
	for _, organization := range n.Organizations {
		organization.Users += users[organization.Name]
		if n.topology.Weaver {
			organization.UserNames = append(userNames[organization.Name], "User1", "User2", "Relay", "RelayAdmin")
		} else {
			organization.UserNames = append(userNames[organization.Name], "User1", "User2")
		}
	}
	for _, p := range n.Peers {
		if p.Type == topology.FSCPeer {
			continue
		}
		ports := api.Ports{}
		for _, portName := range PeerPortNames() {
			ports[portName] = n.Context.ReservePort()
		}
		n.Context.SetPortsByPeerID(n.Prefix, p.ID(), ports)
	}
	for _, extension := range n.Extensions {
		extension.CheckTopology()
	}
}
func (n *Network) ConcatenateTLSCACertificates() {
	bundle := &bytes.Buffer{}
	for _, tlsCertPath := range n.ListTLSCACertificates() {
		certBytes, err := ioutil.ReadFile(tlsCertPath)
		Expect(err).NotTo(HaveOccurred())
		bundle.Write(certBytes)
	}
	if len(bundle.Bytes()) == 0 {
		return
	}
	err := ioutil.WriteFile(n.CACertsBundlePath(), bundle.Bytes(), 0660)
	Expect(err).NotTo(HaveOccurred())
}
func (n *Network) ListTLSCACertificates() []string {
	fileName2Path := make(map[string]string)
	filepath.Walk(filepath.Join(n.Context.RootDir(), n.Prefix, "crypto"), func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if strings.HasPrefix(info.Name(), "tlsca") && strings.Contains(info.Name(), "-cert.pem") {
			fileName2Path[info.Name()] = path
		}
		return nil
	})
	var tlsCACertificates []string
	for _, path := range fileName2Path {
		tlsCACertificates = append(tlsCACertificates, path)
	}
	return tlsCACertificates
}
func (n *Network) CreateAndJoinChannels(o *topology.Orderer) {
	for _, c := range n.Channels {
		n.CreateAndJoinChannel(o, c.Name)
	}
}
func (n *Network) CreateAndJoinChannel(o *topology.Orderer, channelName string) {
	peers := n.PeersWithChannel(channelName)
	if len(peers) == 0 {
		return
	}
	n.CreateChannel(channelName, o, peers[0])
	n.JoinChannel(channelName, o, peers...)
}