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

test: Create hapi tests for transfer and send operations for system accounts Part 1 #11359

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.hedera.node.app.service.mono.store.contracts.precompile;

import static com.hedera.node.app.service.evm.utils.ValidationUtils.validateTrue;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;

import com.esaulpaugh.headlong.abi.BigIntegerType;
import com.esaulpaugh.headlong.abi.TypeFactory;
import com.hedera.node.app.service.mono.context.properties.GlobalDynamicProperties;
Expand Down Expand Up @@ -82,6 +85,7 @@ public long gasRequirement(Bytes bytes) {
@Override
public Bytes compute(final Bytes input, final MessageFrame frame) {
try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
tinker-michaelj marked this conversation as resolved.
Show resolved Hide resolved
final var selector = input.getInt(0);
final var amount = biValueFrom(input);
final var activeRate = exchange.activeRate(consensusNow.get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.FAIL_INVALID;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_GAS;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TOKEN_ID;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.NOT_SUPPORTED;

import com.google.common.annotations.VisibleForTesting;
Expand Down Expand Up @@ -313,7 +314,7 @@ void prepareFields(final MessageFrame frame) {
void prepareComputation(Bytes input, final UnaryOperator<byte[]> aliasResolver) {
this.precompile = null;
this.transactionBody = null;

validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
lukelee-sl marked this conversation as resolved.
Show resolved Hide resolved
final int functionId = input.getInt(0);
this.gasRequirement = 0L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.hederahashgraph.api.proto.java.HederaFunctionality.ContractCall;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.FAIL_INVALID;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_GAS;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;

import com.google.common.annotations.VisibleForTesting;
import com.hedera.node.app.service.evm.exceptions.InvalidTransactionException;
Expand Down Expand Up @@ -135,6 +136,7 @@ public PrecompileContractResult computePrecompile(final Bytes input, final Messa
Pair<PrecompileContractResult, ResponseCodeEnum> computePrngResult(
final long gasNeeded, final Bytes input, final MessageFrame frame) {
try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
validateTrue(frame.getRemainingGas() >= gasNeeded, INSUFFICIENT_GAS);
final var randomNum = generatePseudoRandomData(input);
return Pair.of(PrecompiledContract.PrecompileContractResult.success(randomNum), null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.contractsConfigOf;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.proxyUpdaterFor;
import static com.hedera.node.app.service.evm.utils.ValidationUtils.validateTrue;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static java.util.Objects.requireNonNull;

import com.esaulpaugh.headlong.abi.BigIntegerType;
Expand Down Expand Up @@ -57,6 +59,7 @@ public FullResult computeFully(@NonNull Bytes input, @NonNull MessageFrame messa
requireNonNull(input);
requireNonNull(messageFrame);
try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
gasRequirement = contractsConfigOf(messageFrame).precompileExchangeRateGasCost();
final var selector = input.getInt(0);
final var amount = biValueFrom(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asNumberedContractId;
import static com.hedera.node.app.service.contract.impl.utils.SystemContractUtils.contractFunctionResultFailedFor;
import static com.hedera.node.app.service.contract.impl.utils.SystemContractUtils.successResultOf;
import static com.hedera.node.app.service.evm.utils.ValidationUtils.validateTrue;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static java.util.Objects.requireNonNull;

import com.hedera.hapi.node.base.ContractID;
Expand Down Expand Up @@ -71,6 +73,7 @@ public FullResult computeFully(@NonNull final Bytes input, @NonNull final Messag
final HtsCall call;
final HtsCallAttempt attempt;
try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
attempt = callFactory.createCallAttemptFrom(input, frame);
call = requireNonNull(attempt.asExecutableCall());
if (frame.isStatic() && !call.allowsStaticFrame()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import static com.hedera.node.app.service.contract.impl.utils.SystemContractUtils.HTS_PRECOMPILE_MIRROR_ID;
import static com.hedera.node.app.service.contract.impl.utils.SystemContractUtils.contractFunctionResultFailedFor;
import static com.hedera.node.app.service.contract.impl.utils.SystemContractUtils.successResultOfZeroValueTraceable;
import static com.hedera.node.app.service.evm.utils.ValidationUtils.validateTrue;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.FAIL_INVALID;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static java.util.Objects.requireNonNull;
import static org.hyperledger.besu.evm.frame.ExceptionalHaltReason.INVALID_OPERATION;

Expand Down Expand Up @@ -80,6 +82,7 @@ public FullResult computeFully(@NonNull final Bytes input, @NonNull final Messag
final ContractID contractID = asEvmContractId(Address.fromHexString(PRNG_PRECOMPILE_ADDRESS));

try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
// compute the pseudorandom number
final var randomNum = generatePseudoRandomData(input, frame);
requireNonNull(randomNum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class HtsSystemContractTest {
private MockedStatic<FrameUtils> frameUtils;

private HtsSystemContract subject;
private final Bytes validInput = Bytes.fromHexString("91548228");

@BeforeEach
void setUp() {
Expand All @@ -103,15 +104,14 @@ void returnsResultFromImpliedCall() {
given(attempt.senderId()).willReturn(SENDER_ID);
given(frame.getValue()).willReturn(Wei.ZERO);

assertSame(pricedResult.fullResult(), subject.computeFully(Bytes.EMPTY, frame));
assertSame(pricedResult.fullResult(), subject.computeFully(validInput, frame));
}

@Test
void invalidCallAttemptHaltsAndConsumesRemainingGas() {
given(attemptFactory.createCallAttemptFrom(Bytes.EMPTY, frame)).willThrow(RuntimeException.class);

final var expected = haltResult(ExceptionalHaltReason.INVALID_OPERATION, frame.getRemainingGas());
final var result = subject.computeFully(Bytes.EMPTY, frame);
final var result = subject.computeFully(validInput, frame);
assertSamePrecompileResult(expected, result);
}

Expand All @@ -121,6 +121,13 @@ void internalErrorAttemptHaltsAndConsumesRemainingGas() {
given(call.execute(frame)).willThrow(RuntimeException.class);

final var expected = haltResult(ExceptionalHaltReason.PRECOMPILE_ERROR, frame.getRemainingGas());
final var result = subject.computeFully(validInput, frame);
assertSamePrecompileResult(expected, result);
}

@Test
void testComputeFullyWithEmptyBytes() {
final var expected = haltResult(ExceptionalHaltReason.INVALID_OPERATION, frame.getRemainingGas());
final var result = subject.computeFully(Bytes.EMPTY, frame);
assertSamePrecompileResult(expected, result);
}
Expand All @@ -130,7 +137,7 @@ private void givenValidCallAttempt() {
frameUtils.when(() -> proxyUpdaterFor(frame)).thenReturn(updater);
lenient().when(updater.enhancement()).thenReturn(enhancement);
lenient().when(enhancement.systemOperations()).thenReturn(systemOperations);
given(attemptFactory.createCallAttemptFrom(Bytes.EMPTY, frame)).willReturn(attempt);
given(attemptFactory.createCallAttemptFrom(validInput, frame)).willReturn(attempt);
given(attempt.asExecutableCall()).willReturn(call);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@
import static com.hedera.services.bdd.suites.contract.Utils.aaWith;
import static com.hedera.services.bdd.suites.contract.Utils.accountId;
import static com.hedera.services.bdd.suites.contract.Utils.captureOneChildCreate2MetaFor;
import static com.hedera.services.bdd.suites.contract.Utils.mirrorAddrWith;
import static com.hedera.services.bdd.suites.contract.Utils.ocWith;
import static com.hedera.services.bdd.suites.file.FileUpdateSuite.CIVILIAN;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.ACCOUNT_FROZEN_FOR_TOKEN;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.ACCOUNT_KYC_NOT_GRANTED_FOR_TOKEN;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.ACCOUNT_REPEATED_IN_ACCOUNT_AMOUNTS;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.AMOUNT_EXCEEDS_ALLOWANCE;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.CONTRACT_REVERT_EXECUTED;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_SENDER_ACCOUNT_BALANCE_FOR_CUSTOM_FEE;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_TOKEN_BALANCE;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_ACCOUNT_AMOUNTS;
Expand Down Expand Up @@ -243,6 +245,8 @@ public List<HapiSpec> getSpecsInSuite() {
okToRepeatSerialNumbersInWipeList(),
okToRepeatSerialNumbersInBurnList(),
canUseAliasAndAccountCombinations(),
testTransferToSystemAccounts(),
testTransferToSystemAccountsAndCheckSenderBalance(),
transferInvalidTokenIdWithDecimals());
}

Expand Down Expand Up @@ -2116,6 +2120,62 @@ final HapiSpec hapiTransferFromForFungibleTokenWithCustomFeesWithAllowance() {
.then();
}

@HapiTest
final HapiSpec testTransferToSystemAccounts() {
final var contract = "CryptoTransfer";
final var systemAccounts = List.of(359L, 360L, 361L);
final HapiSpecOperation[] opsArray = new HapiSpecOperation[systemAccounts.size() * 3];

for (int i = 0; i < systemAccounts.size(); i++) {
opsArray[i] = contractCall(contract, "sendViaTransfer", mirrorAddrWith(systemAccounts.get(i)))
.payingWith(SENDER)
.sending(ONE_HBAR * 10)
.gas(100000)
.hasKnownStatus(CONTRACT_REVERT_EXECUTED);

opsArray[systemAccounts.size() + i] = contractCall(
contract, "sendViaSend", mirrorAddrWith(systemAccounts.get(i)))
.payingWith(SENDER)
.sending(ONE_HBAR * 10)
.gas(100000)
.hasKnownStatus(CONTRACT_REVERT_EXECUTED);

opsArray[systemAccounts.size() * 2 + i] = contractCall(
contract, "sendViaCall", mirrorAddrWith(systemAccounts.get(i)))
.payingWith(SENDER)
.sending(ONE_HBAR * 10)
.gas(100000)
.hasKnownStatus(CONTRACT_REVERT_EXECUTED);
}

return defaultHapiSpec("testTransferToSystemAccounts", EXPECT_STREAMLINED_INGEST_RECORDS)
.given(
cryptoCreate(SENDER).balance(ONE_HUNDRED_HBARS),
uploadInitCode(contract),
contractCreate(contract))
.when(opsArray)
.then();
}

@HapiTest
final HapiSpec testTransferToSystemAccountsAndCheckSenderBalance() {
final var transferContract = "CryptoTransfer";
final var balanceContract = "BalanceChecker46Version";
final var senderAccount = "detachedSenderAccount";
return defaultHapiSpec("testTransferToSystemAccountsAndCheckSenderBalance", EXPECT_STREAMLINED_INGEST_RECORDS)
.given(
cryptoCreate(senderAccount).balance(ONE_HUNDRED_HBARS),
uploadInitCode(transferContract),
contractCreate(transferContract),
uploadInitCode(balanceContract),
contractCreate(balanceContract))
.when(contractCall(transferContract, "sendViaTransfer", mirrorAddrWith(359L))
.payingWith(senderAccount)
.sending(ONE_HBAR * 10)
.hasKnownStatus(CONTRACT_REVERT_EXECUTED))
.then(getAccountBalance(senderAccount, false).hasTinyBars(9994320000L));
}

@HapiTest
final HapiSpec transferInvalidTokenIdWithDecimals() {
return defaultHapiSpec("transferInvalidTokenIdWithDecimals", FULLY_NONDETERMINISTIC)
Expand Down
Loading
Loading