Skip to content

Commit

Permalink
fix: Exchange rate precompile return error when called with value #13052
Browse files Browse the repository at this point in the history
 (#13053)

Signed-off-by: Stefan Stefanov <stefan.stefanooov@gmail.com>
  • Loading branch information
stefan-stefanooov committed May 13, 2024
1 parent 9f5c168 commit 4e9d1c5
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
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_FEE_SUBMITTED;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static java.util.Objects.requireNonNull;

import com.esaulpaugh.headlong.abi.BigIntegerType;
import com.esaulpaugh.headlong.abi.TypeFactory;
import com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason;
import com.hedera.node.app.service.contract.impl.utils.ConversionUtils;
import com.hedera.node.app.service.evm.exceptions.InvalidTransactionException;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.math.BigInteger;
import java.util.Optional;
Expand Down Expand Up @@ -60,6 +63,7 @@ public FullResult computeFully(@NonNull Bytes input, @NonNull MessageFrame messa
requireNonNull(messageFrame);
try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
validateTrue(messageFrame.getValue().getAsBigInteger().equals(BigInteger.ZERO), INVALID_FEE_SUBMITTED);
gasRequirement = contractsConfigOf(messageFrame).precompileExchangeRateGasCost();
final var selector = input.getInt(0);
final var amount = biValueFrom(input);
Expand All @@ -74,7 +78,17 @@ public FullResult computeFully(@NonNull Bytes input, @NonNull MessageFrame messa
};
requireNonNull(result);
return new FullResult(PrecompileContractResult.success(result), gasRequirement, null);
} catch (Exception ignore) {
} catch (InvalidTransactionException e) {
ExceptionalHaltReason haltReason;
if (e.getResponseCode() == INVALID_FEE_SUBMITTED) {
haltReason = CustomExceptionalHaltReason.INVALID_FEE_SUBMITTED;
} else {
haltReason = ExceptionalHaltReason.INVALID_OPERATION;
}

return new FullResult(
PrecompileContractResult.halt(Bytes.EMPTY, Optional.of(haltReason)), gasRequirement, null);
} catch (Exception e) {
return new FullResult(
PrecompileContractResult.halt(Bytes.EMPTY, Optional.of(ExceptionalHaltReason.INVALID_OPERATION)),
gasRequirement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public FullResult computeFully(@NonNull final Bytes input, @NonNull final Messag
PrecompiledContract.PrecompileContractResult.halt(Bytes.EMPTY, Optional.of(INVALID_OPERATION)),
gasRequirement,
null);
} catch (NullPointerException e) {
} catch (Exception e) {
// Log a warning as this error will be caused by insufficient entropy
log.warn("Internal precompile failure", e);
createFailedRecord(frame, FAIL_INVALID, contractID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import com.google.common.primitives.Longs;
import com.hedera.hapi.node.transaction.ExchangeRate;
import com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.ExchangeRateSystemContract;
import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils;
import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater;
Expand All @@ -34,6 +35,7 @@
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
Expand Down Expand Up @@ -80,6 +82,7 @@ void closeMocks() {

@Test
void convertsPositiveNumberToTinybarsAsExpected() {
given(frame.getValue()).willReturn(Wei.ZERO);
givenRate(someRate);

final var someInput = tinycentsInput(someTinycentAmount);
Expand All @@ -90,6 +93,7 @@ void convertsPositiveNumberToTinybarsAsExpected() {

@Test
void convertsPositiveNumberToTinycentsAsExpected() {
given(frame.getValue()).willReturn(Wei.ZERO);
givenRate(someRate);

final var positiveInput = tinybarsInput(someTinybarAmount);
Expand All @@ -100,6 +104,7 @@ void convertsPositiveNumberToTinycentsAsExpected() {

@Test
void convertsZeroToTinybarsAsExpected() {
given(frame.getValue()).willReturn(Wei.ZERO);
givenRate(someRate);

final var zeroInput = tinycentsInput(0);
Expand All @@ -118,6 +123,17 @@ void inputCannotUnderflow() {
assertThat(result.result().getHaltReason().get()).isEqualTo(ExceptionalHaltReason.INVALID_OPERATION);
}

@Test
void valueShouldNotBeSentToThePrecompile() {
given(frame.getValue()).willReturn(Wei.MAX_WEI);

final var zeroInput = tinycentsInput(0);
final var result = subject.computeFully(zeroInput, frame);

assertThat(result.output()).isEqualTo(Bytes.EMPTY);
assertThat(result.result().getHaltReason().get()).isEqualTo(CustomExceptionalHaltReason.INVALID_FEE_SUBMITTED);
}

@Test
void selectorMustBeFullyPresent() {
final var fragmentSelector = Bytes.of(0xab);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,12 @@ final HapiSpec exchangeRatePrecompileWorks() {
.logged(),
sourcing(() -> contractCall(rateAware, "invalidCall")
.sending(minValueToAccessGatedMethodAtCurrentRate.get())
.hasKnownStatus(CONTRACT_REVERT_EXECUTED)),
sourcing(() -> contractCall(
rateAware,
"callWithValue",
BigInteger.valueOf(minValueToAccessGatedMethodAtCurrentRate.get()))
.sending(minValueToAccessGatedMethodAtCurrentRate.get())
.hasKnownStatus(CONTRACT_REVERT_EXECUTED)));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
608060405234801561001057600080fd5b506040516106503803806106508339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61059a806100b66000396000f3fe6080604052600436106100345760003560e01c806303b636e61461003957806389dea1d014610043578063bff4f54f1461004d575b600080fd5b61004161006b565b005b61004b610154565b005b61005561018a565b60405161006291906103d1565b60405180910390f35b60008061016873ffffffffffffffffffffffffffffffffffffffff1663bff4f54f60e01b604051602401604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516100ff9190610466565b6000604051808303816000865af19150503d806000811461013c576040519150601f19603f3d011682016040523d82523d6000602084013e610141565b606091505b50915091508161015057600080fd5b5050565b60005460006305f5e1008261016991906104ac565b905060006101768261019a565b90508034101561018557600080fd5b505050565b6000610195346102a9565b905090565b600080600061016873ffffffffffffffffffffffffffffffffffffffff16632e3cff6a60e01b856040516024016101d191906103d1565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161023b9190610466565b6000604051808303816000865af19150503d8060008114610278576040519150601f19603f3d011682016040523d82523d6000602084013e61027d565b606091505b50915091508161028c57600080fd5b808060200190518101906102a09190610537565b92505050919050565b600080600061016873ffffffffffffffffffffffffffffffffffffffff166343a8822960e01b856040516024016102e091906103d1565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161034a9190610466565b6000604051808303816000865af19150503d8060008114610387576040519150601f19603f3d011682016040523d82523d6000602084013e61038c565b606091505b50915091508161039b57600080fd5b808060200190518101906103af9190610537565b92505050919050565b6000819050919050565b6103cb816103b8565b82525050565b60006020820190506103e660008301846103c2565b92915050565b600081519050919050565b600081905092915050565b60005b83811015610420578082015181840152602081019050610405565b8381111561042f576000848401525b50505050565b6000610440826103ec565b61044a81856103f7565b935061045a818560208601610402565b80840191505092915050565b60006104728284610435565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006104b7826103b8565b91506104c2836103b8565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156104fb576104fa61047d565b5b828202905092915050565b600080fd5b610514816103b8565b811461051f57600080fd5b50565b6000815190506105318161050b565b92915050565b60006020828403121561054d5761054c610506565b5b600061055b84828501610522565b9150509291505056fea26469706673582212209dd36ad26d305d7a60354b6e84fa8424f3555a41d74121cdadc47dfc040a11d664736f6c63430008090033
608060405234801561000f575f80fd5b5060405161041938038061041983398101604081905261002e91610035565b5f5561004c565b5f60208284031215610045575f80fd5b5051919050565b6103c0806100595f395ff3fe60806040526004361061003e575f3560e01c806303b636e6146100425780633f39929f1461004c57806389dea1d01461005f578063bff4f54f14610067575b5f80fd5b61004a610081565b005b61004a61005a366004610307565b61010c565b61004a610118565b61006f610149565b60405190815260200160405180910390f35b60408051600481526024810182526020810180516001600160e01b031663bff4f54f60e01b17905290515f918291610168916100bc9161031e565b5f604051808303815f865af19150503d805f81146100f5576040519150601f19603f3d011682016040523d82523d5f602084013e6100fa565b606091505b509150915081610108575f80fd5b5050565b61011581610158565b50565b5f80549061012a6305f5e1008361034a565b90505f6101368261020d565b905080341015610144575f80fd5b505050565b5f610153346102dd565b905090565b5f806101686001600160a01b0316346343a8822960e01b8560405160240161018291815260200190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516101c0919061031e565b5f6040518083038185875af1925050503d805f81146101fa576040519150601f19603f3d011682016040523d82523d5f602084013e6101ff565b606091505b509150915081610144575f80fd5b5f805f6101686001600160a01b0316632e3cff6a60e01b8560405160240161023791815260200190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610275919061031e565b5f604051808303815f865af19150503d805f81146102ae576040519150601f19603f3d011682016040523d82523d5f602084013e6102b3565b606091505b5091509150816102c1575f80fd5b808060200190518101906102d59190610373565b949350505050565b5f805f6101686001600160a01b03166343a8822960e01b8560405160240161023791815260200190565b5f60208284031215610317575f80fd5b5035919050565b5f82515f5b8181101561033d5760208186018101518583015201610323565b505f920191825250919050565b808202811582820484141761036d57634e487b7160e01b5f52601160045260245ffd5b92915050565b5f60208284031215610383575f80fd5b505191905056fea2646970667358221220fbb1848818142a7e5b6f1a743d4ea51e969fba3350e33fa6541dc8fe34b198a264736f6c63430008180033
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
[{"inputs":[{"internalType":"uint256","name":"_toll","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"approxUsdValue","outputs":[{"internalType":"uint256","name":"tinycents","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gatedAccess","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"invalidCall","outputs":[],"stateMutability":"payable","type":"function"}]
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_toll",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "approxUsdValue",
"outputs": [
{
"internalType": "uint256",
"name": "tinycents",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "callWithValue",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "gatedAccess",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "invalidCall",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
]
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.5.0 <0.9.0;

import "./SelfFunding.sol";

Expand All @@ -18,6 +19,10 @@ contract ExchangeRatePrecompile is SelfFunding {
tinycents = tinybarsToTinycents(msg.value);
}

function callWithValue(uint256 _value) external payable {
callToPrecompileWithValue(_value);
}

function invalidCall() external payable {
// Should fail, this is not a valid selector
(bool success, bytes memory result) = PRECOMPILE_ADDRESS.call(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ abstract contract SelfFunding {
tinycents = abi.decode(result, (uint256));
}

function callToPrecompileWithValue(uint256 tinybars) internal {
(bool success, bytes memory result) = PRECOMPILE_ADDRESS.call{value: msg.value}(
abi.encodeWithSelector(IExchangeRate.tinybarsToTinycents.selector, tinybars));
require(success);
}

modifier costsCents(uint256 cents) {
uint256 tinycents = cents * TINY_PARTS_PER_WHOLE;
uint256 requiredTinybars = tinycentsToTinybars(tinycents);
Expand Down

0 comments on commit 4e9d1c5

Please sign in to comment.