Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.hashgraph.sdk.examples;

import com.hedera.hashgraph.sdk.*;
import com.hedera.hashgraph.sdk.logger.LogLevel;
import com.hedera.hashgraph.sdk.logger.Logger;
import io.github.cdimascio.dotenv.Dotenv;
import java.util.Objects;

/**
* Create a Hedera account using high-volume throttles.
*/
class HighVolumeAccountCreateExample {

/*
* See .env.sample in the examples folder root for how to specify values below
* or set environment variables with the same names.
*/

/**
* Operator's account ID.
* Used to sign and pay for operations on Hedera.
*/
private static final AccountId OPERATOR_ID =
AccountId.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_ID")));

/**
* Operator's private key.
*/
private static final PrivateKey OPERATOR_KEY =
PrivateKey.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_KEY")));

/**
* HEDERA_NETWORK defaults to testnet if not specified in dotenv file.
* Network can be: localhost, testnet, previewnet or mainnet.
*/
private static final String HEDERA_NETWORK = Dotenv.load().get("HEDERA_NETWORK", "testnet");

/**
* SDK_LOG_LEVEL defaults to SILENT if not specified in dotenv file.
* Log levels can be: TRACE, DEBUG, INFO, WARN, ERROR, SILENT.
* <p>
* Important pre-requisite: set simple logger log level to same level as the SDK_LOG_LEVEL,
* for example via VM options: -Dorg.slf4j.simpleLogger.log.org.hiero=trace
*/
private static final String SDK_LOG_LEVEL = Dotenv.load().get("SDK_LOG_LEVEL", "SILENT");

public static void main(String[] args) throws Exception {
System.out.println("High-Volume Account Create Example Start!");

/*
* Step 0:
* Create and configure the SDK Client.
*/
Client client = ClientHelper.forName(HEDERA_NETWORK);
// All generated transactions will be paid by this account and signed by this key.
client.setOperator(OPERATOR_ID, OPERATOR_KEY);
// Attach logger to the SDK Client.
client.setLogger(new Logger(LogLevel.valueOf(SDK_LOG_LEVEL)));

/*
* Step 1:
* Generate ED25519 private and public key pair for the account.
*/
PrivateKey privateKey = PrivateKey.generateED25519();
PublicKey publicKey = privateKey.getPublicKey();
System.out.println("Future account private key: " + privateKey);
System.out.println("Future account public key: " + publicKey);

/*
* Step 2:
* Create a new account using high-volume throttles and set a fee limit.
*/
System.out.println("Creating new account with high-volume throttles...");
TransactionResponse accountCreateTxResponse = new AccountCreateTransaction()
.setKeyWithoutAlias(publicKey)
.setInitialBalance(Hbar.from(1))
.setHighVolume(true)
.setMaxTransactionFee(Hbar.from(5))
.execute(client);

// This will wait for the receipt to become available.
TransactionReceipt accountCreateTxReceipt = accountCreateTxResponse.getReceipt(client);
AccountId newAccountId = accountCreateTxReceipt.accountId;
Objects.requireNonNull(newAccountId);
System.out.println("Created account with ID: " + newAccountId);

/*
* Clean up:
* Delete created account.
*/
new AccountDeleteTransaction()
.setTransferAccountId(OPERATOR_ID)
.setAccountId(newAccountId)
.freezeWith(client)
.sign(privateKey)
.execute(client)
.getReceipt(client);

client.close();

System.out.println("High-Volume Account Create Example Complete!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ public enum FeeDataType {
* The resource cost for the transaction type includes a ConsensusSubmitMessage
* for a topic with custom fees.
*/
SUBMIT_MESSAGE_WITH_CUSTOM_FEES(SubType.SUBMIT_MESSAGE_WITH_CUSTOM_FEES);
SUBMIT_MESSAGE_WITH_CUSTOM_FEES(SubType.SUBMIT_MESSAGE_WITH_CUSTOM_FEES),

/**
* The resource cost for the transaction type that includes a CryptoTransfer with hook invocations
*/
CRYPTO_TRANSFER_WITH_HOOKS(SubType.CRYPTO_TRANSFER_WITH_HOOKS);

final SubType code;

Expand All @@ -70,6 +75,7 @@ static FeeDataType valueOf(SubType code) {
case SCHEDULE_CREATE_CONTRACT_CALL -> SCHEDULE_CREATE_CONTRACT_CALL;
case TOPIC_CREATE_WITH_CUSTOM_FEES -> TOPIC_CREATE_WITH_CUSTOM_FEES;
case SUBMIT_MESSAGE_WITH_CUSTOM_FEES -> SUBMIT_MESSAGE_WITH_CUSTOM_FEES;
case CRYPTO_TRANSFER_WITH_HOOKS -> CRYPTO_TRANSFER_WITH_HOOKS;
default -> throw new IllegalStateException("(BUG) unhandled SubType (FeeDataType)");
};
}
Expand All @@ -85,6 +91,7 @@ public String toString() {
case SCHEDULE_CREATE_CONTRACT_CALL -> "SCHEDULE_CREATE_CONTRACT_CALL";
case TOPIC_CREATE_WITH_CUSTOM_FEES -> "TOPIC_CREATE_WITH_CUSTOM_FEES";
case SUBMIT_MESSAGE_WITH_CUSTOM_FEES -> "SUBMIT_MESSAGE_WITH_CUSTOM_FEES";
case CRYPTO_TRANSFER_WITH_HOOKS -> "CRYPTO_TRANSFER_WITH_HOOKS";
};
}
}
41 changes: 33 additions & 8 deletions sdk/src/main/java/com/hedera/hashgraph/sdk/RequestType.java
Original file line number Diff line number Diff line change
Expand Up @@ -507,22 +507,39 @@ public enum RequestType {
ATOMIC_BATCH(HederaFunctionality.AtomicBatch),

/**
* Update one or more storage slots in an lambda EVM hook.
*
* @deprecated Use {@link #HOOK_STORE} instead.
* (DEPRECATED) Remove once no production throttle assets reference it.
*/
@Deprecated
LAMBDA_S_STORE(HederaFunctionality.LambdaSStore),

/**
* (Internal-only) Dispatch a hook action.
*/
HOOK_DISPATCH(HederaFunctionality.HookDispatch),

/**
* Update one or more storage slots in an EVM hook.
*/
HOOK_STORE(HederaFunctionality.HookStore),

/**
* (Internal-only) Dispatch a hook action.
* (Internal-only) Publish a new ledger id and chain-of-trust key.
*/
LEDGER_ID_PUBLICATION(HederaFunctionality.LedgerIdPublication),

/**
* Create a registered node
*/
REGISTERED_NODE_CREATE(HederaFunctionality.RegisteredNodeCreate),

/**
* Update a registered node
*/
REGISTERED_NODE_UPDATE(HederaFunctionality.RegisteredNodeUpdate),

/**
* Delete a registered node
*/
HOOK_DISPATCH(HederaFunctionality.HookDispatch);
REGISTERED_NODE_DELETE(HederaFunctionality.RegisteredNodeDelete);

final HederaFunctionality code;

Expand Down Expand Up @@ -624,8 +641,12 @@ static RequestType valueOf(HederaFunctionality code) {
case CrsPublication -> CRS_PUBLICATION;
case AtomicBatch -> ATOMIC_BATCH;
case LambdaSStore -> LAMBDA_S_STORE;
case HookStore -> HOOK_STORE;
case HookDispatch -> HOOK_DISPATCH;
case HookStore -> HOOK_STORE;
case LedgerIdPublication -> LEDGER_ID_PUBLICATION;
case RegisteredNodeCreate -> REGISTERED_NODE_CREATE;
case RegisteredNodeUpdate -> REGISTERED_NODE_UPDATE;
case RegisteredNodeDelete -> REGISTERED_NODE_DELETE;
default -> throw new IllegalStateException("(BUG) unhandled HederaFunctionality");
};
}
Expand Down Expand Up @@ -725,8 +746,12 @@ public String toString() {
case CRS_PUBLICATION -> "CRS_PUBLICATION";
case ATOMIC_BATCH -> "ATOMIC_BATCH";
case LAMBDA_S_STORE -> "LAMBDA_S_STORE";
case HOOK_STORE -> "HOOK_STORE";
case HOOK_DISPATCH -> "HOOK_DISPATCH";
case HOOK_STORE -> "HOOK_STORE";
case LEDGER_ID_PUBLICATION -> "LEDGER_ID_PUBLICATION";
case REGISTERED_NODE_CREATE -> "REGISTERED_NODE_CREATE";
case REGISTERED_NODE_UPDATE -> "REGISTERED_NODE_UPDATE";
case REGISTERED_NODE_DELETE -> "REGISTERED_NODE_DELETE";
};
}
}
47 changes: 43 additions & 4 deletions sdk/src/main/java/com/hedera/hashgraph/sdk/Status.java
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,11 @@ public enum Status {
*/
INVALID_SERIALIZED_TX_MESSAGE_HASH_ALGORITHM(ResponseCodeEnum.INVALID_SERIALIZED_TX_MESSAGE_HASH_ALGORITHM),

/**
* A HookStore referenced a valid entity number but with the wrong entity type.
*/
WRONG_HOOK_ENTITY_TYPE(ResponseCodeEnum.WRONG_HOOK_ENTITY_TYPE),

/**
* An EVM hook execution was throttled due to high network gas utilization.
*/
Expand Down Expand Up @@ -1992,7 +1997,7 @@ public enum Status {
/**
* The HookStore tried to update too many storage slots in a single transaction.
*/
TOO_MANY_LAMBDA_STORAGE_UPDATES(ResponseCodeEnum.TOO_MANY_LAMBDA_STORAGE_UPDATES),
TOO_MANY_EVM_HOOK_STORAGE_UPDATES(ResponseCodeEnum.TOO_MANY_EVM_HOOK_STORAGE_UPDATES),

/**
* An EVM hook mapping slot, storage key, or storage value failed to use the
Expand Down Expand Up @@ -2046,11 +2051,43 @@ public enum Status {
*/
HOOKS_ARE_NOT_SUPPORTED_IN_AIRDROPS(ResponseCodeEnum.HOOKS_ARE_NOT_SUPPORTED_IN_AIRDROPS),

WRONG_HOOK_ENTITY_TYPE(ResponseCodeEnum.WRONG_HOOK_ENTITY_TYPE),
/**
* This operation cannot be completed because the target
* account is a "Node Account".<br/>
* This account is currently in use as the "Node Account" for a
* consensus node, and therefore the requested change is
* not permitted. The transaction may be resubmitted once the
* account is no longer in use as a "Node Account" for any
* consensus node.
*/
ACCOUNT_IS_LINKED_TO_A_NODE(ResponseCodeEnum.ACCOUNT_IS_LINKED_TO_A_NODE),

/**
* Hooks are not supported to be used in Batch transactions and Scheduled transactions.
* They are only supported in a top level CryptoTransfer transaction.
*/
HOOKS_EXECUTIONS_REQUIRE_TOP_LEVEL_CRYPTO_TRANSFER(
ResponseCodeEnum.HOOKS_EXECUTIONS_REQUIRE_TOP_LEVEL_CRYPTO_TRANSFER),
NODE_ACCOUNT_HAS_ZERO_BALANCE(ResponseCodeEnum.NODE_ACCOUNT_HAS_ZERO_BALANCE);

/**
* This operation cannot be completed because the target
* account has a zero balance.<br/>
* Node accounts require a positive balance. The transaction may be
* resubmitted once the account has been funded.
*/
NODE_ACCOUNT_HAS_ZERO_BALANCE(ResponseCodeEnum.NODE_ACCOUNT_HAS_ZERO_BALANCE),

/**
* This operation cannot be completed because the target
* account is a "Fee Collection Account".<br/>
* Any attempt to transfer to a fee collection account is not permitted.
*/
TRANSFER_TO_FEE_COLLECTION_ACCOUNT_NOT_ALLOWED(ResponseCodeEnum.TRANSFER_TO_FEE_COLLECTION_ACCOUNT_NOT_ALLOWED),

/**
* The number of hook invocations exceeds the maximum allowed per transaction.
*/
TOO_MANY_HOOK_INVOCATIONS(ResponseCodeEnum.TOO_MANY_HOOK_INVOCATIONS);

final ResponseCodeEnum code;

Expand Down Expand Up @@ -2443,7 +2480,7 @@ static Status valueOf(ResponseCodeEnum code) {
case HOOKS_NOT_ENABLED -> HOOKS_NOT_ENABLED;
case HOOK_IS_NOT_AN_EVM_HOOK -> HOOK_IS_NOT_AN_EVM_HOOK;
case HOOK_DELETED -> HOOK_DELETED;
case TOO_MANY_LAMBDA_STORAGE_UPDATES -> TOO_MANY_LAMBDA_STORAGE_UPDATES;
case TOO_MANY_EVM_HOOK_STORAGE_UPDATES -> TOO_MANY_EVM_HOOK_STORAGE_UPDATES;
case HOOK_CREATION_BYTES_MUST_USE_MINIMAL_REPRESENTATION ->
HOOK_CREATION_BYTES_MUST_USE_MINIMAL_REPRESENTATION;
case HOOK_CREATION_BYTES_TOO_LONG -> HOOK_CREATION_BYTES_TOO_LONG;
Expand All @@ -2459,6 +2496,8 @@ static Status valueOf(ResponseCodeEnum code) {
case HOOKS_EXECUTIONS_REQUIRE_TOP_LEVEL_CRYPTO_TRANSFER ->
HOOKS_EXECUTIONS_REQUIRE_TOP_LEVEL_CRYPTO_TRANSFER;
case NODE_ACCOUNT_HAS_ZERO_BALANCE -> NODE_ACCOUNT_HAS_ZERO_BALANCE;
case TRANSFER_TO_FEE_COLLECTION_ACCOUNT_NOT_ALLOWED -> TRANSFER_TO_FEE_COLLECTION_ACCOUNT_NOT_ALLOWED;
case TOO_MANY_HOOK_INVOCATIONS -> TOO_MANY_HOOK_INVOCATIONS;
case UNRECOGNIZED ->
// NOTE: Protobuf deserialization will not give us the code on the wire
throw new IllegalArgumentException(
Expand Down
31 changes: 30 additions & 1 deletion sdk/src/main/java/com/hedera/hashgraph/sdk/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public abstract class Transaction<T extends Transaction<T>>

private String memo = "";

private boolean highVolume = false;

List<CustomFeeLimit> customFeeLimits = new ArrayList<>();

private Key batchKey = null;
Expand All @@ -156,6 +158,7 @@ public abstract class Transaction<T extends Transaction<T>>
setTransactionValidDuration(DEFAULT_TRANSACTION_VALID_DURATION);
setMaxTransactionFee(Hbar.fromTinybars(txBody.getTransactionFee()));
setTransactionMemo(txBody.getMemo());
setHighVolume(txBody.getHighVolume());

sourceTransactionBody = txBody;
}
Expand Down Expand Up @@ -245,6 +248,7 @@ public abstract class Transaction<T extends Transaction<T>>
DurationConverter.fromProtobuf(sourceTransactionBody.getTransactionValidDuration()));
setMaxTransactionFee(Hbar.fromTinybars(sourceTransactionBody.getTransactionFee()));
setTransactionMemo(sourceTransactionBody.getMemo());
setHighVolume(sourceTransactionBody.getHighVolume());

this.customFeeLimits = sourceTransactionBody.getMaxCustomFeesList().stream()
.map(CustomFeeLimit::fromProtobuf)
Expand Down Expand Up @@ -859,6 +863,30 @@ public final T setTransactionMemo(String memo) {
return (T) this;
}

/**
* Extract the high-volume flag.
*
* @return true if high-volume throttles are enabled, false otherwise
*/
public final boolean getHighVolume() {
return highVolume;
}

/**
* If set to true, this transaction uses high-volume throttles and pricing
* for entity creation. It only affects supported transaction types; otherwise,
* it is ignored.
*
* @param highVolume true to enable high-volume throttles, false otherwise
* @return {@code this}
*/
public final T setHighVolume(boolean highVolume) {
requireNotFrozen();
this.highVolume = highVolume;
// noinspection unchecked
return (T) this;
}

/**
* batchify method is used to mark a transaction as part of a batch transaction or make it so-called inner transaction.
* The Transaction will be frozen and signed by the operator of the client.
Expand Down Expand Up @@ -1236,7 +1264,8 @@ protected TransactionBody.Builder spawnBodyBuilder(@Nullable Client client) {
.setTransactionValidDuration(DurationConverter.toProtobuf(transactionValidDuration).toBuilder())
.addAllMaxCustomFees(
customFeeLimits.stream().map(CustomFeeLimit::toProtobuf).collect(Collectors.toList()))
.setMemo(memo);
.setMemo(memo)
.setHighVolume(highVolume);
if (batchKey != null) {
builder.setBatchKey(batchKey.toProtobufKey());
}
Expand Down
Loading
Loading