diff --git a/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java b/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java index 8702f443..78885db6 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java +++ b/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java @@ -95,9 +95,18 @@ boolean isBlockEvent() { } TransactionEvent getTransactionEvent(int index) throws InvalidProtocolBufferException { + TransactionEvent ret = null; + + EnvelopeInfo envelopeInfo = getEnvelopeInfo(index); + if (envelopeInfo.getType() == EnvelopeType.TRANSACTION_ENVELOPE) { + if (isFiltered()) { + ret = new TransactionEvent(getEnvelopeInfo(index).filteredTx); + } else { + ret = new TransactionEvent((TransactionEnvelopeInfo) getEnvelopeInfo(index)); + } + } - return isFiltered() ? new TransactionEvent(getEnvelopeInfo(index).filteredTx) : - new TransactionEvent((TransactionEnvelopeInfo) getEnvelopeInfo(index)); + return ret; } public class TransactionEvent extends TransactionEnvelopeInfo { @@ -147,7 +156,7 @@ public Peer getPeer() { List getTransactionEventsList() { - ArrayList ret = new ArrayList(getEnvelopeCount()); + ArrayList ret = new ArrayList(getTransactionCount()); for (TransactionEvent transactionEvent : getTransactionEvents()) { ret.add(transactionEvent); } @@ -165,29 +174,37 @@ public Iterable getTransactionEvents() { class TransactionEventIterator implements Iterator { final int max; int ci = 0; + int returned = 0; TransactionEventIterator() { - max = getEnvelopeCount(); - + max = getTransactionCount(); } @Override public boolean hasNext() { - return ci < max; + return returned < max; } @Override public TransactionEvent next() { + TransactionEvent ret = null; + // Filter for only transactions but today it's not really needed. + // Blocks with transactions only has transactions or a single pdate. try { - return getTransactionEvent(ci++); + do { + + ret = getTransactionEvent(ci++); + + } while (ret == null); + } catch (InvalidProtocolBufferException e) { throw new InvalidProtocolBufferRuntimeException(e); } - + ++returned; + return ret; } - } class TransactionEventIterable implements Iterable { diff --git a/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java b/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java index e1a2adf3..d2ce565b 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java +++ b/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java @@ -33,6 +33,7 @@ import static java.lang.String.format; import static org.hyperledger.fabric.protos.peer.FabricProposalResponse.Endorsement; +import static org.hyperledger.fabric.sdk.BlockInfo.EnvelopeType.TRANSACTION_ENVELOPE; /** * BlockInfo contains the data from a {@link Block} @@ -140,6 +141,52 @@ public int getEnvelopeCount() { return isFiltered() ? filteredBlock.getFilteredTransactionsCount() : block.getData().getDataCount(); } + private int transactionCount = -1; + + /** + * Number of endorser transaction found in the block. + * + * @return Number of endorser transaction found in the block. + */ + + public int getTransactionCount() { + if (isFiltered()) { + + int ltransactionCount = transactionCount; + if (ltransactionCount < 0) { + ltransactionCount = 0; + + for (int i = filteredBlock.getFilteredTransactionsCount() - 1; i >= 0; --i) { + FilteredTransaction filteredTransactions = filteredBlock.getFilteredTransactions(i); + Common.HeaderType type = filteredTransactions.getType(); + if (type == Common.HeaderType.ENDORSER_TRANSACTION) { + ++ltransactionCount; + } + } + transactionCount = ltransactionCount; + } + + return transactionCount; + } + int ltransactionCount = transactionCount; + if (ltransactionCount < 0) { + + ltransactionCount = 0; + for (int i = getEnvelopeCount() - 1; i >= 0; --i) { + try { + EnvelopeInfo envelopeInfo = getEnvelopeInfo(i); + if (envelopeInfo.getType() == TRANSACTION_ENVELOPE) { + ++ltransactionCount; + } + } catch (InvalidProtocolBufferException e) { + throw new InvalidProtocolBufferRuntimeException(e); + } + } + transactionCount = ltransactionCount; + } + return transactionCount; + } + /** * Wrappers Envelope */ diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java index e54f6988..d49df09b 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java @@ -914,6 +914,7 @@ void blockWalker(HFClient client, Channel channel) throws InvalidArgumentExcepti assertEquals(1, envelopeCount); out("current block number %d has %d envelope count:", blockNumber, returnedBlock.getEnvelopeCount()); int i = 0; + int transactionCount = 0; for (BlockInfo.EnvelopeInfo envelopeInfo : returnedBlock.getEnvelopeInfos()) { ++i; @@ -929,6 +930,7 @@ void blockWalker(HFClient client, Channel channel) throws InvalidArgumentExcepti out(" Transaction number %d has submitter mspid: %s, certificate: %s", i, envelopeInfo.getCreator().getMspid(), envelopeInfo.getCreator().getId()); if (envelopeInfo.getType() == TRANSACTION_ENVELOPE) { + ++transactionCount; BlockInfo.TransactionEnvelopeInfo transactionEnvelopeInfo = (BlockInfo.TransactionEnvelopeInfo) envelopeInfo; out(" Transaction number %d has %d actions", i, transactionEnvelopeInfo.getTransactionActionInfoCount()); @@ -1037,6 +1039,9 @@ void blockWalker(HFClient client, Channel channel) throws InvalidArgumentExcepti } } } + + assertEquals(transactionCount, returnedBlock.getTransactionCount()); + } } if (!TX_EXPECTED.isEmpty()) { diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java index f92b63f5..1706190a 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java @@ -34,6 +34,8 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; +import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent; +import org.hyperledger.fabric.sdk.BlockInfo; import org.hyperledger.fabric.sdk.Channel; import org.hyperledger.fabric.sdk.EventHub; import org.hyperledger.fabric.sdk.HFClient; @@ -49,6 +51,8 @@ import static org.hyperledger.fabric.sdk.Channel.PeerOptions.createPeerOptions; import static org.hyperledger.fabric.sdk.testutils.TestUtils.resetConfig; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** @@ -216,6 +220,11 @@ public void setup() { out("\n"); + Thread.sleep(3000); // give time for events to happen + + assertTrue(eventCountFilteredBlock > 0); // make sure we got blockevent that were tested. + assertTrue(eventCountBlock > 0); // make sure we got blockevent that were tested. + out("That's all folks!"); } catch (Exception e) { @@ -224,6 +233,9 @@ public void setup() { } } + int eventCountFilteredBlock = 0; + int eventCountBlock = 0; + private Channel reconstructChannel(String name, HFClient client, SampleOrg sampleOrg) throws Exception { client.setUserContext(sampleOrg.getPeerAdmin()); @@ -234,6 +246,9 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl testConfig.getOrdererProperties(orderName))); } + assertTrue(sampleOrg.getPeerNames().size() > 1); // need at least two for testing. + + int i = 0; for (String peerName : sampleOrg.getPeerNames()) { String peerLocation = sampleOrg.getPeerLocation(peerName); Peer peer = client.newPeer(peerName, peerLocation, testConfig.getPeerProperties(peerName)); @@ -243,9 +258,17 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl if (!channels.contains(name)) { throw new AssertionError(format("Peer %s does not appear to belong to channel %s", peerName, name)); } + Channel.PeerOptions peerOptions = createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.CHAINCODE_QUERY, + Peer.PeerRole.ENDORSING_PEER, Peer.PeerRole.LEDGER_QUERY, Peer.PeerRole.EVENT_SOURCE)); + + if (i % 2 == 0) { + peerOptions.registerEventsForFilteredBlocks(); // we need a mix of each type for testing. + } else { + peerOptions.registerEventsForBlocks(); + } + ++i; - newChannel.addPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.CHAINCODE_QUERY, - Peer.PeerRole.ENDORSING_PEER, Peer.PeerRole.LEDGER_QUERY))); + newChannel.addPeer(peer, peerOptions); } for (String eventHubName : sampleOrg.getEventHubNames()) { @@ -254,6 +277,40 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl newChannel.addEventHub(eventHub); } + //For testing of blocks which are not transactions. + newChannel.registerBlockListener(blockEvent -> { + // Note peer eventing will always start with sending the last block so this will get the last endorser block + int transactions = 0; + int nonTransactions = 0; + for (BlockInfo.EnvelopeInfo envelopeInfo : blockEvent.getEnvelopeInfos()) { + + if (BlockInfo.EnvelopeType.TRANSACTION_ENVELOPE == envelopeInfo.getType()) { + ++transactions; + } else { + assertEquals(BlockInfo.EnvelopeType.ENVELOPE, envelopeInfo.getType()); + ++nonTransactions; + } + + } + assertTrue(format("nontransactions %d, transactions %d", nonTransactions, transactions), nonTransactions < 2); // non transaction blocks only have one envelope + assertTrue(format("nontransactions %d, transactions %d", nonTransactions, transactions), nonTransactions + transactions > 0); // has to be one. + assertFalse(format("nontransactions %d, transactions %d", nonTransactions, transactions), nonTransactions > 0 && transactions > 0); // can't have both. + + if (nonTransactions > 0) { // this is an update block -- don't care about others here. + + if (blockEvent.isFiltered()) { + ++eventCountFilteredBlock; // make sure we're seeing non transaction events. + } else { + ++eventCountBlock; + } + assertEquals(0, blockEvent.getTransactionCount()); + assertEquals(1, blockEvent.getEnvelopeCount()); + for (TransactionEvent transactionEvent : blockEvent.getTransactionEvents()) { + fail("Got transaction event in a block update"); // only events for update should not have transactions. + } + } + }); + newChannel.initialize(); return newChannel;