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

Conversation

mikeal
Copy link
Member

@mikeal mikeal commented Nov 28, 2018

This is SO much cleaner!

@terichadbourne
Copy link
Member

@mikeal Just confirming you're intending this as a full fix to issue #79 once merged?

@mikeal mikeal mentioned this pull request Nov 29, 2018
11 tasks
@terichadbourne
Copy link
Member

@mikeal I definitely want to review this, in particular to ensure the new instructions are clear and I can pass the lessons using the new API, but I wonder if we should also ask someone more familiar with IPFS and the changed API to give it a quick once-over as well?

@terichadbourne
Copy link
Member

@mikeal I'm going to drop here my failed attempts to pass some of these lessons. It's most likely that I'm missing other concepts, as opposed to your code updates being wrong, but if we can talk about my mistakes it will help me rewrite instructions to be more clear or offer some hints.

BASICS

Basics Lesson 2 - http://localhost:8080/#/basics/02

Failled attempt:

/* globals ipfs */

const run = async () => {
  let cid = await ipfs.dag.put({test: 1})
  let cid2 = ipfs.dag.put({bar: new CID(cid)})
  return cid2
}

return run

Error: CID is not defined

Basics Lesson 3

The second example block here still shows a cid.toBaseEncodedString(), which I think doesn't exist anymore. This should be updated to match the new right answer to lesson 2, I presume.

Failed attempt 1:

/* globals ipfs */

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

return run

You forgot to return a result :)

Failed attempt 2:

/* globals ipfs */

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

return run

You forgot to return a result :)

Failed attempt 3:

/* globals ipfs */

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

return run

You forgot to return a result :)

Also tried this with a slash before bar even though that wasn't necessary in the old version of the site.

@terichadbourne
Copy link
Member

@mikeal Comments and my mistakes continued:

BLOG

** Blog Lesson 1**
My screen capture isn't currently working, but in the code sample that precedes the exercise box, the content is too wide for the space it's given. If you hover, you'll see a scroll bar appear. But if you don't hover, you'll just think you're seeing all there is and, if you know your stuff, think there's a closing parens missing. When you do scroll, the gray background says the same size so that parens is on white, not gray.

Note the misspelling in:
In the basic lessons, we learned that a link in IPFS is represented as an **instannce** of CID:

The exercise instructions still say "Remember to use toBaseEncodedString() to make the CID links."

Nothing happens when I click the "Submit" button, but for reference, this is what I tried as my code. I tried it because of my experience with the past version of the lesson, not because the example above suggested I should do it:

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})

  // Modify the blog posts below

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

  return [treePostCid, computerPostCid]
}

return run

Are big silly strings and actual data interchangeable in how this all works? Could a and b be identical? Which of c or d would be right?
a. const link = new CID('z43AaGEvwdfzjrCZ3Sq7DKxdDHrwoaPQDtqF4jfdkNEVTiqGVFW')
b. const link = new CID({author: "Nat"})
c. const link = newCID(natCid)
d. const link = natCid

I think part of why I'm finding this lesson confusing now because the examples are using crazy strings instead of the simplistic data I saw in most of the Basics lesson. When I try to solve an exercise, I hope there's a code example above that's very similar to what I need. I don't know the correct solution to this exercise in its current form, but if I don't need to type "newCid" in my solution, then I find the example above confusing. I want to try to apply whatever I just saw. In retrospect this was might be what had me confused in Basics Lesson 2.

Blog Lesson 2

I passed this one!

I'm noticing that toBaseEncodedString is used in the code block to create console logs that show only the string CID. Would it be worth throwing a quick mention like "See that toBaseEncodedString() we use for our console logs? You can use it if you ever need to do X. "

  console.log('post about trees:', treePostCid.toBaseEncodedString())
  console.log('post about computers:', computerPostCid.toBaseEncodedString())

Blog Lesson 3

While looking at this lesson I realized that we've never introduced the term "node," which is used here and was first used in Basics Lesson 1. Is there an easy way to define it, or will it be defined explicitly in the new decentralized concepts workshop, and we could link to it from the other workshops?

This is not a change you introduced, just something I'm noticing now:

Links don’t necessarily need to be the value of a field (we call those “named links”); they can also be in an array.

I think we should include an example so people are sure they understand what a named link is. Would this be an accurate re-phrasing?

Links don’t necessarily need to be the value of a single field, which we'd call a named link (such as '{author: "Nat"}'. They can also be in an array.  

Or is a named link something that would have been specifically {'/': whatever} in the old API, which is now a format the user has never been exposed to.

