Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Supporting transaction compression (release/21.0.x branch) #746

Merged
merged 12 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/01_technical-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ The typical use of the `Api` object is to call its [`transact` method](https://g
* The `actions` are serialized using the `eosjs-serialize` `ser` object.
* The entire transaction is then [serialized](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-api.ts#L154-L166), also using the `eosjs-serialize` `ser` object.
* The transaction is then optionally signed, using the `signatureProvider`, the previously retrieved `abi`s, the private keys of the `signatureProvider`, and the `chainId`.
* The transaction is then optionally compressed, using the `deflate` function of a Javascript zlib library.
* The transaction is then optionally broadcasted using `JsonRpc`'s [`push_transaction`](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L187).
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"dependencies": {
"@babel/runtime": "7.8.3",
"@types/elliptic": "6.4.10",
"elliptic": "6.5.2"
"elliptic": "6.5.2",
"pako": "1.0.11"
},
"devDependencies": {
"@babel/core": "7.8.3",
Expand All @@ -37,8 +38,9 @@
"@blockone/tslint-config-blockone": "3.0.0",
"@types/jest": "24.9.1",
"@types/node": "11.9.4",
"@types/pako": "1.0.1",
"cypress": "3.8.2",
"eosjs-ecc": "^4.0.7",
"eosjs-ecc": "4.0.7",
"jest": "25.1.0",
"jest-fetch-mock": "2.1.1",
"json-loader": "0.5.7",
Expand Down
1 change: 1 addition & 0 deletions src/eosjs-api-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export interface SignatureProvider {
export interface TransactConfig {
broadcast?: boolean;
sign?: boolean;
compression?: boolean;
blocksBehind?: number;
useLastIrreversible?: boolean;
expireSeconds?: number;
Expand Down
37 changes: 34 additions & 3 deletions src/eosjs-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/
// copyright defined in eosjs/LICENSE.txt

import { inflate, deflate } from 'pako';

import {
AbiProvider,
AuthorityProvider,
Expand Down Expand Up @@ -243,12 +245,23 @@ export class Api {
};
}

/** Deflate a serialized object */
public deflateSerializedArray(serializedArray: Uint8Array): Uint8Array {
return deflate(serializedArray, { level: 9 });
}

/** Inflate a compressed serialized object */
public inflateSerializedArray(compressedSerializedArray: Uint8Array): Uint8Array {
return inflate(compressedSerializedArray);
}

/**
* Create and optionally broadcast a transaction.
*
* Named Parameters:
* * `broadcast`: broadcast this transaction?
* * `sign`: sign this transaction?
* * `compression`: compress this transaction?
* * If both `blocksBehind` and `expireSeconds` are present,
* then fetch the block which is `blocksBehind` behind head block,
* use it as a reference for TAPoS, and expire the transaction `expireSeconds` after that block's time.
Expand All @@ -259,8 +272,8 @@ export class Api {
*/
public async transact(
transaction: any,
{ broadcast = true, sign = true, blocksBehind, useLastIrreversible, expireSeconds }: TransactConfig = {}
): Promise<any> {
{ broadcast = true, sign = true, compression, blocksBehind, useLastIrreversible, expireSeconds }:
TransactConfig = {}): Promise<any> {
let info: GetInfoResult;

if (typeof blocksBehind === 'number' && useLastIrreversible) {
Expand All @@ -273,7 +286,7 @@ export class Api {
}

if ((typeof blocksBehind === 'number' || useLastIrreversible) && expireSeconds) {
transaction = this.generateTapos(info, transaction, blocksBehind, useLastIrreversible, expireSeconds);
transaction = await this.generateTapos(info, transaction, blocksBehind, useLastIrreversible, expireSeconds);
}

if (!this.hasRequiredTaposFields(transaction)) {
Expand Down Expand Up @@ -304,6 +317,9 @@ export class Api {
});
}
if (broadcast) {
if (compression) {
return this.pushCompressedSignedTransaction(pushTransactionArgs);
}
return this.pushSignedTransaction(pushTransactionArgs);
}
return pushTransactionArgs;
Expand All @@ -320,6 +336,21 @@ export class Api {
});
}

public async pushCompressedSignedTransaction(
{ signatures, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
): Promise<any> {
const compressedSerializedTransaction = this.deflateSerializedArray(serializedTransaction);
const compressedSerializedContextFreeData =
this.deflateSerializedArray(serializedContextFreeData || new Uint8Array(0));

return this.rpc.push_transaction({
signatures,
compression: 1,
serializedTransaction: compressedSerializedTransaction,
serializedContextFreeData: compressedSerializedContextFreeData
});
}

private async generateTapos(
info: GetInfoResult | undefined,
transaction: any,
Expand Down
8 changes: 4 additions & 4 deletions src/eosjs-jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,23 +191,23 @@ export class JsonRpc implements AuthorityProvider, AbiProvider {

/** Push a serialized transaction (replaced by send_transaction, but returned format has changed) */
public async push_transaction(
{ signatures, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
{ signatures, compression = 0, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
): Promise<any> {
return await this.fetch('/v1/chain/push_transaction', {
signatures,
compression: 0,
compression,
packed_context_free_data: arrayToHex(serializedContextFreeData || new Uint8Array(0)),
packed_trx: arrayToHex(serializedTransaction),
});
}

/** Send a serialized transaction */
public async send_transaction(
{ signatures, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
{ signatures, compression = 0, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
): Promise<any> {
return await this.fetch('/v1/chain/send_transaction', {
signatures,
compression: 0,
compression,
packed_context_free_data: arrayToHex(serializedContextFreeData || new Uint8Array(0)),
packed_trx: arrayToHex(serializedTransaction),
});
Expand Down
1 change: 1 addition & 0 deletions src/eosjs-rpc-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export interface GetRawCodeAndAbiResult {
/** Arguments for `push_transaction` */
export interface PushTransactionArgs {
signatures: string[];
compression?: number;
serializedTransaction: Uint8Array;
serializedContextFreeData?: Uint8Array;
}
5 changes: 5 additions & 0 deletions src/tests/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ describe('Node JS environment', () => {
expect(Object.keys(transactionResponse)).toContain('transaction_id');
}, 10000);

it('transacts with compressed transaction', async () => {
transactionResponse = await tests.transactWithConfig({ blocksBehind: 3, expireSeconds: 30, compression: true });
expect(Object.keys(transactionResponse)).toContain('transaction_id');
});

it('transacts without broadcasting, returning signatures and packed transaction', async () => {
transactionSignatures = await tests.transactWithConfig({
broadcast: false,
Expand Down
26 changes: 25 additions & 1 deletion src/tests/web.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,30 @@
resultsLabel.innerText = FAILED;
return false;
};


const testTransactWithCompression = async (e) => {
resultsLabel = e.target;
resultsLabel.innerText = EXECUTING;

try {
transactionResponse =
await transactWithConfig({ blocksBehind: 3, expireSeconds: 30, compression: true });
} catch (error) {
resultsLabel.className = 'failed';
resultsLabel.innerText = FAILED;
console.error('Transact With Config Test Failure: ', error.message);
return false;
}

if (transactionResponse.transaction_id) {
resultsLabel.className = "success";
resultsLabel.innerText = SUCCESS;
return true;
}
resultsLabel.className = 'failed';
resultsLabel.innerText = FAILED;
return false;
}

const testTransactWithoutBroadcast = async (e) => {
resultsLabel = e.target;
Expand Down Expand Up @@ -266,6 +289,7 @@ <h1>Web Build Integration Tests</h1>
<div><h2>Transact with blocksBehind Configuration Parameter</h2><button onClick='testTransactWithConfigBlocksBehind(event);'>Test</button></div>
<div><h2>Transact with useLastIrreversible Configuration Parameter</h2><button onClick='testTransactWithConfigUseLastIrreversible(event);'>Test</button></div>
<div><h2>Transact with Manually Configured TAPOS</h2><button onClick='testTransactWithoutConfig(event);'>Test</button></div>
<div><h2>Transact with Compression</h2><button onClick='testTransactWithCompression(event);'>Test</button></div>
<div><h2>Transact without Broadcasting</h2><button onClick='testTransactWithoutBroadcast(event);'>Test</button></div>
<div><h2>Broadcast Transaction</h2><button onClick='testBroadcastResult(event);'>Test</button></div>
<div><h2>Invalid Transaction Throws Error</h2><button onClick='testTransactShouldFail(event);'>Test</button></div>
Expand Down
9 changes: 7 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.4.tgz#ceb0048a546db453f6248f2d1d95e937a6f00a14"
integrity sha512-Zl8dGvAcEmadgs1tmSPcvwzO1YRsz38bVJQvH1RvRqSR9/5n61Q1ktcDL0ht3FXWR+ZpVmXVwN1LuH4Ax23NsA==

"@types/pako@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.1.tgz#33b237f3c9aff44d0f82fe63acffa4a365ef4a61"
integrity sha512-GdZbRSJ3Cv5fiwT6I0SQ3ckeN2PWNqxd26W9Z2fCK1tGrrasGy4puvNFtnddqH9UJFMQYXxEuuB7B8UK+LLwSg==

"@types/sizzle@2.3.2":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
Expand Down Expand Up @@ -2596,7 +2601,7 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
memory-fs "^0.5.0"
tapable "^1.0.0"

eosjs-ecc@^4.0.7:
eosjs-ecc@4.0.7:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eosjs-ecc/-/eosjs-ecc-4.0.7.tgz#f5246da3b84839fcc237204768ef6e5ea56cc814"
integrity sha512-uuqhqnrDy9XTpKfkhiZqRDUTCCI9oWBalVK5IosL7kpYwA9I3lm68INYFLyWsHpF2xwHqPql8MrMYJ3zfOn5Qg==
Expand Down Expand Up @@ -5116,7 +5121,7 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==

pako@~1.0.5:
pako@1.0.11, pako@~1.0.5:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
Expand Down