Skip to content

Commit

Permalink
fix: formatting (#29)
Browse files Browse the repository at this point in the history
The markdown renderer does not like code blocks in bullet lists. Also only a double newline starts a new paragraph, so there were countless instances where text on the next line had been hoisted to the previous.
  • Loading branch information
alanshaw authored Nov 15, 2024
1 parent 912c819 commit 14b9e17
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 32 deletions.
6 changes: 3 additions & 3 deletions problems/1-space-out/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ In this exercise your challenge is to setup a space where you can upload data to

Yes - each space has a DID as well!

Anyway, lets get started. Create a _new_ file for your solution e.g. `ex2.mjs`. Import the w3up library and create the client as before. Now, you need to create a space - a place you can upload data to...but wait, there's a catch. To make your space usable, you need to "provision" it. There's two options here. You can provision it with your account _or_ you can redeem a coupon. If you don't have a coupon or are unsure what to do, choose option 1.
Anyway, lets get started. Create a _new_ file for your solution e.g. `ex2.mjs`. Import the w3up library and create the client as before. Now, you need to create a space - a place you can upload data to...but wait, there's a catch. To make your space usable, you need to "provision" it. There's two options here. You can provision it with your account OR you can redeem a coupon. If you don't have a coupon or are unsure what to do, choose option 1.

## 1. Create a space and provision it using your own account.
**1. Create a space and provision it using your own account.**

First, login to your account:

Expand All @@ -38,7 +38,7 @@ Finally, log the DID of the space, for verification:
console.log(space.did())
```

## 2. Create a space and provision it with a coupon.
**2. Create a space and provision it with a coupon.**

```js
const space = await client.createSpace('my space')
Expand Down
10 changes: 10 additions & 0 deletions problems/2-cat-memes/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,37 @@ On the third web, you hash your content first. This means the hash you generate
Download a meme locally (or use the one that you already have!), upload them to web3.storage, and print out their unique CID (Content Identifier). Once you downloaded the last meme your friend sent you, continue with:

**1. Create a New File**

Create a _new_ file, like `ex3.mjs`.

**2. Import w3up and create the client**

Import the w3up library and create the client as before.

**3. Install the `files-from-path` module**

It helps read files from your local file system and transforms file paths into a format that can be uploaded to web3.storage. Without this module, you’d be stuck doing all the heavy lifting of file reading and formatting - who has time for that in this economy?
Install `npm install files-from-path` and import:

```js
import { filesFromPaths } from 'files-from-path'
```
**4. Upload the meme**

Specify the path to the meme:

```js
const files = await filesFromPaths(['path-to-your-meme'])
```

and upload it with using the client's `uploadDirectory` function:

```js
const root = await client.uploadDirectory(files)
```

Finally, print the CID:

```js
console.log(root.toString())
```
Expand Down
32 changes: 25 additions & 7 deletions problems/3-delegation/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ Excellent cat memes. Well done you.

Now, lets talk UCAN.

**What are UCANs?**
## What are UCANs?

UCANs (User Controlled Authorization Networks) are like supercharged passwords. They’re used for secure, decentralized authorization. When you create a UCAN, you sign it with your private key, kind of like signing a document with your unique signature.

**Why are UCANs cool?**
## Why are UCANs cool?

The best thing about UCANs is that you can securely give permission to others to do things on your behalf without sharing your private key. This is called "delegation".

**Your Mission**
## Your Mission

In this exercise, you're going to delegate an `upload/list` capability to the workshop. The workshop will create its own private key and pass its public key (DID) to you via `stdin` (standard input).

Your program should read from `process.stdin`, create a delegation for the `upload/list` capability and write it to `process.stdout`. So, something like this:
Expand All @@ -23,30 +26,40 @@ Then the workshop will be able to **invoke** the capability to list the items _y

One last thing, make sure the delegation remains valid for **more than one hour**.


**Steps to complete the task**

**1. Create new file and read a DID from `stdin`**

Create new file, like `ex4.mjs` and then you can read and parse the DID from `process.stdin`:

```js
import fs from 'node:fs'
import * as DID from '@ipld/dag-ucan/did'

const data = fs.readFileSync(process.stdin.fd, 'utf-8')
const principal = DID.parse(data)
```

**2. Create the delegetion**

Use the client to create a delegation for `upload/list` to the provided DID:

```js
import * as Client from '@web3-storage/w3up-client'
```

Create the client and set the expiration time for the delegation:

```js
const client = await Client.create()
const twoHours = 1000 * 60 * 60 * 2 // Two hours in milliseconds
```
In the example above, it is set to two hours.

**3. Generate the delegation**

Create the delegation for the `upload/list` capability:

```js
const delegation = await client.createDelegation(principal, ['upload/list'], {
// Expiration is in seconds from Unix epoch
Expand All @@ -55,7 +68,9 @@ const delegation = await client.createDelegation(principal, ['upload/list'], {
```

**4. Archive the delegation**

Archive the delegation and handle any errors:

```js
const { ok: archive, error } = await delegation.archive()
if (!archive) {
Expand All @@ -64,10 +79,13 @@ if (!archive) {
```

**5. Output the delegation**

Write the delegation to `process.stdout`:
```js
process.stdout.write(archive)
```

```js
process.stdout.write(archive)
```

─────────────────────────────────────────────────────────────────────────────
* To print these instructions again, run: `$ADVENTURE_NAME print`
* To verify your program, run: `$ADVENTURE_NAME verify ex4.mjs`
Expand Down
29 changes: 23 additions & 6 deletions problems/4-infinite-compression/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,57 @@
YAS BOSS! That's how you do it!

## What’s the Deal with Content Addressing?

So, here’s the scoop: when you upload data to web3.storage, it gets transformed into a **Directed Acyclic Graph (DAG)**. Each piece of your data becomes a node, and each node gets a unique identifier called a **Content Identifier (CID)**. This whole DAG is then packed into a Content-Addressed Archive (CAR)—think of it like a digital suitcase for your data, ready to travel the web.

## How It Works:

When you upload a file, it’s broken down into smaller pieces called **CAR shards**. Each shard gets its own CID, making it easy to identify and retrieve.
After all the shards are uploaded, they come together to form the full DAG, with a root CID that ties everything together.

Here’s the best part: If the system already has the data you’re trying to upload, it’ll tell you so. No need to send the data again! It’s like magic—data management on autopilot! 🚗✨

## Your Task:
1. Start by creating a new file, like `ex5.mjs`.
2. Upload Content: You’ll upload a file—maybe another cat meme—just like you did before. But this time, the file gets split into multiple shards.

**1. Start by creating a new file, like `ex5.mjs`.**

**2. Upload Content**

You’ll upload a file—maybe another cat meme—just like you did before. But this time, the file gets split into multiple shards.

```js
const client = await Client.create()
const files = await filesFromPaths(['./awesome-cat-meme.jpg'])
```
3. Print Each Shard’s CID: As each shard is stored, you’ll print out its CID. Think of these as the pieces of your compression puzzle.

**3. Print Each Shard’s CID**

As each shard is stored, you’ll print out its CID. Think of these as the pieces of your compression puzzle.

```js
const root = await client.uploadDirectory(files, {
onShardStored: shard => console.log(shard.cid.toString())
})
```
4. Reveal the DAG Root: After all the shards are uploaded, print the CID of the root of the DAG. This is the final piece that ties everything together.

**4. Reveal the DAG Root**

After all the shards are uploaded, print the CID of the root of the DAG. This is the final piece that ties everything together.

```js
console.log(root.toString())
```

## Why It’s Awesome:

**Efficiency:** You’re not just uploading data—you’re breaking it down and managing it in a super-efficient way.

**Organization:** The DAG structure helps keep your data neatly organized, and the CIDs act as a digital map to navigate it all.

** No Redundant Uploads:** Thanks to content addressing, if the data already exists, you don’t need to send it again—saving time and bandwidth.

**No Redundant Uploads:** Thanks to content addressing, if the data already exists, you don’t need to send it again—saving time and bandwidth.

## Next Steps:

**1. Run the Code:** Try running your code to see the CIDs of each shard and the final DAG root.

**2. Explore Further:** Think about how this structure could be used in larger projects or how you might expand on it.
Expand Down
34 changes: 29 additions & 5 deletions problems/5-memes/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,70 @@
Ain't you cool? Now, let's shift gears and dive into the next challenge: retrieving content from a decentralized network.

## The Challenge:

Every meme (or any other file) you upload is instantly available for retrieval. In this exercise, your task is to fetch a text file from a public gateway using its root CID. The cool part? You can use any gateway, thanks to the decentralized nature of peer-to-peer networking. But for simplicity, we’ll use the `w3s.link` gateway.

## What You Need to Do:
1. Start by creating a new JavaScript file, ex6.mjs.

2. Fetch the CID from `stdin`: The CID (Content Identifier) of the file you need to fetch will be provided via `process.stdin`. You’ll need to read this input first.
**1. Start by creating a new JavaScript file, ex6.mjs.**

**2. Fetch the CID from `stdin`**

The CID (Content Identifier) of the file you need to fetch will be provided via `process.stdin`. You’ll need to read this input first.

```js
import fs from 'node:fs'
import { CID } from 'multiformats'

const cid = CID.decode(fs.readFileSync(process.stdin.fd))
```
3. Construct the Gateway URL: Format the URL to fetch the content using the `w3s.link` gateway. The URL format is:

**3. Construct the Gateway URL**

Format the URL to fetch the content using the `w3s.link` gateway. The URL format is:

```js
https://w3s.link/ipfs/<CID>
```

Replace <CID> with the actual CID you decoded.

```js
const url = `https://w3s.link/ipfs/${cid}`
```
4. Fetch the Content: Use the fetch API to send an HTTP request to the gateway and retrieve the data.

**4. Fetch the Content**

Use the fetch API to send an HTTP request to the gateway and retrieve the data.

```js
const res = await fetch(url)
```
5. Output the Content: Finally, write the fetched content directly to `process.stdout`.

**5. Output the Content**

Finally, write the fetched content directly to `process.stdout`.

```js
process.stdout.write(await res.text())
```

## What’s Happening Here?

**CID Decoding:** The CID you receive is in a compact binary form. You use the multiformats library to decode it into a human-readable string that you can use in the URL.

**Gateway Flexibility:** We use w3s.link here, but you can use any IPFS gateway.

**Real-time Retrieval:** Once you have the CID, fetching content from a decentralized network is as simple as sending a request to a URL.

## Why This is Cool:

This challenge shows you how easy it is to retrieve content from a decentralized network. It’s like pulling a meme out of thin air—instant access, no matter where the file is stored on the network.

Now, create that `ex6.mjs` file, plug in your code, and see how seamlessly you can fetch content from the decentralized web. Happy coding! 🚀

**Next Steps:**

- Try fetching different types of content by changing the CID.
- Explore how different gateways work and compare their performance.

Expand Down
38 changes: 32 additions & 6 deletions problems/6-dude-where/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,46 @@
Alright, you’ve made it this far, so let’s take things up a notch. We’ve talked about CAR files before, but now we’re going to really dig into them. Your task? Re-assemble a CAR file into a file, but do it trustlessly—meaning you don’t just take what you get; you verify it.

## The Challenge:

A CAR file contains a DAG—a graph of nodes that represent your data. When you fetch data over HTTP, it’s all nice and tidy, but there’s a catch: you can’t just trust the bytes you receive. You need to verify that what you got actually matches the CID you were expecting. This means re-assembling the data into its original DAG structure and making sure everything checks out.

## What You Need to Do:
1. Yes, you guessed it - file number 7 - `ex7.mjs`, for this challenge.
2. Install Necessary Libraries: You’ll need two libraries to get this done: `@ipld/car` for reading CAR files and `ipfs-unixfs-exporter` for exporting files from an IPFS DAG.

**1. Yes, you guessed it - file number 7 - `ex7.mjs`, for this challenge.**

**2. Install Necessary Libraries**

You’ll need two libraries to get this done: `@ipld/car` for reading CAR files and `ipfs-unixfs-exporter` for exporting files from an IPFS DAG.

```js
npm install @ipld/car
npm install ipfs-unixfs-exporter
```
3. Fetch the CAR File: You’ll be fetching a CAR file from the web3.storage trustless gateway. The CID for the directory containing the file you want is `bafybeifdnnn35jnwel2dno7hu7zfew6gtxhkaynaszuj4i77j4m7wsv72a`, and the specific file to extract is `/cat2.txt`.

**3. Fetch the CAR File**

You’ll be fetching a CAR file from the web3.storage trustless gateway. The CID for the directory containing the file you want is `bafybeifdnnn35jnwel2dno7hu7zfew6gtxhkaynaszuj4i77j4m7wsv72a`, and the specific file to extract is `/cat2.txt`.

```js
const cid = 'bafybeifdnnn35jnwel2dno7hu7zfew6gtxhkaynaszuj4i77j4m7wsv72a'
const path = '/cat2.txt'

const res = await fetch(`https://dag.w3s.link/ipfs/${cid}?format=car`)
const bytes = new Uint8Array(await res.arrayBuffer())
```
4. Read the CAR File: Use CarReader from `@ipld/car` to read the CAR file. This step is crucial because you need to adapt this reader to work with the exporter from `ipfs-unixfs-exporter`.

**4. Read the CAR File**

Use CarReader from `@ipld/car` to read the CAR file. This step is crucial because you need to adapt this reader to work with the exporter from `ipfs-unixfs-exporter`.

```js
const reader = await CarReader.fromBytes(bytes)
```
5. Create an Adapter: You’ll need to create a simple adapter that allows the exporter to pull data from your CAR reader. This adapter will fetch the blocks (nodes) as needed during the re-assembly process.

**5. Create an Adapter**

You’ll need to create a simple adapter that allows the exporter to pull data from your CAR reader. This adapter will fetch the blocks (nodes) as needed during the re-assembly process.

```js
const entry = await exporter(`${cid}${path}`, {
async get (cid) {
Expand All @@ -34,22 +52,30 @@ const entry = await exporter(`${cid}${path}`, {
}
})
```
6. Re-assemble and Output: Finally, you’ll re-assemble the file from the DAG and output it directly to the console.

**6. Re-assemble and Output**

Finally, you’ll re-assemble the file from the DAG and output it directly to the console.

```js
import { Readable } from 'node:stream'
Readable.from(entry.content()).pipe(process.stdout)
```

## What’s Happening Here?

- **Trustless Verification:** You’re not just taking the data as-is; you’re verifying that the nodes of the DAG match the expected structure and hashes.
- **Re-assembly:** The client (your code) re-assembles the file from the DAG, ensuring that the file you get matches the original content.
- **Flexibility:** By adapting the CAR reader to work with the exporter, you gain the flexibility to handle data more securely and efficiently.

## Why It’s Important:

This challenge teaches you the importance of trustless systems in decentralized environments. You’re learning how to verify data integrity independently, which is crucial in a world where trust can be a luxury.

Now, go ahead and build that ex7.mjs file, fetch your CAR, and make sure everything checks out. Happy coding! 🚗🔍

**Next Steps:**

Experiment with different CAR files and paths to deepen your understanding.
Think about how this process could be automated or expanded for larger datasets.

Expand Down
Loading

0 comments on commit 14b9e17

Please sign in to comment.