nip-13: add settings for target difficulty and timeout

adding settings to change difficulty target and timeout, so users
can change or disable pow. also added some explanation and link
to nip-13.

setting arbitrary low default to 16 zero target difficulty and
5 seconds timeout.
OFF0 2 years ago
parent f8bb537160
commit c3eaef56ca
Signed by: offbyn
GPG Key ID: 94A2F643C51F37FA

@ -10,7 +10,7 @@
} }
@media (orientation: portrait) { @media (orientation: portrait) {
.mbox { .mbox {
padding: 0 calc(.5 * var(--gap)); padding: 0 var(--gap-half);
} }
} }
.mbox:last-child { .mbox:last-child {

@ -43,6 +43,7 @@ label {
transition: background-color var(--transition-duration); transition: background-color var(--transition-duration);
} }
input[type="number"],
input[type="password"], input[type="password"],
input[type="text"], input[type="text"],
input[type="url"], input[type="url"],
@ -54,6 +55,7 @@ textarea {
margin: 0 0 1.2rem 0; margin: 0 0 1.2rem 0;
padding: var(--padding); padding: var(--padding);
} }
input[type="number"]:focus,
input[type="password"]:focus, input[type="password"]:focus,
input[type="text"]:focus, input[type="text"]:focus,
input[type="url"]:focus, input[type="url"]:focus,
@ -169,11 +171,13 @@ button:disabled {
margin-left: var(--gap); margin-left: var(--gap);
} }
.form-inline button, .form-inline button,
.form-inline input[type="number"],
.form-inline input[type="text"], .form-inline input[type="text"],
.form-inline textarea { .form-inline textarea {
margin: .4rem 0; margin: .4rem 0;
} }
.form-inline input[type="number"],
.form-inline input[type="text"], .form-inline input[type="text"],
.form-inline textarea { .form-inline textarea {
flex-basis: 50%; flex-basis: 50%;
@ -187,6 +191,46 @@ button:disabled {
flex-grow: 0; flex-grow: 0;
} }
label.number {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: var(--gap);
padding: 0;
}
* + label.number {
margin: var(--gap) 0 0 0;
}
label.number span {
flex-grow: 1;
padding: 0 0 0 var(--padding);
}
label.number input[type="number"] {
align-self: baseline;
margin-bottom: 0;
}
@media (orientation: landscape) {
label.number span {
align-self: center;
}
label.number input[type="number"] + span {
padding: 0 var(--padding) 0 0;
}
}
@media (orientation: portrait) {
label.number {
flex-direction: column;
gap: var(--gap-half);
padding: 0;
}
label.number span {
padding: 0 var(--padding);
}
label.number input[type="number"] {
align-self: stretch;
}
}
button#publish { button#publish {
align-self: end; align-self: end;
order: 2; order: 2;

@ -83,6 +83,27 @@
<button type="submit" name="publish" tabindex="0" disabled>publish</button> <button type="submit" name="publish" tabindex="0" disabled>publish</button>
</div> </div>
</form> </form>
<form action="#" name="options">
<label class="number" for="difficutlyTarget">
<span>
target difficulty<br>
<small>
with which difficulty to try to mine a proof of work when publishing events, such as: notes, replies, reactions and profile updates.
use zero to disable mining.
difficulty is defined as the number of leading zero bits, read more about
<a href="https://github.com/nostr-protocol/nips/blob/master/13.md" target="_blank" rel="noopener noreferrer">proof of work (nip-13)</a>.
</small>
</span>
<input type="number" name="difficulty_target" step="1" min="0" max="256" id="difficutlyTarget" value="16">
</label>
<label class="number" for="miningTimeout">
<span>
mining timeout<br>
<small>abord trying to find a proof if timeout (in seconds) exceeds. use 0 to mine without a time limit.</small>
</span>
<input type="number" name="mining_timeout" step="1" min="0" max="256" id="miningTimeout" value="5">
</label>
</form>
<form action="#" name="settings" autocomplete="new-password"> <form action="#" name="settings" autocomplete="new-password">
<label for="pubkey">public-key</label> <label for="pubkey">public-key</label>
<input type="text" id="pubkey" autocomplete="off"> <input type="text" id="pubkey" autocomplete="off">

@ -15,6 +15,7 @@
--focus-outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color); --focus-outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
--font-small: 1.2rem; --font-small: 1.2rem;
--gap: 2.4rem; --gap: 2.4rem;
--gap-half: 1.2rem;
--max-width: 96ch; --max-width: 96ch;
} }

