|
| 1 | +/* eslint-disable no-await-in-loop */ |
| 2 | +import chai, { expect } from 'chai'; |
| 3 | +// import gen from 'general-number'; |
| 4 | +import chaiHttp from 'chai-http'; |
| 5 | +import chaiAsPromised from 'chai-as-promised'; |
| 6 | +import config from 'config'; |
| 7 | +import logger from '@polygon-nightfall/common-files/utils/logger.mjs'; |
| 8 | +import Nf3 from '../cli/lib/nf3.mjs'; |
| 9 | +import { |
| 10 | + getLayer2Balances, |
| 11 | + expectTransaction, |
| 12 | + Web3Client, |
| 13 | + getUserCommitments, |
| 14 | + getClientTransactions, |
| 15 | + restartClient, |
| 16 | +} from './utils.mjs'; |
| 17 | + |
| 18 | +chai.use(chaiHttp); |
| 19 | +chai.use(chaiAsPromised); |
| 20 | + |
| 21 | +// const { generalise } = gen; |
| 22 | +const environment = config.ENVIRONMENTS[process.env.ENVIRONMENT] || config.ENVIRONMENTS.localhost; |
| 23 | +const { |
| 24 | + fee, |
| 25 | + transferValue, |
| 26 | + tokenConfigs: { tokenType, tokenId }, |
| 27 | + mnemonics, |
| 28 | + signingKeys, |
| 29 | +} = config.TEST_OPTIONS; |
| 30 | + |
| 31 | +const web3Client = new Web3Client(); |
| 32 | +const eventLogs = []; |
| 33 | +let rollbackCount = 0; |
| 34 | + |
| 35 | +const nf3User = new Nf3(signingKeys.user1, environment); |
| 36 | +const nf3User2 = new Nf3(signingKeys.user2, environment); |
| 37 | + |
| 38 | +const nf3Proposer = new Nf3(signingKeys.proposer1, environment); |
| 39 | + |
| 40 | +async function makeBlock() { |
| 41 | + logger.debug(`Make block...`); |
| 42 | + await nf3Proposer.makeBlockNow(); |
| 43 | + await web3Client.waitForEvent(eventLogs, ['blockProposed']); |
| 44 | +} |
| 45 | + |
| 46 | +describe('Client synchronisation tests', () => { |
| 47 | + let erc20Address; |
| 48 | + |
| 49 | + before(async () => { |
| 50 | + await nf3User.init(mnemonics.user1); |
| 51 | + await nf3User2.init(mnemonics.user2); |
| 52 | + |
| 53 | + await nf3Proposer.init(mnemonics.proposer); |
| 54 | + await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); |
| 55 | + |
| 56 | + // Proposer listening for incoming events |
| 57 | + const newGasBlockEmitter = await nf3Proposer.startProposer(); |
| 58 | + newGasBlockEmitter.on('rollback', () => { |
| 59 | + rollbackCount += 1; |
| 60 | + logger.debug( |
| 61 | + `Proposer received a signalRollback complete, Now no. of rollbacks are ${rollbackCount}`, |
| 62 | + ); |
| 63 | + }); |
| 64 | + |
| 65 | + erc20Address = await nf3User.getContractAddress('ERC20Mock'); |
| 66 | + web3Client.subscribeTo('logs', eventLogs, { address: nf3User.stateContractAddress }); |
| 67 | + web3Client.subscribeTo('logs', eventLogs, { address: nf3User.shieldContractAddress }); |
| 68 | + }); |
| 69 | + |
| 70 | + describe('Test nightfall-client', () => { |
| 71 | + it('Should do two deposit successfully', async function () { |
| 72 | + const userL2BalanceBefore = await getLayer2Balances(nf3User, erc20Address); |
| 73 | + |
| 74 | + // first deposit |
| 75 | + const res = await nf3User.deposit(erc20Address, tokenType, transferValue, tokenId, fee); |
| 76 | + expectTransaction(res); |
| 77 | + |
| 78 | + await web3Client.waitForEvent(eventLogs, ['TransactionSubmitted']); |
| 79 | + const transactions = await getClientTransactions(environment.clientApiUrl); |
| 80 | + |
| 81 | + // passing of below expect proves that transaction are save in |
| 82 | + // transactionEventHandler |
| 83 | + expect(transactions.length).to.be.equal(1); |
| 84 | + expect(res.transactionHashL2).to.be.equal(transactions[0].transactionHash); |
| 85 | + |
| 86 | + await makeBlock(); |
| 87 | + |
| 88 | + // second deposit |
| 89 | + await nf3User.deposit(erc20Address, tokenType, transferValue, tokenId, fee); |
| 90 | + |
| 91 | + await makeBlock(); |
| 92 | + |
| 93 | + const userL2BalanceAfter = await getLayer2Balances(nf3User, erc20Address); |
| 94 | + expect(userL2BalanceAfter - userL2BalanceBefore).to.be.equal(transferValue * 2 - fee * 2); |
| 95 | + }); |
| 96 | + |
| 97 | + // this test is to check nightfall-client behaviour in a case |
| 98 | + // where two same transfer transactions is created but second one with higher fee |
| 99 | + context('Test nightfall-client duplicate transaction deletion logic', () => { |
| 100 | + let userCommitments; |
| 101 | + let firstTransfer; |
| 102 | + let userL2BalanceBefore; |
| 103 | + before(async () => { |
| 104 | + userCommitments = await getUserCommitments( |
| 105 | + environment.clientApiUrl, |
| 106 | + nf3User.zkpKeys.compressedZkpPublicKey, |
| 107 | + ); |
| 108 | + userL2BalanceBefore = await getLayer2Balances(nf3User, erc20Address); |
| 109 | + }); |
| 110 | + |
| 111 | + it('Should successfully create a transfer transaction', async function () { |
| 112 | + const res = await nf3User.transfer( |
| 113 | + false, |
| 114 | + erc20Address, |
| 115 | + tokenType, |
| 116 | + transferValue, |
| 117 | + tokenId, |
| 118 | + nf3User2.zkpKeys.compressedZkpPublicKey, |
| 119 | + fee, |
| 120 | + userCommitments.map(c => c.commitmentHash), |
| 121 | + ); |
| 122 | + expectTransaction(res); |
| 123 | + firstTransfer = res.transactionHashL2; |
| 124 | + await web3Client.waitForEvent(eventLogs, ['TransactionSubmitted']); |
| 125 | + const transactions = await getClientTransactions(environment.clientApiUrl); |
| 126 | + |
| 127 | + expect(transactions.length).to.be.equal(3); |
| 128 | + expect(res.transactionHashL2).to.be.equal(transactions[2].transactionHash); |
| 129 | + }); |
| 130 | + |
| 131 | + it('Should successfully do a transfer with higher fee with create block', async function () { |
| 132 | + let transactions; |
| 133 | + const res = await nf3User.transfer( |
| 134 | + false, |
| 135 | + erc20Address, |
| 136 | + tokenType, |
| 137 | + transferValue, |
| 138 | + tokenId, |
| 139 | + nf3User2.zkpKeys.compressedZkpPublicKey, |
| 140 | + fee + 1, |
| 141 | + userCommitments.map(c => c.commitmentHash), |
| 142 | + ); |
| 143 | + expectTransaction(res); |
| 144 | + |
| 145 | + transactions = await getClientTransactions(environment.clientApiUrl); |
| 146 | + expect(transactions.length).to.be.equal(3); |
| 147 | + expect(firstTransfer).to.be.equal(transactions[2].transactionHash); |
| 148 | + |
| 149 | + // here we will also test client resync atleast for TransactionSubmitEvent Handler |
| 150 | + await restartClient(nf3User); |
| 151 | + |
| 152 | + transactions = await getClientTransactions(environment.clientApiUrl); |
| 153 | + // if below expect passes it proves client resync is working. |
| 154 | + expect(transactions.length).to.be.equal(4); |
| 155 | + expect(res.transactionHashL2).to.be.equal(transactions[3].transactionHash); |
| 156 | + |
| 157 | + // client re-sync has made sure higer fee transfer transaction is received in |
| 158 | + // transaction submit eventHandler, infact that what passing of above expect proves |
| 159 | + // But for optimist to receive same transaction lets wait for TransactionSubmitted |
| 160 | + // event trigger, needed before proceeding to makeBLock |
| 161 | + await web3Client.waitForEvent(eventLogs, ['TransactionSubmitted']); |
| 162 | + await makeBlock(); |
| 163 | + const userL2BalanceAfter = await getLayer2Balances(nf3User, erc20Address); |
| 164 | + expect(userL2BalanceAfter - userL2BalanceBefore).to.be.equal(-(transferValue + fee + 1)); |
| 165 | + |
| 166 | + transactions = await getClientTransactions(environment.clientApiUrl); |
| 167 | + // if below expect passes it proves blockEventHandler delete duplicate transaction is working. |
| 168 | + expect(transactions.length).to.be.equal(3); |
| 169 | + expect(res.transactionHashL2).to.be.equal(transactions[2].transactionHash); |
| 170 | + }); |
| 171 | + }); |
| 172 | + }); |
| 173 | +}); |
0 commit comments