Failed code attempt:

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})
  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"]
  })

  const outdoorCid = await ipfs.dag.put({
  tag: "outdoor",
  posts: [treePostCid]
})

  const hobbyCid = await ipfs.dag.put({
  tag: "hobby",
  posts: [treePostCid, computerPostCid]
})
 return [outdoorCid, hobbyCid]
}

return run

Error: Unexpected token {
Console log:

03.vue?c9fc:119 Uncaught (in promise) TypeError: post.toBaseEncodedString is not a function
    at eval (03.vue?c9fc:119)
    at Array.map (<anonymous>)
    at Object._callee$ (03.vue?c9fc:119)
    at tryCatch (runtime.js?96cf:62)
    at Generator.invoke [as _invoke] (runtime.js?96cf:288)
    at Generator.prototype.(:8080/anonymous function) [as next] (webpack-internal:///./node_modules/regenerator-runtime/runtime.js:114:21)
    at step (asyncToGenerator.js?3040:10)
    at _next (asyncToGenerator.js?3040:25)

@terichadbourne
Copy link
Member

@mikeal Continued...

BLOG

Blog Lesson 4

failed attempt 1:

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})
  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"]
  })

  const dogsPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny", "hobby"]
  })

  // Add your code here

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

  return dogsPostCid
}



return run

Error: dogsPostCid is not defined

failed attempt 2:

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})
  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"]
  })

  const dogsPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny", "hobby"]
  })

  // Add your code here

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

  return ipfs.dag.get(dogsPostCid)
}

return run

Did not return a valid CID instance.

failed attempt 3

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})
  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"]
  })

   const dogsPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny"]
  })

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

  return dogsPostCid
}

return run

submit button appears to user not to work but the following error is logged in the console:

Uncaught (in promise) TypeError: node.author.toBaseEncodedString is not a function
    at Object._callee$ (04.vue?184f:108)
    at tryCatch (runtime.js?96cf:62)
    at Generator.invoke [as _invoke] (runtime.js?96cf:288)
    at Generator.prototype.(:8080/anonymous function) [as next] (webpack-internal:///./node_modules/regenerator-runtime/runtime.js:114:21)
    at step (asyncToGenerator.js?3040:10)
    at _next (asyncToGenerator.js?3040:25)

failed attempt 4:

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})
  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"]
  })

   const dogsPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny"]
  })

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

  return ipfs.dag.get(dogsPostCid)
}

return run

Did not return a valid CID instance.

Same result as above if I do return await ipfs.dag.get(dogsPostCid)

Blog Lesson 5

failed attempt 1:

/* globals ipfs */

const run = async () => {
  const natCid = await ipfs.dag.put({author: "Nat"})
  const samCid = await ipfs.dag.put({author: "Sam"})
  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"]
  })
  const dogPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny", "hobby"]
  })

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

  // Add your new code here and modify the tags above

  return [outdoorTagCid, hobbyTagCid, funnyTagCid ]
}

return run

no error message appears to user when button is clicked but the following is in the console:

