Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add check for parent's existence when checking delegate call #13013

Merged
merged 11 commits into from
May 2, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public HtsCallAddressChecks() {
* @return true if the frame's parent is a delegate call
*/
public boolean hasParentDelegateCall(@NonNull final MessageFrame frame) {
return isDelegateCall(parentOf(frame));
return frame.getMessageFrameStack().size() > 1 && isDelegateCall(parentOf(frame));
lukelee-sl marked this conversation as resolved.
Show resolved Hide resolved
}

private MessageFrame parentOf(@NonNull final MessageFrame frame) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.hedera.services.bdd.suites.leaky;

import static com.hedera.services.bdd.junit.TestTags.SMART_CONTRACT;
import static com.hedera.services.bdd.spec.HapiPropertySource.asContractIdWithEvmAddress;
import static com.hedera.services.bdd.spec.HapiSpec.propertyPreservingHapiSpec;
import static com.hedera.services.bdd.spec.assertions.TransactionRecordAsserts.recordWith;
import static com.hedera.services.bdd.spec.keys.KeyFactory.KeyType.THRESHOLD;
Expand All @@ -25,21 +26,37 @@
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.cryptoCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.cryptoTransfer;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.ethereumCall;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.ethereumCallWithFunctionAbi;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.tokenAssociate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.tokenCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.uploadInitCode;
import static com.hedera.services.bdd.spec.transactions.contract.HapiParserUtil.asHeadlongAddress;
import static com.hedera.services.bdd.spec.transactions.crypto.HapiCryptoTransfer.tinyBarsFromAccountToAlias;
import static com.hedera.services.bdd.spec.transactions.token.TokenMovement.moving;
import static com.hedera.services.bdd.spec.utilops.CustomSpecAssert.allRunFor;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.overriding;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.resetToDefault;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.withOpContext;
import static com.hedera.services.bdd.spec.utilops.records.SnapshotMatchMode.NONDETERMINISTIC_CONTRACT_CALL_RESULTS;
import static com.hedera.services.bdd.spec.utilops.records.SnapshotMatchMode.NONDETERMINISTIC_ETHEREUM_DATA;
import static com.hedera.services.bdd.suites.contract.Utils.FunctionType.FUNCTION;
import static com.hedera.services.bdd.suites.contract.Utils.asAddress;
import static com.hedera.services.bdd.suites.contract.Utils.getABIFor;
import static com.hedera.services.bdd.suites.crypto.CryptoCreateSuite.ACCOUNT;
import static com.hedera.services.bdd.suites.leaky.LeakyContractTestsSuite.RECEIVER;
import static com.hedera.services.bdd.suites.token.TokenAssociationSpecs.VANILLA_TOKEN;
import static com.hedera.services.bdd.suites.token.TokenTransactSpecs.SUPPLY_KEY;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.SUCCESS;
import static com.hederahashgraph.api.proto.java.TokenType.FUNGIBLE_COMMON;
import static com.swirlds.common.utility.CommonUtils.unhex;

import com.google.protobuf.ByteString;
import com.hedera.node.app.hapi.utils.ethereum.EthTxData.EthTransactionType;
import com.hedera.services.bdd.junit.HapiTest;
import com.hedera.services.bdd.junit.HapiTestSuite;
import com.hedera.services.bdd.spec.HapiSpec;
import com.hedera.services.bdd.spec.transactions.contract.HapiParserUtil;
import com.hedera.services.bdd.suites.HapiSuite;
import com.hederahashgraph.api.proto.java.ResponseCodeEnum;
import java.math.BigInteger;
Expand All @@ -57,6 +74,11 @@ public class LeakyEthereumTestsSuite extends HapiSuite {
private static final String PAY_RECEIVABLE_CONTRACT = "PayReceivable";
private static final Logger log = LogManager.getLogger(LeakyEthereumTestsSuite.class);

private static final String EVM_VERSION_PROPERTY = "contracts.evm.version";
private static final String ALLOW_CALLS_TO_NON_CONTRACT_ACCOUNTS = "contracts.evm.allowCallsToNonContractAccounts";
private static final String DYNAMIC_EVM_PROPERTY = "contracts.evm.version.dynamic";
private static final String EVM_VERSION_050 = "v0.50";

public static void main(String... args) {
new LeakyEthereumTestsSuite().runSuiteAsync();
}
Expand All @@ -68,7 +90,7 @@ public boolean canRunConcurrent() {

@Override
public List<HapiSpec> getSpecsInSuite() {
return Stream.of(legacyUnprotectedEtxBeforeEIP155(), legacyEtxAfterEIP155())
return Stream.of(legacyUnprotectedEtxBeforeEIP155(), legacyEtxAfterEIP155(), callHtsSystemContractTest())
.toList();
}

Expand Down Expand Up @@ -166,6 +188,64 @@ HapiSpec legacyEtxAfterEIP155() {
resetToDefault(CHAIN_ID_PROP));
}

@HapiTest
final HapiSpec callHtsSystemContractTest() {
lukelee-sl marked this conversation as resolved.
Show resolved Hide resolved
final var callHtsSystemContractTxn = "callHtsSystemContractTxn";
final var function = getABIFor(FUNCTION, "transferToken", "IHederaTokenService");
final var HTS_SYSTEM_CONTRACT = "hts";
final var HTS_SYSTEM_CONTRACT_ADDRESS = "0000000000000000000000000000000000000167";

return propertyPreservingHapiSpec("callHtsSystemContractTest")
.preserving(EVM_VERSION_PROPERTY, DYNAMIC_EVM_PROPERTY)
.given(
overriding(DYNAMIC_EVM_PROPERTY, "true"),
overriding(EVM_VERSION_PROPERTY, EVM_VERSION_050),
overriding(ALLOW_CALLS_TO_NON_CONTRACT_ACCOUNTS, "true"),
lukelee-sl marked this conversation as resolved.
Show resolved Hide resolved
newKeyNamed(SECP_256K1_SOURCE_KEY).shape(SECP_256K1_SHAPE),
newKeyNamed(SUPPLY_KEY),
cryptoTransfer(tinyBarsFromAccountToAlias(GENESIS, SECP_256K1_SOURCE_KEY, ONE_HUNDRED_HBARS)),
cryptoCreate(RELAYER).balance(6 * ONE_MILLION_HBARS),
cryptoCreate(ACCOUNT).balance(6 * ONE_MILLION_HBARS),
cryptoCreate(TOKEN_TREASURY),
cryptoCreate(RECEIVER),
tokenCreate(VANILLA_TOKEN)
.tokenType(FUNGIBLE_COMMON)
.treasury(TOKEN_TREASURY)
.supplyKey(SUPPLY_KEY)
.initialSupply(1_000),
tokenAssociate(ACCOUNT, VANILLA_TOKEN),
tokenAssociate(RECEIVER, VANILLA_TOKEN),
cryptoTransfer(moving(500, VANILLA_TOKEN).between(TOKEN_TREASURY, ACCOUNT)))
.when(withOpContext((spec, opLog) -> {
final var receiver1 =
asHeadlongAddress(asAddress(spec.registry().getAccountID(RECEIVER)));
final var sender =
asHeadlongAddress(asAddress(spec.registry().getAccountID(ACCOUNT)));

spec.registry()
.saveContractId(
HTS_SYSTEM_CONTRACT,
asContractIdWithEvmAddress(
ByteString.copyFrom(unhex(HTS_SYSTEM_CONTRACT_ADDRESS))));
allRunFor(
spec,
ethereumCallWithFunctionAbi(
false,
HTS_SYSTEM_CONTRACT,
function,
HapiParserUtil.asHeadlongAddress(
asAddress(spec.registry().getTokenID(VANILLA_TOKEN))),
sender,
receiver1,
1L)
.payingWith(RELAYER)
.type(EthTransactionType.EIP1559)
.via(callHtsSystemContractTxn)
.hasKnownStatus(SUCCESS));
}))
.then();
}

@Override
protected Logger getResultsLogger() {
return log;
Expand Down

Large diffs are not rendered by default.