Skip to content

Commit 56f5dd4

Browse files
committed
chore: add tests
Signed-off-by: nikolay <[email protected]>
1 parent 3dc9478 commit 56f5dd4

File tree

2 files changed

+286
-3
lines changed

2 files changed

+286
-3
lines changed

packages/server/tests/acceptance/rpc_batch1.spec.ts

Lines changed: 283 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { expect } from 'chai';
2222
import { ethers } from 'ethers';
2323

2424
import { ConfigServiceTestHelper } from '../../../config-service/tests/configServiceTestHelper';
25-
import { withOverriddenEnvsInMochaTest } from '../../../relay/tests/helpers';
25+
import { overrideEnvsInMochaDescribe, withOverriddenEnvsInMochaTest } from '../../../relay/tests/helpers';
2626
import basicContract from '../../tests/contracts/Basic.json';
2727
import RelayCalls from '../../tests/helpers/constants';
2828
import MirrorClient from '../clients/mirrorClient';
@@ -32,6 +32,7 @@ import basicContractJson from '../contracts/Basic.json';
3232
import logsContractJson from '../contracts/Logs.json';
3333
// Local resources from contracts directory
3434
import parentContractJson from '../contracts/Parent.json';
35+
import reverterContractJson from '../contracts/Reverter.json';
3536
// Assertions from local resources
3637
import Assertions from '../helpers/assertions';
3738
import { Utils } from '../helpers/utils';
@@ -765,6 +766,287 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () {
765766
type: 1,
766767
};
767768