Uncaught (in promise) TypeError: post.toBaseEncodedString is not a function
    at eval (05.vue?754e:142)
    at Array.map (<anonymous>)
    at Object._callee$ (05.vue?754e:142)
    at tryCatch (runtime.js?96cf:62)
    at Generator.invoke [as _invoke] (runtime.js?96cf:288)
    at Generator.prototype.(:8080/anonymous function) [as next] (webpack-internal:///./node_modules/regenerator-runtime/runtime.js:114:21)
    at step (asyncToGenerator.js?3040:10)
    at _next (asyncToGenerator.js?3040:25)

@mikeal mikeal changed the title fix: updating to new CID API in latest js-ipfs fix: updating to new CID API in latest js-ipfs, fixes #79 Nov 29, 2018
@mikeal
Copy link
Member Author

mikeal commented Nov 29, 2018

Just confirming you're intending this as a full fix to issue #79 once merged?

Yup, updated PR title to be clear.

@terichadbourne
Copy link
Member

terichadbourne commented Nov 30, 2018

Oh hey, this works a lot better after I install the new dependencies 🤦‍♀️

The last lesson is still way harder than the others and is very prone to stalling out the whole site if you get the code wrong, but otherwise I was able to pass the lessons with the new API.

Suggested edits for clarity:

Basics

Lesson 2:

  • Change the code sample in lesson to use a variable representing a CID instead of new CID(string) (or show both options), since the former is what you actually need for this exercise.
    New Lesson:
  • Insert a lesson between 2 & 3 that explains the difference between a CID itself (as returned by ipfs.dag.put() or new CID and the string that is returned by cid.toBaseEncodedString() (useful for console logging) and can be fed into new CID(baseEncodedString
    Lesson 3:
  • In second example code block, change other: {'/': cid.toBaseEncodedString()} to other: cid to match the new simplified API

Blog
Lesson 1:

  • Replace or add to current link example since it uses new CID() which is not used in this lesson
  • If keeping that example with the long string, fix the UI so you can see either the full text or the fact that a scroll bar exists without hovering.
  • Explain that we call this kind of link a named link
  • Fix spelling of instannce in second paragraph
  • Change Modify the two existing blog posts *and add* a new field to Modify the two existing blog posts *by adding* a new field
  • Remove Remember to use toBaseEncodedString() to make the CID links.

Lesson 2:

  • Add a call-out to how we use .toBaseEncodedString() for console
  • In the success message remind them to look at the console logs to see how the CIDs changed

Lesson 3:

  • Improve the wording around named links to include an example of what we've done so far
  • Replace Links don’t necessarily need to be the value of a field (we call those “named links”); they can also be in an array. with Until now, we've been using named links, meaning that we create a named field with a single link as its value, such as (author: natCid`) However, we can also choose to gather links into an array without naming each one individually."
  • It's confusing that the specific instructions here are halfway down the explainer text, not in the exercise box. In the top section, change This is perfect for our use case. Create a new node for the tags “outdoor” and “hobby.” The structure should look like this: to This is perfect for our use case, where a single tag should be associated with many posts: and in the exercise box change Insert those new tag objects into IPFS via ipfs.dag.put() and return the two resulting CIDs as an array. to Create new nodes for the tags "outdoor" and "hobby" as shown above, linking to the relevant posts using arrays. Insert the new tag objects into IPFS via ipfs.dag.put() and return the two resulting CIDs as an array.

Lesson 5:

  • In the 2nd sentence, change "Now, update the nodes" to "Let's update the nodes"
  • Change

There isn’t a node for the funny tag yet either, so create a new node with the same data as the other tag nodes and add a link to the blog post about dogs.

Return the CIDs of all three tag nodes.

to

First, you'll need to add a link to the new blog post from the node for the hobby tag. 

We don't yet have a node for the funny tag. Create a new tag node that matches the format of the others and links to the blog post about dogs. 

Return the CIDs of all three tag nodes as an array.

Lesson 7:
This one's dangerous because it easy to create endless console logs or multple async calls that essentially break the website. Couldn't solve it myself except by copying the solution code from the codebase because there are too many ways to screw it up.

  • Remove the line const CID = require('cids')
  • Explain why we're using value.prev instead of (cid, 'prev') learned earlier
  • Add clues about being sure to wrap parens around the right part of it (ending before .value.prev
  • Add clues about not reusing await statements (because of lag time)
  • Add clues about using a while loop

@mikeal Anything in these proposals you disagree with? Would you like to make these changes yourself or would you like me to take a stab at it?

- package-lock.json updated by `npm install`
@mikeal
Copy link
Member Author

mikeal commented Nov 30, 2018

@terichadbourne go ahead and make changes directly in to the branch and I'll review them before we merge this.

- Remove a few extraneous references to the old API
- Update examples to use links stored as variables, since the
'new CID(string)' format hasn't been introduced and isn't needed in the
exercises
- Corrected a few grammatical errors
- Attempted to clarify instructions across lessons
- Moved some text between exercise box and general lesson text for
consistency
@terichadbourne
Copy link
Member

@mikeal I've made my edits as proposed to remove a few remaining references to the old API and improve clarity of instructions throughout. I'd appreciate it if you could give this a careful once-over before merging in case I actually introduced any inaccuracies while trying to make it more comprehensible.

I'll update the issue for blog lesson 7, which is still really hard to solve and needs a little more explanation, although I did drop some clues in here.

I'll also add an issue to add another lesson to the basics workshop that shows the base encoded strings and new CID being used. I found the use of them in examples here confusing because the code needed to pass the exercises doesn't use them, and I've therefore replaced with references to CID instances already saved to variables.

Your API changes seem to be working, so I'm comfortable with you merging if you're good with my edits.

@mikeal mikeal changed the base branch from master to code December 5, 2018 22:41
@terichadbourne terichadbourne merged commit 5e2273b into code Dec 6, 2018
@terichadbourne terichadbourne deleted the cids-everywhere branch December 7, 2018 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants