### Install Dassie Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/guides/quick-start.md Installs Dassie on a Linux server using a provided script. Requires curl and a Linux distribution with systemd. ```sh curl --tlsv1.2 -sSf https://sh.dassie.land | sh ``` -------------------------------- ### Initialize Dassie Configuration Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/guides/quick-start.md Initializes Dassie's configuration, including setting up a TLS certificate using Let's Encrypt integration. This command also outputs the URL for the web setup. ```sh dassie init ``` -------------------------------- ### Start Dassie Development Environment Source: https://github.com/justmoon/dassie/blob/main/README.md Runs the Dassie development environment after dependencies have been installed. ```sh pnpm start ``` -------------------------------- ### View Dassie Logs Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/guides/quick-start.md Retrieves Dassie logs using journalctl, useful for finding the setup URL if it was missed. ```sh journalctl -xeu dassie ``` -------------------------------- ### Uninstall Dassie Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/guides/quick-start.md Uninstalls Dassie from the server using the installation script with the 'uninstall' flag. ```sh curl --tlsv1.2 -sSf https://sh.dassie.land | sh -s -- uninstall ``` -------------------------------- ### Custom Script Generation via HTTP Headers Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/install-command.md This example demonstrates how to pass system information (like `uname`) to the server via HTTP headers when downloading a script. The server can then generate a custom script based on this information. ```sh curl -H "Uname: $(uname -sm)" ... ``` -------------------------------- ### Install Dassie Dependencies Source: https://github.com/justmoon/dassie/blob/main/README.md Enables corepack to use the pnpm package manager and installs all necessary project dependencies. ```sh corepack enable pnpm install ``` -------------------------------- ### Creating a Reactor and Actor Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Demonstrates the basic setup of lib-reactive by creating a root actor and initializing a reactor. The actor logs a message to the console upon creation. ```typescript const RootActor = () => createActor(() => console.log("Hello world")) createReactor(RootActor) ``` -------------------------------- ### Build Dassie Binaries Source: https://github.com/justmoon/dassie/blob/main/README.md Initiates the process of building Dassie binaries using Docker. This command creates a builder Docker image and then executes it. ```sh pnpm build ``` -------------------------------- ### Secure Curl Installation Command Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/install-command.md This command uses `curl` to download an installation script, ensuring only secure TLS versions are used and preventing redirects. It pipes the script directly to `sh` for execution. ```sh curl --tlsv1.2 -sSf https://sh.dassie.land | sh ``` -------------------------------- ### Build Dassie Binaries with Custom Target Source: https://github.com/justmoon/dassie/blob/main/README.md Builds Dassie binaries with a specific build target, such as 'release'. This allows for customized binary creation. ```sh pnpm build release ``` -------------------------------- ### Complete Ping-Pong Example with Multiple Actors Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md A comprehensive example demonstrating a ping-pong communication pattern between three actors (Pinger, Ponger, Logger) using a shared topic. It includes emitting, listening, and timed events. ```ts import { EffectContext, createActor, createReactor, createTopic, } from "@dassie/lib-reactive" const PingPongTopic = () => createTopic() const Pinger = () => createActor((sig) => { sig.on(PingPongTopic, (message) => { if (message === "pong") { sig.reactor.use(PingPongTopic).emit("ping") } }) }) const Ponger = () => createActor((sig) => { sig.on(PingPongTopic, (message) => { if (message === "ping") { sig.timeout(() => { sig.reactor.use(PingPongTopic).emit("pong") }, 75) } }) }) const Logger = () => createActor((sig) => { sig.on(PingPongTopic, console.log) }) const RootActor = () => createActor((sig) => { sig.run(Pinger) sig.run(Ponger) sig.run(Logger) sig.emit(PingPongTopic, "ping") sig.timeout(() => sig.reactor.dispose(), 200) }) createReactor(RootActor) ``` -------------------------------- ### Update Dassie Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/guides/quick-start.md Manually triggers an update for Dassie. Dassie has an auto-updater enabled by default. ```sh sudo dassie update ``` -------------------------------- ### Verify Dassie Release Signature Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/install-command.md This bash script verifies the signature of a Dassie release. It downloads developer keys, compares them, imports them into a temporary keyring, downloads the release checksums and signature, verifies the signature, downloads the release file, and checks its checksum. It includes cleanup steps for temporary files. ```bash #!/bin/bash set -e VERSION="0.0.1" FILENAME="dassie-${VERSION}-linux-x64.tar.xz" KEYRING="./dassie-keyring.gpg" # download the keyfiles curl -s https://keybase.io/dassie/pgp_keys.asc -o keybase.asc curl -s https://dassie.land/pgp_keys.asc -o dassie.asc # compare the keyfiles if ! cmp -s "keybase.asc" "dassie.asc"; then echo "FAILURE: The keys are different." exit 1 fi # import the keys into a temporary keyring gpg --no-default-keyring --keyring ${KEYRING} --import keybase.asc # download SHASUMS256.txt and SHASUMS256.txt.sig curl -s "https://get.dassie.land/${VERSION}/SHASUMS256.txt" -o SHASUMS256.txt curl -s "https://get.dassie.land/${VERSION}/SHASUMS256.txt.sig" -o SHASUMS256.txt.sig # verify the signature if ! gpg --no-default-keyring --keyring ${KEYRING} --verify SHASUMS256.txt.sig SHASUMS256.txt; then echo "FAILURE: The signature is invalid." exit 1 fi # download the file to be verified curl -s "https://get.dassie.land/${VERSION}/${FILENAME}" -o "${FILENAME}" # verify the checksum if ! grep "${FILENAME}" SHASUMS256.txt | sha256sum -c -; then echo "FAILURE: Checksum did not match." exit 1 fi # cleanup rm -f keybase.asc dassie.asc ${KEYRING} SHASUMS256.txt SHASUMS256.txt.sig echo "VERIFIED" ``` -------------------------------- ### Computed Values Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Illustrates the creation and usage of computed values, which are signals that update based on other signals. It includes an example of a counter, a computed doubled value, and actors to log their changes. ```ts import { EffectContext, createActor, createComputed, createReactor, createSignal, } from "@dassie/lib-reactive" const CounterSignal = () => createSignal(0) const DoubledComputed = (reactor: Reactor) => createComputed(reactor, (sig) => { return sig.readAndTrack(CounterSignal) * 2 }) const Clock = () => createActor((sig) => { sig.interval(() => { sig.reactor.use(CounterSignal).update((state) => state + 1) }, 75) }) const Logger = () => createActor((sig) => { const counterValue = sig.readAndTrack(CounterSignal) const doubledValue = sig.readAndTrack(DoubledComputed) console.log(`the counter value is: ${counterValue}`) console.log(`the doubled value is: ${doubledValue}`) } const RootActor = () => createActor((sig) => { sig.run(Clock) sig.run(Logger) sig.timeout(() => void sig.reactor.dispose(), 400) }) createReactor(RootActor)) ``` -------------------------------- ### Self-Validating Shell Script Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/install-command.md This script includes a checksum validation mechanism. It calculates the SHA256 checksum of its own content (excluding the first few lines) and compares it against a predefined checksum to ensure integrity. ```sh #!/bin/bash SCRIPT_CHECKSUM="a24b0f1559e51e0a889191fad61856d94a3b2e49883d084cda123d5d0cb9d7b2" SELF_CHECKSUM=$(tail -n +5 $0 | sha256sum | cut -d' ' -f1) if [ "$SELF_CHECKSUM" != "$SCRIPT_CHECKSUM" ]; then echo "Checksum validation failed! Exiting." exit 1 fi # The rest of the script starts here ``` -------------------------------- ### Inter-Actor Communication with Messaging Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Provides an example of how Dassie actors can communicate with each other using a messaging pattern. The `RootActor` instantiates `PingActor` and `PongActor`, and they exchange messages indefinitely via `tell()` calls. ```ts const RootActor = () => createActor((sig) => { // Instantiate the two actors sig.run(PingActor) sig.run(PongActor) // Get the process started by sending a message to the ping actor sig.reactor.use(PingActor).api.ping.tell() }) const PingActor = () => createActor((sig) => { const pongActor = sig.reactor.use(PongActor) return { ping: () => pongActor.api.pong.tell(), } }) const PongActor = () => createActor((sig) => { const pingActor = sig.reactor.use(PingActor) return { pong: () => { sig.timeout(() => { pingActor.api.ping.tell() }, 75) }, } }) createReactor(RootActor) ``` -------------------------------- ### Create and Emit on a Topic Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Demonstrates how to create a new topic using `createTopic` and emit a message on it from within an actor using `sig.reactor.use().emit()`. ```ts import { createActor, createReactor, createTopic } from "@dassie/lib-reactive" const PingPongTopic = () => createTopic() const RootActor = () => createActor((sig) => { sig.reactor.use(PingPongTopic).emit("ping") }) createReactor(RootActor) ``` -------------------------------- ### Signals as Topics Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Demonstrates how to use signals to subscribe to changes, similar to topics. It shows how to create a signal and an actor that logs changes to that signal. ```ts import { EffectContext, createActor, createReactor, createSignal, } from "@dassie/lib-reactive" const CounterSignal = () => createSignal(0) const Logger = () => createActor((sig) => { sig.on(CounterSignal, (counterValue) => { console.log(`the counter is: ${counterValue}`) }) }) ``` -------------------------------- ### Using Reactor Instances and Context Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Illustrates how to create a reactor and access its instances using the `reactor.use` method. It shows the convention of using camelCase for factories and mixedCase for instances. ```typescript const RootActor = () => createActor(() => console.log("Hello world")) const reactor = createReactor(RootActor) const rootActor = reactor.use(RootActor) ``` -------------------------------- ### Basic Logger Usage Source: https://github.com/justmoon/dassie/blob/main/packages/lib-logger/README.md Demonstrates how to create and use a logger instance from the @dassie/lib-logger library. It shows how to log messages at different levels (debug, info, warn, error) and how to log errors. ```ts import { createLogger } from "@dassie/lib-logger" const logger = createLogger("foo:example:http-server") logger.debug?.("This will print depending on the debug scope") logger.info("This will always print") logger.warn("This will print with some emphasis") logger.error("This will print with maximum emphasis") logger.logError(new Error("This is an example error")) ``` -------------------------------- ### Dassie Protocol Steps Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/token-payment-protocol.md Details the complete protocol flow for Dassie, from initial quote requests to service fulfillment and witness reporting. This includes the interaction between Node A and Node B, and the role of witnesses. ```APIDOC Project: /justmoon/dassie Protocol Steps: 1. Node B requests a quote from Node A for a service (e.g., inclusion in a magazine). - Request includes service description. 2. Node A responds with a quote: - Service description - Price in tokens - Expiry date - Signature over the quote. 3. Node B sends an unfulfillable packet to Node A with an estimated token amount. 4. Node A responds with a rejection indicating the actual price per token. 5. Node B estimates cost per token and calculates total service cost. 6. Node B requests a quote to purchase a token, including a unique public key. 7. Node A responds with a signed quote: - Confirmation of token purchase - Node B's public key - An executionCondition. 8. Node B sends sufficient tokens using the executionCondition. 9. Node A fulfills the packet, making the token valid. 10. Node B repeats steps 6-9 for the required number of tokens. 11. Node B requests Node A to redeem tokens for the service. 12. Node A responds with a signed acknowledgement. 13. If acknowledgement received, stop. Otherwise, proceed to step 14. 14. Node B submits its request to a set of witnesses (W). 15. Witnesses submit the request to Node A, record the response, and return a witness report to Node B: - Witness identity - Current date and time - Submission URL - Request details - Response received - Signature over the witness report. ``` -------------------------------- ### Listen to a Topic with Automatic Cleanup Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Shows how to listen to messages on a topic using `sig.on`, which automatically handles cleanup of the listener when the actor is disposed. ```ts import { createActor, createReactor, createTopic } from "@dassie/lib-reactive" const PingPongTopic = () => createTopic() const RootActor = () => createActor((sig) => { sig.on(PingPongTopic, (message) => { console.log(message) }) }) createReactor(RootActor) ``` -------------------------------- ### Actor Hierarchy with Sub-Actors Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Shows how to create an actor hierarchy by using the `run` method from the `ActorContext` to instantiate subsidiary actors. This demonstrates nested actor creation and execution. ```typescript const RootActor = () => createActor((sig) => console.log("Hello from the root actor") sig.run(subActor) }) const SubActor = () => createActor((sig) => console.log("Hello from the sub actor") ) createReactor(rootActor) ``` -------------------------------- ### Dassie Features Overview Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/index.mdx This section highlights the key features of Dassie, including its scalability, currency-neutrality, and ledger-neutrality. It also mentions that Dassie is still under development. ```html Dassie can handle very large amounts of very small payments and scales horizontally meaning its throughput capacity increases as more nodes join the network. Dassie automatically handles currency exchange and routing. You can use any (supported) currency you like and still transact with everyone else on the Dassie network. The current implementation uses various cryptocurrencies as the underlying value transfer systems, but Dassie is based on [Interledger](https://interledger.org/), which means that it can be used with any payments system with an open API. Dassie is still in the early stages of development and is not yet ready for production use. If you're still interested, [give it a try](/guides/quick-start/). ``` -------------------------------- ### Create and Use a Signal with Update Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Illustrates how to create a signal using `createSignal` and modify its state using the `update` method with a reducer function. Actors can read signals using `sig.readAndTrack`. ```ts import { EffectContext, createActor, createReactor, createSignal, } from "@dassie/lib-reactive" const CounterSignal = () => createSignal(0) const Clock = () => createActor((sig) => { sig.interval(() => { sig.reactor.use(CounterSignal).update((state) => state + 1) }, 75) }) const Logger = () => createActor((sig) => { const counterValue = sig.readAndTrack(CounterSignal) console.log(`the counter is: ${counterValue}`) }) const RootActor = () => createActor((sig) => { sig.run(Clock) sig.run(Logger) sig.timeout(() => void sig.reactor.dispose(), 400) }) createReactor(RootActor) ``` -------------------------------- ### Consolidating Shutdown Logic with sig.timeout Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Demonstrates how to manage application shutdown timers within the actor system using `sig.timeout`. This ensures that all cleanup logic is handled consistently when the reactor is disposed, preventing issues with multiple disposal triggers. ```ts const RootActor = () => createActor((sig) => { sig.interval(() => console.log("tick!"), 100) sig.timeout(() => { console.log("exiting after one second") reactor.dispose() }, 1000) sig.timeout(() => { console.log("exiting after a random amount of time") reactor.dispose() }, 2000 * Math.random()) }) createReactor(RootActor) ``` -------------------------------- ### Actor Cleanup with sig.interval Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Shows a simplified approach to actor cleanup using the built-in `sig.interval` helper. This method automatically handles the disposal of the interval when the actor is disposed, reducing boilerplate code. ```ts const RootActor = () => createActor((sig) => { sig.interval(() => console.log("tick!"), 100) }) const reactor = createReactor(RootActor) setTimeout(() => reactor.dispose(), 1000) ``` -------------------------------- ### Actor Cleanup with onCleanup Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Demonstrates how to manually register a cleanup callback using `sig.onCleanup` to clear an interval when an actor is disposed. This is useful for managing resources like timers or event listeners. ```ts const RootActor = () => createActor((sig) => { const interval = setInterval(() => console.log("tick!"), 100) sig.onCleanup(() => clearInterval(interval)) }) const reactor = createReactor(RootActor) setTimeout(() => reactor.dispose(), 1000) ``` -------------------------------- ### Basic OER Schema and Parsing Source: https://github.com/justmoon/dassie/blob/main/packages/lib-oer/README.md Demonstrates how to define a schema for a 'Person' object using sequence, utf8String, and uint8Number, and then parse a Uint8Array against this schema. It shows how to infer the TypeScript type from the schema and handle parsing results. ```typescript import { Infer, sequence, uint8Number, utf8String } from "@dassie/lib-oer" const personSchema = sequence({ name: utf8String(), age: uint8Number(), }) type Person = Infer const result = personSchema.parse(uint8ArrayContainingPerson) if (result.success) { const person: Person = result.value } else { console.error("Parsing failed:", result.toString()) } ``` -------------------------------- ### Batching Signal Updates Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Demonstrates batching of signal updates. Multiple signal updates within the same tick result in a single re-computation of dependent values, as shown by an actor logging batched updates. ```ts import { EffectContext, createActor, createReactor, createTopic, } from "@dassie/lib-reactive" const Signal1 = () => createSignal(0) const Signal2 = () => createSignal(0) const Signal3 = () => createSignal(0) const Logger = () => createActor((sig) => { const t1 = sig.readAndTrack(Signal1) const t2 = sig.readAndTrack(Signal2) const t3 = sig.readAndTrack(Signal3) console.log(`actor run with ${t1} ${t2} ${t3}`) }) const RootActor = () => createActor((sig) => { sig.interval(() => { // Even though we are triggering three state updates, the actor will only re-run once sig.reactor.use(Signal1).update((a) => a + 1) sig.reactor.use(Signal2).update((a) => a + 3) sig.reactor.use(Signal3).update((a) => a + 5) }, 1000) sig.run(Logger) // Stop the application after 10 seconds sig.timeout(sig.reactor.dispose, 10_000) }) createReactor(RootActor) ``` -------------------------------- ### Dassie Tip Source: https://github.com/justmoon/dassie/blob/main/packages/app-website/src/content/docs/index.mdx A helpful tip indicating that Dassie is not a blockchain and explaining its payment routing mechanism. ```astro ``` -------------------------------- ### Dassie Protocol Attack Vector: Denial of Service Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/token-payment-protocol.md Describes a denial of service attack scenario where Node A appears dishonest due to inaccessibility during the protocol's submission phase. It also outlines mitigation strategies. ```APIDOC Attack Vector: Denial of service Description: Node A can be perceived as dishonest if it is under a denial of service (DoS) attack during the protocol's submission phase. If witnesses cannot reach Node A, it may appear as malicious non-responsiveness. Mitigation: - Implement standard DoS mitigations (scope beyond this article). - Utilize generous deadlines to require attackers to sustain the attack for longer periods. For example, a week-long deadline allows witnesses to retry requests hourly, increasing the chance of eventual success. ``` -------------------------------- ### Handling Multiple Disposal Triggers Source: https://github.com/justmoon/dassie/blob/main/packages/lib-reactive/README.md Illustrates a scenario where multiple timeouts could trigger actor disposal, leading to potential race conditions or unintended behavior. It highlights the importance of containing application shutdown logic within the actor system. ```ts const RootActor = () => createActor((sig) => { sig.interval(() => console.log("tick!"), 100) }) const reactor = createReactor(RootActor) setTimeout(() => { console.log("exiting after one second") reactor.dispose() }, 1000) setTimeout(() => { console.log("exiting after a random amount of time") reactor.dispose() }, 2000 * Math.random()) ``` -------------------------------- ### Settlement from Peer Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/internal-ledger.md Shows the accounting transfers for a settlement process initiated by a peer (A). It involves debiting the settlement asset account and crediting the interledger asset account for that peer. ```text Transfer 1: Dr. xrp:assets/settlement Cr. xrp:assets/interledger/peerA ``` -------------------------------- ### Interledger Payment (Same Currency) Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/internal-ledger.md Illustrates the accounting transfers for an interledger payment between two peers (A and B) when the same currency is used. It shows debits and credits for interledger accounts and revenue for fees. ```text Transfer 1: Dr. xrp:assets/interledger/peerA Cr. xrp:assets/interledger/peerB Transfer 2: Dr. xrp:liabilities/peerA/interledger Cr. xrp:revenue/fees ``` -------------------------------- ### Content Security Policy for XSS Prevention Source: https://github.com/justmoon/dassie/blob/main/docs/implementation-notes/frontend-security.md A Content Security Policy (CSP) can be implemented in the Dassie frontend to mitigate security risks such as cross-site scripting (XSS) attacks by defining which resources the browser is allowed to load. ```markdown The Dassie frontend could benefit from a Content Security Policy to prevent some types of attacks like cross-site scripting (XSS). ```