Skip to content

Commit

Permalink
Update to Nimiq PoS Albatross
Browse files Browse the repository at this point in the history
  • Loading branch information
sisou committed Dec 2, 2024
1 parent e24de9a commit 41ae5d6
Show file tree
Hide file tree
Showing 60 changed files with 34,786 additions and 73 deletions.
132 changes: 59 additions & 73 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,121 +3,108 @@
<head>
<meta charset=utf-8 />
<title>Nimiq Demo</title>
<script type="text/javascript" src="https://cdn.nimiq.com/latest/nimiq.js"></script>
<script>
<script type="module">
import * as Nimiq from '/nimiq/web/index.js';

window.Nimiq = Nimiq;

function _onConsensusChanged(state) {
document.getElementById('message').innerText = `Consensus ${state}.`;

if (state === Nimiq.Client.ConsensusState.ESTABLISHED) {
if (state === 'established') {
_updateBalance();
}
}

async function _updateBalance() {
// Get current balance.
const account = await $.client.getAccount($.wallet.address);
const account = await $.client.getAccount($.keypair.toAddress());
_onBalanceChanged(account);
}

function _onBalanceChanged(account) {
console.log(`New balance of ${$.wallet.address.toUserFriendlyAddress()} is ${account.balance}.`);
document.getElementById('balance').innerText = Nimiq.Policy.lunasToCoins(account.balance).toFixed(2);
console.log(`New balance of ${$.keypair.toAddress().toUserFriendlyAddress()} is ${account.balance}.`);
document.getElementById('balance').innerText = (account.balance / 1e5).toFixed(2);
}

async function _onHeadChanged() {
const height = await $.client.getHeadHeight();
console.log(`Now at height ${height}.`);
document.getElementById('height').innerText = height;

// Recheck balance on every head change.
_updateBalance();
// Recheck balance at every macro block (60s).
if (Nimiq.Policy.isMacroBlockAt(height)) {
_updateBalance();
}
}

async function _updatePeerCount() {
const statistics = await $.client.network.getStatistics();
const peerCount = statistics.totalPeerCount;
async function _updatePeerCount(_peerId, _reason, peerCount, _peerInfo) {
// console.log(`Now connected to ${peerCount} peers.`);
document.getElementById('peers').innerText = peerCount;
}

const nimiqInitPromise = new Promise((resolve, reject) => Nimiq.init(resolve, (code) => {
switch (code) {
case Nimiq.ERR_WAIT:
alert('Error: Already open in another tab or window.');
break;
case Nimiq.ERR_UNSUPPORTED:
alert('Error: Browser not supported');
break;
default:
alert('Error: Nimiq initialization error');
break;
}
reject(code);
}));

function init(clientType = 'pico') {
nimiqInitPromise.then(async () => {
document.getElementById('message').innerText = 'Nimiq loaded. Connecting and establishing consensus.';

try {
// Try to connect to the testnet.
Nimiq.GenesisConfig.test();
} catch (error) {
console.error(error);
// Don't fail if GenesisConfig has already been initialized (e.g. for mainnet).
}
const nimiqInitPromise = Nimiq.default().then(() => {
// Create client configuration so it can be manipulated before creating the client.
window.config = new Nimiq.ClientConfiguration();
}).catch(error => {
alert(`Error: ${error.message}`);
throw error;
});

const $ = {};
window.$ = $;
window.init = async function(clientType = 'light') {
await nimiqInitPromise;

// Create client configuration.
const configBuilder = Nimiq.Client.Configuration.builder();
if (clientType === 'light') {
// Adding the Mempool feature triggers a light consensus.
configBuilder.feature(Nimiq.Client.Feature.MEMPOOL);
}
document.getElementById('message').innerText = 'Nimiq loaded. Connecting and establishing consensus.';

// Instantiate the client based on the configuration.
// The client automatically connects to the network when instantiated.
$.client = configBuilder.instantiateClient();

try {
// Get wallet from wallet store.
// The wallet store generates a new wallet (and stores it) when no wallets are stored.
const walletStore = await new Nimiq.WalletStore();
$.wallet = await walletStore.getDefault();
} catch (error) {
// The wallet store accesses IndexedDB, which can fail for all kinds of browser-reasons.
console.error(error);
console.log('Using temporary wallet.')
// Generate a temporary wallet.
$.wallet = await Nimiq.Wallet.generate();
} finally {
document.getElementById('address').innerText = $.wallet.address.toUserFriendlyAddress();
}
const $ = {};
window.$ = $;

// Instantiate the client based on the configuration.
// The client automatically connects to the network when instantiated.
$.client = await Nimiq.Client.create(window.config.build());

$.client.addConsensusChangedListener(_onConsensusChanged);
$.keypair = await Nimiq.KeyPair.generate();
document.getElementById('address').innerText = $.keypair.toAddress().toUserFriendlyAddress();

$.client.addHeadChangedListener(_onHeadChanged);
$.client.addConsensusChangedListener(_onConsensusChanged);

// Update the peer count every 1 second
setInterval(_updatePeerCount, 1000);
});
$.client.addHeadChangedListener(_onHeadChanged);

$.client.addPeerChangedListener(_updatePeerCount);
}

window.mainnet = function() {
window.config.network('mainalbatross');
window.config.seedNodes([
'/dns4/aurora.seed.nimiq.com/tcp/443/wss',
'/dns4/catalyst.seed.nimiq.network/tcp/443/wss',
'/dns4/cipher.seed.nimiq-network.com/tcp/443/wss',
'/dns4/eclipse.seed.nimiq.cloud/tcp/443/wss',
'/dns4/lumina.seed.nimiq.systems/tcp/443/wss',
'/dns4/nebula.seed.nimiq.com/tcp/443/wss',
'/dns4/nexus.seed.nimiq.network/tcp/443/wss',
'/dns4/polaris.seed.nimiq-network.com/tcp/443/wss',
'/dns4/photon.seed.nimiq.cloud/tcp/443/wss',
'/dns4/pulsar.seed.nimiq.systems/tcp/443/wss',
'/dns4/quasar.seed.nimiq.com/tcp/443/wss',
'/dns4/solstice.seed.nimiq.network/tcp/443/wss',
'/dns4/vortex.seed.nimiq.cloud/tcp/443/wss',
'/dns4/zenith.seed.nimiq.systems/tcp/443/wss',
]);
console.log('Configured client for mainnet.');
}
</script>

<!-- Use Nimiq's brand font (regular and bold weights). -->
<link href="https://fonts.googleapis.com/css?family=Muli:400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Mulish:400,700" rel="stylesheet">
</head>
<body>
<h1>Getting started with the Nimiq Client API</h1>
This HTML file demonstrates the most simple way to build web applications on top of the <a target="_blank" href="https://nimiq.com">Nimiq Blockchain</a>.
<h2>Most Simple Client</h2>
<p id="client-selector">
Client type:
<a href="#" client-type="pico">pico</a>
<!-- <a href="#" client-type="pico">pico</a> -->
<a href="#" client-type="light">light</a>
</p>
<div id="client-info" style="display:none">
Expand All @@ -129,13 +116,13 @@ <h2>Most Simple Client</h2>
</div>

<h2>Source Code</h2>
<a target="_blank" href="https://github.com/nimiq-network/nimiq-demo/blob/master/index.html">View Source Code on Github.</a>
<a target="_blank" href="https://github.com/nimiq/nimiq-demo/blob/master/index.html">View Source Code on Github.</a>

<style>
body {
background: #F4F4F4;
color: #1F2348; /* Nimiq Indigo */
font-family: 'Muli', sans-serif;
font-family: 'Mulish', sans-serif;
padding: 6% 8%;
}

Expand All @@ -150,7 +137,6 @@ <h2>Source Code</h2>
el.addEventListener('click', (event) => {
event.preventDefault();
const type = el.getAttribute('client-type');
window.clientType = type;
document.getElementById('client-selector').textContent = 'Client type: ' + type;
document.getElementById('client-info').style.display = 'block';
init(type);
Expand Down
134 changes: 134 additions & 0 deletions nimiq/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Nimiq Albatross Light Client

A very light Nimiq Proof-of-Stake client for browsers and NodeJS, compiled from Rust to WebAssembly.

> **Note**
> This light client is intended to be used in web browsers or NodeJS only (no WASI support either). Other webworker-enabled environments are not yet supported.
## 📦 Installation

You need to install this package from the `next` tag:

```sh
npm install @nimiq/core@next
```

or

```sh
yarn add @nimiq/core@next
```

## 🛠️ Usage

This package contains the WASM file bundled for three [targets](https://rustwasm.github.io/wasm-pack/book/commands/build.html#target): `bundler`, `web` and `node`.

### With Bundlers

If you use any bundler for your project, like Webpack or Vite, you should probably use the `bundler` target exported from the package root. If that doesn't work, or you require the `web` target for your use-case, jump to the [With ES Modules](#with-es-modules) section.

> [!IMPORTANT]
> For Webpack 5:
> - Enable the [`asyncWebAssembly`](https://webpack.js.org/configuration/experiments/#asyncWebAssembly) experiment in your config.
> - Dynamically import the package with `await import()`.
> [!IMPORTANT]
> For Vite:
> - Use the [`vite-plugin-wasm`](https://www.npmjs.com/package/vite-plugin-wasm) plugin.
> - Exclude this package from Vite's dependency optimization:
> ```ts
> // vite.config.ts
> optimizeDeps: {
> exclude: ['@nimiq/core'],
> }
> ```
> [!IMPORTANT]
> For Nuxt:
> - Use the [`vite-plugin-wasm`](https://www.npmjs.com/package/vite-plugin-wasm) plugin.
> - Exclude this package from Vite's dependency optimization:
> ```ts
> // nuxt.config.ts
> vite: {
> optimizeDeps: {
> exclude: ['@nimiq/core'],
> }
> }
> ```
> - Ensure the package is only run client-side: either set [`ssr: false`](https://nuxt.com/docs/guide/concepts/rendering#client-side-rendering) in your Nuxt config, import this package only in client-side plugins, or wrap it in [`<ClientOnly>`](https://nuxt.com/docs/api/components/client-only).
```js
// With Webpack: import the package asynchronously:
const Nimiq = await import('@nimiq/core');
// With Vite, import at the top of your file:
import * as Nimiq from '@nimiq/core';
// Create a configuration builder:
const config = new Nimiq.ClientConfiguration();
// Change the config, if necessary:
// --------------------------------
// Specify the network to use:
// Optional, default is 'testalbatross'
config.network('testalbatross');
// Specify the seed nodes to initially connect to:
// Optional, default is ['/dns4/seed1.pos.nimiq-testnet.com/tcp/8443/wss']
config.seedNodes(['/dns4/seed1.pos.nimiq-testnet.com/tcp/8443/wss']);
// Change the lowest log level that is output to the console:
// Optional, default is 'info'
config.logLevel('debug');
// Instantiate and launch the client:
const client = await Nimiq.Client.create(config.build());
```
### With ES Modules

```js
// Import the loader and package from the /web path:
import init, * as Nimiq from '@nimiq/core/web';

// Load and initialize the WASM file
init().then(() => {
// Create a configuration builder:
const config = new Nimiq.ClientConfiguration();

// Change the config as shown above, if necessary
// ...

// Instantiate and launch the client:
const client = await Nimiq.Client.create(config.build());
});
```

### NodeJS

For NodeJS, this package includes both CommonJS and ESM builds. You can either `require()` the package or `import` it.

```js
// Import as CommonJS module
const Nimiq = require("@nimiq/core");
// Or import as ESM module
import * as Nimiq from "@nimiq/core";

// In ESM modules you can use await at the top-level and do not need an async wrapper function.
async function main() {
// Create a configuration builder:
const config = new Nimiq.ClientConfiguration();

// Change the config as shown above, if necessary
// ...

// Instantiate and launch the client:
const client = await Nimiq.Client.create(config.build());
}
main();
```

## 🐛 Issues, Bugs and Feedback

This is an early version of the client code compiled to WebAssembly and as such there can be problems and friction, especially now that more people try it out in more environments than we could ever test ourselves.

If you encounter issues or you find a bug, please open an issue in our Github at https://github.com/nimiq/core-rs-albatross.

If you want to provide feedback or have questions about the client, our "Nimiq Coders Dojo" Telegram group and the [Community Forum](https://forum.nimiq.community/) are the right places for that.
4 changes: 4 additions & 0 deletions nimiq/bundler/crypto-wasm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import * as wasm from "./index_bg.wasm";
export * from "./index_bg.js";
import { __wbg_set_wasm } from "./index_bg.js";
__wbg_set_wasm(wasm);
Loading

0 comments on commit 41ae5d6

Please sign in to comment.