UNPKG

ox

Version:

Ethereum Standard Library

173 lines 5.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.toBytes = toBytes; exports.toHex = toHex; exports.to = to; exports.decodeRlpCursor = decodeRlpCursor; exports.readLength = readLength; exports.readList = readList; exports.from = from; exports.fromBytes = fromBytes; exports.fromHex = fromHex; const Bytes = require("./Bytes.js"); const Errors = require("./Errors.js"); const Hex = require("./Hex.js"); const Cursor = require("./internal/cursor.js"); function toBytes(value) { return to(value, 'Bytes'); } function toHex(value) { return to(value, 'Hex'); } function to(value, to) { const to_ = to ?? (typeof value === 'string' ? 'Hex' : 'Bytes'); const bytes = (() => { if (typeof value === 'string') { if (value.length > 3 && value.length % 2 !== 0) throw new Hex.InvalidLengthError(value); return Bytes.fromHex(value); } return value; })(); const cursor = Cursor.create(bytes, { recursiveReadLimit: Number.POSITIVE_INFINITY, }); const result = decodeRlpCursor(cursor, to_); return result; } function decodeRlpCursor(cursor, to = 'Hex') { if (cursor.bytes.length === 0) return (to === 'Hex' ? Hex.fromBytes(cursor.bytes) : cursor.bytes); const prefix = cursor.readByte(); if (prefix < 0x80) cursor.decrementPosition(1); if (prefix < 0xc0) { const length = readLength(cursor, prefix, 0x80); const bytes = cursor.readBytes(length); return (to === 'Hex' ? Hex.fromBytes(bytes) : bytes); } const length = readLength(cursor, prefix, 0xc0); return readList(cursor, length, to); } function readLength(cursor, prefix, offset) { if (offset === 0x80 && prefix < 0x80) return 1; if (prefix <= offset + 55) return prefix - offset; if (prefix === offset + 55 + 1) return cursor.readUint8(); if (prefix === offset + 55 + 2) return cursor.readUint16(); if (prefix === offset + 55 + 3) return cursor.readUint24(); if (prefix === offset + 55 + 4) return cursor.readUint32(); throw new Errors.BaseError('Invalid RLP prefix'); } function readList(cursor, length, to) { const position = cursor.position; const value = []; while (cursor.position - position < length) value.push(decodeRlpCursor(cursor, to)); return value; } function from(value, options) { const { as } = options; const encodable = getEncodable(value); const cursor = Cursor.create(new Uint8Array(encodable.length)); encodable.encode(cursor); if (as === 'Hex') return Hex.fromBytes(cursor.bytes); return cursor.bytes; } function fromBytes(bytes, options = {}) { const { as = 'Bytes' } = options; return from(bytes, { as }); } function fromHex(hex, options = {}) { const { as = 'Hex' } = options; return from(hex, { as }); } function getEncodable(bytes) { if (Array.isArray(bytes)) return getEncodableList(bytes.map((x) => getEncodable(x))); return getEncodableBytes(bytes); } function getEncodableList(list) { const bodyLength = list.reduce((acc, x) => acc + x.length, 0); const sizeOfBodyLength = getSizeOfLength(bodyLength); const length = (() => { if (bodyLength <= 55) return 1 + bodyLength; return 1 + sizeOfBodyLength + bodyLength; })(); return { length, encode(cursor) { if (bodyLength <= 55) { cursor.pushByte(0xc0 + bodyLength); } else { cursor.pushByte(0xc0 + 55 + sizeOfBodyLength); if (sizeOfBodyLength === 1) cursor.pushUint8(bodyLength); else if (sizeOfBodyLength === 2) cursor.pushUint16(bodyLength); else if (sizeOfBodyLength === 3) cursor.pushUint24(bodyLength); else cursor.pushUint32(bodyLength); } for (const { encode } of list) { encode(cursor); } }, }; } function getEncodableBytes(bytesOrHex) { const bytes = typeof bytesOrHex === 'string' ? Bytes.fromHex(bytesOrHex) : bytesOrHex; const sizeOfBytesLength = getSizeOfLength(bytes.length); const length = (() => { if (bytes.length === 1 && bytes[0] < 0x80) return 1; if (bytes.length <= 55) return 1 + bytes.length; return 1 + sizeOfBytesLength + bytes.length; })(); return { length, encode(cursor) { if (bytes.length === 1 && bytes[0] < 0x80) { cursor.pushBytes(bytes); } else if (bytes.length <= 55) { cursor.pushByte(0x80 + bytes.length); cursor.pushBytes(bytes); } else { cursor.pushByte(0x80 + 55 + sizeOfBytesLength); if (sizeOfBytesLength === 1) cursor.pushUint8(bytes.length); else if (sizeOfBytesLength === 2) cursor.pushUint16(bytes.length); else if (sizeOfBytesLength === 3) cursor.pushUint24(bytes.length); else cursor.pushUint32(bytes.length); cursor.pushBytes(bytes); } }, }; } function getSizeOfLength(length) { if (length <= 0xff) return 1; if (length <= 0xff_ff) return 2; if (length <= 0xff_ff_ff) return 3; if (length <= 0xff_ff_ff_ff) return 4; throw new Errors.BaseError('Length is too large.'); } //# sourceMappingURL=Rlp.js.map