Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
<dependency>
<groupId>org.hyperledger.fabric-sdk-java</groupId>
<artifactId>fabric-sdk-java</artifactId>
<version>2.1.1</version>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/hyperledger/fabric/gateway/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.hyperledger.fabric.gateway.spi.CommitHandlerFactory;
import org.hyperledger.fabric.sdk.Peer;

/**
Expand All @@ -31,6 +32,17 @@ public interface Transaction {
*/
String getName();

/**
* Get the transaction ID that will be used when submitting this transaction. This can be useful for:
* <ul>
* <li>Asynchronously listening for commit events for this transaction when using the
* {@link DefaultCommitHandlers#NONE} commit handler.</li>
* <li>Correlating client application operations with activity in Fabric peers and orderers.</li>
* </ul>
* @return A transaction ID.
*/
String getTransactionId();

/**
* Set transient data that will be passed to the transaction function
* but will not be stored on the ledger. This can be used to pass
Expand All @@ -49,6 +61,14 @@ public interface Transaction {
*/
Transaction setCommitTimeout(long timeout, TimeUnit timeUnit);

/**
* Set the commit handler to use for this transaction invocation instead of the default handler configured for the
* gateway.
* @param commitHandler A commit handler implementation.
* @return this transaction object to allow method chaining.
*/
Transaction setCommitHandler(CommitHandlerFactory commitHandler);

