From 9bf00f7012c991fb026b525d2f47ff1c016a4f04 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Tue, 4 Feb 2025 17:38:33 +0000 Subject: [PATCH 1/5] Fix e2e tests on alfajores The explicit gas fields test was failing due to having too low a gas price. This was likely because the test was using the base fee from the last block as the base fee, and the tip was small enough that when converted to fee currency it was 0. To prevent this happening again the max fee cap is set to the last block baseFee * 10 and a constant tip of 1 is set. The overlapping nonce tx test was also failing due to replacement transactions being underpriced. I suspect this could be due to some loss of precision when during price bump adjustment and currency conversion. Modifying the price bump to be 1.11 instead of 1.1 seems to have solved this. --- e2e_test/js-tests/test_viem_tx.mjs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/e2e_test/js-tests/test_viem_tx.mjs b/e2e_test/js-tests/test_viem_tx.mjs index e42c7ba793..30356c3b35 100644 --- a/e2e_test/js-tests/test_viem_tx.mjs +++ b/e2e_test/js-tests/test_viem_tx.mjs @@ -5,12 +5,11 @@ import { } from "viem"; import { publicClient, walletClient } from "./viem_setup.mjs" -// Returns the base fee per gas for the current block multiplied by 2 to account for any increase in the subsequent block. -async function getGasFees(publicClient, tip, feeCurrency) { +// Returns the base fee per gas for the current block in the given fee currency. +async function getBaseFee(publicClient, feeCurrency) { const rate = await getRate(feeCurrency); const b = await publicClient.getBlock(); - const tipInFeeCurrency = rate.toFeeCurrency(tip); - return [rate.toFeeCurrency(b.baseFeePerGas) + tipInFeeCurrency, tipInFeeCurrency]; + return rate.toFeeCurrency(b.baseFeePerGas); } const testNonceBump = async ( @@ -99,14 +98,14 @@ describe("viem send tx", () => { }).timeout(10_000); it("send fee currency tx with explicit gas fields and check receipt", async () => { - const [maxFeePerGas, tip] = await getGasFees(publicClient, 2n, process.env.FEE_CURRENCY); + const baseFeeForFeeCurrency = await getBaseFee(publicClient, process.env.FEE_CURRENCY); const request = await walletClient.prepareTransactionRequest({ to: "0x00000000000000000000000000000000DeaDBeef", value: 2, gas: 171000, feeCurrency: process.env.FEE_CURRENCY, - maxFeePerGas: maxFeePerGas, - maxPriorityFeePerGas: tip, + maxFeePerGas: baseFeeForFeeCurrency*10n, + maxPriorityFeePerGas: 1n, }); const signature = await walletClient.signTransaction(request); const hash = await walletClient.sendRawTransaction({ @@ -195,15 +194,15 @@ describe("viem send tx", () => { // more liable to result in a failure. it("send overlapping nonce tx in different currencies", async () => { // Note the threshold for a price bump to be accepted is 10%, i.e >= oldPrice * 1.1 - const priceBump = 1.1; // minimum bump percentage to replace a transaction + const priceBump = 1.11; // minimum bump percentage to replace a transaction const priceNearBump = 1.09; // slightly lower percentage than the price bump const rate = await getRate(process.env.FEE_CURRENCY); // Native to FEE_CURRENCY const nativeCap = 30_000_000_000; - const bumpCurrencyCap = rate.toFeeCurrency(BigInt(Math.round(nativeCap * priceBump))); + const bumpCurrencyCap = rate.toFeeCurrency(BigInt(Math.ceil(nativeCap * priceBump))); const failToBumpCurrencyCap = rate.toFeeCurrency(BigInt( - Math.round(nativeCap * priceNearBump) + Math.floor(nativeCap * priceNearBump) )); const tokenCurrency = process.env.FEE_CURRENCY; const nativeCurrency = null; @@ -224,9 +223,9 @@ describe("viem send tx", () => { // FEE_CURRENCY to Native const currencyCap = 60_000_000_000; - const bumpNativeCap = rate.toNative(BigInt(Math.round(currencyCap * priceBump))); + const bumpNativeCap = rate.toNative(BigInt(Math.ceil(currencyCap * priceBump))); const failToBumpNativeCap = rate.toNative(BigInt( - Math.round(currencyCap * priceNearBump) + Math.floor(currencyCap * priceNearBump) )); await testNonceBump( currencyCap, From 232effe5ad741efcffc4b924f941eb8c5de66eaf Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Wed, 5 Feb 2025 12:13:09 +0100 Subject: [PATCH 2/5] Fix use converted min-tip in error message --- core/txpool/validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 9e49697a95..97c125d160 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -157,7 +157,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types return err } if tx.GasTipCapIntCmp(minTip) < 0 { - return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrUnderpriced, tx.GasTipCap(), opts.MinTip) + return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrUnderpriced, tx.GasTipCap(), minTip) } if tx.Type() == types.BlobTxType { // Ensure the blob fee cap satisfies the minimum blob gas price From e527ae66130749830a7786275d9474e691be9641 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 5 Feb 2025 11:45:40 +0000 Subject: [PATCH 3/5] Fix tip in explicit gas fields test The tip needs to be convered to fee currency to meet the min tip requirements. --- e2e_test/js-tests/test_viem_tx.mjs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/e2e_test/js-tests/test_viem_tx.mjs b/e2e_test/js-tests/test_viem_tx.mjs index 30356c3b35..01c3ed4c83 100644 --- a/e2e_test/js-tests/test_viem_tx.mjs +++ b/e2e_test/js-tests/test_viem_tx.mjs @@ -6,10 +6,11 @@ import { import { publicClient, walletClient } from "./viem_setup.mjs" // Returns the base fee per gas for the current block in the given fee currency. -async function getBaseFee(publicClient, feeCurrency) { +async function getGasFees(publicClient, feeCurrency, tip) { const rate = await getRate(feeCurrency); const b = await publicClient.getBlock(); - return rate.toFeeCurrency(b.baseFeePerGas); + const convertedTip = rate.toFeeCurrency(tip); + return [ rate.toFeeCurrency(b.baseFeePerGas)+convertedTip, convertedTip]; } const testNonceBump = async ( @@ -98,14 +99,21 @@ describe("viem send tx", () => { }).timeout(10_000); it("send fee currency tx with explicit gas fields and check receipt", async () => { - const baseFeeForFeeCurrency = await getBaseFee(publicClient, process.env.FEE_CURRENCY); + // Our execution nodes are configured by default with a min tip of 1 wei in + // celo, which when converted to fee currency could be a higher value, so + // we need to ensure we use the min tip in fee currency when submitting a + // tx with fee a fee currency. + const [maxFeePerGasInFeeCurrency, tipInFeeCurrency] = await getGasFees(publicClient, process.env.FEE_CURRENCY, 1n); + const request = await walletClient.prepareTransactionRequest({ to: "0x00000000000000000000000000000000DeaDBeef", value: 2, gas: 171000, feeCurrency: process.env.FEE_CURRENCY, - maxFeePerGas: baseFeeForFeeCurrency*10n, - maxPriorityFeePerGas: 1n, + // We multiply the maxFeePerGas by 10 here to account for fluctuations in + // the base fee, since these tests can be run against a live network. + maxFeePerGas: maxFeePerGasInFeeCurrency*10n, + maxPriorityFeePerGas: tipInFeeCurrency, }); const signature = await walletClient.signTransaction(request); const hash = await walletClient.sendRawTransaction({ From b301128910db97cc8b44a772e6c69c697eefcff0 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 5 Feb 2025 15:43:23 +0000 Subject: [PATCH 4/5] Ensure tx tip is at least 1 When converting the tip to fee currency the result can be zero, sending a transaction with a zero tip even if that is the result of converting the required 1 wei to a fee currency results in a transaction that is not processed. --- e2e_test/js-tests/test_viem_tx.mjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/e2e_test/js-tests/test_viem_tx.mjs b/e2e_test/js-tests/test_viem_tx.mjs index 01c3ed4c83..b27532611f 100644 --- a/e2e_test/js-tests/test_viem_tx.mjs +++ b/e2e_test/js-tests/test_viem_tx.mjs @@ -102,8 +102,15 @@ describe("viem send tx", () => { // Our execution nodes are configured by default with a min tip of 1 wei in // celo, which when converted to fee currency could be a higher value, so // we need to ensure we use the min tip in fee currency when submitting a - // tx with fee a fee currency. - const [maxFeePerGasInFeeCurrency, tipInFeeCurrency] = await getGasFees(publicClient, process.env.FEE_CURRENCY, 1n); + // tx with fee a fee currency. However somewhere else it is enforced that + // the tip must be at least 1, so if conversion of tip to fee currency + // results in 0 we need to set it to 1. + let [maxFeePerGasInFeeCurrency, tipInFeeCurrency] = await getGasFees(publicClient, process.env.FEE_CURRENCY, 1n); + + if (tipInFeeCurrency == 0n) { + console.log("tip was 0"); + tipInFeeCurrency = 1n; + } const request = await walletClient.prepareTransactionRequest({ to: "0x00000000000000000000000000000000DeaDBeef", From 45b24c79de5635de163469b5c57fd6a107d2e180 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 5 Feb 2025 15:48:09 +0000 Subject: [PATCH 5/5] Only execute a dummy first transaction for devmode geth --- e2e_test/run_all_tests.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/e2e_test/run_all_tests.sh b/e2e_test/run_all_tests.sh index 9d0675abd1..53c446a1ee 100755 --- a/e2e_test/run_all_tests.sh +++ b/e2e_test/run_all_tests.sh @@ -23,13 +23,15 @@ if [ -z $NETWORK ]; then ## Run tests echo Geth ready, start tests + + # There's a problem with geth return errors on the first transaction sent. + # See https://github.com/ethereum/web3.py/issues/3212 + # To work around this, send a transaction before running tests + cast send --json --private-key "$ACC_PRIVKEY" "$TOKEN_ADDR" 'transfer(address to, uint256 value) returns (bool)' 0x000000000000000000000000000000000000dEaD 100 > /dev/null || true + fi cd "$SCRIPT_DIR" || exit 1 -# There's a problem with geth return errors on the first transaction sent. -# See https://github.com/ethereum/web3.py/issues/3212 -# To work around this, send a transaction before running tests -cast send --json --private-key "$ACC_PRIVKEY" "$TOKEN_ADDR" 'transfer(address to, uint256 value) returns (bool)' 0x000000000000000000000000000000000000dEaD 100 > /dev/null || true failures=0 tests=0