Search code examples
javahyperledger-fabricblockchainhyperledger-chaincode

Not able to do the invoke transaction from Java SDK for the BYFN in Fabric


I have been trying out to invoke and querying transactions from the Java SDK for the BYFN network in Hyperledger Fabric v1.4.4 So far i have started the network (which has two peers in two orgs, an orderer and chaincode mycc installed). The network starts successfully, and scripts and tests complete (As per the end of execution the values of a and b after the byfn.sh scripts runs is 90 and 210 respectively)

Now I have my Java SDK, through which the query proposal response works correctly (returns 90 and 210), but after moving (doing the invoke) request and then querying the value returned is still 90, there is no change, I am not sure what I am doing wrong here.

My code:

public class sdksample {

    // Main program to simply call the client, Am i making some mistake here ?? persistency ?
    public static void main(String[] args) throws Exception {
        // create fabric-ca client
        BlockChainHFClient.getInstance().setupCryptoMaterialsForClient();
        BlockChainHFClient.getInstance().initChannel();

        // get HFC client instance
        BlockChainHFClient client = BlockChainHFClient.getInstance();
        System.out.println(client);

    }
}

HFClient

import static java.lang.String.format;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.hyperledger.fabric.protos.ledger.rwset.kvrwset.KvRwset;
import org.hyperledger.fabric.sdk.BlockInfo;
import org.hyperledger.fabric.sdk.BlockInfo.EnvelopeType;
import org.hyperledger.fabric.sdk.ChaincodeID;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.HFClient;
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.TransactionProposalRequest;
import org.hyperledger.fabric.sdk.TxReadWriteSetInfo;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.exception.BaseException;
import org.hyperledger.fabric.sdk.exception.CryptoException;
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.TransactionException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

import com.google.protobuf.InvalidProtocolBufferException;

public class BlockChainHFClient {

    private static BlockChainHFClient instance;

    /**
     * Client instance constructor
     */
    private BlockChainHFClient() {
    }

    /**
     * Returns an instance of the Fabric client
     * 
     * @return instance
     */
    public static synchronized BlockChainHFClient getInstance() {
        if (instance == null) {
            instance = new BlockChainHFClient();
        }
        return instance;
    }

    /**
     * Fabric client object
     */
    final HFClient hfClient = HFClient.createNewInstance();
    /**
     * Crypto config folder location . keep crypto-config folder in user/home
     */
    final String CRYPTO_CONFIG_HOME_DIR = System.getProperty("user.home");
    /**
     * Grpcs URL
     */
    final String GRPCS = "grpcs://";
    /**
     * Dot for utility
     */
    final String DOT = ".";
    /**
     * MSP ID Root
     */
    final String ROOT_MSP_ID = "Org1MSP";
    /**
     * Admin user
     */
    final String PEER_ADMIN = "PeerAdmin";
    /**
     * Channel object
     */
    Channel channel;

    /**
     * Channel initialize timeout values
     */
    final Long ChannelBuilderOptionkeepAliveMinutes = 15L;
    final Long ChannelBuilderOptionkeepAliveSeconds = 15L;

    /**
     * Get channel instance
     * 
     * @return channel
     */
    public Channel getChannel() {
        return channel;
    }

    /**
     * Get HF client
     * 
     * @return HF client
     */
    public HFClient getClient() {
        return hfClient;
    }

