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

Handle context-free data #535

Merged
merged 1 commit into from
Apr 16, 2019
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
3 changes: 3 additions & 0 deletions src/eosjs-api-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export interface SignatureProviderArgs {
/** Transaction to sign */
serializedTransaction: Uint8Array;

/** Context-free data to sign */
serializedContextFreeData?: Uint8Array;

/** ABIs for all contracts with actions included in `serializedTransaction` */
abis: BinaryAbi[];
}
Expand Down
24 changes: 22 additions & 2 deletions src/eosjs-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,19 @@ export class Api {
return buffer.asUint8Array();
}

/** Serialize context-free data */
public serializeContextFreeData(contextFreeData: Uint8Array[]): Uint8Array {
if (!contextFreeData) {
return null;
}
const buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
buffer.pushVaruint32(contextFreeData.length);
for (const data of contextFreeData) {
buffer.pushBytes(data);
}
return buffer.asUint8Array();
}

/** Convert a transaction from binary. Leaves actions in hex. */
public deserializeTransaction(transaction: Uint8Array): any {
const buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
Expand Down Expand Up @@ -235,7 +248,10 @@ export class Api {
const abis: BinaryAbi[] = await this.getTransactionAbis(transaction);
transaction = { ...transaction, actions: await this.serializeActions(transaction.actions) };
const serializedTransaction = this.serializeTransaction(transaction);
let pushTransactionArgs: PushTransactionArgs = { serializedTransaction, signatures: [] };
const serializedContextFreeData = this.serializeContextFreeData(transaction.context_free_data);
let pushTransactionArgs: PushTransactionArgs = {
serializedTransaction, serializedContextFreeData, signatures: []
};

if (sign) {
const availableKeys = await this.signatureProvider.getAvailableKeys();
Expand All @@ -244,6 +260,7 @@ export class Api {
chainId: this.chainId,
requiredKeys,
serializedTransaction,
serializedContextFreeData,
abis,
});
}
Expand All @@ -254,10 +271,13 @@ export class Api {
}

/** Broadcast a signed transaction */
public async pushSignedTransaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any> {
public async pushSignedTransaction(
{ signatures, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
): Promise<any> {
return this.rpc.push_transaction({
signatures,
serializedTransaction,
serializedContextFreeData
});
}

Expand Down
6 changes: 4 additions & 2 deletions src/eosjs-jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,13 @@ export class JsonRpc implements AuthorityProvider, AbiProvider {
}

/** Push a serialized transaction */
public async push_transaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any> {
public async push_transaction(
{ signatures, serializedTransaction, serializedContextFreeData }: PushTransactionArgs
): Promise<any> {
return await this.fetch('/v1/chain/push_transaction', {
signatures,
compression: 0,
packed_context_free_data: '',
packed_context_free_data: arrayToHex(serializedContextFreeData || new Uint8Array(0)),
packed_trx: arrayToHex(serializedTransaction),
});
}
Expand Down
33 changes: 30 additions & 3 deletions src/eosjs-jssig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ import * as ecc from 'eosjs-ecc';
import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces';
import { convertLegacyPublicKey } from './eosjs-numeric';

function hexToUint8Array(hex: string) {
if (typeof hex !== 'string') {
throw new Error('Expected string containing hex digits');
}
if (hex.length % 2) {
throw new Error('Odd number of hex digits');
}
const l = hex.length / 2;
const result = new Uint8Array(l);
for (let i = 0; i < l; ++i) {
const x = parseInt(hex.substr(i * 2, 2), 16);
if (Number.isNaN(x)) {
throw new Error('Expected hex string');
}
result[i] = x;
}
return result;
}

/** Signs transactions using in-process private keys */
export class JsSignatureProvider implements SignatureProvider {
/** map public to private keys */
Expand All @@ -30,13 +49,21 @@ export class JsSignatureProvider implements SignatureProvider {
}

/** Sign a transaction */
public async sign({ chainId, requiredKeys, serializedTransaction }: SignatureProviderArgs) {
public async sign(
{ chainId, requiredKeys, serializedTransaction, serializedContextFreeData }: SignatureProviderArgs
) {
const signBuf = Buffer.concat([
new Buffer(chainId, 'hex'), new Buffer(serializedTransaction), new Buffer(new Uint8Array(32)),
new Buffer(chainId, 'hex'),
new Buffer(serializedTransaction),
new Buffer(
serializedContextFreeData ?
hexToUint8Array(ecc.sha256(serializedContextFreeData)) :
new Uint8Array(32)
),
]);
const signatures = requiredKeys.map(
(pub) => ecc.Signature.sign(signBuf, this.keys.get(convertLegacyPublicKey(pub))).toString(),
);
return { signatures, serializedTransaction };
return { signatures, serializedTransaction, serializedContextFreeData };
}
}
1 change: 1 addition & 0 deletions src/eosjs-rpc-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ export interface GetRawCodeAndAbiResult {
export interface PushTransactionArgs {
signatures: string[];
serializedTransaction: Uint8Array;
serializedContextFreeData?: Uint8Array;
}