Skip to content

Commit

Permalink
feat(codec): molecule unpack works with BytesLike (#365)
Browse files Browse the repository at this point in the history
* feat(codec): molecule unpack works with BytesLike

* refactor(codec): rm unnecessary XLike codec
  • Loading branch information
homura authored Jul 18, 2022
1 parent 30fec41 commit c967aa6
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 38 deletions.
17 changes: 6 additions & 11 deletions packages/codec/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ export type UnpackParam<T extends AnyCodec> = T extends Codec<
? Unpackable
: never;

export type BytesCodec<Unpacked = any, Packable = Unpacked> = Codec<
export type Uint8ArrayCodec<Unpacked = any, Packable = Unpacked> = Codec<
Uint8Array,
Unpacked,
Packable
>;

export type BytesLike = ArrayLike<number> | ArrayBuffer | string;

export type BytesLikeCodec<Unpacked = any, Packable = Unpacked> = Codec<
export type BytesCodec<Unpacked = any, Packable = Unpacked> = Codec<
Uint8Array,
Unpacked,
Packable,
Expand All @@ -69,8 +69,8 @@ export type BytesLikeCodec<Unpacked = any, Packable = Unpacked> = Codec<
* @param codec
*/
export function createBytesCodec<Unpacked, Packable = Unpacked>(
codec: BytesCodec<Unpacked, Packable>
): BytesLikeCodec<Unpacked, Packable> {
codec: Uint8ArrayCodec<Unpacked, Packable>
): BytesCodec<Unpacked, Packable> {
return {
pack: (unpacked) => codec.pack(unpacked),
unpack: (bytesLike) => codec.unpack(bytify(bytesLike)),
Expand All @@ -88,20 +88,15 @@ export type FixedBytesCodec<Unpacked = any, Packable = Unpacked> = BytesCodec<
> &
Fixed;

export type FixedBytesLikeCodec<
Unpacked = any,
Packable = Unpacked
> = BytesLikeCodec<Unpacked, Packable> & Fixed;

export function isFixedCodec<T>(
codec: BytesCodec<T>
): codec is FixedBytesCodec<T> {
return isObjectLike(codec) && !!codec.__isFixedCodec__;
}

export function createFixedBytesCodec<Unpacked, Packable = Unpacked>(
codec: BytesCodec<Unpacked, Packable> & { byteLength: number }
): FixedBytesLikeCodec<Unpacked, Packable> {
codec: Uint8ArrayCodec<Unpacked, Packable> & { byteLength: number }
): FixedBytesCodec<Unpacked, Packable> {
const byteLength = codec.byteLength;
return {
__isFixedCodec__: true,
Expand Down
24 changes: 18 additions & 6 deletions packages/codec/src/blockchain.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {
AnyCodec,
BytesCodec,
BytesLike,
createBytesCodec,
createFixedBytesCodec,
FixedBytesCodec,
PackParam,
UnpackResult,
} from "./base";
import { bytify, hexify } from "./bytes";
Expand Down Expand Up @@ -47,11 +49,18 @@ export function WitnessArgsOf<
lock: LockCodec;
input_type: InputTypeCodec;
output_type: OutputTypeCodec;
}): BytesCodec<{
lock?: UnpackResult<LockCodec>;
input_type?: UnpackResult<InputTypeCodec>;
output_type?: UnpackResult<OutputTypeCodec>;
}> {
}): BytesCodec<
{
lock?: UnpackResult<LockCodec>;
input_type?: UnpackResult<InputTypeCodec>;
output_type?: UnpackResult<OutputTypeCodec>;
},
{
lock?: PackParam<LockCodec>;
input_type?: PackParam<InputTypeCodec>;
output_type?: PackParam<OutputTypeCodec>;
}
> {
return table(
{
lock: option(byteVecOf(payload.lock)),
Expand All @@ -62,7 +71,10 @@ export function WitnessArgsOf<
);
}

const HexifyCodec = createBytesCodec<string>({ pack: bytify, unpack: hexify });
const HexifyCodec = createBytesCodec<string, BytesLike>({
pack: bytify,
unpack: hexify,
});

/**
*
Expand Down
15 changes: 10 additions & 5 deletions packages/codec/src/molecule/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { assertBufferLength, assertMinBufferLength } from "../utils";
import { concat } from "../bytes";
import { BytesCodec, createFixedBytesCodec, FixedBytesCodec } from "../base";
import {
BytesCodec,
createBytesCodec,
createFixedBytesCodec,
FixedBytesCodec,
} from "../base";
import { Uint32LE } from "../number";

/**
Expand Down Expand Up @@ -30,8 +35,8 @@ export function byteOf<T>(codec: BytesCodec<T>): FixedBytesCodec<T> {
* a helper function to create custom codec of `vector Bytes <byte>`
* @param codec
*/
export function byteVecOf<T>(codec: BytesCodec<T>): BytesCodec<T> {
return {
export const byteVecOf = <T>(codec: BytesCodec<T>): BytesCodec<T> => {
return createBytesCodec({
pack(unpacked) {
const payload = codec.pack(unpacked);
const header = Uint32LE.pack(payload.byteLength);
Expand All @@ -44,5 +49,5 @@ export function byteVecOf<T>(codec: BytesCodec<T>): BytesCodec<T> {
assertBufferLength(packed.slice(4), header);
return codec.unpack(packed.slice(4));
},
};
}
});
};
25 changes: 12 additions & 13 deletions packages/codec/src/molecule/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

import type { BytesCodec, Fixed, FixedBytesCodec, UnpackResult } from "../base";
import { createFixedBytesCodec, isFixedCodec } from "../base";
import { createBytesCodec, createFixedBytesCodec, isFixedCodec } from "../base";
import { Uint32LE } from "../number";
import { concat } from "../bytes";

Expand Down Expand Up @@ -48,8 +48,7 @@ export function array<T extends FixedBytesCodec>(
itemCodec: T,
itemCount: number
): ArrayCodec<T> & Fixed {
return Object.freeze({
__isFixedCodec__: true,
return createFixedBytesCodec({
byteLength: itemCodec.byteLength * itemCount,
pack(items) {
const itemsBuf = items.map((item) => itemCodec.pack(item));
Expand Down Expand Up @@ -123,7 +122,7 @@ export function struct<T extends Record<string, FixedBytesCodec>>(
}

export function fixvec<T extends FixedBytesCodec>(itemCodec: T): ArrayCodec<T> {
return {
return createBytesCodec({
pack(items) {
return concat(
Uint32LE.pack(items.length),
Expand All @@ -142,11 +141,11 @@ export function fixvec<T extends FixedBytesCodec>(itemCodec: T): ArrayCodec<T> {
const itemCount = Uint32LE.unpack(buf.slice(0, 4));
return array(itemCodec, itemCount).unpack(buf.slice(4));
},
};
});
}

export function dynvec<T extends BytesCodec>(itemCodec: T): ArrayCodec<T> {
return {
return createBytesCodec({
pack(obj) {
const packed = obj.reduce(
(result, item) => {
Expand Down Expand Up @@ -198,7 +197,7 @@ export function dynvec<T extends BytesCodec>(itemCodec: T): ArrayCodec<T> {
return result;
}
},
};
});
}

export function vector<T extends BytesCodec>(itemCodec: T): ArrayCodec<T> {
Expand All @@ -213,7 +212,7 @@ export function table<T extends Record<string, BytesCodec>>(
fields: (keyof T)[]
): ObjectCodec<T> {
checkShape(shape, fields);
return {
return createBytesCodec({
pack(obj) {
const headerLength = 4 + fields.length * 4;
const packed = fields.reduce(
Expand Down Expand Up @@ -271,14 +270,14 @@ export function table<T extends Record<string, BytesCodec>>(
>;
}
},
};
});
}

export function union<T extends Record<string, BytesCodec>>(
itemCodec: T,
fields: (keyof T)[]
): UnionCodec<T> {
return {
return createBytesCodec({
pack(obj) {
const type = obj.type;
const fieldIndex = fields.indexOf(type);
Expand All @@ -294,11 +293,11 @@ export function union<T extends Record<string, BytesCodec>>(
const type = fields[typeIndex];
return { type, value: itemCodec[type].unpack(buf.slice(4)) };
},
};
});
}

export function option<T extends BytesCodec>(itemCodec: T): OptionCodec<T> {
return {
return createBytesCodec({
pack(obj?) {
if (obj !== undefined && obj !== null) {
return itemCodec.pack(obj);
Expand All @@ -312,5 +311,5 @@ export function option<T extends BytesCodec>(itemCodec: T): OptionCodec<T> {
}
return itemCodec.unpack(buf);
},
};
});
}
4 changes: 2 additions & 2 deletions packages/codec/src/number/uint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BI, BIish } from "@ckb-lumos/bi";
import { createFixedBytesCodec, FixedBytesLikeCodec } from "../base";
import { createFixedBytesCodec, FixedBytesCodec } from "../base";

function assertNumberRange(value: BIish, min: BIish, max: BIish): void {
value = BI.from(value);
Expand All @@ -14,7 +14,7 @@ function assertNumberRange(value: BIish, min: BIish, max: BIish): void {
function createUintNumberCodec(
byteLength: number,
littleEndian = false
): FixedBytesLikeCodec<number, BIish> {
): FixedBytesCodec<number, BIish> {
const codec = createUintBICodec(byteLength, littleEndian);
return {
__isFixedCodec__: true,
Expand Down
13 changes: 12 additions & 1 deletion packages/codec/tests/blockchain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const SECP256K1_SIGNATURE_LENGTH = 65;

test("secp256k1 witness args", (t) => {
const unsigned = WitnessArgs.pack({
lock: hexify(Buffer.alloc(SECP256K1_SIGNATURE_LENGTH)),
lock: Buffer.alloc(SECP256K1_SIGNATURE_LENGTH),
});

t.deepEqual(
Expand All @@ -18,6 +18,17 @@ test("secp256k1 witness args", (t) => {
)
);

t.deepEqual(
WitnessArgs.unpack(
"0x55000000100000005500000055000000410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
),
{
lock: hexify(Buffer.alloc(SECP256K1_SIGNATURE_LENGTH)),
input_type: undefined,
output_type: undefined,
}
);

const signature = bytify(randomBytes(SECP256K1_SIGNATURE_LENGTH));
const signed = WitnessArgs.pack({ lock: hexify(signature) });

Expand Down

1 comment on commit c967aa6

@vercel
Copy link

@vercel vercel bot commented on c967aa6 Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

lumos-website – ./

lumos-website.vercel.app
lumos-website-cryptape.vercel.app
lumos-website-git-develop-cryptape.vercel.app

Please sign in to comment.