Skip to content

Commit

Permalink
better clients
Browse files Browse the repository at this point in the history
  • Loading branch information
hendrikebbers committed Jul 14, 2024
1 parent 6c05f8d commit 3d1aedd
Show file tree
Hide file tree
Showing 24 changed files with 436 additions and 229 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.openelements.hedera.base.data;
package com.openelements.hedera.base;

import com.hedera.hashgraph.sdk.AccountId;
import com.hedera.hashgraph.sdk.ContractId;
Expand All @@ -11,6 +11,16 @@
import java.math.BigInteger;
import java.util.Objects;

/**
* Represents a parameter for a smart contract call (see {@link com.openelements.hedera.base.SmartContractClient}).
* For all supported types, see the static factory methods.
* Normally a developer should not need to create instances of this class directly.
*
* @param value the value of the parameter
* @param nativeType the native type of the parameter
* @param supplier the supplier of the parameter
* @param <T> the type of the parameter
*/
public record ContractParam<T>(@NonNull T value, @NonNull String nativeType, @NonNull ParamSupplier<T> supplier) {

public ContractParam {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,53 @@
import com.hedera.hashgraph.sdk.FileId;
import edu.umd.cs.findbugs.annotations.NonNull;

/**
* A client for interacting with the file service on the Hedera network.
*/
public interface FileClient {

/**
* Create a new file with the given contents.
* @param contents the contents of the file
* @return the ID of the new file
* @throws HederaException if the file could not be created
*/
@NonNull
FileId createFile(@NonNull byte[] contents) throws HederaException;

/**
* Create a new file with the given contents.
* @param fileId the ID of the file to update
* @return the ID of the new file
* @throws HederaException if the file could not be created
*/
@NonNull
default byte[] readFile(@NonNull String fileId) throws HederaException {
return readFile(FileId.fromString(fileId));
}

/**
* Read the contents of a file.
* @param fileId the ID of the file to read
* @return the contents of the file
* @throws HederaException if the file could not be read
*/
@NonNull
byte[] readFile(@NonNull FileId fileId) throws HederaException;

/**
* Delete a file.
* @param fileId the ID of the file to delete
* @throws HederaException if the file could not be deleted
*/
default void deleteFile(@NonNull String fileId) throws HederaException {
deleteFile(FileId.fromString(fileId));
}

/**
* Delete a file.
* @param fileId the ID of the file to delete
* @throws HederaException if the file could not be deleted
*/
void deleteFile(@NonNull FileId fileId) throws HederaException;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.openelements.hedera.base;

import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Represents an exception that occurred while interacting with the Hedera network.
*/
Expand All @@ -9,7 +11,7 @@ public class HederaException extends Exception {
* Constructs a new HederaException with the specified detail message.
* @param message The detail message.
*/
public HederaException(String message) {
public HederaException(@NonNull String message) {
super(message);
}

Expand All @@ -18,7 +20,7 @@ public HederaException(String message) {
* @param message The detail message.
* @param cause The cause.
*/
public HederaException(String message, Throwable cause) {
public HederaException(@NonNull String message, @NonNull Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,78 @@
import com.hedera.hashgraph.sdk.ContractFunctionResult;
import com.hedera.hashgraph.sdk.ContractId;
import com.hedera.hashgraph.sdk.FileId;
import com.openelements.hedera.base.data.ContractParam;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.nio.file.Path;

/**
* A client for interacting with the smart contract service on the Hedera network.
*/
public interface SmartContractClient {

/**
* Create a new smart contract based on the file the given file ID. The file must contain the bytecode for the contract.
* @param fileId the ID of the file containing the contract bytecode
* @param constructorParams the parameters to pass to the contract constructor
* @return the ID of the new contract
* @throws HederaException if the contract could not be created
*/
@NonNull
default ContractId createContract(@NonNull String fileId, @Nullable ContractParam<?>... constructorParams) throws HederaException {
return createContract(FileId.fromString(fileId), constructorParams);
}

/**
* Create a new smart contract based on the file the given file ID. The file must contain the bytecode for the contract.
* @param fileId the ID of the file containing the contract bytecode
* @param constructorParams the parameters to pass to the contract constructor
* @return the ID of the new contract
* @throws HederaException if the contract could not be created
*/
@NonNull
ContractId createContract(@NonNull FileId fileId, @Nullable ContractParam<?>... constructorParams) throws HederaException;

/**
* Create a new smart contract with the given contents. The contents must be the bytecode for the contract.
* @param contents the contents of the contract
* @param constructorParams the parameters to pass to the contract constructor
* @return the ID of the new contract
* @throws HederaException if the contract could not be created
*/
@NonNull
ContractId createContract(@NonNull byte[] contents, @Nullable ContractParam<?>... constructorParams) throws HederaException;

/**
* Create a new smart contract based on a file. The contents of the file must be the bytecode for the contract.
* @param pathToBin the path to the file containing the contract bytecode
* @param constructorParams the parameters to pass to the contract constructor
* @return the ID of the new contract
* @throws HederaException if the contract could not be created
*/
@NonNull
ContractId createContract(@NonNull Path pathToBin, @Nullable ContractParam<?>... constructorParams) throws HederaException;

/**
* Call a function on a smart contract.
* @param contractId the ID of the contract
* @param functionName the name of the function to call
* @param params the parameters to pass to the function
* @return the result of the function call
* @throws HederaException if the function could not be called
*/
@NonNull
default ContractFunctionResult callContractFunction(@NonNull String contractId, @NonNull String functionName, @Nullable ContractParam<?>... params) throws HederaException {
return callContractFunction(ContractId.fromString(contractId), functionName, params);
}

/**
* Call a function on a smart contract.
* @param contractId the ID of the contract
* @param functionName the name of the function to call
* @param params the parameters to pass to the function
* @return the result of the function call
* @throws HederaException if the function could not be called
*/
@NonNull
ContractFunctionResult callContractFunction(@NonNull ContractId contractId, @NonNull String functionName, @Nullable ContractParam<?>... params) throws HederaException;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.openelements.hedera.base.implementation;

import com.hedera.hashgraph.sdk.FileId;
import com.openelements.hedera.base.FileClient;
import com.openelements.hedera.base.HederaException;
import com.openelements.hedera.base.protocol.FileAppendRequest;
import com.openelements.hedera.base.protocol.FileAppendResult;
import com.openelements.hedera.base.protocol.FileContentsRequest;
import com.openelements.hedera.base.protocol.FileContentsResponse;
import com.openelements.hedera.base.protocol.FileCreateRequest;
import com.openelements.hedera.base.protocol.FileCreateResult;
import com.openelements.hedera.base.protocol.FileDeleteRequest;
import com.openelements.hedera.base.protocol.ProtocolLevelClient;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Arrays;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileClientImpl implements FileClient {

private final static Logger log = LoggerFactory.getLogger(FileClientImpl.class);

private final ProtocolLevelClient protocolLevelClient;

public FileClientImpl(@NonNull final ProtocolLevelClient protocolLevelClient) {
this.protocolLevelClient = Objects.requireNonNull(protocolLevelClient, "protocolLevelClient must not be null");
}

@Override
public FileId createFile(byte[] contents) throws HederaException {
if(contents.length <= FileCreateRequest.FILE_CREATE_MAX_BYTES) {
final FileCreateRequest request = FileCreateRequest.of(contents);
final FileCreateResult result = protocolLevelClient.executeFileCreateTransaction(request);
return result.fileId();
} else {
if(log.isDebugEnabled()) {
final int appendCount = Math.floorDiv(contents.length, FileCreateRequest.FILE_CREATE_MAX_BYTES);
log.debug("Content of size {} is to big for 1 FileCreate transaction. Will append {} FileAppend transactions", contents.length, appendCount);
}
byte[] start = Arrays.copyOf(contents, FileCreateRequest.FILE_CREATE_MAX_BYTES);
final FileCreateRequest request = FileCreateRequest.of(start);
final FileCreateResult result = protocolLevelClient.executeFileCreateTransaction(request);
FileId fileId = result.fileId();
byte[] remaining = Arrays.copyOfRange(contents, FileCreateRequest.FILE_CREATE_MAX_BYTES, contents.length);
while(remaining.length > 0) {
final int length = Math.min(remaining.length, FileCreateRequest.FILE_CREATE_MAX_BYTES);
byte[] next = Arrays.copyOf(remaining, length);
final FileAppendRequest appendRequest = FileAppendRequest.of(fileId, next);
final FileAppendResult appendResult = protocolLevelClient.executeFileAppendRequestTransaction(appendRequest);
remaining = Arrays.copyOfRange(remaining, length, remaining.length);
}
return fileId;
}
}

@NonNull
@Override
public byte[] readFile(@NonNull FileId fileId) throws HederaException {
try {
final FileContentsRequest request = FileContentsRequest.of(fileId);
final FileContentsResponse response = protocolLevelClient.executeFileContentsQuery(request);
return response.contents();
} catch (Exception e) {
throw new HederaException("Failed to read file with fileId " + fileId, e);
}
}

@Override
public void deleteFile(@NonNull FileId fileId) throws HederaException {
try {
final FileDeleteRequest request = FileDeleteRequest.of(fileId);
protocolLevelClient.executeFileDeleteTransaction(request);
} catch (Exception e) {
throw new HederaException("Failed to delete file with fileId " + fileId, e);
}
}
}
Loading

0 comments on commit 3d1aedd

Please sign in to comment.