WIP(test):adding more unit test cases

staking
neeboo 5 years ago
parent ffbbffb07d
commit 171e0d2d46
  1. 126
      packages/harmony-transaction/src/transaction.ts
  2. 460
      packages/harmony-transaction/test/testSend.test.ts
  3. 10
      packages/harmony-transaction/test/testSign.test.ts
  4. 2
      packages/harmony-transaction/tsconfig.test.json
  5. 7
      scripts/jest/jest.src.config.js

@ -345,6 +345,25 @@ class Transaction {
}
}
async confirm(
txHash: string,
maxAttempts: number = 20,
interval: number = 1000,
shardID: number | string = this.txParams.shardID,
toShardID: number | string = this.txParams.toShardID,
) {
const txConfirmed = await this.txConfirm(txHash, maxAttempts, interval, shardID);
if (!this.isCrossShard()) {
return txConfirmed;
}
if (txConfirmed.isConfirmed()) {
const cxConfirmed = await this.cxConfirm(txHash, maxAttempts, interval, toShardID);
return cxConfirmed;
} else {
return txConfirmed;
}
}
async trackTx(txHash: string, shardID: number | string = this.shardID) {
if (!this.messenger) {
throw new Error('Messenger not found');
@ -356,7 +375,6 @@ class Transaction {
this.messenger.chainType,
typeof shardID === 'string' ? Number.parseInt(shardID, 10) : shardID,
);
if (res.isResult() && res.result !== null) {
this.receipt = res.result;
this.emitReceipt(this.receipt);
@ -393,7 +411,7 @@ class Transaction {
}
}
async confirm(
async txConfirm(
txHash: string,
maxAttempts: number = 20,
interval: number = 1000,
@ -572,74 +590,65 @@ class Transaction {
txHash: string,
maxAttempts: number = 20,
interval: number = 1000,
shardID: number | string = this.txParams.shardID,
toShardID: number | string = this.txParams.toShardID,
) {
const normalConfirmed = await this.confirm(txHash, maxAttempts, interval, shardID);
if (this.isCrossShard()) {
if (normalConfirmed.isConfirmed()) {
if (this.messenger.provider instanceof HttpProvider) {
const oldBlock = await this.getBlockNumber(toShardID);
let checkBlock = oldBlock;
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
try {
const newBlock = await this.getBlockNumber(toShardID);
// TODO: this is super ugly, must be a better way doing this
const nextBlock = checkBlock.add(new BN(attempt === 0 ? attempt : 1));
if (newBlock.gte(nextBlock)) {
checkBlock = newBlock;
this.emitCxTrack({
txHash,
attempt,
currentBlock: checkBlock.toString(),
toShardID,
});
if (await this.trackCx(txHash, toShardID)) {
this.emitCxConfirm(this.cxStatus);
return this;
}
} else {
attempt = attempt - 1 >= 0 ? attempt - 1 : 0;
}
} catch (err) {
this.cxStatus = TxStatus.REJECTED;
this.emitCxConfirm(this.cxStatus);
throw err;
}
if (this.messenger.provider instanceof HttpProvider) {
const oldBlock = await this.getBlockNumber(toShardID);
let checkBlock = oldBlock;
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
try {
const newBlock = await this.getBlockNumber(toShardID);
// TODO: this is super ugly, must be a better way doing this
const nextBlock = checkBlock.add(new BN(attempt === 0 ? attempt : 1));
if (newBlock.gte(nextBlock)) {
checkBlock = newBlock;
this.emitCxTrack({
txHash,
attempt,
currentBlock: checkBlock.toString(),
toShardID,
});
if (attempt + 1 < maxAttempts) {
// await sleep(interval * attempt);
await sleep(interval);
}
}
this.cxStatus = TxStatus.REJECTED;
this.emitCxConfirm(this.cxStatus);
throw new Error(`The transaction is still not confirmed after ${maxAttempts} attempts.`);
} else {
try {
if (await this.trackCx(txHash, toShardID)) {
this.emitCxConfirm(this.cxStatus);
return this;
} else {
const result = await this.socketCxConfirm(txHash, maxAttempts, toShardID);
return result;
}
} catch (error) {
this.cxStatus = TxStatus.REJECTED;
this.emitCxConfirm(this.cxStatus);
throw new Error(
`The transaction is still not confirmed after ${maxAttempts * interval} mil seconds.`,
);
} else {
attempt = attempt - 1 >= 0 ? attempt - 1 : 0;
}
} catch (err) {
this.cxStatus = TxStatus.REJECTED;
this.emitCxConfirm(this.cxStatus);
throw err;
}
if (attempt + 1 < maxAttempts) {
await sleep(interval);
}
}
this.cxStatus = TxStatus.REJECTED;
this.emitCxConfirm(this.cxStatus);
throw new Error(`The transaction is still not confirmed after ${maxAttempts} attempts.`);
} else {
return normalConfirmed;
try {
if (await this.trackCx(txHash, toShardID)) {
this.emitCxConfirm(this.cxStatus);
return this;
} else {
const result = await this.socketCxConfirm(txHash, maxAttempts, toShardID);
return result;
}
} catch (error) {
this.cxStatus = TxStatus.REJECTED;
this.emitCxConfirm(this.cxStatus);
throw new Error(
`The transaction is still not confirmed after ${maxAttempts * interval} mil seconds.`,
);
}
}
}
async trackCx(txHash: string, toShardID: number | string) {
if (!this.messenger) {
throw new Error('Messenger not found');
@ -651,7 +660,6 @@ class Transaction {
this.messenger.chainPrefix,
typeof toShardID === 'string' ? Number.parseInt(toShardID, 10) : toShardID,
);
if (res.isResult() && res.result !== null) {
this.emitCxReceipt(res.result);
this.cxStatus = TxStatus.CONFIRMED;
@ -660,7 +668,7 @@ class Transaction {
const currentBlock = await this.getBlockNumber(toShardID);
this.cxBlockNumbers.push('0x' + currentBlock.toString('hex'));
this.cxConfirmationCheck += 1;
this.cxStatus = TxStatus.REJECTED;
this.cxStatus = TxStatus.PENDING;
return false;
}
}

@ -0,0 +1,460 @@
import { TransactionFactory, Transaction, TxStatus } from '../src';
// tslint:disable-next-line: no-implicit-dependencies
import { Wallet } from '@harmony-js/account';
import { HttpProvider, Messenger } from '@harmony-js/network';
import { ChainType, ChainID } from '@harmony-js/utils';
import { toChecksumAddress, randomBytes } from '@harmony-js/crypto';
// tslint:disable-next-line: no-implicit-dependencies
import fetch from 'jest-fetch-mock';
const http = new HttpProvider('http://mock.com');
// const ws = new WSProvider('ws://mock.com');
const addr = toChecksumAddress('0x' + randomBytes(20));
const msgHttp = new Messenger(http, ChainType.Harmony, ChainID.HmyLocal);
// const msgWs = new Messenger(ws, ChainType.Harmony, ChainID.HmyLocal);
const walletHttp = new Wallet(msgHttp);
// const walletWs = new Wallet(msgWs);
describe('test send transaction', () => {
beforeEach(() => {
// jest.useFakeTimers();
});
afterEach(() => {
fetch.resetMocks();
// jest.clearAllTimers();
});
it('should test wallet sign and send', async () => {
const responses = [
{
jsonrpc: '2.0',
id: 1,
result: '0x666666666666',
},
{
jsonrpc: '2.0',
id: 1,
result: '0x1',
},
{
jsonrpc: '2.0',
id: 1,
result: '0x7e1ef610f700805b93cf85b1e55bce84fcbd04373252a968755366a8d2215424',
},
].map((res) => [JSON.stringify(res)] as [string]);
fetch.mockResponses(...responses);
const factory = new TransactionFactory(msgHttp);
const tx: Transaction = factory.newTx(
{
to: addr,
value: '1',
gasLimit: '21000',
gasPrice: '1',
},
false,
);
expect(tx.txStatus).toEqual(TxStatus.INTIALIZED);
const account: any | Account = await walletHttp.createAccount();
const signed: Transaction = await account.signTransaction(tx, true, 'rlp', 'latest');
expect(signed.txStatus).toEqual(TxStatus.SIGNED);
expect(signed.txParams.nonce).toEqual(1);
expect(signed.txPayload.nonce).toEqual('0x1');
expect(signed.txParams.signature.r).toBeTruthy();
expect(signed.txParams.signature.s).toBeTruthy();
expect(signed.txParams.signature.v).toBeTruthy();
expect(signed.txParams.rawTransaction).toEqual(signed.getRawTransaction());
const [sent, hash] = await signed.sendTransaction();
expect(sent.txParams.id).toEqual(hash);
expect(sent.txStatus).toEqual(TxStatus.PENDING);
});
it('should test wallet sign and send shardingTransaction', async () => {
const factory = new TransactionFactory(msgHttp);
const tx: Transaction = factory.newTx(
{
to: addr + '-1',
value: '1',
gasLimit: '21000',
gasPrice: '1',
},
true,
);
expect(tx.cxStatus).toEqual(TxStatus.INTIALIZED);
});
it('should reject and confirm tx', async () => {
const responses = [
{
jsonrpc: '2.0',
id: 1,
result: [
{
current: true,
http: 'http://localhost',
shardID: 0,
ws: 'ws://localhost',
},
{
current: false,
http: 'http://localhost',
shardID: 1,
ws: 'ws://localhost',
},
],
},
{
jsonrpc: '2.0',
id: 5,
result: '0x0',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x1',
},
{
jsonrpc: '2.0',
id: 5,
result: null,
},
{
jsonrpc: '2.0',
id: 5,
result: '0x1',
},
// attemp 1
{
jsonrpc: '2.0',
id: 5,
result: '0x2',
},
{
jsonrpc: '2.0',
id: 5,
result: null,
},
{
jsonrpc: '2.0',
id: 5,
result: '0x2',
},
// attemp 2
{
jsonrpc: '2.0',
id: 5,
result: '0x3',
},
{
jsonrpc: '2.0',
id: 5,
result: null,
},
{
jsonrpc: '2.0',
id: 5,
result: '0x3',
},
// attemp 3
{
jsonrpc: '2.0',
id: 5,
result: '0x4',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x5',
},
{
jsonrpc: '2.0',
id: 3,
result: {
blockHash: '0x7ef01c8532dbe8ae9930ebf3d38cf5f3937193c3c90680d4e9d5206552e4f6a6',
blockNumber: '0x1d3c0',
contractAddress: null,
cumulativeGasUsed: '0x5208',
from: 'one1z05g55zamqzfw9qs432n33gycdmyvs38xjemyl',
gasUsed: '0x5208',
logs: [],
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
shardID: 0,
status: '0x1',
to: 'one1z05g55zamqzfw9qs432n33gycdmyvs38xjemyl',
transactionHash: '0x1bb3cadb2031e5ce987b0c557abe134986b9834963dd0d54f75a9c7d966606ce',
transactionIndex: '0x0',
},
},
{
jsonrpc: '2.0',
id: 5,
result: '0x5',
},
].map((res) => [JSON.stringify(res)] as [string]);
fetch.mockResponses(...responses);
const hash = '0x7e1ef610f700805b93cf85b1e55bce84fcbd04373252a968755366a8d2215424';
const factory = new TransactionFactory(msgHttp);
const shardID = 0;
const toShardID = 1;
const tx: Transaction = factory.newTx({ shardID, toShardID }, false);
expect(tx.cxStatus).toEqual(TxStatus.INTIALIZED);
await tx.messenger.setShardingProviders();
await expect(tx.txConfirm(hash, 3, 100, shardID)).rejects.toThrow(
'The transaction is still not confirmed after 3 attempts.',
);
const confirmed = await tx.txConfirm(hash, 4, 100, shardID);
expect(confirmed.txStatus).toEqual(TxStatus.CONFIRMED);
});
it('should reject and confirm cx', async () => {
const responses = [
{
jsonrpc: '2.0',
id: 1,
result: [
{
current: true,
http: 'http://localhost',
shardID: 0,
ws: 'ws://localhost',
},
{
current: false,
http: 'http://localhost',
shardID: 1,
ws: 'ws://localhost',
},
],
},
{
jsonrpc: '2.0',
id: 5,
result: '0x0',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x1',
},
{
jsonrpc: '2.0',
id: 5,
result: null,
},
{
jsonrpc: '2.0',
id: 5,
result: '0x1',
},
// attemp 1
{
jsonrpc: '2.0',
id: 5,
result: '0x2',
},
{
jsonrpc: '2.0',
id: 5,
result: null,
},
{
jsonrpc: '2.0',
id: 5,
result: '0x2',
},
// attemp 2
{
jsonrpc: '2.0',
id: 5,
result: '0x3',
},
{
jsonrpc: '2.0',
id: 5,
result: null,
},
{
jsonrpc: '2.0',
id: 5,
result: '0x3',
},
// attemp 3
{
jsonrpc: '2.0',
id: 5,
result: '0x4',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x5',
},
{
jsonrpc: '2.0',
id: 6,
result: {
blockHash: '0xd92f3610d52bde907ab42e064d73c2314c058015a7162ee8a4500bc581903cc2',
blockNumber: '0x18465',
hash: '0xcff4a3a6fd4eb34b9a7e48e3eca0c8c899de71a1ea21a126cc1048e65b332a72',
from: 'one1v5fevthrnfeqjwcl5p0sfq3u34c2gmtqq095at',
to: 'one18spwh74s5hkg2nva40scx7hwdjpup28dw4dfsg',
shardID: 0,
toShardID: 1,
value: '0xde0b6b3a7640000',
},
},
{
jsonrpc: '2.0',
id: 5,
result: '0x5',
},
].map((res) => [JSON.stringify(res)] as [string]);
fetch.mockResponses(...responses);
const hash = '0x7e1ef610f700805b93cf85b1e55bce84fcbd04373252a968755366a8d2215424';
const factory = new TransactionFactory(msgHttp);
const shardID = 0;
const toShardID = 1;
const tx: Transaction = factory.newTx({ shardID, toShardID }, false);
expect(tx.cxStatus).toEqual(TxStatus.INTIALIZED);
await tx.messenger.setShardingProviders();
await expect(tx.cxConfirm(hash, 3, 100, toShardID)).rejects.toThrow(
'The transaction is still not confirmed after 3 attempts.',
);
const confirmed = await tx.cxConfirm(hash, 4, 100, toShardID);
expect(confirmed.cxStatus).toEqual(TxStatus.CONFIRMED);
});
it('should confirm and confirm cx', async () => {
const responses = [
{
jsonrpc: '2.0',
id: 1,
result: [
{
current: true,
http: 'http://localhost',
shardID: 0,
ws: 'ws://localhost',
},
{
current: false,
http: 'http://localhost',
shardID: 1,
ws: 'ws://localhost',
},
],
},
{
jsonrpc: '2.0',
id: 5,
result: '0x0',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x1',
},
{
jsonrpc: '2.0',
id: 3,
result: {
blockHash: '0x7ef01c8532dbe8ae9930ebf3d38cf5f3937193c3c90680d4e9d5206552e4f6a6',
blockNumber: '0x1d3c0',
contractAddress: null,
cumulativeGasUsed: '0x5208',
from: 'one1z05g55zamqzfw9qs432n33gycdmyvs38xjemyl',
gasUsed: '0x5208',
logs: [],
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
shardID: 0,
status: '0x1',
to: 'one1z05g55zamqzfw9qs432n33gycdmyvs38xjemyl',
transactionHash: '0x1bb3cadb2031e5ce987b0c557abe134986b9834963dd0d54f75a9c7d966606ce',
transactionIndex: '0x0',
},
},
{
jsonrpc: '2.0',
id: 5,
result: '0x1',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x4',
},
{
jsonrpc: '2.0',
id: 5,
result: '0x5',
},
{
jsonrpc: '2.0',
id: 6,
result: {
blockHash: '0xd92f3610d52bde907ab42e064d73c2314c058015a7162ee8a4500bc581903cc2',
blockNumber: '0x18465',
hash: '0xcff4a3a6fd4eb34b9a7e48e3eca0c8c899de71a1ea21a126cc1048e65b332a72',
from: 'one1v5fevthrnfeqjwcl5p0sfq3u34c2gmtqq095at',
to: 'one18spwh74s5hkg2nva40scx7hwdjpup28dw4dfsg',
shardID: 0,
toShardID: 1,
value: '0xde0b6b3a7640000',
},
},
{
jsonrpc: '2.0',
id: 5,
result: '0x5',
},
].map((res) => [JSON.stringify(res)] as [string]);
fetch.mockResponses(...responses);
const hash = '0x7e1ef610f700805b93cf85b1e55bce84fcbd04373252a968755366a8d2215424';
const factory = new TransactionFactory(msgHttp);
const shardID = 0;
const toShardID = 1;
const tx: Transaction = factory.newTx({ shardID, toShardID }, false);
expect(tx.txStatus).toEqual(TxStatus.INTIALIZED);
expect(tx.cxStatus).toEqual(TxStatus.INTIALIZED);
await tx.messenger.setShardingProviders();
tx.observed()
.on('track', (track) => {
expect(track).toBeTruthy();
})
.on('confirmation', (confirmation) => {
expect(confirmation).toBeTruthy();
});
const confirmed = await tx.confirm(hash);
expect(confirmed.isSigned()).toEqual(false);
expect(confirmed.isPending()).toEqual(false);
expect(confirmed.isRejected()).toEqual(false);
expect(confirmed.isInitialized()).toEqual(false);
expect(confirmed.isConfirmed()).toEqual(true);
expect(confirmed.isCxPending()).toEqual(false);
expect(confirmed.isCxRejected()).toEqual(false);
expect(confirmed.isCxConfirmed()).toEqual(true);
confirmed.setCxStatus(confirmed.cxStatus);
confirmed.setTxStatus(confirmed.txStatus);
expect(confirmed.getTxStatus()).toEqual(TxStatus.CONFIRMED);
expect(confirmed.getCxStatus()).toEqual(TxStatus.CONFIRMED);
});
});

@ -114,10 +114,9 @@ describe('test sign tranction', () => {
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < reTxnVectors.length; i += 1) {
const vector = reTxnVectors[i];
const transaction: Transaction = new Transaction({});
transaction.setMessenger(hmyMessenger);
transaction.recover(vector.signedTransaction);
const factory = new TransactionFactory(hmyMessenger);
factory.setMessenger(hmyMessenger);
const transaction: Transaction = factory.recover(vector.signedTransaction);
if (vector.gasLimit && vector.gasLimit !== '0x') {
expect(transaction.txParams.gasLimit.toString()).toEqual(
@ -151,7 +150,8 @@ describe('test sign tranction', () => {
it('should test transactionFactory', () => {
const hmyMessenger = new Messenger(provider, ChainType.Harmony, ChainID.Default);
const factory = new TransactionFactory(hmyMessenger);
const txn = factory.newTx({}, false);
factory.setMessenger(hmyMessenger);
const txn = factory.newTx({});
expect(txn.getRLPUnsigned()[0]).toBeTruthy();
const txn2 = factory.newTx({}, true);
expect(txn2.getRLPUnsigned()[0]).toBeTruthy();

@ -1,5 +1,5 @@
{
"extends": "../../tsconfig.test.json",
"include": ["src", "test", "../../typings/**/*.d.ts"],
"include": ["src", "test", "../../typings/**/*.d.ts", "src/types"],
"references": []
}

@ -12,6 +12,8 @@ const config = {
testMatch: [
// '<rootDir>/packages/**/test/?(*.)+(spec|test).js',
'<rootDir>/packages/harmony-core/test/?(*.)+(spec|test).ts',
'<rootDir>/packages/harmony-account/test/?(*.)+(spec|test).ts',
'<rootDir>/packages/harmony-network/test/?(*.)+(spec|test).ts',
'<rootDir>/packages/harmony-crypto/test/?(*.)+(spec|test).ts',
'<rootDir>/packages/harmony-contract/test/?(*.)+(spec|test).ts',
'<rootDir>/packages/harmony-transaction/test/?(*.)+(spec|test).ts',
@ -39,8 +41,11 @@ const config = {
'packages/harmony-utils/src/**/*.ts',
'packages/harmony-crypto/src/**/*.ts',
'packages/harmony-transaction/src/**/*.ts',
'packages/harmony-network/src/**/*.ts',
'packages/harmony-contract/src/**/*.ts',
'packages/harmony-account/src/**/*.ts',
],
timers: 'fake',
// timers: 'fake',
setupFiles: ['<rootDir>/scripts/jest/jest.setup.js'],
setupTestFrameworkScriptFile: '<rootDir>/scripts/jest/jest.framework-setup.js',
testEnvironment: process.env.NODE_ENV === 'development' ? 'node' : 'jsdom',

Loading…
Cancel
Save