UNPKG

@steempro/dsteem

Version:
571 lines (570 loc) 21.1 kB
"use strict"; /** * @file Steem protocol serialization. * @author Johan Nordberg <code@johan-nordberg.com> * @license * Copyright (c) 2017 Johan Nordberg. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * You acknowledge that this software is not designed, licensed or intended for use * in the design, construction, operation or maintenance of any military facility. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Types = void 0; const crypto_1 = require("../crypto"); const asset_1 = require("./asset"); const misc_1 = require("./misc"); const VoidSerializer = (buffer) => { throw new Error("Void can not be serialized"); }; const StringSerializer = (buffer, data) => { buffer.writeVString(data); }; const Int8Serializer = (buffer, data) => { buffer.writeInt8(data); }; const Int16Serializer = (buffer, data) => { buffer.writeInt16(data); }; const Int32Serializer = (buffer, data) => { buffer.writeInt32(data); }; const Int64Serializer = (buffer, data) => { buffer.writeInt64(data); }; const UInt8Serializer = (buffer, data) => { buffer.writeUint8(data); }; const UInt16Serializer = (buffer, data) => { buffer.writeUint16(data); }; const UInt32Serializer = (buffer, data) => { buffer.writeUint32(data); }; const UInt64Serializer = (buffer, data) => { buffer.writeUint64(data); }; const BooleanSerializer = (buffer, data) => { buffer.writeByte(data ? 1 : 0); }; const StaticVariantSerializer = (itemSerializers) => (buffer, data) => { const [id, item] = data; buffer.writeVarint32(id); itemSerializers[id](buffer, item); }; /** * Serialize asset. * @note This looses precision for amounts larger than 2^53-1/10^precision. * Should not be a problem in real-word usage. */ const AssetSerializer = (buffer, data) => { const asset = asset_1.Asset.from(data); const precision = asset.getPrecision(); buffer.writeInt64(Math.round(asset.amount * Math.pow(10, precision))); buffer.writeUint8(precision); for (let i = 0; i < 7; i++) { buffer.writeUint8(asset.symbol.charCodeAt(i) || 0); } }; const DateSerializer = (buffer, data) => { buffer.writeUint32(Math.floor(new Date(data + "Z").getTime() / 1000)); }; const PublicKeySerializer = (buffer, data) => { if (data === null || (typeof data === "string" && data.endsWith("1111111111111111111111111111111114T1Anm"))) { buffer.append(Buffer.alloc(33, 0)); } else { buffer.append(crypto_1.PublicKey.from(data).key); } }; const BinarySerializer = (size) => (buffer, data) => { data = misc_1.HexBuffer.from(data); const len = data.buffer.length; if (size) { if (len !== size) { throw new Error(`Unable to serialize binary. Expected ${size} bytes, got ${len}`); } } else { buffer.writeVarint32(len); } buffer.append(data.buffer); }; const VariableBinarySerializer = BinarySerializer(); const FlatMapSerializer = (keySerializer, valueSerializer) => (buffer, data) => { buffer.writeVarint32(data.length); for (const [key, value] of data) { keySerializer(buffer, key); valueSerializer(buffer, value); } }; const ArraySerializer = (itemSerializer) => (buffer, data) => { buffer.writeVarint32(data.length); for (const item of data) { itemSerializer(buffer, item); } }; const ObjectSerializer = (keySerializers) => (buffer, data) => { for (const [key, serializer] of keySerializers) { try { serializer(buffer, data[key]); } catch (error) { error.message = `${key}: ${error.message}`; throw error; } } }; const OptionalSerializer = (valueSerializer) => (buffer, data) => { if (data) { buffer.writeByte(1); valueSerializer(buffer, data); } else { buffer.writeByte(0); } }; const AuthoritySerializer = ObjectSerializer([ ["weight_threshold", UInt32Serializer], ["account_auths", FlatMapSerializer(StringSerializer, UInt16Serializer)], ["key_auths", FlatMapSerializer(PublicKeySerializer, UInt16Serializer)], ]); const BeneficiarySerializer = ObjectSerializer([ ["account", StringSerializer], ["weight", UInt16Serializer], ]); const PriceSerializer = ObjectSerializer([ ["base", AssetSerializer], ["quote", AssetSerializer], ]); const ProposalUpdateSerializer = ObjectSerializer([ ["end_date", DateSerializer], ]); const SignedBlockHeaderSerializer = ObjectSerializer([ ["previous", BinarySerializer(20)], ["timestamp", DateSerializer], ["witness", StringSerializer], ["transaction_merkle_root", BinarySerializer(20)], ["extensions", ArraySerializer(VoidSerializer)], ["witness_signature", BinarySerializer(65)], ]); const ChainPropertiesSerializer = ObjectSerializer([ ["account_creation_fee", AssetSerializer], ["maximum_block_size", UInt32Serializer], ["sbd_interest_rate", UInt16Serializer], ]); const OperationDataSerializer = (operationId, definitions) => { const objectSerializer = ObjectSerializer(definitions); return (buffer, data) => { buffer.writeVarint32(operationId); objectSerializer(buffer, data); }; }; const OperationSerializers = {}; OperationSerializers.account_create = OperationDataSerializer(9, [ ["fee", AssetSerializer], ["creator", StringSerializer], ["new_account_name", StringSerializer], ["owner", AuthoritySerializer], ["active", AuthoritySerializer], ["posting", AuthoritySerializer], ["memo_key", PublicKeySerializer], ["json_metadata", StringSerializer], ]); OperationSerializers.account_create_with_delegation = OperationDataSerializer(41, [ ["fee", AssetSerializer], ["delegation", AssetSerializer], ["creator", StringSerializer], ["new_account_name", StringSerializer], ["owner", AuthoritySerializer], ["active", AuthoritySerializer], ["posting", AuthoritySerializer], ["memo_key", PublicKeySerializer], ["json_metadata", StringSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.account_update = OperationDataSerializer(10, [ ["account", StringSerializer], ["owner", OptionalSerializer(AuthoritySerializer)], ["active", OptionalSerializer(AuthoritySerializer)], ["posting", OptionalSerializer(AuthoritySerializer)], ["memo_key", PublicKeySerializer], ["json_metadata", StringSerializer], ]); OperationSerializers.account_witness_proxy = OperationDataSerializer(13, [ ["account", StringSerializer], ["proxy", StringSerializer], ]); OperationSerializers.account_witness_vote = OperationDataSerializer(12, [ ["account", StringSerializer], ["witness", StringSerializer], ["approve", BooleanSerializer], ]); OperationSerializers.cancel_transfer_from_savings = OperationDataSerializer(34, [ ["from", StringSerializer], ["request_id", UInt32Serializer], ]); OperationSerializers.change_recovery_account = OperationDataSerializer(26, [ ["account_to_recover", StringSerializer], ["new_recovery_account", StringSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.claim_account = OperationDataSerializer(22, [ ["creator", StringSerializer], ["fee", AssetSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.claim_reward_balance = OperationDataSerializer(39, [ ["account", StringSerializer], ["reward_steem", AssetSerializer], ["reward_sbd", AssetSerializer], ["reward_vests", AssetSerializer], ]); OperationSerializers.comment = OperationDataSerializer(1, [ ["parent_author", StringSerializer], ["parent_permlink", StringSerializer], ["author", StringSerializer], ["permlink", StringSerializer], ["title", StringSerializer], ["body", StringSerializer], ["json_metadata", StringSerializer], ]); OperationSerializers.comment_options = OperationDataSerializer(19, [ ["author", StringSerializer], ["permlink", StringSerializer], ["max_accepted_payout", AssetSerializer], ["percent_steem_dollars", UInt16Serializer], ["allow_votes", BooleanSerializer], ["allow_curation_rewards", BooleanSerializer], [ "extensions", ArraySerializer(StaticVariantSerializer([ ObjectSerializer([ ["beneficiaries", ArraySerializer(BeneficiarySerializer)], ]), ])), ], ]); OperationSerializers.convert = OperationDataSerializer(8, [ ["owner", StringSerializer], ["requestid", UInt32Serializer], ["amount", AssetSerializer], ]); OperationSerializers.create_claimed_account = OperationDataSerializer(23, [ ["creator", StringSerializer], ["new_account_name", StringSerializer], ["owner", AuthoritySerializer], ["active", AuthoritySerializer], ["posting", AuthoritySerializer], ["memo_key", PublicKeySerializer], ["json_metadata", StringSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.custom = OperationDataSerializer(15, [ ["required_auths", ArraySerializer(StringSerializer)], ["id", UInt16Serializer], ["data", VariableBinarySerializer], ]); OperationSerializers.custom_binary = OperationDataSerializer(35, [ ["required_owner_auths", ArraySerializer(StringSerializer)], ["required_active_auths", ArraySerializer(StringSerializer)], ["required_posting_auths", ArraySerializer(StringSerializer)], ["required_auths", ArraySerializer(AuthoritySerializer)], ["id", StringSerializer], ["data", VariableBinarySerializer], ]); OperationSerializers.custom_json = OperationDataSerializer(18, [ ["required_auths", ArraySerializer(StringSerializer)], ["required_posting_auths", ArraySerializer(StringSerializer)], ["id", StringSerializer], ["json", StringSerializer], ]); OperationSerializers.decline_voting_rights = OperationDataSerializer(36, [ ["account", StringSerializer], ["decline", BooleanSerializer], ]); OperationSerializers.delegate_vesting_shares = OperationDataSerializer(40, [ ["delegator", StringSerializer], ["delegatee", StringSerializer], ["vesting_shares", AssetSerializer], ]); OperationSerializers.delete_comment = OperationDataSerializer(17, [ ["author", StringSerializer], ["permlink", StringSerializer], ]); OperationSerializers.escrow_approve = OperationDataSerializer(31, [ ["from", StringSerializer], ["to", StringSerializer], ["agent", StringSerializer], ["who", StringSerializer], ["escrow_id", UInt32Serializer], ["approve", BooleanSerializer], ]); OperationSerializers.escrow_dispute = OperationDataSerializer(28, [ ["from", StringSerializer], ["to", StringSerializer], ["agent", StringSerializer], ["who", StringSerializer], ["escrow_id", UInt32Serializer], ]); OperationSerializers.escrow_release = OperationDataSerializer(29, [ ["from", StringSerializer], ["to", StringSerializer], ["agent", StringSerializer], ["who", StringSerializer], ["receiver", StringSerializer], ["escrow_id", UInt32Serializer], ["sbd_amount", AssetSerializer], ["steem_amount", AssetSerializer], ]); OperationSerializers.escrow_transfer = OperationDataSerializer(27, [ ["from", StringSerializer], ["to", StringSerializer], ["sbd_amount", AssetSerializer], ["steem_amount", AssetSerializer], ["escrow_id", UInt32Serializer], ["agent", StringSerializer], ["fee", AssetSerializer], ["json_meta", StringSerializer], ["ratification_deadline", DateSerializer], ["escrow_expiration", DateSerializer], ]); OperationSerializers.feed_publish = OperationDataSerializer(7, [ ["publisher", StringSerializer], ["exchange_rate", PriceSerializer], ]); OperationSerializers.limit_order_cancel = OperationDataSerializer(6, [ ["owner", StringSerializer], ["orderid", UInt32Serializer], ]); OperationSerializers.limit_order_create = OperationDataSerializer(5, [ ["owner", StringSerializer], ["orderid", UInt32Serializer], ["amount_to_sell", AssetSerializer], ["min_to_receive", AssetSerializer], ["fill_or_kill", BooleanSerializer], ["expiration", DateSerializer], ]); OperationSerializers.limit_order_create2 = OperationDataSerializer(21, [ ["owner", StringSerializer], ["orderid", UInt32Serializer], ["amount_to_sell", AssetSerializer], ["exchange_rate", PriceSerializer], ["fill_or_kill", BooleanSerializer], ["expiration", DateSerializer], ]); OperationSerializers.recover_account = OperationDataSerializer(25, [ ["account_to_recover", StringSerializer], ["new_owner_authority", AuthoritySerializer], ["recent_owner_authority", AuthoritySerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.report_over_production = OperationDataSerializer(16, [ ["reporter", StringSerializer], ["first_block", SignedBlockHeaderSerializer], ["second_block", SignedBlockHeaderSerializer], ]); OperationSerializers.request_account_recovery = OperationDataSerializer(24, [ ["recovery_account", StringSerializer], ["account_to_recover", StringSerializer], ["new_owner_authority", AuthoritySerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.reset_account = OperationDataSerializer(37, [ ["reset_account", StringSerializer], ["account_to_reset", StringSerializer], ["new_owner_authority", AuthoritySerializer], ]); OperationSerializers.set_reset_account = OperationDataSerializer(38, [ ["account", StringSerializer], ["current_reset_account", StringSerializer], ["reset_account", StringSerializer], ]); OperationSerializers.set_withdraw_vesting_route = OperationDataSerializer(20, [ ["from_account", StringSerializer], ["to_account", StringSerializer], ["percent", UInt16Serializer], ["auto_vest", BooleanSerializer], ]); OperationSerializers.transfer = OperationDataSerializer(2, [ ["from", StringSerializer], ["to", StringSerializer], ["amount", AssetSerializer], ["memo", StringSerializer], ]); OperationSerializers.transfer_from_savings = OperationDataSerializer(33, [ ["from", StringSerializer], ["request_id", UInt32Serializer], ["to", StringSerializer], ["amount", AssetSerializer], ["memo", StringSerializer], ]); OperationSerializers.transfer_to_savings = OperationDataSerializer(32, [ ["from", StringSerializer], ["to", StringSerializer], ["amount", AssetSerializer], ["memo", StringSerializer], ]); OperationSerializers.transfer_to_vesting = OperationDataSerializer(3, [ ["from", StringSerializer], ["to", StringSerializer], ["amount", AssetSerializer], ]); OperationSerializers.vote = OperationDataSerializer(0, [ ["voter", StringSerializer], ["author", StringSerializer], ["permlink", StringSerializer], ["weight", Int16Serializer], ]); OperationSerializers.withdraw_vesting = OperationDataSerializer(4, [ ["account", StringSerializer], ["vesting_shares", AssetSerializer], ]); OperationSerializers.witness_update = OperationDataSerializer(11, [ ["owner", StringSerializer], ["url", StringSerializer], ["block_signing_key", PublicKeySerializer], ["props", ChainPropertiesSerializer], ["fee", AssetSerializer], ]); OperationSerializers.witness_set_properties = OperationDataSerializer(42, [ ["owner", StringSerializer], ["props", FlatMapSerializer(StringSerializer, VariableBinarySerializer)], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.account_update2 = OperationDataSerializer(43, [ ["account", StringSerializer], ["owner", OptionalSerializer(AuthoritySerializer)], ["active", OptionalSerializer(AuthoritySerializer)], ["posting", OptionalSerializer(AuthoritySerializer)], ["memo_key", OptionalSerializer(PublicKeySerializer)], ["json_metadata", StringSerializer], ["posting_json_metadata", StringSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.create_proposal = OperationDataSerializer(44, [ ["creator", StringSerializer], ["receiver", StringSerializer], ["start_date", DateSerializer], ["end_date", DateSerializer], ["daily_pay", AssetSerializer], ["subject", StringSerializer], ["permlink", StringSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.update_proposal_votes = OperationDataSerializer(45, [ ["voter", StringSerializer], ["proposal_ids", ArraySerializer(Int64Serializer)], ["approve", BooleanSerializer], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.remove_proposal = OperationDataSerializer(46, [ ["proposal_owner", StringSerializer], ["proposal_ids", ArraySerializer(Int64Serializer)], ["extensions", ArraySerializer(VoidSerializer)], ]); OperationSerializers.update_proposal = OperationDataSerializer(47, [ ["proposal_id", UInt64Serializer], ["creator", StringSerializer], ["daily_pay", AssetSerializer], ["subject", StringSerializer], ["permlink", StringSerializer], [ "extensions", ArraySerializer(StaticVariantSerializer([VoidSerializer, ProposalUpdateSerializer])), ], ]); OperationSerializers.collateralized_convert = OperationDataSerializer(48, [ ["owner", StringSerializer], ["requestid", UInt32Serializer], ["amount", AssetSerializer], ]); OperationSerializers.recurrent_transfer = OperationDataSerializer(49, [ ["from", StringSerializer], ["to", StringSerializer], ["amount", AssetSerializer], ["memo", StringSerializer], ["recurrence", UInt16Serializer], ["executions", UInt16Serializer], ["extensions", ArraySerializer(VoidSerializer)], ]); const OperationSerializer = (buffer, operation) => { const serializer = OperationSerializers[operation[0]]; if (!serializer) { throw new Error(`No serializer for operation: ${operation[0]}`); } try { serializer(buffer, operation[1]); } catch (error) { error.message = `${operation[0]}: ${error.message}`; throw error; } }; const TransactionSerializer = ObjectSerializer([ ["ref_block_num", UInt16Serializer], ["ref_block_prefix", UInt32Serializer], ["expiration", DateSerializer], ["operations", ArraySerializer(OperationSerializer)], ["extensions", ArraySerializer(StringSerializer)], ]); const EncryptedMemoSerializer = ObjectSerializer([ ["from", PublicKeySerializer], ["to", PublicKeySerializer], ["nonce", UInt64Serializer], ["check", UInt32Serializer], ["encrypted", BinarySerializer()], ]); exports.Types = { Array: ArraySerializer, Asset: AssetSerializer, Authority: AuthoritySerializer, Binary: BinarySerializer, Boolean: BooleanSerializer, Date: DateSerializer, EncryptedMemo: EncryptedMemoSerializer, FlatMap: FlatMapSerializer, Int16: Int16Serializer, Int32: Int32Serializer, Int64: Int64Serializer, Int8: Int8Serializer, Object: ObjectSerializer, Operation: OperationSerializer, Optional: OptionalSerializer, Price: PriceSerializer, PublicKey: PublicKeySerializer, StaticVariant: StaticVariantSerializer, String: StringSerializer, Transaction: TransactionSerializer, UInt16: UInt16Serializer, UInt32: UInt32Serializer, UInt64: UInt64Serializer, UInt8: UInt8Serializer, Void: VoidSerializer, };