From b38192884f9a550c880a41e17fe219320d952dea Mon Sep 17 00:00:00 2001 From: Maciej Zielinski Date: Wed, 31 Mar 2021 21:00:23 +0200 Subject: [PATCH] Validate deploy size. --- CHANGELOG.md | 6 +++++ package-lock.json | 2 +- package.json | 2 +- src/lib/DeployUtil.ts | 11 ++++++++ src/services/CasperServiceByJsonRPC.ts | 9 +++++++ test/nctl/RPC.test.ts | 36 +++++++++++++++++++++++--- 6 files changed, 60 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56f16d7eb..b0fa26ef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ 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.35 + +### Changed + +- Validate the size of the `Deploy`. Now `CasperServiceByJsonRPC.deploy` throws an error if the size of the deploy is larger then 1 megabyte.` + ## 1.0.34 ### Fixed diff --git a/package-lock.json b/package-lock.json index 6f25e603f..e029bc86e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "casper-client-sdk", - "version": "1.0.33", + "version": "1.0.35", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5d3a5d78e..e3b1a2418 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "casper-client-sdk", - "version": "1.0.34", + "version": "1.0.35", "license": "Apache 2.0", "description": "SDK to interact with the Casper blockchain", "main": "dist/lib.node.js", diff --git a/src/lib/DeployUtil.ts b/src/lib/DeployUtil.ts index 87a36e070..f39ad9360 100644 --- a/src/lib/DeployUtil.ts +++ b/src/lib/DeployUtil.ts @@ -978,3 +978,14 @@ export const addArgToDeploy = ( return makeDeploy(deployParams, session, deploy.payment); }; + +export const deploySizeInBytes = (deploy: Deploy): number => { + const hashSize = deploy.hash.length; + const bodySize = serializeBody(deploy.payment, deploy.session).length; + const headerSize = serializeHeader(deploy.header).length; + const approvalsSize = deploy.approvals.map(approval => { + return (approval.signature.length + approval.signer.length) / 2; + }).reduce((a, b) => a + b, 0); + + return hashSize + headerSize + bodySize + approvalsSize; +} diff --git a/src/services/CasperServiceByJsonRPC.ts b/src/services/CasperServiceByJsonRPC.ts index 394aaf78e..1525dcf68 100644 --- a/src/services/CasperServiceByJsonRPC.ts +++ b/src/services/CasperServiceByJsonRPC.ts @@ -336,6 +336,15 @@ export class CasperServiceByJsonRPC { } public async deploy(signedDeploy: DeployUtil.Deploy) { + const oneMegaByte = 1048576; + const size = DeployUtil.deploySizeInBytes(signedDeploy); + if(size > oneMegaByte) { + throw Error( + `Deploy can not be send, because it's too large: ${size} bytes. ` + + `Max size is 1 megabyte.` + ); + } + return await this.client.request({ method: 'account_put_deploy', params: deployToJson(signedDeploy) diff --git a/test/nctl/RPC.test.ts b/test/nctl/RPC.test.ts index 5cc8ba281..7039fcf02 100644 --- a/test/nctl/RPC.test.ts +++ b/test/nctl/RPC.test.ts @@ -1,12 +1,13 @@ import { assert } from 'chai'; import { CasperServiceByJsonRPC } from '../../src/services'; +import { Keys, DeployUtil, RuntimeArgs } from '../../src/index'; let client = new CasperServiceByJsonRPC( 'http://127.0.0.1:40101/rpc', ); -describe.skip('RPC', () => { - it('should return correct block by number', async () => { +describe('RPC', () => { + xit('should return correct block by number', async () => { let check = async (height: number) => { let result = await client.getBlockInfoByHeight(height); assert.equal(result.block?.header.height, height); @@ -17,7 +18,7 @@ describe.skip('RPC', () => { } }); - it('should return correct block by hash', async () => { + xit('should return correct block by hash', async () => { let check = async (height: number) => { let block_by_height = await client.getBlockInfoByHeight(height); let block_hash = block_by_height.block?.hash!; @@ -29,4 +30,31 @@ describe.skip('RPC', () => { await check(i); } }); -}); \ No newline at end of file + + it('should not allow to send deploy larger then 1 megabyte.', async () => { + // moduleBytes need to have length of (1 megabyte - 169 bytes) to produce + // a deploy with the size of (1 megabyte + 1 byte). + const oneMegaByte = 1048576; + const moduleBytes = Uint8Array.from(Array(oneMegaByte - 169).fill(0)); + + let deployParams = new DeployUtil.DeployParams( + Keys.Ed25519.new().publicKey, 'test'); + let session = DeployUtil.ExecutableDeployItem.newModuleBytes( + moduleBytes, RuntimeArgs.fromMap({}) + ); + let payment = DeployUtil.standardPayment(100000); + let deploy = DeployUtil.makeDeploy(deployParams, session, payment); + + assert.equal(DeployUtil.deploySizeInBytes(deploy), oneMegaByte + 1); + await client.deploy(deploy) + .then(_ => { + assert.fail("client.deploy should't throw an error."); + }) + .catch(err => { + let expectedMessage = + `Deploy can not be send, because it's too large: ${oneMegaByte + 1} bytes. ` + + `Max size is 1 megabyte.` + assert.equal(err.message, expectedMessage); + }); + }); +});