@ -40,10 +40,6 @@ let pubkey = localStorage.getItem('pub_key') || (() => {
return pubkey; return pubkey;
})(); })();
// arbitrary difficulty, still experimenting.
// measured empirically, takes N sec on average to mine a text note event.
const difficulty = 16;
const subList = []; const subList = [];
const unSubAll = () => { const unSubAll = () => {
subList.forEach(sub => sub.unsub()); subList.forEach(sub => sub.unsub());
@ -756,6 +752,23 @@ function hideNewMessage(hide) {
newMessageDiv.hidden = hide; newMessageDiv.hidden = hide;
} }
// arbitrary difficulty default, still experimenting.
let difficulty = JSON.parse(localStorage.getItem('difficutly_target')) ?? 16;
const difficultyTargetInput = document.querySelector('#difficutlyTarget');
difficultyTargetInput.addEventListener('input', (e) => {
localStorage.setItem('difficutly_target', difficultyTargetInput.valueAsNumber);
difficulty = difficultyTargetInput.valueAsNumber;
});
difficultyTargetInput.value = difficulty;
let timeout = JSON.parse(localStorage.getItem('mining_timeout')) ?? 5;
const miningTimeoutInput = document.querySelector('#miningTimeout');
miningTimeoutInput.addEventListener('input', (e) => {
localStorage.setItem('mining_timeout', miningTimeoutInput.valueAsNumber);
timeout = miningTimeoutInput.valueAsNumber;
});
miningTimeoutInput.value = timeout;
async function upvote(eventId, eventPubkey) { async function upvote(eventId, eventPubkey) {
const privatekey = localStorage.getItem('private_key'); const privatekey = localStorage.getItem('private_key');
const note = replyList.find(r => r.id === eventId) || textNoteList.find(n => n.id === (eventId)); const note = replyList.find(r => r.id === eventId) || textNoteList.find(n => n.id === (eventId));
@ -771,7 +784,7 @@ async function upvote(eventId, eventPubkey) {
content: '+', content: '+',
tags, tags,
created_at: Math.floor(Date.now() * 0.001), created_at: Math.floor(Date.now() * 0.001),
}, difficulty, 10).catch(console.warn); }, difficulty, timeout).catch(console.warn);
if (newReaction) { if (newReaction) {
const sig = await signEvent(newReaction, privatekey).catch(console.error); const sig = await signEvent(newReaction, privatekey).catch(console.error);
if (sig) { if (sig) {
@ -810,7 +823,7 @@ writeForm.addEventListener('submit', async (e) => {
pubkey, pubkey,
tags, tags,
created_at: Math.floor(Date.now() * 0.001), created_at: Math.floor(Date.now() * 0.001),
}, difficulty, 10).catch(console.warn); }, difficulty, timeout).catch(console.warn);
if (newEvent) { if (newEvent) {
const sig = await signEvent(newEvent, privatekey).catch(onSendError); const sig = await signEvent(newEvent, privatekey).catch(onSendError);
if (sig) { if (sig) {
@ -954,7 +967,7 @@ profileForm.addEventListener('submit', async (e) => {
content: JSON.stringify(Object.fromEntries(form)), content: JSON.stringify(Object.fromEntries(form)),
tags: [], tags: [],
created_at: Math.floor(Date.now() * 0.001), created_at: Math.floor(Date.now() * 0.001),
}, difficulty, 10).catch(console.warn); }, difficulty, timeout).catch(console.warn);
if (newProfile) { if (newProfile) {
const sig = await signEvent(newProfile, privatekey).catch(console.error); const sig = await signEvent(newProfile, privatekey).catch(console.error);
if (sig) { if (sig) {
@ -1026,8 +1039,12 @@ function validatePow(evt) {
* *
* powEvent returns a rejected promise if the funtion runs for longer than timeout. * powEvent returns a rejected promise if the funtion runs for longer than timeout.
* a zero timeout makes mineEvent run without a time limit. * a zero timeout makes mineEvent run without a time limit.
* a zero difficulty target just resolves the promise without trying to find a 'nonce'.
*/ */
function powEvent(evt, difficulty, timeout = 0) { function powEvent(evt, difficulty, timeout) {
if (difficulty === 0) {
return Promise.resolve(evt);
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const worker = new Worker('./worker.js'); const worker = new Worker('./worker.js');

@ -45,7 +45,7 @@ input[type="radio"]:checked + label {
.tab-content { .tab-content {
max-width: var(--max-width); max-width: var(--max-width);
min-height: 200px; min-height: 200px;
padding: calc(.5 * var(--gap)) 0 100px 0; padding: var(--gap-half) 0 100px 0;
} }
.tabbed { .tabbed {
align-items: start; align-items: start;

Loading…
Cancel
Save