Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/5.2.1' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
shuse2 committed Jan 17, 2022
2 parents 2593d1f + 30fb53e commit 1b30f30
Show file tree
Hide file tree
Showing 36 changed files with 843 additions and 104 deletions.
10 changes: 5 additions & 5 deletions commander/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lisk-commander",
"version": "5.1.7",
"version": "5.1.8-alpha.3",
"description": "A command line interface for Lisk",
"author": "Lisk Foundation <admin@lisk.io>, lightcurve GmbH <admin@lightcurve.io>",
"license": "Apache-2.0",
Expand Down Expand Up @@ -91,15 +91,15 @@
"/docs"
],
"dependencies": {
"@liskhq/lisk-api-client": "^5.1.4",
"@liskhq/lisk-api-client": "^5.1.5-alpha.0",
"@liskhq/lisk-chain": "^0.3.3",
"@liskhq/lisk-client": "^5.2.0",
"@liskhq/lisk-client": "^5.2.1-alpha.0",
"@liskhq/lisk-codec": "^0.2.1",
"@liskhq/lisk-cryptography": "^3.2.0",
"@liskhq/lisk-db": "^0.2.0",
"@liskhq/lisk-genesis": "^0.2.3",
"@liskhq/lisk-passphrase": "^3.1.0",
"@liskhq/lisk-transactions": "^5.2.0",
"@liskhq/lisk-transactions": "^5.2.1-alpha.0",
"@liskhq/lisk-utils": "^0.2.0",
"@liskhq/lisk-validator": "^0.6.1",
"@oclif/command": "1.8.0",
Expand All @@ -114,7 +114,7 @@
"cli-table3": "0.6.0",
"fs-extra": "9.1.0",
"inquirer": "8.0.0",
"lisk-framework": "^0.9.0",
"lisk-framework": "^0.9.1-alpha.3",
"listr": "0.14.3",
"progress": "2.0.3",
"semver": "7.3.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,15 @@
}
},
"dependencies": {
"@liskhq/lisk-framework-dashboard-plugin": "^0.1.4",
"@liskhq/lisk-framework-faucet-plugin": "^0.1.4",
"@liskhq/lisk-framework-dashboard-plugin": "^0.1.6-alpha.2",
"@liskhq/lisk-framework-faucet-plugin": "^0.1.6-alpha.2",
"@oclif/command": "1.8.0",
"@oclif/plugin-autocomplete": "0.3.0",
"@oclif/plugin-help": "3.2.2",
"fs-extra": "9.0.1",
"inquirer": "7.3.2",
"lisk-commander": "^5.1.5",
"lisk-sdk": "^5.1.4",
"lisk-commander": "^5.1.8-alpha.2",
"lisk-sdk": "^5.2.1-alpha.2",
"tar": "6.0.2",
"tslib": "1.13.0",
"axios": "0.21.1"
Expand Down
4 changes: 2 additions & 2 deletions elements/lisk-api-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@liskhq/lisk-api-client",
"version": "5.1.4",
"version": "5.1.5-alpha.0",
"description": "An API client for the Lisk network",
"author": "Lisk Foundation <admin@lisk.io>, lightcurve GmbH <admin@lightcurve.io>",
"license": "Apache-2.0",
Expand Down Expand Up @@ -38,7 +38,7 @@
"dependencies": {
"@liskhq/lisk-codec": "^0.2.1",
"@liskhq/lisk-cryptography": "^3.2.0",
"@liskhq/lisk-transactions": "^5.2.0",
"@liskhq/lisk-transactions": "^5.2.1-alpha.0",
"isomorphic-ws": "4.0.1",
"pm2-axon": "4.0.1",
"pm2-axon-rpc": "0.7.1",
Expand Down
6 changes: 3 additions & 3 deletions elements/lisk-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@liskhq/lisk-client",
"version": "5.2.0",
"version": "5.2.1-alpha.0",
"description": "A default set of Elements for use by clients of the Lisk network",
"author": "Lisk Foundation <admin@lisk.io>, lightcurve GmbH <admin@lightcurve.io>",
"license": "Apache-2.0",
Expand Down Expand Up @@ -55,11 +55,11 @@
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@liskhq/lisk-api-client": "^5.1.4",
"@liskhq/lisk-api-client": "^5.1.5-alpha.0",
"@liskhq/lisk-codec": "^0.2.1",
"@liskhq/lisk-cryptography": "^3.2.0",
"@liskhq/lisk-passphrase": "^3.1.0",
"@liskhq/lisk-transactions": "^5.2.0",
"@liskhq/lisk-transactions": "^5.2.1-alpha.0",
"@liskhq/lisk-tree": "^0.2.1",
"@liskhq/lisk-utils": "^0.2.0",
"@liskhq/lisk-validator": "^0.6.1",
Expand Down
8 changes: 4 additions & 4 deletions elements/lisk-elements/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lisk-elements",
"version": "5.2.0",
"version": "5.2.1-alpha.2",
"description": "Elements for building blockchain applications in the Lisk network",
"author": "Lisk Foundation <admin@lisk.io>, lightcurve GmbH <admin@lightcurve.io>",
"license": "Apache-2.0",
Expand Down Expand Up @@ -36,7 +36,7 @@
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@liskhq/lisk-api-client": "^5.1.4",
"@liskhq/lisk-api-client": "^5.1.5-alpha.0",
"@liskhq/lisk-bft": "^0.3.3",
"@liskhq/lisk-chain": "^0.3.3",
"@liskhq/lisk-codec": "^0.2.1",
Expand All @@ -45,8 +45,8 @@
"@liskhq/lisk-genesis": "^0.2.3",
"@liskhq/lisk-p2p": "^0.7.2",
"@liskhq/lisk-passphrase": "^3.1.0",
"@liskhq/lisk-transaction-pool": "^0.5.1",
"@liskhq/lisk-transactions": "^5.2.0",
"@liskhq/lisk-transaction-pool": "^0.5.2-alpha.1",
"@liskhq/lisk-transactions": "^5.2.1-alpha.0",
"@liskhq/lisk-tree": "^0.2.1",
"@liskhq/lisk-utils": "^0.2.0",
"@liskhq/lisk-validator": "^0.6.1"
Expand Down
2 changes: 1 addition & 1 deletion elements/lisk-transaction-pool/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@liskhq/lisk-transaction-pool",
"version": "0.5.1",
"version": "0.5.2-alpha.1",
"description": "Transaction pool library for use with Lisk-related software",
"author": "Lisk Foundation <admin@lisk.io>, lightcurve GmbH <admin@lightcurve.io>",
"license": "Apache-2.0",
Expand Down
38 changes: 30 additions & 8 deletions elements/lisk-transaction-pool/src/transaction_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface TransactionPoolConfig {
readonly transactionReorganizationInterval?: number;
readonly minReplacementFeeDifference?: bigint;
readonly minFeePerByte: number;
readonly maxPayloadLength: number;
readonly baseFees: BaseFee[];
applyTransactions(transactions: ReadonlyArray<Transaction>): Promise<void>;
}
Expand Down Expand Up @@ -80,6 +81,7 @@ export class TransactionPool {
private readonly _transactionReorganizationInterval: number;
private readonly _minReplacementFeeDifference: bigint;
private readonly _minFeePerByte: number;
private readonly _maxPayloadLength: number;
private readonly _baseFees: BaseFee[];
private readonly _reorganizeJob: Job<void>;
private readonly _feePriorityQueue: dataStructures.MinHeap<Buffer, bigint>;
Expand All @@ -104,6 +106,7 @@ export class TransactionPool {
config.minReplacementFeeDifference ?? DEFAULT_MINIMUM_REPLACEMENT_FEE_DIFFERENCE;
this._baseFees = config.baseFees;
this._minFeePerByte = config.minFeePerByte;
this._maxPayloadLength = config.maxPayloadLength;
this._reorganizeJob = new Job(
async () => this._reorganize(),
this._transactionReorganizationInterval,
Expand Down Expand Up @@ -144,6 +147,15 @@ export class TransactionPool {
5. If PROCESSABLE or UNPROCESSABLE then add it to transactionList and feePriorityQueue, if INVALID then return a relevant error
*/
public async add(incomingTx: Transaction): Promise<AddTransactionResponse> {
// Reject a transaction when its size is greater than maxPayloadLength
if (incomingTx.getBytes().byteLength > this._maxPayloadLength) {
const error = new TransactionPoolError(
`Transaction byte length is greater than ${this._maxPayloadLength}`,
incomingTx.id,
);

return { status: Status.FAIL, error };
}
// Check for duplicate
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (this._allTransactions.has(incomingTx.id)) {
Expand Down Expand Up @@ -176,15 +188,25 @@ export class TransactionPool {
lowestFeePriorityTrx &&
incomingTx.feePriority <= lowestFeePriorityTrx.key
) {
const error = new TransactionPoolError(
'Rejecting transaction due to fee priority when the pool is full.',
incomingTx.id,
'.fee',
incomingTx.feePriority.toString(),
lowestFeePriorityTrx.key.toString(),
);
let totalUnprocessable = 0;
for (const txList of this._transactionList.values()) {
totalUnprocessable += txList.getUnprocessable().length;
}

return { status: Status.FAIL, error };
// If TxPool is full with only unprocessable transactions then it will evict the transaction with the lowestFeePriority
if (totalUnprocessable >= Math.floor(this._maxTransactions / 2)) {
this._evictUnprocessable();
} else {
const error = new TransactionPoolError(
'Rejecting transaction due to fee priority when the pool is full.',
incomingTx.id,
'.fee',
incomingTx.feePriority.toString(),
lowestFeePriorityTrx.key.toString(),
);

return { status: Status.FAIL, error };
}
}

const incomingTxAddress = getAddressFromPublicKey(incomingTx.senderPublicKey);
Expand Down
104 changes: 100 additions & 4 deletions elements/lisk-transaction-pool/test/unit/transaction_pool.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
*/
import { when } from 'jest-when';
import { getAddressFromPublicKey } from '@liskhq/lisk-cryptography';
import { getAddressFromPublicKey, getRandomBytes } from '@liskhq/lisk-cryptography';
import { TransactionList } from '../../src/transaction_list';
import { TransactionPool } from '../../src/transaction_pool';
import { Transaction, Status, TransactionStatus } from '../../src/types';
Expand All @@ -35,6 +35,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});
jest.spyOn(transactionPool.events, 'emit');
});
Expand Down Expand Up @@ -67,6 +68,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});

expect((transactionPool as any)._maxTransactions).toEqual(2048);
Expand Down Expand Up @@ -246,8 +248,21 @@ describe('TransactionPool class', () => {
senderPublicKey: generateRandomPublicKeys()[0],
} as Transaction;

txGetBytesStub = jest.fn();
tx.getBytes = txGetBytesStub.mockReturnValue(Buffer.from(new Array(10)));
beforeEach(() => {
txGetBytesStub = jest.fn();
tx.getBytes = txGetBytesStub.mockReturnValue(Buffer.from(new Array(10)));
});

it('should throw error when transaction size is higher than maxPayloadLength', async () => {
// Arrange
const txGetBytesTempStub = jest.fn();
tx.getBytes = txGetBytesTempStub.mockReturnValue(getRandomBytes(15400));
// Act
const { status } = await transactionPool.add(tx);
txGetBytesTempStub.mockReset();

expect(status).toEqual(Status.FAIL);
});

it('should add a valid transaction to the transaction list as processable', async () => {
// Act
Expand Down Expand Up @@ -355,6 +370,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});
const lowFeeTrx = {
id: Buffer.from('1'),
Expand Down Expand Up @@ -390,6 +406,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});

const tempApplyTransactionsStub = jest.fn();
Expand Down Expand Up @@ -454,6 +471,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});

