Skip to content

Commit

Permalink
Merge pull request #21 from hakierka/amy-wip
Browse files Browse the repository at this point in the history
Problems - copy updates
  • Loading branch information
hakierka authored Aug 15, 2024
2 parents 269ef09 + 6041ce0 commit 3dce4f9
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 57 deletions.
2 changes: 1 addition & 1 deletion bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import adventure from 'adventure'
import * as IntroductionProblem from './problems/0-introduction/index.js'
import * as SpaceOutProblem from './problems/1-space-out/index.js'
import * as CatMemesProblem from './problems/2-cat-gifs/index.js'
import * as CatMemesProblem from './problems/2-cat-memes/index.js'
import * as DelegationProblem from './problems/3-delegation/index.js'
import * as InfiniteCompressionProblem from './problems/4-infinite-compression/index.js'
import * as MemesProblem from './problems/5-memes/index.js'
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
43 changes: 34 additions & 9 deletions problems/4-infinite-compression/problem.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
# Infinite avatar compression!

YES BOSS! That's how you do it. Now your minions can do tasks on your behalf. They can even re-delegate to others! It's delegations all the way down.
YAS BOSS! That's how you do it!

One thing to note about delegations is that they're not secrets, they can only be used by the target "audience" - in this case the DID of the workshop. So you can embed in scripts and/or send them in emails or whatever really. They're just a proof that you have been given the capability to do something.
## 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.

Ok, moving on. We talked about content addressing a couple of exercises ago. Right? Yeah well that content addressed data that you uploaded is now a DAG. Yeah, a DAG - Directed Acyclic Graph. So I don't know if you know anything about hashing but the CID you received is no ordinary hash. It's a CID that addresses a graph of _many_ nodes each with their _own_ CID...and with this one very special property - no cycles. Cool huh?! Fun fact: the CID you have is the CID of the root node of the graph. It's the hash of the node's data **and** any links it has to other nodes.
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! 🚗✨

The DAG is packed into a CAR 🚗 - beep beep. jk jk a CAR is a Content-Addressed Archive. It's kinda like a `tar` file but for DAGs. It's a useful container format for transferring content addressed data over HTTP.
## 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.
```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.
```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.
```js
console.log(root.toString())
```

In web3.storage, we content address CARs as well! So we generate a hash for the CAR and invoke a `store/add` capability, passing the CAR CID as parameters to the invocation. The service will reply with a signed URL - a place to put the CAR that will only accept data that hashes to the CID of the CAR.
## Why It’s Awesome:
**Efficiency:** You’re not just uploading data—you’re breaking it down and managing it in a super-efficient way.

**BUT** if we know the CAR you want to send has already been stored then we'll send back a flag to say that you don't need to send it! Hey presto, infinite compression! Joking aside, isn't content addressing awesome?!
**Organization:** The DAG structure helps keep your data neatly organized, and the CIDs act as a digital map to navigate it all.

I know loads of text, but one more thing, sometimes y'all got big datas. If the datas are big, we split the DAG across multiple CAR files. In this exercise we're going to store something else and log out the CAR CIDs a.k.a. the CID of the CAR _shards_.
** No Redundant Uploads:** Thanks to content addressing, if the data already exists, you don’t need to send it again—saving time and bandwidth.

Create a _new_ file for your solution e.g. `ex5.mjs` and upload something like you did in the cat memes exercise. This time though, print out the CIDs of the CAR shards as they are sent, and then _finally_ the CID of the root of the DAG. Your output is expected to be newline delimited.

Good luck!
## 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.

Now, it’s your turn to dive into the world of infinite compression! Good luck, and have fun compressing! 🚀

─────────────────────────────────────────────────────────────────────────────
* To print these instructions again, run: `$ADVENTURE_NAME print`
Expand Down
45 changes: 38 additions & 7 deletions problems/5-memes/problem.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,53 @@
# Memes for my eyes

