Skip to content

Commit

Permalink
chore: cherry pick #11013 (#11025)
Browse files Browse the repository at this point in the history
transform evm v46 checks to prechecks

Signed-off-by: nikolay <n.atanasow94@gmail.com>
Signed-off-by: lukelee-sl <luke.lee@swirldslabs.com>
Co-authored-by: Nikolay Atanasow <n.atanasow94@gmail.com>
  • Loading branch information
lukelee-sl and natanasow authored Jan 18, 2024
1 parent 2369888 commit c963b4a
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public void doStateTransitionOperation(
final var sender = accountStore.loadAccount(senderId);
final var target = targetOf(op);

Account receiver = extractAndValidateReceiver(op, target, relayerId);
Account receiver = extractAndValidateReceiver(op, target, relayerId != null, true);

final var callData = !op.getFunctionParameters().isEmpty()
? Bytes.wrap(op.getFunctionParameters().toByteArray())
Expand Down Expand Up @@ -212,7 +212,45 @@ public Function<TransactionBody, ResponseCodeEnum> semanticCheck() {
return this::validateSemantics;
}

private ResponseCodeEnum validateSemantics(final TransactionBody transactionBody) {
public Function<TransactionBody, ResponseCodeEnum> semanticEthCheck() {
return this::validateEthSemantics;
}

private ResponseCodeEnum validateSemantics(final TransactionBody txBody) {
final var op = txBody.getContractCall();

final var commonSemanticsResult = validateSemanticsCommon(txBody);
if (commonSemanticsResult != OK) {
return commonSemanticsResult;
}

try {
extractAndValidateReceiver(op, targetOf(op), false, false);
} catch (InvalidTransactionException e) {
return e.getResponseCode();
}

return OK;
}

private ResponseCodeEnum validateEthSemantics(final TransactionBody txBody) {
final var op = txBody.getContractCall();

final var commonSemanticsResult = validateSemanticsCommon(txBody);
if (commonSemanticsResult != OK) {
return commonSemanticsResult;
}

try {
extractAndValidateReceiver(op, targetOf(op), true, false);
} catch (InvalidTransactionException e) {
return e.getResponseCode();
}

return OK;
}

private ResponseCodeEnum validateSemanticsCommon(final TransactionBody transactionBody) {
var op = transactionBody.getContractCall();

if (op.getGas()
Expand Down Expand Up @@ -282,7 +320,10 @@ private EntityNum targetOf(final ContractCallTransactionBody op) {
}

private Account extractAndValidateReceiver(
ContractCallTransactionBody op, final EntityNum unaliasedTargetNum, final Id relayerId) {
ContractCallTransactionBody op,
final EntityNum unaliasedTargetNum,
final boolean isEthTx,
final boolean isHandle) {

final var unaliasedTargetId = unaliasedTargetNum.toId();
final var targetAliasIsMissing = unaliasedTargetNum.equals(EntityNum.MISSING_NUM);
Expand All @@ -299,15 +340,17 @@ private Account extractAndValidateReceiver(
if (!targetAliasIsMissing) {

if (op.getAmount() > 0) {
// Since contracts cannot have receiverSigRequired=true, this can only
// restrict us from sending value to an EOA
final var sigReqIsMet = sigsVerifier.hasActiveKeyOrNoReceiverSigReq(
false,
unaliasedTargetNum.toEvmAddress(),
NEVER_ACTIVE_CONTRACT_ADDRESS,
worldLedgers,
ContractCall);
validateTrue(sigReqIsMet, INVALID_SIGNATURE);
if (isHandle) {
// Since contracts cannot have receiverSigRequired=true, this can only
// restrict us from sending value to an EOA
final var sigReqIsMet = sigsVerifier.hasActiveKeyOrNoReceiverSigReq(
false,
unaliasedTargetNum.toEvmAddress(),
NEVER_ACTIVE_CONTRACT_ADDRESS,
worldLedgers,
ContractCall);
validateTrue(sigReqIsMet, INVALID_SIGNATURE);
}
validateTrue(!isSystemAccount, INVALID_FEE_SUBMITTED);
validateTrue(
entityAccess.isExtant(unaliasedTargetNum.toEvmAddress())
Expand Down Expand Up @@ -340,7 +383,7 @@ private Account extractAndValidateReceiver(
// lazy create flow
if (op.getAmount() > 0) {
// do not permit lazy creation from non-ethereum transaction
validateTrue(relayerId != null, INVALID_FEE_SUBMITTED);
validateTrue(isEthTx, INVALID_FEE_SUBMITTED);
// do not permit lazy creation in EVM version v030
validateTrue(!properties.evmVersion().equals(EVM_VERSION_0_30), INVALID_SOLIDITY_ADDRESS);
// do not permit lazy creation of mirror address
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2023 Hedera Hashgraph, LLC
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -166,7 +166,7 @@ public ResponseCodeEnum validateSemantics(final TxnAccessor accessor) {
txn = isPrecheck ? syntheticTxnFactory.synthPrecheckContractOpFromEth(ethTxData) : INVALID_SYNTH_BODY;
}
if (txn.hasContractCall()) {
return contractCallTransitionLogic.semanticCheck().apply(txn);
return contractCallTransitionLogic.semanticEthCheck().apply(txn);
} else if (txn.hasContractCreateInstance()) {
return contractCreateTransitionLogic.semanticCheck().apply(txn);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,8 @@ void acceptsOkSyntax() {
given(properties.maxGasPerSec()).willReturn(gas + 1);
given(properties.callsToNonExistingEntitiesEnabled(any())).willReturn(true);
contractAccount.setSmartContract(true);
given(entityAccess.isExtant(any())).willReturn(true);

// expect:
assertEquals(OK, subject.semanticCheck().apply(contractCallTxn));
}
Expand All @@ -797,6 +799,7 @@ void acceptsOkSyntaxIfTokenAddress() {
givenValidTxnCtx();
given(properties.callsToNonExistingEntitiesEnabled(any())).willReturn(true);
given(properties.maxGasPerSec()).willReturn(gas + 1);
given(entityAccess.isExtant(any())).willReturn(true);
// expect:
assertEquals(OK, subject.semanticCheck().apply(contractCallTxn));
}
Expand All @@ -807,9 +810,12 @@ void acceptsOkSyntaxIfPossibleLazyCreate() {
given(properties.callsToNonExistingEntitiesEnabled(any())).willReturn(true);
given(properties.maxGasPerSec()).willReturn(gas + 1);
given(aliasManager.lookupIdBy(alias)).willReturn(EntityNum.MISSING_NUM);
given(properties.evmVersion()).willReturn(EVM_VERSION_0_34);
given(properties.isAutoCreationEnabled()).willReturn(true);
given(properties.isLazyCreationEnabled()).willReturn(true);

// expect:
assertEquals(OK, subject.semanticCheck().apply(contractCallTxn));
assertEquals(OK, subject.semanticEthCheck().apply(contractCallTxn));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2023 Hedera Hashgraph, LLC
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -273,7 +273,7 @@ void hasCallValidityIfReasonableCall() {
givenReasonableSemantics();
given(spanMapAccessor.getEthTxBodyMeta(accessor)).willReturn(callTxn);
given(semanticCheck.apply(callTxn)).willReturn(INVALID_ACCOUNT_ID);
given(contractCallTransitionLogic.semanticCheck()).willReturn(semanticCheck);
given(contractCallTransitionLogic.semanticEthCheck()).willReturn(semanticCheck);

assertEquals(INVALID_ACCOUNT_ID, subject.validateSemantics(accessor));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ HapiSpec topLevelBurnToZeroAddressReverts() {
.maxFeePerGas(50L)
.maxPriorityGas(2L)
.gasLimit(1_000_000L)
.hasKnownStatus(INVALID_SOLIDITY_ADDRESS));
.hasPrecheck(INVALID_SOLIDITY_ADDRESS));
}

@HapiTest
Expand All @@ -500,7 +500,7 @@ HapiSpec topLevelLazyCreateOfMirrorAddressReverts() {
.maxFeePerGas(50L)
.maxPriorityGas(2L)
.gasLimit(1_000_000L)
.hasKnownStatusFrom(INVALID_CONTRACT_ID, CONTRACT_EXECUTION_EXCEPTION));
.hasPrecheckFrom(INVALID_CONTRACT_ID, CONTRACT_EXECUTION_EXCEPTION));
}

@HapiTest
Expand Down Expand Up @@ -528,7 +528,7 @@ HapiSpec topLevelSendToReceiverSigRequiredAccountReverts() {
.maxFeePerGas(50L)
.maxPriorityGas(2L)
.gasLimit(1_000_000L)
.hasKnownStatus(INVALID_SIGNATURE)))
.hasPrecheck(INVALID_SIGNATURE)))
.then(getAccountBalance(receiverSigAccount).hasTinyBars(changeFromSnapshot(preCallBalance, 0L)));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2905,21 +2905,8 @@ HapiSpec callToNonExistingContractFailsGracefully() {
.nonce(0)
.gasPrice(0L)
.gasLimit(1_000_000L)
.hasKnownStatus(INVALID_CONTRACT_ID))))
.then(withOpContext((spec, opLog) -> allRunFor(
spec,
getTxnRecord("invalidContractCallTxn")
.hasPriority(recordWith()
.contractCallResult(resultWith()
.error(Bytes.of(INVALID_CONTRACT_ID
.name()
.getBytes())
.toHexString())
.senderId(spec.registry()
.getAccountID(spec.registry()
.aliasIdFor(SECP_256K1_SOURCE_KEY)
.getAlias()
.toStringUtf8())))))));
.hasPrecheck(INVALID_CONTRACT_ID))))
.then();
}

@HapiTest
Expand Down

0 comments on commit c963b4a

Please sign in to comment.