Skip to content

Commit

Permalink
hello world (x2)
Browse files Browse the repository at this point in the history
  • Loading branch information
dskvr committed Sep 14, 2024
1 parent 94fcdbc commit 421d03a
Show file tree
Hide file tree
Showing 12 changed files with 496 additions and 242 deletions.
57 changes: 57 additions & 0 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: deploy demo to gh pages
on:
push:
branches: ["master"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Delete demo/pkg symlink
run: rm -fr demo/pkg

- name: Setup Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
target: wasm32-unknown-unknown

- uses: qmaru/[email protected]
with:
version: 'latest'

- name: Build with wasm-pack
run: |
export RUSTFLAGS="-C target-feature=+simd128"
wasm-pack build --target web --release
- name: Prepare Demo Directory
run: mkdir -p demo/pkg

- name: Copy Build Artifacts to Demo
run: cp -r pkg/* demo/pkg/

- name: Setup GitHub Pages
uses: actions/configure-pages@v5

- name: Upload Pages Artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'demo'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
nostr_miner
pkg
notemine
target

./pkg
!./demo/pkg
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions cargo.toml → Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "nostr_miner"
name = "notemine"
version = "0.1.0"
edition = "2021"
description = "A Nostr event miner compiled to WebAssembly"
repository = "https://github.com/yourusername/nostr_miner" # Replace with your repository URL
repository = "https://github.com/sandwichfarm/notemine"
license = "MIT" # Choose an appropriate license

[lib]
Expand All @@ -19,3 +19,8 @@ js-sys = "0.3"
web-sys = { version = "0.3", features = ["console"] }
serde-wasm-bindgen = "0.6" # Added serde-wasm-bindgen
console_error_panic_hook = "0.1.6" # Added for better error reporting

[profile.release]
opt-level = "z" # Optimize for size; alternatively, use "s" for size or "3" for speed
lto = true
codegen-units = 1
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ⛏️ notemine
A wasm miner for nostr events. Variable difficulty and realtime hashrate. See web [demo](https://sandwichfarm.github.io/notemine-wasm) or build it yourself.

# deps
```
cargo install wasm-pack
```

# build
```
cargo clean
RUSTFLAGS="-C target-feature=+simd128" wasm-pack build --target web --release
```

# use demo
```
cd demo && npx serve
```

# license
public domain.
90 changes: 90 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>⛏️ notemine</title>
<style>

body {
font-family: Arial, sans-serif;
margin: 20px;
}
textarea {
width: 100%;
max-width: 600px;
}
input[type="number"] {
width: 100px;
}
button {
padding: 10px 20px;
font-size: 16px;
}
pre {
background-color: #f4f4f4;
padding: 10px;
max-width: 600px;
overflow-x: auto;
}

code {
font-size: 30px;
}
</style>

<!-- Include NostrTools library -->
<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
</head>
<body>
<h1><code>⛏️ notemine</code></h1>

<p>this is a demo of notemine, a wasm nostr note miner written in rust. </p>

<!-- Optional: Button for Nostr authentication -->
<button
data-npub="npub1uac67zc9er54ln0kl6e4qp2y6ta3enfcg7ywnayshvlw9r5w6ehsqq99rx"
data-relays="wss://relay.damus.io,wss://relay.snort.social,wss://nos.lol,wss://nostr.fmt.wiz.biz,wss://nostr.mutinywallet.com,wss://nostr.mywire.org,wss://relay.primal.net"
style="inline-block"
>
⚡️ zap me
</button>

<button
onclick="document.location.href='https://njump.me/nprofile1qythwumn8ghj7un9d3shjtnswf5k6ctv9ehx2ap0qy88wumn8ghj7mn0wvhxcmmv9uq3samnwvaz7tmwdaehgu3wvekhgtnhd9azucnf0ghsqg88wxhskpwga90umah7kdgq23xjlvwv6wz83r5lfy9m8m3garkkdusz5s2r'"
style="display: inline-block; cursor: pointer;"
>
🍻 follow
</button>

<button
onclick="document.location.href='https://github.com/sandwichfarm/minnote-wasm'"
style="display: inline-block; cursor: pointer;"
>
📦️ git
</button>

<br/><br/>

<textarea id="eventInput" rows="10" placeholder="Enter event content here"></textarea>
<br><br>

<label for="difficulty">Difficulty:</label>
<input type="number" id="difficulty" value="21" min="1">
<br><br>

<button id="mineButton" disabled>Mine & Publish</button>

<h2>Hash Rate:</h2>
<pre id="hashrate">0 H/s</pre>
<h2>Result:</h2>
<pre id="result">Waiting for worker to initialize...</pre>

<code id="relayStatus"></code>

<button id="cancelButton" disabled>Cancel Mining</button>

<!-- Include main.js as a module -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script type="module" src="main.js"></script>
</body>
</html>
156 changes: 156 additions & 0 deletions demo/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
let minedEvent = {}

//conf
const CLIENT = 'notemine'
const TOPIC = 'notemine'
const RELAYS = ['wss://nostr.bitcoiner.social', 'wss://nostr.bitcoiner.social', 'wss://nostr.mom', 'wss://nos.lol', 'wss://powrelay.xyz', 'wss://powrelay.xyz', 'wss://labour.fiatjaf.com/', 'wss://nostr.lu.ke', 'wss://140.f7z.io']

const Relay = window.NostrTools.Relay
const SimplePool = window.NostrTools.SimplePool

//anon user
const secret = window.NostrTools.generateSecretKey();
const pubkey = window.NostrTools.getPublicKey(secret)

const pool = new SimplePool()
let pubs = []

//worker
const worker = new Worker('./worker.js', { type: 'module' });

//dom
const mineButton = document.getElementById('mineButton');
const eventInput = document.getElementById('eventInput');
const difficultyInput = document.getElementById('difficulty');
const resultOutput = document.getElementById('result');
const hashrateOutput = document.getElementById('hashrate');
const cancelButton = document.getElementById('cancelButton');
const relayStatus = document.getElementById('relayStatus');

let isWorkerReady = false;

const MOVING_AVERAGE_WINDOW = 5;
let recentHashRates = [];

worker.onmessage = function (e) {
const { type, data, error, hashCount, elapsedTime } = e.data;

if (type === 'progress') {
recentHashRates.push(hashCount / elapsedTime);
if (recentHashRates.length > MOVING_AVERAGE_WINDOW) {
recentHashRates.shift();
}
const averageHashRate = recentHashRates.reduce((a, b) => a + b, 0) / recentHashRates.length;
hashrateOutput.textContent = `${(averageHashRate/1000).toFixed(2)} kH/s`;
} else if (type === 'ready') {
isWorkerReady = true;
console.log('Worker is ready.');
mineButton.disabled = false;
resultOutput.textContent = 'Worker is ready. You can start mining.';
} else if (type === 'result') {
if (data.error) {
resultOutput.textContent = `Error: ${data.error}`;
} else {
try {
resultOutput.textContent = JSON.stringify(data, null, 2);
publishEvent(data.event);
} catch (e) {
console.error('Error publishing event:', e);
resultOutput.textContent = `Error publishing event: ${e.message}`;
}
}
hashrateOutput.textContent = '0 H/s';
mineButton.disabled = false;
} else if (type === 'error') {
resultOutput.textContent = `Error: ${error}`;
hashrateOutput.textContent = '0 H/s';
mineButton.disabled = false;
}
};

mineButton.addEventListener('click', () => {
const content = eventInput.value.trim();
const nostrEvent = generateEvent(content);
const difficulty = parseInt(difficultyInput.value, 10);

if (!content) {
alert('Please enter content for the Nostr event.');
return;
}

if (isNaN(difficulty) || difficulty <= 0) {
alert('Please enter a valid difficulty.');
return;
}

if (!isWorkerReady) {
alert('Worker is not ready yet. Please wait.');
return;
}

const event = JSON.stringify(nostrEvent);

mineButton.disabled = true;
resultOutput.textContent = 'Mining in progress...';
hashrateOutput.textContent = '0 H/s';

worker.postMessage({
type: 'mine',
event,
difficulty: difficulty,
});
});

cancelButton.addEventListener('click', () => {
if (isWorkerReady) {
worker.postMessage({ type: 'cancel' });
resultOutput.textContent = 'Mining cancellation requested.';
hashrateOutput.textContent = '0 H/s';
mineButton.disabled = false;
}
});


const generateEvent = (content) => {
return {
pubkey,
kind: 1,
tags: [['t', TOPIC], ['client', CLIENT]],
content,
}
}

const publishEvent = async (ev) => {
console.log('Publishing event:', ev);
try {
ev = window.NostrTools.finalizeEvent(ev, secret);
let isGood = window.NostrTools.verifyEvent(ev);
if (!isGood) throw new Error('Event is not valid');
pubs = pool.publish(RELAYS, ev);
await Promise.allSettled(pubs);
showRelayStatus()
console.log('Event published successfully.');
} catch (error) {
console.error('Error publishing event:', error);
resultOutput.textContent = `Error publishing event: ${error.message}`;
}
};

const showRelayStatus = () => {
const settled = Array(pubs.length).fill(false);
const intervalId = setInterval(() => {
settledCount = settled.filter(Boolean).length;
relayStatus.textContent = `Published to ${settledCount}/${pubs.length} relays.`
if (settledCount === pubs.length) {
clearInterval(intervalId);
}
}, 100);

pubs.forEach((pub, index) => {
pub.finally(() => {
relayStatus.textContent = `Published to all relays [${RELAYS.join(', ')}]`
settled[index] = true;
});
});

}
1 change: 1 addition & 0 deletions demo/pkg
Loading

0 comments on commit 421d03a

Please sign in to comment.