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 @@ -45,6 +45,7 @@ class HtsCallAddressChecksTest {
void detectsParentDelegateCall() {
givenParentFrame();
given(frame.getMessageFrameStack()).willReturn(stack);
given(frame.getRecipientAddress()).willReturn(TestHelpers.NON_SYSTEM_LONG_ZERO_ADDRESS);
given(parentFrame.getContractAddress()).willReturn(TestHelpers.EIP_1014_ADDRESS);
given(parentFrame.getRecipientAddress()).willReturn(TestHelpers.NON_SYSTEM_LONG_ZERO_ADDRESS);
assertTrue(subject.hasParentDelegateCall(frame));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.hedera.node.app.hapi.utils.CommonUtils.asEvmAddress;
import static com.hedera.node.app.service.evm.utils.EthSigsUtils.recoverAddressFromPubKey;
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.HapiPropertySource.asHexedSolidityAddress;
import static com.hedera.services.bdd.spec.HapiPropertySource.asSolidityAddress;
import static com.hedera.services.bdd.spec.HapiSpec.defaultHapiSpec;
Expand Down Expand Up @@ -67,6 +68,7 @@
import static com.hedera.services.bdd.spec.utilops.records.SnapshotMatchMode.NONDETERMINISTIC_FUNCTION_PARAMETERS;
import static com.hedera.services.bdd.spec.utilops.records.SnapshotMatchMode.NONDETERMINISTIC_NONCE;
import static com.hedera.services.bdd.spec.utilops.records.SnapshotMatchMode.NONDETERMINISTIC_TRANSACTION_FEES;
import static com.hedera.services.bdd.suites.contract.Utils.FunctionType.FUNCTION;
import static com.hedera.services.bdd.suites.contract.Utils.aaWith;
import static com.hedera.services.bdd.suites.contract.Utils.asAddress;
import static com.hedera.services.bdd.suites.contract.Utils.asToken;
Expand All @@ -76,14 +78,19 @@
import static com.hedera.services.bdd.suites.contract.precompile.CreatePrecompileSuite.TOKEN_NAME;
import static com.hedera.services.bdd.suites.crypto.AutoCreateUtils.updateSpecFor;
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.MULTI_KEY;
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.hedera.services.bdd.suites.utils.contracts.precompile.HTSPrecompileResult.htsPrecompileResult;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.BUSY;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.CONTRACT_REVERT_EXECUTED;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_PAYER_BALANCE;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_ETHEREUM_TRANSACTION;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_FULL_PREFIX_SIGNATURE_FOR_PRECOMPILE;
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 static org.hyperledger.besu.datatypes.Address.contractAddress;
import static org.hyperledger.besu.datatypes.Address.fromHexString;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -99,6 +106,7 @@
import com.hedera.services.bdd.spec.HapiSpec;
import com.hedera.services.bdd.spec.queries.meta.HapiGetTxnRecord;
import com.hedera.services.bdd.spec.transactions.TxnUtils;
import com.hedera.services.bdd.spec.transactions.contract.HapiParserUtil;
import com.hedera.services.bdd.suites.BddMethodIsNotATest;
import com.hedera.services.bdd.suites.HapiSuite;
import com.hedera.services.bdd.suites.contract.Utils;
Expand Down Expand Up @@ -1174,6 +1182,60 @@ HapiSpec legacyUnprotectedEtxBeforeEIP155WithDefaultChainId() {
.hasPriority(recordWith().status(SUCCESS)))));
}

@HapiTest
final HapiSpec callHtsSystemContractTest() {
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 defaultHapiSpec("callHtsSystemContractTest")
.given(
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.