diff --git a/src/codec.spec.ts b/src/codec.spec.ts index 5cf2544..2e8305c 100644 --- a/src/codec.spec.ts +++ b/src/codec.spec.ts @@ -1,9 +1,5 @@ import { expect } from "chai"; -import { - DecoderV0, - EncoderV0, - MessageV0, -} from "js-waku/lib/waku_message/version_0"; +import { DecoderV0, EncoderV0 } from "js-waku/lib/waku_message/version_0"; import { RLNDecoder, RLNEncoder } from "./codec.js"; @@ -26,7 +22,10 @@ describe("js-rln: encoder", () => { index, memKeys ); - const rlnDecoder = new RLNDecoder(new DecoderV0(TestContentTopic)); + const rlnDecoder = new RLNDecoder( + rlnInstance, + new DecoderV0(TestContentTopic) + ); const bytes = await rlnEncoder.encode({ payload }); const protoResult = await rlnDecoder.decodeProto(bytes!); @@ -34,13 +33,11 @@ describe("js-rln: encoder", () => { const msg = (await rlnDecoder.decode(protoResult!))!; // Validate proof - const verifResult = rlnInstance.verifyProof(msg.rateLimitProof!); - expect(verifResult).to.be.true; + expect(msg.verify()).to.be.true; - const msgV0 = msg as MessageV0; - expect(msgV0.contentTopic).to.eq(TestContentTopic); - expect(msgV0.version).to.eq(0); - expect(msgV0.payload).to.deep.eq(payload); - expect(msgV0.timestamp).to.not.be.undefined; + expect(msg.contentTopic).to.eq(TestContentTopic); + expect(msg.msg.version).to.eq(0); + expect(msg.payload).to.deep.eq(payload); + expect(msg.timestamp).to.not.be.undefined; }); }); diff --git a/src/codec.ts b/src/codec.ts index 535be68..265f149 100644 --- a/src/codec.ts +++ b/src/codec.ts @@ -7,6 +7,7 @@ import { ProtoMessage, } from "js-waku/lib/interfaces"; +import { RlnMessage } from "./message.js"; import { MembershipKey, RLNInstance } from "./rln.js"; const log = debug("waku:message:rln-encoder"); @@ -53,11 +54,11 @@ export class RLNEncoder implements Encoder { } } -export class RLNDecoder implements Decoder { - public contentTopic: string; +export class RLNDecoder implements Decoder> { + constructor(private rlnInstance: RLNInstance, private decoder: Decoder) {} - constructor(private decoder: Decoder) { - this.contentTopic = decoder.contentTopic; + get contentTopic(): string { + return this.decoder.contentTopic; } decodeProto(bytes: Uint8Array): Promise { @@ -66,12 +67,10 @@ export class RLNDecoder implements Decoder { return Promise.resolve(protoMessage); } - async decode(proto: ProtoMessage): Promise { - const msg = await this.decoder.decode(proto); - if (msg) { - msg.rateLimitProof = proto.rateLimitProof; - } - return msg; + async decode(proto: ProtoMessage): Promise | undefined> { + const msg: T | undefined = await this.decoder.decode(proto); + if (!msg) return; + return new RlnMessage(this.rlnInstance, msg, proto.rateLimitProof); } } diff --git a/src/message.ts b/src/message.ts new file mode 100644 index 0000000..ab6d45a --- /dev/null +++ b/src/message.ts @@ -0,0 +1,37 @@ +import { Message, RateLimitProof } from "js-waku/lib/interfaces"; + +import { epochBytesToInt } from "./epoch.js"; +import { RLNInstance } from "./rln.js"; + +export class RlnMessage implements Message { + constructor( + public rlnInstance: RLNInstance, + public msg: T, + public rateLimitProof?: RateLimitProof + ) {} + + public verify(): boolean | undefined { + return this.rateLimitProof + ? this.rlnInstance.verifyProof(this.rateLimitProof) + : undefined; + } + + get payload(): Uint8Array | undefined { + return this.msg.payload; + } + + get contentTopic(): string | undefined { + return this.msg.contentTopic; + } + + get timestamp(): Date | undefined { + return this.msg.timestamp; + } + + get epoch(): number | undefined { + const bytes = this.msg.rateLimitProof?.epoch; + if (!bytes) return; + + return epochBytesToInt(bytes); + } +}