Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions anchor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs';
import {Veritas, SLabel} from '@spacesprotocol/veritas';
import b4a from 'b4a';
import {EventRecord, CompactEvent, signableCompactEvent, TargetInfo} from './messages';
import {log} from './utils';
import {log, getProofFromTags} from './utils';

interface Anchor {
root: string;
Expand Down Expand Up @@ -98,9 +98,11 @@ export class AnchorStore {

public assertAnchored(evt: CompactEvent, targetInfo: TargetInfo, prev?: EventRecord): EventRecord {
if (!targetInfo.space) throw new Error('Not a space anchored')
if (evt.proof.length === 0) throw new Error('Proof needed')

const proof = this.veritas.verifyProof(evt.proof);

const proofBase64 = getProofFromTags(evt.tags);
Copy link
Member

Choose a reason for hiding this comment

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

Encoding the proof as a base64 string significantly increases the size of each event sent over the wire which undermines the purpose of CompactEvent being compact. We should keep the proof in binary form when transmitting, especially to avoid UDP fragmentation issues.

if (proofBase64.length == 0) throw new Error('Proof is needed');
const proofBuffer = b4a.from(proofBase64, 'base64');
const proof = this.veritas.verifyProof(proofBuffer);
const space = new SLabel(targetInfo.space);
const utxo = proof.findSpace(space);
if (!utxo) throw new Error('No space utxo found in proof');
Expand Down
3 changes: 3 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ interface NodeResposne {
event: CompactEvent
}

export { AnchorStore } from './anchor'


export interface FabricOptions extends HyperDHTOptions {
maxSize?: number;
maxAge?: number;
Expand Down
10 changes: 1 addition & 9 deletions messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export interface CompactEvent {
binary_content: boolean,
content: Uint8Array,
sig: Uint8Array,
proof: Uint8Array
}

export interface EventRecord {
Expand All @@ -28,16 +27,14 @@ export interface TargetInfo {

export function toCompactEvent(evt: NostrEvent, binary_content: boolean) : Uint8Array {
if (!evt.sig) throw new Error('must be a signed event');

return c.encode(compactEvent, {
created_at: evt.created_at,
kind: evt.kind,
tags: evt.tags,
binary_content: binary_content,
content: b4a.from(evt.content, binary_content ? 'base64' : 'utf-8'),
content: b4a.from(evt.content, binary_content ? 'base64' : 'utf-8'),
sig: b4a.from(evt.sig, 'hex'),
pubkey: b4a.from(evt.pubkey, 'hex'),
proof: evt.proof ? b4a.from(evt.proof, 'base64') : null,
});
}

Expand All @@ -60,11 +57,9 @@ export function toEvent(evt: CompactEvent) : NostrEvent {
tags: evt.tags,
content: b4a.toString(evt.content || new Uint8Array(), evt.binary_content ? 'base64' : 'utf-8'),
sig: b4a.toString(evt.sig, 'hex'),
proof: evt.proof ? b4a.toString(evt.proof, 'base64') : undefined
}
}


export const compactEvent = {
preencode (state: any, m: CompactEvent): void {
c.uint.preencode(state, m.created_at)
Expand All @@ -74,7 +69,6 @@ export const compactEvent = {
c.bool.preencode(state, m.binary_content)
c.buffer.preencode(state, m.content)
c.fixed64.preencode(state, m.sig)
c.buffer.preencode(state, m.proof)
},
encode (state: any, m: CompactEvent): void {
c.uint.encode(state, m.created_at)
Expand All @@ -84,7 +78,6 @@ export const compactEvent = {
c.bool.encode(state, m.binary_content)
c.buffer.encode(state, m.content)
c.fixed64.encode(state, m.sig)
c.buffer.encode(state, m.proof)
},
decode (state: any): CompactEvent {
return {
Expand All @@ -95,7 +88,6 @@ export const compactEvent = {
binary_content: c.bool.decode(state),
content: c.buffer.decode(state) || new Uint8Array,
sig: c.fixed64.decode(state),
proof: c.buffer.decode(state) || new Uint8Array
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"version": "0.0.7",
"description": "",
"main": "dist/index.js",
"exports": {
".": "./dist/index.js",
"./anchor": "./dist/anchor.js"
},
"types": "./dist/index.d.ts",
"scripts": {
"prepare": "npm run build",
"build": "tsc",
Expand Down
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */

/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
Expand Down
19 changes: 16 additions & 3 deletions utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export type NostrEvent = {
pubkey: string
content: string
created_at: number
proof?: string
}

// from nostr-tools:
Expand Down Expand Up @@ -73,6 +72,8 @@ export function computeSpaceTarget(space : string, kind : number, d : string = '
if (!space.startsWith('@')) throw new Error('space name must start with @')

const key = Veritas.sha256(b4a.from(space, 'utf-8'));


const targetString = nostrTarget(b4a.toString(key, 'hex'), kind, d);
return Veritas.sha256(b4a.from(targetString, 'utf-8'));
}
Expand All @@ -84,15 +85,27 @@ export function computePubkeyTarget(pubkey: string | Uint8Array, kind : number,
return Veritas.sha256(b4a.from(targetString, 'utf-8'));
}

export function getProofFromTags(tags: string[][]): string {
for (const tag of tags) {
if (tag.length === 3 && tag[0] === 's') {
return tag[2];
}
}
return '';
}


export function computeTarget(evt: CompactEvent) : TargetInfo {
const anchored = evt.proof.length !== 0;
const proof = getProofFromTags(evt.tags);
const anchored = proof.length !== 0;

if (isNaN(evt.kind)) throw new Error('Invalid event kind must be a number');

let space, d;

for (const tag of evt.tags) {
if (tag.length < 2) continue;
if (!space && anchored && tag[0] === 'space') {
if (!space && anchored && tag[0] === 's' && tag.length >= 2) {
Copy link
Member

Choose a reason for hiding this comment

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

isn't the tag.length >= 2 redundant given there's if (tag.length < 2) continue; first?

space = tag[1];
continue;
}
Expand Down