go_study/fabric-main/integration/pvtdatapurge/data_purge_test.go

522 lines
25 KiB
Go

/*
Copyright IBM Corp All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package pvtdatapurge
import (
"context"
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"syscall"
"time"
"github.com/golang/protobuf/proto"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
ab "github.com/hyperledger/fabric-protos-go/orderer"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric/integration/channelparticipation"
"github.com/hyperledger/fabric/integration/nwo"
"github.com/hyperledger/fabric/integration/nwo/commands"
"github.com/hyperledger/fabric/integration/pvtdata/marblechaincodeutil"
"github.com/hyperledger/fabric/protoutil"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec"
"github.com/tedsuo/ifrit"
ginkgomon "github.com/tedsuo/ifrit/ginkgomon_v2"
)
const channelID = "testchannel"
var _ = Describe("Pvtdata purge", func() {
var (
config *nwo.Config
applicationCapabilitiesVersion string
testDir string
network *nwo.Network
orderer *nwo.Orderer
org1Peer0, org2Peer0, org3Peer0, org3Peer1 *nwo.Peer
processes map[string]ifrit.Process
peerRunners map[string]*ginkgomon.Runner
cancel context.CancelFunc
chaincode *nwo.Chaincode
)
JustBeforeEach(func() {
var err error
testDir, err = ioutil.TempDir("", "purgedata")
Expect(err).NotTo(HaveOccurred())
// Add additional peer before generating config tree
org3Peer1 = &nwo.Peer{
Name: "peer1",
Organization: "Org3",
Channels: []*nwo.PeerChannel{
{Name: "testchannel", Anchor: true},
},
}
config.Peers = append(config.Peers, org3Peer1)
network = nwo.New(config, testDir, nil, StartPort(), components)
network.GenerateConfigTree()
network.Bootstrap()
// Remove additional peer from the network to be added later when required
peers := []*nwo.Peer{}
for _, p := range config.Peers {
if p.Organization != org3Peer1.Organization || p.Name != org3Peer1.Name {
peers = append(peers, p)
}
}
network.Peers = peers
processes = map[string]ifrit.Process{}
peerRunners = map[string]*ginkgomon.Runner{}
orderer = network.Orderer("orderer")
ordererRunner := network.OrdererRunner(orderer)
process := ifrit.Invoke(ordererRunner)
Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
processes[orderer.ID()] = process
for _, peer := range network.Peers {
startPeer(network, processes, peerRunners, peer)
}
channelparticipation.JoinOrdererJoinPeersAppChannel(network, channelID, orderer, ordererRunner)
network.VerifyMembership(
network.PeersWithChannel(channelID),
channelID,
)
nwo.EnableCapabilities(
network,
channelID,
"Application", applicationCapabilitiesVersion,
orderer,
network.PeersWithChannel(channelID)...,
)
chaincode = &nwo.Chaincode{
Name: "marblesp",
Version: "0.0",
Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd"),
Lang: "binary",
PackageFile: filepath.Join(testDir, "purgecc.tar.gz"),
Ctor: `{"Args":[]}`,
SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`,
CollectionsConfig: CollectionConfig("collections_config9.json"),
Sequence: "1",
InitRequired: false,
Label: "purgecc_label",
}
nwo.DeployChaincode(network, channelID, orderer, *chaincode)
org1Peer0 = network.Peer("Org1", "peer0")
org2Peer0 = network.Peer("Org2", "peer0")
org3Peer0 = network.Peer("Org3", "peer0")
_, cancel = context.WithTimeout(context.Background(), network.EventuallyTimeout)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-0", "color":"blue", "size":35, "owner":"tom", "price":99}`, org2Peer0)
})
AfterEach(func() {
cancel()
for _, process := range processes {
process.Signal(syscall.SIGTERM)
Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
}
if network != nil {
network.Cleanup()
}
os.RemoveAll(testDir)
})
When("the purge private data capability is not enabled", func() {
BeforeEach(func() {
config = nwo.ThreeOrgEtcdRaft()
applicationCapabilitiesVersion = "V2_0"
})
It("should fail with an error if the purge capability has not been enabled on the channel", func() {
marblePurgeBase64 := base64.StdEncoding.EncodeToString([]byte(`{"name":"test-marble-0"}`))
purgeCommand := commands.ChaincodeInvoke{
ChannelID: channelID,
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
Name: chaincode.Name,
Ctor: `{"Args":["purge"]}`,
Transient: fmt.Sprintf(`{"marble_purge":"%s"}`, marblePurgeBase64),
PeerAddresses: []string{
network.PeerAddress(org2Peer0, nwo.ListenPort),
},
WaitForEvent: true,
}
marblechaincodeutil.AssertInvokeChaincodeFails(network, org2Peer0, purgeCommand, "Failed to purge state:PURGE_PRIVATE_DATA failed: transaction ID: [a-f0-9]{64}: purge private data is not enabled, channel application capability of V2_5 or later is required")
})
})
When("the purge private data capability is enabled", func() {
BeforeEach(func() {
config = nwo.ThreeOrgEtcdRaft()
config.Profiles[0].Blocks = &nwo.Blocks{
BatchTimeout: 1,
MaxMessageCount: 30,
AbsoluteMaxBytes: 99,
PreferredMaxBytes: 512,
}
applicationCapabilitiesVersion = "V2_5"
})
It("should prevent purged data being included in responses after the purge transaction has been committed", func() {
By("Adding marbles and confirming they exist in private state")
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-1", "color":"green", "size":42, "owner":"simon", "price":180}`, org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-2", "color":"red", "size":24, "owner":"heather", "price":635}`, org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-3", "color":"black", "size":12, "owner":"bob", "price":2}`, org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-4", "color":"yellow", "size":180, "owner":"liz", "price":100}`, org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-0", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-0", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-1", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-1", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-2", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-2", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-3", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-3", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-4", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-4", org2Peer0)
By("Purging 2 marbles in separate blocks and confirming they are longer exist in private state")
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-0"}`, org2Peer0)
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-1"}`, org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-0", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-0", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-1", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-1", org2Peer0)
By("Purging 3 more marbles in a single block and confirming they are longer exist in private state")
var wg sync.WaitGroup
wg.Add(3)
for i := 2; i < 5; i++ {
go func(marblePurge string) {
defer GinkgoRecover()
defer wg.Done()
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, marblePurge, org2Peer0)
}(fmt.Sprintf(`{"name":"test-marble-%d"}`, i))
}
wg.Wait()
Expect(nwo.GetLedgerHeight(network, org2Peer0, channelID)).To(Equal(14)) // Anchor peers are in genesis block
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-2", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-2", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-3", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-3", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-4", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-4", org2Peer0)
By("Adding 2 new marbles and confirming only the new marbles exist in block events")
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-5", "color":"black", "size":12, "owner":"bob", "price":2}`, org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-6", "color":"yellow", "size":180, "owner":"liz", "price":100}`, org2Peer0)
assertBlockEventsOnlyContainUnpurgedPrivateData(network, org2Peer0, chaincode.Name, []string{"test-marble-5", "\x00color~name\x00black\x00test-marble-5\x00", "test-marble-6", "\x00color~name\x00yellow\x00test-marble-6\x00"})
By("Adding a marble and setting state-basedendorsement policy to Org3, future endorsements from Org2 will be invalidated")
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-7-sbe", "color":"black", "size":12, "owner":"bob", "price":2}`, org2Peer0)
marblechaincodeutil.SetMarblePolicy(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-7-sbe","org":"Org3"}`, org2Peer0)
marblePurgeBase64 := base64.StdEncoding.EncodeToString([]byte(`{"name":"test-marble-7-sbe"}`))
purgeCommand := commands.ChaincodeInvoke{
ChannelID: channelID,
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
Name: chaincode.Name,
Ctor: `{"Args":["purge"]}`,
Transient: fmt.Sprintf(`{"marble_purge":"%s"}`, marblePurgeBase64),
PeerAddresses: []string{
network.PeerAddress(org2Peer0, nwo.ListenPort),
},
WaitForEvent: true,
}
marblechaincodeutil.AssertInvokeChaincodeFails(network, org2Peer0, purgeCommand, "Error: transaction invalidated with status \\(ENDORSEMENT_POLICY_FAILURE\\) - proposal response: <nil>")
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-7-sbe", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-7-sbe", org2Peer0)
By("Starting a new peer, it should pull private data from existing peers without errors or warnings")
process := addPeer(network, orderer, org3Peer1)
processes[org3Peer1.ID()] = process
nwo.PackageAndInstallChaincode(network, *chaincode, org3Peer1)
network.VerifyMembership(network.Peers, channelID, chaincode.Name)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, `test-marble-4`, org3Peer1)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, `test-marble-4`, org3Peer1)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, `test-marble-5`, org3Peer1)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, `test-marble-5`, org3Peer1)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, `test-marble-6`, org3Peer1)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, `test-marble-6`, org3Peer1)
By("Adding data with new peer down, and then restarting new peer with other peers down to test reconciliation")
// stop new peer
stopPeer(network, processes, org3Peer1)
network.Peers = []*nwo.Peer{org1Peer0, org2Peer0, org3Peer0}
network.VerifyMembership(network.Peers, channelID)
// add two marbles and purge one
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-8-keep", "color":"green", "size":42, "owner":"simon", "price":180}`, org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-9-purge", "color":"red", "size":24, "owner":"heather", "price":635}`, org2Peer0)
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-9-purge"}`, org2Peer0)
// stop original peers
stopPeer(network, processes, org1Peer0)
stopPeer(network, processes, org2Peer0)
stopPeer(network, processes, org3Peer0)
network.Peers = []*nwo.Peer{}
// restart new peer by itself and wait for "Could not fetch" message
startPeer(network, processes, peerRunners, org3Peer1)
network.Peers = append(network.Peers, org3Peer1)
runner := peerRunners[org3Peer1.ID()]
Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Could not fetch \\(or mark to reconcile later\\) 2 eligible collection private write sets for block \\[\\d+\\] \\(0 from local cache, 0 from transient store, 0 from other peers\\)\\. Will commit block with missing private write sets:\\[txID: [0123456789abcdef]+, seq: \\d+, namespace: marblesp, collection: collectionMarblePrivateDetails"))
// restart original peers
startPeer(network, processes, peerRunners, org1Peer0)
network.Peers = append(network.Peers, org1Peer0)
startPeer(network, processes, peerRunners, org2Peer0)
network.Peers = append(network.Peers, org2Peer0)
startPeer(network, processes, peerRunners, org3Peer0)
network.Peers = append(network.Peers, org3Peer0)
// Wait for peers to connect and reconciliation on org3Peer1
Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Reconciliation cycle finished successfully"))
// We can't rely on a single log message about successful reconciliation, because sometimes the reconciliation completes in one cycle (5s) and sometimes in two cycles (10s), so wait for another potential cycle
// Although sleep is generally not a good practice in tests, in this case we can't rely on the Eventually in the query for the private data,
// because prior to reconciliation the query will return an error "private data matching public hash version is not available" and will not get re-tried in the Eventually.
time.Sleep(10 * time.Second)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, `test-marble-8-keep`, org3Peer1)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, `test-marble-8-keep`, org3Peer1)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, `test-marble-9-purge`, org3Peer1)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, `test-marble-9-purge`, org3Peer1)
By("Adding two marbles, removing Org3 from the collection, purging the marbles, and confirming that they still got purged from Org3")
// Make sure all peers are up and connected after prior test, before continuing with this test
network.VerifyMembership(network.Peers, channelID)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-10-purge-after-ineligible", "color":"white", "size":4, "owner":"liz", "price":4}`, org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-11-purge-after-ineligible", "color":"orange", "size":80, "owner":"clive", "price":88}`, org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-10-purge-after-ineligible", org3Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-10-purge-after-ineligible", org3Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-11-purge-after-ineligible", org3Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-11-purge-after-ineligible", org3Peer0)
chaincode.Version = "1.1"
chaincode.CollectionsConfig = CollectionConfig("remove_org3_config.json")
chaincode.Sequence = "2"
nwo.DeployChaincode(network, channelID, orderer, *chaincode)
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-10-purge-after-ineligible"}`, org2Peer0)
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-11-purge-after-ineligible"}`, org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-10-purge-after-ineligible", org3Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-10-purge-after-ineligible", org3Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-11-purge-after-ineligible", org3Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-11-purge-after-ineligible", org3Peer0)
runner = peerRunners[org3Peer0.ID()]
Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Purging private data from private data storage channel=testchannel chaincode=marblesp collection=collectionMarblePrivateDetails key=test-marble-10-purge-after-ineligible blockNum=\\d+ tranNum=\\d+"))
Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Purging private data from private data storage channel=testchannel chaincode=marblesp collection=collectionMarblePrivateDetails key=test-marble-11-purge-after-ineligible blockNum=\\d+ tranNum=\\d+"))
Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Purged private data from private data storage channel=testchannel numKeysPurged=\\d+ numPrivateDataStoreRecordsPurged=\\d+"))
By("Adding a marble, Purging a marble, and then Re-Adding the same marble should be possible")
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-12-re-add", "color":"black", "size":12, "owner":"bob", "price":2}`, org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-12-re-add", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-12-re-add", org2Peer0)
marblechaincodeutil.PurgeMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-12-re-add"}`, org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, chaincode.Name, "test-marble-12-re-add", org2Peer0)
marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, chaincode.Name, "test-marble-12-re-add", org2Peer0)
marblechaincodeutil.AddMarble(network, orderer, channelID, chaincode.Name, `{"name":"test-marble-12-re-add", "color":"black", "size":12, "owner":"bob", "price":2}`, org2Peer0)
marblechaincodeutil.AssertPresentInCollectionM(network, channelID, chaincode.Name, "test-marble-12-re-add", org2Peer0)
marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, chaincode.Name, "test-marble-12-re-add", org2Peer0)
})
})
})
func assertBlockEventsOnlyContainUnpurgedPrivateData(network *nwo.Network, peer *nwo.Peer, chaincodeName string, expectedPrivateDataKeys []string) {
ledgerHeight := nwo.GetLedgerHeight(network, peer, channelID)
conn := network.PeerClientConn(peer)
ctx, cancel := context.WithTimeout(context.Background(), network.EventuallyTimeout)
defer cancel()
dp, err := pb.NewDeliverClient(conn).DeliverWithPrivateData(ctx)
Expect(err).NotTo(HaveOccurred())
defer dp.CloseSend()
signingIdentity := network.PeerUserSigner(peer, "User1")
deliverEnvelope, err := protoutil.CreateSignedEnvelope(
cb.HeaderType_DELIVER_SEEK_INFO,
channelID,
signingIdentity,
&ab.SeekInfo{
Behavior: ab.SeekInfo_BLOCK_UNTIL_READY,
Start: &ab.SeekPosition{
Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}},
},
Stop: &ab.SeekPosition{
Type: &ab.SeekPosition_Specified{
Specified: &ab.SeekSpecified{Number: uint64(ledgerHeight)},
},
},
},
0,
0,
)
Expect(err).NotTo(HaveOccurred())
err = dp.Send(deliverEnvelope)
Expect(err).NotTo(HaveOccurred())
privateDataKeys := getPrivateDataKeys(dp, ledgerHeight)
Expect(privateDataKeys).To(ConsistOf(expectedPrivateDataKeys))
}
func getPrivateDataKeys(client pb.Deliver_DeliverWithPrivateDataClient, ledgerHeight int) []string {
pvtKeys := make(map[string]struct{})
blockCount := 0
for {
msg, err := client.Recv()
Expect(err).NotTo(HaveOccurred())
switch t := msg.Type.(type) {
case *pb.DeliverResponse_BlockAndPrivateData:
for _, txPvtRwset := range t.BlockAndPrivateData.PrivateDataMap {
if txPvtRwset == nil {
continue
}
for _, nsPvtRwset := range txPvtRwset.NsPvtRwset {
if nsPvtRwset.Namespace != "marblesp" {
continue
}
for _, col := range nsPvtRwset.CollectionPvtRwset {
Expect(col.CollectionName).Should(SatisfyAny(
Equal("collectionMarbles"),
Equal("collectionMarblePrivateDetails")))
kvRwset := kvrwset.KVRWSet{}
err := proto.Unmarshal(col.GetRwset(), &kvRwset)
Expect(err).NotTo(HaveOccurred())
for _, kvWrite := range kvRwset.Writes {
pvtKeys[kvWrite.Key] = struct{}{}
}
}
}
}
}
blockCount++
if blockCount == ledgerHeight {
var keys []string
for key := range pvtKeys {
keys = append(keys, key)
}
return keys
}
}
}
func startPeer(network *nwo.Network, processes map[string]ifrit.Process, runners map[string]*ginkgomon.Runner, peer *nwo.Peer) {
if _, ok := processes[peer.ID()]; !ok {
r := network.PeerRunner(peer)
p := ifrit.Invoke(r)
runners[peer.ID()] = r
processes[peer.ID()] = p
Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
}
}
func stopPeer(network *nwo.Network, processes map[string]ifrit.Process, peer *nwo.Peer) {
id := peer.ID()
if p, ok := processes[peer.ID()]; ok {
p.Signal(syscall.SIGTERM)
Eventually(p.Wait(), network.EventuallyTimeout).Should(Receive())
delete(processes, id)
}
}
func startNewPeer(network *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, ledgerHeight int, processes map[string]ifrit.Process, runners map[string]*ginkgomon.Runner) {
startPeer(network, processes, runners, peer)
network.JoinChannel(channelID, orderer, peer)
sess, err := network.PeerAdminSession(
peer,
commands.ChannelFetch{
Block: "newest",
ChannelID: channelID,
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
OutputFile: filepath.Join(network.RootDir, "newest_block.pb"),
},
)
Expect(err).NotTo(HaveOccurred())
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
Expect(sess.Err).To(gbytes.Say(fmt.Sprintf("Received block: %d", ledgerHeight-1)))
network.Peers = append(network.Peers, peer)
nwo.WaitUntilEqualLedgerHeight(network, channelID, ledgerHeight-1, network.Peers...)
}
func addPeer(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer) ifrit.Process {
process := ifrit.Invoke(n.PeerRunner(peer))
Eventually(process.Ready(), n.EventuallyTimeout).Should(BeClosed())
n.JoinChannel(channelID, orderer, peer)
ledgerHeight := nwo.GetLedgerHeight(n, n.Peers[0], channelID)
sess, err := n.PeerAdminSession(
peer,
commands.ChannelFetch{
Block: "newest",
ChannelID: channelID,
Orderer: n.OrdererAddress(orderer, nwo.ListenPort),
OutputFile: filepath.Join(n.RootDir, "newest_block.pb"),
},
)
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
Expect(sess.Err).To(gbytes.Say(fmt.Sprintf("Received block: %d", ledgerHeight-1)))
n.Peers = append(n.Peers, peer)
nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, n.Peers[0], channelID), n.Peers...)
return process
}