diff --git a/src/main/java/org/hyperledger/fabric/sdk/Channel.java b/src/main/java/org/hyperledger/fabric/sdk/Channel.java index e9b6e70c..97b04817 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/Channel.java +++ b/src/main/java/org/hyperledger/fabric/sdk/Channel.java @@ -193,7 +193,7 @@ private Channel(String name, HFClient hfClient, Orderer orderer, ChannelConfigur ByteString configUpdate = configUpdateEnv.getConfigUpdate(); sendUpdateChannel(configUpdate.toByteArray(), signers, orderer); - // final ConfigUpdateEnvelope.Builder configUpdateEnvBuilder = configUpdateEnv.toBuilder(); + // final ConfigUpdateEnvelope.Builder configUpdateEnvBuilder = configUpdateEnv.toBuilder();` //--------------------------------------- @@ -3070,6 +3070,8 @@ public synchronized void shutdown(boolean force) { blockListeners.clear(); + client.removeChannel(this); + for (EventHub eh : getEventHubs()) { try { @@ -3100,6 +3102,8 @@ public synchronized void shutdown(boolean force) { eventQueueThread.interrupt(); } eventQueueThread = null; + + client = null; } @Override diff --git a/src/main/java/org/hyperledger/fabric/sdk/HFClient.java b/src/main/java/org/hyperledger/fabric/sdk/HFClient.java index a76b6145..cffb137f 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/HFClient.java +++ b/src/main/java/org/hyperledger/fabric/sdk/HFClient.java @@ -32,6 +32,7 @@ import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; import org.hyperledger.fabric.sdk.exception.ProposalException; import org.hyperledger.fabric.sdk.exception.TransactionException; +import org.hyperledger.fabric.sdk.helper.Utils; import org.hyperledger.fabric.sdk.security.CryptoSuite; import static java.lang.String.format; @@ -109,10 +110,23 @@ public static HFClient createNewInstance() { public Channel newChannel(String name) throws InvalidArgumentException { clientCheck(); - logger.trace("Creating channel :" + name); - Channel newChannel = Channel.createNewInstance(name, this); - channels.put(name, newChannel); - return newChannel; + if (Utils.isNullOrEmpty(name)) { + throw new InvalidArgumentException("Channel name can not be null or empty string."); + } + + synchronized (channels) { + + if (channels.containsKey(name)) { + throw new InvalidArgumentException(format("Channel by the name %s already exits", name)); + } + logger.trace("Creating channel :" + name); + Channel newChannel = Channel.createNewInstance(name, this); + + channels.put(name, newChannel); + return newChannel; + + } + } /** @@ -131,10 +145,25 @@ public Channel newChannel(String name) throws InvalidArgumentException { public Channel newChannel(String name, Orderer orderer, ChannelConfiguration channelConfiguration, byte[]... channelConfigurationSignatures) throws TransactionException, InvalidArgumentException { clientCheck(); - logger.trace("Creating channel :" + name); - Channel newChannel = Channel.createNewInstance(name, this, orderer, channelConfiguration, channelConfigurationSignatures); - channels.put(name, newChannel); - return newChannel; + if (Utils.isNullOrEmpty(name)) { + throw new InvalidArgumentException("Channel name can not be null or empty string."); + } + + synchronized (channels) { + + if (channels.containsKey(name)) { + throw new InvalidArgumentException(format("Channel by the name %s already exits", name)); + } + + logger.trace("Creating channel :" + name); + + Channel newChannel = Channel.createNewInstance(name, this, orderer, channelConfiguration, channelConfigurationSignatures); + + channels.put(name, newChannel); + return newChannel; + + } + } /** @@ -500,4 +529,9 @@ private void clientCheck() throws InvalidArgumentException { } + void removeChannel(Channel channel) { + synchronized (channels) { + channels.remove(channel.getName()); + } + } } diff --git a/src/main/proto/ledger/rwset/rwset.proto b/src/main/proto/ledger/rwset/rwset.proto index 8b0709bb..2ccfd09e 100644 --- a/src/main/proto/ledger/rwset/rwset.proto +++ b/src/main/proto/ledger/rwset/rwset.proto @@ -62,4 +62,12 @@ message NsPvtReadWriteSet { message CollectionPvtReadWriteSet { string collection_name = 1; bytes rwset = 2; // Data model specific serialized proto message (e.g., kvrwset.KVRWSet for KV and Document data models) +} + +// CollectionProperty defines an element of a private data that corresponds +// to a certain transaction and collection +message CollectionCriteria { + string channel = 1; + string tx_id = 2; + string collection = 3; } \ No newline at end of file diff --git a/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java b/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java index 470cffb7..8a56a5da 100644 --- a/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java +++ b/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java @@ -45,9 +45,6 @@ //CHECKSTYLE.ON: IllegalImport - - - public class ChannelTest { private static HFClient hfclient = null; private static Channel shutdownChannel = null; @@ -395,7 +392,7 @@ public void testChannelBadPeerDoesNotBelong() throws Exception { Collection peers = Arrays.asList((Peer[]) new Peer[] {hfclient.newPeer("peer2", "grpc://localhost:22")}); - createRunningChannel(peers); + createRunningChannel("testChannelBadPeerDoesNotBelong", peers); channel.sendInstantiationProposal(hfclient.newInstantiationProposalRequest(), peers); @@ -411,7 +408,7 @@ public void testChannelBadPeerDoesNotBelong2() throws Exception { Peer peer = channel.getPeers().iterator().next(); - final Channel channel2 = createRunningChannel(null); + final Channel channel2 = createRunningChannel("testChannelBadPeerDoesNotBelong2", null); setField(peer, "channel", channel2); @@ -458,8 +455,30 @@ public void testChannelBadPeerCollectionNull() throws Exception { } + @Test + public void testTwoChannelsSameName() throws Exception { + + thrown.expect(InvalidArgumentException.class); + thrown.expectMessage("Channel by the name testTwoChannelsSameName already exits"); + + createRunningChannel("testTwoChannelsSameName", null); + createRunningChannel("testTwoChannelsSameName", null); + + } + + static final String CHANNEL_NAME2 = "channel"; + public static Channel createRunningChannel(Collection peers) throws InvalidArgumentException, NoSuchFieldException, IllegalAccessException { - Channel channel = hfclient.newChannel("channel"); + Channel prevChannel = hfclient.getChannel(CHANNEL_NAME2); + if (null != prevChannel) { //cleanup remove default channel. + prevChannel.shutdown(false); + } + return createRunningChannel(CHANNEL_NAME2, peers); + } + + public static Channel createRunningChannel(String channelName, Collection peers) throws InvalidArgumentException, NoSuchFieldException, IllegalAccessException { + + Channel channel = hfclient.newChannel(channelName); if (peers == null) { Peer peer = hfclient.newPeer("peer1", "grpc://localhost:22"); channel.addPeer(peer); @@ -480,13 +499,13 @@ public static Channel createRunningChannel(Collection peers) throws Invali public void testChannelBadPeerDoesNotBelongJoin() throws Exception { thrown.expect(ProposalException.class); - thrown.expectMessage("Can not add peer peer2 to channel channel because it already belongs to channel channel"); + thrown.expectMessage("Can not add peer peer2 to channel testChannelBadPeerDoesNotBelongJoin because it already belongs to channel testChannelBadPeerDoesNotBelongJoin2"); - final Channel channel = createRunningChannel(null); + final Channel channel = createRunningChannel("testChannelBadPeerDoesNotBelongJoin", null); Collection peers = Arrays.asList((Peer[]) new Peer[] {hfclient.newPeer("peer2", "grpc://localhost:22")}); - createRunningChannel(peers); + createRunningChannel("testChannelBadPeerDoesNotBelongJoin2", peers); //Peer joining channel when it belongs to another channel. @@ -527,7 +546,7 @@ public void testChannelInitNullClient() throws Exception { thrown.expect(InvalidArgumentException.class); thrown.expectMessage("Can not initialize channel without a client object."); - final Channel channel = hfclient.newChannel("del"); + final Channel channel = hfclient.newChannel("testChannelInitNullClient"); setField(channel, "client", null); channel.initialize(); @@ -746,5 +765,4 @@ private Unsafe getUnsafe() { //lets us throw undeclared exceptions. } } - } diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java index f0c5730d..0eb6fa62 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java @@ -39,7 +39,6 @@ import org.hyperledger.fabric.sdk.Peer; import org.hyperledger.fabric.sdk.ProposalResponse; import org.hyperledger.fabric.sdk.QueryByChaincodeRequest; -import org.hyperledger.fabric.sdk.SDKUtils; import org.hyperledger.fabric.sdk.TestConfigHelper; import org.hyperledger.fabric.sdk.TransactionProposalRequest; import org.hyperledger.fabric.sdk.UpgradeProposalRequest; @@ -258,13 +257,6 @@ void runChannel(HFClient client, Channel channel, SampleOrg sampleOrg, final int fail("Not enough endorsers for install :" + successful.size() + ". " + first.getMessage()); } - // Check that all the proposals are consistent with each other. We should have only one set - // where all the proposals above are consistent. - Collection> proposalConsistencySets = SDKUtils.getProposalConsistencySets(responses); - if (proposalConsistencySets.size() != 1) { - fail(format("Expected only one set of consistent install proposal responses but got %d", proposalConsistencySets.size())); - } - ////////////////// // Upgrade chaincode to ***double*** our move results. @@ -317,13 +309,6 @@ void runChannel(HFClient client, Channel channel, SampleOrg sampleOrg, final int + successful.size() + ". " + first.getMessage()); } - // Check that all the proposals are consistent with each other. We should have only one set - // where the proposals above are consistent. - proposalConsistencySets = SDKUtils.getProposalConsistencySets(responses2); - if (proposalConsistencySets.size() != 1) { - fail(format("Expected only one set of consistent upgrade proposal responses but got %d", proposalConsistencySets.size())); - } - if (changeContext) { return channel.sendTransaction(successful, sampleOrg.getPeerAdmin()).get(testConfig.getTransactionWaitTime(), TimeUnit.SECONDS); @@ -451,13 +436,6 @@ CompletableFuture moveAmount(HFClient client, Chann } } - // Check that all the proposals are consistent with each other. We should have only one set - // where all the proposals above are consistent. - Collection> proposalConsistencySets = SDKUtils.getProposalConsistencySets(invokePropResp); - if (proposalConsistencySets.size() != 1) { - fail(format("Expected only one set of consistent move proposal responses but got %d", proposalConsistencySets.size())); - } - out("Received %d transaction proposal responses. Successful+verified: %d . Failed: %d", invokePropResp.size(), successful.size(), failed.size()); if (failed.size() > 0) { diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java index c0d7c690..e4b4af3f 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java @@ -339,7 +339,6 @@ class ChaincodeEventCapture { //A test class to capture chaincode events } } - SDKUtils.getProposalConsistencySets(responses); // } out("Received %d install proposal responses. Successful+verified: %d . Failed: %d", numInstallProposal, successful.size(), failed.size()); @@ -443,7 +442,9 @@ policy OR(Org1MSP.member, Org2MSP.member) meaning 1 signature from someone in ei } // Check that all the proposals are consistent with each other. We should have only one set - // where all the proposals above are consistent. + // where all the proposals above are consistent. Note the when sending to Orderer this is done automatically. + // Shown here as an example that applications can invoke and select. + // See org.hyperledger.fabric.sdk.proposal.consistency_validation config property. Collection> proposalConsistencySets = SDKUtils.getProposalConsistencySets(transactionPropResp); if (proposalConsistencySets.size() != 1) { fail(format("Expected only one set of consistent proposal responses but got %d", proposalConsistencySets.size()));