@esteemapp/dhive
Version:
Hive blockchain RPC client library
538 lines (537 loc) • 21.5 kB
JavaScript
;
/**
* @file Hive 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 });
const client_1 = require("./../client");
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).steem_symbols();
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 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],
[(client_1.rebrandedApiGlobal ? 'hbd' : 'sbd') + '_interest_rate', UInt16Serializer]
]);
const OperationDataSerializer = (operationId, definitions) => {
const objectSerializer = ObjectSerializer(definitions);
return (buffer, data) => {
buffer.writeVarint32(operationId);
objectSerializer(buffer, data);
};
};
const OperationSerializers = {};
exports.updateOperations = () => {
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_' + (client_1.rebrandedApiGlobal ? 'hive' : 'steem'), AssetSerializer],
['reward_' + (client_1.rebrandedApiGlobal ? 'hbd' : '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_' + (client_1.rebrandedApiGlobal ? 'hbd' : '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],
[(client_1.rebrandedApiGlobal ? 'hbd' : 'sbd') + '_amount', AssetSerializer],
[(client_1.rebrandedApiGlobal ? 'hive' : 'steem') + '_amount', AssetSerializer]
]);
OperationSerializers.escrow_transfer = OperationDataSerializer(27, [
['from', StringSerializer],
['to', StringSerializer],
['agent', StringSerializer],
['escrow_id', UInt32Serializer],
[(client_1.rebrandedApiGlobal ? 'hbd' : 'sbd') + '_amount', AssetSerializer],
[(client_1.rebrandedApiGlobal ? 'hive' : 'steem') + '_amount', AssetSerializer],
['fee', AssetSerializer],
['ratification_deadline', DateSerializer],
['escrow_expiration', DateSerializer],
['json_meta', StringSerializer]
]);
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],
['fill_or_kill', BooleanSerializer],
['exchange_rate', PriceSerializer],
['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)]
]);
};
exports.updateOperations();
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)]
]);
exports.Types = {
Array: ArraySerializer,
Asset: AssetSerializer,
Authority: AuthoritySerializer,
Binary: BinarySerializer,
Boolean: BooleanSerializer,
Date: DateSerializer,
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
};