const tempApplyTransactionsStub = jest.fn();
Expand Down Expand Up @@ -533,6 +551,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});

const tempApplyTransactionsStub = jest.fn();
Expand Down Expand Up @@ -576,6 +595,80 @@ describe('TransactionPool class', () => {

expect(status).toEqual(Status.FAIL);
});

it('should accept a transaction with a lower feePriority than the unprocessable trx with lowest feePriority present in TxPool', async () => {
const MAX_TRANSACTIONS = 10;
transactionPool = new TransactionPool({
applyTransactions: jest.fn(),
minEntranceFeePriority: BigInt(10),
maxTransactions: MAX_TRANSACTIONS,
baseFees: [
{
assetID: 0,
baseFee: BigInt(1),
moduleID: 3,
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});

const tempApplyTransactionsStub = jest.fn();
(transactionPool as any)._applyFunction = tempApplyTransactionsStub;
txGetBytesStub = jest.fn();
for (let i = 0; i < MAX_TRANSACTIONS; i += 1) {
const tempTx = {
id: Buffer.from(`${i.toString()}`),
moduleID: 3,
assetID: 0,
nonce: BigInt(1),
fee: BigInt(30000),
senderPublicKey: generateRandomPublicKeys()[0],
} as Transaction;
tempTx.getBytes = txGetBytesStub.mockReturnValue(
Buffer.from(new Array(MAX_TRANSACTIONS + i)),
);

// half the trx are unprocessable
if (i < 5) {
when(tempApplyTransactionsStub)
.calledWith([tempTx])
.mockRejectedValue({
transactionError: { code: 'ERR_NONCE_OUT_OF_BOUNDS' },
code: 'ERR_TRANSACTION_VERIFICATION_FAIL',
});
} else {
when(tempApplyTransactionsStub)
.calledWith([tempTx])
.mockResolvedValue([{ status: Status.OK, errors: [] }]);
}

await transactionPool.add(tempTx);
}

expect(transactionPool.getAll()).toHaveLength(MAX_TRANSACTIONS);

const lowFeePriorityTx = {
id: Buffer.from('11'),
moduleID: 3,
assetID: 0,
nonce: BigInt(1),
fee: BigInt(30000),
senderPublicKey: generateRandomPublicKeys()[0],
} as Transaction;

lowFeePriorityTx.getBytes = txGetBytesStub.mockReturnValue(
Buffer.from(new Array(MAX_TRANSACTIONS + 10)),
);

when(tempApplyTransactionsStub)
.calledWith([lowFeePriorityTx])
.mockResolvedValue([{ status: Status.OK, errors: [] }]);

const { status } = await transactionPool.add(lowFeePriorityTx);

expect(status).toEqual(Status.OK);
});
});

describe('remove', () => {
Expand Down Expand Up @@ -702,6 +795,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});
jest.spyOn(transactionPool.events, 'emit');
await transactionPool.add(transactions[0]);
Expand Down Expand Up @@ -792,6 +886,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});
jest.spyOn(transactionPool.events, 'emit');
await transactionPool.add(transactionsFromSender1[0]);
Expand All @@ -814,7 +909,7 @@ describe('TransactionPool class', () => {
expect((transactionPool as any)._allTransactions).not.toContain(transactionsFromSender2[1]);
// To check if evicted processable transaction is the higher nonce transaction of an account
expect(higherNonceTrxs).toContain(transactionsFromSender2[1]);
expect(transactionPool.events.emit).toHaveBeenCalledTimes(1);
expect(transactionPool.events.emit).toHaveBeenCalledTimes(2);
});
});

Expand Down Expand Up @@ -889,6 +984,7 @@ describe('TransactionPool class', () => {
},
],
minFeePerByte: 1000,
maxPayloadLength: 15360,
});
await transactionPool.add(transactionsFromSender1[0]);
await transactionPool.add(transactionsFromSender1[1]);
Expand Down
Loading

0 comments on commit 1b30f30

Please sign in to comment.