Skip to content

Commit 6ece601

Browse files
feat: Implement HookEvmFrameState (#21329)
Signed-off-by: Neeharika-Sompalli <[email protected]> Signed-off-by: Michael Tinker <[email protected]> Co-authored-by: Michael Tinker <[email protected]>
1 parent 34ba879 commit 6ece601

File tree

62 files changed

+2126
-1568
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2126
-1568
lines changed

hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/impl/BlockStreamBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,11 @@ public long getNextHookId() {
13081308
return nextHookId;
13091309
}
13101310

1311+
@Override
1312+
public Bytes getEvmCallResult() {
1313+
return requireNonNull(evmTransactionResult).resultData();
1314+
}
1315+
13111316
@Override
13121317
public void nullOutSideEffectFields() {
13131318
serialNumbers.clear();

hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/impl/PairedStreamBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,4 +693,9 @@ public void nextHookId(final long nextHookId) {
693693
public long getNextHookId() {
694694
return blockStreamBuilder.getNextHookId();
695695
}
696+
697+
@Override
698+
public Bytes getEvmCallResult() {
699+
return blockStreamBuilder.getEvmCallResult();
700+
}
696701
}

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/RecordStreamBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,11 @@ public ContractOperationStreamBuilder testForIdenticalKeys(@NonNull final Predic
11231123
return this;
11241124
}
11251125

1126+
@Override
1127+
public Bytes getEvmCallResult() {
1128+
return requireNonNull(contractFunctionResult).contractCallResult();
1129+
}
1130+
11261131
/**
11271132
* Sets the contractStateChanges which are part of sidecar records.
11281133
*

hedera-node/hedera-config/src/main/java/com/hedera/node/config/data/HooksConfig.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
@ConfigData("hooks")
99
public record HooksConfig(
1010
@ConfigProperty(defaultValue = "10") @NetworkProperty int maxLambdaSStoreUpdates,
11-
@ConfigProperty(defaultValue = "false") @NetworkProperty boolean hooksEnabled) {}
11+
@ConfigProperty(defaultValue = "false") @NetworkProperty boolean hooksEnabled,
12+
@ConfigProperty(value = "evm.lambdaIntrinsicGasCost", defaultValue = "1000") @NetworkProperty
13+
int lambdaIntrinsicGasCost) {}

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/QueryModule.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121
import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater;
2222
import com.hedera.node.app.service.contract.impl.hevm.QueryContextHevmBlocks;
2323
import com.hedera.node.app.service.contract.impl.state.EvmFrameStateFactory;
24+
import com.hedera.node.app.service.contract.impl.state.EvmFrameStates;
2425
import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater;
25-
import com.hedera.node.app.service.contract.impl.state.ScopedEvmFrameStateFactory;
2626
import com.hedera.node.app.spi.workflows.QueryContext;
2727
import com.hedera.node.config.data.HederaConfig;
2828
import dagger.Binds;
2929
import dagger.Module;
3030
import dagger.Provides;
3131
import edu.umd.cs.findbugs.annotations.NonNull;
3232
import java.time.Instant;
33+
import org.hyperledger.besu.evm.code.CodeFactory;
3334

3435
@Module
3536
public interface QueryModule {
@@ -102,10 +103,6 @@ static HederaEvmContext provideHederaEvmContext(
102103
null);
103104
}
104105

105-
@Binds
106-
@QueryScope
107-
EvmFrameStateFactory bindEvmFrameStateFactory(ScopedEvmFrameStateFactory factory);
108-
109106
@Binds
110107
@QueryScope
111108
HederaOperations bindHederaOperations(QueryHederaOperations queryExtWorldScope);
@@ -121,4 +118,13 @@ static HederaEvmContext provideHederaEvmContext(
121118
@Binds
122119
@QueryScope
123120
SystemContractOperations bindSystemContractOperations(QuerySystemContractOperations querySystemContractOperations);
121+
122+
@Provides
123+
@QueryScope
124+
static EvmFrameStateFactory provideEvmFrameStateFactory(
125+
@NonNull final CodeFactory codeFactory,
126+
@NonNull final HederaOperations operations,
127+
@NonNull final HederaNativeOperations nativeOperations) {
128+
return EvmFrameStates.DEFAULT.from(operations, nativeOperations, codeFactory);
129+
}
124130
}

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionComponent.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.hedera.node.app.service.contract.impl.annotations.TransactionScope;
66
import com.hedera.node.app.service.contract.impl.exec.scope.HederaOperations;
77
import com.hedera.node.app.service.contract.impl.hevm.HydratedEthTxData;
8+
import com.hedera.node.app.service.contract.impl.state.EvmFrameStates;
89
import com.hedera.node.app.spi.workflows.HandleContext;
910
import dagger.BindsInstance;
1011
import dagger.Subcomponent;
@@ -16,7 +17,9 @@ public interface TransactionComponent {
1617
@Subcomponent.Factory
1718
interface Factory {
1819
TransactionComponent create(
19-
@BindsInstance HandleContext context, @BindsInstance HederaFunctionality functionality);
20+
@BindsInstance HandleContext context,
21+
@BindsInstance HederaFunctionality functionality,
22+
@BindsInstance EvmFrameStates evmFrameStates);
2023
}
2124

2225
ContextTransactionProcessor contextTransactionProcessor();

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionConfigModule.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.hedera.node.config.data.ContractsConfig;
1010
import com.hedera.node.config.data.EntitiesConfig;
1111
import com.hedera.node.config.data.HederaConfig;
12+
import com.hedera.node.config.data.HooksConfig;
1213
import com.hedera.node.config.data.LedgerConfig;
1314
import com.hedera.node.config.data.StakingConfig;
1415
import com.swirlds.config.api.Configuration;
@@ -42,6 +43,12 @@ static LedgerConfig provideLedgerConfig(@NonNull final Configuration configurati
4243
return requireNonNull(configuration).getConfigData(LedgerConfig.class);
4344
}
4445

46+
@Provides
47+
@TransactionScope
48+
static HooksConfig provideHooksConfig(@NonNull final Configuration configuration) {
49+
return requireNonNull(configuration).getConfigData(HooksConfig.class);
50+
}
51+
4552
@Provides
4653
@TransactionScope
4754
static StakingConfig provideStakingConfig(@NonNull final Configuration configuration) {

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionModule.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import com.hedera.node.app.service.contract.impl.infra.EthereumCallDataHydration;
3535
import com.hedera.node.app.service.contract.impl.records.ContractOperationStreamBuilder;
3636
import com.hedera.node.app.service.contract.impl.state.EvmFrameStateFactory;
37-
import com.hedera.node.app.service.contract.impl.state.ScopedEvmFrameStateFactory;
37+
import com.hedera.node.app.service.contract.impl.state.EvmFrameStates;
3838
import com.hedera.node.app.service.file.ReadableFileStore;
3939
import com.hedera.node.app.spi.info.NetworkInfo;
4040
import com.hedera.node.app.spi.validation.AttributeValidator;
@@ -52,6 +52,7 @@
5252
import edu.umd.cs.findbugs.annotations.Nullable;
5353
import java.time.Instant;
5454
import java.util.Map;
55+
import org.hyperledger.besu.evm.code.CodeFactory;
5556

5657
@Module(includes = {TransactionConfigModule.class, TransactionInitialStateModule.class})
5758
public interface TransactionModule {
@@ -209,10 +210,6 @@ static HederaWorldUpdater.Enhancement provideEnhancement(
209210
return new HederaWorldUpdater.Enhancement(operations.begin(), nativeOperations, systemContractOperations);
210211
}
211212

212-
@Binds
213-
@TransactionScope
214-
EvmFrameStateFactory bindEvmFrameStateFactory(ScopedEvmFrameStateFactory factory);
215-
216213
@Binds
217214
@TransactionScope
218215
HederaOperations bindHederaOperations(HandleHederaOperations handleExtWorldScope);
@@ -229,4 +226,17 @@ SystemContractOperations bindSystemContractOperations(
229226
@Binds
230227
@TransactionScope
231228
HederaEvmBlocks bindHederaEvmBlocks(HandleContextHevmBlocks handleContextHevmBlocks);
229+
230+
@Provides
231+
@TransactionScope
232+
static EvmFrameStateFactory provideEvmFrameStateFactory(
233+
@NonNull final EvmFrameStates evmFrameStates,
234+
@NonNull final CodeFactory codeFactory,
235+
@NonNull final HederaOperations operations,
236+
@NonNull final HederaNativeOperations nativeOperations) {
237+
// If this EVM tx is for a hook, the factory returned here will
238+
// create "hook-aware" EvmFrameState's that e.g. return the executing
239+
// hook contract's bytecode from address 0x16d
240+
return evmFrameStates.from(operations, nativeOperations, codeFactory);
241+
}
232242
}

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionProcessor.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.hedera.hapi.node.base.AccountID;
1919
import com.hedera.hapi.node.contract.ContractCreateTransactionBody;
2020
import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCharging;
21+
import com.hedera.node.app.service.contract.impl.exec.gas.GasCharges;
2122
import com.hedera.node.app.service.contract.impl.exec.processors.CustomMessageCallProcessor;
2223
import com.hedera.node.app.service.contract.impl.exec.utils.FrameBuilder;
2324
import com.hedera.node.app.service.contract.impl.exec.utils.OpsDurationCounter;
@@ -124,8 +125,10 @@ private HederaEvmTransactionResult processTransactionWithParties(
124125
@NonNull final Configuration config,
125126
@NonNull final OpsDurationCounter opsDurationCounter,
126127
@NonNull final InvolvedParties parties) {
127-
final var gasCharges =
128-
gasCharging.chargeForGas(parties.sender(), parties.relayer(), context, updater, transaction);
128+
// If it is hook dispatch, skip gas charging because gas is pre-paid in cryptoTransfer already
129+
final var gasCharges = transaction.isHookDispatch()
130+
? GasCharges.NONE
131+
: gasCharging.chargeForGas(parties.sender(), parties.relayer(), context, updater, transaction);
129132
final var initialFrame = frameBuilder.buildInitialFrameWith(
130133
transaction,
131134
updater,
@@ -142,14 +145,18 @@ private HederaEvmTransactionResult processTransactionWithParties(
142145
final var result = frameRunner.runToCompletion(
143146
transaction.gasLimit(), parties.senderId(), initialFrame, tracer, messageCall, contractCreation);
144147

145-
// Maybe refund some of the charged fees before committing
146-
gasCharging.maybeRefundGiven(
147-
transaction.unusedGas(result.gasUsed()),
148-
gasCharges.relayerAllowanceUsed(),
149-
parties.sender(),
150-
parties.relayer(),
151-
context,
152-
updater);
148+
// Maybe refund some of the charged fees before committing if not a hook dispatch
149+
// Note that for hook dispatch, gas is charged during cryptoTransfer and will not be refunded once
150+
// hook is executed
151+
if (!transaction.isHookDispatch()) {
152+
gasCharging.maybeRefundGiven(
153+
transaction.unusedGas(result.gasUsed()),
154+
gasCharges.relayerAllowanceUsed(),
155+
parties.sender(),
156+
parties.relayer(),
157+
context,
158+
updater);
159+
}
153160
initialFrame.getSelfDestructs().forEach(updater::deleteAccount);
154161

155162
// Tries to commit and return the original result; returns a fees-only result on resource exhaustion

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/gas/GasCharges.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55
* @param intrinsicGas the intrinsic gas cost of a transaction
66
* @param relayerAllowanceUsed the gas for the relayer
77
*/
8-
public record GasCharges(long intrinsicGas, long relayerAllowanceUsed) {}
8+
public record GasCharges(long intrinsicGas, long relayerAllowanceUsed) {
9+
// A constant representing no gas charges.
10+
// A hook dispatch has no gas charges, because all gas is charged prior in crypto transfer.
11+
public static final GasCharges NONE = new GasCharges(0L, 0L);
12+
}

0 commit comments

Comments
 (0)