Skip to content

Commit

Permalink
[LUM-860] Upgrade to new JS SDK (#144)
Browse files Browse the repository at this point in the history
* Update js sdk

* Upgrade to new js sdk

* fix warnings

* Last fixes

* Upgrade github workflow node version

* Fix unit test

* Fixes according to review

* Fixes according to review

* Fix warnings

* Fixes according to review
  • Loading branch information
ThibaultJRD authored Feb 14, 2024
1 parent 922ad06 commit 8fa0191
Show file tree
Hide file tree
Showing 39 changed files with 975 additions and 589 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

- uses: actions/setup-node@v1
with:
node-version: '16.18.0'
node-version: '18.19.0'

- name: Install the project dependencies
run: yarn install
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"dependencies": {
"@bull-board/api": "^5.9.1",
"@bull-board/express": "^5.9.1",
"@lum-network/sdk-javascript": "^0.8.9",
"@lum-network/sdk-javascript": "^1.0.0-beta.2",
"@nestjs/axios": "^3.0.1",
"@nestjs/bull": "^10.0.1",
"@nestjs/cache-manager": "^2.1.1",
Expand Down
2 changes: 1 addition & 1 deletion src/async/consumers/asset.consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

import dayjs from 'dayjs';
import { ProposalStatus } from '@lum-network/sdk-javascript/build/codec/cosmos/gov/v1beta1/gov';
import { ProposalStatus } from '@lum-network/sdk-javascript/build/codegen/cosmos/gov/v1beta1/gov';

import { hasFalsyProperties, LUM_DFR_ALLOCATION_TYPE_URL, QueueJobs, Queues } from '@app/utils';
import { AssetService, ChainService, DfractService, ProposalService } from '@app/services';
Expand Down
2 changes: 1 addition & 1 deletion src/async/consumers/beam.consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class BeamConsumer {
this._logger.debug(`Ingesting beam ${job.data.id}`);

// Get beam by passing the id received by the tx dispatch in block consumer
const remoteBeam = await this._chainService.getChain(AssetSymbol.LUM).client.queryClient.beam.get(job.data.id);
const { beam: remoteBeam } = await this._chainService.getChain(AssetSymbol.LUM).client.lum.network.beam.beam({ id: job.data.id });

// We format the remote beam to match it against our schema
const formattedBeam = {
Expand Down
73 changes: 34 additions & 39 deletions src/async/consumers/block.consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { InjectQueue, Process, Processor } from '@nestjs/bull';

import { Job, Queue } from 'bull';
import dayjs from 'dayjs';
import { LumConstants, LumMessages, LumRegistry, LumUtils } from '@lum-network/sdk-javascript';
import { LumRegistry, parseRawLogs, sha256, toHex, toJSON, MICRO_LUM_DENOM, toBech32, LumBech32Prefixes } from '@lum-network/sdk-javascript';
import { MsgMultiSend } from '@lum-network/sdk-javascript/build/codegen/cosmos/bank/v1beta1/tx';

import { BlockEntity, TransactionEntity } from '@app/database';
import { BlockService, ChainService, TransactionService, ValidatorService } from '@app/services';
Expand Down Expand Up @@ -40,63 +41,57 @@ export class BlockConsumer {
this._logger.debug(`Ingesting block ${job.data.blockHeight} (attempt ${job.attemptsMade})`);

// Get block data
const block = await this._chainService.getChain(AssetSymbol.LUM).client.getBlock(job.data.blockHeight);
const block = await this._chainService.getChain(AssetSymbol.LUM).client.cosmos.base.tendermint.v1beta1.getBlockByHeight({ height: BigInt(job.data.blockHeight) });

// Get the operator address
const proposerAddress = LumUtils.toHex(block.block.header.proposerAddress).toUpperCase();
const proposerAddress = toBech32(LumBech32Prefixes.CONS_ADDR, block.block.header.proposerAddress);
const validator = await this._validatorService.getByProposerAddress(proposerAddress);
if (!validator) {
throw new Error(`Failed to find validator for ${proposerAddress}, exiting for retry`);
}

// Format block data
const blockDoc: Partial<BlockEntity> = {
hash: LumUtils.toHex(block.blockId.hash).toUpperCase(),
height: block.block.header.height,
hash: toHex(block.blockId.hash).toUpperCase(),
height: Number(block.block.header.height),
time: dayjs(block.block.header.time as Date).toDate(),
tx_count: block.block.txs.length,
tx_hashes: block.block.txs.map((tx) => LumUtils.toHex(LumUtils.sha256(tx)).toUpperCase()),
tx_count: block.block.data.txs.length,
tx_hashes: block.block.data.txs.map((tx) => toHex(sha256(tx)).toUpperCase()),
proposer_address: proposerAddress,
operator_address: validator.operator_address,
raw_block: LumUtils.toJSON(block) as string,
operator_address: validator?.operator_address ?? '',
raw_block: toJSON(block) as string,
};

// Fetch and format transactions data
const getFormattedTx = async (rawTx: Uint8Array): Promise<Partial<TransactionEntity>> => {
// Acquire raw TX
const tx = await this._chainService.getChain(AssetSymbol.LUM).client.getTx(LumUtils.sha256(rawTx));
const getFormattedTx = async (rawTx: any): Promise<Partial<TransactionEntity>> => {
const hash = toHex(sha256(rawTx)).toUpperCase();

// Decode TX to human-readable format
const txData = LumRegistry.decodeTx(tx.tx);
// Acquire raw TX
const tx = await this._chainService.getChain(AssetSymbol.LUM).client.cosmos.tx.v1beta1.getTx({ hash: hash });

// Parse the raw logs
const logs = LumUtils.parseRawLogs(tx.result.log);
const logs = parseRawLogs(tx.txResponse.rawLog);

// Build the transaction document from information
const res: Partial<TransactionEntity> = {
hash: LumUtils.toHex(tx.hash).toUpperCase(),
height: tx.height,
hash: hash,
height: Number(tx.txResponse.height),
time: blockDoc.time,
proposer_address: blockDoc.proposer_address,
operator_address: blockDoc.operator_address,
success: tx.result.code === 0,
code: tx.result.code,
fees: txData.authInfo.fee.amount.map((coin) => {
return { denom: coin.denom, amount: parseFloat(coin.amount) };
}),
success: tx.txResponse.code === 0,
code: tx.txResponse.code,
addresses: [],
gas_wanted: (tx.result as unknown as { gasWanted: number }).gasWanted,
gas_used: (tx.result as unknown as { gasUsed: number }).gasUsed,
memo: txData.body.memo,
messages: txData.body.messages.map((msg) => {
return { type_url: msg.typeUrl, value: LumUtils.toJSON(LumRegistry.decode(msg)) };
gas_wanted: Number(tx.txResponse.gasWanted),
gas_used: Number(tx.txResponse.gasUsed),
fees: [],
memo: tx.tx.body.memo,
messages: tx.tx.body.messages.map((msg) => {
return { type_url: msg.typeUrl, value: toJSON(LumRegistry.decode(msg)) };
}),
message_type: txData.body.messages.length ? txData.body.messages[0].typeUrl : null,
messages_count: txData.body.messages.length,
message_type: tx.tx.body.messages.length ? tx.tx.body.messages[0].typeUrl : null,
messages_count: tx.tx.body.messages.length,
raw_logs: logs as any[],
raw_events: tx.result.events.map((ev) => LumUtils.toJSON(ev)),
raw_tx: LumUtils.toJSON(tx) as string,
raw_tx_data: LumUtils.toJSON(txData) as string,
raw_events: tx.txResponse.events.map((ev) => toJSON(ev)),
raw_tx: toJSON(tx) as string,
raw_tx_data: toJSON(tx.txResponse.data) as string,
};

// Add addresses in case of transaction failure
Expand Down Expand Up @@ -185,13 +180,13 @@ export class BlockConsumer {
}

// Multisend case
if (res.messages.length === 1 && res.messages[0].type_url === LumMessages.MsgMultiSendUrl) {
if (res.messages.length === 1 && res.messages[0].type_url === MsgMultiSend.typeUrl) {
res.amount = {
denom: LumConstants.MicroLumDenom,
denom: MICRO_LUM_DENOM,
amount: !res.messages[0].value.inputs
? '0'
: res.messages[0].value.inputs
.map((i: any) => (!i.coins ? 0 : i.coins.map((c: any) => (c.denom === LumConstants.MicroLumDenom ? parseInt(c.amount) : 0)).reduce((a: number, b: number) => a + b)))
.map((i: any) => (!i.coins ? 0 : i.coins.map((c: any) => (c.denom === MICRO_LUM_DENOM ? parseInt(c.amount) : 0)).reduce((a: number, b: number) => a + b)))
.reduce((a: number, b: number) => a + b),
};
}
Expand All @@ -201,7 +196,7 @@ export class BlockConsumer {

// Save entities
await this._blockService.save(blockDoc);
const transactions = await Promise.all(block.block.txs.map(getFormattedTx));
const transactions = await Promise.all(block.block.data.txs.map(getFormattedTx));
await this._transactionService.saveBulk(transactions);

// Dispatch beams for ingest
Expand Down
21 changes: 11 additions & 10 deletions src/async/schedulers/block.scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ export class BlockScheduler {
async backwardIngest() {
// Daily check that we did not miss a block sync somehow
const chainId = this._chainService.getChain<LumChain>(AssetSymbol.LUM).chainId;
const blockHeight = await this._chainService.getChain<LumChain>(AssetSymbol.LUM).client.getBlockHeight();
const lastedBlock = await this._chainService.getChain<LumChain>(AssetSymbol.LUM).client.cosmos.base.tendermint.v1beta1.getLatestBlock();

await this._queue.add(
QueueJobs.TRIGGER_VERIFY_BLOCKS_BACKWARD,
{
chainId: chainId,
fromBlock: this._configService.get<number>('STARTING_HEIGHT'),
toBlock: blockHeight,
toBlock: lastedBlock.block.header.height,
},
{
priority: QueuePriority.LOW,
Expand All @@ -39,20 +40,20 @@ export class BlockScheduler {
@Cron(CronExpression.EVERY_10_SECONDS, { name: 'blocks_live_ingest' })
async liveIngest() {
const chainId = this._chainService.getChain<LumChain>(AssetSymbol.LUM).chainId;
const lastBlocks = await this._chainService.getChain<LumChain>(AssetSymbol.LUM).client.tmClient.blockchain();
this._logger.debug(`Dispatching last 20 blocks for ingestion at height ${lastBlocks.lastHeight}`);
const lastBlock = await this._chainService.getChain<LumChain>(AssetSymbol.LUM).client.cosmos.base.tendermint.v1beta1.getLatestBlock();

this._logger.debug(`Dispatching last 20 blocks for ingestion at height ${lastBlock.block.header.height}`);

// For each block, dispatch the ingestion job to the queue
for (const meta of lastBlocks.blockMetas) {
const height = meta.header.height;
for (let i = 0; i < 20; i++) {
// For each block, dispatch the ingestion job to the queue
await this._queue.add(
QueueJobs.INGEST,
{
blockHeight: height,
notify: true,
blockHeight: Number(lastBlock.block.header.height) - i,
notify: false,
},
{
jobId: `${chainId}-block-${height}`,
jobId: `${chainId}-block-${Number(lastBlock.block.header.height) - i}`,
attempts: 5,
backoff: 60000,
priority: QueuePriority.HIGH,
Expand Down
12 changes: 6 additions & 6 deletions src/async/schedulers/governance.scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class GovernanceScheduler {
// Acquire the typeUrl
typeUrl = proposal.messages[0].typeUrl.split('/')[1];
// If it's an old system, we have to take the inner typeUrl
if (typeUrl === 'cosmos.gov.v1.MsgExecLegacyContent') {
if (typeUrl === 'cosmos.gov.v1beta1.MsgExecLegacyContent') {
typeUrl = decodedMsg.content.typeUrl.split('/')[1];
}

Expand All @@ -49,7 +49,7 @@ export class GovernanceScheduler {

// If the decoded content is a MsgSubmitProposal it contains plan, we need to patch the height value to store raw int
if (decodedContent.plan !== undefined && decodedContent.plan !== null) {
decodedContent.plan.height = decodedContent.plan.height.toNumber();
decodedContent.plan.height = Number(decodedContent.plan.height);
}
}
}
Expand All @@ -70,7 +70,7 @@ export class GovernanceScheduler {

// Create or update the entity
await this._governanceProposalService.createOrUpdateProposal({
id: proposal.id.toNumber(),
id: Number(proposal.id),
type_url: typeUrl,
status: proposal.status,
metadata: proposal.metadata,
Expand All @@ -95,7 +95,7 @@ export class GovernanceScheduler {
voting_end_time: proposal.votingEndTime,
});

this._logger.debug(`Synced proposal #${proposal.id.toNumber()}`);
this._logger.debug(`Synced proposal #${proposal.id}`);
}
}

Expand All @@ -117,7 +117,7 @@ export class GovernanceScheduler {
// Only start the patch process if there are actual proposalId
for (const id of proposalIds) {
// Fetch the votes based on the proposalId
const getVotes = await this._chainService.getChain(AssetSymbol.LUM).client.queryClient.gov.votes(id);
const getVotes = await this._chainService.getChain(AssetSymbol.LUM).client.cosmos.gov.v1beta1.votes({ proposalId: id });

// Map the votes to get the voters, the voteOption and the voteWeight
const getVoterAndOptions = getVotes.votes.map((voteArgs) => ({
Expand Down Expand Up @@ -155,7 +155,7 @@ export class GovernanceScheduler {
// Only start the patch process if there are actual proposalId
for (const id of proposalIds) {
// Fetch the deposits based on the proposalId
const getDeposits = await this._chainService.getChain(AssetSymbol.LUM).client.queryClient.gov.deposits(id);
const getDeposits = await this._chainService.getChain(AssetSymbol.LUM).client.cosmos.gov.v1beta1.deposits({ proposalId: id });

// Map the deposits to get the depositors and the amount
const getDepositor = getDeposits.deposits.map((deposit) => ({
Expand Down
Loading

0 comments on commit 8fa0191

Please sign in to comment.