Any meme you upload is almost instantly available for retrieval. Other files also. Content is made available by root CID and by CAR shard CID. In this exercise you are going to fetch a text file from the public gateway by it's root CID and log it to the console.
Ain't you cool? Now, let's shift gears and dive into the next challenge: retrieving content from a decentralized network.

You can use the `w3s.link` gateway to retrieve the data but the magic of decentralized peer to peer networking means that you should be able to use any gateway.
## 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.

Create a _new_ file for your solution e.g. `ex6.mjs`.
## What You Need to Do:
1. Start by creating a new JavaScript file, ex6.mjs.

To retrieve data from a gateway you should format the request like:
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:
```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.
```js
const res = await fetch(url)
```
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! 🚀

The CID of the data to fetch will be provided to `process.stdin`.
**Next Steps:**
- Try fetching different types of content by changing the CID.
- Explore how different gateways work and compare their performance.

You should install the `multiformats` library from npm (`npm install multiformats`) to `decode` the CID from it's compact binary form and then format it as a string in the URL.
You’re doing great—keep pushing forward!

Finally send a HTTP request to fetch the content and write the data directly to `process.stdout`.

─────────────────────────────────────────────────────────────────────────────
* To print these instructions again, run: `$ADVENTURE_NAME print`
Expand Down
68 changes: 43 additions & 25 deletions problems/6-dude-where/problem.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,59 @@
# DUDE, WHERE'S MY CAR?

We talked about CARs earlier. We're going to talk some more now.
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.

A CAR file contains a DAG, a collection of nodes created from your data. There's loads of benefits to this - for example, you can retrieve sub-graphs and fetch different nodes from different peers, spreading the load and optimising speed.
## 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.

However, when you access data from a gateway, IPFS fetches the nodes of the graph, verifies their individual hashes, re-assembles the file and sends it to you over HTTP.

You receive a bunch of bytes, but the problem is you can't verify those bytes correspond to your CID, without transforming them back into a DAG 🙈.

...and then, guess what, there's not just one way to build a DAG!

So even if you did build a new DAG, you may not be using the same settings as whoever built it in the first place and you might come up with a different CID to the one you accessed the content with!

One answer is to move the re-assembily from DAG to file into the client - the entity requesting the data. This removes the trust element as the client can now verify the hashes of the nodes in the graph.

In this exercise you're going to fetch a CAR file from a "trustless" gateway (I know that sounds bad but actually it's good!) and re-assemble it into a file.

Create a _new_ file for your solution e.g. `ex7.mjs`. You're going to need a couple of libraries, one for reading CARs and one for exporting files from an IPFS DAG:

```sh
## 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.
```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`.
```js
const cid = 'bafybeifdnnn35jnwel2dno7hu7zfew6gtxhkaynaszuj4i77j4m7wsv72a'
const path = '/cat2.txt'

You can fetch a CAR from the web3.storage trustless gateway like this:

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`.
```js
const reader = await CarReader.fromBytes(bytes)
```
https://dag.w3s.link/ipfs/<CID>?format=car
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) {
const block = await reader.get(cid)
if (!block) throw new Error(`not found: ${cid}`)
return block.bytes
}
})
```
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.

The data to fetch is in a directory with the CID: `bafybeifdnnn35jnwel2dno7hu7zfew6gtxhkaynaszuj4i77j4m7wsv72a`. The path to extract is `/cat2.txt`.
Now, go ahead and build that ex7.mjs file, fetch your CAR, and make sure everything checks out. Happy coding! 🚗🔍

Fetch the CAR file, then give it to a CAR reader. You'll need to create a simple adapter over the CAR reader that you can give to the `exporter` for extracting the data.
**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.

Hint - these docs might come in helpful:
* https://npm.im/@ipld/car#async-carreaderfrombytesbytes
* https://npm.im/ipfs-unixfs-exporter#exportercid-blockstore-options
You’re doing an awesome job - one more to go!

─────────────────────────────────────────────────────────────────────────────
* To print these instructions again, run: `$ADVENTURE_NAME print`
Expand Down
Loading

0 comments on commit 3dce4f9

Please sign in to comment.