Reputation: 31
I am working on a Hyperledger Fabric application using the Java SDK to interact with a smart contract. My query transaction works perfectly, but when I attempt to execute a create transaction, it fails with an "Contract Exception." and message "Invalid Transaction".
Here are the details:
Smart Contract Code (Go):
I have a smart contract deployed on my Fabric network. The CreateContract function is as follows:
This function creates a new contract with the provided parameters or throws an error if the contract already exists.
func (s *SmartContract) CreateContract(ctx contractapi.TransactionContextInterface, contractId string, client string, supplier string, description string) (string, error) {
if contractId == "" {
return "", fmt.Errorf("Contract Id cannot be empty.")
}
if client == "" {
return "", fmt.Errorf("Client field cannot be empty.")
}
if supplier == "" {
return "", fmt.Errorf("Supplier field cannot be empty.")
}
chatAsBytes, err := ctx.GetStub().GetState(contractId)
if err != nil {
return "", fmt.Errorf("Failed to read from world state. %s", err.Error())
}
if chatAsBytes == nil {
newContract := LegalContractSchema{
DocType: "Legal Contract",
Participants: []string{client, supplier},
Description: description,
}
newContractAsBytes, _ := json.Marshal(newContract)
err := ctx.GetStub().PutState(contractId, newContractAsBytes)
if err != nil {
return "", fmt.Errorf("Failed writing to world state. %s", err.Error())
}
return "Successfully created contract", nil
} else {
return "", fmt.Errorf("Failed to create contract schema, contract already exists.")
}
}
Java SDK Code:
I am using the Java SDK to interact with the smart contract. My code for invoking the CreateContract function is as follows:
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet, "admin")
.networkConfig(networkConfigFile)
.discovery(true)
.commitTimeout(60, TimeUnit.SECONDS);
try (Gateway gateway = builder.connect()) {
Network network = gateway.getNetwork("mychannel");
Contract contract = network.getContract("legalContract");
// Submit a create transaction
byte[] createResult = contract.createTransaction("CreateContract")
.submit("contractId123", "ClientName", "SupplierName", "This is a test description");
System.out.println("Create Transaction Result: " + new String(createResult, StandardCharsets.UTF_8));
}
Query Transaction:
The query transaction (GetLegalContractCert) works perfectly using the same Java code structure:
byte[] queryResult = contract.evaluateTransaction("GetLegalContractCert", "contractId123");
System.out.println("Query Result: " + new String(queryResult, StandardCharsets.UTF_8));
Issue:
When I invoke the CreateContract function, I get the following error:
Invalid transaction Contract Exception
The query transaction works fine, but the create transaction fails.
What I've Tried:
Environment:
My Connection Profile looks like the following:
{
"name": "test-network-org1",
"version": "1.0.0",
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300"
}
}
}
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
]
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\XYF\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com"
}
}
},
"certificateAuthorities": {
"ca.org1.example.com": {
"url": "https://localhost:7054",
"caName": "ca-org1",
"tlsCACerts": {
"pem": ["-----BEGIN CERTIFICATE-----\XYZ\n-----END CERTIFICATE-----\n"]
},
"httpOptions": {
"verify": false
}
}
}
}
Upvotes: 1
Views: 44
Reputation: 1649
If you are using (or can use) Fabric v2.4 or later, your best solution is to use the Fabric Gateway client API instead of the legacy Java SDK to build your client application.
If you really cannot move to a current Fabric version and must continue with the legacy Java SDK, I suspect that your issue might be the need to set the as_localhost
configuration property for service discovery. This is based on your connection profile listing localhost addresses for your peer and orderer. See the API documentation for scenarios where this setting is required and how to configure it using environment variables.
Upvotes: 1