    /**
     * Set up User contexts by using Crypto materials - Private key and cert files
     * 
     * @throws CryptoException
     * @throws InvalidArgumentException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public void setupCryptoMaterialsForClient()
            throws CryptoException, InvalidArgumentException, IllegalAccessException, InstantiationException,
            ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
        hfClient.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
        hfClient.setUserContext(new User() {
            public String getName() {
                return PEER_ADMIN;
            }

            public Set<String> getRoles() {
                return null;
            }

            public String getAccount() {
                return null;
            }

            public String getAffiliation() {
                return null;
            }

            public Enrollment getEnrollment() {
                return new Enrollment() {
                    public PrivateKey getKey() {
                        PrivateKey privateKey = null;
                        File privateKeyFile = findFileSk(
                                "D:\\Hyperledger Fabric_Research_Blockchain\\Fabric1.4.4\\fabric-samples\\first-network\\crypto-config\\peerOrganizations\\org1.example.com\\users\\[email protected]\\msp\\keystore");
                        try {
                            privateKey = getPrivateKeyFromBytes(
                                    IOUtils.toByteArray(new FileInputStream(privateKeyFile)));
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (NoSuchProviderException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (NoSuchAlgorithmException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (InvalidKeySpecException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        return privateKey;
                    }

                    public String getCert() {

                        String certificate = null;
                        try {
                            File certificateFile = new File(
                                    "D:\\Hyperledger Fabric_Research_Blockchain\\Fabric1.4.4\\fabric-samples\\first-network\\crypto-config\\peerOrganizations\\org1.example.com\\users\\[email protected]\\msp\\signcerts\\[email protected]");
                            certificate = new String(IOUtils.toByteArray(new FileInputStream(certificateFile)),
                                    "UTF-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return certificate;
                    }
                };
            }

            public String getMspId() {
                return ROOT_MSP_ID;
            }
        });
    }

    public void initChannel() throws Exception {
        Properties peerProperties = new Properties();
        peerProperties.setProperty("pemFile",
                "D:\\Hyperledger Fabric_Research_Blockchain\\Fabric1.4.4\\fabric-samples\\first-network\\crypto-config\\peerOrganizations\\org1.example.com\\peers\\peer0.org1.example.com\\tls\\server.crt");
        peerProperties.setProperty("trustServerCertificate", "true"); // testing environment only NOT FOR PRODUCTION!
        peerProperties.setProperty("hostnameOverride", "peer0.org1.example.com");
        peerProperties.setProperty("sslProvider", "openSSL");
        peerProperties.setProperty("negotiationType", "TLS");
        peerProperties.put("grpc.NettyChannelBuilderOption.maxInboundMessageSize", 9000000);
        Peer peer = hfClient.newPeer("peer0.org1.example.com", "grpc://localhost:7051");


        Properties ordererProperties = new Properties();
        ordererProperties.setProperty("pemFile",
                "D:\\Hyperledger Fabric_Research_Blockchain\\Fabric1.4.4\\fabric-samples\\first-network\\crypto-config\\ordererOrganizations\\example.com\\orderers\\orderer.example.com\\tls\\server.crt");
        ordererProperties.setProperty("trustServerCertificate", "true"); // testing environment only NOT FOR PRODUCTION!
        ordererProperties.setProperty("hostnameOverride", "orderer.example.com");
        ordererProperties.setProperty("sslProvider", "openSSL");
        ordererProperties.setProperty("negotiationType", "TLS");
        ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] { 5L, TimeUnit.MINUTES });
        ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] { 8L, TimeUnit.SECONDS });
        Orderer orderer = hfClient.newOrderer("orderer.example.com", "grpc://localhost:7050");


        Channel channel = hfClient.newChannel("mychannel");
        channel.addPeer(peer);
        channel.addOrderer(orderer);
        channel.initialize();



        moveUnits(hfClient);
        queryBlockChain(hfClient);

    }

    private String printableString(String string) {
        int maxLogStringLength = 10000;
        if (string == null || string.length() == 0) {
            return string;
        }

        String ret = string.replaceAll("[^\\p{Print}]", "\n");

        ret = ret.substring(0, Math.min(ret.length(), maxLogStringLength))
                + (ret.length() > maxLogStringLength ? "..." : "");

        return ret;
    }

    void queryBlockChain(HFClient client) throws ProposalException, InvalidArgumentException {
        // get channel instance from client
        Channel channel = client.getChannel("mychannel");
        // create chaincode request
        QueryByChaincodeRequest qpr = client.newQueryProposalRequest();
        // build cc id providing the chaincode name. Version is omitted here.
        ChaincodeID cid = ChaincodeID.newBuilder().setName("mycc").build();
        qpr.setChaincodeID(cid);
        // CC function to be called
        qpr.setFcn("query");
        qpr.setArgs(new String[] { "a" });
        Collection<ProposalResponse> res = channel.queryByChaincode(qpr);
        // display response
        for (ProposalResponse pres : res) {
            String stringResponse = new String(pres.getChaincodeActionResponsePayload());
            System.out.println(stringResponse);
        }
    }

     void moveUnits(HFClient client)
                throws Exception {
            Channel channel = client.getChannel("mychannel");
            TransactionProposalRequest req = client.newTransactionProposalRequest();
            ChaincodeID cid = ChaincodeID.newBuilder().setName("mycc").setVersion("1.0").build();
            req.setChaincodeID(cid);
            req.setFcn("invoke");
            req.setArgs(new String[] {"a","b","50"});
            Collection<ProposalResponse> resps = channel.sendTransactionProposal(req);

                channel.sendTransaction(resps);

        } 

    /**
     * Utility method to get private key from bytes using Bouncy Castle Security
     * Provider
     * 
     * @param data
     * @return privateKey
     * @throws IOException
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private PrivateKey getPrivateKeyFromBytes(byte[] data)
            throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
        final Reader pemReader = new StringReader(new String(data));
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        final PrivateKeyInfo pemPair;
        try (PEMParser pemParser = new PEMParser(pemReader)) {
            pemPair = (PrivateKeyInfo) pemParser.readObject();
        }

        PrivateKey privateKey = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .getPrivateKey(pemPair);

        return privateKey;
    }

    /**
     * Find files ending with _sk
     * 
     * @param directorys
     * @return file
     */
    private File findFileSk(String directorys) {

        File directory = new File(directorys);

        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];
    }
}

There seems to be no errors, the moveUnits function seems to work. But the query returns the same values. Suggestions? Thanks !


Solution

  • Worked. apparently i had to add another peer (peer0.org2.example.com) to the channel so as to satisfy the endorsement policy that two peers had to validate. The invoke then worked !