/**
* Set the peers that should be used for endorsement of transaction submitted to the ledger using
* {@link #submit(String...)}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.exception.ServiceDiscoveryException;
import org.hyperledger.fabric.sdk.transaction.TransactionContext;

import static org.hyperledger.fabric.sdk.Channel.DiscoveryOptions.createDiscoveryOptions;

Expand All @@ -47,11 +48,12 @@ public final class TransactionImpl implements Transaction {
private final NetworkImpl network;
private final Channel channel;
private final GatewayImpl gateway;
private final CommitHandlerFactory commitHandlerFactory;
private CommitHandlerFactory commitHandlerFactory;
private TimePeriod commitTimeout;
private final QueryHandler queryHandler;
private Map<String, byte[]> transientData = null;
private Collection<Peer> endorsingPeers = null;
private final TransactionContext transactionContext;

TransactionImpl(final ContractImpl contract, final String name) {
this.contract = contract;
Expand All @@ -62,13 +64,19 @@ public final class TransactionImpl implements Transaction {
commitHandlerFactory = gateway.getCommitHandlerFactory();
commitTimeout = gateway.getCommitTimeout();
queryHandler = network.getQueryHandler();
transactionContext = channel.newTransactionContext();
}

@Override
public String getName() {
return name;
}

@Override
public String getTransactionId() {
return transactionContext.getTxID();
}

@Override
public Transaction setTransient(final Map<String, byte[]> transientData) {
this.transientData = transientData;
Expand All @@ -81,6 +89,12 @@ public Transaction setCommitTimeout(final long timeout, final TimeUnit timeUnit)
return this;
}

@Override
public Transaction setCommitHandler(final CommitHandlerFactory commitHandler) {
commitHandlerFactory = commitHandler;
return this;
}

@Override
public Transaction setEndorsingPeers(final Collection<Peer> peers) {
endorsingPeers = peers;
Expand Down Expand Up @@ -116,8 +130,7 @@ private Collection<ProposalResponse> sendTransactionProposal(final TransactionPr
} else if (network.getGateway().isDiscoveryEnabled()) {
Channel.DiscoveryOptions discoveryOptions = createDiscoveryOptions()
.setEndorsementSelector(ServiceDiscovery.EndorsementSelector.ENDORSEMENT_SELECTION_RANDOM)
.setInspectResults(true)
.setForceDiscovery(true);
.setInspectResults(true);
return channel.sendTransactionProposalToEndorsers(request, discoveryOptions);
} else {
return channel.sendTransactionProposal(request);
Expand All @@ -127,9 +140,8 @@ private Collection<ProposalResponse> sendTransactionProposal(final TransactionPr
private byte[] commitTransaction(final Collection<ProposalResponse> validResponses)
throws TimeoutException, ContractException, InterruptedException {
ProposalResponse proposalResponse = validResponses.iterator().next();
String transactionId = proposalResponse.getTransactionID();

CommitHandler commitHandler = commitHandlerFactory.create(transactionId, network);
CommitHandler commitHandler = commitHandlerFactory.create(getTransactionId(), network);
commitHandler.startListening();

try {
Expand Down Expand Up @@ -172,6 +184,7 @@ private void configureRequest(final TransactionRequest request, final String...
request.setChaincodeName(contract.getChaincodeId());
request.setFcn(name);
request.setArgs(args);
request.setTransactionContext(transactionContext);
}

private Collection<ProposalResponse> validatePeerResponses(final Collection<ProposalResponse> proposalResponses)
Expand Down
32 changes: 28 additions & 4 deletions src/test/java/org/hyperledger/fabric/gateway/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

import org.bouncycastle.operator.OperatorCreationException;
import org.hyperledger.fabric.gateway.impl.GatewayImpl;
import org.hyperledger.fabric.gateway.impl.identity.GatewayUser;
import org.hyperledger.fabric.gateway.spi.PeerDisconnectEvent;
Expand All @@ -34,10 +31,13 @@
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.ProposalResponse;
import org.hyperledger.fabric.sdk.QueryByChaincodeRequest;
import org.hyperledger.fabric.sdk.TransactionProposalRequest;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ServiceDiscoveryException;
import org.hyperledger.fabric.sdk.identity.X509Enrollment;
import org.hyperledger.fabric.sdk.transaction.TransactionContext;
import org.mockito.Mockito;

public final class TestUtils {
Expand All @@ -46,6 +46,8 @@ public final class TestUtils {
private static final String UNUSED_FILE_PREFIX = "fgj-unused-";
private static final Path NETWORK_CONFIG_PATH = Paths.get("src", "test", "java", "org", "hyperledger", "fabric", "gateway", "connection.json");

private final AtomicLong currentTransactionId = new AtomicLong();

public static TestUtils getInstance() {
return INSTANCE;
}
Expand Down Expand Up @@ -79,6 +81,8 @@ public HFClient newMockClient() {

HFClient mockClient = Mockito.mock(HFClient.class);
Mockito.when(mockClient.getUserContext()).thenReturn(user);
Mockito.when(mockClient.newTransactionProposalRequest()).thenReturn(TransactionProposalRequest.newInstance(user));
Mockito.when(mockClient.newQueryProposalRequest()).thenReturn(QueryByChaincodeRequest.newInstance(user));

return mockClient;
}
Expand All @@ -100,6 +104,8 @@ public Peer newMockPeer(String name) {
public Channel newMockChannel(String name) {
Channel mockChannel = Mockito.mock(Channel.class);
Mockito.when(mockChannel.getName()).thenReturn(name);
Mockito.when(mockChannel.newTransactionContext())
.thenAnswer(invocation -> newMockTransactionContext());

AtomicReference<Channel.SDPeerAddition> sdPeerAdditionRef = new AtomicReference<>(newMockSDPeerAddition());
Mockito.when(mockChannel.getSDPeerAddition())
Expand All @@ -110,6 +116,16 @@ public Channel newMockChannel(String name) {
return mockChannel;
}

private TransactionContext newMockTransactionContext() {
TransactionContext mockContext = Mockito.mock(TransactionContext.class);
Mockito.when(mockContext.getTxID()).thenReturn(newFakeTransactionId());
return mockContext;
}

private String newFakeTransactionId() {
return Long.toHexString(currentTransactionId.incrementAndGet());
}

private Channel.SDPeerAddition newMockSDPeerAddition() {
Channel.SDPeerAddition mockPeerAddition = Mockito.mock(Channel.SDPeerAddition.class);
try {
Expand Down Expand Up @@ -166,6 +182,14 @@ public Throwable getCause() {
};
}

public ProposalResponse newSuccessfulProposalResponse() {
return newSuccessfulProposalResponse(new byte[0]);
}

public ProposalResponse newSuccessfulProposalResponse(String responsePayload) {
return newSuccessfulProposalResponse(responsePayload.getBytes());
}

public ProposalResponse newSuccessfulProposalResponse(byte[] responsePayload) {
ProposalResponse response = newProposalResponse(200, responsePayload);
Mockito.when(response.getStatus()).thenReturn(ChaincodeResponse.Status.SUCCESS);
Expand Down
Loading