package org.hyperledger.fabric.sdkintegration;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Hex;
import org.hyperledger.fabric.protos.ledger.rwset.kvrwset.KvRwset;
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.ChaincodeID;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.ChannelConfiguration;
import org.hyperledger.fabric.sdk.EventHub;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.InstallProposalRequest;
import org.hyperledger.fabric.sdk.InstantiateProposalRequest;
import org.hyperledger.fabric.sdk.Orderer;
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.TransactionInfo;
import org.hyperledger.fabric.sdk.TransactionProposalRequest;
import org.hyperledger.fabric.sdk.TxReadWriteSetInfo;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.InvalidProtocolBufferRuntimeException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.exception.TransactionEventException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
import org.hyperledger.fabric.sdk.testutils.TestConfig;
import org.hyperledger.fabric_ca.sdk.HFCAClient;
import org.hyperledger.fabric_ca.sdk.RegistrationRequest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
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.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class End2endIT {
private static final TestConfig testConfig = TestConfig.getConfig();
private static final String TEST_ADMIN_NAME = "admin";
private static final String TESTUSER_1_NAME = "user1";
private static final String TEST_FIXTURES_PATH = "src/test/fixture";
private static final String CHAIN_CODE_NAME = "example_cc_go";
private static final String CHAIN_CODE_PATH = "github.com/example_cc";
private static final String CHAIN_CODE_VERSION = "1";
private static final String FOO_CHANNEL_NAME = "foo";
private static final String BAR_CHANNEL_NAME = "bar";
String testTxID = null;
private final TestConfigHelper configHelper = new TestConfigHelper();
private Collection testSampleOrgs;
@Before
public void checkConfig() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, MalformedURLException {
out("\n\n\nRUNNING: End2endIT.\n");
configHelper.clearConfig();
configHelper.customizeConfig();
testSampleOrgs = testConfig.getIntegrationTestsSampleOrgs();
for (SampleOrg sampleOrg : testSampleOrgs) {
sampleOrg.setCAClient(HFCAClient.createNewInstance(sampleOrg.getCALocation(), sampleOrg.getCAProperties()));
}
}
@After
public void clearConfig() {
try {
configHelper.clearConfig();
} catch (Exception e) {
}
}
@Test
public void setup() {
try {
HFClient client = HFClient.createNewInstance();
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
File sampleStoreFile = new File(System.getProperty("java.io.tmpdir") + "/HFCSampletest.properties");
if (sampleStoreFile.exists()) {
sampleStoreFile.delete();
}
final SampleStore sampleStore = new SampleStore(sampleStoreFile);
for (SampleOrg sampleOrg : testSampleOrgs) {
HFCAClient ca = sampleOrg.getCAClient();
final String orgName = sampleOrg.getName();
final String mspid = sampleOrg.getMSPID();
ca.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
SampleUser admin = sampleStore.getMember(TEST_ADMIN_NAME, orgName);
if (!admin.isEnrolled()) {
admin.setEnrollment(ca.enroll(admin.getName(), "adminpw"));
admin.setMspId(mspid);
}
sampleOrg.setAdmin(admin);
SampleUser user = sampleStore.getMember(TESTUSER_1_NAME, sampleOrg.getName());
if (!user.isRegistered()) {
RegistrationRequest rr = new RegistrationRequest(user.getName(), "org1.department1");
user.setEnrollmentSecret(ca.register(rr, admin));
}
if (!user.isEnrolled()) {
user.setEnrollment(ca.enroll(user.getName(), user.getEnrollmentSecret()));
user.setMspId(mspid);
}
sampleOrg.addUser(user);
final String sampleOrgName = sampleOrg.getName();
final String sampleOrgDomainName = sampleOrg.getDomainName();
SampleUser peerOrgAdmin = sampleStore.getMember(sampleOrgName + "Admin", sampleOrgName, sampleOrg.getMSPID(),
findFileSk(Paths.get(testConfig.getTestChannlePath(), "crypto-config/peerOrganizations/",
sampleOrgDomainName, format("/users/Admin@%s/msp/keystore", sampleOrgDomainName)).toFile()),
Paths.get(testConfig.getTestChannlePath(), "crypto-config/peerOrganizations/", sampleOrgDomainName,
format("/users/Admin@%s/msp/signcerts/Admin@%s-cert.pem", sampleOrgDomainName, sampleOrgDomainName)).toFile());
sampleOrg.setPeerAdmin(peerOrgAdmin);
}
SampleOrg sampleOrg = testConfig.getIntegrationTestsSampleOrg("peerOrg1");
Channel fooChannel = constructChannel(FOO_CHANNEL_NAME, client, sampleOrg);
runChannel(client, fooChannel, true, sampleOrg, 0);
fooChannel.shutdown(true);
out("\n");
sampleOrg = testConfig.getIntegrationTestsSampleOrg("peerOrg2");
Channel barChannel = constructChannel(BAR_CHANNEL_NAME, client, sampleOrg);
runChannel(client, barChannel, true, sampleOrg, 100);
out("\nTraverse the blocks for chain %s ", barChannel.getName());
blockWalker(barChannel);
out("That's all folks!");
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
void runChannel(HFClient client, Channel channel, boolean installChaincode, SampleOrg sampleOrg, int delta) {
try {
final String channelName = channel.getName();
boolean isFooChain = FOO_CHANNEL_NAME.equals(channelName);
out("Running channel %s", channelName);
channel.setTransactionWaitTime(testConfig.getTransactionWaitTime());
channel.setDeployWaitTime(testConfig.getDeployWaitTime());
Collection channelPeers = channel.getPeers();
Collection orderers = channel.getOrderers();
final ChaincodeID chaincodeID;
Collection responses;
Collection successful = new LinkedList<>();
Collection failed = new LinkedList<>();
chaincodeID = ChaincodeID.newBuilder().setName(CHAIN_CODE_NAME)
.setVersion(CHAIN_CODE_VERSION)
.setPath(CHAIN_CODE_PATH).build();
if (installChaincode) {
client.setUserContext(sampleOrg.getPeerAdmin());
out("Creating install proposal");
InstallProposalRequest installProposalRequest = client.newInstallProposalRequest();
installProposalRequest.setChaincodeID(chaincodeID);
if (isFooChain) {
installProposalRequest.setChaincodeSourceLocation(new File(TEST_FIXTURES_PATH + "/sdkintegration/gocc/sample1"));
} else {
installProposalRequest.setChaincodeInputStream(Util.generateTarGzInputStream(
(Paths.get(TEST_FIXTURES_PATH, "/sdkintegration/gocc/sample1", "src", CHAIN_CODE_PATH).toFile()),
Paths.get("src", CHAIN_CODE_PATH).toString()));
}
installProposalRequest.setChaincodeVersion(CHAIN_CODE_VERSION);
out("Sending install proposal");
int numInstallProposal = 0;
Set peersFromOrg = sampleOrg.getPeers();
numInstallProposal = numInstallProposal + peersFromOrg.size();
responses = client.sendInstallProposal(installProposalRequest, peersFromOrg);
for (ProposalResponse response : responses) {
if (response.getStatus() == ProposalResponse.Status.SUCCESS) {
out("Successful install proposal response Txid: %s from peer %s", response.getTransactionID(), response.getPeer().getName());
successful.add(response);
} else {
failed.add(response);
}
}
SDKUtils.getProposalConsistencySets(responses);
out("Received %d install proposal responses. Successful+verified: %d . Failed: %d", numInstallProposal, successful.size(), failed.size());
if (failed.size() > 0) {
ProposalResponse first = failed.iterator().next();
fail("Not enough endorsers for install :" + successful.size() + ". " + first.getMessage());
}
}
InstantiateProposalRequest instantiateProposalRequest = client.newInstantiationProposalRequest();
instantiateProposalRequest.setProposalWaitTime(testConfig.getProposalWaitTime());
instantiateProposalRequest.setChaincodeID(chaincodeID);
instantiateProposalRequest.setFcn("init");
instantiateProposalRequest.setArgs(new String[] {"a", "500", "b", "" + (200 + delta)});
Mapbyte[]> tm = new HashMap<>();
tm.put("HyperLedgerFabric", "InstantiateProposalRequest:JavaSDK".getBytes(UTF_8));
tm.put("method", "InstantiateProposalRequest".getBytes(UTF_8));
instantiateProposalRequest.setTransientMap(tm);
ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy();
chaincodeEndorsementPolicy.fromYamlFile(new File(TEST_FIXTURES_PATH + "/sdkintegration/chaincodeendorsementpolicy.yaml"));
instantiateProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);
out("Sending instantiateProposalRequest to all peers with arguments: a and b set to 100 and %s respectively", "" + (200 + delta));
successful.clear();
failed.clear();
if (isFooChain) {
responses = channel.sendInstantiationProposal(instantiateProposalRequest, channel.getPeers());
} else {
responses = channel.sendInstantiationProposal(instantiateProposalRequest);
}
for (ProposalResponse response : responses) {
if (response.isVerified() && response.getStatus() == ProposalResponse.Status.SUCCESS) {
successful.add(response);
out("Succesful instantiate proposal response Txid: %s from peer %s", response.getTransactionID(), response.getPeer().getName());
} else {
failed.add(response);
}
}
out("Received %d instantiate proposal responses. Successful+verified: %d . Failed: %d", responses.size(), successful.size(), failed.size());
if (failed.size() > 0) {
ProposalResponse first = failed.iterator().next();
fail("Not enough endorsers for instantiate :" + successful.size() + "endorser failed with " + first.getMessage() + ". Was verified:" + first.isVerified());
}
out("Sending instantiateTransaction to orderer with a and b set to 100 and %s respectively", "" + (200 + delta));
channel.sendTransaction(successful, orderers).thenApply(transactionEvent -> {
waitOnFabric(0);
assertTrue(transactionEvent.isValid());
out("Finished instantiate transaction with transaction id %s", transactionEvent.getTransactionID());
try {
successful.clear();
failed.clear();
client.setUserContext(sampleOrg.getUser(TESTUSER_1_NAME));
TransactionProposalRequest transactionProposalRequest = client.newTransactionProposalRequest();
transactionProposalRequest.setChaincodeID(chaincodeID);
transactionProposalRequest.setFcn("invoke");
transactionProposalRequest.setProposalWaitTime(testConfig.getProposalWaitTime());
transactionProposalRequest.setArgs(new String[] {"move", "a", "b", "100"});
Mapbyte[]> tm2 = new HashMap<>();
tm2.put("HyperLedgerFabric", "TransactionProposalRequest:JavaSDK".getBytes(UTF_8));
tm2.put("method", "TransactionProposalRequest".getBytes(UTF_8));
tm2.put("result", ":)".getBytes(UTF_8));
transactionProposalRequest.setTransientMap(tm2);
out("sending transactionProposal to all peers with arguments: move(a,b,100)");
Collection transactionPropResp = channel.sendTransactionProposal(transactionProposalRequest, channel.getPeers());
for (ProposalResponse response : transactionPropResp) {
if (response.getStatus() == ProposalResponse.Status.SUCCESS) {
out("Successful transaction proposal response Txid: %s from peer %s", response.getTransactionID(), response.getPeer().getName());
successful.add(response);
} else {
failed.add(response);
}
}
Collection> proposalConsistencySets = SDKUtils.getProposalConsistencySets(transactionPropResp);
if (proposalConsistencySets.size() != 1) {
fail(format("Expected only one set of consistent proposal responses but got %d", proposalConsistencySets.size()));
}
out("Received %d transaction proposal responses. Successful+verified: %d . Failed: %d",
transactionPropResp.size(), successful.size(), failed.size());
if (failed.size() > 0) {
ProposalResponse firstTransactionProposalResponse = failed.iterator().next();
fail("Not enough endorsers for invoke(move a,b,100):" + failed.size() + " endorser error: " +
firstTransactionProposalResponse.getMessage() +
". Was verified: " + firstTransactionProposalResponse.isVerified());
}
out("Successfully received transaction proposal responses.");
ProposalResponse resp = transactionPropResp.iterator().next();
byte[] x = resp.getChaincodeActionResponsePayload();
String resultAsString = null;
if (x != null) {
resultAsString = new String(x, "UTF-8");
}
assertEquals(":)", resultAsString);
assertEquals(200, resp.getChaincodeActionResponseStatus());
TxReadWriteSetInfo readWriteSetInfo = resp.getChaincodeActionResponseReadWriteSetInfo();
assertNotNull(readWriteSetInfo);
assertTrue(readWriteSetInfo.getNsRwsetCount() > 0);
ChaincodeID cid = resp.getChaincodeID();
assertNotNull(cid);
assertEquals(CHAIN_CODE_PATH, cid.getPath());
assertEquals(CHAIN_CODE_NAME, cid.getName());
assertEquals(CHAIN_CODE_VERSION, cid.getVersion());
out("Sending chaincode transaction(move a,b,100) to orderer.");
return channel.sendTransaction(successful).get(testConfig.getTransactionWaitTime(), TimeUnit.SECONDS);
} catch (Exception e) {
out("Caught an exception while invoking chaincode");
e.printStackTrace();
fail("Failed invoking chaincode with error : " + e.getMessage());
}
return null;
}).thenApply(transactionEvent -> {
try {
waitOnFabric(0);
assertTrue(transactionEvent.isValid());
out("Finished transaction with transaction id %s", transactionEvent.getTransactionID());
testTxID = transactionEvent.getTransactionID();
String expect = "" + (300 + delta);
out("Now query chaincode for the value of b.");
QueryByChaincodeRequest queryByChaincodeRequest = client.newQueryProposalRequest();
queryByChaincodeRequest.setArgs(new String[] {"query", "b"});
queryByChaincodeRequest.setFcn("invoke");
queryByChaincodeRequest.setChaincodeID(chaincodeID);
Mapbyte[]> tm2 = new HashMap<>();
tm2.put("HyperLedgerFabric", "QueryByChaincodeRequest:JavaSDK".getBytes(UTF_8));
tm2.put("method", "QueryByChaincodeRequest".getBytes(UTF_8));
queryByChaincodeRequest.setTransientMap(tm2);
Collection queryProposals = channel.queryByChaincode(queryByChaincodeRequest, channel.getPeers());
for (ProposalResponse proposalResponse : queryProposals) {
if (!proposalResponse.isVerified() || proposalResponse.getStatus() != ProposalResponse.Status.SUCCESS) {
fail("Failed query proposal from peer " + proposalResponse.getPeer().getName() + " status: " + proposalResponse.getStatus() +
". Messages: " + proposalResponse.getMessage()
+ ". Was verified : " + proposalResponse.isVerified());
} else {
String payload = proposalResponse.getProposalResponse().getResponse().getPayload().toStringUtf8();
out("Query payload of b from peer %s returned %s", proposalResponse.getPeer().getName(), payload);
assertEquals(payload, expect);
}
}
return null;
} catch (Exception e) {
out("Caught exception while running query");
e.printStackTrace();
fail("Failed during chaincode query with error : " + e.getMessage());
}
return null;
}).exceptionally(e -> {
if (e instanceof TransactionEventException) {
BlockEvent.TransactionEvent te = ((TransactionEventException) e).getTransactionEvent();
if (te != null) {
fail(format("Transaction with txid %s failed. %s", te.getTransactionID(), e.getMessage()));
}
}
fail(format("Test failed with %s exception %s", e.getClass().getName(), e.getMessage()));
return null;
}).get(testConfig.getTransactionWaitTime(), TimeUnit.SECONDS);
Set peerSet = sampleOrg.getPeers();
BlockchainInfo channelInfo = channel.queryBlockchainInfo();
out("Channel info for : " + channelName);
out("Channel height: " + channelInfo.getHeight());
String chainCurrentHash = Hex.encodeHexString(channelInfo.getCurrentBlockHash());
String chainPreviousHash = Hex.encodeHexString(channelInfo.getPreviousBlockHash());
out("Chain current block hash: " + chainCurrentHash);
out("Chainl previous block hash: " + chainPreviousHash);
BlockInfo returnedBlock = channel.queryBlockByNumber(channelInfo.getHeight() - 1);
String previousHash = Hex.encodeHexString(returnedBlock.getPreviousHash());
out("queryBlockByNumber returned correct block with blockNumber " + returnedBlock.getBlockNumber()
+ " \n previous_hash " + previousHash);
assertEquals(channelInfo.getHeight() - 1, returnedBlock.getBlockNumber());
assertEquals(chainPreviousHash, previousHash);
byte[] hashQuery = returnedBlock.getPreviousHash();
returnedBlock = channel.queryBlockByHash(hashQuery);
out("queryBlockByHash returned block with blockNumber " + returnedBlock.getBlockNumber());
assertEquals(channelInfo.getHeight() - 2, returnedBlock.getBlockNumber());
returnedBlock = channel.queryBlockByTransactionID(testTxID);
out("queryBlockByTxID returned block with blockNumber " + returnedBlock.getBlockNumber());
assertEquals(channelInfo.getHeight() - 1, returnedBlock.getBlockNumber());
TransactionInfo txInfo = channel.queryTransactionByID(testTxID);
out("QueryTransactionByID returned TransactionInfo: txID " + txInfo.getTransactionID()
+ "\n validation code " + txInfo.getValidationCode().getNumber());
out("Running for Channel %s done", channelName);
} catch (Exception e) {
out("Caught an exception running channel %s", channel.getName());
e.printStackTrace();
fail("Test failed with error : " + e.getMessage());
}
}
private Channel constructChannel(String name, HFClient client, SampleOrg sampleOrg) throws Exception {
out("Constructing channel %s", name);
client.setUserContext(sampleOrg.getPeerAdmin());
Collection orderers = new LinkedList<>();
for (String orderName : sampleOrg.getOrdererNames()) {
Properties ordererProperties = testConfig.getOrdererProperties(orderName);
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] {5L, TimeUnit.MINUTES});
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});
orderers.add(client.newOrderer(orderName, sampleOrg.getOrdererLocation(orderName),
ordererProperties));
}
Orderer anOrderer = orderers.iterator().next();
orderers.remove(anOrderer);
ChannelConfiguration channelConfiguration = new ChannelConfiguration(new File(TEST_FIXTURES_PATH + "/sdkintegration/e2e-2Orgs/channel/" + name + ".tx"));
Channel newChannel = client.newChannel(name, anOrderer, channelConfiguration, client.getChannelConfigurationSignature(channelConfiguration, sampleOrg.getPeerAdmin()));
out("Created channel %s", name);
for (String peerName : sampleOrg.getPeerNames()) {
String peerLocation = sampleOrg.getPeerLocation(peerName);
Properties peerProperties = testConfig.getPeerProperties(peerName);
if (peerProperties == null) {
peerProperties = new Properties();
}
peerProperties.put("grpc.NettyChannelBuilderOption.maxInboundMessageSize", 9000000);
Peer peer = client.newPeer(peerName, peerLocation, peerProperties);
newChannel.joinPeer(peer);
out("Peer %s joined channel %s", peerName, name);
sampleOrg.addPeer(peer);
}
for (Orderer orderer : orderers) {
newChannel.addOrderer(orderer);
}
for (String eventHubName : sampleOrg.getEventHubNames()) {
final Properties eventHubProperties = testConfig.getEventHubProperties(eventHubName);
eventHubProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] {5L, TimeUnit.MINUTES});
eventHubProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});
EventHub eventHub = client.newEventHub(eventHubName, sampleOrg.getEventHubLocation(eventHubName),
eventHubProperties);
newChannel.addEventHub(eventHub);
}
newChannel.initialize();
out("Finished initialization channel %s", name);
return newChannel;
}
static void out(String format, Object... args) {
System.err.flush();
System.out.flush();
System.out.println(format(format, args));
System.err.flush();
System.out.flush();
}
private void waitOnFabric(int additional) {
}
File findFileSk(File directory) {
File[] matches = directory.listFiles((dir, name) -> name.endsWith("_sk"));
if (null == matches) {
throw new RuntimeException(format("Matches returned null does %s directory exist?", directory.getAbsoluteFile().getName()));
}
if (matches.length != 1) {
throw new RuntimeException(format("Expected in %s only 1 sk file but found %d", directory.getAbsoluteFile().getName(), matches.length));
}
return matches[0];
}
private static final Map TX_EXPECTED;
static {
TX_EXPECTED = new HashMap<>();
TX_EXPECTED.put("readset1", "Missing readset for channel bar block 1");
TX_EXPECTED.put("writeset1", "Missing writeset for channel bar block 1");
}
void blockWalker(Channel channel) throws InvalidArgumentException, ProposalException, IOException {
try {
BlockchainInfo channelInfo = channel.queryBlockchainInfo();
for (long current = channelInfo.getHeight() - 1; current > -1; --current) {
BlockInfo returnedBlock = channel.queryBlockByNumber(current);
final long blockNumber = returnedBlock.getBlockNumber();
out("current block number %d has data hash: %s", blockNumber, Hex.encodeHexString(returnedBlock.getDataHash()));
out("current block number %d has previous hash id: %s", blockNumber, Hex.encodeHexString(returnedBlock.getPreviousHash()));
out("current block number %d has calculated block hash is %s", blockNumber, Hex.encodeHexString(SDKUtils.calculateBlockHash(blockNumber, returnedBlock.getPreviousHash(), returnedBlock.getDataHash())));
final int envelopCount = returnedBlock.getEnvelopCount();
assertEquals(1, envelopCount);
out("current block number %d has %d envelope count:", blockNumber, returnedBlock.getEnvelopCount());
int i = 0;
for (BlockInfo.EnvelopeInfo envelopeInfo : returnedBlock.getEnvelopeInfos()) {
++i;
out(" Transaction number %d has transaction id: %s", i, envelopeInfo.getTransactionID());
final String channelId = envelopeInfo.getChannelId();
assertTrue("foo".equals(channelId) || "bar".equals(channelId));
out(" Transaction number %d has channel id: %s", i, channelId);
out(" Transaction number %d has epoch: %d", i, envelopeInfo.getEpoch());
out(" Transaction number %d has transaction timestamp: %tB %, i, envelopeInfo.getTimestamp());
out(" Transaction number %d has type id: %s", i, "" + envelopeInfo.getType());
if (envelopeInfo.getType() == TRANSACTION_ENVELOPE) {
BlockInfo.TransactionEnvelopeInfo transactionEnvelopeInfo = (BlockInfo.TransactionEnvelopeInfo) envelopeInfo;
out(" Transaction number %d has %d actions", i, transactionEnvelopeInfo.getTransactionActionInfoCount());
assertEquals(1, transactionEnvelopeInfo.getTransactionActionInfoCount());
out(" Transaction number %d isValid %b", i, transactionEnvelopeInfo.isValid());
assertEquals(transactionEnvelopeInfo.isValid(), true);
out(" Transaction number %d validation code %d", i, transactionEnvelopeInfo.getValidationCode());
assertEquals(0, transactionEnvelopeInfo.getValidationCode());
int j = 0;
for (BlockInfo.TransactionEnvelopeInfo.TransactionActionInfo transactionActionInfo : transactionEnvelopeInfo.getTransactionActionInfos()) {
++j;
out(" Transaction action %d has response status %d", j, transactionActionInfo.getResponseStatus());
assertEquals(200, transactionActionInfo.getResponseStatus());
out(" Transaction action %d has response message bytes as string: %s", j,
printableString(new String(transactionActionInfo.getResponseMessageBytes(), "UTF-8")));
out(" Transaction action %d has %d endorsements", j, transactionActionInfo.getEndorsementsCount());
assertEquals(2, transactionActionInfo.getEndorsementsCount());
for (int n = 0; n < transactionActionInfo.getEndorsementsCount(); ++n) {
BlockInfo.EndorserInfo endorserInfo = transactionActionInfo.getEndorsementInfo(n);
out("Endorser %d signature: %s", n, Hex.encodeHexString(endorserInfo.getSignature()));
out("Endorser %d endorser: %s", n, new String(endorserInfo.getEndorser(), "UTF-8"));
}
out(" Transaction action %d has %d chaincode input arguments", j, transactionActionInfo.getChaincodeInputArgsCount());
for (int z = 0; z < transactionActionInfo.getChaincodeInputArgsCount(); ++z) {
out(" Transaction action %d has chaincode input argument %d is: %s", j, z,
printableString(new String(transactionActionInfo.getChaincodeInputArgs(z), "UTF-8")));
}
out(" Transaction action %d proposal response status: %d", j,
transactionActionInfo.getProposalResponseStatus());
out(" Transaction action %d proposal response payload: %s", j,
printableString(new String(transactionActionInfo.getProposalResponsePayload())));
TxReadWriteSetInfo rwsetInfo = transactionActionInfo.getTxReadWriteSet();
if (null != rwsetInfo) {
out(" Transaction action %d has %d name space read write sets", j, rwsetInfo.getNsRwsetCount());
for (TxReadWriteSetInfo.NsRwsetInfo nsRwsetInfo : rwsetInfo.getNsRwsetInfos()) {
final String namespace = nsRwsetInfo.getNaamespace();
KvRwset.KVRWSet rws = nsRwsetInfo.getRwset();
int rs = -1;
for (KvRwset.KVRead readList : rws.getReadsList()) {
rs++;
out(" Namespace %s read set %d key %s version [%d:%d]", namespace, rs, readList.getKey(),
readList.getVersion().getBlockNum(), readList.getVersion().getTxNum());
if ("bar".equals(channelId) && blockNumber == 2) {
if ("example_cc_go".equals(namespace)) {
if (rs == 0) {
assertEquals("a", readList.getKey());
assertEquals(1, readList.getVersion().getBlockNum());
assertEquals(0, readList.getVersion().getTxNum());
} else if (rs == 1) {
assertEquals("b", readList.getKey());
assertEquals(1, readList.getVersion().getBlockNum());
assertEquals(0, readList.getVersion().getTxNum());
} else {
fail(format("unexpected readset %d", rs));
}
TX_EXPECTED.remove("readset1");
}
}
}
rs = -1;
for (KvRwset.KVWrite writeList : rws.getWritesList()) {
rs++;
String valAsString = printableString(new String(writeList.getValue().toByteArray(), "UTF-8"));
out(" Namespace %s write set %d key %s has value '%s' ", namespace, rs,
writeList.getKey(),
valAsString);
if ("bar".equals(channelId) && blockNumber == 2) {
if (rs == 0) {
assertEquals("a", writeList.getKey());
assertEquals("400", valAsString);
} else if (rs == 1) {
assertEquals("b", writeList.getKey());
assertEquals("400", valAsString);
} else {
fail(format("unexpected writeset %d", rs));
}
TX_EXPECTED.remove("writeset1");
}
}
}
}
}
}
}
}
if (!TX_EXPECTED.isEmpty()) {
fail(TX_EXPECTED.get(0));
}
} catch (InvalidProtocolBufferRuntimeException e) {
throw e.getCause();
}
}
static String printableString(final String string) {
int maxLogStringLength = 64;
if (string == null || string.length() == 0) {
return string;
}
String ret = string.replaceAll("[^\\p{Print}]", "?");
ret = ret.substring(0, Math.min(ret.length(), maxLogStringLength)) + (ret.length() > maxLogStringLength ? "..." : "");
return ret;
}
}