diff --git a/checkstyle-config.xml b/checkstyle-config.xml index 75a9e22a..0bddcf20 100644 --- a/checkstyle-config.xml +++ b/checkstyle-config.xml @@ -105,7 +105,11 @@ - + + + + + diff --git a/pom.xml b/pom.xml index 4a4eef32..b61b79d1 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ 1.8.0 - 1.58 + 1.59 4.5.4 true 8.1.7.v20160121 @@ -102,7 +102,7 @@ com.google.protobuf protobuf-java - 3.5.0 + 3.5.1 diff --git a/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java b/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java index 3c8b48ac..82d55d62 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java +++ b/src/main/java/org/hyperledger/fabric/sdk/BlockEvent.java @@ -19,7 +19,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import org.hyperledger.fabric.protos.common.Common.Block; -import org.hyperledger.fabric.protos.orderer.Ab; +import org.hyperledger.fabric.protos.peer.PeerEvents; import org.hyperledger.fabric.protos.peer.PeerEvents.Event; import org.hyperledger.fabric.sdk.exception.InvalidProtocolBufferRuntimeException; @@ -29,7 +29,6 @@ * @see Block */ public class BlockEvent extends BlockInfo { - // private static final Log logger = LogFactory.getLog(BlockEvent.class); private final EventHub eventHub; @@ -50,9 +49,8 @@ public class BlockEvent extends BlockInfo { this.event = event; } - BlockEvent(Peer peer, Ab.DeliverResponse resp) { - super(resp.getBlock()); - + BlockEvent(Peer peer, PeerEvents.DeliverResponse resp) { + super(resp); eventHub = null; this.peer = peer; this.event = null; @@ -89,35 +87,26 @@ public Peer getPeer() { // } boolean isBlockEvent() { + if (peer != null) { + return true; //peer always returns Block type events; + } - return event == null || event.getEventCase() == Event.EventCase.BLOCK; + return event != null && event.getEventCase() == PeerEvents.Event.EventCase.BLOCK; } TransactionEvent getTransactionEvent(int index) throws InvalidProtocolBufferException { - return new TransactionEvent((TransactionEnvelopeInfo) getEnvelopeInfo(index), index); + return isFiltered() ? new TransactionEvent(getEnvelopeInfo(index).filteredTx) : + new TransactionEvent((TransactionEnvelopeInfo) getEnvelopeInfo(index)); } - List getTransactionEventsList() { - - ArrayList ret = new ArrayList(getEnvelopeCount()); - for (TransactionEvent transactionEvent : getTransactionEvents()) { - ret.add(transactionEvent); + public class TransactionEvent extends TransactionEnvelopeInfo { + TransactionEvent(TransactionEnvelopeInfo transactionEnvelopeInfo) { + super(transactionEnvelopeInfo.getTransactionDeserializer()); } - return ret; - - } - - public Iterable getTransactionEvents() { - - return new TransactionEventIterable(); - - } - - public class TransactionEvent extends TransactionEnvelopeInfo { - TransactionEvent(TransactionEnvelopeInfo transactionEnvelopeInfo, int index) { - super(transactionEnvelopeInfo.getTransactionDeserializer(), index); + TransactionEvent(PeerEvents.FilteredTransaction filteredTransaction) { + super(filteredTransaction); } /** @@ -144,6 +133,23 @@ public Peer getPeer() { } } + List getTransactionEventsList() { + + ArrayList ret = new ArrayList(getEnvelopeCount()); + for (TransactionEvent transactionEvent : getTransactionEvents()) { + ret.add(transactionEvent); + } + + return ret; + + } + + public Iterable getTransactionEvents() { + + return new TransactionEventIterable(); + + } + class TransactionEventIterator implements Iterator { final int max; int ci = 0; diff --git a/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java b/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java index 026010e6..bc8c40f6 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java +++ b/src/main/java/org/hyperledger/fabric/sdk/BlockInfo.java @@ -20,64 +20,123 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import org.hyperledger.fabric.protos.common.Common; import org.hyperledger.fabric.protos.common.Common.Block; import org.hyperledger.fabric.protos.ledger.rwset.Rwset.TxReadWriteSet; import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeInput; +import org.hyperledger.fabric.protos.peer.FabricTransaction; +import org.hyperledger.fabric.protos.peer.PeerEvents; +import org.hyperledger.fabric.protos.peer.PeerEvents.FilteredTransaction; import org.hyperledger.fabric.sdk.exception.InvalidProtocolBufferRuntimeException; import org.hyperledger.fabric.sdk.transaction.ProtoUtils; +import static java.lang.String.format; import static org.hyperledger.fabric.protos.peer.FabricProposalResponse.Endorsement; /** * BlockInfo contains the data from a {@link Block} */ public class BlockInfo { - private final BlockDeserializer block; + private final BlockDeserializer block; //can be only one or the other. + private final PeerEvents.FilteredBlock filteredBlock; BlockInfo(Block block) { + + filteredBlock = null; this.block = new BlockDeserializer(block); } +// BlockInfo(PeerEvents.Event event) { +// if (event.getEventCase() == PeerEvents.Event.EventCase.FILTERED_BLOCK) { +// block = null; +// filteredBlock = event.getFilteredBlock(); +// } else { +// this.block = new BlockDeserializer(event.getBlock()); +// filteredBlock = null; +// } +// } + + BlockInfo(PeerEvents.DeliverResponse resp) { + + final PeerEvents.DeliverResponse.TypeCase type = resp.getTypeCase(); + + if (type == PeerEvents.DeliverResponse.TypeCase.BLOCK) { + final Block respBlock = resp.getBlock(); + filteredBlock = null; + if (respBlock == null) { + throw new AssertionError("DeliverResponse type block but block is null"); + } + this.block = new BlockDeserializer(respBlock); + } else if (type == PeerEvents.DeliverResponse.TypeCase.FILTERED_BLOCK) { + filteredBlock = resp.getFilteredBlock(); + block = null; + if (filteredBlock == null) { + throw new AssertionError("DeliverResponse type filter block but filter block is null"); + } + + } else { + throw new AssertionError(format("DeliverResponse type has unexpected type: %s, %d", type.name(), type.getNumber())); + } + + } + + public boolean isFiltered() { + if (filteredBlock == null && block == null) { + throw new AssertionError("Both block and filter is null."); + } + if (filteredBlock != null && block != null) { + throw new AssertionError("Both block and filter are set."); + } + return filteredBlock != null; + } + public String getChannelId() throws InvalidProtocolBufferException { - return getEnvelopeInfo(0).getChannelId(); + return isFiltered() ? filteredBlock.getChannelId() : getEnvelopeInfo(0).getChannelId(); } /** * @return the raw {@link Block} */ public Block getBlock() { - return block.getBlock(); + return isFiltered() ? null : block.getBlock(); + } + + /** + * @return the raw {@link org.hyperledger.fabric.protos.peer.PeerEvents.FilteredBlock} + */ + public PeerEvents.FilteredBlock getFilteredBlock() { + return !isFiltered() ? null : filteredBlock; } /** - * @return the {@link Block} previousHash value + * @return the {@link Block} previousHash value and null if filtered block. */ public byte[] getPreviousHash() { - return block.getPreviousHash().toByteArray(); + return isFiltered() ? null : block.getPreviousHash().toByteArray(); } /** - * @return the {@link Block} data hash value + * @return the {@link Block} data hash value and null if filtered block. */ public byte[] getDataHash() { - return block.getDataHash().toByteArray(); + return isFiltered() ? null : block.getDataHash().toByteArray(); } /** - * @return the {@link Block} transaction metadata value + * @return the {@link Block} transaction metadata value return null if filtered block. */ public byte[] getTransActionsMetaData() { - return block.getTransActionsMetaData(); + return isFiltered() ? null : block.getTransActionsMetaData(); } /** * @return the {@link Block} index number */ public long getBlockNumber() { - return block.getNumber(); + return isFiltered() ? filteredBlock.getNumber() : block.getNumber(); } /** @@ -87,59 +146,101 @@ public long getBlockNumber() { */ public int getEnvelopeCount() { - return block.getData().getDataCount(); + return isFiltered() ? filteredBlock.getFilteredTxCount() : block.getData().getDataCount(); } public class EnvelopeInfo { private final EnvelopeDeserializer envelopeDeserializer; - HeaderDeserializer headerDeserializer; + private final HeaderDeserializer headerDeserializer; + protected final FilteredTransaction filteredTx; + + boolean isFiltered() { + return filteredTx != null; + + } //private final EnvelopeDeserializer envelopeDeserializer; - EnvelopeInfo(EnvelopeDeserializer envelopeDeserializer, int blockIndex) { + EnvelopeInfo(EnvelopeDeserializer envelopeDeserializer) { this.envelopeDeserializer = envelopeDeserializer; headerDeserializer = envelopeDeserializer.getPayload().getHeader(); - headerDeserializer.getChannelHeader().getType(); + filteredTx = null; + } + + public EnvelopeInfo(FilteredTransaction filteredTx) { + this.filteredTx = filteredTx; + envelopeDeserializer = null; + headerDeserializer = null; + } public String getChannelId() { - return headerDeserializer.getChannelHeader().getChannelId(); + return BlockInfo.this.isFiltered() ? filteredBlock.getChannelId() : headerDeserializer.getChannelHeader().getChannelId(); } public String getTransactionID() { - return headerDeserializer.getChannelHeader().getTxId(); + return BlockInfo.this.isFiltered() ? filteredTx.getTxid() : headerDeserializer.getChannelHeader().getTxId(); } + /** + * @return epoch and -1 if filtered block. + * @deprecated + */ + public long getEpoch() { - return headerDeserializer.getChannelHeader().getEpoch(); + return BlockInfo.this.isFiltered() ? -1 : headerDeserializer.getChannelHeader().getEpoch(); } + /** + * Timestamp + * + * @return timestamp and null if filtered block. + */ + public Date getTimestamp() { - return ProtoUtils.getDateFromTimestamp(headerDeserializer.getChannelHeader().getTimestamp()); + return BlockInfo.this.isFiltered() ? null : + ProtoUtils.getDateFromTimestamp(headerDeserializer.getChannelHeader().getTimestamp()); } /** * @return whether this Transaction is marked as TxValidationCode.VALID */ public boolean isValid() { - return envelopeDeserializer.isValid(); + return BlockInfo.this.isFiltered() ? filteredTx.getTxValidationCode().getNumber() == FabricTransaction.TxValidationCode.VALID_VALUE + : envelopeDeserializer.isValid(); } /** * @return the validation code of this Transaction (enumeration TxValidationCode in Transaction.proto) */ public byte getValidationCode() { + if (BlockInfo.this.isFiltered()) { + + return (byte) filteredTx.getTxValidationCode().getNumber(); + + } return envelopeDeserializer.validationCode(); } public EnvelopeType getType() { - switch (headerDeserializer.getChannelHeader().getType()) { - case 3: + final int type; + + if (BlockInfo.this.isFiltered()) { + + type = filteredTx.getTypeValue(); + + } else { + type = headerDeserializer.getChannelHeader().getType(); + + } + + switch (type) { + case Common.HeaderType.ENDORSER_TRANSACTION_VALUE: return EnvelopeType.TRANSACTION_ENVELOPE; default: @@ -164,15 +265,30 @@ public EnvelopeInfo getEnvelopeInfo(int envelopeIndex) throws InvalidProtocolBuf EnvelopeInfo ret; - EnvelopeDeserializer ed = EnvelopeDeserializer.newInstance(block.getBlock().getData().getData(envelopeIndex), block.getTransActionsMetaData()[envelopeIndex]); + if (isFiltered()) { + + switch (filteredBlock.getFilteredTx(envelopeIndex).getType().getNumber()) { + case Common.HeaderType.ENDORSER_TRANSACTION_VALUE: + ret = new TransactionEnvelopeInfo(this.filteredBlock.getFilteredTx(envelopeIndex)); + break; + default: //just assume base properties. + ret = new EnvelopeInfo(this.filteredBlock.getFilteredTx(envelopeIndex)); + break; + } + + } else { - switch (ed.getType()) { - case 3: - ret = new TransactionEnvelopeInfo((EndorserTransactionEnvDeserializer) ed, envelopeIndex); - break; - default: //just assume base properties. - ret = new EnvelopeInfo(ed, envelopeIndex); - break; + EnvelopeDeserializer ed = EnvelopeDeserializer.newInstance(block.getBlock().getData().getData(envelopeIndex), block.getTransActionsMetaData()[envelopeIndex]); + + switch (ed.getType()) { + case Common.HeaderType.ENDORSER_TRANSACTION_VALUE: + ret = new TransactionEnvelopeInfo((EndorserTransactionEnvDeserializer) ed); + break; + default: //just assume base properties. + ret = new EnvelopeInfo(ed); + break; + + } } return ret; @@ -196,22 +312,25 @@ public Iterable getEnvelopeInfos() { public class TransactionEnvelopeInfo extends EnvelopeInfo { - EndorserTransactionEnvDeserializer getTransactionDeserializer() { - return transactionDeserializer; + TransactionEnvelopeInfo(FilteredTransaction filteredTx) { + super(filteredTx); + this.transactionDeserializer = null; } - protected final EndorserTransactionEnvDeserializer transactionDeserializer; - - public TransactionEnvelopeInfo(EndorserTransactionEnvDeserializer transactionDeserializer, int blockIndex) { - super(transactionDeserializer, blockIndex); + TransactionEnvelopeInfo(EndorserTransactionEnvDeserializer transactionDeserializer) { + super(transactionDeserializer); this.transactionDeserializer = transactionDeserializer; - this.headerDeserializer = transactionDeserializer.getPayload().getHeader(); + } + EndorserTransactionEnvDeserializer getTransactionDeserializer() { + return transactionDeserializer; } + protected final EndorserTransactionEnvDeserializer transactionDeserializer; + public int getTransactionActionInfoCount() { - return transactionDeserializer.getPayload().getTransaction().getActionsCount(); + return BlockInfo.this.isFiltered() ? filteredTx.getTransactionActions().getChaincodeActionsCount() : transactionDeserializer.getPayload().getTransaction().getActionsCount(); } public Iterable getTransactionActionInfos() { @@ -222,28 +341,45 @@ public Iterable getTransactionActionInfos() { public class TransactionActionInfo { private final TransactionActionDeserializer transactionAction; + private final PeerEvents.FilteredChaincodeAction filteredAction; List endorserInfos = null; + private boolean isFiltered() { + return filteredAction != null; + + } + TransactionActionInfo(TransactionActionDeserializer transactionAction) { this.transactionAction = transactionAction; + filteredAction = null; + } + + TransactionActionInfo(PeerEvents.FilteredChaincodeAction filteredAction) { + this.filteredAction = filteredAction; + transactionAction = null; + } public byte[] getResponseMessageBytes() { - return transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseMessageBytes(); + return isFiltered() ? null : transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseMessageBytes(); } public String getResponseMessage() { - return transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseMessage(); + return isFiltered() ? null : + transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseMessage(); } public int getResponseStatus() { - return transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseStatus(); + return isFiltered() ? -1 : transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseStatus(); } int getChaincodeInputArgsCount = -1; public int getChaincodeInputArgsCount() { + if (isFiltered()) { + return 0; + } if (getChaincodeInputArgsCount < 0) { getChaincodeInputArgsCount = transactionAction.getPayload().getChaincodeProposalPayload(). getChaincodeInvocationSpec().getChaincodeInput().getChaincodeInput().getArgsCount(); @@ -252,6 +388,9 @@ public int getChaincodeInputArgsCount() { } public byte[] getChaincodeInputArgs(int index) { + if (isFiltered()) { + return null; + } ChaincodeInput input = transactionAction.getPayload().getChaincodeProposalPayload(). getChaincodeInvocationSpec().getChaincodeInput().getChaincodeInput(); @@ -262,6 +401,9 @@ public byte[] getChaincodeInputArgs(int index) { int getEndorsementsCount = -1; public int getEndorsementsCount() { + if (isFiltered()) { + return 0; + } if (getEndorsementsCount < 0) { getEndorsementsCount = transactionAction.getPayload().getAction().getEndorsementsCount(); } @@ -269,6 +411,9 @@ public int getEndorsementsCount() { } public EndorserInfo getEndorsementInfo(int index) { + if (isFiltered()) { + return null; + } if (null == endorserInfos) { endorserInfos = new ArrayList<>(); @@ -284,12 +429,18 @@ public EndorserInfo getEndorsementInfo(int index) { } public byte[] getProposalResponseMessageBytes() { + if (isFiltered()) { + return null; + } return transactionAction.getPayload().getAction().getProposalResponsePayload().getExtension().getResponseMessageBytes(); } public byte[] getProposalResponsePayload() { + if (isFiltered()) { + return null; + } byte[] ret = null; ByteString retByteString = transactionAction.getPayload().getAction().getProposalResponsePayload(). @@ -303,6 +454,9 @@ public byte[] getProposalResponsePayload() { } public int getProposalResponseStatus() { + if (isFiltered()) { + return -1; + } return transactionAction.getPayload().getAction().getProposalResponsePayload(). getExtension().getResponseStatus(); @@ -318,13 +472,19 @@ public int getProposalResponseStatus() { public TxReadWriteSetInfo getTxReadWriteSet() { - TxReadWriteSet txReadWriteSet = transactionAction.getPayload().getAction().getProposalResponsePayload() - .getExtension().getResults(); - if (txReadWriteSet == null) { + if (BlockInfo.this.isFiltered()) { return null; - } - return new TxReadWriteSetInfo(txReadWriteSet); + } else { + + TxReadWriteSet txReadWriteSet = transactionAction.getPayload().getAction().getProposalResponsePayload() + .getExtension().getResults(); + if (txReadWriteSet == null) { + return null; + } + + return new TxReadWriteSetInfo(txReadWriteSet); + } } @@ -335,6 +495,10 @@ public TxReadWriteSetInfo getTxReadWriteSet() { */ public ChaincodeEvent getEvent() { + if (isFiltered()) { + final PeerEvents.FilteredChaincodeAction chaincodeActions = filteredAction; + return new ChaincodeEvent(chaincodeActions.getCcEvent().toByteString()); + } return transactionAction.getPayload().getAction().getProposalResponsePayload() .getExtension().getEvent(); @@ -344,7 +508,8 @@ public ChaincodeEvent getEvent() { } public TransactionActionInfo getTransactionActionInfo(int index) { - return new TransactionActionInfo(transactionDeserializer.getPayload().getTransaction().getTransactionAction(index)); + return BlockInfo.this.isFiltered() ? new TransactionActionInfo(filteredTx.getTransactionActions().getChaincodeActionsList().get(index)) + : new TransactionActionInfo(transactionDeserializer.getPayload().getTransaction().getTransactionAction(index)); } public class TransactionActionInfoIterator implements Iterator { @@ -365,8 +530,13 @@ public boolean hasNext() { @Override public TransactionActionInfo next() { - return getTransactionActionInfo(ci++); + if (ci >= max) { + throw new ArrayIndexOutOfBoundsException(format("Current index: %d. Max index: %d", ci, max)); + } + // return BlockInfo.this.isFiltered() ? new TransactionActionInfo(filteredTx.getFilteredAction(ci++)) + return BlockInfo.this.isFiltered() ? new TransactionActionInfo(filteredTx.getTransactionActions().getChaincodeActions(ci++)) + : getTransactionActionInfo(ci++); } } @@ -377,7 +547,6 @@ public Iterator iterator() { return new TransactionActionInfoIterator(); } } - } class EnvelopeInfoIterator implements Iterator { @@ -385,7 +554,7 @@ class EnvelopeInfoIterator implements Iterator { final int max; EnvelopeInfoIterator() { - max = block.getData().getDataCount(); + max = isFiltered() ? filteredBlock.getFilteredTxCount() : block.getData().getDataCount(); } @@ -398,6 +567,10 @@ public boolean hasNext() { @Override public EnvelopeInfo next() { + if (ci >= max) { + throw new ArrayIndexOutOfBoundsException(format("Current index: %d. Max index: %d", ci, max)); + } + try { return getEnvelopeInfo(ci++); } catch (InvalidProtocolBufferException e) { diff --git a/src/main/java/org/hyperledger/fabric/sdk/Channel.java b/src/main/java/org/hyperledger/fabric/sdk/Channel.java index ac734ccb..fc9f7196 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/Channel.java +++ b/src/main/java/org/hyperledger/fabric/sdk/Channel.java @@ -561,7 +561,7 @@ public String getName() { */ public Channel addPeer(Peer peer) throws InvalidArgumentException { - return addPeer(peer, PeerOptions.create()); + return addPeer(peer, PeerOptions.createPeerOptions()); } @@ -615,7 +615,7 @@ public Channel addPeer(Peer peer, PeerOptions peerOptions) throws InvalidArgumen */ public Channel joinPeer(Peer peer) throws ProposalException { - return joinPeer(peer, PeerOptions.create()); + return joinPeer(peer, PeerOptions.createPeerOptions()); } private Collection getEventingPeers() { @@ -644,8 +644,7 @@ private Collection getLedgerQueryPeers() { } /** - * - * @param peer the peer to join the channel. + * @param peer the peer to join the channel. * @param peerOptions see {@link PeerOptions} * @return * @throws ProposalException @@ -852,7 +851,7 @@ public Collection getPeers(EnumSet roles) { /** * Set peerOptions in the channel that has not be initialized yet. * - * @param peer the peer to set options on. + * @param peer the peer to set options on. * @param peerOptions see {@link PeerOptions} * @return old options. */ @@ -1040,6 +1039,7 @@ boolean isSystemChannel() { /** * Is the channel shutdown. + * * @return return true if the channel is shutdown. */ public boolean isShutdown() { @@ -1048,6 +1048,7 @@ public boolean isShutdown() { /** * Get signed byes of the update channel. + * * @param updateChannelConfiguration * @param signer * @return @@ -2404,8 +2405,8 @@ public CompletableFuture sendTransaction(Collection peerRoles; - // protected String blockType = "Filter"; // not yet used. protected Boolean newest = true; protected Long startEvents; protected Long stopEvents = Long.MAX_VALUE; + protected boolean registerEventsForFilteredBlocks = false; + + /** + * Is the peer eventing service registered for filtered blocks + * + * @return true if filtered blocks will be returned by the peer eventing service. + */ + public boolean isRegisterEventsForFilteredBlocks() { + return registerEventsForFilteredBlocks; + } + + /** + * Register the peer eventing services to return filtered blocks. + * + * @return the PeerOptions instance. + */ + + public PeerOptions registerEventsForFilteredBlocks() { + registerEventsForFilteredBlocks = true; + return this; + } /** - * Get newest block on startup. + * Register the peer eventing services to return full event blocks. + * + * @return the PeerOptions instance. + */ + + public PeerOptions registerEventsForBlocks() { + registerEventsForFilteredBlocks = false; + return this; + } + + /** + * Get newest block on startup of peer eventing service. + * * @return */ - Boolean getNewest() { + public Boolean getNewest() { return newest; } /** - * The block number to start getting. + * The block number to start getting events from on start up of the peer eventing service.. * * @return the start number */ @@ -3169,7 +3202,7 @@ public Long getStartEvents() { } /** - * The stopping block number. + * The stopping block number when the peer eventing service will stop sending blocks. * * @return the stop block number. */ @@ -3184,10 +3217,11 @@ protected PeerOptions() { /** * Create an instance of PeerOptions. + * * @return the PeerOptions instance. */ - public static PeerOptions create() { + public static PeerOptions createPeerOptions() { return new PeerOptions(); } @@ -3206,6 +3240,7 @@ public EnumSet getPeerRoles() { /** * Set the roles this peer will have on the chain it will added or joined. + * * @param peerRoles {@link PeerRole} * @return This PeerOptions. */ @@ -3217,6 +3252,7 @@ public PeerOptions setPeerRoles(EnumSet peerRoles) { /** * Add to the roles this peer will have on the chain it will added or joined. + * * @param peerRole see {@link PeerRole} * @return This PeerOptions. */ @@ -3233,6 +3269,7 @@ public PeerOptions addPeerRole(PeerRole peerRole) { /** * Set the block number the eventing peer will start relieving events. + * * @param start The staring block number. * @return This PeerOptions. */ @@ -3246,6 +3283,7 @@ public PeerOptions startEvents(long start) { /** * This is the default. It will start retrieving events with the newest. Note this is not the * next block that is added to the chain but the current block on the chain. + * * @return This PeerOptions. */ @@ -3258,6 +3296,7 @@ public PeerOptions startEventsNewest() { /** * The block number to stop sending events. + * * @param stop the number to stop sending events. * @return This PeerOptions. */ @@ -3268,6 +3307,7 @@ public PeerOptions stopEvents(long stop) { /** * Clone. + * * @return return a duplicate of this instance. */ diff --git a/src/main/java/org/hyperledger/fabric/sdk/NetworkConfig.java b/src/main/java/org/hyperledger/fabric/sdk/NetworkConfig.java index ca074e77..f9993d3b 100755 --- a/src/main/java/org/hyperledger/fabric/sdk/NetworkConfig.java +++ b/src/main/java/org/hyperledger/fabric/sdk/NetworkConfig.java @@ -567,7 +567,7 @@ private Channel reconstructChannel(HFClient client, String channelName, JsonObje } // Set the various roles - PeerOptions peerOptions = PeerOptions.create(); + PeerOptions peerOptions = PeerOptions.createPeerOptions(); setPeerRole(channelName, peerOptions, jsonPeer, PeerRole.ENDORSING_PEER); setPeerRole(channelName, peerOptions, jsonPeer, PeerRole.CHAINCODE_QUERY); setPeerRole(channelName, peerOptions, jsonPeer, PeerRole.LEDGER_QUERY); diff --git a/src/main/java/org/hyperledger/fabric/sdk/Orderer.java b/src/main/java/org/hyperledger/fabric/sdk/Orderer.java index 1212bc41..3619baf1 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/Orderer.java +++ b/src/main/java/org/hyperledger/fabric/sdk/Orderer.java @@ -36,7 +36,32 @@ public class Orderer implements Serializable { private static final Log logger = LogFactory.getLog(Orderer.class); private static final long serialVersionUID = 4281642068914263247L; private final Properties properties; + private final String name; + private final String url; private transient boolean shutdown = false; + private Channel channel; + private transient volatile OrdererClient ordererClient = null; + + Orderer(String name, String url, Properties properties) throws InvalidArgumentException { + + if (StringUtil.isNullOrEmpty(name)) { + throw new InvalidArgumentException("Invalid name for orderer"); + } + Exception e = checkGrpcUrl(url); + if (e != null) { + throw new InvalidArgumentException(e); + } + + this.name = name; + this.url = url; + this.properties = properties == null ? null : (Properties) properties.clone(); //keep our own copy. + + } + + static Orderer createNewInstance(String name, String url, Properties properties) throws InvalidArgumentException { + return new Orderer(name, url, properties); + + } /** * Get Orderer properties. @@ -58,25 +83,6 @@ public String getName() { return name; } - private final String name; - private final String url; - - Orderer(String name, String url, Properties properties) throws InvalidArgumentException { - - if (StringUtil.isNullOrEmpty(name)) { - throw new InvalidArgumentException("Invalid name for orderer"); - } - Exception e = checkGrpcUrl(url); - if (e != null) { - throw new InvalidArgumentException(e); - } - - this.name = name; - this.url = url; - this.properties = properties == null ? null : (Properties) properties.clone(); //keep our own copy. - - } - /** * getUrl - the Grpc url of the Orderer * @@ -86,28 +92,12 @@ public String getUrl() { return url; } - void setChannel(Channel channel) throws InvalidArgumentException { - if (channel == null) { - throw new InvalidArgumentException("setChannel Channel can not be null"); - } - - if (null != this.channel && this.channel != channel) { - throw new InvalidArgumentException(format("Can not add orderer %s to channel %s because it already belongs to channel %s.", - name, channel.getName(), this.channel.getName())); - } - - this.channel = channel; - - } - void unsetChannel() { channel = null; } - private Channel channel; - /** * Get the channel of which this orderer is a member. * @@ -117,6 +107,20 @@ Channel getChannel() { return channel; } + void setChannel(Channel channel) throws InvalidArgumentException { + if (channel == null) { + throw new InvalidArgumentException("setChannel Channel can not be null"); + } + + if (null != this.channel && this.channel != channel) { + throw new InvalidArgumentException(format("Can not add orderer %s to channel %s because it already belongs to channel %s.", + name, channel.getName(), this.channel.getName())); + } + + this.channel = channel; + + } + /** * Send transaction to Order * @@ -148,13 +152,6 @@ Ab.BroadcastResponse sendTransaction(Common.Envelope transaction) throws Excepti } - static Orderer createNewInstance(String name, String url, Properties properties) throws InvalidArgumentException { - return new Orderer(name, url, properties); - - } - - private transient volatile OrdererClient ordererClient = null; - DeliverResponse[] sendDeliver(Common.Envelope transaction) throws TransactionException { if (shutdown) { @@ -184,21 +181,20 @@ synchronized void shutdown(boolean force) { if (shutdown) { return; } + shutdown = true; + channel = null; + if (ordererClient != null) { OrdererClient torderClientDeliver = ordererClient; ordererClient = null; torderClientDeliver.shutdown(force); - } - shutdown = true; - channel = null; - } @Override protected void finalize() throws Throwable { - super.finalize(); shutdown(true); + super.finalize(); } } // end Orderer diff --git a/src/main/java/org/hyperledger/fabric/sdk/Peer.java b/src/main/java/org/hyperledger/fabric/sdk/Peer.java index 697de2f3..4726be8f 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/Peer.java +++ b/src/main/java/org/hyperledger/fabric/sdk/Peer.java @@ -153,7 +153,7 @@ void setChannel(Channel channel) throws InvalidArgumentException { */ public String getUrl() { - return this.url; + return url; } /** diff --git a/src/main/java/org/hyperledger/fabric/sdk/PeerEventServiceClient.java b/src/main/java/org/hyperledger/fabric/sdk/PeerEventServiceClient.java index dc8295c2..6884aeb2 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/PeerEventServiceClient.java +++ b/src/main/java/org/hyperledger/fabric/sdk/PeerEventServiceClient.java @@ -30,9 +30,9 @@ import org.apache.commons.logging.LogFactory; import org.hyperledger.fabric.protos.common.Common.Envelope; import org.hyperledger.fabric.protos.orderer.Ab; -import org.hyperledger.fabric.protos.orderer.Ab.DeliverResponse; import org.hyperledger.fabric.protos.orderer.Ab.SeekInfo; -import org.hyperledger.fabric.protos.orderer.AtomicBroadcastGrpc; +import org.hyperledger.fabric.protos.peer.DeliverGrpc; +import org.hyperledger.fabric.protos.peer.PeerEvents.DeliverResponse; import org.hyperledger.fabric.sdk.Channel.PeerOptions; import org.hyperledger.fabric.sdk.exception.CryptoException; import org.hyperledger.fabric.sdk.exception.TransactionException; @@ -40,9 +40,12 @@ import org.hyperledger.fabric.sdk.transaction.TransactionContext; import static java.lang.String.format; -import static org.hyperledger.fabric.protos.orderer.Ab.DeliverResponse.TypeCase.STATUS; +import static org.hyperledger.fabric.protos.peer.PeerEvents.DeliverResponse.TypeCase.BLOCK; +import static org.hyperledger.fabric.protos.peer.PeerEvents.DeliverResponse.TypeCase.FILTERED_BLOCK; +import static org.hyperledger.fabric.protos.peer.PeerEvents.DeliverResponse.TypeCase.STATUS; import static org.hyperledger.fabric.sdk.transaction.ProtoUtils.createSeekInfoEnvelope; + /** * Sample client code that makes gRPC calls to the server. */ @@ -56,8 +59,11 @@ class PeerEventServiceClient { private final String url; private final long ordererWaitTimeMilliSecs; private final PeerOptions peerOptions; - private Channel.ChannelEventQue channelEventQue; + private final boolean filterBlock; Properties properties = new Properties(); + StreamObserver nso = null; + StreamObserver so = null; + private Channel.ChannelEventQue channelEventQue; private boolean shutdown = false; private ManagedChannel managedChannel = null; private transient TransactionContext transactionContext; @@ -69,6 +75,7 @@ class PeerEventServiceClient { PeerEventServiceClient(Peer peer, ManagedChannelBuilder channelBuilder, Properties properties, PeerOptions peerOptions) { this.channelBuilder = channelBuilder; + this.filterBlock = peerOptions.isRegisterEventsForFilteredBlocks(); this.peer = peer; name = peer.getName(); url = peer.getUrl(); @@ -140,9 +147,6 @@ synchronized void shutdown(boolean force) { } - StreamObserver nso = null; - StreamObserver so = null; - @Override public void finalize() { shutdown(true); @@ -165,7 +169,7 @@ DeliverResponse[] connectEnvelope(Envelope envelope) throws TransactionException try { - AtomicBroadcastGrpc.AtomicBroadcastStub broadcast = AtomicBroadcastGrpc.newStub(lmanagedChannel); + DeliverGrpc.DeliverStub broadcast = DeliverGrpc.newStub(lmanagedChannel); // final DeliverResponse[] ret = new DeliverResponse[1]; final List retList = new ArrayList<>(); @@ -192,7 +196,9 @@ public void onNext(DeliverResponse resp) { return; } - if (resp.getTypeCase() == STATUS) { + final DeliverResponse.TypeCase typeCase = resp.getTypeCase(); + + if (typeCase == STATUS) { done = true; logger.debug(format("DeliverResponse channel %s peer %s setting done.", channelName, peer.getName())); @@ -200,12 +206,16 @@ public void onNext(DeliverResponse resp) { finishLatch.countDown(); - } else { + } else if (typeCase == FILTERED_BLOCK || typeCase == BLOCK) { logger.trace(format("Channel %s peer %s got event block hex hashcode: %016x, block number: %d", channelName, peer.getName(), resp.getBlock().hashCode(), resp.getBlock().getHeader().getNumber())); retList.add(resp); finishLatch.countDown(); channelEventQue.addBEvent(new BlockEvent(peer, resp)); + } else { + logger.error(format("Channel %s peer %s got event block with unknown type: %s, %d", + channelName, peer.getName(), typeCase.name(), typeCase.getNumber()) + ); } } @@ -217,7 +227,7 @@ public void onError(Throwable t) { return; // make sure we do this once. } if (!shutdown) { - logger.error(format("Received error on channel %s, orderer %s, url %s, %s", + logger.error(format("Received error on channel %s, peer %s, url %s, %s", channelName, name, url, t.getMessage()), t); done = true; @@ -243,7 +253,8 @@ public void onCompleted() { } }; - nso = broadcast.deliver(so); + nso = filterBlock ? broadcast.deliverFiltered(so) : broadcast.deliver(so); + nso.onNext(envelope); //nso.onCompleted(); @@ -251,7 +262,7 @@ public void onCompleted() { // if (!finishLatch.await(ordererWaitTimeMilliSecs, TimeUnit.MILLISECONDS)) { if (!finishLatch.await(9999999, TimeUnit.MILLISECONDS)) { TransactionException ex = new TransactionException(format( - "Channel %s connect time exceeded for orderer %s, timed out at %d ms.", channelName, name, ordererWaitTimeMilliSecs)); + "Channel %s connect time exceeded for peer eventing service %s, timed out at %d ms.", channelName, name, ordererWaitTimeMilliSecs)); logger.error(ex.getMessage(), ex); throw ex; } @@ -264,7 +275,7 @@ public void onCompleted() { if (!throwableList.isEmpty()) { Throwable throwable = throwableList.get(0); TransactionException e = new TransactionException(format( - "Channel %s connect failed on orderer %s. Reason: %s", channelName, name, throwable.getMessage()), throwable); + "Channel %s connect failed on peer eventing service %s. Reason: %s", channelName, name, throwable.getMessage()), throwable); logger.error(e.getMessage(), e); throw e; } diff --git a/src/main/java/org/hyperledger/fabric/sdk/helper/Config.java b/src/main/java/org/hyperledger/fabric/sdk/helper/Config.java index 1c27b1ef..f7d1e728 100644 --- a/src/main/java/org/hyperledger/fabric/sdk/helper/Config.java +++ b/src/main/java/org/hyperledger/fabric/sdk/helper/Config.java @@ -62,7 +62,6 @@ public class Config { public static final String SECURITY_CURVE_MAPPING = "org.hyperledger.fabric.sdk.security_curve_mapping"; public static final String HASH_ALGORITHM = "org.hyperledger.fabric.sdk.hash_algorithm"; public static final String ASYMMETRIC_KEY_TYPE = "org.hyperledger.fabric.sdk.crypto.asymmetric_key_type"; - public static final String CERTIFICATE_FORMAT = "org.hyperledger.fabric.sdk.crypto.certificate_format"; public static final String SIGNATURE_ALGORITHM = "org.hyperledger.fabric.sdk.crypto.default_signature_algorithm"; /** diff --git a/src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java b/src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java index 6d2b1a9d..82012f78 100644 --- a/src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java +++ b/src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java @@ -102,6 +102,10 @@ */ public class HFCAClient { + /** + * Default profile name. + */ + public static final String DEFAULT_PROFILE_NAME = ""; private static final Log logger = LogFactory.getLog(HFCAClient.class); private static final String HFCA_CONTEXT_ROOT = "/api/v1/"; private static final String HFCA_ENROLL = HFCA_CONTEXT_ROOT + "enroll"; diff --git a/src/main/proto/peer/events.proto b/src/main/proto/peer/events.proto index 51baea38..6179b50a 100644 --- a/src/main/proto/peer/events.proto +++ b/src/main/proto/peer/events.proto @@ -27,15 +27,14 @@ option go_package = "github.com/hyperledger/fabric/protos/peer"; package protos; - //----Event objects---- enum EventType { - REGISTER = 0; - BLOCK = 1; - CHAINCODE = 2; - REJECTION = 3; - FILTEREDBLOCK = 4; + REGISTER = 0; + BLOCK = 1; + CHAINCODE = 2; + REJECTION = 3; + FILTEREDBLOCK = 4; } //ChaincodeReg is used for registering chaincode Interests @@ -81,7 +80,6 @@ message Unregister { message FilteredBlock { string channel_id = 1; uint64 number = 2; // The position in the blockchain - common.HeaderType type = 3; repeated FilteredTransaction filtered_tx = 4; } @@ -89,13 +87,22 @@ message FilteredBlock { //within a block. message FilteredTransaction { string txid = 1; - TxValidationCode tx_validation_code = 2; - repeated FilteredAction filtered_action = 3; + common.HeaderType type = 2; + TxValidationCode tx_validation_code = 3; + oneof Data { + FilteredTransactionActions transaction_actions = 4; + } +} + +// FilteredTransactionActions is a wrapper for array of TransactionAction +// message from regular block +message FilteredTransactionActions { + repeated FilteredChaincodeAction chaincode_actions = 1; } -//FilteredAction is a minimal set of information about an action within a +//FilteredChaincodeAction is a minimal set of information about an action within a //transaction. -message FilteredAction { +message FilteredChaincodeAction { ChaincodeEvent ccEvent = 1; } @@ -129,10 +136,35 @@ message Event { bytes creator = 6; // Timestamp of the client - used to mitigate replay attacks google.protobuf.Timestamp timestamp = 8; + + // If mutual TLS is employed, this represents + // the hash of the client's TLS certificate + bytes tls_cert_hash = 9; } // Interface exported by the events server service Events { // event chatting using Event - rpc Chat(stream SignedEvent) returns (stream Event) {} + rpc Chat (stream SignedEvent) returns (stream Event) { + } } + +// DeliverResponse +message DeliverResponse { + oneof Type { + common.Status status = 1; + common.Block block = 2; + FilteredBlock filtered_block = 3; + } +} + +service Deliver { + // deliver first requires an Envelope of type ab.DELIVER_SEEK_INFO with Payload data as a marshaled orderer.SeekInfo message, + // then a stream of block replies is received. + rpc Deliver (stream common.Envelope) returns (stream DeliverResponse) { + } + // deliver first requires an Envelope of type ab.DELIVER_SEEK_INFO with Payload data as a marshaled orderer.SeekInfo message, + // then a stream of **filtered** block replies is received. + rpc DeliverFiltered (stream common.Envelope) returns (stream DeliverResponse) { + } +} \ No newline at end of file diff --git a/src/main/proto/peer/query.proto b/src/main/proto/peer/query.proto index 8dc3ec4d..d934104f 100644 --- a/src/main/proto/peer/query.proto +++ b/src/main/proto/peer/query.proto @@ -26,35 +26,41 @@ package protos; // instantiated on a channel), and GetInstalledChaincodes (returns all chaincodes // installed on a peer) message ChaincodeQueryResponse { - repeated ChaincodeInfo chaincodes = 1; + repeated ChaincodeInfo chaincodes = 1; } // ChaincodeInfo contains general information about an installed/instantiated // chaincode message ChaincodeInfo { - string name = 1; - string version = 2; - // the path as specified by the install/instantiate transaction - string path = 3; - // the chaincode function upon instantiation and its arguments. This will be - // blank if the query is returning information about installed chaincodes. - string input = 4; - // the name of the ESCC for this chaincode. This will be - // blank if the query is returning information about installed chaincodes. - string escc = 5; - // the name of the VSCC for this chaincode. This will be - // blank if the query is returning information about installed chaincodes. - string vscc = 6; + string name = 1; + string version = 2; + // the path as specified by the install/instantiate transaction + string path = 3; + // the chaincode function upon instantiation and its arguments. This will be + // blank if the query is returning information about installed chaincodes. + string input = 4; + // the name of the ESCC for this chaincode. This will be + // blank if the query is returning information about installed chaincodes. + string escc = 5; + // the name of the VSCC for this chaincode. This will be + // blank if the query is returning information about installed chaincodes. + string vscc = 6; + // the chaincode unique id. + // computed as: H( + // H(name || version) || + // H(CodePackage) + // ) + bytes id = 7; } // ChannelQueryResponse returns information about each channel that pertains // to a query in lscc.go, such as GetChannels (returns all channels for a // given peer) message ChannelQueryResponse { - repeated ChannelInfo channels = 1; + repeated ChannelInfo channels = 1; } // ChannelInfo contains general information about channels message ChannelInfo { - string channel_id = 1; + string channel_id = 1; } diff --git a/src/test/fixture/sdkintegration/peer-base/peer-base.yaml b/src/test/fixture/sdkintegration/peer-base/peer-base.yaml index 0830baf8..7f29ca9d 100644 --- a/src/test/fixture/sdkintegration/peer-base/peer-base.yaml +++ b/src/test/fixture/sdkintegration/peer-base/peer-base.yaml @@ -13,6 +13,7 @@ services: - CORE_PEER_ENDORSER_ENABLED=true - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false + - CORE_PEER_CHANNELSERVICE_ENABLED=true # The following setting skips the gossip handshake since we are # are not doing mutual TLS - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/msp diff --git a/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java b/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java index 3d24641c..0251e22f 100644 --- a/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java +++ b/src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java @@ -41,6 +41,7 @@ import org.junit.rules.ExpectedException; import sun.misc.Unsafe; +import static org.hyperledger.fabric.sdk.Channel.PeerOptions.createPeerOptions; import static org.hyperledger.fabric.sdk.testutils.TestUtils.setField; //CHECKSTYLE.ON: IllegalImport @@ -246,7 +247,7 @@ protected void loadCACertificates() { final Channel testChannel = new MockChannel(CHANNEL_NAME, hfclient); final Peer peer = hfclient.newPeer("peer_", "grpc://localhost:7051"); - testChannel.addPeer(peer, Channel.PeerOptions.create().setPeerRoles(Peer.PeerRole.NO_EVENT_SOURCE)); + testChannel.addPeer(peer, createPeerOptions().setPeerRoles(Peer.PeerRole.NO_EVENT_SOURCE)); Assert.assertFalse(testChannel.isInitialized()); testChannel.initialize(); Assert.assertTrue(testChannel.isInitialized()); diff --git a/src/test/java/org/hyperledger/fabric/sdk/PeerTest.java b/src/test/java/org/hyperledger/fabric/sdk/PeerTest.java index a16bc286..02658ca7 100644 --- a/src/test/java/org/hyperledger/fabric/sdk/PeerTest.java +++ b/src/test/java/org/hyperledger/fabric/sdk/PeerTest.java @@ -55,37 +55,37 @@ public void testGetName() { } - @Test(expected = InvalidArgumentException.class) + @Test (expected = InvalidArgumentException.class) public void testSetNullName() throws InvalidArgumentException { peer = hfclient.newPeer(null, "grpc://localhost:4"); Assert.fail("expected set null name to throw exception."); } - @Test(expected = InvalidArgumentException.class) + @Test (expected = InvalidArgumentException.class) public void testSetEmptyName() throws InvalidArgumentException { peer = hfclient.newPeer("", "grpc://localhost:4"); Assert.fail("expected set empty name to throw exception."); } - @Test(expected = PeerException.class) + @Test (expected = PeerException.class) public void testSendNullProposal() throws PeerException, InvalidArgumentException { peer.sendProposal(null); Assert.fail("Expected null proposal to throw exception."); } - @Test(expected = PeerException.class) + @Test (expected = PeerException.class) public void testSendNullChannel() throws InvalidArgumentException, PeerException { Peer badpeer = hfclient.newPeer("badpeer", "grpc://localhost:7051"); badpeer.sendProposal(FabricProposal.SignedProposal.newBuilder().build()); Assert.fail("Expected peer with no channel throw exception"); } - @Test(expected = PeerException.class) + @Test (expected = PeerException.class) public void testSendAsyncNullProposal() throws PeerException, InvalidArgumentException { peer.sendProposalAsync(null); } - @Test(expected = InvalidArgumentException.class) + @Test (expected = InvalidArgumentException.class) public void testBadURL() throws InvalidArgumentException { hfclient.newPeer(PEER_NAME, " "); Assert.fail("Expected peer with no channel throw exception"); diff --git a/src/test/java/org/hyperledger/fabric/sdk/testutils/TestConfig.java b/src/test/java/org/hyperledger/fabric/sdk/testutils/TestConfig.java index 4bdbc65f..0be2d72f 100644 --- a/src/test/java/org/hyperledger/fabric/sdk/testutils/TestConfig.java +++ b/src/test/java/org/hyperledger/fabric/sdk/testutils/TestConfig.java @@ -87,7 +87,7 @@ private TestConfig() { // Default values - defaultProperty(INVOKEWAITTIME, "100000"); + defaultProperty(INVOKEWAITTIME, "120"); defaultProperty(DEPLOYWAITTIME, "120000"); defaultProperty(PROPOSALWAITTIME, "120000"); diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java index dfbcbf41..8d5e65da 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endAndBackAgainIT.java @@ -15,7 +15,6 @@ package org.hyperledger.fabric.sdkintegration; import java.io.File; -import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; @@ -29,16 +28,16 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; import org.hyperledger.fabric.protos.common.Configtx; import org.hyperledger.fabric.protos.peer.Query.ChaincodeInfo; import org.hyperledger.fabric.sdk.BlockEvent; +import org.hyperledger.fabric.sdk.BlockInfo; import org.hyperledger.fabric.sdk.BlockchainInfo; import org.hyperledger.fabric.sdk.ChaincodeEndorsementPolicy; +import org.hyperledger.fabric.sdk.ChaincodeEvent; import org.hyperledger.fabric.sdk.ChaincodeID; import org.hyperledger.fabric.sdk.ChaincodeResponse.Status; import org.hyperledger.fabric.sdk.Channel; @@ -57,7 +56,6 @@ import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; import org.hyperledger.fabric.sdk.exception.ProposalException; import org.hyperledger.fabric.sdk.exception.TransactionEventException; -import org.hyperledger.fabric.sdk.exception.TransactionException; import org.hyperledger.fabric.sdk.security.CryptoSuite; import org.hyperledger.fabric.sdk.testutils.TestConfig; import org.hyperledger.fabric.sdk.testutils.TestUtils; @@ -67,6 +65,8 @@ import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hyperledger.fabric.sdk.BlockInfo.EnvelopeType.TRANSACTION_ENVELOPE; +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; @@ -236,17 +236,25 @@ public void setup() { // Now test replay feature of V1.1 peer eventing services. byte[] replayChannelBytes = barChannel.serializeChannel(); barChannel.shutdown(true); + Channel replayChannel = client.deSerializeChannel(replayChannelBytes); - testPeerServiceEventingReplay(client, replayChannel, 0L, -1L); + out("doing testPeerServiceEventingReplay,0,-1,false"); + testPeerServiceEventingReplay(client, replayChannel, 0L, -1L, false); + + replayChannel = client.deSerializeChannel(replayChannelBytes); + out("doing testPeerServiceEventingReplay,0,-1,true"); // block 0 is import to test + testPeerServiceEventingReplay(client, replayChannel, 0L, -1L, true); //Now do it again starting at block 1 replayChannel = client.deSerializeChannel(replayChannelBytes); - testPeerServiceEventingReplay(client, replayChannel, 1L, -1L); + out("doing testPeerServiceEventingReplay,1,-1,false"); + testPeerServiceEventingReplay(client, replayChannel, 1L, -1L, false); //Now do it again starting at block 2 to 3 replayChannel = client.deSerializeChannel(replayChannelBytes); - testPeerServiceEventingReplay(client, replayChannel, 2L, 3L); + out("doing testPeerServiceEventingReplay,2,3,false"); + testPeerServiceEventingReplay(client, replayChannel, 2L, 3L, false); } @@ -575,12 +583,21 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl testConfig.getOrdererProperties(ordererName))); } + boolean everyOther = false; + for (String peerName : sampleOrg.getPeerNames()) { String peerLocation = sampleOrg.getPeerLocation(peerName); Properties peerProperties = testConfig.getPeerProperties(peerName); Peer peer = client.newPeer(peerName, peerLocation, peerProperties); + final PeerOptions peerEventingOptions = // we have two peers on one use block on other use filtered + everyOther ? + createPeerOptions().registerEventsForBlocks() : + createPeerOptions().registerEventsForFilteredBlocks(); + newChannel.addPeer(peer, IS_FABRIC_V10 ? - PeerOptions.create().setPeerRoles(PeerRole.NO_EVENT_SOURCE) : PeerOptions.create()); + createPeerOptions().setPeerRoles(PeerRole.NO_EVENT_SOURCE) : peerEventingOptions); + + everyOther = !everyOther; } //For testing mix it up. For v1.1 use just peer eventing service for foo channel. @@ -684,23 +701,23 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl return newChannel; } + /** - * This code test the replay feature of the new peer event services. - * Instead of the default of starting the eventing peer to retrieve the newest block it sets it - * retrieve starting from the start parameter. * + *This code test the replay feature of the new peer event services. + * Instead of the default of starting the eventing peer to retrieve the newest block it sets it + * retrieve starting from the start parameter. Also checks with block and filterblock replays. + * Depends on end2end and end2endAndBackagain of have fully run to have the blocks need to work with. * @param client * @param replayTestChannel - * @throws IOException + * @param start + * @param stop + * @param useFilteredBlocks * @throws InvalidArgumentException - * @throws TransactionException - * @throws InterruptedException - * @throws ExecutionException - * @throws TimeoutException - * @throws ProposalException */ - void testPeerServiceEventingReplay(HFClient client, Channel replayTestChannel, final long start, final long stop) throws InvalidArgumentException, TransactionException, InterruptedException, ExecutionException, TimeoutException, ProposalException { + private void testPeerServiceEventingReplay(HFClient client, Channel replayTestChannel, final long start, final long stop, + final boolean useFilteredBlocks) throws InvalidArgumentException { if (testConfig.isRunningAgainstFabric10()) { return; // not supported for v1.0 @@ -724,16 +741,20 @@ void testPeerServiceEventingReplay(HFClient client, Channel replayTestChannel, f assertNotNull(client.getChannel(replayTestChannel.getName())); // should be known by client. + final PeerOptions eventingPeerOptions = createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.EVENT_SOURCE)); + if (useFilteredBlocks) { + eventingPeerOptions.registerEventsForFilteredBlocks(); + } + if (-1L == stop) { //the height of the blockchain - replayTestChannel.addPeer(eventingPeer, PeerOptions.create().setPeerRoles(EnumSet.of(PeerRole.EVENT_SOURCE)) - .startEvents(start)); // Eventing peer start getting blocks from block 0 + replayTestChannel.addPeer(eventingPeer, eventingPeerOptions.startEvents(start)); // Eventing peer start getting blocks from block 0 } else { - replayTestChannel.addPeer(eventingPeer, PeerOptions.create().setPeerRoles(EnumSet.of(PeerRole.EVENT_SOURCE)) + replayTestChannel.addPeer(eventingPeer, eventingPeerOptions .startEvents(start).stopEvents(stop)); // Eventing peer start getting blocks from block 0 - } - replayTestChannel.addPeer(ledgerPeer, PeerOptions.create().setPeerRoles(EnumSet.of(PeerRole.LEDGER_QUERY))); + //add a ledger peer + replayTestChannel.addPeer(ledgerPeer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.LEDGER_QUERY))); CompletableFuture done = new CompletableFuture<>(); // future to set when done. // some variable used by the block listener being set up. @@ -749,9 +770,13 @@ void testPeerServiceEventingReplay(HFClient client, Channel replayTestChannel, f final long blockNumber = blockEvent.getBlockNumber(); BlockEvent seen = blockEvents.put(blockNumber, blockEvent); assertNull(format("Block number %d seen twice", blockNumber), seen); + + assertTrue(format("Wrong type of block seen block number %d. expected filtered block %b but got %b", + blockNumber, useFilteredBlocks, blockEvent.isFiltered()), + useFilteredBlocks ? blockEvent.isFiltered() : !blockEvent.isFiltered()); final long count = bcount.getAndIncrement(); //count starts with 0 not 1 ! - out("Block count: %d, block number: %d received from peer: %s", count, blockNumber, blockEvent.getPeer().getName()); + //out("Block count: %d, block number: %d received from peer: %s", count, blockNumber, blockEvent.getPeer().getName()); if (count == 0 && stop == -1L) { final BlockchainInfo blockchainInfo = finalChannel.queryBlockchainInfo(); @@ -774,22 +799,85 @@ void testPeerServiceEventingReplay(HFClient client, Channel replayTestChannel, f } }); - replayTestChannel.initialize(); // start it all up. - done.get(30, TimeUnit.SECONDS); // give a timeout here. - Thread.sleep(1000); // sleep a little to see if more blocks trickle in .. they should not - replayTestChannel.unregisterBlockListener(blockListenerHandle); - final long expectNumber = stopValue.longValue() - start + 1L; // Start 2 and stop is 3 expect 2 + try { + replayTestChannel.initialize(); // start it all up. + done.get(30, TimeUnit.SECONDS); // give a timeout here. + Thread.sleep(1000); // sleep a little to see if more blocks trickle in .. they should not + replayTestChannel.unregisterBlockListener(blockListenerHandle); - assertEquals(format("Didn't get number we expected %d but got %d block events. Start: %d, end: %d, height: %d", - expectNumber, blockEvents.size(), start, stop, stopValue.longValue()), expectNumber, blockEvents.size()); + final long expectNumber = stopValue.longValue() - start + 1L; // Start 2 and stop is 3 expect 2 - for (long i = stopValue.longValue(); i >= start; i--) { //make sure all are there. - final BlockEvent blockEvent = blockEvents.get(i); - assertNotNull(format("Missing block event for block number %d. Start= %d", i, start), blockEvent); - } + assertEquals(format("Didn't get number we expected %d but got %d block events. Start: %d, end: %d, height: %d", + expectNumber, blockEvents.size(), start, stop, stopValue.longValue()), expectNumber, blockEvents.size()); + + for (long i = stopValue.longValue(); i >= start; i--) { //make sure all are there. + final BlockEvent blockEvent = blockEvents.get(i); + assertNotNull(format("Missing block event for block number %d. Start= %d", i, start), blockEvent); + } + + //light weight test just see if we get reasonable values for traversing the block. Test just whats common between + // Block and FilteredBlock. + + int transactionEventCounts = 0; + int chaincodeEventsCounts = 0; + + for (long i = stopValue.longValue(); i >= start; i--) { + + final BlockEvent blockEvent = blockEvents.get(i); +// out("blockwalker %b, start: %d, stop: %d, i: %d, block %d", useFilteredBlocks, start, stopValue.longValue(), i, blockEvent.getBlockNumber()); + assertEquals(useFilteredBlocks, blockEvent.isFiltered()); // check again + + if (useFilteredBlocks) { + assertNull(blockEvent.getBlock()); // should not have raw block event. + assertNotNull(blockEvent.getFilteredBlock()); // should have raw filtered block. + } else { + assertNotNull(blockEvent.getBlock()); // should not have raw block event. + assertNull(blockEvent.getFilteredBlock()); // should have raw filtered block. + } + + assertEquals(replayTestChannel.getName(), blockEvent.getChannelId()); + + for (BlockInfo.EnvelopeInfo envelopeInfo : blockEvent.getEnvelopeInfos()) { + if (envelopeInfo.getType() == TRANSACTION_ENVELOPE) { + + BlockInfo.TransactionEnvelopeInfo transactionEnvelopeInfo = (BlockInfo.TransactionEnvelopeInfo) envelopeInfo; + assertTrue(envelopeInfo.isValid()); // only have valid blocks. + assertEquals(envelopeInfo.getValidationCode(), 0); + + ++transactionEventCounts; + for (BlockInfo.TransactionEnvelopeInfo.TransactionActionInfo ta : transactionEnvelopeInfo.getTransactionActionInfos()) { + // out("\nTA:", ta + "\n\n"); + ChaincodeEvent event = ta.getEvent(); + if (event != null) { + assertNotNull(event.getChaincodeId()); + assertNotNull(event.getEventName()); + chaincodeEventsCounts++; + } + + } + + } else { + assertEquals("Only non transaction block should be block 0.", blockEvent.getBlockNumber(), 0); - replayTestChannel.shutdown(true); //all done. + } + + } + + } + + assertTrue(transactionEventCounts > 0); + + if (expectNumber > 4) { // this should be enough blocks with CC events. + + assertTrue(chaincodeEventsCounts > 0); + } + + replayTestChannel.shutdown(true); //all done. + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } } private void queryChaincodeForExpectedValue(HFClient client, Channel channel, final String expect, ChaincodeID chaincodeID) { diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java index ca637d18..118b3e2b 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java @@ -39,7 +39,6 @@ import org.hyperledger.fabric.sdk.ChaincodeEvent; import org.hyperledger.fabric.sdk.ChaincodeID; import org.hyperledger.fabric.sdk.Channel; -import org.hyperledger.fabric.sdk.Channel.PeerOptions; import org.hyperledger.fabric.sdk.ChannelConfiguration; import org.hyperledger.fabric.sdk.EventHub; import org.hyperledger.fabric.sdk.HFClient; @@ -70,6 +69,7 @@ import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static org.hyperledger.fabric.sdk.BlockInfo.EnvelopeType.TRANSACTION_ENVELOPE; +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; @@ -726,9 +726,10 @@ private Channel constructChannel(String name, HFClient client, SampleOrg sampleO Peer peer = client.newPeer(peerName, peerLocation, peerProperties); if (doPeerEventing && everyother) { - newChannel.joinPeer(peer); //Default is all roles. + newChannel.joinPeer(peer, createPeerOptions()); //Default is all roles. } else { - newChannel.joinPeer(peer, PeerOptions.create().setPeerRoles(PeerRole.NO_EVENT_SOURCE)); + // Set peer to not be all roles but eventing. + newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(PeerRole.NO_EVENT_SOURCE)); } out("Peer %s joined channel %s", peerName, name); everyother = !everyother; diff --git a/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java b/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java index 8bbb453d..e3505097 100644 --- a/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java +++ b/src/test/java/org/hyperledger/fabric/sdkintegration/UpdateChannelIT.java @@ -35,7 +35,6 @@ import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.hyperledger.fabric.sdk.Channel; -import org.hyperledger.fabric.sdk.Channel.PeerOptions; import org.hyperledger.fabric.sdk.EventHub; import org.hyperledger.fabric.sdk.HFClient; import org.hyperledger.fabric.sdk.Peer; @@ -47,6 +46,7 @@ import org.junit.Test; import static java.lang.String.format; +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.fail; @@ -242,7 +242,7 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl throw new AssertionError(format("Peer %s does not appear to belong to channel %s", peerName, name)); } - newChannel.addPeer(peer, PeerOptions.create().setPeerRoles(EnumSet.of(Peer.PeerRole.CHAINCODE_QUERY, + newChannel.addPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.CHAINCODE_QUERY, Peer.PeerRole.ENDORSING_PEER, Peer.PeerRole.LEDGER_QUERY))); } diff --git a/src/test/java/org/hyperledger/fabric_ca/sdkintegration/HFCAClientIT.java b/src/test/java/org/hyperledger/fabric_ca/sdkintegration/HFCAClientIT.java index 42bce0fb..f5097920 100644 --- a/src/test/java/org/hyperledger/fabric_ca/sdkintegration/HFCAClientIT.java +++ b/src/test/java/org/hyperledger/fabric_ca/sdkintegration/HFCAClientIT.java @@ -55,6 +55,7 @@ import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static org.hyperledger.fabric.sdk.testutils.TestUtils.resetConfig; +import static org.hyperledger.fabric_ca.sdk.HFCAClient.DEFAULT_PROFILE_NAME; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -278,7 +279,7 @@ public void testReenrollAndRevoke() throws Exception { sleepALittle(); // get another enrollment - EnrollmentRequest req = new EnrollmentRequest("profile 1", "label 1", null); + EnrollmentRequest req = new EnrollmentRequest(DEFAULT_PROFILE_NAME, "label 1", null); req.addHost("example1.ibm.com"); req.addHost("example2.ibm.com"); Enrollment tmpEnroll = client.reenroll(user, req); @@ -322,7 +323,7 @@ public void testUserRevoke() throws Exception { } if (!user.isEnrolled()) { - EnrollmentRequest req = new EnrollmentRequest("profile 2", "label 2", null); + EnrollmentRequest req = new EnrollmentRequest(DEFAULT_PROFILE_NAME, "label 2", null); req.addHost("example3.ibm.com"); user.setEnrollment(client.enroll(user.getName(), user.getEnrollmentSecret(), req)); @@ -384,7 +385,7 @@ public void testUserRevokeNullReason() throws Exception { sleepALittle(); if (!user.isEnrolled()) { - EnrollmentRequest req = new EnrollmentRequest("profile 2", "label 2", null); + EnrollmentRequest req = new EnrollmentRequest(DEFAULT_PROFILE_NAME, "label 2", null); req.addHost("example3.ibm.com"); user.setEnrollment(client.enroll(user.getName(), user.getEnrollmentSecret(), req)); @@ -450,7 +451,7 @@ public void testUserRevokeGenCRL() throws Exception { sleepALittle(); if (!user.isEnrolled()) { - EnrollmentRequest req = new EnrollmentRequest("profile 2", "label 2", null); + EnrollmentRequest req = new EnrollmentRequest(DEFAULT_PROFILE_NAME, "label 2", null); req.addHost("example3.ibm.com"); user.setEnrollment(client.enroll(user.getName(), user.getEnrollmentSecret(), req)); @@ -512,7 +513,7 @@ public void testEnrollNoKeyPair() throws Exception { SampleUser user = getEnrolledUser(TEST_ADMIN_ORG); - EnrollmentRequest req = new EnrollmentRequest("profile 1", "label 1", null); + EnrollmentRequest req = new EnrollmentRequest(DEFAULT_PROFILE_NAME, "label 1", null); req.setCsr("test"); client.enroll(user.getName(), user.getEnrollmentSecret(), req); }