Skip to content

Commit

Permalink
Add modularized property (#9927)
Browse files Browse the repository at this point in the history
The integration of reusable services will span through multiple releases and will be delivered in chunks. That's why we need a feature flag to disable the new code before it's fully implemented and properly tested.

---------

Signed-off-by: Bilyana Gospodinova <[email protected]>
Signed-off-by: Kristiyan Selveliev <[email protected]>
Co-authored-by: Kristiyan Selveliev <[email protected]>
  • Loading branch information
bilyana-gospodinova and kselveliev authored Dec 18, 2024
1 parent 26878b7 commit 991f378
Show file tree
Hide file tree
Showing 36 changed files with 1,103 additions and 431 deletions.
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ value, it is recommended to only populate overridden properties in the custom `a
| `hedera.mirror.web3.evm.maxTokensPerAccount` | 1000 | Maximum number token associations per account |
| `hedera.mirror.web3.evm.maxTokenSymbolUtf8Bytes` | 100 | Maximum size in bytes for token symbol |
| `hedera.mirror.web3.evm.minAutoRenewDuration` | 2592000 | Minimum duration for auto-renew account |
| `hedera.mirror.web3.evm.modularizedServices` | false | Flag that indicates if the hedera.app dependency is used. This is under development. It is recommended to be set to false. |
| `hedera.mirror.web3.evm.network` | TESTNET | Which Hedera network to use. Can be either `MAINNET`, `PREVIEWNET`, `TESTNET` or `OTHER` |
| `hedera.mirror.web3.evm.feesTokenTransferUsageMultiplier` | 380 | Used to calculate token transfer fees |
| `hedera.mirror.web3.evm.trace.enabled` | false | Flag enabling tracer |
Expand Down
5 changes: 4 additions & 1 deletion hedera-mirror-web3/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ plugins {
id("spring-conventions")
}

// We need to use this version in order to be able to decode hex data when using the hedera.app
// dependency
val headlongVersion = "6.1.1"
val javaxInjectVersion = "1"

dependencies {
implementation(platform("org.springframework.cloud:spring-cloud-dependencies"))
implementation(project(":common"))
implementation("com.bucket4j:bucket4j-core")
implementation("com.esaulpaugh:headlong")
implementation("com.esaulpaugh:headlong:$headlongVersion")
implementation("com.hedera.hashgraph:app") { exclude(group = "io.netty") }
implementation("com.hedera.evm:hedera-evm")
implementation("io.github.mweirauch:micrometer-jvm-extras")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,14 @@ public class ContractCallContext {

/**
* The TransactionExecutor from the modularized services integration deploys contracts in 2 steps:
*
* 1. The initcode is uploaded and saved as a file using a {@link FileCreateTransactionBody}.
* 2. The returned file id from step 1 is then passed to a {@link ContractCreateTransactionBody}.
* Each step performs a separate transaction.
* For step 2 even if we pass the correct file id, since the mirror node data is readonly,
* the {@link FileReadableKVState} is not able to populate the contract's bytecode from the DB
* since it was never explicitly persisted in the DB.
*
* This is the function of the field "file" to hold temporary the bytecode and the fileId
* during contract deploy.
* <p>
* 1. The initcode is uploaded and saved as a file using a {@link FileCreateTransactionBody}. 2. The returned file
* id from step 1 is then passed to a {@link ContractCreateTransactionBody}. Each step performs a separate
* transaction. For step 2 even if we pass the correct file id, since the mirror node data is readonly, the
* {@link FileReadableKVState} is not able to populate the contract's bytecode from the DB since it was never
* explicitly persisted in the DB.
* <p>
* This is the function of the field "file" to hold temporary the bytecode and the fileId during contract deploy.
*/
@Setter
private Optional<File> file = Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import jakarta.validation.constraints.Positive;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -46,6 +47,7 @@
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hibernate.validator.constraints.time.DurationMin;
import org.hyperledger.besu.datatypes.Address;
Expand Down Expand Up @@ -176,10 +178,16 @@ public class MirrorNodeEvmProperties implements EvmProperties {
"contracts.maxRefundPercentOfGasLimit",
String.valueOf(maxGasRefundPercentage()));

@Getter(lazy = true)
private final Map<String, String> transactionProperties = buildTransactionProperties();

@Getter
@Min(1)
private int feesTokenTransferUsageMultiplier = 380;

@Getter
private boolean modularizedServices;

public boolean shouldAutoRenewAccounts() {
return autoRenewTargetTypes.contains(EntityType.ACCOUNT);
}
Expand Down Expand Up @@ -314,6 +322,18 @@ public int feesTokenTransferUsageMultiplier() {
return feesTokenTransferUsageMultiplier;
}

private Map<String, String> buildTransactionProperties() {
final Map<String, String> mirrorNodeProperties = new HashMap<>(properties);
mirrorNodeProperties.put(
"contracts.evm.version",
"v"
+ getSemanticEvmVersion().major() + "."
+ getSemanticEvmVersion().minor());
mirrorNodeProperties.put(
"ledger.id", Bytes.wrap(getNetwork().getLedgerId()).toHexString());
return mirrorNodeProperties;
}

@Getter
@RequiredArgsConstructor
public enum HederaNetwork {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import com.hedera.mirror.web3.common.ContractCallContext;
import com.hedera.mirror.web3.evm.contracts.execution.MirrorEvmTxProcessor;
import com.hedera.mirror.web3.evm.properties.MirrorNodeEvmProperties;
import com.hedera.mirror.web3.evm.store.Store;
import com.hedera.mirror.web3.exception.BlockNumberNotFoundException;
import com.hedera.mirror.web3.exception.MirrorEvmTransactionException;
Expand All @@ -44,21 +45,26 @@
public abstract class ContractCallService {
static final String GAS_LIMIT_METRIC = "hedera.mirror.web3.call.gas.limit";
static final String GAS_USED_METRIC = "hedera.mirror.web3.call.gas.used";
protected final Store store;
private final MeterProvider<Counter> gasLimitCounter;
private final MeterProvider<Counter> gasUsedCounter;
protected final Store store;
private final MirrorEvmTxProcessor mirrorEvmTxProcessor;
private final RecordFileService recordFileService;
private final ThrottleProperties throttleProperties;
private final Bucket gasLimitBucket;
private final MirrorNodeEvmProperties mirrorNodeEvmProperties;
private final TransactionExecutionService transactionExecutionService;

@SuppressWarnings("java:S107")
protected ContractCallService(
MirrorEvmTxProcessor mirrorEvmTxProcessor,
Bucket gasLimitBucket,
ThrottleProperties throttleProperties,
MeterRegistry meterRegistry,
RecordFileService recordFileService,
Store store) {
Store store,
MirrorNodeEvmProperties mirrorNodeEvmProperties,
TransactionExecutionService transactionExecutionService) {
this.gasLimitCounter = Counter.builder(GAS_LIMIT_METRIC)
.description("The amount of gas limit sent in the request")
.withRegistry(meterRegistry);
Expand All @@ -70,24 +76,26 @@ protected ContractCallService(
this.recordFileService = recordFileService;
this.throttleProperties = throttleProperties;
this.gasLimitBucket = gasLimitBucket;
this.mirrorNodeEvmProperties = mirrorNodeEvmProperties;
this.transactionExecutionService = transactionExecutionService;
}

/**
* This method is responsible for calling a smart contract function. The method is divided into two main parts:
* <p>
* 1. If the call is historical, the method retrieves the corresponding record file and initializes
* the contract call context with the historical state. The method then proceeds to call the contract.
* 1. If the call is historical, the method retrieves the corresponding record file and initializes the contract
* call context with the historical state. The method then proceeds to call the contract.
* </p>
* <p>
* 2. If the call is not historical, the method initializes the contract call context with the current state
* and proceeds to call the contract.
* 2. If the call is not historical, the method initializes the contract call context with the current state and
* proceeds to call the contract.
* </p>
*
* @param params the call service parameters
* @param ctx the contract call context
* @param ctx the contract call context
* @return {@link HederaEvmTransactionProcessingResult} of the contract call
* @throws MirrorEvmTransactionException if any pre-checks
* fail with {@link IllegalStateException} or {@link IllegalArgumentException}
* @throws MirrorEvmTransactionException if any pre-checks fail with {@link IllegalStateException} or
* {@link IllegalArgumentException}
*/
protected HederaEvmTransactionProcessingResult callContract(CallServiceParameters params, ContractCallContext ctx)
throws MirrorEvmTransactionException {
Expand All @@ -106,7 +114,12 @@ protected HederaEvmTransactionProcessingResult doProcessCall(
CallServiceParameters params, long estimatedGas, boolean restoreGasToThrottleBucket)
throws MirrorEvmTransactionException {
try {
var result = mirrorEvmTxProcessor.execute(params, estimatedGas);
HederaEvmTransactionProcessingResult result;
if (!mirrorNodeEvmProperties.isModularizedServices()) {
result = mirrorEvmTxProcessor.execute(params, estimatedGas);
} else {
result = transactionExecutionService.execute(params, estimatedGas);
}
if (!restoreGasToThrottleBucket) {
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.hedera.mirror.web3.evm.contracts.execution.MirrorEvmTxProcessor;
import com.hedera.mirror.web3.evm.contracts.execution.OpcodesProcessingResult;
import com.hedera.mirror.web3.evm.contracts.execution.traceability.OpcodeTracerOptions;
import com.hedera.mirror.web3.evm.properties.MirrorNodeEvmProperties;
import com.hedera.mirror.web3.evm.store.Store;
import com.hedera.mirror.web3.exception.MirrorEvmTransactionException;
import com.hedera.mirror.web3.repository.ContractActionRepository;
Expand All @@ -43,15 +44,26 @@
public class ContractDebugService extends ContractCallService {
private final ContractActionRepository contractActionRepository;

@SuppressWarnings("java:S107")
public ContractDebugService(
ContractActionRepository contractActionRepository,
RecordFileService recordFileService,
Store store,
MirrorEvmTxProcessor mirrorEvmTxProcessor,
Bucket gasLimitBucket,
ThrottleProperties throttleProperties,
MeterRegistry meterRegistry) {
super(mirrorEvmTxProcessor, gasLimitBucket, throttleProperties, meterRegistry, recordFileService, store);
MeterRegistry meterRegistry,
MirrorNodeEvmProperties mirrorNodeEvmProperties,
TransactionExecutionService transactionExecutionService) {
super(
mirrorEvmTxProcessor,
gasLimitBucket,
throttleProperties,
meterRegistry,
recordFileService,
store,
mirrorNodeEvmProperties,
transactionExecutionService);
this.contractActionRepository = contractActionRepository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.base.Stopwatch;
import com.hedera.mirror.web3.common.ContractCallContext;
import com.hedera.mirror.web3.evm.contracts.execution.MirrorEvmTxProcessor;
import com.hedera.mirror.web3.evm.properties.MirrorNodeEvmProperties;
import com.hedera.mirror.web3.evm.store.Store;
import com.hedera.mirror.web3.service.model.ContractExecutionParameters;
import com.hedera.mirror.web3.service.utils.BinaryGasEstimator;
Expand All @@ -38,15 +39,26 @@ public class ContractExecutionService extends ContractCallService {

private final BinaryGasEstimator binaryGasEstimator;

@SuppressWarnings("java:S107")
public ContractExecutionService(
MeterRegistry meterRegistry,
BinaryGasEstimator binaryGasEstimator,
Store store,
MirrorEvmTxProcessor mirrorEvmTxProcessor,
RecordFileService recordFileService,
ThrottleProperties throttleProperties,
Bucket gasLimitBucket) {
super(mirrorEvmTxProcessor, gasLimitBucket, throttleProperties, meterRegistry, recordFileService, store);
Bucket gasLimitBucket,
MirrorNodeEvmProperties mirrorNodeEvmProperties,
TransactionExecutionService transactionExecutionService) {
super(
mirrorEvmTxProcessor,
gasLimitBucket,
throttleProperties,
meterRegistry,
recordFileService,
store,
mirrorNodeEvmProperties,
transactionExecutionService);
this.binaryGasEstimator = binaryGasEstimator;
}

Expand Down
Loading

0 comments on commit 991f378

Please sign in to comment.