From 661d4b8582698ed43a45f80d325f0221ebc823cc Mon Sep 17 00:00:00 2001 From: Maciej Zielinski Date: Tue, 9 Feb 2021 13:18:46 +0100 Subject: [PATCH 1/3] CLValue: asList, isList. --- packages/sdk/CHANGELOG.md | 10 +++++++ packages/sdk/package.json | 4 +-- packages/sdk/src/lib/CLValue.ts | 36 ++++++++++++++++------- packages/sdk/test/lib/RuntimeArgs.test.ts | 19 +++++++++++- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 26d98056..811622f5 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to casper-client-sdk. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.19] + +### Added + +- `CLValue.isList` and `CLValue.asList`. + +### Fixed + +- BytesArrayValue's fromBytes. + ## [1.0.18] ### Added diff --git a/packages/sdk/package.json b/packages/sdk/package.json index ef34dca6..15ae92cb 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "casper-client-sdk", - "version": "1.0.18", + "version": "1.0.19", "license": "Apache 2.0", "description": "SDK to interact with the Casper blockchain", "main": "dist/index.js", @@ -38,7 +38,7 @@ "husky": "^2.7.0", "lint-staged": "^8.2.1", "minimist": ">=1.2.3", - "mocha": "^6.1.4", + "mocha": "^6.2.3", "nodemon": "^2.0.2", "nyc": "^15.0.1", "prettier": "^1.18.2", diff --git a/packages/sdk/src/lib/CLValue.ts b/packages/sdk/src/lib/CLValue.ts index bec88bd8..277dbff9 100644 --- a/packages/sdk/src/lib/CLValue.ts +++ b/packages/sdk/src/lib/CLValue.ts @@ -491,7 +491,7 @@ const fromBytesSimpleType = ( }; export class List extends CLTypedAndToBytes { - constructor(private vec: T[]) { + constructor(public vec: T[]) { super(); if (vec.length === 0) { throw new Error("Can't create instance for empty list"); @@ -811,7 +811,7 @@ class ByteArrayValue extends CLTypedAndToBytes { } public static fromBytes(bytes: Uint8Array): Result { - const b = new ByteArrayValue(bytes); + const b = new ByteArrayValue(bytes.subarray(0, 32)); return Result.Ok(b, bytes.subarray(32)); } } @@ -1655,7 +1655,7 @@ export class CLValue implements ToBytes { const numberCoder = this.value as NumberCoder; return BigNumber.from(numberCoder.val); } else { - throw new Error("The CLValue can't convert to BigNumber"); + throw new Error("The CLValue is not an instance of BigNumber"); } } @@ -1665,7 +1665,7 @@ export class CLValue implements ToBytes { public asBoolean() { if (!this.isBoolean()) { - throw new Error("The CLValue can't convert to Boolean"); + throw new Error("The CLValue is not an instance of Boolean"); } return (this.value as Bool).val; } @@ -1676,7 +1676,7 @@ export class CLValue implements ToBytes { public asString() { if (!this.isString()) { - throw new Error("The CLValue can't convert to String"); + throw new Error("The CLValue is not an instance of String"); } return (this.value as StringValue).val; } @@ -1687,7 +1687,7 @@ export class CLValue implements ToBytes { public asPublicKey(): PublicKey { if (!this.isPublicKey()) { - throw new Error("The CLValue can't convert to PublicKey"); + throw new Error("The CLValue is not an instance of PublicKey"); } return this.value as PublicKey; } @@ -1698,7 +1698,7 @@ export class CLValue implements ToBytes { public asKey() { if (!this.isKey()) { - throw new Error("The CLValue can't convert to Key"); + throw new Error("The CLValue is not an instance of Key"); } return this.value as KeyValue; } @@ -1709,7 +1709,7 @@ export class CLValue implements ToBytes { public asURef() { if (!this.isURef()) { - throw new Error("The CLValue can't convert to URef"); + throw new Error("The CLValue is not an instance of URef"); } return this.value as URef; } @@ -1720,7 +1720,7 @@ export class CLValue implements ToBytes { public asBytesArray() { if (!this.isBytesArray()) { - throw new Error("The CLValue can't convert to BytesArray"); + throw new Error("The CLValue is not an instance of BytesArray"); } return (this.value as ByteArrayValue).toBytes(); } @@ -1731,10 +1731,26 @@ export class CLValue implements ToBytes { public asOption() { if (!this.isOption()) { - throw new Error("The CLValue can't convert to Option"); + throw new Error("The CLValue is not an instance of Option"); } return this.value as Option; } + + public isList() { + return this.clType instanceof ListType + } + + public asList() { + if (!this.isList()) { + throw new Error("The CLValue is not an instance of List"); + } + let innerType = (this.clType as ListType); + let list = List.fromBytes(innerType, this.clValueBytes()); + if (list.hasError()) { + throw new Error("The CLValue can not be parsed to list.") + } + return list.value().vec.map((e) => CLValue.fromT(e)); + } } export enum KeyVariant { diff --git a/packages/sdk/test/lib/RuntimeArgs.test.ts b/packages/sdk/test/lib/RuntimeArgs.test.ts index 0a083129..76134b77 100644 --- a/packages/sdk/test/lib/RuntimeArgs.test.ts +++ b/packages/sdk/test/lib/RuntimeArgs.test.ts @@ -1,5 +1,5 @@ import { expect, assert } from 'chai'; -import { CLValue, RuntimeArgs, CLTypedAndToBytesHelper } from '../../src/lib'; +import { CLValue, RuntimeArgs, CLTypedAndToBytesHelper, Keys } from '../../src/lib'; import { decodeBase16 } from '../../src'; import { TypedJSON } from 'typedjson'; @@ -71,4 +71,21 @@ describe(`RuntimeArgs`, () => { let value = serializer.parse(str)!; assert.isTrue(value.args.get('a')!.asOption().isNone()); }); + + it('should allow to extract lists of account hashes.', () => { + const account0 = Keys.Ed25519.new().accountHash(); + const account1 = Keys.Ed25519.new().accountHash(); + let runtimeArgs = RuntimeArgs.fromMap({ + accounts: CLValue.list([ + CLTypedAndToBytesHelper.bytes(account0), + CLTypedAndToBytesHelper.bytes(account1) + ]) + }); + let serializer = new TypedJSON(RuntimeArgs); + let json = serializer.stringify(runtimeArgs); + + let accounts = runtimeArgs.args.get('accounts')!.asList(); + assert.deepEqual(accounts[0].asBytesArray(), account0); + assert.deepEqual(accounts[1].asBytesArray(), account1); + }); }); From 059879d74d364e1f69788fa9b1845bd0c7c9b2c4 Mon Sep 17 00:00:00 2001 From: Maciej Zielinski Date: Tue, 9 Feb 2021 13:19:14 +0100 Subject: [PATCH 2/3] Lint --- packages/sdk/src/lib/CLValue.ts | 26 +++++++++++------------ packages/sdk/test/lib/RuntimeArgs.test.ts | 24 +++++++++++++++++---- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/sdk/src/lib/CLValue.ts b/packages/sdk/src/lib/CLValue.ts index 277dbff9..1db04c18 100644 --- a/packages/sdk/src/lib/CLValue.ts +++ b/packages/sdk/src/lib/CLValue.ts @@ -1655,7 +1655,7 @@ export class CLValue implements ToBytes { const numberCoder = this.value as NumberCoder; return BigNumber.from(numberCoder.val); } else { - throw new Error("The CLValue is not an instance of BigNumber"); + throw new Error('The CLValue is not an instance of BigNumber'); } } @@ -1665,7 +1665,7 @@ export class CLValue implements ToBytes { public asBoolean() { if (!this.isBoolean()) { - throw new Error("The CLValue is not an instance of Boolean"); + throw new Error('The CLValue is not an instance of Boolean'); } return (this.value as Bool).val; } @@ -1676,7 +1676,7 @@ export class CLValue implements ToBytes { public asString() { if (!this.isString()) { - throw new Error("The CLValue is not an instance of String"); + throw new Error('The CLValue is not an instance of String'); } return (this.value as StringValue).val; } @@ -1687,7 +1687,7 @@ export class CLValue implements ToBytes { public asPublicKey(): PublicKey { if (!this.isPublicKey()) { - throw new Error("The CLValue is not an instance of PublicKey"); + throw new Error('The CLValue is not an instance of PublicKey'); } return this.value as PublicKey; } @@ -1698,7 +1698,7 @@ export class CLValue implements ToBytes { public asKey() { if (!this.isKey()) { - throw new Error("The CLValue is not an instance of Key"); + throw new Error('The CLValue is not an instance of Key'); } return this.value as KeyValue; } @@ -1709,7 +1709,7 @@ export class CLValue implements ToBytes { public asURef() { if (!this.isURef()) { - throw new Error("The CLValue is not an instance of URef"); + throw new Error('The CLValue is not an instance of URef'); } return this.value as URef; } @@ -1720,7 +1720,7 @@ export class CLValue implements ToBytes { public asBytesArray() { if (!this.isBytesArray()) { - throw new Error("The CLValue is not an instance of BytesArray"); + throw new Error('The CLValue is not an instance of BytesArray'); } return (this.value as ByteArrayValue).toBytes(); } @@ -1731,25 +1731,25 @@ export class CLValue implements ToBytes { public asOption() { if (!this.isOption()) { - throw new Error("The CLValue is not an instance of Option"); + throw new Error('The CLValue is not an instance of Option'); } return this.value as Option; } public isList() { - return this.clType instanceof ListType + return this.clType instanceof ListType; } public asList() { if (!this.isList()) { - throw new Error("The CLValue is not an instance of List"); + throw new Error('The CLValue is not an instance of List'); } - let innerType = (this.clType as ListType); + let innerType = this.clType as ListType; let list = List.fromBytes(innerType, this.clValueBytes()); if (list.hasError()) { - throw new Error("The CLValue can not be parsed to list.") + throw new Error('The CLValue can not be parsed to list.'); } - return list.value().vec.map((e) => CLValue.fromT(e)); + return list.value().vec.map(e => CLValue.fromT(e)); } } diff --git a/packages/sdk/test/lib/RuntimeArgs.test.ts b/packages/sdk/test/lib/RuntimeArgs.test.ts index 76134b77..7f43e6a5 100644 --- a/packages/sdk/test/lib/RuntimeArgs.test.ts +++ b/packages/sdk/test/lib/RuntimeArgs.test.ts @@ -1,5 +1,10 @@ import { expect, assert } from 'chai'; -import { CLValue, RuntimeArgs, CLTypedAndToBytesHelper, Keys } from '../../src/lib'; +import { + CLValue, + RuntimeArgs, + CLTypedAndToBytesHelper, + Keys +} from '../../src/lib'; import { decodeBase16 } from '../../src'; import { TypedJSON } from 'typedjson'; @@ -56,8 +61,14 @@ describe(`RuntimeArgs`, () => { let str = serializer.stringify(value); let parsed = serializer.parse(str)!; assert.deepEqual( - value.asOption().getSome().asBigNumber(), - parsed.asOption().getSome().asBigNumber() + value + .asOption() + .getSome() + .asBigNumber(), + parsed + .asOption() + .getSome() + .asBigNumber() ); }); @@ -69,7 +80,12 @@ describe(`RuntimeArgs`, () => { let serializer = new TypedJSON(RuntimeArgs); let str = serializer.stringify(runtimeArgs); let value = serializer.parse(str)!; - assert.isTrue(value.args.get('a')!.asOption().isNone()); + assert.isTrue( + value.args + .get('a')! + .asOption() + .isNone() + ); }); it('should allow to extract lists of account hashes.', () => { From 37ff810a49f43b0d1cc89a903b2f77f54aa1593d Mon Sep 17 00:00:00 2001 From: Maciej Zielinski Date: Tue, 9 Feb 2021 15:12:27 +0100 Subject: [PATCH 3/3] Deploy serialization tests. --- packages/sdk/src/lib/CLValue.ts | 4 +- packages/sdk/test/lib/DeployUtil.test.ts | 75 ++++++++++++++++++++--- packages/sdk/test/lib/RuntimeArgs.test.ts | 3 - 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/packages/sdk/src/lib/CLValue.ts b/packages/sdk/src/lib/CLValue.ts index 1db04c18..55c2d5fd 100644 --- a/packages/sdk/src/lib/CLValue.ts +++ b/packages/sdk/src/lib/CLValue.ts @@ -1744,8 +1744,8 @@ export class CLValue implements ToBytes { if (!this.isList()) { throw new Error('The CLValue is not an instance of List'); } - let innerType = this.clType as ListType; - let list = List.fromBytes(innerType, this.clValueBytes()); + const innerType = this.clType as ListType; + const list = List.fromBytes(innerType, this.clValueBytes()); if (list.hasError()) { throw new Error('The CLValue can not be parsed to list.'); } diff --git a/packages/sdk/test/lib/DeployUtil.test.ts b/packages/sdk/test/lib/DeployUtil.test.ts index a9c0bf6f..02bc49ad 100644 --- a/packages/sdk/test/lib/DeployUtil.test.ts +++ b/packages/sdk/test/lib/DeployUtil.test.ts @@ -3,7 +3,7 @@ import { Keys, DeployUtil, CLValue } from '../../src/lib'; import { TypedJSON } from 'typedjson'; describe('DeployUtil', () => { - it('should stringify/parse DeployHeader correctly', function () { + it('should stringify/parse DeployHeader correctly', function() { const ed25519Key = Keys.Ed25519.new(); const deployHeader = new DeployUtil.DeployHeader( ed25519Key.publicKey, @@ -20,7 +20,7 @@ describe('DeployUtil', () => { expect(deployHeader1).to.deep.equal(deployHeader); }); - it('should allow to extract data from Transfer', function () { + it('should allow to extract data from Transfer', function() { const senderKey = Keys.Ed25519.new(); const recipientKey = Keys.Ed25519.new(); const networkName = 'test-network'; @@ -53,11 +53,17 @@ describe('DeployUtil', () => { assert.isTrue(deploy.isStandardPayment()); assert.deepEqual(deploy.header.account, senderKey.publicKey); assert.deepEqual( - deploy.payment.getArgByName('amount')!.asBigNumber().toNumber(), + deploy.payment + .getArgByName('amount')! + .asBigNumber() + .toNumber(), paymentAmount ); assert.deepEqual( - deploy.session.getArgByName('amount')!.asBigNumber().toNumber(), + deploy.session + .getArgByName('amount')! + .asBigNumber() + .toNumber(), transferAmount ); assert.deepEqual( @@ -77,7 +83,7 @@ describe('DeployUtil', () => { assert.deepEqual(deploy.approvals[1].signer, recipientKey.accountHex()); }); - it('should allow to add arg to Deploy', function () { + it('should allow to add arg to Deploy', function() { const senderKey = Keys.Ed25519.new(); const recipientKey = Keys.Ed25519.new(); const networkName = 'test-network'; @@ -111,18 +117,27 @@ describe('DeployUtil', () => { deploy = DeployUtil.deployFromJson(json)!; assert.deepEqual( - deploy.session.getArgByName('custom_id')!.asBigNumber().toNumber(), + deploy.session + .getArgByName('custom_id')! + .asBigNumber() + .toNumber(), customId ); assert.isTrue(deploy.isTransfer()); assert.isTrue(deploy.isStandardPayment()); assert.deepEqual(deploy.header.account, senderKey.publicKey); assert.deepEqual( - deploy.payment.getArgByName('amount')!.asBigNumber().toNumber(), + deploy.payment + .getArgByName('amount')! + .asBigNumber() + .toNumber(), paymentAmount ); assert.deepEqual( - deploy.session.getArgByName('amount')!.asBigNumber().toNumber(), + deploy.session + .getArgByName('amount')! + .asBigNumber() + .toNumber(), transferAmount ); assert.deepEqual( @@ -143,7 +158,7 @@ describe('DeployUtil', () => { assert.notEqual(oldDeploy.header.bodyHash, deploy.header.bodyHash); }); - it('should not allow to add arg to a signed Deploy', function () { + it('should not allow to add arg to a signed Deploy', function() { const senderKey = Keys.Ed25519.new(); const recipientKey = Keys.Ed25519.new(); const networkName = 'test-network'; @@ -171,4 +186,46 @@ describe('DeployUtil', () => { DeployUtil.addArgToDeploy(deploy, 'custom_id', CLValue.u32(customId)); }).to.throw('Can not add argument to already signed deploy.'); }); + + it('should allow to extract additional args from Transfer.', function() { + const from = Keys.Ed25519.new(); + const to = Keys.Ed25519.new(); + const networkName = 'test-network'; + const paymentAmount = 10000000000000; + const transferAmount = 10; + const id = 34; + + let deployParams = new DeployUtil.DeployParams(from.publicKey, networkName); + let session = DeployUtil.ExecutableDeployItem.newTransfer( + transferAmount, + to.publicKey, + undefined, + id + ); + let payment = DeployUtil.standardPayment(paymentAmount); + let deploy = DeployUtil.makeDeploy(deployParams, session, payment); + let fromRawPK = from.publicKey.rawPublicKey; + + let transferDeploy = DeployUtil.addArgToDeploy( + deploy, + 'fromPublicKey', + CLValue.publicKey(fromRawPK) + ); + + assert.deepEqual( + transferDeploy.session.getArgByName('fromPublicKey')?.asPublicKey() + .rawPublicKey, + fromRawPK + ); + + let newTransferDeploy = DeployUtil.deployFromJson( + DeployUtil.deployToJson(transferDeploy) + ); + + assert.deepEqual( + newTransferDeploy?.session.getArgByName('fromPublicKey')?.asPublicKey() + .rawPublicKey, + fromRawPK + ); + }); }); diff --git a/packages/sdk/test/lib/RuntimeArgs.test.ts b/packages/sdk/test/lib/RuntimeArgs.test.ts index 7f43e6a5..6a4f4600 100644 --- a/packages/sdk/test/lib/RuntimeArgs.test.ts +++ b/packages/sdk/test/lib/RuntimeArgs.test.ts @@ -97,9 +97,6 @@ describe(`RuntimeArgs`, () => { CLTypedAndToBytesHelper.bytes(account1) ]) }); - let serializer = new TypedJSON(RuntimeArgs); - let json = serializer.stringify(runtimeArgs); - let accounts = runtimeArgs.args.get('accounts')!.asList(); assert.deepEqual(accounts[0].asBytesArray(), account0); assert.deepEqual(accounts[1].asBytesArray(), account1);