769+
describe('Transaction Pool feature', async () => {
770+
describe('ENABLE_TX_POOL = true', async () => {
771+
overrideEnvsInMochaDescribe({ ENABLE_TX_POOL: true });
772+
it('should have equal nonces (pending and latest) after successful validated transaction', async () => {
773+
const tx = {
774+
...defaultLondonTransactionData,
775+
to: accounts[2].address,
776+
nonce: await relay.getAccountNonce(accounts[1].address),
777+
};
778+
const signedTx = await accounts[1].wallet.signTransaction(tx);
779+
const txHash = await relay.sendRawTransaction(signedTx);
780+
await relay.pollForValidTransactionReceipt(txHash);
781+
782+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
783+
const noncePending = await relay.getAccountNonce(accounts[1].address, 'pending');
784+
785+
expect(nonceLatest).to.equal(noncePending);
786+
});
787+
788+
it('should have equal nonces (pending and latest) after CN reverted transaction', async () => {
789+
const tx = {
790+
...defaultLondonTransactionData,
791+
to: null,
792+
data: '0x' + '00'.repeat(5121),
793+
nonce: await relay.getAccountNonce(accounts[1].address),
794+
gasLimit: 41484,
795+
};
796+
const signedTx = await accounts[1].wallet.signTransaction(tx);
797+
const txHash = await relay.sendRawTransaction(signedTx);
798+
await relay.pollForValidTransactionReceipt(txHash);
799+
const mnResult = await mirrorNode.get(`/contracts/results/${txHash}`);
800+
801+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
802+
const noncePending = await relay.getAccountNonce(accounts[1].address, 'pending');
803+
804+
expect(mnResult.result).to.equal('INSUFFICIENT_GAS');
805+
expect(nonceLatest).to.equal(noncePending);
806+
});
807+
808+
it('should have equal nonces (pending and latest) after multiple CN reverted transactions', async () => {
809+
const accountNonce = await relay.getAccountNonce(accounts[1].address);
810+
const tx1 = {
811+
...defaultLondonTransactionData,
812+
to: null,
813+
data: '0x' + '00'.repeat(5121),
814+
nonce: accountNonce,
815+
gasLimit: 41484,
816+
};
817+
const tx2 = {
818+
...defaultLondonTransactionData,
819+
to: accounts[2].address,
820+
nonce: accountNonce,
821+
gasLimit: 21000,
822+
};
823+
const tx3 = {
824+
...defaultLondonTransactionData,
825+
to: null,
826+
data: '0x' + '00'.repeat(5121),
827+
nonce: accountNonce + 1,
828+
gasLimit: 41484,
829+
};
830+
const signedTx1 = await accounts[1].wallet.signTransaction(tx1);
831+
const signedTx2 = await accounts[1].wallet.signTransaction(tx2);
832+
const signedTx3 = await accounts[1].wallet.signTransaction(tx3);
833+
834+
const txHash1 = await relay.sendRawTransaction(signedTx1);
835+
await new Promise((r) => setTimeout(r, 100));
836+
const txHash2 = await relay.sendRawTransaction(signedTx2);
837+
await new Promise((r) => setTimeout(r, 100));
838+
const txHash3 = await relay.sendRawTransaction(signedTx3);
839+
840+
await Promise.all([
841+
relay.pollForValidTransactionReceipt(txHash1),
842+
relay.pollForValidTransactionReceipt(txHash2),
843+
relay.pollForValidTransactionReceipt(txHash3),
844+
]);
845+
846+
const [mnResult1, mnResult2, mnResult3] = await Promise.all([
847+
mirrorNode.get(`/contracts/results/${txHash1}`),
848+
mirrorNode.get(`/contracts/results/${txHash2}`),
849+
mirrorNode.get(`/contracts/results/${txHash3}`),
850+
]);
851+
852+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
853+
const noncePending = await relay.getAccountNonce(accounts[1].address, 'pending');
854+
855+
expect(mnResult1.result).to.equal('INSUFFICIENT_GAS');
856+
expect(mnResult2.result).to.equal('SUCCESS');
857+
expect(mnResult3.result).to.equal('INSUFFICIENT_GAS');
858+
expect(nonceLatest).to.equal(noncePending);
859+
});
860+
861+
it('should have equal nonces (pending and latest_ for contract reverted transaction', async () => {
862+
const reverterContract = await Utils.deployContract(
863+
reverterContractJson.abi,
864+
reverterContractJson.bytecode,
865+
accounts[0].wallet,
866+
);
867+
868+
const tx = {
869+
...defaultLondonTransactionData,
870+
to: reverterContract.target,
871+
data: '0xd0efd7ef',
872+
nonce: await relay.getAccountNonce(accounts[1].address),
873+
value: ONE_TINYBAR,
874+
};
875+
const signedTx = await accounts[1].wallet.signTransaction(tx);
876+
const txHash = await relay.sendRawTransaction(signedTx);
877+
await relay.pollForValidTransactionReceipt(txHash);
878+
const mnResult = await mirrorNode.get(`/contracts/results/${txHash}`);
879+
880+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
881+
const noncePending = await relay.getAccountNonce(accounts[1].address, 'pending');
882+
883+
expect(mnResult.result).to.equal('CONTRACT_REVERT_EXECUTED');
884+
expect(nonceLatest).to.equal(noncePending);
885+
});
886+
887+
it('scenario #5', async () => {});
888+
889+
it('should have difference between pending and latest nonce when a single transaction has been sent', async () => {
890+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
891+
const signedTx1 = await accounts[1].wallet.signTransaction({
892+
...defaultLondonTransactionData,
893+
to: accounts[2].address,
894+
nonce: nonceLatest,
895+
gasLimit: 21000,
896+
});
897+
const txHash1 = await relay.sendRawTransaction(signedTx1);
898+
899+
const noncePending = await relay.getAccountNonce(accounts[1].address, 'pending');
900+
const signedTx2 = await accounts[1].wallet.signTransaction({
901+
...defaultLondonTransactionData,
902+
to: accounts[2].address,
903+
nonce: noncePending,
904+
gasLimit: 21000,
905+
});
906+
const txHash2 = await relay.sendRawTransaction(signedTx2);
907+
908+
const [receipt1, receipt2] = await Promise.all([
909+
relay.pollForValidTransactionReceipt(txHash1),
910+
relay.pollForValidTransactionReceipt(txHash2),
911+
]);
912+
913+
expect(receipt1.status).to.equal('0x1');
914+
expect(receipt2.status).to.equal('0x1');
915+
expect(nonceLatest).to.be.lessThan(noncePending);
916+
});
917+
918+
it('should have difference between pending and latest nonce when multiple transactions have been sent simultaneously', async () => {
919+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
920+
const signedTx1 = await accounts[1].wallet.signTransaction({
921+
...defaultLondonTransactionData,
922+
to: accounts[2].address,
923+
nonce: nonceLatest,
924+
gasLimit: 21000,
925+
});
926+
const txHash1 = await relay.sendRawTransaction(signedTx1);
927+
928+
const noncePendingTx2 = await relay.getAccountNonce(accounts[1].address, 'pending');
929+
const signedTx2 = await accounts[1].wallet.signTransaction({
930+
...defaultLondonTransactionData,
931+
to: accounts[2].address,
932+
nonce: noncePendingTx2,
933+
gasLimit: 21000,
934+
});
935+
const txHash2 = await relay.sendRawTransaction(signedTx2);
936+
937+
const noncePendingTx3 = await relay.getAccountNonce(accounts[1].address, 'pending');
938+
const signedTx3 = await accounts[1].wallet.signTransaction({
939+
...defaultLondonTransactionData,
940+
to: accounts[2].address,
941+
nonce: noncePendingTx3,
942+
gasLimit: 21000,
943+
});
944+
const txHash3 = await relay.sendRawTransaction(signedTx3);
945+
946+
const [receipt1, receipt2, receipt3] = await Promise.all([
947+
relay.pollForValidTransactionReceipt(txHash1),
948+
relay.pollForValidTransactionReceipt(txHash2),
949+
relay.pollForValidTransactionReceipt(txHash3),
950+
]);
951+
952+
expect(receipt1.status).to.equal('0x1');
953+
expect(receipt2.status).to.equal('0x1');
954+
expect(receipt3.status).to.equal('0x1');
955+
expect(nonceLatest).to.be.lessThan(noncePendingTx2);
956+
expect(noncePendingTx2).to.be.lessThan(noncePendingTx3);
957+
});
958+
});
959+
960+
describe('ENABLE_TX_POOL = false', async () => {
961+
overrideEnvsInMochaDescribe({ ENABLE_TX_POOL: false });
962+
it('should return latest nonce after transaction has been sent ', async () => {
963+
const nonce = await relay.getAccountNonce(accounts[1].address);
964+
const tx = {
965+
...defaultLondonTransactionData,
966+
to: accounts[2].address,
967+
nonce,
968+
};
969+
const signedTx = await accounts[1].wallet.signTransaction(tx);
970+
const txHash = await relay.sendRawTransaction(signedTx);
971+
await relay.pollForValidTransactionReceipt(txHash);
972+
973+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
974+
975+
expect(nonce).to.not.equal(nonceLatest);
976+
expect(nonce).to.be.lessThan(nonceLatest);
977+
});
978+
979+
it('should return equal nonces (pending and latest) when transaction has been sent', async () => {
980+
const nonce = await relay.getAccountNonce(accounts[1].address);
981+
const tx = {
982+
...defaultLondonTransactionData,
983+
to: accounts[2].address,
984+
nonce,
985+
};
986+
const signedTx = await accounts[1].wallet.signTransaction(tx);
987+
await relay.sendRawTransaction(signedTx);
988+
989+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
990+
const noncePending = await relay.getAccountNonce(accounts[1].address, Constants.BLOCK_PENDING);
991+
992+
expect(nonceLatest).to.equal(noncePending);
993+
});
994+
995+
it('should fail with WRONG_NONCE when multiple transactions have been sent simultaneously', async () => {
996+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
997+
998+
const txs = [];
999+
for (let i = 0; i < 10; i++) {
1000+
txs.push(
1001+
relay.sendRawTransaction(
1002+
await accounts[1].wallet.signTransaction({
1003+
...defaultLondonTransactionData,
1004+
to: accounts[2].address,
1005+
nonce: nonceLatest + i,
1006+
}),
1007+
),
1008+
);
1009+
}
1010+
const txHashes = await Promise.all(txs);
1011+
1012+
// wait for at least one block time
1013+
await new Promise((r) => setTimeout(r, 2100));
1014+
1015+
// currently, there is no way to fetch WRONG_NONCE transactions via MN or on `eth_getTransactionReceipt` by evm hash
1016+
// eth_sendRawTransaction returns always an evm hash, so as end-users we don't have the transaction id
1017+
1018+
// the WRONG_NONCE transactions are filtered out from MN /api/v1/contract/results/<evm_tx_hash>
1019+
// and /api/v1/transactions/<evm_hash> doesn't exist (only /api/v1/transactions/<transaction_id>
1020+
1021+
// the only thing we can rely on right now is the "not found" status that is returned on /api/v1/contracts/results/<evm_hash> by evm tx hash
1022+
const receipts = await Promise.allSettled(
1023+
txHashes.map((hash) => mirrorNode.get(`/contracts/results/${hash}`)),
1024+
);
1025+
const rejected = receipts.filter((receipt) => receipt.status === 'rejected');
1026+
expect(rejected).to.not.be.empty;
1027+
rejected.forEach((reject) => expect(reject.reason.response.status).to.equal(404));
1028+
});
1029+
});
1030+
1031+
it('should fail with WRONG_NONCE when a transaction with very high nonce has been sent', async () => {
1032+
const nonceLatest = await relay.getAccountNonce(accounts[1].address);
1033+
const txHash = await relay.sendRawTransaction(
1034+
await accounts[1].wallet.signTransaction({
1035+
...defaultLondonTransactionData,
1036+
to: accounts[2].address,
1037+
nonce: nonceLatest + 100,
1038+
}),
1039+
);
1040+
1041+
// wait for at least one block time
1042+
await new Promise((r) => setTimeout(r, 2100));
1043+
1044+
await expect(mirrorNode.get(`/contracts/results/${txHash}`)).to.eventually.be.rejected.and.satisfy(
1045+
(err: any) => err.response.status === 404,
1046+
);
1047+
});
1048+
});
1049+
7681050
it('@release should execute "eth_getTransactionByBlockHashAndIndex"', async function () {
7691051
const response = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_TRANSACTION_BY_BLOCK_HASH_AND_INDEX, [
7701052
mirrorContractDetails.block_hash.substring(0, 66),

packages/server/tests/clients/relayClient.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,11 @@ export default class RelayClient {
9494

9595
/**
9696
* @param evmAddress
97+
* @param blockTag
9798
* Returns: The nonce of the account with the provided `evmAddress`
9899
*/
99-
async getAccountNonce(evmAddress: string): Promise<number> {
100-
const nonce = await this.provider.send('eth_getTransactionCount', [evmAddress, 'latest']);
100+
async getAccountNonce(evmAddress: string, blockTag: string = 'latest'): Promise<number> {
101+
const nonce = await this.provider.send('eth_getTransactionCount', [evmAddress, blockTag]);
101102
return Number(nonce);
102103
}
103104

0 commit comments

Comments
 (0)