From 29005ea7b5e6df4506fecdbfd2cbf1df15e069ca Mon Sep 17 00:00:00 2001 From: Denis Davidyuk Date: Sat, 15 Jun 2024 10:55:56 +1000 Subject: [PATCH] refactor(tx-builder): extract common pointers code --- src/tx/builder/field-types/pointers.ts | 59 +++++++++++++++++------ src/tx/builder/field-types/pointers2.ts | 62 ------------------------- src/tx/builder/schema.ts | 6 +-- 3 files changed, 48 insertions(+), 79 deletions(-) delete mode 100644 src/tx/builder/field-types/pointers2.ts diff --git a/src/tx/builder/field-types/pointers.ts b/src/tx/builder/field-types/pointers.ts index 6063a528c1..d40a5d2df3 100644 --- a/src/tx/builder/field-types/pointers.ts +++ b/src/tx/builder/field-types/pointers.ts @@ -1,31 +1,56 @@ import { NamePointer as NamePointerString } from '../../../apis/node'; import { toBytes } from '../../../utils/bytes'; -import { Encoded } from '../../../utils/encoder'; -import { IllegalArgumentError } from '../../../utils/errors'; +import { + Encoded, Encoding, decode, encode, +} from '../../../utils/encoder'; +import { isAddressValid } from '../../../utils/crypto'; +import { IllegalArgumentError, DecodeError, ArgumentError } from '../../../utils/errors'; import address, { AddressEncodings, idTagToEncoding } from './address'; +const ID_TAG = Buffer.from([1]); +const DATA_TAG = Buffer.from([2]); +const DATA_LENGTH_MAX = 1024; const addressAny = address(...idTagToEncoding); // TODO: remove after fixing node types type NamePointer = NamePointerString & { id: Encoded.Generic; }; +type NamePointerRaw = NamePointerString & { + id: Encoded.Generic; +}; -export default { +export default (allowRaw: AllowRaw): { + serialize: (pointers: Array) => Buffer[][]; + deserialize: ( + pointers: Array<[key: Buffer, id: Buffer]>, + ) => Array; +} => ({ /** * Helper function to build pointers for name update TX * @param pointers - Array of pointers * `([ { key: 'account_pubkey', id: 'ak_32klj5j23k23j5423l434l2j3423'} ])` * @returns Serialized pointers array */ - serialize(pointers: NamePointer[]): Buffer[][] { + serialize(pointers) { if (pointers.length > 32) { throw new IllegalArgumentError(`Expected 32 pointers or less, got ${pointers.length} instead`); } - - return pointers.map( - (pointer) => [toBytes(pointer.key), addressAny.serialize(pointer.id)], - ); + return pointers.map(({ key, id }) => { + let payload; + if (isAddressValid(id, ...idTagToEncoding)) { + payload = [...allowRaw ? [ID_TAG] : [], addressAny.serialize(id)]; + } + if (isAddressValid(id, Encoding.Bytearray)) { + const data = decode(id); + if (data.length > DATA_LENGTH_MAX) { + throw new ArgumentError('Raw pointer', `shorter than ${DATA_LENGTH_MAX + 1} bytes`, `${data.length} bytes`); + } + payload = [DATA_TAG, data]; + } + if (payload == null) throw new DecodeError(`Unknown AENS pointer value: ${id}`); + return [toBytes(key), Buffer.concat(payload)]; + }); }, /** @@ -33,9 +58,17 @@ export default { * @param pointers - Array of pointers * @returns Deserialize pointer array */ - deserialize(pointers: Array<[key: Buffer, id: Buffer]>): NamePointer[] { - return pointers.map( - ([key, id]) => ({ key: key.toString(), id: addressAny.deserialize(id) }), - ); + deserialize(pointers) { + return pointers.map(([bKey, bId]) => { + if (!allowRaw) return { key: bKey.toString(), id: addressAny.deserialize(bId) }; + const tag = bId.subarray(0, 1); + const payload = bId.subarray(1); + let id; + if (tag.equals(ID_TAG)) id = addressAny.deserialize(payload); + // TS can't figure out the real type depending on allowRaw + if (tag.equals(DATA_TAG)) id = encode(payload, Encoding.Bytearray) as Encoded.AccountAddress; + if (id == null) throw new DecodeError(`Unknown AENS pointer tag: ${tag}`); + return { key: bKey.toString(), id }; + }); }, -}; +}); diff --git a/src/tx/builder/field-types/pointers2.ts b/src/tx/builder/field-types/pointers2.ts deleted file mode 100644 index fe849ab3ef..0000000000 --- a/src/tx/builder/field-types/pointers2.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { NamePointer as NamePointerString } from '../../../apis/node'; -import { toBytes } from '../../../utils/bytes'; -import { - Encoded, Encoding, decode, encode, -} from '../../../utils/encoder'; -import { isAddressValid } from '../../../utils/crypto'; -import { IllegalArgumentError, DecodeError, ArgumentError } from '../../../utils/errors'; -import address, { AddressEncodings, idTagToEncoding } from './address'; - -const ID_TAG = Buffer.from([1]); -const DATA_TAG = Buffer.from([2]); -const DATA_LENGTH_MAX = 1024; -const addressAny = address(...idTagToEncoding); - -// TODO: remove after fixing node types -type NamePointer = NamePointerString & { - id: Encoded.Generic; -}; - -export default { - /** - * Helper function to build pointers for name update TX - * @param pointers - Array of pointers - * `([ { key: 'account_pubkey', id: 'ak_32klj5j23k23j5423l434l2j3423'} ])` - * @returns Serialized pointers array - */ - serialize(pointers: NamePointer[]): Buffer[][] { - if (pointers.length > 32) { - throw new IllegalArgumentError(`Expected 32 pointers or less, got ${pointers.length} instead`); - } - return pointers.map(({ key, id }) => { - let payload; - if (isAddressValid(id, ...idTagToEncoding)) payload = [ID_TAG, addressAny.serialize(id)]; - if (isAddressValid(id, Encoding.Bytearray)) { - const data = decode(id); - if (data.length > DATA_LENGTH_MAX) { - throw new ArgumentError('Raw pointer', `shorter than ${DATA_LENGTH_MAX + 1} bytes`, `${data.length} bytes`); - } - payload = [DATA_TAG, data]; - } - if (payload == null) throw new DecodeError(`Unknown AENS pointer value: ${id}`); - return [toBytes(key), Buffer.concat(payload)]; - }); - }, - - /** - * Helper function to read pointers from name update TX - * @param pointers - Array of pointers - * @returns Deserialize pointer array - */ - deserialize(pointers: Array<[key: Buffer, id: Buffer]>): NamePointer[] { - return pointers.map(([bKey, bId]) => { - const tag = bId.subarray(0, 1); - const payload = bId.subarray(1); - let id; - if (tag.equals(ID_TAG)) id = addressAny.deserialize(payload); - if (tag.equals(DATA_TAG)) id = encode(payload, Encoding.Bytearray); - if (id == null) throw new DecodeError(`Unknown AENS pointer tag: ${tag}`); - return { key: bKey.toString(), id }; - }); - }, -}; diff --git a/src/tx/builder/schema.ts b/src/tx/builder/schema.ts index c0ec4ba76a..3d4d9231b1 100644 --- a/src/tx/builder/schema.ts +++ b/src/tx/builder/schema.ts @@ -22,7 +22,6 @@ import nameFee from './field-types/name-fee'; import nameId from './field-types/name-id'; import nonce from './field-types/nonce'; import pointers from './field-types/pointers'; -import pointers2 from './field-types/pointers2'; import queryFee from './field-types/query-fee'; import raw from './field-types/raw'; import shortUInt from './field-types/short-u-int'; @@ -70,7 +69,6 @@ interface EntryTreesPoi { const entryTreesPoi = entry(EntryTag.TreesPoi) as unknown as EntryTreesPoi; -// TODO: inline after dropping Iris compatibility const clientTtl = withDefault(60 * 60, shortUInt); // https://github.com/aeternity/protocol/blob/fd17982/AENS.md#update /** @@ -130,7 +128,7 @@ export const txSchema = [{ nonce: nonce('accountId'), nameId, nameTtl, - pointers, + pointers: pointers(false), clientTtl, fee, ttl, @@ -141,7 +139,7 @@ export const txSchema = [{ nonce: nonce('accountId'), nameId, nameTtl, - pointers: pointers2, + pointers: pointers(true), clientTtl, fee, ttl,