Skip to content

Commit

Permalink
Merge pull request #497 from casper-ecosystem/CSDK-213
Browse files Browse the repository at this point in the history
Fix issue with BlockTransaction serialisation and rewardedSignatures …
  • Loading branch information
Comp0te authored Jan 30, 2025
2 parents 5648d02 + a9890c7 commit 14c4be8
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 31 deletions.
110 changes: 109 additions & 1 deletion src/rpc/rpc_client.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { TypedJSON } from 'typedjson';
import { expect } from 'chai';

import { InfoGetTransactionResultV1Compatible } from './response';
import {
ChainGetBlockResult,
ChainGetBlockResultV1Compatible,
InfoGetTransactionResultV1Compatible
} from './response';
import { BlockBodyV2 } from '../types';

describe('RPC Client', () => {
it('should be able to parse getTransactionByTransactionHash response', () => {
Expand Down Expand Up @@ -460,4 +465,107 @@ describe('RPC Client', () => {
txResult.executionInfo?.executionResult.transfers[0].transactionHash.toString()
).to.deep.equal(txResult.transaction.hash.toHex());
});

it('Should process RPC.getBlockByHash response', () => {
const json = {
jsonrpc: '2.0',
id: '1',
result: {
api_version: '2.0.0',
block_with_signatures: {
block: {
Version2: {
hash:
'b51e5d16944c63eab276e6c5494fd39a454418e3a3f6aa519797882b6c3c0d4b',
header: {
parent_hash:
'11040b60955bc9921dfbeff3abf4ee3e1c702865b0183638cd5eba922cd34fe3',
state_root_hash:
'cf1d7c8d33ce0fbc6c5211000ade4cc88ab671cb51e8be6e458c774dd82f8ab0',
body_hash:
'ab363e6bf68b4190176b53196caa16954d2eb97f3f0dbe004b16f0e6951893cc',
random_bit: true,
accumulated_seed:
'22cfe5e17ebb2f79af99556e2f134051d8a64e6ff6cb96eac5378f24b8b8a486',
era_end: null,
timestamp: '2025-01-27T10:51:36.846Z',
era_id: 14828,
height: 3444515,
protocol_version: '2.0.1',
proposer:
'0140afe8f752e5ff100e0189c080bc207e8805b3e5e82f792ec608de2f11f39f6c',
current_gas_price: 1,
last_switch_block_hash:
'a265470a3663bbf88ab37d276cd1786c5e0f53f3da5a8fc268dfddedaf890b93'
},
body: {
transactions: {
'3': [
{
Deploy:
'c102a6fed7f4b9a435ca8584b4d2f704f419d523a1c3f7199799b534df264c9a'
}
]
},
rewarded_signatures: [[240], [0], [0]]
}
}
},
proofs: [
{
public_key:
'01032146b0b9de01e26aaec7b0d1769920de94681dbd432c3530bfe591752ded6c',
signature:
'0120730fd151cfd40d8b86abfc679c66dd50f49d0c76fe6d68a75d7f18efd05b0363009b98f2c0e760e5426abdaab11401e0223e1306d13474eb910434da197d07'
},
{
public_key:
'0126d4637eb0c0769274f03a696df1112383fa621c9f73f57af4c5c0fbadafa8cf',
signature:
'01ffcb8fdcf25cda1a673a5e43c37990147d0e6091f2eb51b5e295594270b4dd57b32c06e00275acbd8398ed6ee6f454d3431e2724a8fc8d37eeece9badb2bad00'
},
{
public_key:
'0140afe8f752e5ff100e0189c080bc207e8805b3e5e82f792ec608de2f11f39f6c',
signature:
'018fa481deb7701276f13e1a6d97cc9fa3c4b720eaf357e217caf687082401d4803d580a41247a3588e78a210622745e282b3429420c1a184a8cda8ff6d9886f07'
},
{
public_key:
'017536433a73f7562526f3e9fcb8d720428ae2d28788a9909f3c6f637a9d848a4b',
signature:
'01527594370613aa56be947badb595f2fbd96611debda997afca05c3b4a93ecca59e2fbc0fb34174ba222824e03476272ee0c1c236bfbb086fc899b921f3da140e'
}
]
}
}
};

const serializer = new TypedJSON(ChainGetBlockResultV1Compatible);
const result = serializer.parse(json.result)!;
result.rawJSON = json.result;

const ser = new TypedJSON(BlockBodyV2);
const blockV2BodyJson = JSON.stringify(
ser.toPlainJson(result.blockWithSignatures!.block.blockV2!.body)
);

const blockResult = ChainGetBlockResult.newChainGetBlockResultFromV1Compatible(
result,
result.rawJSON
);
blockResult.rawJSON = json.result;

expect(blockResult).to.be.not.undefined;
expect(blockResult).to.be.not.empty;
expect(blockResult.block?.hash.toHex()).to.deep.equal(
json.result.block_with_signatures.block.Version2.hash
);
expect(
result.blockWithSignatures?.block.blockV2?.hash?.toHex()
).to.deep.equal(json.result.block_with_signatures.block.Version2.hash);
expect(blockV2BodyJson).to.equal(
JSON.stringify(json.result.block_with_signatures.block.Version2.body)
);
});
});
65 changes: 44 additions & 21 deletions src/types/Block.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { jsonObject, jsonMember, jsonArrayMember } from 'typedjson';
import { jsonObject, jsonMember, jsonArrayMember, TypedJSON } from 'typedjson';
import { Hash } from './key';
import { Timestamp } from './Time';
import { Proposer } from './BlockProposer';
Expand All @@ -10,6 +10,7 @@ import {
} from './Transaction';
import { PublicKey } from './keypair';
import { HexBytes } from './HexBytes';
import { getEnumKeyByValue } from "../utils";

/**
* Represents a proof containing a public key and a signature, used for validating the authenticity of data.
Expand Down Expand Up @@ -180,8 +181,8 @@ export class Block {
/**
* A list of signature IDs that were rewarded in this block.
*/
@jsonArrayMember(Number, { name: 'rewarded_signatures' })
public rewardedSignatures: number[];
@jsonArrayMember(Number, { dimensions: 2, name: 'rewarded_signatures' })
public rewardedSignatures: number[][];

/**
* A list of proofs associated with this block.
Expand Down Expand Up @@ -235,7 +236,7 @@ export class Block {
protocolVersion: string | undefined,
eraEnd: EraEnd | undefined,
transactions: BlockTransaction[],
rewardedSignatures: number[],
rewardedSignatures: number[][],
proofs: Proof[],
originBlockV1?: BlockV1,
originBlockV2?: BlockV2
Expand Down Expand Up @@ -427,13 +428,14 @@ export class BlockTransaction {
* console.log(transactions); // Outputs an array of BlockTransaction instances.
*/
public static fromJSON(data: any): BlockTransaction[] {
const serializer = new TypedJSON(TransactionHash)
const source = {
Mint: data['0'] || [],
Auction: data['1'] || [],
InstallUpgrade: data['2'] || [],
Large: data['3'] || [],
Medium: data['4'] || [],
Small: data['5'] || []
Mint: (data['0'] || []).map((json: any) => serializer.parse(json)),
Auction: (data['1'] || []).map((json: any) => serializer.parse(json)),
InstallUpgrade: (data['2'] || []).map((json: any) => serializer.parse(json)),
Large: (data['3'] || []).map((json: any) => serializer.parse(json)),
Medium: (data['4'] || []).map((json: any) => serializer.parse(json)),
Small: (data['5'] || []).map((json: any) => serializer.parse(json))
};

const transactions: BlockTransaction[] = [];
Expand Down Expand Up @@ -466,6 +468,12 @@ export class BlockTransaction {

return transactions;
}

public toJSON(): string {
return JSON.stringify({
[this.category.toString()]: [{[getEnumKeyByValue(TransactionVersion, this.version) ?? '']: this.hash.toJSON()}]
});
}
}

/**
Expand All @@ -490,15 +498,24 @@ function getBlockTransactionsFromTransactionHashes(

return hashes.map(hash => {
const transactionHash = hash.transactionV1;
const deployHash = hash.deploy;

if (!transactionHash) {
throw new Error('Invalid TransactionHash: transactionV1 is undefined');
if (transactionHash) {
return new BlockTransaction(
category,
TransactionVersion.V1,
transactionHash
);
} else if (deployHash) {
return new BlockTransaction(
category,
TransactionVersion.Deploy,
deployHash
);
}

return new BlockTransaction(
category,
TransactionVersion.V1,
transactionHash
throw new Error(
'Invalid TransactionHash: transactionV1 and deploy is undefined'
);
});
}
Expand Down Expand Up @@ -895,18 +912,24 @@ export class BlockBodyV2 {
/**
* The list of transactions included in the block.
*/
@jsonArrayMember(BlockTransaction, {
@jsonMember(BlockTransaction, {
name: 'transactions',
deserializer: (json: any) =>
json.map((it: string) => BlockTransaction.fromJSON(it))
deserializer: (json: any) => BlockTransaction.fromJSON(json),
serializer: (value: BlockTransaction[]) => {
return {
...value.reduce((acc, tx) => {
return {...acc, ...JSON.parse(tx.toJSON())};
}, {})
};
}
})
public transactions: BlockTransaction[];

/**
* The list of signature IDs that were rewarded in this block.
*/
@jsonArrayMember(Number, { name: 'rewarded_signatures' })
public rewardedSignatures: number[];
@jsonArrayMember(Number, { dimensions: 2, name: 'rewarded_signatures' })
public rewardedSignatures: number[][];
}

/**
Expand Down
17 changes: 14 additions & 3 deletions src/utils/auction-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ import {
Duration,
ExecutableDeployItem,
PublicKey,
StoredContractByHash
StoredContractByHash,
Timestamp
} from '../types';
import { AuctionManagerEntryPoint, CasperNetworkName } from '../@types';
import { AuctionManagerContractHashMap } from './constants';

export interface IMakeAuctionManagerDeployParams {
contractEntryPoint: AuctionManagerEntryPoint.delegate | AuctionManagerEntryPoint.undelegate | AuctionManagerEntryPoint.redelegate;
contractEntryPoint:
| AuctionManagerEntryPoint.delegate
| AuctionManagerEntryPoint.undelegate
| AuctionManagerEntryPoint.redelegate;
delegatorPublicKeyHex: string;
validatorPublicKeyHex: string;
newValidatorPublicKeyHex?: string;
amount: string;
paymentAmount?: string;
chainName?: CasperNetworkName;
ttl?: number;
timestamp?: string;
}

/**
Expand All @@ -49,6 +54,7 @@ export interface IMakeAuctionManagerDeployParams {
* @param params.ttl - (Optional) The time-to-live (TTL) for the `Deploy` in milliseconds.
* Specifies how long the `Deploy` is valid before it expires.
* Defaults 1800000 (30 minutes)
* @param params.timestamp - (Optional) The timestamp in ISO 8601 format
*
* @returns A deploy object that can be signed and sent to the network.
*
Expand All @@ -74,7 +80,8 @@ export const makeAuctionManagerDeploy = ({
paymentAmount = '2500000000',
chainName = CasperNetworkName.Mainnet,
newValidatorPublicKeyHex,
ttl = DEFAULT_DEPLOY_TTL
ttl = DEFAULT_DEPLOY_TTL,
timestamp
}: IMakeAuctionManagerDeployParams) => {
const delegatorPublicKey = PublicKey.newPublicKey(delegatorPublicKeyHex);
const validatorPublicKey = PublicKey.newPublicKey(validatorPublicKeyHex);
Expand Down Expand Up @@ -107,5 +114,9 @@ export const makeAuctionManagerDeploy = ({
deployHeader.chainName = chainName;
deployHeader.ttl = new Duration(ttl);

if (timestamp) {
deployHeader.timestamp = Timestamp.fromJSON(timestamp);
}

return Deploy.makeDeploy(deployHeader, payment, session);
};
15 changes: 12 additions & 3 deletions src/utils/cep-18-transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
Key,
KeyTypeID,
PublicKey,
StoredVersionedContractByHash
StoredVersionedContractByHash,
Timestamp
} from '../types';
import { CasperNetworkName } from '../@types';

Expand All @@ -23,6 +24,7 @@ export interface IMakeCep18TransferDeployParams {
paymentAmount: string;
chainName?: string;
ttl?: number;
timestamp?: string;
}

/**
Expand All @@ -43,6 +45,8 @@ export interface IMakeCep18TransferDeployParams {
* @param params.ttl - (Optional) The time-to-live (TTL) for the `Deploy` in milliseconds.
* Specifies how long the `Deploy` is valid before it expires.
* Defaults 1800000 (30 minutes)
* @param params.timestamp - (Optional) The timestamp in ISO 8601 format
*
* @returns A promise that resolves to the created Deploy instance, ready to be sent to the Casper network.
*
* @example
Expand All @@ -68,7 +72,8 @@ export const makeCep18TransferDeploy = ({
transferAmount,
paymentAmount,
chainName = CasperNetworkName.Mainnet,
ttl = DEFAULT_DEPLOY_TTL
ttl = DEFAULT_DEPLOY_TTL,
timestamp
}: IMakeCep18TransferDeployParams): Deploy => {
const senderPublicKey = PublicKey.newPublicKey(senderPublicKeyHex);
const recipientPublicKey = PublicKey.newPublicKey(recipientPublicKeyHex);
Expand All @@ -86,7 +91,7 @@ export const makeCep18TransferDeploy = ({
)
),
amount: CLValueUInt256.newCLUInt256(transferAmount)
}),
})
);

const payment = ExecutableDeployItem.standardPayment(paymentAmount);
Expand All @@ -96,5 +101,9 @@ export const makeCep18TransferDeploy = ({
deployHeader.chainName = chainName;
deployHeader.ttl = new Duration(ttl);

if (timestamp) {
deployHeader.timestamp = Timestamp.fromJSON(timestamp);
}

return Deploy.makeDeploy(deployHeader, payment, session);
};
Loading

0 comments on commit 14c4be8

Please sign in to comment.