Merge branch 'pow' into 'develop'
Add NIP-13 proof-of-work policy See merge request soapbox-pub/strfry-policies!7
This commit is contained in:
commit
2d880629cc
11
deno.lock
11
deno.lock
@ -210,5 +210,16 @@
|
|||||||
"https://esm.sh/v113/nostr-tools@1.8.1/lib/references.d.ts": "b2e39f5c439380a1dc8e578b471ba3992f33e3936aa0eecf625734c7ba669098",
|
"https://esm.sh/v113/nostr-tools@1.8.1/lib/references.d.ts": "b2e39f5c439380a1dc8e578b471ba3992f33e3936aa0eecf625734c7ba669098",
|
||||||
"https://esm.sh/v113/nostr-tools@1.8.1/lib/relay.d.ts": "9bc6f2897a95ec12d128e94b2e7d6161d30a6bfe8d4350e217fbf4b710988db3",
|
"https://esm.sh/v113/nostr-tools@1.8.1/lib/relay.d.ts": "9bc6f2897a95ec12d128e94b2e7d6161d30a6bfe8d4350e217fbf4b710988db3",
|
||||||
"https://esm.sh/v113/nostr-tools@1.8.1/lib/utils.d.ts": "6f37b09db0dce09f17ff7b70b921b9bb809bcb18c3bc058cb914afdf3c0e774e"
|
"https://esm.sh/v113/nostr-tools@1.8.1/lib/utils.d.ts": "6f37b09db0dce09f17ff7b70b921b9bb809bcb18c3bc058cb914afdf3c0e774e"
|
||||||
|
},
|
||||||
|
"npm": {
|
||||||
|
"specifiers": {
|
||||||
|
"@noble/secp256k1@^1.7.1": "@noble/secp256k1@1.7.1"
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@noble/secp256k1@1.7.1": {
|
||||||
|
"integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
mod.ts
1
mod.ts
@ -4,6 +4,7 @@ export { default as hellthreadPolicy, type Hellthread } from './src/policies/hel
|
|||||||
export { default as keywordPolicy } from './src/policies/keyword-policy.ts';
|
export { default as keywordPolicy } from './src/policies/keyword-policy.ts';
|
||||||
export { default as noopPolicy } from './src/policies/noop-policy.ts';
|
export { default as noopPolicy } from './src/policies/noop-policy.ts';
|
||||||
export { default as openaiPolicy, type OpenAI, type OpenAIHandler } from './src/policies/openai-policy.ts';
|
export { default as openaiPolicy, type OpenAI, type OpenAIHandler } from './src/policies/openai-policy.ts';
|
||||||
|
export { default as powPolicy } from './src/policies/pow-policy.ts';
|
||||||
export { default as pubkeyBanPolicy } from './src/policies/pubkey-ban-policy.ts';
|
export { default as pubkeyBanPolicy } from './src/policies/pubkey-ban-policy.ts';
|
||||||
export { default as rateLimitPolicy, type RateLimit } from './src/policies/rate-limit-policy.ts';
|
export { default as rateLimitPolicy, type RateLimit } from './src/policies/rate-limit-policy.ts';
|
||||||
export { default as readOnlyPolicy } from './src/policies/read-only-policy.ts';
|
export { default as readOnlyPolicy } from './src/policies/read-only-policy.ts';
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export { readLines } from 'https://deno.land/std@0.181.0/io/mod.ts';
|
export { readLines } from 'https://deno.land/std@0.181.0/io/mod.ts';
|
||||||
export { assert, assertEquals } from 'https://deno.land/std@0.181.0/testing/asserts.ts';
|
export { assert, assertEquals } from 'https://deno.land/std@0.181.0/testing/asserts.ts';
|
||||||
export { Keydb } from 'https://deno.land/x/keydb@1.0.0/sqlite.ts';
|
export { Keydb } from 'https://deno.land/x/keydb@1.0.0/sqlite.ts';
|
||||||
|
export * as secp from 'npm:@noble/secp256k1@^1.7.1';
|
||||||
|
20
src/policies/pow-policy.test.ts
Normal file
20
src/policies/pow-policy.test.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { assertEquals } from '../deps.ts';
|
||||||
|
import { buildEvent, buildInputMessage } from '../test.ts';
|
||||||
|
|
||||||
|
import powPolicy from './pow-policy.ts';
|
||||||
|
|
||||||
|
Deno.test('blocks events without a nonce', async () => {
|
||||||
|
const msg = buildInputMessage();
|
||||||
|
assertEquals((await powPolicy(msg)).action, 'reject');
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test('accepts event with sufficient POW', async () => {
|
||||||
|
const msg = buildInputMessage({
|
||||||
|
event: buildEvent({
|
||||||
|
id: '000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358',
|
||||||
|
tags: [['nonce', '776797', '20']],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals((await powPolicy(msg, { difficulty: 20 })).action, 'accept');
|
||||||
|
});
|
74
src/policies/pow-policy.ts
Normal file
74
src/policies/pow-policy.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { secp } from '../deps.ts';
|
||||||
|
|
||||||
|
import type { Policy } from '../types.ts';
|
||||||
|
|
||||||
|
/** Policy options for `powPolicy`. */
|
||||||
|
interface POW {
|
||||||
|
/** Events will be rejected if their `id` does not contain at least this many leading `0`'s. Default: `1` */
|
||||||
|
difficulty?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reject events which don't meet Proof-of-Work ([NIP-13](https://github.com/nostr-protocol/nips/blob/master/13.md)) criteria. */
|
||||||
|
const powPolicy: Policy<POW> = ({ event }, opts = {}) => {
|
||||||
|
const { difficulty = 1 } = opts;
|
||||||
|
|
||||||
|
const pow = getPow(event.id);
|
||||||
|
const nonce = event.tags.find((t) => t[0] === 'nonce');
|
||||||
|
|
||||||
|
if (pow >= difficulty && nonce && Number(nonce[2]) >= difficulty) {
|
||||||
|
return {
|
||||||
|
id: event.id,
|
||||||
|
action: 'accept',
|
||||||
|
msg: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: event.id,
|
||||||
|
action: 'reject',
|
||||||
|
msg: `pow: insufficient proof-of-work (difficulty ${difficulty})`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get POW difficulty from a Nostr hex ID. */
|
||||||
|
function getPow(id: string): number {
|
||||||
|
return getLeadingZeroBits(secp.utils.hexToBytes(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get number of leading 0 bits. Adapted from nostream.
|
||||||
|
* https://github.com/Cameri/nostream/blob/fb6948fd83ca87ce552f39f9b5eb780ea07e272e/src/utils/proof-of-work.ts
|
||||||
|
*/
|
||||||
|
function getLeadingZeroBits(hash: Uint8Array): number {
|
||||||
|
let total: number, i: number, bits: number;
|
||||||
|
|
||||||
|
for (i = 0, total = 0; i < hash.length; i++) {
|
||||||
|
bits = msb(hash[i]);
|
||||||
|
total += bits;
|
||||||
|
if (bits !== 8) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted from nostream.
|
||||||
|
* https://github.com/Cameri/nostream/blob/fb6948fd83ca87ce552f39f9b5eb780ea07e272e/src/utils/proof-of-work.ts
|
||||||
|
*/
|
||||||
|
function msb(b: number) {
|
||||||
|
let n = 0;
|
||||||
|
|
||||||
|
if (b === 0) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// deno-lint-ignore no-cond-assign
|
||||||
|
while (b >>= 1) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 7 - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default powPolicy;
|
Loading…
Reference in New Issue
Block a user