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

Commit

Permalink
Merge pull request #746 from EOSIO/transaction-compression
Browse files Browse the repository at this point in the history
Supporting transaction compression (release/21.0.x branch)
  • Loading branch information
Brad Hart authored Jun 9, 2020
2 parents bef1888 + 83ad7d2 commit a9a6337
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 12 deletions.
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

0 comments on commit a9a6337

Please sign in to comment.