From 24dfe8955eef36a4c90ea4181c0ec1ba0fa5ea9c Mon Sep 17 00:00:00 2001 From: swelf Date: Tue, 22 Aug 2023 12:23:59 +0300 Subject: [PATCH 1/2] test for sudo gas limit --- src/testcases/parallel/simple.test.ts | 37 +++++- .../run_in_band/interchaintx.test.ts | 113 +++++++++++++++++- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/src/testcases/parallel/simple.test.ts b/src/testcases/parallel/simple.test.ts index 2851b9e4..0fb23d63 100644 --- a/src/testcases/parallel/simple.test.ts +++ b/src/testcases/parallel/simple.test.ts @@ -470,7 +470,7 @@ describe('Neutron / Simple', () => { await neutronAccount.executeContract( contractAddress, JSON.stringify({ - integration_tests_set_sudo_failure_mock: {}, + integration_tests_set_sudo_failure_mock: { state: 'enabled' }, }), ); @@ -552,6 +552,41 @@ describe('Neutron / Simple', () => { ); }); }); + + test('execute contract with sudo out of gas', async () => { + // Mock sudo handler to fail + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + integration_tests_set_sudo_failure_mock: { + state: 'enabled_infinite_loop', + }, + }), + ); + + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + send: { + channel: 'channel-0', + to: gaiaAccount.wallet.address.toString(), + denom: NEUTRON_DENOM, + amount: '1000', + }, + }), + ); + + await neutronChain.blockWaiter.waitBlocks(5); + + const res = await getWithAttempts( + neutronChain.blockWaiter, + async () => neutronChain.queryAckFailures(contractAddress), + // Wait until there 6 failures in the list + async (data) => data.failures.length == 6, + ); + expect(res.failures.length).toEqual(6); + }); + describe('Failures limit test', () => { test("failures with small limit doesn't return an error", async () => { const pagination: PageRequest = { diff --git a/src/testcases/run_in_band/interchaintx.test.ts b/src/testcases/run_in_band/interchaintx.test.ts index 416ae8d0..b7d08887 100644 --- a/src/testcases/run_in_band/interchaintx.test.ts +++ b/src/testcases/run_in_band/interchaintx.test.ts @@ -545,7 +545,7 @@ describe('Neutron / Interchain TXs', () => { await neutronAccount.executeContract( contractAddress, JSON.stringify({ - integration_tests_set_sudo_failure_mock: {}, + integration_tests_set_sudo_failure_mock: { state: 'enabled' }, }), ); @@ -669,12 +669,57 @@ describe('Neutron / Interchain TXs', () => { ); }); + test('ack failure during sudo out of gas', async () => { + // Mock sudo handler to fail + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + integration_tests_set_sudo_failure_mock: { + state: 'enabled_infinite_loop', + }, + }), + ); + + // Testing ACK failure + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + delegate: { + interchain_account_id: icaId1, + validator: testState.wallets.cosmos.val1.address.toString(), + amount: '10', + denom: gaiaChain.denom, + }, + }), + ); + + // wait until sudo is called and processed and failure is recorder + await getWithAttempts( + neutronChain.blockWaiter, + async () => neutronChain.queryAckFailures(contractAddress), + async (data) => data.failures.length == 4, + 100, + ); + + // make sure contract's state hasn't been changed + const acks = await getAcks(neutronChain, contractAddress); + expect(acks.length).toEqual(0); + + // Restore sudo handler's normal state + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + integration_tests_unset_sudo_failure_mock: {}, + }), + ); + }); + test('timeout failure during sudo', async () => { // Mock sudo handler to fail await neutronAccount.executeContract( contractAddress, JSON.stringify({ - integration_tests_set_sudo_failure_mock: {}, + integration_tests_set_sudo_failure_mock: { state: 'enabled' }, }), ); @@ -696,7 +741,53 @@ describe('Neutron / Interchain TXs', () => { await getWithAttempts( neutronChain.blockWaiter, async () => neutronChain.queryAckFailures(contractAddress), - async (data) => data.failures.length == 4, + async (data) => data.failures.length == 5, + 100, + ); + + // make sure contract's state hasn't been changed + const acks = await getAcks(neutronChain, contractAddress); + expect(acks.length).toEqual(0); + + // Restore sudo handler's normal state + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + integration_tests_unset_sudo_failure_mock: {}, + }), + ); + }); + + test('out of gas failure during sudo timeout', async () => { + // Mock sudo handler to fail + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + integration_tests_set_sudo_failure_mock: { + state: 'enabled_infinite_loop', + }, + }), + ); + + // Testing timeout failure + await neutronAccount.executeContract( + contractAddress, + JSON.stringify({ + delegate: { + interchain_account_id: icaId2, + validator: testState.wallets.cosmos.val1.address.toString(), + amount: '10', + denom: gaiaChain.denom, + timeout: 1, + }, + }), + ); + + // wait until sudo is called and processed and failure is recorder + await getWithAttempts( + neutronChain.blockWaiter, + async () => neutronChain.queryAckFailures(contractAddress), + async (data) => data.failures.length == 6, 100, ); @@ -747,6 +838,22 @@ describe('Neutron / Interchain TXs', () => { 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '3', ack_id: '5', + ack_type: 'ack', + }, + { + channel_id: 'channel-3', + address: + 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', + id: '4', + ack_id: '6', + ack_type: 'timeout', + }, + { + channel_id: 'channel-2', + address: + 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', + id: '5', + ack_id: '3', ack_type: 'timeout', }, ]); From be6e78e6b8ab2f21c487b0cf241e344b05b6d0b0 Mon Sep 17 00:00:00 2001 From: swelf Date: Fri, 15 Sep 2023 11:45:47 +0300 Subject: [PATCH 2/2] topup balance at the beginning of the test --- src/helpers/types.ts | 21 +------ src/testcases/parallel/simple.test.ts | 37 ++++++++++-- .../run_in_band/interchaintx.test.ts | 57 +++++++------------ 3 files changed, 53 insertions(+), 62 deletions(-) diff --git a/src/helpers/types.ts b/src/helpers/types.ts index 9780bf12..2d437d2b 100644 --- a/src/helpers/types.ts +++ b/src/helpers/types.ts @@ -80,26 +80,7 @@ export type AckFailuresResponse = { type Failure = { address: string; id: string; - ack: { - response: { - result: string | null; // base64 encoded bytes - error: string | null; // error text - }; - }; - ack_type: string; - packet: { - data: string; - destination_channel: string; - destination_port: string; - sequence: string; - source_channel: string; - source_port: string; - timeout_height: { - revision_height: string; - revision_number: string; - }; - timeout_timestamp: string; - }; + sudo_payload: string; // base64 encoded json bytes }; export type ScheduleResponse = { diff --git a/src/testcases/parallel/simple.test.ts b/src/testcases/parallel/simple.test.ts index d5dcb9b5..2e140e13 100644 --- a/src/testcases/parallel/simple.test.ts +++ b/src/testcases/parallel/simple.test.ts @@ -526,25 +526,54 @@ describe('Neutron / Simple', () => { expect.objectContaining({ address: contractAddress, id: '0', - ack_type: 'ack', }), expect.objectContaining({ address: contractAddress, id: '1', - ack_type: 'ack', }), expect.objectContaining({ address: contractAddress, id: '2', - ack_type: 'timeout', }), expect.objectContaining({ address: contractAddress, id: '3', - ack_type: 'timeout', }), ]); + expect( + JSON.parse( + Buffer.from( + failuresAfterCall.failures[0].sudo_payload, + 'base64', + ).toString(), + ), + ).toHaveProperty('response'); + expect( + JSON.parse( + Buffer.from( + failuresAfterCall.failures[1].sudo_payload, + 'base64', + ).toString(), + ), + ).toHaveProperty('response'); + expect( + JSON.parse( + Buffer.from( + failuresAfterCall.failures[2].sudo_payload, + 'base64', + ).toString(), + ), + ).toHaveProperty('timeout'); + expect( + JSON.parse( + Buffer.from( + failuresAfterCall.failures[3].sudo_payload, + 'base64', + ).toString(), + ), + ).toHaveProperty('timeout'); + // Restore sudo handler to state await neutronAccount.executeContract( contractAddress, diff --git a/src/testcases/run_in_band/interchaintx.test.ts b/src/testcases/run_in_band/interchaintx.test.ts index dbac5ec6..39a4c2c8 100644 --- a/src/testcases/run_in_band/interchaintx.test.ts +++ b/src/testcases/run_in_band/interchaintx.test.ts @@ -74,6 +74,10 @@ describe('Neutron / Interchain TXs', () => { }); }); describe('Create ICAs and setup contract', () => { + test('fund contract to pay fees', async () => { + const res = await neutronAccount.msgSend(contractAddress, '100000'); + expect(res.code).toEqual(0); + }); test('create ICA1', async () => { const res = await neutronAccount.executeContract( contractAddress, @@ -98,6 +102,13 @@ describe('Neutron / Interchain TXs', () => { ); expect(res.code).toEqual(0); }); + test('check contract balance', async () => { + const res = await neutronChain.queryBalances(contractAddress); + const balance = res.balances.find( + (b) => b.denom === neutronChain.denom, + )?.amount; + expect(balance).toEqual('98000'); + }); test('multiple IBC accounts created', async () => { const channels = await getWithAttempts( neutronChain.blockWaiter, @@ -157,10 +168,7 @@ describe('Neutron / Interchain TXs', () => { ); expect(res.code).toEqual(0); }); - test('fund contract to pay fees', async () => { - const res = await neutronAccount.msgSend(contractAddress, '100000'); - expect(res.code).toEqual(0); - }); + test('add some money to ICAs', async () => { const res1 = await gaiaAccount.msgSend(icaAddress1.toString(), '10000'); expect(res1.code).toEqual(0); @@ -230,7 +238,7 @@ describe('Neutron / Interchain TXs', () => { const balance = res.balances.find( (b) => b.denom === neutronChain.denom, )?.amount; - expect(balance).toEqual('98000'); + expect(balance).toEqual('96000'); }); }); @@ -304,7 +312,7 @@ describe('Neutron / Interchain TXs', () => { (b) => b.denom === neutronChain.denom, )?.amount; // two interchain txs inside (2000 * 2 = 4000) - expect(balance).toEqual('94000'); + expect(balance).toEqual('92000'); }); }); @@ -881,67 +889,37 @@ describe('Neutron / Interchain TXs', () => { test('check stored failures and acks', async () => { const failures = await neutronChain.queryAckFailures(contractAddress); - // 3 ack failures, 1 timeout failure, just as described in the tests above + // 4 ack failures, 2 timeout failure, just as described in the tests above expect(failures.failures).toEqual([ expect.objectContaining({ address: 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '0', - packet: expect.objectContaining({ - source_channel: 'channel-3', - sequence: '2', - }), - ack_type: 'ack', }), expect.objectContaining({ address: 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '1', - packet: expect.objectContaining({ - source_channel: 'channel-3', - sequence: '3', - }), - ack_type: 'ack', }), expect.objectContaining({ address: 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '2', - packet: expect.objectContaining({ - source_channel: 'channel-3', - sequence: '4', - }), - ack_type: 'ack', }), expect.objectContaining({ address: 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '3', - packet: expect.objectContaining({ - source_channel: 'channel-3', - sequence: '5', - }), - ack_type: 'ack', }), expect.objectContaining({ address: 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '4', - packet: expect.objectContaining({ - source_channel: 'channel-3', - sequence: '6', - }), - ack_type: 'timeout', }), expect.objectContaining({ address: 'neutron1m0z0kk0qqug74n9u9ul23e28x5fszr628h20xwt6jywjpp64xn4qatgvm0', id: '5', - packet: expect.objectContaining({ - source_channel: 'channel-2', - sequence: '3', - }), - ack_type: 'timeout', }), ]); @@ -1028,7 +1006,10 @@ describe('Neutron / Interchain TXs', () => { // make sure contract's state has been changed const acks = await getAcks(neutronChain, contractAddress); expect(acks.length).toEqual(1); - expect(acks[0].sequence_id).toEqual(+failure.packet.sequence); + expect(acks[0].sequence_id).toEqual( + +JSON.parse(Buffer.from(failure.sudo_payload, 'base64').toString()) + .response.request.sequence, + ); }); }); });