Skip to content

fix: updating to new CID API in latest js-ipfs, fixes #79 #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11,445 changes: 4,852 additions & 6,593 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
},
"dependencies": {
"async": "^2.6.1",
"cids": "^0.5.3",
"cids": "^0.5.6",
"highlight.js": "^9.12.0",
"ipfs": "^0.31.0",
"ipfs": "^0.33.1",
"ipfs-css": "^0.6.0",
"marked": "^0.4.0",
"monaco-editor": "^0.6.1",
Expand Down
4 changes: 2 additions & 2 deletions src/components/Lesson.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ const defaultCode = `/* globals ipfs */

const run = async () => {
// your code goes here!
// example: ipfs.dag.put({hello: 'world'})
// be sure this function returns the requested value
}

return run
Expand Down Expand Up @@ -206,7 +206,7 @@ export default {
let basePath = this.$route.path.slice(0, -2)
let number = this.$route.path.slice(-2)
while (this.$router.resolve(basePath + number).route.name !== '404') {
number ++
number++
number = number.toString().padStart(2, '0')
}
return parseInt(number) - 1
Expand Down
2 changes: 1 addition & 1 deletion src/lessons/Basics/01-concepts.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
**CID** - Content Identifier. An unique address for a block of data in IPFS that is derived from it's content.
**CID** - Content Identifier. An unique address for a block of data in IPFS that is derived from its content.
4 changes: 1 addition & 3 deletions src/lessons/Basics/01-exercise.md
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
Use `ipfs.dag.put` to create a node for the data `{test: 1}`.

This method will return a CID (Content Identifier), which you should in turn return from your `run()` function.
Use `ipfs.dag.put` to create a node for the data `{test: 1}`. Return the CID of your new node.
21 changes: 20 additions & 1 deletion src/lessons/Basics/01.md
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
You can create nodes using the `ipfs.dag.put` API.
In this workshop we'll be exploring the IPFS DAG API, which lets us store data
objects in IPFS. (You can store more exciting things in IPFS, like your favorite
cat GIF, but you'd need to use a different API for that.)

You can create a new node by passing a data object into the `ipfs.dag.put` method,
which returns a Content Identifier (CID) for the newly created node.

```javascript
ipfs.dag.put({hello: 'world'})
```

A CID is an address for a block of data in IPFS that is derived from its content. Every
time someone puts the same `{hello: 'world'}` data into IPFS, they'll get back an
identical CID to the one you got. If they put in `{hell0: 'w0rld'}` instead, the
CID will be different.

_Note: Throughout our lessons we'll be using a code editor like the one below.
Enter your solution code within the `run` function that's pre-populated for you,
being sure to return the requested value within that function. (You won't need to
update the `return run` line at the end; that's just there to make the code editor work.)_
2 changes: 1 addition & 1 deletion src/lessons/Basics/02-concepts.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
**CID** - Content Identifier. An unique address for a block of data in IPFS that is derived from it's content.
**CID** - Content Identifier. An unique address for a block of data in IPFS that is derived from its content.

**DAG** - Directed Acyclic Graph. Blocks in IPFS form a graph as they can point to other blocks by their CID. These links can only point one direction (directed) and across the whole graph there are no loops or cycles (acyclic).
2 changes: 1 addition & 1 deletion src/lessons/Basics/02-exercise.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Create a link named `bar` that points to the node we created in the first the lesson. Put it into IPFS and return its CID.
Create a named link called `bar` that points to the node we created in the first the lesson. Put it into IPFS and return its CID.

The editor is pre-populated with the code to create the node we're linking to.
21 changes: 6 additions & 15 deletions src/lessons/Basics/02.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
One important feature of DAGs is the ability to link them together.
One important feature of Directed Acyclic Graphs (DAGs) is the ability to link them together.

The way you express links in the `ipfs` DAG store is with an object with a
single `'/'` attribute pointed at the `CID` of another node.
The way you express links in the `ipfs` DAG store is with the `CID` of
another node.

For example, if we wanted one node to have a link called "foo" pointed
to another CID, it might look like:
to another CID instance previously saved as `barCid`, it might look like:

```javascript
{
foo: {'/': 'z43AaGEvwdfzjrCZ3Sq7DKxdDHrwoaPQDtqF4jfdkNEVTiqGVFW'}
}
```

In `js-ipfs` we tend to work with instances of `CID` from the `cids` module.
Links need to be expressed with a base encoded string, so to create the
structure above you might use:

```javascript
{
foo: {'/': cid.toBaseEncodedString()}
foo: barCid
}
```
When we give a field a name and make its value a link to a CID, we call this a named link.
2 changes: 1 addition & 1 deletion src/lessons/Basics/02.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const validate = async (result, ipfs) => {
return {success: 'Everything works!'}
} else {
let obj = await ipfs.dag.get(result)
let expected = JSON.stringify({bar: {'/': hash}})
let expected = JSON.stringify({bar: new CID(hash)})
let got = JSON.stringify(obj.value)
let fail = `Was expecting "${expected}" but got "${got}"`
return {fail}
Expand Down
4 changes: 2 additions & 2 deletions src/lessons/Basics/03.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ console.log(await ipfs.dag.get(cid, '/my/deep/obj'))
/* prints {value: 'is cool', remainderPath: ''} */
```

`ipfs.dag.get()` allows queries using IPFS paths.
`ipfs.dag.get` allows queries using IPFS paths.
These queries return an object containing the value of the query and any remaining path that was unresolved.

The cool thing about this API is that it can also traverse through links.
Expand All @@ -22,7 +22,7 @@ The cool thing about this API is that it can also traverse through links.
let cid = await ipfs.dag.put({foo: 'bar'})
let cid2 = await ipfs.dag.put({
my: {
other: {'/': cid.toBaseEncodedString()}
other: cid
}
})

Expand Down
4 changes: 1 addition & 3 deletions src/lessons/Basics/03.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ let code = `/* globals ipfs */

const run = async () => {
let cid = await ipfs.dag.put({test: 1})
let cid2 = await ipfs.dag.put(
{bar: {'/': cid.toBaseEncodedString()}}
)
let cid2 = await ipfs.dag.put({bar: cid})
/* your code goes here */
}

Expand Down
2 changes: 1 addition & 1 deletion src/lessons/Blog/01-exercise.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Modify the two existing blog posts and add a new field `author` that links to the author of the blog post. The post about trees was authored by Sam, while Nat wrote the post about computers. Remember to use `toBaseEncodedString()` to make the CID links.
Modify the two existing blog posts by adding a new field `author` that links to the author of each post. The post about trees was authored by Sam, while Nat wrote the post about computers.
11 changes: 7 additions & 4 deletions src/lessons/Blog/01.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
This exercise has some prepared code to get started faster. It resembles a blog. There are authors (Nat and Sam) and some blog posts about trees and computers. At the moment there’s no relation between them. Let’s update the blog posts so that they link to the author.

In the [basic lessons](#/basics/02), we learned that a link in IPFS is represented as an object with a slash as its only field:
In the [Basics workshop](#/basics/02), we learned that a link in IPFS is represented as an instance of `CID`:

```javascript
const link = {'/': 'a-base-encoded-cid'}
{
linkToAwesomeNode: awesomeCid
}
```
When we give a field a name and make its value a link to a CID, we call this a named link.

The exercise below has some prepared code to get us started. The data structure resembles a blog which has two authors, Nat and Sam, and some blog posts about trees and computers. At the moment there’s no relation between them. Let’s update the blog posts so that they link to the author.
12 changes: 6 additions & 6 deletions src/lessons/Blog/01.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ const run = async () => {
const samCid = await ipfs.dag.put({author: "Sam"})
const treePostCid = await ipfs.dag.put({
content: "trees",
author: {"/": samCid.toBaseEncodedString()}
author: samCid
})
const computerPostCid = await ipfs.dag.put({
content: "computers",
author: {"/": natCid.toBaseEncodedString()}
author: natCid
})

return [treePostCid, computerPostCid]
Expand All @@ -71,11 +71,11 @@ const validate = async (result, ipfs) => {
if (node.author === undefined) {
return {fail: 'Blog posts need to have an `author` field.'}
}
if (node.author['/'] === undefined) {
if (!CID.isCID(node.author)) {
return {fail: 'The value of `author` needs to be a link (`{"/": "some-cid"}`).'}
}
const nodeAuthor = new CID(node.author['/']).toBaseEncodedString()
if (![natCid, samCid].includes(nodeAuthor)) {
const nodeAuthor = node.author
if (![natCid, samCid].includes(nodeAuthor.toBaseEncodedString())) {
return {fail: 'You need to link to the CID of an author (Nat or Sam).'}
}
let expectedAuthor
Expand All @@ -87,7 +87,7 @@ const validate = async (result, ipfs) => {
expectedAuthor = natCid
break
}
if (nodeAuthor !== expectedAuthor) {
if (nodeAuthor.toBaseEncodedString() !== expectedAuthor) {
return {fail: `The author of the "${node.content}" blog post (${nodeAuthor}) did not match the the expected author (${expectedAuthor}).`}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/lessons/Blog/02.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Everything that is stored in IPFS has an associated CID. That CID is constructed by hashing the data itself. If the same hash and encoding is used, then the same data will result in the same CID. This means that as soon as you edit data and store it, it will have a new CID. The old data won’t be overridden; it’s still there.
Everything that is stored in IPFS has an associated CID. That CID is constructed by hashing the data itself. If the same hash and encoding is used, then the same data will result in the same CID. However, as soon as you edit data and store it again, it will have a new CID. The old data won’t be overridden; it’s still stored there with its old CID.

Before modifying the code, please open the developer tools in your browser and submit the code. You’ll see the CIDs of the blog posts in the console. When you look at the console again after you’ve modified the code, you’ll see the CIDs have changed.
Our blog doesn't have any tags yet. Let’s modify the posts again to add some tags, watching how the CID for each post changes as we change its contents.

Another common thing in blogs is tagging. Let’s modify the blog posts again and add some tags.
Before modifying the code, please open the developer tools in your browser and submit the code in its current state. You’ll see the CIDs of the blog posts in the console. When you look at the console again after you’ve modified the code, you’ll see that the CIDs have changed. (Notice how we use `CID.toBaseEncodedString()` to access the CID as a string for purposes of console logging.)
10 changes: 5 additions & 5 deletions src/lessons/Blog/02.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ const run = async () => {

const treePostCid = await ipfs.dag.put({
content: "trees",
author: {"/": samCid.toBaseEncodedString()}
author: samCid
})
const computerPostCid = await ipfs.dag.put({
content: "computers",
author: {"/": natCid.toBaseEncodedString()}
author: natCid
})

console.log('post about trees:', treePostCid.toBaseEncodedString())
Expand All @@ -49,12 +49,12 @@ const run = async () => {
const samCid = await ipfs.dag.put({author: "Sam"})
const treePostCid = await ipfs.dag.put({
content: "trees",
author: {"/": samCid.toBaseEncodedString()},
author: samCid,
tags: ["outdoor", "hobby"]
})
const computerPostCid = await ipfs.dag.put({
content: "computers",
author: {"/": natCid.toBaseEncodedString()},
author: natCid,
tags: ["hobby"]
})

Expand Down Expand Up @@ -100,7 +100,7 @@ const validate = async (result, ipfs) => {
}
// Don't check the CIDs as then the order of the tags would matter.
// But that order really doesn't matter.
return {success: 'Everything works!'}
return {success: 'Everything works! Did you remember to check the console logs?'}
}

export default {
Expand Down
2 changes: 1 addition & 1 deletion src/lessons/Blog/03-exercise.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Insert those new tag objects into IPFS via `ipfs.dag.put()` and return the two resulting CIDs as an array.
Create new nodes for the tags "outdoor" and "hobby" in the format shown above, linking to the relevant blog posts using arrays. Insert the new tag objects into IPFS via `ipfs.dag.put()` and return the two resulting CIDs as an array.
21 changes: 14 additions & 7 deletions src/lessons/Blog/03.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
A single object can have many links to other nodes. To illustrate this, we are creating new nodes which could be used for a tag cloud.
A single object can have many links to other nodes. To illustrate this, let's create new nodes which could be used for a tag cloud.

Links don’t necessarily need to be the value of a field (we call those “named links”); they can also be in an array.
Until now, we've been using named links, meaning that we create a named field with a single link as its value, such as:

```javascript
{
author: samCid
}
```
However, we can also choose to gather links into an array without naming each one individually.

```javascript
{ links: [
{'/': 'a-base-encoded-cid'},
{'/': 'another-base-encoded-cid'}
natCid,
samCid
]
}
```

This is perfect for our use case. Create a new node for the tags “outdoor” and “hobby.” The structure should look like this:
This is perfect for our use case, where a single tag should be associated with many posts, like so:

```javavscript
```javascript
{
tag: "name-of-the-tag",
posts: [
Expand All @@ -21,4 +28,4 @@ This is perfect for our use case. Create a new node for the tags “outdoor” a
}
```

Please note that arrays are order-dependent. This means that two arrays with the same links in a different order will get a different CID.
Please note that arrays are order-dependent. This means that two arrays with the same links in a different order will get different CIDs.
18 changes: 9 additions & 9 deletions src/lessons/Blog/03.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ const run = async () => {
const samCid = await ipfs.dag.put({author: "Sam"})
const treePostCid = await ipfs.dag.put({
content: "trees",
author: {"/": samCid.toBaseEncodedString()},
author: samCid,
tags: ["outdoor", "hobby"]
})
const computerPostCid = await ipfs.dag.put({
content: "computers",
author: {"/": natCid.toBaseEncodedString()},
author: natCid,
tags: ["hobby"]
})

Expand All @@ -46,26 +46,26 @@ const run = async () => {
const samCid = await ipfs.dag.put({author: "Sam"})
const treePostCid = await ipfs.dag.put({
content: "trees",
author: {"/": samCid.toBaseEncodedString()},
author: samCid,
tags: ["outdoor", "hobby"]
})
const computerPostCid = await ipfs.dag.put({
content: "computers",
author: {"/": natCid.toBaseEncodedString()},
author: natCid,
tags: ["hobby"]
})

const outdoorTagCid = await ipfs.dag.put({
tag: "outdoor",
posts: [
{"/": treePostCid.toBaseEncodedString()}
treePostCid
]
})
const hobbyTagCid = await ipfs.dag.put({
tag: "hobby",
posts: [
{"/": treePostCid.toBaseEncodedString()},
{"/": computerPostCid.toBaseEncodedString()}
treePostCid,
computerPostCid
]
})

Expand Down Expand Up @@ -98,7 +98,7 @@ const validate = async (result, ipfs) => {
if (!Array.isArray(node.posts)) {
return {fail: 'The value of the `posts` field must be an array of links.'}
}
const isLinks = node.posts.every((post) => '/' in post)
const isLinks = node.posts.every((post) => CID.isCID(post))
if (!isLinks) {
return {fail: 'The values of the `posts` array must be links.'}
}
Expand All @@ -116,7 +116,7 @@ const validate = async (result, ipfs) => {
default:
return {fail: `Wrong tag (${node.tag}). Did you mean "hobby" or "outdoor"?`}
}
const nodePosts = node.posts.map((post) => new CID(post['/']).toBaseEncodedString())
const nodePosts = node.posts.map(post => post.toBaseEncodedString())
if (!shallowEqualArrays(nodePosts.sort(), expectedPosts.sort())) {
return {fail: `The posts of the tag "${node.tag}" ${utils.stringify(nodePosts)} did not match the the expected posts ${utils.stringify(expectedPosts)}.`}
}
Expand Down
Loading