nip-13: add settings for target difficulty and timeout
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details

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 8683435957
commit 18c0dc62a6
Signed by: offbyn
GPG Key ID: 94A2F643C51F37FA

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

@ -43,6 +43,7 @@ label {
transition: background-color var(--transition-duration);
}
input[type="number"],
input[type="password"],
input[type="text"],
input[type="url"],
@ -54,6 +55,7 @@ textarea {
margin: 0 0 1.2rem 0;
padding: var(--padding);
}
input[type="number"]:focus,
input[type="password"]:focus,
input[type="text"]:focus,
input[type="url"]:focus,
@ -169,11 +171,13 @@ button:disabled {
margin-left: var(--gap);
}
.form-inline button,
.form-inline input[type="number"],
.form-inline input[type="text"],
.form-inline textarea {
margin: .4rem 0;
}
.form-inline input[type="number"],
.form-inline input[type="text"],
.form-inline textarea {
flex-basis: 50%;
@ -187,6 +191,46 @@ button:disabled {
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 {
align-self: end;
order: 2;

@ -83,6 +83,27 @@
<button type="submit" name="publish" tabindex="0" disabled>publish</button>
</div>
</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">
<label for="pubkey">public-key</label>
<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);
--font-small: 1.2rem;
--gap: 2.4rem;
--gap-half: 1.2rem;
--max-width: 96ch;
}

@ -41,10 +41,6 @@ let pubkey = localStorage.getItem('pub_key') || (() => {
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 unSubAll = () => {
subList.forEach(sub => sub.unsub());
@ -767,6 +763,23 @@ function hideNewMessage(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, relay) {
const privatekey = localStorage.getItem('private_key');
const newReaction = await powEvent({
@ -775,7 +788,7 @@ async function upvote(eventId, relay) {
content: '+',
tags: [['e', eventId, relay, 'reply']],
created_at: Math.floor(Date.now() * 0.001),
}, difficulty, 10).catch(console.warn);
}, difficulty, timeout).catch(console.warn);
if (newReaction) {
const sig = await signEvent(newReaction, privatekey).catch(console.error);
if (sig) {
@ -814,7 +827,7 @@ writeForm.addEventListener('submit', async (e) => {
pubkey,
tags,
created_at: Math.floor(Date.now() * 0.001),
}, difficulty, 10).catch(console.warn);
}, difficulty, timeout).catch(console.warn);
if (newEvent) {
const sig = await signEvent(newEvent, privatekey).catch(onSendError);
if (sig) {
@ -958,7 +971,7 @@ profileForm.addEventListener('submit', async (e) => {
content: JSON.stringify(Object.fromEntries(form)),
tags: [],
created_at: Math.floor(Date.now() * 0.001),
}, difficulty, 10).catch(console.warn);
}, difficulty, timeout).catch(console.warn);
if (newProfile) {
const sig = await signEvent(newProfile, privatekey).catch(console.error);
if (sig) {
@ -1030,8 +1043,12 @@ function validatePow(evt) {
*
* 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 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) => {
const worker = new Worker('./worker.js');

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

Loading…
Cancel
Save