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

Commit

Permalink
♻️ Add tests and improve code base
Browse files Browse the repository at this point in the history
  • Loading branch information
ishantiw committed Feb 29, 2024
1 parent 6aecb55 commit d1488cd
Show file tree
Hide file tree
Showing 15 changed files with 1,548 additions and 2,504 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ import {
codec,
ChainAccount,
getMainchainID,
TransactionJSON,
} from 'lisk-sdk';
import { ChainAPIClient } from './chain_api_client';
import { ChainConnectorDB } from './db';
import { BlockHeader, LastSentCCM, Logger, ModuleMetadata } from './types';
import { CCM_PROCESSED, CCM_SEND_SUCCESS, DEFAULT_SENT_CCU_TIMEOUT } from './constants';
import { CCUHandler } from './ccu_handler';

export interface NewBlockHandlerConfig {
interface NewBlockHandlerConfig {
registrationHeight: number;
ownChainID: Buffer;
receivingChainID: Buffer;
Expand Down Expand Up @@ -114,7 +113,7 @@ export class BlockEventHandler {
// On a new block start with CCU creation process
this._sendingChainAPIClient.subscribe(
'chain_newBlock',
async (data?: Record<string, unknown>) => this.handleNewBlock(data),
async (data?: Record<string, unknown>) => this._handleNewBlock(data),
);

this._sendingChainAPIClient.subscribe(
Expand All @@ -126,7 +125,7 @@ export class BlockEventHandler {
this._initializeReceivingChainClient().catch(this._logger.error);
}

public async handleNewBlock(data?: Record<string, unknown>) {
private async _handleNewBlock(data?: Record<string, unknown>) {
const { blockHeader: receivedBlock } = data as unknown as Data;
const newBlockHeader = chain.BlockHeader.fromJSON(receivedBlock).toObject();

Expand Down Expand Up @@ -189,6 +188,9 @@ export class BlockEventHandler {
this._receivingChainID,
);
if (!receivingChainAccount) {
this._logger.info(
'Receiving chain is not registered on the sending chain yet and has no chain data.',
);
return;
}
this._isReceivingChainRegistered = true;
Expand All @@ -205,11 +207,13 @@ export class BlockEventHandler {
this._logger.info(
`Still pending CCU on the receiving CCU with tx ID ${this._lastSentCCUTxID}`,
);

return;
}
} catch (error) {
this._logger.error(
{ err: error },
`Error occured while computing CCU for the blockHeader at height: ${newBlockHeader.height}`,
`Error occurred while computing CCU for the blockHeader at height: ${newBlockHeader.height}`,
);

return;
Expand Down Expand Up @@ -246,7 +250,7 @@ export class BlockEventHandler {
}
}

public async _saveOnNewBlock(newBlockHeader: BlockHeader) {
private async _saveOnNewBlock(newBlockHeader: BlockHeader) {
await this._db.saveToDBOnNewBlock(newBlockHeader);
// Check for events if any and store them
const events = await this._sendingChainAPIClient.getEvents(newBlockHeader.height);
Expand Down Expand Up @@ -366,8 +370,8 @@ export class BlockEventHandler {
inboxSize: inbox.size,
lastCertificateHeight: chainAccount.lastCertificate?.height,
});
try {
if (this._lastSentCCUTxID !== '') {
if (this._lastSentCCUTxID !== '') {
try {
await this._receivingChainAPIClient.getTransactionByID(this._lastSentCCUTxID);
this._logger.info(
`CCU transaction with ${this._lastSentCCUTxID} was included on the receiving chain`,
Expand All @@ -380,9 +384,9 @@ export class BlockEventHandler {
this._lastIncludedCCMOnReceivingChain = this._lastSentCCM;
await this._db.setLastSentCCM(this._lastIncludedCCMOnReceivingChain);
}
} catch (error) {
throw new Error(`Failed to get transaction with ID ${this._lastSentCCUTxID}`);
}
} catch (error) {
throw new Error(`Failed to get transaction with ID ${this._lastSentCCUTxID}`);
}
await this._cleanup();
} catch (error) {
Expand All @@ -398,9 +402,7 @@ export class BlockEventHandler {
if (total > this._ccuSaveLimit) {
// listOfCCUs is a descending list of CCUs by nonce
for (let i = total; i > this._ccuSaveLimit; i -= 1) {
await this._db.deleteCCUTransaction(
chain.Transaction.fromJSON(listOfCCUs[i] as TransactionJSON).toObject(),
);
await this._db.deleteCCUTransaction(Buffer.from(listOfCCUs[i]?.id as string, 'hex'));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,57 @@ export class CCUHandler {
};
}

public async submitCCU(
ccuParams: CrossChainUpdateTransactionParams,
lastSentCCUTxID: string,
): Promise<string | undefined> {
if (!this._db.privateKey) {
throw new Error('There is no key enabled to submit CCU');
}
const relayerPublicKey = cryptography.ed.getPublicKeyFromPrivateKey(this._db.privateKey);
const targetCommand = this._isReceivingChainMainchain
? COMMAND_NAME_SUBMIT_MAINCHAIN_CCU
: COMMAND_NAME_SUBMIT_SIDECHAIN_CCU;

const nonce = await this._receivingChainAPIClient.getAuthAccountNonceFromPublicKey(
relayerPublicKey,
);

const txWithoutFee = {
module: MODULE_NAME_INTEROPERABILITY,
command: targetCommand,
nonce: BigInt(nonce),
senderPublicKey: relayerPublicKey,
params: codec.encode(ccuParamsSchema, ccuParams),
signatures: [],
};

const tx = new Transaction({
...txWithoutFee,
fee: await this._getCcuFee({
...txWithoutFee,
params: ccuParams,
}),
});

tx.sign(this._receivingChainID, this._db.privateKey);
if (tx.id.equals(Buffer.from(lastSentCCUTxID, 'hex'))) {
return undefined;
}
let result: { transactionId: string };
if (this._isSaveCCU) {
result = { transactionId: tx.id.toString('hex') };
} else {
result = await this._receivingChainAPIClient.postTransaction(tx.getBytes());
}
// Save the sent CCU
await this._db.setCCUTransaction(tx.toObject());
// Update logs
this._logger.info({ transactionID: result.transactionId }, 'Sent CCU transaction');

return result.transactionId;
}

private async _findCertificate() {
// First certificate can be picked directly from first valid aggregateCommit taking registration height into account
if (this._lastCertificate.height === 0) {
Expand Down Expand Up @@ -318,55 +369,4 @@ export class CCUHandler {
}
return computedMinFee;
}

public async submitCCU(
ccuParams: CrossChainUpdateTransactionParams,
lastSentCCUTxID: string,
): Promise<string | undefined> {
if (!this._db.privateKey) {
throw new Error('There is no key enabled to submit CCU');
}
const relayerPublicKey = cryptography.ed.getPublicKeyFromPrivateKey(this._db.privateKey);
const targetCommand = this._isReceivingChainMainchain
? COMMAND_NAME_SUBMIT_MAINCHAIN_CCU
: COMMAND_NAME_SUBMIT_SIDECHAIN_CCU;

const nonce = await this._receivingChainAPIClient.getAuthAccountNonceFromPublicKey(
relayerPublicKey,
);

const txWithoutFee = {
module: MODULE_NAME_INTEROPERABILITY,
command: targetCommand,
nonce: BigInt(nonce),
senderPublicKey: relayerPublicKey,
params: codec.encode(ccuParamsSchema, ccuParams),
signatures: [],
};

const tx = new Transaction({
...txWithoutFee,
fee: await this._getCcuFee({
...txWithoutFee,
params: ccuParams,
}),
});

tx.sign(this._receivingChainID, this._db.privateKey);
if (tx.id.equals(Buffer.from(lastSentCCUTxID, 'hex'))) {
return undefined;
}
let result: { transactionId: string };
if (this._isSaveCCU) {
result = { transactionId: tx.id.toString('hex') };
} else {
result = await this._receivingChainAPIClient.postTransaction(tx.getBytes());
}
// Save the sent CCU
await this._db.setCCUTransaction(tx.toObject());
// Update logs
this._logger.info({ transactionID: result.transactionId }, 'Sent CCU transaction');

return result.transactionId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const checkChainOfTrust = async (
db: ChainConnectorDB,
): Promise<boolean> => {
const blockHeader = await db.getBlockHeaderByHeight(aggregateCommit.height - 1);

if (!blockHeader) {
throw new Error(
`No block header found for the given the previous height ${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,20 @@
* Removal or modification of this copyright notice is prohibited.
*/

import { BasePlugin, PluginInitContext, db as liskDB } from 'lisk-sdk';
import { BasePlugin, PluginInitContext } from 'lisk-sdk';
import { CCU_TOTAL_CCM_SIZE } from './constants';
import { configSchema } from './schemas';
import { ChainConnectorPluginConfig } from './types';
import { ChainAPIClient } from './chain_api_client';
import { BlockEventHandler } from './block_event_handler';
import { ChainConnectorDB, getDBInstance } from './db';
import { ChainConnectorDB } from './db';
import { ChainConnectorEndpoint } from './endpoint';

export class ChainConnectorPlugin extends BasePlugin<ChainConnectorPluginConfig> {
public endpoint = new ChainConnectorEndpoint();
public readonly endpoint = new ChainConnectorEndpoint();
public configSchema = configSchema;

private _chainConnectorPluginDB!: liskDB.Database;
private _chainConnectorDB!: ChainConnectorDB;
private readonly _chainConnectorDB = new ChainConnectorDB();
private _receivingChainClient!: ChainAPIClient;
private _sendingChainClient!: ChainAPIClient;
private _ownChainID!: Buffer;
Expand All @@ -52,17 +51,16 @@ export class ChainConnectorPlugin extends BasePlugin<ChainConnectorPluginConfig>
isSaveCCU: this.config.isSaveCCU,
ccuSaveLimit: this.config.ccuSaveLimit,
});
}

public async load(): Promise<void> {
this._chainConnectorPluginDB = await getDBInstance(this.dataPath);
this._chainConnectorDB = new ChainConnectorDB(this._chainConnectorPluginDB);
this.endpoint.load(this.config, this._chainConnectorDB);

this._sendingChainClient = new ChainAPIClient({
ipcPath: this.appConfig.system.dataPath,
logger: this.logger,
});
}

public async load(): Promise<void> {
await this._chainConnectorDB.load(this.dataPath);
this.endpoint.load(this.config.encryptedPrivateKey, this._chainConnectorDB);

await this._sendingChainClient.connect(this.apiClient);
this._ownChainID = Buffer.from(this.appConfig.genesis.chainID, 'hex');
if (this._receivingChainID[0] !== this._ownChainID[0]) {
Expand Down
Loading

0 comments on commit d1488cd

Please sign in to comment.