From 211236fff351ebc2d62ed638911c85c6fdbe3cbd Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:12:44 +0200 Subject: [PATCH 1/7] Revert "Temporarily skip fee-currency e2e tests" This reverts commit 25314bcb23a9bcc18be274e7c0df320daa2d7215. --- e2e_test/run_all_tests.sh | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/e2e_test/run_all_tests.sh b/e2e_test/run_all_tests.sh index 4aa3ed60fd..1a87baa83a 100755 --- a/e2e_test/run_all_tests.sh +++ b/e2e_test/run_all_tests.sh @@ -34,22 +34,15 @@ failures=0 tests=0 for f in test_*"$TEST_GLOB"* do - # temporarily skip fee-currency related tests - if (echo "$f" | grep -q -e fee_currency ) + echo -e "\nRun $f" + if "./$f" then tput setaf 2 || true - echo "SKIP $f" + echo "PASS $f" else - echo -e "\nRun $f" - if "./$f" - then - tput setaf 2 || true - echo "PASS $f" - else - tput setaf 1 || true - echo "FAIL $f ❌" - ((failures++)) || true - fi + tput setaf 1 || true + echo "FAIL $f ❌" + ((failures++)) || true fi tput sgr0 || true ((tests++)) || true From a1682bd12ce5ac70ba3292f3aad84f995c3cbdff Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Mon, 12 Aug 2024 22:49:46 +0200 Subject: [PATCH 2/7] Refactor e2e tests Since some e2e tests now produce invalidated transactions that remain in the txpool until replaced, the `send_tx.mjs` script required some changes to replace the sent CIP64 transaction. It will get replaced after 2 blocks of producing no receipt. Those changes also required the geth-node to run in periodic --dev mode instead of the on-demand "produce-block-per-transaction" mode, which will unfortunately make the tests run longer than before. The bash scripts and tests itself have also been refactored to make code segments more reusable with the help of functions. --- .../debug-fee-currency/deploy_and_send_tx.sh | 11 +- e2e_test/debug-fee-currency/lib.sh | 56 +++++++ e2e_test/js-tests/send_tx.mjs | 143 ++++++++++++++---- e2e_test/js-tests/test_viem_tx.mjs | 2 +- e2e_test/run_all_tests.sh | 24 ++- e2e_test/shared.sh | 9 +- e2e_test/test_base_fee_recipient.sh | 5 +- e2e_test/test_fee_currency_fails_intrinsic.sh | 26 +++- e2e_test/test_fee_currency_fails_on_credit.sh | 28 +++- e2e_test/test_fee_currency_fails_on_debit.sh | 10 +- 10 files changed, 248 insertions(+), 66 deletions(-) create mode 100755 e2e_test/debug-fee-currency/lib.sh diff --git a/e2e_test/debug-fee-currency/deploy_and_send_tx.sh b/e2e_test/debug-fee-currency/deploy_and_send_tx.sh index 1cfd9eec73..258b3b013c 100755 --- a/e2e_test/debug-fee-currency/deploy_and_send_tx.sh +++ b/e2e_test/debug-fee-currency/deploy_and_send_tx.sh @@ -2,12 +2,7 @@ #shellcheck disable=SC2034,SC2155,SC2086 set -xeo pipefail -export FEE_CURRENCY=$(\ - forge create --root . --contracts . --private-key $ACC_PRIVKEY DebugFeeCurrency.sol:DebugFeeCurrency --constructor-args '100000000000000000000000000' $1 $2 $3 --json\ - | jq .deployedTo -r) +source ./lib.sh -cast send --private-key $ACC_PRIVKEY $ORACLE3 'setExchangeRate(address, uint256, uint256)' $FEE_CURRENCY 2ether 1ether -cast send --private-key $ACC_PRIVKEY $FEE_CURRENCY_DIRECTORY_ADDR 'setCurrencyConfig(address, address, uint256)' $FEE_CURRENCY $ORACLE3 60000 -echo Fee currency: $FEE_CURRENCY - -(cd ../js-tests/ && ./send_tx.mjs "$(cast chain-id)" $ACC_PRIVKEY $FEE_CURRENCY) +fee_currency=$(deploy_fee_currency $1 $2 $3) +cip_64_tx $fee_currency diff --git a/e2e_test/debug-fee-currency/lib.sh b/e2e_test/debug-fee-currency/lib.sh new file mode 100755 index 0000000000..34b4fa540f --- /dev/null +++ b/e2e_test/debug-fee-currency/lib.sh @@ -0,0 +1,56 @@ +#!/bin/bash +#shellcheck disable=SC2034,SC2155,SC2086 +set -xeo pipefail + +# args: +# $1: failOnDebit (bool): +# if true, this will make the DebugFeeCurrenc.DebitFees() call fail with a revert +# $2: failOnCredit (bool) +# if true, this will make the DebugFeeCurrenc.CreditFees() call fail with a revert +# $3: highGasOnCredit (bool) +# if true, this will make the DebugFeeCurrenc.CreditFees() call use +# a high amount of gas +# returns: +# deployed fee-currency address +function deploy_fee_currency() { + ( + local fee_currency=$( + forge create --root "$SCRIPT_DIR/debug-fee-currency" --contracts "$SCRIPT_DIR/debug-fee-currency" --private-key $ACC_PRIVKEY DebugFeeCurrency.sol:DebugFeeCurrency --constructor-args '100000000000000000000000000' $1 $2 $3 --json | jq .deployedTo -r + ) + if [ -z "${fee_currency}" ]; then + exit 1 + fi + cast send --private-key $ACC_PRIVKEY $ORACLE3 'setExchangeRate(address, uint256, uint256)' $fee_currency 2ether 1ether &>/dev/null + cast send --private-key $ACC_PRIVKEY $FEE_CURRENCY_DIRECTORY_ADDR 'setCurrencyConfig(address, address, uint256)' $fee_currency $ORACLE3 60000 &>/dev/null + echo "$fee_currency" + ) +} + +# args: +# $1: feeCurrencyAddress (string): +# which fee-currency address to use for the default CIP-64 transaction +function cip_64_tx() { + $SCRIPT_DIR/js-tests/send_tx.mjs "$(cast chain-id)" $ACC_PRIVKEY $1 +} + +# use this function to assert the cip_64_tx return value, by using a pipe like +# `cip_64_tx "$fee-currency" | assert_cip_64_tx true` +# +# args: +# $1: success (string): +# expected success value, "true" for when the cip-64 tx should have succeeded, "false" if not +# $2: error-regex (string): +# expected RPC return-error value regex to grep for, use "null", "" or unset value if no error is assumed. +function assert_cip_64_tx() { + local value + read -r value + local expected_error="$2" + + if [ "$(echo "$value" | jq .success)" != "$1" ]; then + exit 1 + fi + if [ -z "$expected_error" ]; then + expected_error="null" + fi + echo "$value" | jq .error | grep -qE "$expected_error" +} diff --git a/e2e_test/js-tests/send_tx.mjs b/e2e_test/js-tests/send_tx.mjs index 5a9b469502..b102adfab0 100755 --- a/e2e_test/js-tests/send_tx.mjs +++ b/e2e_test/js-tests/send_tx.mjs @@ -1,44 +1,127 @@ #!/usr/bin/env node import { - createPublicClient, - createWalletClient, - http, - defineChain, + createWalletClient, + createPublicClient, + http, + defineChain, + TransactionReceiptNotFoundError, } from "viem"; import { celoAlfajores } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; const [chainId, privateKey, feeCurrency] = process.argv.slice(2); const devChain = defineChain({ - ...celoAlfajores, - id: parseInt(chainId, 10), - name: "local dev chain", - network: "dev", - rpcUrls: { - default: { - http: ["http://127.0.0.1:8545"], - }, - }, + ...celoAlfajores, + id: parseInt(chainId, 10), + name: "local dev chain", + network: "dev", + rpcUrls: { + default: { + http: ["http://127.0.0.1:8545"], + }, + }, }); const account = privateKeyToAccount(privateKey); -const walletClient = createWalletClient({ - account, - chain: devChain, - transport: http(), -}); -const request = await walletClient.prepareTransactionRequest({ - account, - to: "0x00000000000000000000000000000000DeaDBeef", - value: 2, - gas: 90000, - feeCurrency, - maxFeePerGas: 2000000000n, - maxPriorityFeePerGas: 0n, +const publicClient = createPublicClient({ + account, + chain: devChain, + transport: http(), }); -const signature = await walletClient.signTransaction(request); -const hash = await walletClient.sendRawTransaction({ - serializedTransaction: signature, +const walletClient = createWalletClient({ + account, + chain: devChain, + transport: http(), }); -console.log(hash); + +async function getTransactionReceiptAfterWait(hash, numBlocks) { + var count = 0; + + const res = new Promise((resolve) => { + resolve(); + }); + const unwatch = publicClient.watchBlockNumber({ + onBlockNumber: () => { + count++; + if (count >= numBlocks) { + res.resolve(); + } + }, + }); + await res; + unwatch(); + try { + return await publicClient.getTransactionReceipt({ hash: hash }); + } catch (e) { + if (e instanceof TransactionReceiptNotFoundError) { + return undefined; + } + throw e; + } +} + +async function replaceTx(tx) { + const request = await walletClient.prepareTransactionRequest({ + account: tx.account, + to: account.address, + value: 0n, + gas: 21000, + nonce: tx.nonce, + maxFeePerGas: tx.maxFeePerGas, + maxPriorityFeePerGas: tx.maxPriorityFeePerGas + 1000n, + }); + const hash = await walletClient.sendRawTransaction({ + serializedTransaction: await walletClient.signTransaction(request), + }); + const receipt = await publicClient.waitForTransactionReceipt({ + hash: hash, + confirmations: 2, + }); + return receipt; +} + +async function main() { + const request = await walletClient.prepareTransactionRequest({ + account, + to: "0x00000000000000000000000000000000DeaDBeef", + value: 2n, + gas: 90000, + feeCurrency, + maxFeePerGas: 2000000000n, + maxPriorityFeePerGas: 0n, + }); + + var hash; + try { + hash = await walletClient.sendRawTransaction({ + serializedTransaction: await walletClient.signTransaction(request), + }); + } catch (e) { + // direct revert + console.log( + JSON.stringify({ + success: false, + error: e, + }), + ); + return; + } + + var success = true; + var receipt = await getTransactionReceiptAfterWait(hash, 2); + if (!receipt) { + receipt = await replaceTx(request); + success = false; + } + // print for bash script wrapper return value + console.log( + JSON.stringify({ + success: success, + error: null, + }), + ); + + return receipt; +} +await main(); diff --git a/e2e_test/js-tests/test_viem_tx.mjs b/e2e_test/js-tests/test_viem_tx.mjs index ea79beacaf..b1b2377418 100644 --- a/e2e_test/js-tests/test_viem_tx.mjs +++ b/e2e_test/js-tests/test_viem_tx.mjs @@ -243,7 +243,7 @@ describe("viem send tx", () => { nativeCurrency, false, ); - }).timeout(10_000); + }).timeout(20_000); it("send tx with unregistered fee currency", async () => { const request = await walletClient.prepareTransactionRequest({ diff --git a/e2e_test/run_all_tests.sh b/e2e_test/run_all_tests.sh index 1a87baa83a..6d4529c445 100755 --- a/e2e_test/run_all_tests.sh +++ b/e2e_test/run_all_tests.sh @@ -2,19 +2,19 @@ set -eo pipefail SCRIPT_DIR=$(readlink -f "$(dirname "$0")") +source "$SCRIPT_DIR/shared.sh" + TEST_GLOB=$1 ## Start geth cd "$SCRIPT_DIR/.." || exit 1 make geth -trap 'kill %%' EXIT # kill bg job at exit -build/bin/geth --dev --http --http.api eth,web3,net &> "$SCRIPT_DIR/geth.log" & +trap 'kill %%' EXIT # kill bg job at exit +build/bin/geth --dev --dev.period 1 --http --http.api eth,web3,net &>"$SCRIPT_DIR/geth.log" & # Wait for geth to be ready -for _ in {1..10} -do - if cast block &> /dev/null - then +for _ in {1..10}; do + if cast block &>/dev/null; then break fi sleep 0.2 @@ -27,16 +27,13 @@ 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 -source ./shared.sh -cast send --json --private-key $ACC_PRIVKEY $TOKEN_ADDR 'transfer(address to, uint256 value) returns (bool)' 0x000000000000000000000000000000000000dEaD 100 --async +cast send --json --private-key $ACC_PRIVKEY $TOKEN_ADDR 'transfer(address to, uint256 value) returns (bool)' 0x000000000000000000000000000000000000dEaD 100 failures=0 tests=0 -for f in test_*"$TEST_GLOB"* -do +for f in test_*"$TEST_GLOB"*; do echo -e "\nRun $f" - if "./$f" - then + if "./$f"; then tput setaf 2 || true echo "PASS $f" else @@ -50,8 +47,7 @@ done ## Final summary echo -if [[ $failures -eq 0 ]] -then +if [[ $failures -eq 0 ]]; then tput setaf 2 || true echo All $tests tests succeeded! else diff --git a/e2e_test/shared.sh b/e2e_test/shared.sh index 87d85dc24d..0b946fa0f4 100644 --- a/e2e_test/shared.sh +++ b/e2e_test/shared.sh @@ -1,6 +1,8 @@ #!/bin/bash #shellcheck disable=SC2034 # unused vars make sense in a shared file +SCRIPT_DIR=$(readlink -f "$(dirname "$0")") +export SCRIPT_DIR export ETH_RPC_URL=http://127.0.0.1:8545 export ACC_ADDR=0x42cf1bbc38BaAA3c4898ce8790e21eD2738c6A4a @@ -15,6 +17,9 @@ export ORACLE3=0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0003 export FIXIDITY_1=1000000000000000000000000 export ZERO_ADDRESS=0x0000000000000000000000000000000000000000 -prepare_node () { - (cd js-tests || exit 1; [[ -d node_modules ]] || npm install) +prepare_node() { + ( + cd js-tests || exit 1 + [[ -d node_modules ]] || npm install + ) } diff --git a/e2e_test/test_base_fee_recipient.sh b/e2e_test/test_base_fee_recipient.sh index ec22198f88..9a8b2f9e79 100755 --- a/e2e_test/test_base_fee_recipient.sh +++ b/e2e_test/test_base_fee_recipient.sh @@ -14,4 +14,7 @@ base_fee=$(cast base-fee $block_number) expected_balance_change=$((base_fee * gas_used)) balance_after=$(cast balance $FEE_HANDLER) echo "Balance change: $balance_before -> $balance_after" -[[ $((balance_before + expected_balance_change)) -eq $balance_after ]] || (echo "Balance did not change as expected"; exit 1) +[[ $((balance_before + expected_balance_change)) -eq $balance_after ]] || ( + echo "Balance did not change as expected" + exit 1 +) diff --git a/e2e_test/test_fee_currency_fails_intrinsic.sh b/e2e_test/test_fee_currency_fails_intrinsic.sh index df4d14a512..babc9bd916 100755 --- a/e2e_test/test_fee_currency_fails_intrinsic.sh +++ b/e2e_test/test_fee_currency_fails_intrinsic.sh @@ -3,10 +3,30 @@ set -eo pipefail source shared.sh +source debug-fee-currency/lib.sh # Expect that the creditGasFees failed and is logged by geth -tail -f -n0 geth.log >debug-fee-currency/geth.intrinsic.log & # start log capture -(cd debug-fee-currency && ./deploy_and_send_tx.sh false false true) +tail -F -n 0 geth.log >debug-fee-currency/geth.intrinsic.log & # start log capture +( + sleep 0.2 + fee_currency=$(deploy_fee_currency false false true) + + # trigger the first failed call to the CreditFees(), causing the + # currency to get temporarily blocklisted. + # initial tx should not succeed, should have required a replacement transaction. + cip_64_tx $fee_currency | assert_cip_64_tx false + + sleep 2 + + # since the fee currency is temporarily blocked, + # this should NOT make the transaction execute anymore, + # but invalidate the transaction earlier. + # initial tx should not succeed, should have required a replacement transaction. + cip_64_tx $fee_currency | assert_cip_64_tx false + +) sleep 0.5 kill %1 # stop log capture -grep "surpassed maximum allowed intrinsic gas for CreditFees() in fee-currency: out of gas" debug-fee-currency/geth.intrinsic.log +# although we sent a transaction wih faulty fee-currency twice, +# the EVM call should have been executed only once +if [ "$(grep -Ec "fee-currency EVM execution error, temporarily blocking fee-currency in local txpools .+ surpassed maximum allowed intrinsic gas for CreditFees\(\) in fee-currency" debug-fee-currency/geth.intrinsic.log)" -ne 1 ]; then exit 1; fi diff --git a/e2e_test/test_fee_currency_fails_on_credit.sh b/e2e_test/test_fee_currency_fails_on_credit.sh index dbf16dfa2d..a3aab257b7 100755 --- a/e2e_test/test_fee_currency_fails_on_credit.sh +++ b/e2e_test/test_fee_currency_fails_on_credit.sh @@ -3,10 +3,30 @@ set -eo pipefail source shared.sh +source debug-fee-currency/lib.sh -# Expect that the creditGasFees failed and is logged by geth -tail -f -n0 geth.log >debug-fee-currency/geth.partial.log & # start log capture -(cd debug-fee-currency && ./deploy_and_send_tx.sh false true false) +tail -F -n0 geth.log >debug-fee-currency/geth.partial.log & # start log capture +( + sleep 0.2 + fee_currency=$(deploy_fee_currency false true false) + + # trigger the first failed call to the CreditFees(), causing the + # currency to get temporarily blocklisted. + # initial tx should not succeed, should have required a replacement transaction. + cip_64_tx $fee_currency | assert_cip_64_tx false + + sleep 2 + + # since the fee currency is temporarily blocked, + # this should NOT make the transaction execute anymore, + # but invalidate the transaction earlier. + # initial tx should not succeed, should have required a replacement transaction. + cip_64_tx $fee_currency | assert_cip_64_tx false + +) sleep 0.5 kill %1 # stop log capture -grep "This DebugFeeCurrency always fails in (old) creditGasFees!" debug-fee-currency/geth.partial.log +# although we sent a transaction wih faulty fee-currency twice, +# the EVM call should have been executed only once +grep "" debug-fee-currency/geth.partial.log +if [ "$(grep -Ec "fee-currency EVM execution error, temporarily blocking fee-currency in local txpools .+ This DebugFeeCurrency always fails in \(old\) creditGasFees!" debug-fee-currency/geth.partial.log)" -ne 1 ]; then exit 1; fi diff --git a/e2e_test/test_fee_currency_fails_on_debit.sh b/e2e_test/test_fee_currency_fails_on_debit.sh index 105c448e36..1a0369d8be 100755 --- a/e2e_test/test_fee_currency_fails_on_debit.sh +++ b/e2e_test/test_fee_currency_fails_on_debit.sh @@ -3,8 +3,12 @@ set -eo pipefail source shared.sh +source debug-fee-currency/lib.sh # Expect that the debitGasFees fails during tx submission -(cd debug-fee-currency && ./deploy_and_send_tx.sh true false false) &>debug-fee-currency/send_tx.log || true -grep "debitGasFees reverted: This DebugFeeCurrency always fails in debitGasFees!" debug-fee-currency/send_tx.log || - (cat debug-fee-currency/send_tx.log && false) +# +fee_currency=$(deploy_fee_currency true false false) +# this fails during the RPC call, since the DebitFees() is part of the pre-validation +cip_64_tx $fee_currency | assert_cip_64_tx false "fee-currency internal error" + +cleanup_fee_currency $fee_currency From c18433f40232159b2ef0348bdc8cfb84898bab74 Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:42:03 +0200 Subject: [PATCH 3/7] Fix js waitBlocks --- e2e_test/js-tests/send_tx.mjs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/e2e_test/js-tests/send_tx.mjs b/e2e_test/js-tests/send_tx.mjs index b102adfab0..73a3b537d9 100755 --- a/e2e_test/js-tests/send_tx.mjs +++ b/e2e_test/js-tests/send_tx.mjs @@ -34,23 +34,19 @@ const walletClient = createWalletClient({ chain: devChain, transport: http(), }); +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +async function waitBlocks(numBlocks) { + var initial = await publicClient.getBlockNumber({ cacheTime: 0 }); + var next = initial; + while (next - initial < numBlocks) { + await sleep(500); + next = await publicClient.getBlockNumber({ cacheTime: 0 }); + } +} -async function getTransactionReceiptAfterWait(hash, numBlocks) { - var count = 0; - - const res = new Promise((resolve) => { - resolve(); - }); - const unwatch = publicClient.watchBlockNumber({ - onBlockNumber: () => { - count++; - if (count >= numBlocks) { - res.resolve(); - } - }, - }); - await res; - unwatch(); +async function getTransactionReceipt(hash) { try { return await publicClient.getTransactionReceipt({ hash: hash }); } catch (e) { @@ -109,7 +105,9 @@ async function main() { } var success = true; - var receipt = await getTransactionReceiptAfterWait(hash, 2); + // give the node some time to process the transaction + await waitBlocks(5); + var receipt = await getTransactionReceipt(hash); if (!receipt) { receipt = await replaceTx(request); success = false; From 8d49c17ee8c40deb8308d574476ebfc5715ba29f Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:54:12 +0200 Subject: [PATCH 4/7] Fix e2e oracle reuse causing exchangeRate error The geth-devmode predeployed "oracle3" is reused throughout the e2e tests for all dynamically deployed fee-currencies. However the tested fee-currencies are never removed from the FeeCurrencyDirectory. This causes the node to try to query exchange-rates for the leftover fee-currencies. This fails, because the oracle associated with the old fee-currency has a different token address assigned and thus causes a revert. This issue is not critical and only causes emission of a log message and some unneccessary evm calls, but it is better practice to clean up the fee-currency from the directory anyways. --- e2e_test/debug-fee-currency/lib.sh | 15 +++++++++++++++ e2e_test/test_fee_currency_fails_intrinsic.sh | 1 + e2e_test/test_fee_currency_fails_on_credit.sh | 1 + 3 files changed, 17 insertions(+) diff --git a/e2e_test/debug-fee-currency/lib.sh b/e2e_test/debug-fee-currency/lib.sh index 34b4fa540f..fe9cdd0d4d 100755 --- a/e2e_test/debug-fee-currency/lib.sh +++ b/e2e_test/debug-fee-currency/lib.sh @@ -20,12 +20,27 @@ function deploy_fee_currency() { if [ -z "${fee_currency}" ]; then exit 1 fi + # this always resets the token address for the predeployed oracle3 cast send --private-key $ACC_PRIVKEY $ORACLE3 'setExchangeRate(address, uint256, uint256)' $fee_currency 2ether 1ether &>/dev/null cast send --private-key $ACC_PRIVKEY $FEE_CURRENCY_DIRECTORY_ADDR 'setCurrencyConfig(address, address, uint256)' $fee_currency $ORACLE3 60000 &>/dev/null echo "$fee_currency" ) } +# args: +# $1: feeCurrency (address): +# deployed fee-currency address to be cleaned up +function cleanup_fee_currency() { + ( + local fee_currency=$1 + # HACK: this uses a static index 2, which relies on the fact that all non-predeployed currencies will be always cleaned up + # from the directory and the list never has more than 3 elements. Once there is the need for more dynamic removal we + # can parse the following call and find the index ourselves: + # local currencies=$(cast call "$FEE_CURRENCY_DIRECTORY_ADDR" 'getCurrencies() (address[] memory)') + cast send --private-key $ACC_PRIVKEY $FEE_CURRENCY_DIRECTORY_ADDR 'removeCurrencies(address, uint256)' $fee_currency 2 --json | jq 'if .status == "0x1" then 0 else 1 end' -r + ) +} + # args: # $1: feeCurrencyAddress (string): # which fee-currency address to use for the default CIP-64 transaction diff --git a/e2e_test/test_fee_currency_fails_intrinsic.sh b/e2e_test/test_fee_currency_fails_intrinsic.sh index babc9bd916..cda95135f5 100755 --- a/e2e_test/test_fee_currency_fails_intrinsic.sh +++ b/e2e_test/test_fee_currency_fails_intrinsic.sh @@ -24,6 +24,7 @@ tail -F -n 0 geth.log >debug-fee-currency/geth.intrinsic.log & # start log captu # initial tx should not succeed, should have required a replacement transaction. cip_64_tx $fee_currency | assert_cip_64_tx false + cleanup_fee_currency $fee_currency ) sleep 0.5 kill %1 # stop log capture diff --git a/e2e_test/test_fee_currency_fails_on_credit.sh b/e2e_test/test_fee_currency_fails_on_credit.sh index a3aab257b7..5573fccb67 100755 --- a/e2e_test/test_fee_currency_fails_on_credit.sh +++ b/e2e_test/test_fee_currency_fails_on_credit.sh @@ -23,6 +23,7 @@ tail -F -n0 geth.log >debug-fee-currency/geth.partial.log & # start log capture # initial tx should not succeed, should have required a replacement transaction. cip_64_tx $fee_currency | assert_cip_64_tx false + cleanup_fee_currency $fee_currency ) sleep 0.5 kill %1 # stop log capture From ea116745d1e38628edd2355e372cf9c9b032c1c6 Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:55:38 +0200 Subject: [PATCH 5/7] Remove accidentally checked in comment --- core/celo_evm.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/celo_evm.go b/core/celo_evm.go index 69a5c994dd..aba5eb41f6 100644 --- a/core/celo_evm.go +++ b/core/celo_evm.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// XXYXX func setCeloFieldsInBlockContext(blockContext *vm.BlockContext, header *types.Header, config *params.ChainConfig, statedb vm.StateDB) { if !config.IsCel2(header.Time) { return From 8d1b90f4818595aa6bbb9a30d52952f5abbc6c14 Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:10:57 +0200 Subject: [PATCH 6/7] Reintroduce geth insta-mine in e2e tests --- e2e_test/js-tests/send_tx.mjs | 8 +++++--- e2e_test/run_all_tests.sh | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/e2e_test/js-tests/send_tx.mjs b/e2e_test/js-tests/send_tx.mjs index 73a3b537d9..21bf5dae20 100755 --- a/e2e_test/js-tests/send_tx.mjs +++ b/e2e_test/js-tests/send_tx.mjs @@ -72,7 +72,7 @@ async function replaceTx(tx) { }); const receipt = await publicClient.waitForTransactionReceipt({ hash: hash, - confirmations: 2, + confirmations: 1, }); return receipt; } @@ -89,6 +89,7 @@ async function main() { }); var hash; + try { hash = await walletClient.sendRawTransaction({ serializedTransaction: await walletClient.signTransaction(request), @@ -105,8 +106,9 @@ async function main() { } var success = true; - // give the node some time to process the transaction - await waitBlocks(5); + // wait 1 second to give the node time to potentially process the tx + // in instamine mode. + await sleep(1000); var receipt = await getTransactionReceipt(hash); if (!receipt) { receipt = await replaceTx(request); diff --git a/e2e_test/run_all_tests.sh b/e2e_test/run_all_tests.sh index 6d4529c445..81347cacf7 100755 --- a/e2e_test/run_all_tests.sh +++ b/e2e_test/run_all_tests.sh @@ -10,7 +10,7 @@ TEST_GLOB=$1 cd "$SCRIPT_DIR/.." || exit 1 make geth trap 'kill %%' EXIT # kill bg job at exit -build/bin/geth --dev --dev.period 1 --http --http.api eth,web3,net &>"$SCRIPT_DIR/geth.log" & +build/bin/geth --dev --http --http.api eth,web3,net &>"$SCRIPT_DIR/geth.log" & # Wait for geth to be ready for _ in {1..10}; do @@ -27,7 +27,7 @@ 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 +cast send --async --json --private-key "$ACC_PRIVKEY" "$TOKEN_ADDR" 'transfer(address to, uint256 value) returns (bool)' 0x000000000000000000000000000000000000dEaD 100 failures=0 tests=0 From a6aa79eed6576e709bbe6ab54c86fc88e8295f21 Mon Sep 17 00:00:00 2001 From: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:56:55 +0200 Subject: [PATCH 7/7] Add replacement transaction related arguments to send_tx --- e2e_test/debug-fee-currency/lib.sh | 7 ++++- e2e_test/js-tests/send_tx.mjs | 29 ++++++++++++------- e2e_test/test_fee_currency_fails_intrinsic.sh | 4 +-- e2e_test/test_fee_currency_fails_on_credit.sh | 4 +-- e2e_test/test_fee_currency_fails_on_debit.sh | 2 +- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/e2e_test/debug-fee-currency/lib.sh b/e2e_test/debug-fee-currency/lib.sh index fe9cdd0d4d..263c86fdac 100755 --- a/e2e_test/debug-fee-currency/lib.sh +++ b/e2e_test/debug-fee-currency/lib.sh @@ -44,8 +44,13 @@ function cleanup_fee_currency() { # args: # $1: feeCurrencyAddress (string): # which fee-currency address to use for the default CIP-64 transaction +# $2: waitBlocks (num): +# how many blocks to wait until the lack of a receipt is considered a failure +# $3: replaceTransaction (bool): +# replace the transaction with a transaction of higher priority-fee when +# there is no receipt after the `waitBlocks` time passed function cip_64_tx() { - $SCRIPT_DIR/js-tests/send_tx.mjs "$(cast chain-id)" $ACC_PRIVKEY $1 + $SCRIPT_DIR/js-tests/send_tx.mjs "$(cast chain-id)" $ACC_PRIVKEY $1 $2 $3 } # use this function to assert the cip_64_tx return value, by using a pipe like diff --git a/e2e_test/js-tests/send_tx.mjs b/e2e_test/js-tests/send_tx.mjs index 21bf5dae20..9e6b359a5f 100755 --- a/e2e_test/js-tests/send_tx.mjs +++ b/e2e_test/js-tests/send_tx.mjs @@ -9,7 +9,8 @@ import { import { celoAlfajores } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; -const [chainId, privateKey, feeCurrency] = process.argv.slice(2); +const [chainId, privateKey, feeCurrency, waitBlocks, replaceTxAfterWait] = + process.argv.slice(2); const devChain = defineChain({ ...celoAlfajores, id: parseInt(chainId, 10), @@ -37,10 +38,9 @@ const walletClient = createWalletClient({ function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } -async function waitBlocks(numBlocks) { - var initial = await publicClient.getBlockNumber({ cacheTime: 0 }); - var next = initial; - while (next - initial < numBlocks) { +async function waitUntilBlock(blocknum) { + var next = await publicClient.getBlockNumber({ cacheTime: 0 }); + while (next < blocknum) { await sleep(500); next = await publicClient.getBlockNumber({ cacheTime: 0 }); } @@ -57,7 +57,7 @@ async function getTransactionReceipt(hash) { } } -async function replaceTx(tx) { +async function replaceTransaction(tx) { const request = await walletClient.prepareTransactionRequest({ account: tx.account, to: account.address, @@ -90,6 +90,8 @@ async function main() { var hash; + var blocknum = await publicClient.getBlockNumber({ cacheTime: 0 }); + var replaced = false; try { hash = await walletClient.sendRawTransaction({ serializedTransaction: await walletClient.signTransaction(request), @@ -99,6 +101,7 @@ async function main() { console.log( JSON.stringify({ success: false, + replaced: replaced, error: e, }), ); @@ -106,18 +109,24 @@ async function main() { } var success = true; - // wait 1 second to give the node time to potentially process the tx - // in instamine mode. - await sleep(1000); + var waitBlocksForReceipt = parseInt(waitBlocks); var receipt = await getTransactionReceipt(hash); + while (waitBlocksForReceipt > 0) { + await waitUntilBlock(blocknum + BigInt(1)); + waitBlocksForReceipt--; + var receipt = await getTransactionReceipt(hash); + } if (!receipt) { - receipt = await replaceTx(request); + if (replaceTxAfterWait == "true") { + receipt = await replaceTransaction(request); + } success = false; } // print for bash script wrapper return value console.log( JSON.stringify({ success: success, + replaced: replaced, error: null, }), ); diff --git a/e2e_test/test_fee_currency_fails_intrinsic.sh b/e2e_test/test_fee_currency_fails_intrinsic.sh index cda95135f5..feb2139c8e 100755 --- a/e2e_test/test_fee_currency_fails_intrinsic.sh +++ b/e2e_test/test_fee_currency_fails_intrinsic.sh @@ -14,7 +14,7 @@ tail -F -n 0 geth.log >debug-fee-currency/geth.intrinsic.log & # start log captu # trigger the first failed call to the CreditFees(), causing the # currency to get temporarily blocklisted. # initial tx should not succeed, should have required a replacement transaction. - cip_64_tx $fee_currency | assert_cip_64_tx false + cip_64_tx $fee_currency 1 true | assert_cip_64_tx false sleep 2 @@ -22,7 +22,7 @@ tail -F -n 0 geth.log >debug-fee-currency/geth.intrinsic.log & # start log captu # this should NOT make the transaction execute anymore, # but invalidate the transaction earlier. # initial tx should not succeed, should have required a replacement transaction. - cip_64_tx $fee_currency | assert_cip_64_tx false + cip_64_tx $fee_currency 1 true | assert_cip_64_tx false cleanup_fee_currency $fee_currency ) diff --git a/e2e_test/test_fee_currency_fails_on_credit.sh b/e2e_test/test_fee_currency_fails_on_credit.sh index 5573fccb67..8fae3f6f19 100755 --- a/e2e_test/test_fee_currency_fails_on_credit.sh +++ b/e2e_test/test_fee_currency_fails_on_credit.sh @@ -13,7 +13,7 @@ tail -F -n0 geth.log >debug-fee-currency/geth.partial.log & # start log capture # trigger the first failed call to the CreditFees(), causing the # currency to get temporarily blocklisted. # initial tx should not succeed, should have required a replacement transaction. - cip_64_tx $fee_currency | assert_cip_64_tx false + cip_64_tx $fee_currency 1 true | assert_cip_64_tx false sleep 2 @@ -21,7 +21,7 @@ tail -F -n0 geth.log >debug-fee-currency/geth.partial.log & # start log capture # this should NOT make the transaction execute anymore, # but invalidate the transaction earlier. # initial tx should not succeed, should have required a replacement transaction. - cip_64_tx $fee_currency | assert_cip_64_tx false + cip_64_tx $fee_currency 1 true | assert_cip_64_tx false cleanup_fee_currency $fee_currency ) diff --git a/e2e_test/test_fee_currency_fails_on_debit.sh b/e2e_test/test_fee_currency_fails_on_debit.sh index 1a0369d8be..983cf8c00d 100755 --- a/e2e_test/test_fee_currency_fails_on_debit.sh +++ b/e2e_test/test_fee_currency_fails_on_debit.sh @@ -9,6 +9,6 @@ source debug-fee-currency/lib.sh # fee_currency=$(deploy_fee_currency true false false) # this fails during the RPC call, since the DebitFees() is part of the pre-validation -cip_64_tx $fee_currency | assert_cip_64_tx false "fee-currency internal error" +cip_64_tx $fee_currency 1 false | assert_cip_64_tx false "fee-currency internal error" cleanup_fee_currency $fee_currency