Skip to content

Commit

Permalink
Make serialization roundtrip work for transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
vgrichina committed Nov 15, 2019
1 parent 54d5d50 commit 9b02fb2
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 70 deletions.
12 changes: 6 additions & 6 deletions lib/transaction.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions lib/utils/key_pair.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 6 additions & 9 deletions lib/utils/key_pair.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 24 additions & 14 deletions lib/utils/serialize.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions src.ts/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@ export const SCHEMA = new Map<Function, any>([
[Action, {kind: 'enum', field: 'enum', values: [
['createAccount', CreateAccount],
['deployContract', DeployContract],
['functionCall', functionCall],
['transfer', transfer],
['stake', stake],
['addKey', addKey],
['deleteKey', deleteKey],
['deleteAccount', deleteAccount],
['functionCall', FunctionCall],
['transfer', Transfer],
['stake', Stake],
['addKey', AddKey],
['deleteKey', DeleteKey],
['deleteAccount', DeleteAccount],
]}],
[CreateAccount, { kind: 'struct', fields: [] }],
[DeployContract, { kind: 'struct', fields: [
Expand Down
16 changes: 6 additions & 10 deletions src.ts/utils/key_pair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import nacl from 'tweetnacl';
import { base_encode, base_decode } from './serialize';
import { Assignable } from './enums';

export type Arrayish = string | ArrayLike<number>;

Expand Down Expand Up @@ -32,15 +33,10 @@ function str_to_key_type(keyType: string): KeyType {
/**
* PublicKey representation that has type and bytes of the key.
*/
export class PublicKey {
export class PublicKey extends Assignable {
keyType: KeyType;
data: Uint8Array;

constructor(keyType: KeyType, data: Uint8Array) {
this.keyType = keyType;
this.data = data;
}

static from(value: string | PublicKey): PublicKey {
if (typeof value === 'string') {
return PublicKey.fromString(value);
Expand All @@ -51,11 +47,11 @@ export class PublicKey {
static fromString(encodedKey: string): PublicKey {
const parts = encodedKey.split(':');
if (parts.length === 1) {
return new PublicKey(KeyType.ED25519, base_decode(parts[0]));
return new PublicKey({ keyType: KeyType.ED25519, data: base_decode(parts[0]) });
} else if (parts.length === 2) {
return new PublicKey(str_to_key_type(parts[0]), base_decode(parts[1]));
return new PublicKey({ keyType: str_to_key_type(parts[0]), data: base_decode(parts[1]) });
} else {
throw new Error('Invlaid encoded key format, must be <curve>:<encoded key>');
throw new Error('Invalid encoded key format, must be <curve>:<encoded key>');
}
}

Expand Down Expand Up @@ -108,7 +104,7 @@ export class KeyPairEd25519 extends KeyPair {
constructor(secretKey: string) {
super();
const keyPair = nacl.sign.keyPair.fromSecretKey(base_decode(secretKey));
this.publicKey = new PublicKey(KeyType.ED25519, keyPair.publicKey);
this.publicKey = new PublicKey({ keyType: KeyType.ED25519, data: keyPair.publicKey });
this.secretKey = secretKey;
}

Expand Down
46 changes: 32 additions & 14 deletions src.ts/utils/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,12 @@ export class BinaryReader {

read_u64(): BN {
const buf = this.read_buffer(8);
buf.reverse();
return new BN(`${buf.toString('hex')}`, 16);
return new BN(buf, 'le');
}

read_u128(): BN {
const buf = this.read_buffer(16);
return new BN(buf);
return new BN(buf, 'le');
}

private read_buffer(len: number): Buffer {
Expand Down Expand Up @@ -203,25 +202,44 @@ export function serialize(schema: Schema, obj: any): Uint8Array {
return writer.toArray();
}

function deserializeField(schema: Schema, fieldType: any, reader: any): any {
function deserializeField(schema: Schema, fieldType: any, reader: BinaryReader): any {
if (typeof fieldType === 'string') {
return reader[`read_${fieldType}`]();
} else if (fieldType instanceof Array) {
}

if (fieldType instanceof Array) {
if (typeof fieldType[0] === 'number') {
return reader.read_fixed_array(fieldType[0]);
} else {
return reader.read_array(() => deserializeField(schema, fieldType[0], reader));
}
} else {
return deserializeStruct(schema, fieldType, reader);

return reader.read_array(() => deserializeField(schema, fieldType[0], reader));
}

return deserializeStruct(schema, fieldType, reader);
}

function deserializeStruct(schema: Schema, classType: any, reader: any) {
const fields = schema.get(classType).fields.map(([fieldName, fieldType]: [any, any]) => {
return deserializeField(schema, fieldType, reader);
});
return new classType(...fields);
function deserializeStruct(schema: Schema, classType: any, reader: BinaryReader) {
const structSchema = schema.get(classType);
if (!structSchema) {
throw new Error(`Class ${classType.name} is missing in schema`);
}

if (structSchema.kind === 'struct') {
const result = {};
for (const [fieldName, fieldType] of schema.get(classType).fields) {
result[fieldName] = deserializeField(schema, fieldType, reader);
};
return new classType(result);
}

if (structSchema.kind === 'enum') {
const idx = reader.read_u8();
const [fieldName, fieldType] = structSchema.values[idx];
const fieldValue = deserializeField(schema, fieldType, reader);
return new classType({ [fieldName]: fieldValue });
}

throw new Error(`Unexpected schema kind: ${structSchema.kind} for ${classType.constructor.name}`);
}

/// Deserializes object from bytes using schema.
Expand Down
12 changes: 3 additions & 9 deletions test/serialize.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@

const nearlib = require('../lib/index');

class Test {
constructor(x, y, z, q) {
this.x = x;
this.y = y;
this.z = z;
this.q = q;
}
class Test extends nearlib.utils.enums.Assignable {
}

test('serialize object', async () => {
const value = new Test(255, 20, '123', [1, 2, 3]);
const value = new Test({ x: 255, y: 20, z: '123', q: [1, 2, 3]});
const schema = new Map([[Test, {kind: 'struct', fields: [['x', 'u8'], ['y', 'u64'], ['z', 'string'], ['q', [3]]] }]]);
let buf = nearlib.utils.serialize.serialize(schema, value);
let new_value = nearlib.utils.serialize.deserialize(schema, Test, buf);
Expand Down Expand Up @@ -58,7 +52,7 @@ test('serialize transfer tx', async() => {
expect(serialized.toString('hex')).toEqual('09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000301000000000000000000000000000000');

const deserialized = nearlib.utils.serialize.deserialize(nearlib.transactions.SCHEMA, nearlib.transactions.Transaction, serialized);
expect(deserialized).toEqual(transaction);
expect(nearlib.utils.serialize.serialize(nearlib.transactions.SCHEMA, deserialized)).toEqual(serialized);
});

test('serialize and sign transfer tx', async() => {
Expand Down

0 comments on commit 9b02fb2

Please sign in to comment.