From c962b80f625d550573e847e6f1466524109fd3ea Mon Sep 17 00:00:00 2001 From: Zhang Zengbo Date: Wed, 18 Jul 2018 18:38:40 +0800 Subject: [PATCH] bsip38: serialization of extension logic correction --- lib/serializer/src/SerializerValidation.js | 12 ++- lib/serializer/src/operations.js | 13 +-- lib/serializer/src/types.js | 117 +++++++++++---------- test/serializer/all_types.js | 19 +++- 4 files changed, 91 insertions(+), 70 deletions(-) diff --git a/lib/serializer/src/SerializerValidation.js b/lib/serializer/src/SerializerValidation.js index 9e91fdc9..9aae09fb 100644 --- a/lib/serializer/src/SerializerValidation.js +++ b/lib/serializer/src/SerializerValidation.js @@ -20,7 +20,17 @@ var _my = { } return value; }, - + require_array: function(value, instance_require) { + if ( !( value instanceof Array) ) { + throw new Error(`array required`); + } + if( instance_require ){ + value.forEach( i =>{ + instance_require(i); + }) + } + return value; + }, require_long(value, field_name = "") { if (!Long.isLong(value)) { throw new Error(`Long value required ${field_name} ${value}`); diff --git a/lib/serializer/src/operations.js b/lib/serializer/src/operations.js index 7eb19b66..2ac11619 100644 --- a/lib/serializer/src/operations.js +++ b/lib/serializer/src/operations.js @@ -24,7 +24,6 @@ var { address, time_point_sec, optional, - indexed_optional, extension } = types; @@ -487,19 +486,15 @@ export const limit_order_cancel = new Serializer("limit_order_cancel", { extensions: set(future_extensions) }); -export const call_order_update_options = new Serializer( - "call_order_update_options", - { - target_collateral_ratio: indexed_optional(uint16, 0) - } -); - export const call_order_update = new Serializer("call_order_update", { fee: asset, funding_account: protocol_id_type("account"), delta_collateral: asset, delta_debt: asset, - extensions: extension(call_order_update_options) + extensions: extension([{ + name: "target_collateral_ratio", + type: uint16 + }]) }); export const fill_order = new Serializer("fill_order", { diff --git a/lib/serializer/src/types.js b/lib/serializer/src/types.js index 1b7ee5a2..34e5357f 100644 --- a/lib/serializer/src/types.js +++ b/lib/serializer/src/types.js @@ -9,6 +9,7 @@ import ObjectId from "../../chain/src/ObjectId"; import {PublicKey, Address} from "../../ecc"; import {ChainConfig} from "bitsharesjs-ws"; +import ByteBuffer from "bytebuffer"; const Buffer = require("safe-buffer").Buffer; var Types = {}; @@ -684,85 +685,87 @@ Types.optional = function(st_operation) { }; }; -Types.indexed_optional = function(st_operation, index) { - v.required(st_operation, "st_operation"); + +Types.extension = function (fields_def) { + // fields_def is an array + v.require_array(fields_def, (r) => { + v.string(r.name); + v.required(r.type, "st_operation"); + }); + //v.required(st_operation, "st_operation"); return { fromByteBuffer(b) { - if (!(b.readVarint32() === index)) { + let count = b.readVarint32(); + if (count === 0) { return undefined; } - return st_operation.fromByteBuffer(b); - }, - appendByteBuffer(b, object) { - if (object !== null && object !== undefined) { - b.writeVarint32(index); - st_operation.appendByteBuffer(b, object); - } - return; - }, - fromObject(object) { - if (object === undefined) { - return undefined; + let o = {}; + if (count > fields_def.length) { + throw new Error('two many fields'); } - return st_operation.fromObject(object); - }, - toObject(object, debug = {}) { - // toObject is only null save if use_default is true - var result_object = (() => { - if (!debug.use_default && object === undefined) { - return undefined; - } else { - return st_operation.toObject(object, debug); + while (count > 0) { + let index = b.readVarint32(); + if (index >= fields_def.length) { + throw new Error('index out of range'); } - })(); - - if (debug.annotate) { - if (typeof result_object === "object") { - result_object.__optional = "parent is optional"; - } else { - result_object = {__optional: result_object}; - } - } - return result_object; - } - }; -}; - -Types.extension = function(st_operation) { - v.required(st_operation, "st_operation"); - return { - fromByteBuffer(b) { - if (!(b.readVarint32() === 1)) { - return undefined; + let operation = fields_def[index]; + o[operation.name] = operation.type.fromByteBuffer(b); + count--; } - return st_operation.fromByteBuffer(b); + return o; + // return st_operation.fromByteBuffer(b); }, appendByteBuffer(b, object) { - if ( - object !== null && - object !== undefined && - !(typeof object == "object" && Object.keys(object).length == 0) - ) { - b.writeVarint32(1); - st_operation.appendByteBuffer(b, object); - } else { - b.writeVarint32(0); + //let tempBuffer = new Buffer([]); + let tempBuffer = new ByteBuffer( + ByteBuffer.DEFAULT_CAPACITY, + ByteBuffer.LITTLE_ENDIAN + ); + var count = 0; + if (object) { + fields_def.forEach((f, i) => { + if (object[f.name] !== undefined && object[f.name] !== null) { + tempBuffer.writeVarint32(i); + f.type.appendByteBuffer(tempBuffer, object[f.name]); + count++; + } + }); } + b.writeVarint32(count); + tempBuffer.flip(); + b.append(tempBuffer); + return; }, fromObject(object) { if (object === undefined) { return undefined; } + /* return st_operation.fromObject(object); + */ + var result = {}; + fields_def.forEach((f) => { + if (object[f.name] !== undefined && object[f.name] !== null) { + result[f.name] = f.type.fromObject(object[f.name]); + } + }); + return result; }, toObject(object, debug = {}) { // toObject is only null save if use_default is true var result_object = (() => { - if (!debug.use_default && object === undefined) { + if (object === undefined) { return undefined; } else { - return st_operation.toObject(object, debug); + // return st_operation.toObject(object, debug); + let result = {}; + fields_def.forEach((f) => { + if (object[f.name] !== undefined && object[f.name] !== null) { + result[f.name] = f.type.toObject(object[f.name], debug); + } + }); + return result; } })(); @@ -770,7 +773,7 @@ Types.extension = function(st_operation) { if (typeof result_object === "object") { result_object.__optional = "parent is optional"; } else { - result_object = {__optional: result_object}; + result_object = { __optional: result_object }; } } return result_object; diff --git a/test/serializer/all_types.js b/test/serializer/all_types.js index 453bb3e8..6e580303 100644 --- a/test/serializer/all_types.js +++ b/test/serializer/all_types.js @@ -37,6 +37,14 @@ var { var {asset, account_name_eq_lit_predicate} = ops; // Must stay in sync with allTypes below. + +let extType = extension([{ + name: 'f1', + type: uint16 +}, { + name: 'f2', + type: string +}]); let AllTypes = new Serializer("all_types", { uint8, uint16, @@ -65,8 +73,8 @@ let AllTypes = new Serializer("all_types", { time_optional: optional(time_point_sec), time_point_sec1: time_point_sec, time_point_sec2: time_point_sec, - ext1: extension(string), - ext2: extension(string) + ext1: extType, + ext2: extType, }); // Must stay in sync with AllTypes above. @@ -110,7 +118,12 @@ let allTypes = { time_optional: undefined, time_point_sec1: new Date(), time_point_sec2: Math.floor(Date.now() / 1000), - ext1: "test extension" + ext1: { + f1: 300 + }, + ext2: { + f2: "hello" + } }; describe("Serializer", function() {