mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-07 00:02:47 +00:00
contents of zip
This commit is contained in:
702
scripts/protocol_buffers.js
Executable file
702
scripts/protocol_buffers.js
Executable file
@@ -0,0 +1,702 @@
|
||||
// Use strict
|
||||
"use strict";
|
||||
|
||||
|
||||
// Classes
|
||||
|
||||
// Protocol Buffers class
|
||||
class ProtocolBuffers {
|
||||
|
||||
// Public
|
||||
|
||||
// Decode
|
||||
static decode(messageType, data, schema) {
|
||||
|
||||
// Check if schema for message type isn't known
|
||||
if(messageType.toFixed() in schema === false) {
|
||||
|
||||
// Throw error
|
||||
throw "Schema for message type isn't known.";
|
||||
}
|
||||
|
||||
// Get message schema
|
||||
var messageSchema = schema[messageType.toFixed()];
|
||||
|
||||
// Initialize result
|
||||
var result = {};
|
||||
|
||||
// Go through all fields in the data
|
||||
for(var i = 0; i < data["length"];) {
|
||||
|
||||
// Get field tag
|
||||
var fieldTag = ProtocolBuffers.decodeVarint(data, i);
|
||||
|
||||
// Go to start of the field payload
|
||||
i += ProtocolBuffers.getVarintLength(data, i);
|
||||
|
||||
// Check if field tag is too big
|
||||
if(fieldTag > Number.MAX_SAFE_INTEGER) {
|
||||
|
||||
// Throw error
|
||||
throw "Field tag is too big.";
|
||||
}
|
||||
|
||||
// Get field number
|
||||
var fieldNumber = fieldTag.toNumber() >>> 3;
|
||||
|
||||
// Get field wire type
|
||||
var fieldWireType = fieldTag.toNumber() & 0b111;
|
||||
|
||||
// Check if field is known in the message schema
|
||||
if(fieldNumber.toFixed() in messageSchema === true) {
|
||||
|
||||
// Check field's expected type
|
||||
switch(messageSchema[fieldNumber.toFixed()]["Type"]) {
|
||||
|
||||
// Uint, bool, enum, or sint
|
||||
case ProtocolBuffers.UINT_SCHEMA_DATA_TYPE:
|
||||
case ProtocolBuffers.BOOL_SCHEMA_DATA_TYPE:
|
||||
case ProtocolBuffers.ENUM_SCHEMA_DATA_TYPE:
|
||||
case ProtocolBuffers.SINT_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if field wire type isn't correct
|
||||
if(fieldWireType !== ProtocolBuffers.VARINT_WIRE_TYPE) {
|
||||
|
||||
// Throw error
|
||||
throw "Field wire type isn't correct.";
|
||||
}
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// String or bytes
|
||||
case ProtocolBuffers.STRING_SCHEMA_DATA_TYPE:
|
||||
case ProtocolBuffers.BYTES_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if field wire type isn't correct
|
||||
if(fieldWireType !== ProtocolBuffers.LEN_WIRE_TYPE) {
|
||||
|
||||
// Throw error
|
||||
throw "Field wire type isn't correct.";
|
||||
}
|
||||
|
||||
// Break
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if field doesn't exist in the result
|
||||
if(messageSchema[fieldNumber.toFixed()]["Name"] in result === false) {
|
||||
|
||||
// Create field in result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]] = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Check field wire type
|
||||
switch(fieldWireType) {
|
||||
|
||||
// Varint
|
||||
case ProtocolBuffers.VARINT_WIRE_TYPE:
|
||||
|
||||
// Check if field is known in the message schema
|
||||
if(fieldNumber.toFixed() in messageSchema === true) {
|
||||
|
||||
// Get value from the field payload
|
||||
var value = ProtocolBuffers.decodeVarint(data, i);
|
||||
|
||||
// Check field's expected type
|
||||
switch(messageSchema[fieldNumber.toFixed()]["Type"]) {
|
||||
|
||||
// Uint
|
||||
case ProtocolBuffers.UINT_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Append value to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push(value);
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Bool
|
||||
case ProtocolBuffers.BOOL_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Append value as a boolean to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push(value.isZero() === false);
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Enum
|
||||
case ProtocolBuffers.ENUM_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value is too big
|
||||
if(value > Number.MAX_SAFE_INTEGER) {
|
||||
|
||||
// Throw error
|
||||
throw "Value is too big.";
|
||||
}
|
||||
|
||||
// Append value as an enum to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push(value.toNumber());
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Sint
|
||||
case ProtocolBuffers.SINT_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Get if value is even
|
||||
if(value.modulo(2).isZero() === true) {
|
||||
|
||||
// Append value as a positive number to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push(value.dividedToIntegerBy(2));
|
||||
}
|
||||
|
||||
// Otherwise
|
||||
else {
|
||||
|
||||
// Append value as a negative number to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push(value.plus(1).dividedToIntegerBy(-2));
|
||||
}
|
||||
|
||||
// Break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Go to next field
|
||||
i += ProtocolBuffers.getVarintLength(data, i);
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// I64
|
||||
case ProtocolBuffers.I64_WIRE_TYPE:
|
||||
|
||||
// Check if field payload doesn't contain data
|
||||
if(i + Common.BYTES_IN_A_UINT64 > data["length"]) {
|
||||
|
||||
// Throw error
|
||||
throw "Field payload doesn't contain data.";
|
||||
}
|
||||
|
||||
// Go to next field
|
||||
i += Common.BYTES_IN_A_UINT64;
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Len
|
||||
case ProtocolBuffers.LEN_WIRE_TYPE:
|
||||
|
||||
// Get length from the field payload
|
||||
var length = ProtocolBuffers.decodeVarint(data, i);
|
||||
|
||||
// Go to the field payload's data
|
||||
i += ProtocolBuffers.getVarintLength(data, i);
|
||||
|
||||
// Check if length is too big
|
||||
if(length > Number.MAX_SAFE_INTEGER) {
|
||||
|
||||
// Throw error
|
||||
throw "Length is too big.";
|
||||
}
|
||||
|
||||
// Check if field payload doesn't contain data
|
||||
if(i + length.toNumber() > data["length"]) {
|
||||
|
||||
// Throw error
|
||||
throw "Field payload doesn't contain data.";
|
||||
}
|
||||
|
||||
// Check if field is known in the message schema
|
||||
if(fieldNumber.toFixed() in messageSchema === true) {
|
||||
|
||||
// Get value from the field payload's data
|
||||
var value = data.subarray(i, i + length.toNumber());
|
||||
|
||||
// Check field's expected type
|
||||
switch(messageSchema[fieldNumber.toFixed()]["Type"]) {
|
||||
|
||||
// String
|
||||
case ProtocolBuffers.STRING_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Append value as a string to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push((new TextDecoder("utf-8", {"fatal": true})).decode(value));
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Bytes
|
||||
case ProtocolBuffers.BYTES_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Append value to result
|
||||
result[messageSchema[fieldNumber.toFixed()]["Name"]].push(value);
|
||||
|
||||
// Break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Go to next field
|
||||
i += length.toNumber();
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// I32
|
||||
case ProtocolBuffers.I32_WIRE_TYPE:
|
||||
|
||||
// Check if field payload doesn't contain data
|
||||
if(i + Common.BYTES_IN_A_UINT32 > data["length"]) {
|
||||
|
||||
// Throw error
|
||||
throw "Field payload doesn't contain data.";
|
||||
}
|
||||
|
||||
// Go to next field
|
||||
i += Common.BYTES_IN_A_UINT32;
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Default
|
||||
default:
|
||||
|
||||
// Throw error
|
||||
throw "Field wire type isn't known.";
|
||||
}
|
||||
}
|
||||
|
||||
// Return result
|
||||
return result;
|
||||
}
|
||||
|
||||
// Encode
|
||||
static encode(messageType, data, schema) {
|
||||
|
||||
// Check if schema for message type isn't known
|
||||
if(messageType.toFixed() in schema === false) {
|
||||
|
||||
// Throw error
|
||||
throw "Schema for message type isn't known.";
|
||||
}
|
||||
|
||||
// Get message schema
|
||||
var messageSchema = schema[messageType.toFixed()];
|
||||
|
||||
// Initialize result
|
||||
var result = new Uint8Array([]);
|
||||
|
||||
// Go through all values in the data
|
||||
for(var name in data) {
|
||||
|
||||
if(data.hasOwnProperty(name) === true) {
|
||||
|
||||
// Initialize value found
|
||||
var valueFound = false;
|
||||
|
||||
// Go through all fields in the message schema
|
||||
for(var fieldNumber in messageSchema) {
|
||||
|
||||
if(messageSchema.hasOwnProperty(fieldNumber) === true) {
|
||||
|
||||
// Check if field is for the value
|
||||
if(messageSchema[fieldNumber]["Name"] === name) {
|
||||
|
||||
// Set value found
|
||||
valueFound = true;
|
||||
|
||||
// Check field's type
|
||||
switch(messageSchema[fieldNumber]["Type"]) {
|
||||
|
||||
// Uint
|
||||
case ProtocolBuffers.UINT_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value type isn't correct
|
||||
if(data[name] instanceof BigNumber === false) {
|
||||
|
||||
// Throw error
|
||||
throw "Value's type isn't correct.";
|
||||
}
|
||||
|
||||
// Set field wire type
|
||||
var fieldWireType = ProtocolBuffers.VARINT_WIRE_TYPE;
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = ProtocolBuffers.encodeVarint(data[name]);
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Bool
|
||||
case ProtocolBuffers.BOOL_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value type isn't correct
|
||||
if(typeof data[name] !== "boolean") {
|
||||
|
||||
// Throw error
|
||||
throw "Value's type isn't correct.";
|
||||
}
|
||||
|
||||
// Set field wire type
|
||||
var fieldWireType = ProtocolBuffers.VARINT_WIRE_TYPE;
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = ProtocolBuffers.encodeVarint(new BigNumber((data[name] === true) ? 1 : 0));
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Enum
|
||||
case ProtocolBuffers.ENUM_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value type isn't correct
|
||||
if(typeof data[name] !== "number") {
|
||||
|
||||
// Throw error
|
||||
throw "Value's type isn't correct.";
|
||||
}
|
||||
|
||||
// Set field wire type
|
||||
var fieldWireType = ProtocolBuffers.VARINT_WIRE_TYPE;
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = ProtocolBuffers.encodeVarint(new BigNumber(data[name]));
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// String
|
||||
case ProtocolBuffers.STRING_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value's type isn't correct
|
||||
if(typeof data[name] !== "string") {
|
||||
|
||||
// Throw error
|
||||
throw "Value's type isn't correct.";
|
||||
}
|
||||
|
||||
// Set field wire type
|
||||
var fieldWireType = ProtocolBuffers.LEN_WIRE_TYPE;
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = Common.mergeArrays([
|
||||
|
||||
// Length
|
||||
ProtocolBuffers.encodeVarint(new BigNumber(data[name]["length"])),
|
||||
|
||||
// Data
|
||||
(new TextEncoder()).encode(data[name])
|
||||
]);
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Bytes
|
||||
case ProtocolBuffers.BYTES_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value's type isn't correct
|
||||
if(data[name] instanceof Uint8Array === false) {
|
||||
|
||||
// Throw error
|
||||
throw "Value's type isn't correct.";
|
||||
}
|
||||
|
||||
// Check if no data exists and data is optional
|
||||
if(data[name]["length"] === 0 && "Optional" in messageSchema[fieldNumber] === true && messageSchema[fieldNumber]["Optional"] === true) {
|
||||
|
||||
// Clear value found
|
||||
valueFound = false;
|
||||
}
|
||||
|
||||
// Otherwise
|
||||
else {
|
||||
|
||||
// Set field wire type
|
||||
var fieldWireType = ProtocolBuffers.LEN_WIRE_TYPE;
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = Common.mergeArrays([
|
||||
|
||||
// Length
|
||||
ProtocolBuffers.encodeVarint(new BigNumber(data[name]["length"])),
|
||||
|
||||
// Data
|
||||
data[name]
|
||||
]);
|
||||
}
|
||||
|
||||
// Break
|
||||
break;
|
||||
|
||||
// Sint
|
||||
case ProtocolBuffers.SINT_SCHEMA_DATA_TYPE:
|
||||
|
||||
// Check if value type isn't correct
|
||||
if(data[name] instanceof BigNumber === false) {
|
||||
|
||||
// Throw error
|
||||
throw "Value's type isn't correct.";
|
||||
}
|
||||
|
||||
// Set field wire type
|
||||
var fieldWireType = ProtocolBuffers.VARINT_WIRE_TYPE;
|
||||
|
||||
// Check if value is positive
|
||||
if(data[name].isPositive() === true) {
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = ProtocolBuffers.encodeVarint(data[name].multipliedBy(2));
|
||||
}
|
||||
|
||||
// Otherwise
|
||||
else {
|
||||
|
||||
// Set field payload
|
||||
var fieldPayload = ProtocolBuffers.encodeVarint(data[name].multipliedBy(-2).minus(1));
|
||||
}
|
||||
|
||||
// Break
|
||||
break;
|
||||
}
|
||||
|
||||
// Break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if value was found in message schema
|
||||
if(valueFound === true) {
|
||||
|
||||
// Set field tag
|
||||
var fieldTag = ProtocolBuffers.encodeVarint(new BigNumber((fieldNumber << 3) | fieldWireType));
|
||||
|
||||
// Append field tag and field payload to the result
|
||||
result = Common.mergeArrays([
|
||||
|
||||
// Result
|
||||
result,
|
||||
|
||||
// Field tag
|
||||
fieldTag,
|
||||
|
||||
// Field payload
|
||||
fieldPayload
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return result
|
||||
return result;
|
||||
}
|
||||
|
||||
// Uint schema data type
|
||||
static get UINT_SCHEMA_DATA_TYPE() {
|
||||
|
||||
// Return uint data type
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Bool schema data type
|
||||
static get BOOL_SCHEMA_DATA_TYPE() {
|
||||
|
||||
// Return bool data type
|
||||
return ProtocolBuffers.UINT_SCHEMA_DATA_TYPE + 1;
|
||||
}
|
||||
|
||||
// Enum schema data type
|
||||
static get ENUM_SCHEMA_DATA_TYPE() {
|
||||
|
||||
// Return enum data type
|
||||
return ProtocolBuffers.BOOL_SCHEMA_DATA_TYPE + 1;
|
||||
}
|
||||
|
||||
// String schema data type
|
||||
static get STRING_SCHEMA_DATA_TYPE() {
|
||||
|
||||
// Return string data type
|
||||
return ProtocolBuffers.ENUM_SCHEMA_DATA_TYPE + 1;
|
||||
}
|
||||
|
||||
// Bytes schema data type
|
||||
static get BYTES_SCHEMA_DATA_TYPE() {
|
||||
|
||||
// Return bytes data type
|
||||
return ProtocolBuffers.STRING_SCHEMA_DATA_TYPE + 1;
|
||||
}
|
||||
|
||||
// Sint schema data type
|
||||
static get SINT_SCHEMA_DATA_TYPE() {
|
||||
|
||||
// Return sint data type
|
||||
return ProtocolBuffers.BYTES_SCHEMA_DATA_TYPE + 1;
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
// Decode varint
|
||||
static decodeVarint(data, offset) {
|
||||
|
||||
// Initialize payloads
|
||||
var payloads = [];
|
||||
|
||||
// Loop through all bytes in the varint
|
||||
do {
|
||||
|
||||
// Check if data doesn't contain a varint
|
||||
if(offset >= data["length"]) {
|
||||
|
||||
// Throw error
|
||||
throw "Data doesn't contain a varint.";
|
||||
}
|
||||
|
||||
// Get if continuation bit is set
|
||||
var continuationBitSet = (data[offset] & 0b10000000) !== 0;
|
||||
|
||||
// Append payload to list
|
||||
payloads.unshift(data[offset] & 0b01111111);
|
||||
|
||||
// Increment offset
|
||||
++offset;
|
||||
|
||||
} while(continuationBitSet === true);
|
||||
|
||||
// Create bit writer
|
||||
var bitWriter = new BitWriter();
|
||||
|
||||
// Add padding bits to bit writer
|
||||
bitWriter.setBits(0, payloads["length"] % Common.BITS_IN_A_BYTE);
|
||||
|
||||
// Go through all payloads
|
||||
for(var i = 0; i < payloads["length"]; ++i) {
|
||||
|
||||
// Add payload to the bit writer
|
||||
bitWriter.setBits(payloads[i], 7);
|
||||
}
|
||||
|
||||
// Return number value of the bit writer's bytes
|
||||
return new BigNumber(Common.HEX_PREFIX + Common.toHexString(bitWriter.getBytes()));
|
||||
}
|
||||
|
||||
// Get varint length
|
||||
static getVarintLength(data, offset) {
|
||||
|
||||
// Initialize length
|
||||
var length = 0;
|
||||
|
||||
// Loop through all bytes in the varint
|
||||
do {
|
||||
|
||||
// Check if data doesn't contain a varint
|
||||
if(offset + length >= data["length"]) {
|
||||
|
||||
// Throw error
|
||||
throw "Data doesn't contain a varint.";
|
||||
}
|
||||
|
||||
// Get if continuation bit is set
|
||||
var continuationBitSet = (data[offset + length] & 0b10000000) !== 0;
|
||||
|
||||
// Increment length
|
||||
++length;
|
||||
|
||||
} while(continuationBitSet === true);
|
||||
|
||||
// Return length
|
||||
return length;
|
||||
}
|
||||
|
||||
// Encode varint
|
||||
static encodeVarint(value) {
|
||||
|
||||
// Get value as bytes
|
||||
var bytes = value.toBytes(BigNumber.BIG_ENDIAN);
|
||||
|
||||
// Initialize result
|
||||
var result = (new Uint8Array((bytes["length"] > 1 || bytes[0] >= 0b10000000) ? Math.ceil(bytes["length"] * Common.BITS_IN_A_BYTE / 7) : bytes["length"])).fill(0);
|
||||
|
||||
// Initialize bit reader with the bytes
|
||||
var bitReader = new BitReader(bytes);
|
||||
|
||||
// Go through all bytes in the result
|
||||
for(var i = result["length"] - 1; i >= 0; --i) {
|
||||
|
||||
// Set byte's continuation bit
|
||||
result[i] |= (i === result["length"] - 1) ? 0b00000000 : 0b10000000;
|
||||
|
||||
// Check if bytes can be encoded in one payload
|
||||
if(bytes["length"] === 1 && bytes[0] < 0b10000000) {
|
||||
|
||||
// Set byte's payload
|
||||
result[i] |= bitReader.getBits(8);
|
||||
}
|
||||
|
||||
// Otherwise check at the ending byte and a fewer than seven bits remain
|
||||
else if(i === result["length"] - 1 && bytes["length"] * Common.BITS_IN_A_BYTE % 7 !== 0) {
|
||||
|
||||
// Set byte's payload
|
||||
result[i] |= bitReader.getBits(bytes["length"] * Common.BITS_IN_A_BYTE % 7);
|
||||
}
|
||||
|
||||
// Otherwise
|
||||
else {
|
||||
|
||||
// Set byte's payload
|
||||
result[i] |= bitReader.getBits(7);
|
||||
}
|
||||
}
|
||||
|
||||
// Return result
|
||||
return result;
|
||||
}
|
||||
|
||||
// Varint wire type
|
||||
static get VARINT_WIRE_TYPE() {
|
||||
|
||||
// Return varint wire type
|
||||
return 0;
|
||||
}
|
||||
|
||||
// I64 wire type
|
||||
static get I64_WIRE_TYPE() {
|
||||
|
||||
// Return i64 wire type
|
||||
return ProtocolBuffers.VARINT_WIRE_TYPE + 1;
|
||||
}
|
||||
|
||||
// Len wire type
|
||||
static get LEN_WIRE_TYPE() {
|
||||
|
||||
// Return len wire type
|
||||
return ProtocolBuffers.I64_WIRE_TYPE + 1;
|
||||
}
|
||||
|
||||
// Sgroup wire type
|
||||
static get SGROUP_WIRE_TYPE() {
|
||||
|
||||
// Return sgroup wire type
|
||||
return ProtocolBuffers.LEN_WIRE_TYPE + 1;
|
||||
}
|
||||
|
||||
// Egroup wire type
|
||||
static get EGROUP_WIRE_TYPE() {
|
||||
|
||||
// Return egroup wire type
|
||||
return ProtocolBuffers.SGROUP_WIRE_TYPE + 1;
|
||||
}
|
||||
|
||||
// I32 wire type
|
||||
static get I32_WIRE_TYPE() {
|
||||
|
||||
// Return i32 wire type
|
||||
return ProtocolBuffers.EGROUP_WIRE_TYPE + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Main function
|
||||
|
||||
// Set global object's Protocol Buffers
|
||||
globalThis["ProtocolBuffers"] = ProtocolBuffers;
|
Reference in New Issue
Block a user