<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ decentralization - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ decentralization - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 26 May 2026 10:37:23 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/decentralization/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Decentralized Identity – Build a Profile with Next.js, Ethereum & Ceramic Network ]]>
                </title>
                <description>
                    <![CDATA[ Long-standing centralized intermediaries, like the government or big companies, are the ones who make and keep your ID information in traditional systems that manage who you are.  But this implies that you have no control over the information relatin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/decentralized-identity-build-a-profile-with-ethereum-ceramic-and-reactjs/</link>
                <guid isPermaLink="false">66b905ce5730a049b6bfea7d</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ethereum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Fri, 17 Feb 2023 22:44:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/Decentralized-Identity--Build-a-Profile-with-NextJs--Ethereum---Ceramic-Network.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Long-standing centralized intermediaries, like the government or big companies, are the ones who make and keep your ID information in traditional systems that manage who you are. </p>
<p>But this implies that you have no control over the information relating to your identification, who has access to <a target="_blank" href="https://www.dol.gov/general/ppii#:~:text=Personal%20Identifiable%20Information%20(PII)%20is,either%20direct%20or%20indirect%20means.">personally identifiable information (PII)</a>, and to what extent.</p>
<p>As a result, Decentralized Identity provides identity-related information that is self-controlled, private, and portable. Decentralized identifiers and attestations serve as the main building pieces. </p>
<p>Thanks to Ceramic's decentralized application databases, application developers can reuse data across applications and automatically make them interoperable.</p>
<p>In this article, you will learn about Decentralized Identity, Decentralized Identifiers, Ceramic network, and how to build a decentralized identity profile with Ethereum on Ceramic Networks.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ul>
<li>What is a Decentralized Identity?</li>
<li>What are Decentralized Identifiers?</li>
<li>What is Ceramic Data Network?</li>
<li>Why Ceramic Network?</li>
<li>How to Build a Decentralized Identity Profile with Next.js</li>
<li>Prerequisites</li>
<li>Project Setup and Installation</li>
<li>Install TailwindCSS in Next.js</li>
<li>Authenticate Users</li>
<li>Create/Update User Profile</li>
<li>How to Test the Application</li>
<li>Conclusion</li>
<li>References</li>
</ul>
<h2 id="heading-what-is-a-decentralized-identity">What is a Decentralized Identity?</h2>
<p><a target="_blank" href="https://ethereum.org/en/decentralized-identity/">Decentralized Identity</a> is a digital identification concept where people, companies, and items are in charge of their data and can share it selectively without relying on a centralized authority. </p>
<p>This is made possible by using decentralized technologies, such as blockchain. These give people control and ownership over the information associated with their identities rather than having it stored on a central server or managed by a third party.</p>
<p>A decentralized identity is a self-owned, independent identity that enables trusted data exchange.</p>
<p>Blockchain-based digital wallets, such as those used to store and handle cryptocurrencies, serve as a practical illustration of decentralized identification. Users of these wallets control the private keys that provide them access to their money and can distribute their public keys to others to accept payments from them.</p>
<p>Users who manage their private keys can conduct transactions with others without relying on a central authority, such as a bank, and keep custody of their money.</p>
<h2 id="heading-what-are-decentralized-identifiers">What are Decentralized Identifiers?</h2>
<p>Decentralized identifiers (DIDs) are issued, held, and controlled by individuals. Since they are kept on peer-to-peer networks or distributed ledgers (blockchains), they are globally unique, highly available, and cryptographically verifiable. </p>
<p>Decentralized identifiers can be associated with individuals, groups, or governmental entities.</p>
<p>DIDs are a vital component of the developing decentralized identity ecosystem. They are designed to offer a uniform process for developing, maintaining, and exchanging digital identities unaffiliated with any one company or piece of technology. </p>
<p>This implies that a DID can be maintained and controlled by the person or entity to which it belongs and utilized across various systems and applications.</p>
<p>In recent years, smart contract platforms like Ethereum have demonstrated the utility of decentralized applications (dApps) that can be assembled like blocks to create new applications. This is especially evident in tokens that build upon one another, in DeFi protocols that use one another, and so on.</p>
<p>Thanks to Ceramic, data on the internet can now have the same kind of composability. Any data type, including profiles, social connections, blog posts, identities, reputations, and so on., can be included. You will learn more about Ceramic Network in the section below.</p>
<h2 id="heading-what-is-ceramic-network">What is Ceramic Network?</h2>
<p><a target="_blank" href="https://ceramic.network/">Ceramic</a> is a public, permissionless, open-source protocol that offers computation, state transitions, and consensus for all data structures on the decentralized web. </p>
<p>With the help of stream processing provided by Ceramic, developers can build apps that are strong, safe, trustless, and censorship-resistant using dynamic information – without using unreliable database servers.</p>
<p>Ceramic stores all content in smart documents, which are append-only IPFS logs. Before being anchored in a blockchain for consensus, each commit is verified by a decentralized identification (DID).</p>
<p>All papers in Ceramic are openly discoverable and can be referenced by other documents or queried by any other network user because the system is entirely peer-to-peer.</p>
<h2 id="heading-why-ceramic-network">Why Ceramic Network?</h2>
<p>Data interoperability is one of Ceramic Network's key benefits. This platform features a flexible and modular data schema that enables the decentralized and interoperable sharing and combining of various sorts of data. </p>
<p>Developers now have an easier time creating decentralized identification solutions that can be integrated with other programs and systems.</p>
<p>The infrastructure of Ceramic Network is scalable, fault-tolerant, decentralized, and highly available. This enables developers to create robust decentralized identity systems available to users everywhere.</p>
<p>Ceramic Network also provides a set of developer tools and libraries, making it simple to create decentralized identity apps and services. These tools include SDKs, APIs, developer guides, and an expanding ecosystem of open-source tools and libraries.</p>
<p>Now that you have learnt the theories behind decentralized identity, let's take a practical deep dive and get your hands dirty.</p>
<h2 id="heading-how-to-build-a-decentralized-identity-profile-with-nextjs">How to Build a Decentralized Identity Profile with Next.js</h2>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To go through this tutorial, you'll need some experience with JavaScript and React.js. Experience with Next.js isn't a requirement, but it's nice to have.</p>
<p>Make sure to have Node.js or npm installed on your computer. If you don't, click <a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"><strong>here</strong></a>.</p>
<p>Also, it'll be very useful to have a basic understanding of blockchain technology and Web3 concepts.</p>
<h3 id="heading-project-setup-and-installation">Project Setup and Installation</h3>
<p>Navigate to the terminal and <code>cd</code> into any directory of your choice. Then run the following commands:</p>
<pre><code class="lang-bash">mkdir decentralized-identity-project
<span class="hljs-built_in">cd</span> decentralized-identity-project
npx create-next-app@latest .
</code></pre>
<p>Accept the following options:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676416198416/0b46fd0f-d47a-4533-9450-a79007205efe.png" alt="Image" width="611" height="71" loading="lazy"></p>
<p>Install the <code>@self.id/react</code> and <code>@self.id/web</code> packages using the code snippet below:</p>
<pre><code class="lang-bash">npm install @self.id/web @self.id/react
</code></pre>
<p>Next, start the app using the following command:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>You should have something similar to what is shown below: the default boilerplate layout for Next.js 13.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676416289117/799cfc73-78b3-49f9-8b72-a407813f7d9c.png" alt="Image" width="1292" height="884" loading="lazy"></p>
<h3 id="heading-install-tailwindcss-in-nextjs">Install TailwindCSS in Next.js</h3>
<p>In this section, you will set up Tailwind CSS in a Next.js project. Install <code>tailwindcss</code> and its peer dependencies via npm, and then run the init command to generate both <code>tailwind.config.js</code> and <code>postcss.config.js</code>.</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>Navigate to the <code>tailwind.config.js</code> file, and add the paths to your template files with the following code snippet.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./app/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./pages/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./components/**/*.{js,ts,jsx,tsx}"</span>,

    <span class="hljs-comment">// Or if using `src` directory:</span>
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx}"</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Delete all the CSS styles inside <code>globals.css</code> . Add the <code>@tailwind</code> directives for each of Tailwind’s layers to your <code>globals.css</code> file.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<h3 id="heading-configure-the-provider-component">Configure the Provider Component</h3>
<p>The <code>Provider</code> component must be placed at the top of the application tree to use the hooks detailed below. You can use it to supply an initial state as well as a specific configuration for the <a target="_blank" href="http://Self.ID">Self.ID</a> clients and queries.</p>
<p>Update the <code>_app.js</code> file under the pages folder with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Provider component from the "@self.id/react" library.</span>
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@self.id/react"</span>;

<span class="hljs-comment">// Import the "globals.css" file from the "@/styles" directory.</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@/styles/globals.css"</span>;

<span class="hljs-comment">// Define the App component as a default export.</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{

  <span class="hljs-comment">// Render the Provider component, which provides authentication and authorization functionality to the application.</span>
  <span class="hljs-comment">// Pass a client prop to the Provider component, which configures the Ceramic testnet with the "testnet-clay" value.</span>
  <span class="hljs-comment">// Render the Component with its props inside the Provider component, which allows the application to access the authentication and authorization context.</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">ceramic:</span> "<span class="hljs-attr">testnet-clay</span>" }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code snippet above, we:</p>
<ul>
<li>Imported a context provider component and global CSS styles and then defined an <code>App</code> component that wraps the entire application with the context provider.</li>
<li>Configured the context provider with a Ceramic testnet client, which allows the application to access authentication and authorization functionality.</li>
<li>Finally, the <code>Component</code> is rendered with its props inside the context provider, allowing the application to access the authentication and authorization context.</li>
</ul>
<h3 id="heading-build-the-layout">Build the Layout</h3>
<p>Next, navigate to the <code>index.js</code> file under the <code>pages</code> folder and update it with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Head component from the "next/head" module.</span>
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

<span class="hljs-comment">// Import the useViewerConnection and useViewerRecord hooks from the "@self.id/react" library.</span>
<span class="hljs-keyword">import</span> { useViewerConnection, useViewerRecord } <span class="hljs-keyword">from</span> <span class="hljs-string">"@self.id/react"</span>;

<span class="hljs-comment">// Import the EthereumAuthProvider component from the "@self.id/web" library.</span>
<span class="hljs-keyword">import</span> { EthereumAuthProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@self.id/web"</span>;

<span class="hljs-comment">// Import the useState hook from the "react" module.</span>
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>
          Decentralized Identity: Build a Profile with NextJs, Ethereum &amp; Ceramic Network
        <span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-screen bg-gray-200"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gray-600 py-4 px-4 sm:px-6 lg:px-8 lg:py-6 shadow-lg text-white"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto px-6 md:px-0"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-white text-center"</span>&gt;</span>
              Decentralized Identity: Build a Profile with NextJs, Ethereum &amp; Ceramic Network
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center pt-20 font-sans overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-md w-full mx-auto"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-10 rounded-lg shadow-lg"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
                    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>
                  &gt;</span>
                    Name
                  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"border border-gray-300 p-2 w-full rounded-lg"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your name"</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
                    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"bio"</span>
                  &gt;</span>
                    Bio
                  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"border border-gray-300 p-2 w-full rounded-lg"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"bio"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"bio"</span>
                    <span class="hljs-attr">rows</span>=<span class="hljs-string">"5"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Write something about yourself"</span>
                  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
                    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"username"</span>
                  &gt;</span>
                    Username
                  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"border border-gray-300 p-2 w-full rounded-lg"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"username"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your username"</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                  &gt;</span>
                    Update Profile
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                  &gt;</span>
                    Connect Wallet
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>To start the application, run the following command and navigate to localhost:3000 on your browser; you should have something similar to what is shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676418666618/bc0620d9-d7bb-4297-bdb1-6021d08d8d6c.png" alt="Image" width="1544" height="1060" loading="lazy"></p>
<h3 id="heading-how-to-authenticate-users">How to Authenticate Users</h3>
<p>In this section, you will implement user authentication to allow users to connect their wallets and interact with the application.</p>
<p>Update the <code>index.js</code> with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//..</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-comment">// State variables for connection, connect function, and disconnect function</span>
  <span class="hljs-keyword">const</span> [connection, connect, disconnect] = useViewerConnection();


  <span class="hljs-keyword">const</span> [isWindow, setIsWindow] = useState(<span class="hljs-literal">null</span>);


  <span class="hljs-comment">// State variable for viewer's basic profile data</span>
  <span class="hljs-keyword">const</span> record = useViewerRecord(<span class="hljs-string">"basicProfile"</span>);

  <span class="hljs-comment">// Function to create EthereumAuthProvider using window.ethereum provider</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createAuthProvider</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> addresses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">window</span>.ethereum.request({
      <span class="hljs-attr">method</span>: <span class="hljs-string">"eth_requestAccounts"</span>,
    });
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> EthereumAuthProvider(<span class="hljs-built_in">window</span>.ethereum, addresses[<span class="hljs-number">0</span>]);
  }

  <span class="hljs-comment">// Function to connect to viewer's account using created authProvider</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">connectAccount</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> authProvider = <span class="hljs-keyword">await</span> createAuthProvider();
    <span class="hljs-keyword">await</span> connect(authProvider);
  }

  <span class="hljs-comment">// Rendered JSX code</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      {/* ... */}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
        {/* ... */}

        {/* Conditionally render a button to connect/disconnect user */}
        {connection.status === "connected" ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> disconnect()}
          &gt;
            Disconnect
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        ) : isWindow &amp;&amp; "ethereum" in window ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{connection.status</span> === <span class="hljs-string">"connecting"</span> || !<span class="hljs-attr">record</span>}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
              connectAccount();
            }}
          &gt;
            Connect Wallet
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        ) : (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-red-500 text-sm italic mt-2 text-center w-full"</span>&gt;</span>
            An injected Ethereum provider such as{" "}
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://metamask.io/"</span>&gt;</span>MetaMask<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> is needed to
            authenticate.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}
</code></pre>
<p>In the code snippet above,</p>
<ul>
<li>The <code>useViewerConnection</code> hook is used to set up a state variable for the user's connection status, connect and disconnect.</li>
<li><code>isWindow</code> to set the initial state of the the window to avoid <a target="_blank" href="https://nextjs.org/docs/messages/react-hydration-error">React hydration error</a></li>
<li>The <code>useViewerRecord</code> hook is used to retrieve the user's basic profile data.</li>
<li>The <code>createAuthProvider</code> function creates an <code>EthereumAuthProvider</code> object using the <code>window.ethereum</code> provider.</li>
<li>The <code>connectAccount</code> function calls <code>createAuthProvider</code> and connects to the user's account using <code>connect(authProvider)</code>.</li>
<li>The JSX code conditionally renders a button based on the user's connection status and the availability of an <code>ethereum</code> provider in the <code>window</code> object.</li>
<li>If the user is already connected, the button will enable them to disconnect. If the user is not yet connected and an <code>ethereum</code> provider is available, the button will enable them to connect. But if the user is not connected and no <code>ethereum</code> provider is available, a message will be displayed to inform the user that an injected Ethereum provider like MetaMask is required to authenticate.</li>
</ul>
<p>Testing out the authentication functionality, you should have something similar to what is shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676467487656/bc91509c-cd69-479a-80e5-7bc9b680150d.png" alt="Image" width="1561" height="695" loading="lazy"></p>
<h3 id="heading-how-to-create-or-update-a-user-profile">How to Create or Update a User Profile</h3>
<p>In the previous section, you learned how to successfully authenticate users. Next, you will implement functionality to create and update an authenticated user with the following code snippet:</p>
<p><code>pages/index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-comment">// Use the useState hook to create state variables and functions to update them</span>
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [bio, setBio] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-comment">//...</span>

<span class="hljs-comment">// Define an asynchronous function called updateProfile to update the profile information</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateProfile</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// If any of the required fields are empty, return early and do not update</span>
     <span class="hljs-keyword">if</span> (!name || !bio || !username) {
       <span class="hljs-keyword">return</span>;
     }

     <span class="hljs-comment">// Use the merge method to update the record with the new information</span>
     <span class="hljs-keyword">await</span> record.merge({
       name,
       bio,
       username,
     });
   }

  <span class="hljs-comment">// Render the component's UI</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>

    {/* ... */}

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center pt-20 font-sans overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-md w-full mx-auto"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-10 rounded-lg shadow-lg"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
               {/* ... */}
              <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            {connection.status === "connected" &amp;&amp; record &amp;&amp; record.content ? (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center mt-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold mb-6 text-gray-900"</span>&gt;</span>
                  Profile Information
                <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full max-w-md bg-white p-8 rounded-lg shadow-lg"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold text-gray-700 mr-2 text-lg"</span>&gt;</span>
                      Name:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"nameOutput"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>
                      {record.content.name || "No name set"}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold text-gray-700 mr-2 text-lg"</span>&gt;</span>
                      Bio:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"bioOutput"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>
                      {record.content.bio || "No bio set"}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold text-gray-700 mr-2 text-lg"</span>&gt;</span>
                      Username:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"usernameOutput"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>
                      {record.content.username || "No username set"}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            ) : (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-8 rounded-lg shadow-lg"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>No profile found.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            )}

          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  ) 
}
</code></pre>
<p>In the code above,</p>
<ul>
<li>The component uses the useState hook to manage the state of three variables: <code>name</code>, <code>bio</code>, and <code>username</code>.</li>
<li>There's an async function called <code>updateProfile</code> that is responsible for merging the current state of the variables into a record.</li>
<li>If any of the variables is empty, the <code>updateProfile</code> function returns without updating the record.</li>
<li>There are three conditional statements that render a different UI based on whether a record is found or not.</li>
<li>The first conditional statement checks whether the record is still loading, and if it is, it displays a <code>Loading...</code> message.</li>
<li>The second conditional statement checks whether there's no record content and the connection status is connected. If this is true, it displays a <code>No profile found.</code> message.</li>
</ul>
<p>The third conditional statement checks whether the record content exists. If it does, it displays the profile information, which includes the user's <code>name</code>, <code>bio</code>, and <code>username</code>.</p>
<p>You are almost there. In the form tag, update the <code>name</code>, <code>bio</code> and <code>username</code> input field with the following code:</p>
<pre><code class="lang-javascript">&lt;div className=<span class="hljs-string">"mb-6"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>
  &gt;</span>
    Name
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
    //<span class="hljs-attr">...</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
      setName(e.target.value);
    }}
  /&gt;</span>
&lt;/div&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"bio"</span>
  &gt;</span>
    Bio
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
    //<span class="hljs-attr">...</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
      setBio(e.target.value);
    }}
  &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"username"</span>
  &gt;</span>
    Username
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
    //<span class="hljs-attr">...</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
      setUsername(e.target.value);
    }}
  /&gt;
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>In the code snippet above, <code>setName</code>, <code>setBio</code>, and <code>setUsername</code> are functions provided by the <code>useState</code> hook that update the state of <code>name</code>, <code>bio</code>, or <code>username</code>.</p>
<p>Next, the <code>Update Profile</code> button.</p>
<pre><code class="lang-xml">//...

 <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
     <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
     <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
     <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!record.isMutable</span> || <span class="hljs-attr">record.isMutating</span>}
     <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> updateProfile()}
 &gt;
    {record.isMutating ? "Updating..." : "Update Profile"}
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

//..
</code></pre>
<p>In the code snippet above, the button is disabled when the record is not mutable or is currently mutating. </p>
<p>When the button is clicked, it calls the <code>updateProfile</code> function, which is responsible for updating the user's profile information. If the record mutates, the button will display <code>Updating...</code>. Otherwise, it will display <code>Update Profile</code>.</p>
<p>You can test out the application similar to what is shown below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.loom.com/share/f2103bcb44c949f7bfdbd5cb531b0c71">https://www.loom.com/share/f2103bcb44c949f7bfdbd5cb531b0c71</a></div>
<p>Kindly find the complete code on <a target="_blank" href="https://github.com/Olanetsoft/decentralized-identity-project">GitHub repository here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post, you learn about Decentralized Identity, Decentralized Identifiers, Ceramic networks, why Ceramic network is useful, and how to build a decentralized identity profile with Ethereum on Ceramic Networks.</p>
<h3 id="heading-references">References</h3>
<ul>
<li><a target="_blank" href="https://github.com/ceramicnetwork/ceramic">Ceramic Network</a></li>
<li><a target="_blank" href="https://developers.ceramic.network/reference/">Ceramic Documentation</a></li>
<li><a target="_blank" href="https://ethereum.org/en/decentralized-identity/">Decentralized Identity - Ethereum</a></li>
</ul>
<p>I'd love to connect with you at <a target="_blank" href="https://twitter.com/olanetsoft"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/olubisi-idris-ayinde-05727b17a/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/Olanetsoft"><strong>GitHub</strong></a> | <a target="_blank" href="https://idrisolubisi.com/"><strong>Portfolio</strong></a></p>
<p>See you in my next article. Take care!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Web3? The Decentralized Internet of the Future Explained ]]>
                </title>
                <description>
                    <![CDATA[ By Nader Dabit If you’re reading this then you are a participant in the modern web. The web we are experiencing today is much different than what it was just 10 years ago. How has the web evolved, and more importantly – where is it going next? Also, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-web3/</link>
                <guid isPermaLink="false">66d4604be39d8b5612bc0dd0</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralized apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 08 Sep 2021 21:09:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/05/web3-future-of-web.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nader Dabit</p>
<p>If you’re reading this then you are a participant in the modern web. The web we are experiencing today is much different than what it was just 10 years ago. How has the web evolved, and more importantly – where is it going next? Also, why do any of these things matter?</p>
<p>If history has taught us anything, these changes will matter a lot. </p>
<p>In this article, I will lay out how the web has evolved, where's it going next, and why this matters.</p>
<p>Think about how the internet affects your life on a daily basis. Consider how society has changed as a result of the internet. Social media platforms. Mobile apps. And now the internet is going through another paradigm shift as we speak.</p>
<h2 id="heading-the-evolution-of-the-web"><strong>The Evolution of the Web</strong></h2>
<p>The web has evolved a lot over the years, and the applications of it today are almost unrecognizable from its most <a target="_blank" href="https://en.wikipedia.org/wiki/History_of_the_Internet">early days</a>. The evolution of the web is often partitioned into three separate stages: Web 1.0, Web 2.0, and Web 3.0.</p>
<h3 id="heading-what-is-web-10"><strong>What is Web 1.0?</strong></h3>
<p>Web 1.0 was the first iteration of the web. Most participants were consumers of content, and the creators were typically developers who build websites that contained information served up mainly in text or image format. Web 1.0 lasted approximately from 1991 to 2004.</p>
<p>Web 1.0 consisted of sites serving static content instead of dynamic HTML. Data and content were served from a static file system rather than a database, and sites didn't have much interactivity at all.</p>
<p>You can think of Web 1.0 as the read-only web.</p>
<h3 id="heading-what-is-web-20"><strong>What is Web 2.0?</strong></h3>
<p>Most of us have primarily experienced the web in its current form, commonly referred to as <a target="_blank" href="https://en.wikipedia.org/wiki/Web_2.0#top">web2</a>. You can think of web2 as the interactive and social web.</p>
<p>In the web2 world, you don’t have to be a developer to participate in the creation process. Many apps are built in a way that easily allows anyone to be a creator.</p>
<p>If you want to craft a thought and share it with the world, you can. If you want to upload a video and allow millions of people to see it, interact with it, and comment on it, you can do that too.</p>
<p>Web2 is simple, really, and because of its simplicity more and more people around the world are becoming creators.</p>
<p>The web in its current form is really great in many ways, but there are some areas where we can do a lot better.</p>
<h3 id="heading-web-20-monetization-and-security"><strong>Web 2.0 Monetization and Security</strong></h3>
<p>In the web2 world, many popular apps are following a common pattern in their life cycles. Think of some of the apps that you use on a daily basis, and how the following examples might apply to them.</p>
<h4 id="heading-monetization-of-apps"><strong>Monetization of Apps</strong></h4>
<p>Imagine the early days of popular applications like Instagram, Twitter, LinkedIn, or YouTube and how different they are today. The process usually goes something like this:</p>
<ol>
<li>Company launches an app</li>
<li>It onboards as many users as possible</li>
<li>Then it monetizes its user base</li>
</ol>
<p>When a developer or company launches a popular app, the user experience is often very slick as the app continues rising in popularity. This is the reason they are able to gain traction quickly in the first place.</p>
<p>At first, many software companies do not worry about monetization. They strictly focus on growth and on locking in new users – but eventually they have to start turning a profit.</p>
<p>They also need to consider the role of outside investors. Often the constraints of taking on things like venture capital negatively affect the life cycle, and eventually the user experience, of many applications that we use today.</p>
<p>If a company building an application takes in venture capital, its investors often expect a return on investment in the order of magnitude of tens or hundreds of what they paid in.</p>
<p>This means that, instead of going for some sustainable model of growth that they can sustain in a somewhat organic manner, the company is often pushed towards two paths: advertisements or selling personal data.</p>
<p>For many web2 companies like Google, Facebook, Twitter, and others, more data leads to more personalized ads. This leads to more clicks and ultimately more ad revenue. The exploitation and centralization of user data is core to how the web as we know and use it today is engineered to function.</p>
<h4 id="heading-security-and-privacy"><strong>Security and privacy</strong></h4>
<p>Web2 applications repeatedly experience <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_data_breaches">data breaches</a>. There are even <a target="_blank" href="https://haveibeenpwned.com/">websites</a> dedicated to keeping up with these breaches and telling you when your data has been compromised.</p>
<p>In web2, you don’t have any control over your data or how it is stored. In fact, companies often track and save user data without their users' consent. All of this data is then owned and controlled by the companies in charge of these platforms.</p>
<p>Users who live in countries where they have to worry about the negative consequences of free speech are also at risk.</p>
<p>Governments will often shut down servers or seize bank accounts if they believe a person is voicing an opinion that goes against their propaganda. With centralized servers, it is easy for governments to intervene, control, or shut down applications as they see fit.</p>
<p>Because banks are also digital and under centralized control, governments often intervene there as well. They can shut down access to bank accounts or limit access to funds during times of volatility, extreme inflation, or other political unrest.</p>
<p>Web3 aims to solve many of these shortcomings by fundamentally rethinking how we architect and interact with applications from the ground up.</p>
<h2 id="heading-what-is-web-30"><strong>What is Web 3.0?</strong></h2>
<p>There are a few fundamental differences between web2 and web3, but decentralization is at its core.</p>
<p>Web3 enhances the internet as we know it today with a few other added characteristics. web3 is:</p>
<ul>
<li>Verifiable</li>
<li>Trustless</li>
<li>Self-governing</li>
<li>Permissionless</li>
<li>Distributed and robust</li>
<li>Stateful</li>
<li>Native built-in payments</li>
</ul>
<p>In web3, developers don't usually build and deploy applications that run on a single server or that store their data in a single database (usually hosted on and managed by a single cloud provider).</p>
<p>Instead, web3 applications either run on blockchains, decentralized networks of many peer to peer nodes (servers), or a combination of the two that forms a <a target="_blank" href="https://thegraph.com/blog/modeling-cryptoeconomic-protocols-as-complex-systems-part-1">cryptoeconomic protocol</a>. These apps are often referred to as dapps (decentralized apps), and you will see that term used often in the web3 space.</p>
<p>To achieve a stable and secure decentralized network, network participants (developers) are incentivized and compete to provide the highest quality services to anyone using the service.</p>
<p>When you hear about web3, you'll notice that cryptocurrency is often part of the conversation. This is because cryptocurrency plays a big role in many of these protocols. It provides a financial incentive (tokens) for anyone who wants to participate in creating, governing, contributing to, or improving one of the projects themselves.</p>
<p>These protocols may often offer a variety of different services like compute, storage, bandwidth, identity, hosting, and other web services commonly provided by cloud providers in the past.</p>
<p>People can make a living by participating in the protocol in various ways, in both technical and non-technical levels.</p>
<p>Consumers of the service usually pay to use the protocol, similarly to how they would pay a cloud provider like AWS today. Except in web3, the money goes directly to the network participants.</p>
<p>In this, like in many forms of decentralization, you'll see that unnecessary and often inefficient intermediaries are cut out.</p>
<p>Many web infrastructure protocols like <a target="_blank" href="https://filecoin.io/blog/filecoin-circulating-supply/">Filecoin</a>, <a target="_blank" href="https://livepeer.com/">Livepeer</a>, <a target="_blank" href="https://www.arweave.org/">Arweave</a>, and <a target="_blank" href="https://thegraph.com/blog/the-graph-grt-token-economics">The Graph</a> (which is what I work with at Edge &amp; Node) have issued utility tokens that govern how the protocol functions. These tokens also reward participants at many levels of the network. Even native blockchain protocols like <a target="_blank" href="https://ethereum.org/en/">Ethereum</a> operate in this manner.</p>
<h3 id="heading-native-payments"><strong>Native payments</strong></h3>
<p>Tokens also introduce a native payment layer that is completely borderless and frictionless. Companies like Stripe and Paypal have created billions of dollars of value in enabling electronic payments.</p>
<p>These systems are overly complex and still do not enable true international interoperability between participants. They also require you to hand over your sensitive information and personal data in order to use them.</p>
<p>Crypto <a target="_blank" href="https://everest.link/category/0xc00f480db7754ce2e0f992a1080598e53fc511a0/">wallets</a> like <a target="_blank" href="https://metamask.io/">MetaMask</a> and <a target="_blank" href="https://toruswallet.io/">Torus</a> enable you to integrate easy, anonymous, and secure international payments and transactions into web3 applications.</p>
<p>Networks like Solana offer several hundred digit millisecond latency and transaction costs of a small fraction of a penny. Unlike the current financial system, users do not have to go through the traditional numerous, friction-filled steps to interact with and participate in the network. All they need to do is download or install a wallet, and they can start sending and receiving payments without any gatekeeping.</p>
<h3 id="heading-a-new-way-of-building-companies"><strong>A new way of building companies</strong></h3>
<p>Tokens also brings about the idea of tokenization and the realization of a <a target="_blank" href="https://www.oreilly.com/library/view/what-is-the/9781492072973/ch01.html">token economy</a>.</p>
<p>Take, for example, the current state of building a software company. Someone comes up with an idea, but in order to start building they need money in order to support themselves.</p>
<p>To get the money, they take on venture capital and give away a percentage of the company. This investment immediately introduces mis-aligned incentives that will, in the long run, not align well with building out the best user experience.</p>
<p>Also, if the company ever does become successful, it will take a very long time for anyone involved to realize any of the value, often leading to years of work without any real return on investment.</p>
<p>Imagine, instead, that a new and exciting project is announced that solves a real problem. Anyone can participate in building it or investing in it from day one. The company announces the release of x number of tokens, and give 10% to the early builders, put 10% for sale to the public, and set the rest aside for future payment of contributors and funding of the project.</p>
<p>Stakeholders can use their tokens to vote on changes to the future of the project, and the people who helped build the project can sell some of their holdings to make money after the tokens have been released.</p>
<p>People who believe in the project can buy and hold ownership, and people who think the project is headed in the wrong direction can signal this by selling their stake.</p>
<p>Because blockchain data is all completely public and open, purchasers have complete transparency over what is happening. This is in contrast to buying equity in private or centralized businesses where many things are often cloaked in secrecy.</p>
<p>This is already happening in the web3 space.</p>
<p>One example is the app <a target="_blank" href="https://radicle.xyz/blog/introducing-rad.html">Radicle</a> (a decentralized GitHub alternative) which allows stakeholders to participate in the <a target="_blank" href="https://everest.link/category/0x46aff9a161267c2c01f5ce1b6e3b717a77f21480/">governance</a> of their project. <a target="_blank" href="https://gitcoin.co/">Gitcoin</a> is another that allows developers to get paid in cryptocurrency for jumping in and working on Open Source issues. <a target="_blank" href="https://docs.yearn.finance/faq#governance">Yearn</a> allows stakeholders to participate in decision making and voting on proposals. <a target="_blank" href="https://uniswap.org/blog/uni/">Uniswap</a>, <a target="_blank" href="https://superrare.com/rare">SuperRare</a>, <a target="_blank" href="https://thegraph.com/blog/the-graph-grt-token-economics">The Graph</a>, <a target="_blank" href="https://audius.co/">Audius</a>, and countless other protocols and projects have issued tokens as a way to enable ownership, participation, and governance.</p>
<p><a target="_blank" href="https://linda.mirror.xyz/Vh8K4leCGEO06_qSGx-vS5lvgUqhqkCz9ut81WwCP2o">DAOs</a> (Decentralized Autonomous Organizations), which offer an alternative way to build what we traditionally thought of as a company, are gaining tremendous momentum and investment from both traditional developers and venture capital firms. </p>
<p>These types of organizations are tokenized and turn the idea of organizational structure on its head, offering real, liquid, and equitable ownership to larger portions of stakeholders and aligning incentives in new and interesting ways. </p>
<p>For example, <a target="_blank" href="https://www.fwb.help/">Friends with Benefits</a> is a DAO of web3 builders and artists, is about a year old, has a market cap of around $125 million as of this writing, and recently received <a target="_blank" href="https://tittlepress.com/crypto/1146487/">a $10 million round</a> of investment from <a target="_blank" href="https://a16z.com/">a16z</a>. </p>
<p>DAOs could encompass an entire post in and of themselves, but for now I'll just say that I think that they are the future of building products and (what we in the past thought of as) companies. <a target="_blank" href="https://coopahtroopa.mirror.xyz/_EDyn4cs9tDoOxNGZLfKL7JjLo5rGkkEfRa_a-6VEWw">Here is a good post</a> outlining the current DAO landscape.</p>
<h3 id="heading-how-identity-works-in-web3"><strong>How Identity Works in Web3</strong></h3>
<p>In web3, <a target="_blank" href="http://sinahab.com/identity-and-reputation-in-web-3/">Identity</a> also works much differently than what we are used to today. Most of the time in web3 apps, identities will be tied to the wallet address of the user interacting with the application.</p>
<p>Unlike web2 authentication methods like OAuth or email + password (that almost always require users to hand over sensitive and personal information), wallet addresses are completely anonymous unless the user decides to tie their own identity to it publicly.</p>
<p>If the user chooses to use the same wallet across multiple dapps, their identity is also seamlessly transferable across apps, which lets them build up their reputation over time.</p>
<p>Protocols and tools like <a target="_blank" href="https://ceramic.network/">Ceramic</a> and <a target="_blank" href="https://idx.xyz/">IDX</a> already allow developers to build self-sovereign identity into their applications to replace traditional authentication and identity layers. The Ethereum foundation also has <a target="_blank" href="https://notes.ethereum.org/@djrtwo/sign-in-with-ethereum-RFP">a working RFP</a> for defining a specification for "Sign in with Ethereum" which would help provide a more streamlined and documented way to do this going forward. <a target="_blank" href="https://twitter.com/BrantlyMillegan/status/1402388133086367751">This</a> is also a good thread that outlines some of the ways that this would enhance traditional authentication flows.</p>
<h2 id="heading-how-to-build-on-web3"><strong>How to Build on Web3</strong></h2>
<p>I'm a developer who recently transitioned into the web3 space from a traditional development background. So I wanted to start building to get a sense of what the development experience felt like. And I wanted to get an understanding of the types of apps that we can build today.</p>
<p>I dove right in and decided to document some of the things I was doing in a couple of blog posts.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/breaking-into-ethereum-crypto-web3-as-a-developer/">How to Get Into Ethereum, Crypto, and Web3 as a Developer</a> – This is an introduction to the space in general, coming from a developer, for developers looking to break into the industry.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/full-stack-ethereum-development/">The Complete Guide to Full Stack Ethereum Development</a> – This is a tutorial that teaches you how to build out your first dapp.</p>
<p><a target="_blank" href="https://dev.to/dabit3/the-complete-guide-to-full-stack-solana-development-with-react-anchor-rust-and-phantom-3291">The Complete Guide to Full Stack Solana Development with React, Anchor, Rust, and Phantom</a> - This guide dives into Solana to show you how to build a full stack dapp.</p>
<p>If you are interested in learning more about web3 in general, you can check out these posts:</p>
<p><a target="_blank" href="https://dev.to/dabit3/the-new-creator-economy-daos-community-ownership-and-cryptoeconomics-lnl">The New Creator Economy - DAOs, Community Ownership, and Cryptoeconomics</a></p>
<p><a target="_blank" href="https://www.notboring.co/p/the-value-chain-of-the-open-metaverse">The Value Chain of the Open Metaverse</a></p>
<p><a target="_blank" href="https://coopahtroopa.mirror.xyz/gWY6Kfebs9wHdfoZZswfiLTBVzfKiyFaIwNf2q8JpgI">The Rise of Micro-Economies</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Technical Guide to IPFS – the Decentralized Storage of Web3 ]]>
                </title>
                <description>
                    <![CDATA[ By Lukas Lukac When you think about developing a decentralized application, a blockchain like Ethereum probably comes to mind. Blockchain is fantastic for managing state, automating processes via Smart Contracts, and exchanging economic value. You ca... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/technical-guide-to-ipfs-decentralized-storage-of-web3/</link>
                <guid isPermaLink="false">66d46179d7a4e35e384349c3</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ipfs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 21 Jun 2021 16:38:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/tech_guide_ipfs_web3coach_banner-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Lukas Lukac</p>
<p>When you think about developing a decentralized application, a blockchain like Ethereum probably comes to mind.</p>
<p>Blockchain is fantastic for managing state, automating processes via Smart Contracts, and exchanging economic value.</p>
<p>You can <a target="_blank" href="https://www.freecodecamp.org/news/build-a-blockchain-in-golang-from-scratch/">follow this tutorial to learn blockchain by building one from scratch yourself</a> if you want to learn more.</p>
<p><strong>But where do you store your application's content?</strong> Images? Videos? The application's website front-end composed of all the HTML, CSS, and JS files? Are your application and your users' content loaded from a centralized AWS server?</p>
<p>Storing the content on the blockchain would be expensive and inefficient.</p>
<p>Your blockchain application needs decentralized storage!</p>
<p>In this tutorial, I will introduce you to the InterPlanetary File System, or IPFS. You will learn:</p>
<ol>
<li>How to store and retrieve content from a decentralized storage</li>
<li>How to run your IPFS node</li>
<li>All about the low-level internals of the IPFS protocol</li>
<li>And we'll read a Wikipedia website stored on IPFS</li>
</ol>
<p>Ready? Let's go.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-the-ipfs">What is the IPFS?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-an-ipfs-node">How to setup an IPFS node</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-ipfs">How to store and retrieve IPFS content using the CLI and HTTP</a></li>
<li><a class="post-section-overview" href="#heading-how-ipfs-content-addressing-works">What is CID – the IPFS content-based identifier</a></li>
<li><a class="post-section-overview" href="#heading-how-ipfs-stores-content-on-the-file-system">How to reverse engineer the IPFS datastore</a></li>
<li><a class="post-section-overview" href="#heading-how-to-connect-an-ipfs-node-to-the-p2p-network">How to connect an IPFS node to a decentralized network</a></li>
<li><a class="post-section-overview" href="#heading-how-nodes-exchange-data-using-the-bitswap-protocol">How to exchange data using the peer-to-peer Bitswap protocol</a></li>
<li><a class="post-section-overview" href="#heading-how-to-persist-content-from-the-p2p-network">How to persist content from the peer-to-peer network</a></li>
</ul>
<h2 id="heading-what-is-the-ipfs">What is the IPFS?</h2>
<p>The InterPlanetary File System, or IPFS for short, is a peer-to-peer hypermedia protocol designed to make the web faster, safer, and more open.</p>
<p><strong>IPFS is a protocol for storing and sharing content.</strong> As in the blockchain world, every user is running its node (server). The nodes can communicate between each other and exchange files.</p>
<h3 id="heading-what-is-unique-about-ipfs">What is unique about IPFS?</h3>
<p>First of all, the <strong>IPFS is decentralized</strong> because it loads the content from thousands of peers instead of one centralized server. Every piece of data is cryptographically hashed, resulting in a safe, unique <strong>content identifier</strong>: CID.</p>
<p>Store your website in IPFS to avoid censorship and a single point of failure. Your personal IPFS node goes offline? Don't worry, the website will still load from other nodes across the globe serving it.</p>
<p>For example, suppose your government bans Wikipedia. In that case, you can still access a decentralized version of Wikipedia indexed on April 17th by loading it from the IPFS peer-to-peer network persisted under CID:</p>
<blockquote>
<p><strong>"</strong>QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX"</p>
</blockquote>
<p>Second, the integrity of <strong>IPFS content can be cryptographically verified.</strong></p>
<p>And finally, <strong>the IPFS content is de-duplicated.</strong> If you tried storing two identical 1MB files in the same IPFS node, they would be stored only once, eliminating the duplication, because their hash would produce an identical <strong>CID.</strong></p>
<h2 id="heading-how-to-setup-an-ipfs-node">How to Setup an IPFS Node</h2>
<h3 id="heading-install-ipfs">Install IPFS</h3>
<p>Open the <a target="_blank" href="https://docs.ipfs.io/install/">official IPFS docs</a> installation page and follow the instructions depending on your operating system (Windows, macOS, Linux). I will be documenting the Ubuntu installation process below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://docs.ipfs.io/install/command-line/#official-distributions">https://docs.ipfs.io/install/command-line/#official-distributions</a></div>
<p>I prefer compiling the <a target="_blank" href="http://github.com/ipfs/go-ipfs">ipfs/go-ipfs</a> repository from scratch to debug the code when needed, and let's be honest: GoLang rocks.</p>
<h4 id="heading-compile-the-codebase-in-go">Compile the codebase in Go</h4>
<p>Clone the repository and run the install script in the Makefile.</p>
<pre><code>git clone https:<span class="hljs-comment">//github.com/ipfs/go-ipfs.git</span>
cd go-ipfs
git checkout v0<span class="hljs-number">.8</span><span class="hljs-number">.0</span>-rc2
make install
</code></pre><p>Or download pre-compiled IPFS:</p>
<pre><code>sudo snap install ipfs
</code></pre><h3 id="heading-validate-the-installation">Validate the installation</h3>
<p>Let's be honest. Go is amazing and compiling the codebase yourself is bad-ass and decentralized. The resulted binary will be created in your <code>$GOPATH</code>.</p>
<pre><code>which ipfs
&gt; <span class="hljs-regexp">/home/</span>web3coach/go/bin/ipfs

ipfs version
&gt; ipfs version <span class="hljs-number">0.8</span><span class="hljs-number">.0</span>-rc2
</code></pre><h3 id="heading-initialize-a-new-node">Initialize a new node</h3>
<p>Run <code>ipfs init</code> to create your new node. By default, it will create a folder and store all the data in <code>~/.ipfs</code> You can tweak this by configuring the <code>IPFS_PATH</code> ENV variable.</p>
<pre><code>IPFS_PATH=<span class="hljs-regexp">/home/</span>web3coach/.ipfs_tutorial ipfs init

&gt; generating ED25519 keypair...done
&gt; peer identity: <span class="hljs-number">12</span>D3Koo...dNs
&gt; initializing IPFS node at /home/web3coach/.ipfs_tutorial
</code></pre><p>Your node is now fully initialized, awaiting your content.</p>
<h2 id="heading-how-to-use-ipfs">How to Use IPFS</h2>
<h3 id="heading-add-content">Add content</h3>
<p>IPFS can handle all kinds of different data types – from simple strings to images, videos, and websites.</p>
<p>Start by storing a short message <code>hello IPFS world by Web3Coach</code>:</p>
<pre><code>echo <span class="hljs-string">"hello IPFS world by Web3Coach. BTW: Ethereum FTW"</span> | ipfs add
</code></pre><p>The content is now stored and <strong>indexed by a cryptographic hash function</strong> returning its unique content identifier (CID):</p>
<pre><code>&gt; added QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
&gt; <span class="hljs-number">49</span> B / <span class="hljs-number">49</span> B [========] <span class="hljs-number">100</span>%
</code></pre><p>Your IPFS node will generate the same CID on your local file system as in this tutorial. That's because IPFS hashes the content and returns its unique fingerprint, and as we know, a secure hash function will always return the same output given the same input.</p>
<h3 id="heading-pin-content">Pin content</h3>
<p>When you <code>add</code> content, you add it ONLY to your local node. The <strong>content does NOT automatically replicate</strong> across the entire network – this is a common confusion between IPFS users and developers.</p>
<p>When you store content via the <code>add</code> command, IPFS will also execute the <code>pin</code> command by default:</p>
<pre><code>ipfs pin add QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
</code></pre><p>To replicate content, <strong>you must take your node online, join the p2p network, and <code>pin</code> the specific CID from another node.</strong> You will learn how to do this further in the tutorial and find out what happens in the background.</p>
<h3 id="heading-read-content">Read content</h3>
<p>Copy-paste the <strong>CID</strong> to IPFS <code>cat</code> command to read it from disk:</p>
<pre><code>ipfs cat QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
&gt; hello IPFS world by Web3Coach. BTW: Ethereum FTW
</code></pre><p>The <code>add</code> , <code>pin</code> and <code>cat</code> commands are the most significant IPFS functions, and you just learned them. Congrats, well done!</p>
<h2 id="heading-how-ipfs-content-addressing-works">How IPFS Content Addressing Works</h2>
<p>What is QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z?</p>
<p>It’s a self-describing content-based identifier.</p>
<p>What does "self-describing" actually mean? It means that by splitting the string following the IPFS specification, you will know everything you need to know about the data it indexes.</p>
<ul>
<li>what CID version it is</li>
<li>how to read the CID string (base32? base58? hex?)</li>
<li>how data is encoded</li>
<li>what hash function fingerprinted the data</li>
<li>the hash function's length</li>
</ul>
<p>The IPFS team built a convenient <a target="_blank" href="https://cid.ipfs.io/">website</a> for analyzing a CID:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/cid_analyse.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>By parsing the <strong>QmRBkKi1P…p6z</strong> CID, you discover:</p>
<ul>
<li>the CID follows version 0 spec because it starts with <strong>Qm</strong></li>
<li>the <strong>QmRBkKi1P…p6z</strong> string is encoded using <code>base58btc</code></li>
<li>the data "<strong>hello IPFS world by Web3Coach. BTW: Ethereum FTW</strong>" were encoded as <strong>DAG Protobuf</strong> under a codec <strong>0x70</strong> before being stored on disk</li>
<li>the hash code <strong>0x12</strong> signals the data fingerprint obtained using the <code>sha256</code> hash function, producing a unique 32 byte long digest</li>
</ul>
<p>"Slightly more complicated" than a simple auto-increment INT in a MySQL table... but extraordinarily potent and future proof. Let me explain.</p>
<h3 id="heading-cid-versions">CID Versions</h3>
<p>There are currently two CID versions: <strong>v0</strong> and <strong>v1</strong>.</p>
<p><strong>The CID v0</strong> is not flexible and limited to:</p>
<ul>
<li>start with characters "Qm"</li>
<li>where the CID string is encoded using base58btc</li>
<li>the data is encoded with dag-pb by default</li>
<li>can be converted to CID version 1, but not the other way around</li>
</ul>
<p><strong>The CID v1</strong> leverages several prefixes for maximum interoperability:</p>
<blockquote>
<p>CID v1 = Multibase + Multicodec + Multihash</p>
</blockquote>
<p>In another words, parsing the binary into a CID v1 string follows this spec:</p>
<p><code>&lt;base&gt;&lt;codec&gt;&lt;hash-function&gt;&lt;hash-length&gt;&lt;hash-digest&gt;</code></p>
<h3 id="heading-multihash">Multihash</h3>
<p>To be future-proof and enable different hashing algorithms, IPFS created the following standard:</p>
<p>CODE : SIZE : DIGEST</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> DecodedMultihash <span class="hljs-keyword">struct</span> {
   Code   <span class="hljs-keyword">uint64</span> <span class="hljs-comment">// 0x12</span>
   Name   <span class="hljs-keyword">string</span> <span class="hljs-comment">// sha2-256</span>
   Length <span class="hljs-keyword">int</span>    <span class="hljs-comment">// 32 bytes</span>
   Digest []<span class="hljs-keyword">byte</span> <span class="hljs-comment">// Digest holds the raw multihash bytes</span>
}
</code></pre>
<p>Multihash has many advantages. When computers are more powerful in 5 years, you could use a stronger hash function like <code>sha3-512</code> as long as you configure the corresponding <code>0x13</code> code as the Multihash in the CID prefix – the protocol will be ready to handle it.</p>
<h3 id="heading-multicodec">Multicodec</h3>
<p>The <code>Code</code> attribute tells you <strong>how data is encoded</strong> before being stored on disk, so you know <strong>how to decode</strong> it back when the user wants to read it. It could be anything CBOR, Protobuf, JSON…</p>
<p>IPFS maintains a public list of all <a target="_blank" href="https://github.com/multiformats/multicodec/blob/master/table.csv">possible codecs</a>. The most common codecs are:</p>
<pre><code>raw       | ipld      | <span class="hljs-number">0x55</span> | raw binary
dag-pb    | ipld      | <span class="hljs-number">0x70</span> | MerkleDAG protobuf
dag-cbor  | ipld      | <span class="hljs-number">0x71</span> | MerkleDAG cbor

<span class="hljs-comment">// but you could also encode Ethereum blocks on IPFS!</span>
eth-block | ipld      | <span class="hljs-number">0x90</span> | Ethereum Block (RLP)
</code></pre><h3 id="heading-multibase">Multibase</h3>
<p>The problem with CID v0 and the <code>base58btc</code> encoding is the lack of interoperability between environments. A multibase prefix adds support for different encodings like <code>base32</code> to achieve DNS-friendly names.</p>
<p><a target="_blank" href="https://github.com/multiformats/multibase/blob/master/multibase.csv">A table with all Multibase encodings</a>:</p>
<pre><code>encoding  | code
base32    | b
base58btc | z
base64    | m
</code></pre><p>You spot a Multibase encoding based on the first character:</p>
<p><strong>Q</strong>mRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z</p>
<ul>
<li>is CID <code>v0</code></li>
<li>the CID string is encoded with <code>base58btc</code></li>
</ul>
<p><strong>b</strong>afybeibkjmxftowv4lki46nad4arescoqc7kdzfnjkqux257i4jonk44w4</p>
<ul>
<li>CID <code>v1</code></li>
<li>the CID string is encoded with <code>base32</code></li>
</ul>
<p>Both CID versions can retrieve the same content because after you strip the encoding, it's the <strong>Multihash</strong> that indexes the blocks on the datastore level. In contrast, Multibase is only used to pass the CID correctly in different environments (CLI, URL, DNS).</p>
<pre><code>ipfs cat QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
&gt; hello IPFS world by Web3Coach. BTW: Ethereum FTW

<span class="hljs-comment">// equivalent to</span>
ipfs cat bafybeibkjmxftowv4lki46nad4arescoqc7kdzfnjkqux257i4jonk44w4
&gt; hello IPFS world by Web3Coach. BTW: Ethereum FTW
</code></pre><p>Phew. Things got "slightly complex" very quickly.</p>
<p>Speaking of complicated topics, IPFS is powerful because it doesn't treat content as just "data" but as <strong>data structures</strong> – specifically <strong>InterPlanetary Linked Data</strong> structure: <a target="_blank" href="https://docs.ipld.io/#what-is-ipld">IPLD</a>. In short, you can implement any file-system, database, or structure on top of IPLD.</p>
<p>For example, you can store all Ethereum blocks on IPFS as long as you set <code>eth-block</code> and <code>eth-tx</code> codecs and register an appropriate Decoder when working with the IPLD graph.</p>
<p>Let's dig into it and explore the default IPLD structure with the DAG Protobuf codec.</p>
<h2 id="heading-how-ipfs-stores-content-on-the-file-system">How IPFS Stores Content on the File-system</h2>
<p>“The <code>ipfs add</code> command will create a <strong>Merkle DAG</strong> out of the data following the <a target="_blank" href="https://github.com/ipfs/go-unixfs/blob/master/pb/unixfs.proto">UnixFS data format</a>. Your content is broken down into <strong>blocks</strong> using a <strong>Chunker</strong>, and then arranged in a <strong>tree-like structure using 'link nodes'</strong> to tie them together. The returned CID is the hash of the root node in the DAG.”</p>
<p>Confused?</p>
<p>Rolling back to basics.</p>
<h3 id="heading-lets-explore-the-nodes-data-directory">Let's explore the node’s data directory</h3>
<p>At the beginning of this tutorial, when you initialized your IPFS node with the <code>ipfs init</code> command, you generated the following directory:</p>
<pre><code><span class="hljs-keyword">export</span> IPFS_PATH=<span class="hljs-regexp">/home/</span>web3coach/.ipfs_tutorial
cd $IPFS_PATH
~/.ipfs_tutorial  tree

.
├── blocks
│   ├── <span class="hljs-number">6</span>Y
│   │   └── CIQA4XCGRCRTCCHV7XSGAZPZJOAOHLPOI6IQR3H6YQ.data
├── config
├── datastore
│   ├── <span class="hljs-number">000002.</span>ldb
│   ├── <span class="hljs-number">000003.</span>log
│   ├── CURRENT
│   ├── CURRENT.bak
│   ├── LOCK
│   ├── LOG
│   └── MANIFEST<span class="hljs-number">-000004</span>
├── datastore_spec
├── keystore
└── version
</code></pre><p>From a very <strong>high-level point of view:</strong></p>
<ul>
<li><code>blocks</code> — IPFS stores all the chunked data here, although the <code>go-ipfs</code> flexible interfaces <strong>allow you to swap the storage implementation</strong> for a different database</li>
<li><code>config</code> — Node’s settings (file-system, identity, specs, networking)</li>
<li><code>datastore</code> — Indexing and other logic</li>
</ul>
<p>Don't take my word for it. Create a new file with the following content on your local file system and then add it to IPFS:</p>
<pre><code>hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs

ls -la hello_world.txt
&gt; <span class="hljs-number">131</span> bytes hello_world.txt

ipfs add hello_world.txt
&gt; added QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH
</code></pre><p>Reverse engineering the <code>go-ipfs</code> codebase, this is what is happening behind the scenes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/IPFS_UNIX_FS_Protobuf.png" alt="Image" width="600" height="400" loading="lazy">
<em>IPFS UnixFS adding a new file and converting it to a block</em></p>
<p>Validate the persistence process by inspecting the blocks directory. You will find the content was written under the Multihash Datastore Key using <strong>DAG Protobuf encoding</strong> (131 bytes + Protobuf extra encoding).</p>
<pre><code>ls -la blocks/PV/
&gt; <span class="hljs-number">142</span> CIQAQIXXW2OAQSKZ6AQ2SDEYRZXWPDZNJUAFR3YORYN75I5CQ3LHPVQ.data

vim blocks/PV/CIQA...
&lt;<span class="hljs-number">8</span>b&gt;^A^H^B^R&lt;<span class="hljs-number">83</span>&gt;^Ahello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs^X&lt;<span class="hljs-number">83</span>&gt;^A
</code></pre><p>To interact with your raw content, use the <code>ipfs object</code> command.</p>
<pre><code>ipfs object get QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012�\u0001hello IPFS world by Web3Coach. Testing DAGs\nhello IPFS world by Web3Coach. Testing DAGs\nhello IPFS world by Web3Coach. Testing DAGs\u0018�\u0001"</span>
}
</code></pre>
<ul>
<li>Because the content is only 131 bytes, it fits to one DAG Node</li>
<li>The Dag Node is persisted as one Block on disk</li>
<li>The DAG Node has zero links to other Nodes</li>
</ul>
<p>Time to experiment.</p>
<p>Add the same file again, but configure the Chunker to 64 bytes (or use a bigger file, but a smaller Chunker will demonstrate the concept better).</p>
<pre><code>ipfs add --chunker=size<span class="hljs-number">-64</span> hello_world.txt

&gt; <span class="hljs-number">131</span> bytes QmTwtTQgrTaait2qWXYjTsEZiF4sT7CD4U87VqQ27Wnsn8
</code></pre><p><strong>You get a new CID!</strong> </p>
<p>IPFS split the content into 4 DAG Nodes and wrote 4 Blocks with data encoded in DAG Protobuf format to disk.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/ipfs_chunker_4.png" alt="Image" width="600" height="400" loading="lazy">
<em>IPFS splits a file into multiple chunks (DAG Nodes + Blocks)</em></p>
<pre><code>ipfs object get QmTwtTQgrTaait2qWXYjTsEZiF4sT7CD4U87VqQ27Wnsn8 | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmTbsuUYzy3nT6NApb5t7VUq3iQKZXrJJJY2j1miMVgaJU"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">72</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmNy9iFF8uU1Cn7trxpSgqxMsjmi4zQ7xgyEgsWff5rnfH"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">72</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmdEitCfYgBNxLhxTNvdLaDmTypSAWkGErjw33VZxUbWK3"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">11</span>
    }
  ],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0018�\u0001 @ @ \u0003"</span>
}
</code></pre>
<p>The ultimate test is to retrieve each DAG Node's data and verify the text is split into three chunks:</p>
<p><strong>DAG Protobuf Node 1:</strong></p>
<pre><code>ipfs object get QmTbsuUYzy3nT6NApb5t7VUq3iQKZXrJJJY2j1miMVgaJU | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012@hello IPFS world by Web3Coach. Testing DAGs\nhello IPFS world by \u0018@"</span>
}
</code></pre>
<p><strong>DAG Protobuf Node 2:</strong></p>
<pre><code>ipfs object get QmNy9iFF8uU1Cn7trxpSgqxMsjmi4zQ7xgyEgsWff5rnfH | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012@Web3Coach. Testing DAGs\nhello IPFS world by Web3Coach. Testing D\u0018@"</span>
}
</code></pre>
<p><strong>DAG Protobuf Node 3:</strong></p>
<pre><code>ipfs object get QmdEitCfYgBNxLhxTNvdLaDmTypSAWkGErjw33VZxUbWK3 | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012\u0003AGs\u0018\u0003"</span>
}
</code></pre>
<h3 id="heading-whats-the-benefit-of-splitting-the-content-into-multiple-chunks-and-use-content-addressing-and-cids">What’s the benefit of splitting the content into multiple chunks and use content-addressing and CIDs?</h3>
<ul>
<li>Data deduplication</li>
<li>Decentralization</li>
</ul>
<p>Next time you want to store a file that would share part of the content with another file, IPFS wouldn't store a duplicate block! It would instead link to an already existing DAG Node and only store the new, unique chunks.</p>
<p>Converting content to a directed acyclic graph with many nodes also helps to load the content in parallel. For example, a blog post, image, entire Wikipedia website can load from multiple IPFS peer nodes. Your node then verifies the integrity of received blocks by re-hashing all the data content and asserting the constructed CID.</p>
<p>You've now learned the bread and butter of IPFS – excellent progress!</p>
<p>One more critical component left: <strong>Networking</strong>.</p>
<h2 id="heading-how-to-connect-an-ipfs-node-to-the-p2p-network">How to Connect an IPFS Node to the p2p Network</h2>
<p>Every node has its <code>config</code> file generated during the <code>ipfs init</code> execution.</p>
<p>Open it.</p>
<pre><code>vim $IPFS_PATH/config
</code></pre><p>Other settings aside, you find your node’s <strong>Identity (PeerID + Private Key):</strong></p>
<pre><code><span class="hljs-string">"Identity"</span>: {
    <span class="hljs-string">"PeerID"</span>: <span class="hljs-string">"12D3KooWCBmDtsvFwDHEr..."</span>,
    <span class="hljs-string">"PrivKey"</span>: <span class="hljs-string">"CAESQCj..."</span>
  },
</code></pre><p>And a list of <strong>Bootstrap addresses:</strong></p>
<pre><code class="lang-json"><span class="hljs-string">"Bootstrap"</span>: [
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59b...gU1ZjYZcYW3dwt"</span>,
    <span class="hljs-string">"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMG...UtfsmvsqQLuvuJ"</span>,
    <span class="hljs-string">"/ip4/104.131.131.82/udp/4001/quic/p2p/Qma...UtfsmvsqQLuvuJ"</span>,
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooD5...BMjTezGAJN"</span>,
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2Ec...J16u19uLTa"</span>,
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnM...Ucqanj75Nb"</span>
  ],
</code></pre>
<p>You connect to other peers in the IPFS network by running the <code>ipfs daemon</code> command. Your node will first establish a p2p connection with Protocol Labs (company behind IPFS) bootstrap nodes, and through these bootstrap nodes, you will further find hundreds of other peers.</p>
<pre><code>ipfs daemon 

&gt; Initializing daemon...

Swarm listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /ip4/<span class="hljs-number">172.17</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip4/<span class="hljs-number">172.17</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /ip6/::<span class="hljs-number">1</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip6/::<span class="hljs-number">1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /p2p-circuit
Swarm announcing /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">4001</span>
Swarm announcing /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm announcing /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/tcp/<span class="hljs-number">4001</span>
Swarm announcing /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm announcing /ip4/<span class="hljs-number">88.212</span><span class="hljs-number">.40</span><span class="hljs-number">.160</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm announcing /ip6/::<span class="hljs-number">1</span>/tcp/<span class="hljs-number">4001</span>
Swarm announcing /ip6/::<span class="hljs-number">1</span>/udp/<span class="hljs-number">4001</span>/quic

API server listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">5001</span>
<span class="hljs-attr">WebUI</span>: http:<span class="hljs-comment">//127.0.0.1:5001/webui</span>

Gateway (readonly) server listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">8080</span>
Daemon is ready!
</code></pre><p>Keep in mind, that by running the <strong>IPFS Daemon</strong>:</p>
<ol>
<li>Your node connects to the p2p net and can <strong>exchange blocks with other nodes</strong></li>
<li><strong>Other peers can access the content on your node</strong> – as long they know the CIDs</li>
<li>Peers will talk to you through TCP, UDP on port: <strong>4001</strong></li>
<li>If you have an application, start storing and consuming your node's content via the HTTP API listening on port: <strong>5001</strong>.</li>
</ol>
<p>For application development, I recommend the official <a target="_blank" href="https://www.npmjs.com/package/ipfs-http-client">ipfs-http-client</a> library in JS exposing all the core commands – add, cat, object and others. It will speed up your coding progress.</p>
<p>I will use <code>curl</code> to interact with the API to keep this tutorial "short."</p>
<h3 id="heading-how-to-use-the-ipfs-http-api">How to use the IPFS HTTP API:</h3>
<p><strong>Add content:</strong> :5001/api/v0/add</p>
<pre><code>curl -X POST -F file=@/home/web3coach/go/src/github.com/ipfs/go-ipfs/hello_world.txt <span class="hljs-string">"http://127.0.0.1:5001/api/v0/add"</span>
</code></pre><pre><code class="lang-json">{<span class="hljs-attr">"Name"</span>:<span class="hljs-string">"hello_world.txt"</span>,<span class="hljs-attr">"Hash"</span>:<span class="hljs-string">"QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH"</span>,<span class="hljs-attr">"Size"</span>:<span class="hljs-string">"142"</span>}
</code></pre>
<p><strong>Read content:</strong> :5001/api/v0/cat</p>
<pre><code>curl -X POST <span class="hljs-string">"http://127.0.0.1:5001/api/v0/cat?arg=QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH"</span>

hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
</code></pre><p>See the <a target="_blank" href="https://docs.ipfs.io/reference/http/api/#getting-started">official HTTP API docs</a> for the complete list of available commands.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/Screenshot-from-2021-05-26-19-54-49.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-peer-with-other-ipfs-nodes">How to peer with other IPFS nodes</h3>
<p>Fun experiment. Use the <code>ipfs swarm</code> command and check how many nodes you already discovered:</p>
<pre><code>ipfs swarm peers

&gt; 
<span class="hljs-regexp">/ip4/</span><span class="hljs-number">85.70</span><span class="hljs-number">.151</span><span class="hljs-number">.37</span>/tcp/<span class="hljs-number">4001</span>/p2p/QmSuCtR...aPq6h4AczBPZaoej
/ip4/<span class="hljs-number">91.121</span><span class="hljs-number">.168</span><span class="hljs-number">.96</span>/udp/<span class="hljs-number">54001</span>/quic/p2p/QmeC7H..<span class="hljs-number">.8</span>j2TQ99esS
...
...
...

ipfs swarm peers | wc -l
&gt; <span class="hljs-number">186</span>
</code></pre><p>Bravo! You are connected to 186 peers forming an unstoppable peer-to-peer web.</p>
<h3 id="heading-what-about-privacy">What about privacy?</h3>
<p>Other peers can access all the content you add to your IPFS node. There is <strong>no built-in privacy mechanism, so never add unencrypted, sensitive/personal content</strong> to IPFS!</p>
<h2 id="heading-how-nodes-exchange-data-using-the-bitswap-protocol">How Nodes Exchange Data Using the Bitswap Protocol</h2>
<p>So far, you only interacted with your local content. Imagine you live in a place where the local government decided to block access to Wikipedia. No bueno. </p>
<p>Fortunately, because someone added all the Wikipedia content to IPFS, you can run your node and access its knowledge by requesting the content from peers across the globe.</p>
<p><a target="_blank" href="http://localhost:8080/ipfs/QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX/wiki/Anasayfa.html">http://localhost:8080/ipfs/QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX/wiki/Anasayfa.html</a></p>
<p>The DAG Service will check the blocks in your datastore, but it won’t find any for QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX.</p>
<p>The node will therefore create a network request to its peers using the Bitswap protocol via <code>exchange</code> component:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getBlock</span><span class="hljs-params">(ctx context.Context, c cid.Cid, bs blockstore.Blockstore, fget <span class="hljs-keyword">func</span>()</span> <span class="hljs-title">exchange</span>.<span class="hljs-title">Fetcher</span>) <span class="hljs-params">(blocks.Block, error)</span></span> {
   err := verifcid.ValidateCid(c) <span class="hljs-comment">// hash security</span>
   <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, err
   }

   block, err := bs.Get(c)
   <span class="hljs-keyword">if</span> err == <span class="hljs-literal">nil</span> {
      <span class="hljs-keyword">return</span> block, <span class="hljs-literal">nil</span>
   }

   <span class="hljs-keyword">if</span> err == blockstore.ErrNotFound &amp;&amp; fget != <span class="hljs-literal">nil</span> {
      f := fget() <span class="hljs-comment">// Don't load the exchange until we have to</span>

      log.Debug(<span class="hljs-string">"Blockservice: Searching bitswap"</span>)
      blk, err := f.GetBlock(ctx, c)
</code></pre>
<p>Internally, the CID is added to a <code>Wantlist</code> :</p>
<pre><code class="lang-go"><span class="hljs-comment">// Wantlist is a raw list of wanted blocks and their priorities</span>
<span class="hljs-keyword">type</span> Wantlist <span class="hljs-keyword">struct</span> {
   set <span class="hljs-keyword">map</span>[cid.Cid]Entry
}

<span class="hljs-comment">// Entry is an entry in a want list, consisting of a cid and its priority</span>
<span class="hljs-keyword">type</span> Entry <span class="hljs-keyword">struct</span> {
   Cid      cid.Cid
   Priority <span class="hljs-keyword">int32</span>
   WantType pb.Message_Wantlist_WantType
}
</code></pre>
<p>And the <code>PeerManager</code> will iterate over known peers and their peers until it finds an online node capable of providing the wanted Block:</p>
<pre><code class="lang-go"><span class="hljs-comment">// PeerManager manages a pool of peers and sends messages to peers in the pool.</span>
<span class="hljs-keyword">type</span> PeerManager <span class="hljs-keyword">struct</span> {
   pqLk sync.RWMutex

   peerQueues <span class="hljs-keyword">map</span>[peer.ID]PeerQueue
   pwm        *peerWantManager

   createPeerQueue PeerQueueFactory
   ctx             context.Context

   psLk         sync.RWMutex
   sessions     <span class="hljs-keyword">map</span>[<span class="hljs-keyword">uint64</span>]Session
   peerSessions <span class="hljs-keyword">map</span>[peer.ID]<span class="hljs-keyword">map</span>[<span class="hljs-keyword">uint64</span>]<span class="hljs-keyword">struct</span>{}

   self peer.ID
}
</code></pre>
<p>The result?</p>
<p>You can consume the forbidden fruits from Wikipedia directly from <strong>localhost:8080</strong>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/wikipedia_local_ipfs.png" alt="Image" width="600" height="400" loading="lazy">
<em>IPFS loading Wikipedia on your local node</em></p>
<p>Uncensorable, decentralized storage :)</p>
<h2 id="heading-how-to-persist-content-from-the-p2p-network">How to Persist Content from the p2p Network</h2>
<p>You must know a crucial thing about IPFS: the content you access from the network will be garbage collected unless you <strong>pin</strong> it.</p>
<h3 id="heading-pinning-and-garbage-collection">Pinning and Garbage Collection</h3>
<p>At the beginning of the article you learned that content added to your node via the <code>ipfs add</code> command or its HTTP equivalent is pinned by default.</p>
<pre><code>ipfs pin ls | grep QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH
&gt; QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH recursive
</code></pre><p><strong>Pinned blocks are marked as NOT TO BE DELETED</strong> when the Garbage Collection runs.</p>
<p>Why would the Garbage Collection delete some blocks? To keep your node healthy by controlling its storage size.</p>
<p>By reading Wikipedia or by accessing any other content from the p2p network, IPFS downloads its blocks. As the node's datastore grows in size, a periodic garbage collection process will prune unpinned blocks, so you don't run out of disk space.</p>
<p>If you want your content to be accessible 24/7 on the IPFS network, I recommend that you use a reliable remote provider to pin it: <strong><a target="_blank" href="https://infura.io/docs/ipfs?utm_source=web3coach&amp;utm_medium=article">Infura</a> -</strong> is the easiest way to get started, and you get 5GB free of decentralized storage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-from-2021-06-16-09-24-58.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Follow the <a target="_blank" href="https://infura.io/docs/ipfs?utm_source=web3coach&amp;utm_medium=article">getting started docs.</a></p>
<h3 id="heading-how-to-pin-wikipedia-locally">How to pin Wikipedia locally</h3>
<p>Verify that the Wikipedia root-level CID (highest DAG node) isn't yet pinned on your node:</p>
<pre><code>ipfs pin ls | grep QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX
&gt; no output, not pinned
</code></pre><p>IPFS stores specific versions of Wikipedia in the form of a DAG. I recommend inspecting its graph before pinning:</p>
<pre><code>ipfs object get QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"0C-"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmSEwJo8Z5bqVX3AhocyimJzPWetr7HgbWbwCg6zbp43AP"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">1248085</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"43I"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmPW3kRjncDj145bP9DVNc791FowLPwYHnqbTzfe3whdyZ"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">2611324931</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"58wiki"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmRNXpMRzsTHdRrKvwmWisgaojGKLPqHxzQfrXdfNkettC"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">12295304394</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"92M"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"Qmbcvk7jpBTUKdgex139Nvv7BrKocE3pQVKhNJtTU77Qv5"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">793</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"A0index.html"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmNqbYogAxH4mmt5WhuKN7NFEUDZ9V3Scxh7QbLwTKBJDk"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">191</span>
    }
  ],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0005\u0012\u0015\u0001\u0000\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0000\u0000\b\u0000\u0000\u0000\u0000\u0000\u0000\u0010\u0000(\"0�\u0002"</span>
}
</code></pre>
<p>The root DAG object has five links. Four links are relatively small, but <strong>one link points to a DAG node with a total size of 12GB.</strong> If you inspect this DAG node, you will see 256 more links and a total cumulative (recursive) size of 12GB.</p>
<pre><code>ipfs object stat QmRNXpMRzsTHdRrKvwmWisgaojGKLPqHxzQfrXdfNkettC

<span class="hljs-attr">NumLinks</span>:       <span class="hljs-number">256</span>
<span class="hljs-attr">BlockSize</span>:      <span class="hljs-number">12075</span>
<span class="hljs-attr">LinksSize</span>:      <span class="hljs-number">12034</span>
<span class="hljs-attr">DataSize</span>:       <span class="hljs-number">41</span>
<span class="hljs-attr">CumulativeSize</span>: <span class="hljs-number">12295304394</span>
</code></pre><p>Every node with an important pinned article, video, documentary, or a cat meme makes the web more accessible, antifragile, decentralized, and robust.</p>
<pre><code>ipfs pin add QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX
</code></pre><p>The pinning process will recursively traverse the entire DAG node, fetch all its links from the Bitswap protocol and then pin every single Block to your local datastore.</p>
<p>Congratulations! In this article, you learned how decentralized storage works behind the scenes.</p>
<h3 id="heading-i-worked-47-hours-to-write-this-blog-post-but-you-can-re-tweet-it-in-just-5-seconds">I worked 47 hours to write this blog post… but you can re-tweet it in just 5 seconds:</h3>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/Web3Coach/status/1406997483281174528"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Make an NFT and Render it on the OpenSea Marketplace ]]>
                </title>
                <description>
                    <![CDATA[ By Patrick Collins In this article, I'll show you how to make an NFT without software engineering skills. Then we will learn how to make unlimited customizable NFTs with Brownie, Python, and Chainlink. And we'll see how to render and sell our creatio... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-an-nft-and-render-on-opensea-marketplace/</link>
                <guid isPermaLink="false">66d46089a326133d12440a45</guid>
                
                    <category>
                        <![CDATA[ Art ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ NFT ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 01 Apr 2021 17:05:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/03/Advanced-NFT-Deployment---1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Patrick Collins</p>
<p>In this article, I'll show you how to make an NFT without software engineering skills. Then we will learn how to make unlimited customizable NFTs with <a target="_blank" href="https://eth-brownie.readthedocs.io/en/stable/">Brownie</a>, <a target="_blank" href="https://www.python.org/">Python</a>, and <a target="_blank" href="https://docs.chain.link/docs">Chainlink</a>. And we'll see how to render and sell our creation on the <a target="_blank" href="https://opensea.io/">OpenSea</a> NFT marketplace. </p>
<p>If you're looking for a tutorial that uses Truffle, JavaScript, and fun medieval characters, check out how to <a target="_blank" href="https://blog.chain.link/build-deploy-and-sell-your-own-dynamic-nft/">Build, Deploy, and Sell your NFT here</a>. </p>
<h2 id="heading-what-is-an-nft">What is an NFT?</h2>
<p><a target="_blank" href="https://eips.ethereum.org/EIPS/eip-721">NFTs</a> (Non-Fungible Tokens) can be summed up with one word: "unique". These are smart contracts deployed on a blockchain that represent something unique. </p>
<h3 id="heading-erc20-vs-erc721">ERC20 vs ERC721</h3>
<p>NFTs are a blockchain token standard similar to the <a target="_blank" href="https://www.investopedia.com/news/what-erc20-and-what-does-it-mean-ethereum/">ERC20</a>, like AAVE, SNX, and LINK (technically a ERC677). ERC20s are "fungible" tokens, which means “replaceable” or “interchangeable.” </p>
<p>For example, your dollar bill is going to be worth $1 no matter what dollar bill you use. The serial number on the dollar bill might be different, but the bills are interchangeable and they’ll be worth $1 no matter what. </p>
<p>NFTs, on the other hand, are "non-fungible", and they follow their own token standard, the <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-721">ERC721.</a> For example, the Mona Lisa is "non-fungible". Even though someone can make a copy of it, there will always only be one Mona Lisa. If the Mona Lisa was created on a blockchain, it would be an NFT. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/image-145.png" alt="Make an NFT" width="600" height="400" loading="lazy">
_Original Image from <a target="_blank" href="https://en.wikipedia.org/wiki/Mona_Lisa">Wikipedia</a>_</p>
<h2 id="heading-what-are-nfts-for">What are NFTs for?</h2>
<p>NFTs provide value to creators, artists, game designers and more by having a permanent history of deployment stored on-chain. </p>
<p>You'll always know who created the NFT, who owned the NFT, where it came from, and more, giving them a lot of value over traditional art. In traditional art, it can be tricky to understand what a "fake" is, whereas on-chain the history is easily traceable. </p>
<p>And since smart contracts and NFTs are 100% programmable, NFTs can also have added built-in royalties and any other functionality. Compensating artists has always been an issue, since often times an artist's work is spread around without any attribution. </p>
<p>More and more artists and engineers are jumping on this massive value add, because it's finally a great way for artists to be compensated for their work. And more than just that, NFTs are a fun way to show off your creativity and become a collector in a digital world. </p>
<h3 id="heading-the-value-of-nfts">The Value of NFTs</h3>
<p>NFTs have come a long way, and we keep seeing record breaking NFT sales, like "Everydays: The First 5,000 Days” selling for $69.3 million.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2021-03-31-at-9.48.19-AM.png" alt="Make an NFT" width="600" height="400" loading="lazy">
<em>Image from <a target="_blank" href="https://twitter.com/ChristiesInc/status/1361670588608176128">Twitter</a></em></p>
<p>So there is a lot of value here, and it's also a fun, dynamic, and engaging way to create art in the digital world and learn about smart contract creation. So now I'll teach you everything you need to know about making NFTs.</p>
<h2 id="heading-how-to-make-an-nft">How to Make an NFT</h2>
<h3 id="heading-what-we-are-not-going-to-cover">What we are not going to cover</h3>
<p>Now, the easiest way to make an NFT is just to go to a platform like <a target="_blank" href="https://opensea.io/">Opensea</a>, <a target="_blank" href="https://rarible.com/">Rarible</a>, or <a target="_blank" href="https://mintable.app/">Mintible</a> and follow their step-by-step guide to deploying on their platform. </p>
<p>You can 100% take this route, however you could be bound to the platform, and you are shoehorned into the functionality the platform has. You can't achieve the unlimited customization, or really utilize any of the advantages NFTs have. But if you're a beginner software engineer, or not very technical, this is the route for you. </p>
<p>If you're looking to become a stronger software engineer, learn some solidity, and have the power to create something with unlimited creativity, then read on!</p>
<p>If you're new to solidity, don't worry, we will go over the basics there as well. </p>
<h2 id="heading-how-to-make-an-nft-with-unlimited-customization">How to Make an NFT with Unlimited Customization</h2>
<p>I'm going to get you jump started with this <a target="_blank" href="https://github.com/PatrickAlphaC/nft-mix">NFT Brownie Mix</a>. This is a working repo with a lot of boilerplate code. </p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>We need a few things installed to get started:</p>
<ul>
<li><a target="_blank" href="https://www.python.org/downloads/">Python</a></li>
<li><a target="_blank" href="https://nodejs.org/en/download/">Nodejs</a> and npm</li>
<li><a target="_blank" href="https://metamask.io/">Metamask</a></li>
</ul>
<p>If you're unfamiliar with Metamask, you can <a target="_blank" href="https://docs.chain.link/docs/install-metamask">follow this tutorial</a> to get it set up. </p>
<h3 id="heading-rinkeby-testnet-eth-and-link">Rinkeby Testnet ETH and LINK</h3>
<p>We will also be working on the Rinkeby Ethereum testnet, so we will be deploying our contracts to a real blockchain, for free! </p>
<p>Testnets are great ways to test how our smart contracts behave in the real world. We need Rinkeby ETH and Rinkeby LINK, which we can get for free from the links to the latest faucets from the <a target="_blank" href="https://docs.chain.link/docs/link-token-contracts#rinkeby">Chainlink documentation</a>. </p>
<p>We will also need to add the rinkeby LINK token to our metamask, which we can do by following the <a target="_blank" href="https://docs.chain.link/docs/acquire-link">acquire LINK documentation</a>. </p>
<p>If you're still confused, <a target="_blank" href="https://www.youtube.com/watch?v=4ZgFijd02Jo">you can following along with this video</a>, just be sure to use Rinkeby instead of Ropsten. </p>
<p>When working with a smart contract platform like Ethereum, we need to pay a little bit of ETH, and when getting data from off-chain, we have to pay a little bit of LINK. This is why we need the testnet LINK and ETH.</p>
<p>Awesome, let's dive in. This is <a target="_blank" href="https://testnets.opensea.io/assets/0x8acb7ca932892eb83e4411b59309d44dddbc4cdf/0">the NFT we are going to deploy to OpenSea.</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2021-03-31-at-10.58.35-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-quickstart">Quickstart</h3>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/PatrickAlphaC/nft-mix
<span class="hljs-built_in">cd</span> nft-mix
</code></pre>
<p>Awesome! Now we need to install the <code>ganache-cli</code> and <code>eth-brownie</code>.</p>
<pre><code>pip install eth-brownie
npm install -g ganache-cli
</code></pre><p>Now we can <a target="_blank" href="https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html">set our environment variables</a>. If you're unfamiliar with environment variables, you can just add them into your <code>.env</code> file, and then run:</p>
<p><code>source .env</code></p>
<p>A sample <code>.env</code> should be in the repo you just cloned with the environment variables commented out. Uncomment them to use them!</p>
<p>You'll need a <code>WEB3_INFURA_PROJECT_ID</code> and a <code>PRIVATE_KEY</code> . The <code>WEB3_INFURA_PROJECT_ID</code> can be found be signing up for a free <a target="_blank" href="https://infura.io/">Infura</a> account. This will give us a way to send transactions to the blockchain.</p>
<p>We will also need a private key, which you can get from your Metamask. Hit the 3 little dots, and click <code>Account Details</code> and <code>Export Private Key</code>. Please do NOT share this key with anyone if you put real money in it!</p>
<pre><code><span class="hljs-keyword">export</span> PRIVATE_KEY=YOUR_KEY_HERE
<span class="hljs-keyword">export</span> WEB3_INFURA_PROJECT_ID=YOUR_PROJECT_ID_HERE
</code></pre><p>Now we can deploy our NFT contract and create our first collectible with the following two commands. </p>
<pre><code>brownie run scripts/simple_collectible/deploy_simple.py --network rinkeby
brownie run scripts/simple_collectible/create_collectible.py --network rinkeby
</code></pre><p>The first script deploys our NFT contract to the Rinkeby blockchain, and the second one creates our first collectible. </p>
<p>You've just deployed your first smart contract!</p>
<p>It doesn't do much at all, but don't worry – I'll show you how to render it on OpenSea in the advanced part of this tutorial. But first, let's look at the ERC721 token standard. </p>
<h2 id="heading-the-erc721-token-standard">The ERC721 Token Standard</h2>
<p>Let's take a look at the contract that we just deployed, in the <code>SimpleCollectible.sol</code> file. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
pragma solidity <span class="hljs-number">0.6</span><span class="hljs-number">.6</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/ERC721.sol"</span>;

contract SimpleCollectible is ERC721 {
    uint256 public tokenCounter;
    <span class="hljs-keyword">constructor</span> () public ERC721 ("Dogie", "DOG"){
        tokenCounter = <span class="hljs-number">0</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createCollectible</span>(<span class="hljs-params">string memory tokenURI</span>) <span class="hljs-title">public</span> <span class="hljs-title">returns</span> (<span class="hljs-params">uint256</span>) </span>{
        uint256 newItemId = tokenCounter;
        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);
        tokenCounter = tokenCounter + <span class="hljs-number">1</span>;
        <span class="hljs-keyword">return</span> newItemId;
    }

}
</code></pre>
<p>We are using the <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts">OpenZepplin</a> package for the ERC721 token. This package that we've imported allows us to use all the functions of a typical ERC721 token. This defines all the functionality that our tokens are going to have, like <code>transfer</code> which moves tokens to new users, <code>safeMint</code> which creates new tokens, and more. </p>
<p>You can find all the functions that are given to our contract by checking out the <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol">OpenZepplin ERC721 token contract</a>. Our contract inherits these functions on this line: </p>
<pre><code>contract SimpleCollectible is ERC721 {
</code></pre><p>This is how solidity does inheritance. When we deploy a contract, the <code>constructor</code> is automatically called, and it takes a few parameters.</p>
<pre><code><span class="hljs-keyword">constructor</span> () public ERC721 ("Dogie", "DOG"){
        tokenCounter = <span class="hljs-number">0</span>;
    }
</code></pre><p>We also use the constructor of the <code>ERC721</code>, in our constructor, and we just have to give it a name and a symbol. In our case, it's "Dogie" and "DOG". This means that every NFT that we create will be of type Dogie/DOG. </p>
<p>This is like how every Pokemon card is still a pokemon, or every baseball player on a trading card is still a baseball player. Each baseball player is unique, but they are still all baseball players. We are just using type <code>DOG</code>. </p>
<p>We have <code>tokenCounter</code> at the top that counts how many NFTs we've created of this type. Each new token gets a <code>tokenId</code> based on the current <code>tokenCounter</code>.</p>
<p>We can actually create an NFT with the <code>createCollectible</code> function. This is what we call in our <code>create_collectible.py</code> script. </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createCollectible</span>(<span class="hljs-params">string memory tokenURI</span>) <span class="hljs-title">public</span> <span class="hljs-title">returns</span> (<span class="hljs-params">uint256</span>) </span>{
        uint256 newItemId = tokenCounter;
        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);
        tokenCounter = tokenCounter + <span class="hljs-number">1</span>;
        <span class="hljs-keyword">return</span> newItemId;
    }
</code></pre><p>The <code>_safeMint</code> function creates the new NFT, and assigns it to whoever called <code>createdCollectible</code> , aka the <code>msg.sender</code>, with a <code>newItemId</code> derived from the <code>tokenCounter</code>. This is how we can keep track of who owns what, by checking the owner of the <code>tokenId</code>.</p>
<p>You'll notice that we also call <code>_setTokenURI</code>. Let's talk about that.</p>
<h2 id="heading-what-are-nft-metadata-and-tokenuri">What are NFT Metadata and TokenURI?</h2>
<p>When smart contracts were being created, and NFTs were being created, people quickly realized that it's <em>reaaaally</em> expensive to deploy a lot of data to the blockchain. Images as small as one KB can easily <a target="_blank" href="https://ethereum.stackexchange.com/a/896/57451">cost over $1M to store</a>. </p>
<p>This is clearly an issue for NFTs, since having creative art means you have to store this information somewhere. They also wanted a lightweight way to store attributes about an NFT – and this is where the tokenURI and metadata come into play.</p>
<h3 id="heading-tokenuri">TokenURI</h3>
<p>The <code>tokenURI</code> on an NFT is a unique identifier of what the token "looks" like. A URI could be an API call over HTTPS, an IPFS hash, or <a target="_blank" href="https://danielmiessler.com/study/difference-between-uri-url/">anything else</a> unique. </p>
<p>They follow a standard of showing metadata that looks like this:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"name"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"description"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://ipfs.io/ipfs/QmTgqnhFBMkfT9s8PHKcdXBn1f5bG3Q5hmBaR4U6hoTvb1?filename=Chainlink_Elf.png"</span>,
    <span class="hljs-attr">"attributes"</span>: [
        {
            <span class="hljs-attr">"trait_type"</span>: <span class="hljs-string">"trait"</span>,
            <span class="hljs-attr">"value"</span>: <span class="hljs-number">100</span>
        }
    ]
}
</code></pre>
<p>These show what an NFT looks like, and its attributes. The <code>image</code> section points to another URI of what the NFT looks like. This makes it easy for NFT platforms like Opensea, Rarible, and Mintable to render NFTs on their platforms, since they are all looking for this metadata. </p>
<h3 id="heading-off-chain-metadata-vs-on-chain-metadata">Off-Chain Metadata vs On-Chain Metadata</h3>
<p>Now you might be thinking "wait... if the metadata isn't on-chain, does that mean my NFT might go away at some point"? And you'd be correct. </p>
<p>You'd also be correct in thinking that off-chain metadata means that you can't use that metadata to have your smart contracts interact with each other. </p>
<p>This is why we want to focus on on-chain metadata, so that we can program our NFTs to interact with each other. </p>
<p>We still need the <code>image</code> part of the off-chain metadata, though, since we don't have a great way to store large images on-chain. But don't worry, we can do this for free on a decentralized network still by using <a target="_blank" href="https://ipfs.io/">IPFS</a>. </p>
<p>Here's an example imageURI from IPFS that shows the <a target="_blank" href="https://opensea.io/assets/0x8d78277bc2c63f07efc2c0c8a8512de4ad459a05/1">Chainlink Elf</a> created in the <a target="_blank" href="https://blog.chain.link/build-deploy-and-sell-your-own-dynamic-nft/">Dungeons and Dragons tutorial</a>. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2021-03-31-at-12.15.22-PM.png" alt="Make an NFT" width="600" height="400" loading="lazy">
<em>The Chainlink Elf</em></p>
<p>We didn't set a tokenURI for the simple NFT because we wanted to just show a basic example. </p>
<p>Let's jump into the advanced NFT now, so we can see some of the amazing features we can do with on-chain metadata, have the NFT render on opeansea, and get our Dogie up! </p>
<p>If you want a refresher video on the section we just went over, follow along with the <a target="_blank" href="https://www.youtube.com/watch?v=ZH_7nEIJDUY">deploying a simple NFT video.</a> </p>
<h2 id="heading-dynamic-and-advanced-nfts">Dynamic and Advanced NFTs</h2>
<p><a target="_blank" href="https://blog.chain.link/build-deploy-and-sell-your-own-dynamic-nft/">Dynamic NFTs</a> are NFTs that can change over time, or have on-chain features that we can use to interact with each other. These are the NFTs that have the unlimited customization for us to make entire games, worlds, or interactive art of some-kind. Let's jump into the advanced section.</p>
<h3 id="heading-advanced-quickstart">Advanced Quickstart</h3>
<p>Make sure you have enough testnet ETH and LINK in your metamask, then run the following:</p>
<pre><code>brownie run scripts/advanced_collectible/deploy_advanced.py --network rinkeby
brownie run scripts/advanced_collectible/create_collectible.py --network rinkeby
</code></pre><p>Our collectible here is a random dog breed returned from the <a target="_blank" href="https://docs.chain.link/docs/chainlink-vrf">Chainlink VRF</a>. Chainlink VRF is a way to get provable random numbers, and therefore true scarcity in our NFTs. We then want to create its metadata.</p>
<pre><code>brownie run scripts/advanced_collectible/create_metadata.py --network rinkeby
</code></pre><p>We can then optionally upload this data to IPFS so that we can have a tokenURI. I'll show you how to do that later. For now, we are just going to use the sample tokenURI of:</p>
<pre><code>https:<span class="hljs-comment">//ipfs.io/ipfs/Qmd9MCGtdVz2miNumBHDbvj8bigSgTwnr4SbyH6DNnpWdt?filename=1-PUG.json</span>
</code></pre><p>If you download <a target="_blank" href="https://chrome.google.com/webstore/detail/ipfs-companion/nibjojkomfdiaoajekhjakgkdhaomnch?hl=en">IPFS Companion</a> into your browser you can use that URL to see what the URI returns. It'll look like this:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"PUG"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"An adorable PUG pup!"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://ipfs.io/ipfs/QmSsYRx3LpDAb1GZQm7zZ1AuHZjfbPkD6J7s9r41xu1mf8?filename=pug.png"</span>,
    <span class="hljs-attr">"attributes"</span>: [
        {
            <span class="hljs-attr">"trait_type"</span>: <span class="hljs-string">"cuteness"</span>,
            <span class="hljs-attr">"value"</span>: <span class="hljs-number">100</span>
        }
    ]
}
</code></pre>
<p>Then we can run our <code>set_tokenuri.py</code> script:</p>
<pre><code>brownie run scripts/advanced_collectible/set_tokenuri.py --network rinkeby
</code></pre><p>And we will get an output like this: </p>
<pre><code>Running <span class="hljs-string">'scripts/advanced_collectible/set_tokenuri.py::main'</span>...
Working on rinkeby
Transaction sent: <span class="hljs-number">0x8a83a446c306d6255952880c0ca35fa420248a84ba7484c3798d8bbad421f88e</span>
  Gas price: <span class="hljs-number">1.0</span> gwei   Gas limit: <span class="hljs-number">44601</span>   Nonce: <span class="hljs-number">354</span>
  AdvancedCollectible.setTokenURI confirmed - Block: <span class="hljs-number">8331653</span>   Gas used: <span class="hljs-number">40547</span> (<span class="hljs-number">90.91</span>%)

Awesome! You can view your NFT at https:<span class="hljs-comment">//testnets.opensea.io/assets/0x679c5f9adC630663a6e63Fa27153B215fe021b34/0</span>
Please give up to <span class="hljs-number">20</span> minutes, and hit the <span class="hljs-string">"refresh metadata"</span> button
</code></pre><p>And we can hit the link given to see what it looks like on Opensea! You may have to hit the <code>refresh metadata</code> button and wait a few minutes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2021-03-31-at-12.33.42-PM.png" alt="Make an NFT" width="600" height="400" loading="lazy">
<em>Refresh Metadata</em></p>
<h2 id="heading-the-random-breed">The Random Breed</h2>
<p>Let's talk about what we just did. Here is our <code>AdvancedCollectible.sol</code>:</p>
<pre><code>pragma solidity <span class="hljs-number">0.6</span><span class="hljs-number">.6</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/ERC721.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@chainlink/contracts/src/v0.6/VRFConsumerBase.sol"</span>;

contract AdvancedCollectible is ERC721, VRFConsumerBase {
    uint256 public tokenCounter;
    enum Breed{PUG, SHIBA_INU, BRENARD}
    <span class="hljs-comment">// add other things</span>
    mapping(<span class="hljs-function"><span class="hljs-params">bytes32</span> =&gt;</span> address) public requestIdToSender;
    mapping(<span class="hljs-function"><span class="hljs-params">bytes32</span> =&gt;</span> string) public requestIdToTokenURI;
    mapping(<span class="hljs-function"><span class="hljs-params">uint256</span> =&gt;</span> Breed) public tokenIdToBreed;
    mapping(<span class="hljs-function"><span class="hljs-params">bytes32</span> =&gt;</span> uint256) public requestIdToTokenId;
    event requestedCollectible(bytes32 indexed requestId); 


    bytes32 internal keyHash;
    uint256 internal fee;
    uint256 public randomResult;
    <span class="hljs-keyword">constructor</span>(address _VRFCoordinator, address _LinkToken, bytes32 _keyhash)
    public 
    VRFConsumerBase(_VRFCoordinator, _LinkToken)
    ERC721("Dogie", "DOG")
    {
        tokenCounter = <span class="hljs-number">0</span>;
        keyHash = _keyhash;
        fee = <span class="hljs-number">0.1</span> * <span class="hljs-number">10</span> ** <span class="hljs-number">18</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createCollectible</span>(<span class="hljs-params">string memory tokenURI, uint256 userProvidedSeed</span>) 
        <span class="hljs-title">public</span> <span class="hljs-title">returns</span> (<span class="hljs-params">bytes32</span>)</span>{
            bytes32 requestId = requestRandomness(keyHash, fee, userProvidedSeed);
            requestIdToSender[requestId] = msg.sender;
            requestIdToTokenURI[requestId] = tokenURI;
            emit requestedCollectible(requestId);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fulfillRandomness</span>(<span class="hljs-params">bytes32 requestId, uint256 randomNumber</span>) <span class="hljs-title">internal</span> <span class="hljs-title">override</span> </span>{
        address dogOwner = requestIdToSender[requestId];
        string memory tokenURI = requestIdToTokenURI[requestId];
        uint256 newItemId = tokenCounter;
        _safeMint(dogOwner, newItemId);
        _setTokenURI(newItemId, tokenURI);
        Breed breed = Breed(randomNumber % <span class="hljs-number">3</span>); 
        tokenIdToBreed[newItemId] = breed;
        requestIdToTokenId[requestId] = newItemId;
        tokenCounter = tokenCounter + <span class="hljs-number">1</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setTokenURI</span>(<span class="hljs-params">uint256 tokenId, string memory _tokenURI</span>) <span class="hljs-title">public</span> </span>{
        <span class="hljs-built_in">require</span>(
            _isApprovedOrOwner(_msgSender(), tokenId),
            <span class="hljs-string">"ERC721: transfer caller is not owner nor approved"</span>
        );
        _setTokenURI(tokenId, _tokenURI);
    }
}
</code></pre><p>We use the Chainlink VRF to create a random breed from a list of <code>PUG, SHIBA_INU, BRENARD</code>. When we call <code>createCollectible</code> this time, we actually kicked off a request to the Chainlink VRF node off-chain, and returned with a random number to create the NFT with one of those 3 breeds. </p>
<p>Using true randomness in your NFTs is a great way to create true scarcity, and using an Chainlink oracle random number means that your number is provably random, and can't be influenced by the miners. </p>
<p>You can learn more about <a target="_blank" href="https://docs.chain.link/docs/chainlink-vrf">Chainlink VRF in the documentation</a>. </p>
<p>The Chainlink node responds by calling the <code>fulfillRandomness</code> function, and creates the collectible based on the random number. We then still have to call <code>_setTokenURI</code> to give our NFT the appearance that it needs. </p>
<p>We didn't give our NFT attributes here, but attributes are a great way to have our NFTs battle and interact. You can see a great example of NFTs with attributes in this <a target="_blank" href="https://github.com/PatrickAlphaC/dungeons-and-dragons-nft">Dungeons and Dragons example</a>. </p>
<h3 id="heading-metadata-from-ipfs">Metadata from IPFS</h3>
<p>We are using IPFS to store two files:</p>
<ol>
<li>The image of the NFT (the pug image)</li>
<li>The tokenURI file (the JSON file which also includes the link of the image)</li>
</ol>
<p>We use IPFS because it's a free decentralized platform. We can add our tokenURIs and images to IPFS by downloading <a target="_blank" href="https://docs.ipfs.io/install/ipfs-desktop/">IPFS desktop</a>, and hitting the <code>import</code> button. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2021-03-31-at-12.43.13-PM.png" alt="Make an NFT" width="600" height="400" loading="lazy">
<em>IPFS add a file</em></p>
<p>Then, we can share the URI by hitting the 3 dots next to the file we want to share, hitting <code>share link</code> and copying the link given. We can then add this link into our <code>set_tokenuri.py</code> file to change the token URI that we want to use. </p>
<h3 id="heading-persistance">Persistance</h3>
<p>However, if the tokenURI is only on our node, this means when our node is down, no one else can view it. So we want others to <code>pin</code> our NFT. We can use a pinning service like <a target="_blank" href="https://pinata.cloud/">Pinata</a> to help keep our data alive even when our IPFS node is down.</p>
<p>I imagine in the future more and more metadata will be stored on IPFS and decentralized storage platforms. Centralized servers can go down, and would mean that the art on those NFTs is lost forever. Be sure to check where the tokenURI of the NFT you use is located! </p>
<p>I also expect down the line that more people will use dStorage platforms like <a target="_blank" href="https://docs.filecoin.io/">Filecoin</a>, as using a pinning service also isn't as decentralized as it should be.</p>
<h2 id="heading-going-forward">Going forward</h2>
<p>If you'd like a video walkthrough of the advanced NFT, you can watch the <a target="_blank" href="https://www.youtube.com/watch?v=tCR7b9p9GiM">advanced NFT video</a>. </p>
<p>Now you have the skills to make beautiful fun, customizable, interactive NFTs, and have them render on a marketplace. </p>
<p>NFTs are fun, powerful ways to have artists accurately compensated for all the hard work that they do. Good luck, and remember to have fun!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Why Progressive Decentralization is blockchain’s best hope ]]>
                </title>
                <description>
                    <![CDATA[ By Arthur Camara Immutability is blockchain’s greatest strength and biggest barrier. Progressive decentralization could be the answer. When we released CryptoKitties a year ago, we opted not to fund it up front with an ICO but instead build it on a ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-progressive-decentralization-is-blockchains-best-hope-31a497f2673b/</link>
                <guid isPermaLink="false">66c3670321ae2d74bb700a02</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ethereum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 06 Feb 2019 19:36:48 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*qgm9rHxUeF-oy6NxHnXv_A.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arthur Camara</p>
<h4 id="heading-immutability-is-blockchains-greatest-strength-and-biggest-barrier-progressive-decentralization-could-be-the-answer">Immutability is blockchain’s greatest strength and biggest barrier. Progressive decentralization could be the answer.</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4RiJaG98m8kPcAYjnVLTCKifqTzhXEys5TD-" alt="Image" width="800" height="454" loading="lazy"></p>
<p>When we released <a target="_blank" href="https://www.cryptokitties.co">CryptoKitties</a> a year ago, we opted not to fund it up front with an ICO but instead build it on a sustainable revenue model. That model is this: we collect a fee of 3.75% from every transaction in the game. Given that we’d be unable to change the fee once we launched — CryptoKitties is built on the Ethereum blockchain — people often ask how we arrived at that number.</p>
<p>It sounds like a smart, well-reasoned choice. I could spin a compelling story about how we ran simulations with advanced prediction models to find the fee that would yield optimal returns.</p>
<p>But that’s not true.</p>
<p>The truth is we made an educated guess. We picked a number that felt fair and we committed to it.</p>
<h3 id="heading-immutability-is-awesome-and-scary">Immutability is awesome and scary</h3>
<p>We easily could have chosen wrong, and since you can’t change something once you add it to the blockchain, that would have been <em>cat-astrophic</em>. Fortunately for CryptoKitties, our community is so passionate and the Kitties are so adorable that 3.75% worked just fine.</p>
<p>Immutability, the inability to be edited, is at once the blockchain’s greatest strength and its largest barrier to meaningful adoption. The pressures of immortal code paralyze developers: you can tinker in a test environment forever, but there will always be real-world variables you can’t anticipate. Covering your eyes and hitting launch is no way to make breakthroughs. It’s more likely to produce breakdowns.</p>
<p>Our fee was just one decision among many: how long should breeding a Kitty take? At what rate should their breeding cooldowns slow? How much should a Gen 0 cat cost? On blockchain, even a seemingly minor choice can pose serious, even critical, consequences.</p>
<p>Decentralization offers everyday people immense benefits: the fairness of permanent and universal rules and the transparency of code and behavior which, combined, create security. However, because it’s often implemented with all-or-nothing immutability, blockchain makes agile development impossible and slows teams to a crawl.</p>
<p>Agility requires iteration. Iterating quickly is key to building the best products, and the best products spark mass adoption.</p>
<h3 id="heading-enter-progressive-decentralization">Enter Progressive Decentralization</h3>
<p>We encountered these barriers ourselves building CryptoKitties, which forced us to negotiate including decentralized features while building something that, ya know, works. Since then, we’ve started exploring progressive decentralization in development, an idea we briefly introduced <a target="_blank" href="https://medium.com/dapperlabs/how-we-launched-cryptokitties-latest-feature-6318ecceba9f">a while ago</a>.</p>
<p>Let’s take a deeper dive now.</p>
<p>Simply put, progressive decentralization advocates easing into decentralization in stages rather than diving in headfirst. What that looks like is building mechanisms into smart contracts that confer special powers to the creators up front, then incrementally lock those powers away in a transparent and systematic way.</p>
<p>The critical condition is that the locking mechanisms must be public and immutable from the start. The creator can’t decide to tweak the terms later and indefinitely extend their power. That balance is vital: done correctly, progressive decentralization allows creators the flexibility to repair their code without compromising the decentralized features of the contract.</p>
<h3 id="heading-progressive-decentralization-can-take-many-forms">Progressive decentralization can take many forms</h3>
<p>There’s no one right way to implement progressive decentralization. There are dozens of variables to consider, and the best approach will vary from project to project.</p>
<p>Here are a couple ways developers could approach progressive decentralization:</p>
<ol>
<li>Author multiple contracts with appropriate separation of concerns and the ability to replace some of those contracts. Some decentralized apps (“dapps”) like <a target="_blank" href="https://decentraland.org/">Decentraland</a>, which features upgradable contracts, are already using this.</li>
<li>Configurable variables and permissions to change those values independently. <a target="_blank" href="https://www.etheremon.com/">Etheremon</a>, for instance, <a target="_blank" href="https://github.com/Etheremon/smartcontract/blob/master/EtheremonERC721.sol#L125">grants special permissions</a> to groups of users who become moderators.</li>
<li>Incorporate a predefined set of ascending levels in the contract, each allowing the creators certain capabilities. The levels can only be increased, never decreased, so backtracking isn’t an option. On level 1, for example, the contract owners can play around with all gameplay variables. At level 2, their capability to modify core variables ends. At the final level, the contract revokes all their special privileges.</li>
</ol>
<p>To die-hard decentralists, some of this probably sounds too centralized. But this is just the starting point. There are further measures to balance decentralization with iteration. The solution combines transparency of the purpose and the conditions and constraints in the contracts. These constraints could include:</p>
<ol>
<li><strong>Selection:</strong> Not everything can be modified, only the specific items that we need to iterate.</li>
<li><strong>Range:</strong> For many of the questions around game economies, we may have a general idea but not know the precise answer. Limiting configuration to a certain range guarantees users that the iteration will land within a reasonable scope.</li>
<li><strong>Direction:</strong> Similar to the “levels” concept above, allow certain variables to move only in one direction, decreasing or increasing but never backtracking.</li>
</ol>
<h3 id="heading-holding-creators-accountable">Holding creators accountable</h3>
<p>All this sounds great in theory. But how do we ensure creators stay true to their roadmap and reach the fully decentralized version of their contracts? How can users opt-in early with the guarantee that the system is an application of progressive decentralization? How can we know we won’t end up with just another flawed, centralized system?</p>
<p>Progressive decentralization includes tenets to keep creators accountable:</p>
<h4 id="heading-time-or-block-based-maturity"><strong><em>Time- or block-based maturity</em></strong></h4>
<p>Lock certain configuration values, revoke the owner’s capabilities or move to the next level of maturity past a certain time or block number. Once that point is reached, the contract automatically changes.</p>
<p>Imagine, for example, that CryptoKitties had a runway of 360,000 blocks (around 60 days’ time) from the moment it launched to adjust the Kitties’ breeding <em>cooldown</em> variables. We could tweak the cooldown mechanics until that point, giving ourselves the breathing room to perfect the balance, while still guaranteeing players that we wouldn’t have that power indefinitely.</p>
<h4 id="heading-usage-based-maturity"><strong><em>Usage-based maturity</em></strong></h4>
<p>Lock those capabilities once a certain number of users or transactions are completed. This option needs to be carefully thought out to avoid exploits, but we could have, for example, built configurable fees into CryptoKitties that would lock in after 10,000 transactions.</p>
<h4 id="heading-economic-incentive"><strong><em>Economic incentive</em></strong></h4>
<p>Align the creator’s incentives with increased decentralization. In this scenario, the creators profit more when the contract becomes more decentralized. Perhaps the fee rises with each level the developer ascends, locking in at the maximum fee when they reach full decentralization. Or, alternatively, perhaps they make no money at all until full decentralization is in place. This financial reward motivates the developer to reach decentralization at a reasonable pace.</p>
<h3 id="heading-theres-no-best-approach-to-building-on-the-blockchain">There’s no best approach to building on the blockchain</h3>
<p>“Progressive decentralization” is really an umbrella encompassing many strategies, mechanisms, and tools to make building on the blockchain more viable. The best way to apply progressive decentralization will always depend on the project and use a mix of the concepts outlined above.</p>
<p>Progressive decentralization is not perfect. The ideal smart contract is simple and straightforward, and these measures add complexity. How and how much to incorporate it is a trade-off that needs to be evaluated on a case-by-case basis.</p>
<p>Although it may anger hardline decentralists, we believe progressive decentralization is far better for users in the long run: by giving developers the flexibility to adjust, the consumer gets a more useful product. That means they’ll actually use it, and once it brings value to their lives, they’ll sing its praises to the people around them. That’s how mass adoption starts.</p>
<p>_Authors: <a target="_blank" href="https://medium.com/@arthur_camara">Arthur Camara</a>, <a target="_blank" href="https://medium.com/@dete73">Dieter Shirley</a>, and Grady Mitchell_</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An introduction to SOLID, Tim Berners-Lee’s new, re-decentralized Web ]]>
                </title>
                <description>
                    <![CDATA[ By Arnav Bansal Recently, Prof. Tim Berners-Lee lifted the veil off a project called Solid. I decided to check it out. In this article, I describe what Solid aims to do, and also how you can get started with it. What is Solid? Solid is an attempt to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/an-introduction-to-solid-tim-berners-lees-new-re-decentralized-web-25d6b78c523b/</link>
                <guid isPermaLink="false">66c34459160da468ed76f142</guid>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ internet ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 29 Oct 2018 15:20:48 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*P4F0K6HR2L0VfQZmMvYt0g.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arnav Bansal</p>
<p>Recently, <a target="_blank" href="https://en.wikipedia.org/wiki/Tim_Berners-Lee">Prof. Tim Berners-Lee</a> lifted the veil off a project called Solid. I decided to check it out. In this article, I describe what Solid aims to do, and also how you can get started with it.</p>
<h3 id="heading-what-is-solid">What is Solid?</h3>
<p>Solid is an attempt to re-decentralize the web.</p>
<p>_Re<strong>-</strong>_decentralize?</p>
<p>Back in the day, the vision for the web was a decentralized, collaborative read-write space. The first browser (called WorldWideWeb) was <a target="_blank" href="https://www.w3.org/People/Berners-Lee/WorldWideWeb.html">also an editor</a>.</p>
<p>However, as it progressed, the design of web applications began to centralize for a variety of reasons. User data became the source of power and income for Internet companies.</p>
<p>Solid is a solution to this.</p>
<p>Solid is a new paradigm for web applications, one that is backwards compatible with the existing web.</p>
<p>Solid is a tech stack, a group of related protocols, implementations, and a growing community. Much like the web.</p>
<h3 id="heading-the-separation-of-app-and-data">The separation of app and data</h3>
<p>In pre-internet computing, your personal computer stored your data.</p>
<p>As people began using multiple computers, and added smartphones to their lives, the “your data stays with you” model was replaced by “Your data is in one or more massive data centers around the world, managed by the app developer”.</p>
<p>And so, applications were deeply coupled with their data. Creating an application on the web entails managing people’s data at scale.</p>
<p>Apps and their ability to make money are measured by their <em>data silo</em>. Your data is difficult to migrate, since different apps store your data very differently.</p>
<p>The result? Almost every app has walled garden characteristics. This reduces incentives for developers to innovate at the app level. Existing platforms are secured against disruption, since the data lockdown makes it hard for users to move.</p>
<h3 id="heading-data-protection-regulations">Data protection regulations</h3>
<p>Some countries have enacted data protection laws. Companies must make your data available, and you can chose to download or delete it.</p>
<p>This attempts to return control over data back to users. But it’s a legal prescription, and not the technical reality. User data still lies with app developers, and the ability to download your data isn’t very useful if you can’t migrate to an alternative.</p>
<h3 id="heading-pods-bring-your-own-data">Pods: Bring your own data</h3>
<p>Solid remedies this on the technical side. It allows applications to be built in a way where they read and write data stored on your <em>pod</em>.</p>
<p>You have a pod. Your friends have a pod. Pods store your data. You allow apps to access your pod.</p>
<p>Maybe you have multiple pods. Perhaps separate ones for home and work. Your pod can live on your computer, or be distributed across your devices. Or it could be hosted for you.</p>
<p>And pods store <em>linked data</em>. Your pod can link to something on my pod, or anywhere on the web.</p>
<p>We want applications that run across our devices. But we also want autonomy of our data. And we want the ability for different apps to use the same data and write to it.</p>
<h3 id="heading-the-ideas-behind-solid">The ideas behind Solid</h3>
<p>Getting into Solid reminded me of starting out with web development. I remember learning HTML, CSS, JavaScript, and the frameworks of the day, all at the same time.</p>
<p>The only difference: Solid is new, and help is harder to find.</p>
<p>Here’s a collection of day-one concepts you’ll want to know to get started developing for Solid:</p>
<p>(PS: if you just wanna jump in, skip ahead to ‘First steps’)</p>
<h4 id="heading-linked-data"><strong>Linked data</strong></h4>
<p>The power of the Solid, and the web generally, is from the way data is hyperlinked together.</p>
<p>In Solid, you store the data you produce wherever you want. Your personal data likely resides on your pod. To refer to this data, you use URLs, like on the web.</p>
<p>This is also a good time to introduce the full-form of Solid: <strong>SO</strong>cial <strong>LI</strong>nked <strong>D</strong>ata.</p>
<p>Read about <a target="_blank" href="https://solid.inrupt.com/docs/intro-to-linked-data">Linked Data in the context of Solid</a></p>
<h4 id="heading-resource-description-framework"><strong>Resource Description Framework</strong></h4>
<p>RDF is a way to represent linked data with statements of the form <code>subject-predicate-object</code>. These are also called triples.</p>
<p>RDF is an abstract model. You could even represent RDF in English sentences. Here’s a task on a Todo list:</p>
<pre><code>T1 is a taskT1 is labelled <span class="hljs-string">"Write an article about Solid"</span>T1 is due October <span class="hljs-number">5</span>rd <span class="hljs-number">2018</span>T1 is assigned to @itsarnavbT1 is incomplete
</code></pre><h4 id="heading-turtle"><strong>Turtle</strong></h4>
<p>Turtle is a compact way of representing RDF data, using URLs to represent <code>subject</code>, <code>predicate</code> and <code>object</code>.</p>
<p>That’s repetitive and hard to read, so turtle has a prefix and shorthand system. This gets especially important with longer documents.</p>
<p>You can read more about <a target="_blank" href="https://solid.inrupt.com/docs/expressing-ld-with-turtle">turtle</a>. Or you could check out a full turtle document <a target="_blank" href="https://ruben.verborgh.org/profile/#me">here</a>. It’s a detailed public profile of Prof. Ruben Verborgh, who’s a part of the Solid team.</p>
<h4 id="heading-semantic-web">Semantic web</h4>
<p>Tim Berners-Lee best explains this:</p>
<blockquote>
<p>I have a dream for the Web [in which computers] become capable of analyzing all the data on the Web - the content, links, and transactions between people and computers. A “Semantic Web”, which makes this possible, has yet to emerge, but when it does, the day-to-day mechanisms of trade, bureaucracy and our daily lives will be handled by machines talking to machines. The “<a target="_blank" href="https://en.wikipedia.org/wiki/Intelligent_agent">intelligent agents</a>” people have touted for ages will finally materialize</p>
</blockquote>
<h3 id="heading-first-steps">First steps</h3>
<p>Do these, in any order that works for you.</p>
<ul>
<li><a target="_blank" href="https://solid.inrupt.com/get-a-solid-pod">Get a pod</a>: Signup with any free pod provider, or run your own server (if that’s your thing).</li>
<li><a target="_blank" href="https://solid.inrupt.com/docs/app-on-your-lunch-break">Make a Solid app with this tutorial</a></li>
<li><a target="_blank" href="https://solid.gitbook.io/solid-hacks/">Read about these hacks made with Solid</a></li>
<li><a target="_blank" href="https://solid.inrupt.com/docs">Read the Solid docs</a></li>
</ul>
<h3 id="heading-go-solid">Go Solid</h3>
<p>You can help out the Solid ecosystem by</p>
<ul>
<li>contributing to the development of Solid itself, and related infrastructure.</li>
<li>developing apps using Solid.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*tapHw7Osr5LbkuUh" alt="Image" width="730" height="538" loading="lazy"></p>
<p>But beware, at the moment, learning and developing for Solid requires a lot of trial and error, and asking potentially silly questions. There’s no Stack Overflow to refer to. Debugging some errors might require you to dig into the source.</p>
<p>Here are the communities where you can get help:</p>
<ul>
<li><a target="_blank" href="https://reddit.com/r/solid">r/solid</a> (I’m one of the mods)</li>
<li><a target="_blank" href="https://gitter.im/solid/home">gitter.im/solid</a></li>
</ul>
<p>And finally, my DMs are open: <a target="_blank" href="https://twitter.com/itsarnavb">@itsarnavb</a>. I’ll try to answer every question I get, or find someone who can.</p>
<p>And I’ll keep this article up to date with the best resources to learn about Solid.</p>
<h3 id="heading-further-reading">Further Reading</h3>
<ul>
<li><a target="_blank" href="https://solid.mit.edu">Solid website - solid.mit.edu</a></li>
<li><a target="_blank" href="https://ruben.verborgh.org/blog/2017/12/20/paradigm-shifts-for-the-decentralized-web/">Paradigm shifts for the decentralized web - Ruben Verborgh</a></li>
<li><a target="_blank" href="https://medium.com/@timberners_lee/one-small-step-for-the-web-87f92217d085">One Small Step for the Web - Tim Berners-Lee</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A comprehensive guide to coding a blockchain-powered online community ]]>
                </title>
                <description>
                    <![CDATA[ By Sandeep Panda At Hashnode we have been experimenting a lot with blockchain and its use-cases. We have been running a developers’ community ourselves, and the idea behind “decentralized communities” fascinates me a lot. The fact that everyone owns ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-comprehensive-guide-to-coding-a-blockchain-powered-online-community-f938792dbcb4/</link>
                <guid isPermaLink="false">66c3424c4f7405e6476b014a</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 05 Jun 2018 20:08:25 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1h7x469AFYKuUveSj7ZlOA.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sandeep Panda</p>
<p>At Hashnode we have been experimenting a lot with blockchain and its use-cases. We have been running a developers’ community ourselves, and the idea behind “decentralized communities” fascinates me a lot. The fact that everyone owns the data and controls the platform can give rise to new types of social apps and disrupt the traditional way of building online communities.</p>
<p>Platforms like <a target="_blank" href="https://steemit.com">Steemit</a> have proven that it’s possible to build such communities and reward users for their contributions. But how should someone go about replicating it and launching their own decentralized social platform powered by blockchain?</p>
<p>To answer the question, I took up the challenge of building a decentralized version of HackerNews.</p>
<p>During the process, I evaluated multiple platforms and finally zeroed in on a protocol called <a target="_blank" href="https://tendermint.com">Tendermint</a>. Using Tendermint, I have built a prototype called “Mint” which can serve as a boilerplate for building blockchain-powered social apps.</p>
<p>The codebase is on GitHub. You can check out the following links for code and demo:</p>
<ul>
<li><a target="_blank" href="https://github.com/Hashnode/mint">Mint Blockchain</a></li>
<li><a target="_blank" href="https://github.com/Hashnode/Uphack">Website Code (Blockchain Front-end)</a></li>
<li><a target="_blank" href="http://uphack.co">Demo</a></li>
</ul>
<p>So what does it take to build a blockchain-powered social community where the user-generated data is decentralized? If you are looking for an answer, you have come to the right place. Read on.</p>
<h3 id="heading-preliminary-observations">Preliminary Observations</h3>
<p>Initially, I thought of utilizing an existing platform to build the app. Smart Contract platforms like <strong>Ethereum</strong>, <strong>NEM</strong>, <strong>NEO</strong>, and so on offer storage of assets, but these are not designed to store large amount of data.</p>
<p>HyperLedger Fabric is compelling, but it’s designed to be deployed in private blockchain networks. Hashgraph sounds interesting, but it’s experimental as of now.</p>
<p>Other potential solutions were: <strong>Lisk Sidechains</strong>, <strong>Loom Network,</strong> and <strong>BigChainDB</strong>. The first two are in private alpha (invite-only), while BigChainDB is powered by <a target="_blank" href="https://tendermint.com/">Tendermint</a>.</p>
<p>So, instead of using BigChainDB, I decided to play around with Tendermint directly and see what was possible.</p>
<h3 id="heading-why-tendermint">Why Tendermint</h3>
<p>Tendermint is a protocol that takes care of the consensus layer using BFT algorithm while you just focus on writing the business logic.</p>
<p>The beauty of the protocol is that you are literally free to choose any programming language to build an interface (Application Blockchain Interface or simply ABCI) that interacts with the blockchain.</p>
<p>Tendermint handles the most complex aspects of a blockchain such as block production rounds, peer to peer connectivity, gossiping about new blocks, transaction handling, and more. It stores the transactions on the disk using LevelDB and also delivers the confirmed transaction to your ABCI server so that you can create a global state out of it.</p>
<p>Sounds interesting? Let’s see how to create a blockchain app that stores data on chain using Tendermint.</p>
<h3 id="heading-whats-needed">What’s Needed?</h3>
<p>Here is what you are going to need:</p>
<ul>
<li>Macbook / Ubuntu server</li>
<li>Golang</li>
<li>Tendermint</li>
<li>MongoDB</li>
<li>And beer… (Coffee lovers can replace this with coffee)</li>
</ul>
<h3 id="heading-setting-up-the-machine">Setting up the Machine</h3>
<p>Tendermint is written in <a target="_blank" href="https://golang.org/">Go</a>. So, we need to install the Go language first. Visit <a target="_blank" href="https://golang.org/dl/">this link</a> to check out a few download options. If you are on Ubuntu, you can follow <a target="_blank" href="https://medium.com/@patdhlk/how-to-install-go-1-9-1-on-ubuntu-16-04-ee64c073cd79">this guide</a>.</p>
<p>By default, Go chooses <code>$HOME/go</code> as your workspace. If you want to use a different location as your workspace, you can set <code>GOPATH</code> variable in <code>~/.profile</code> . From now on, we’ll refer to this location as <code>GOPATH</code>.</p>
<p>Here is how <code>~/.profile</code> file looks on my machine:</p>
<pre><code><span class="hljs-keyword">export</span> GOPATH=<span class="hljs-string">"$HOME/go"</span> <span class="hljs-keyword">export</span> PATH=~<span class="hljs-regexp">/.yarn/</span>bin:$GOPATH/bin:$PATHexport GOBIN=<span class="hljs-string">"$GOPATH/bin"</span>
</code></pre><p>Remember to set <code>GOBIN</code> variable as shown above. This is where the Go binaries will be installed.</p>
<p><strong>Don’t forget to run source ~/.profile after updating the file.</strong></p>
<p>Now we can install Tendermint. Here are the steps:</p>
<ul>
<li><code>cd $GOPATH/src/github.com</code></li>
<li><code>mkdir tendermint</code></li>
<li><code>cd tendermint</code></li>
</ul>
<p>And finally,</p>
<pre><code>git clone https:<span class="hljs-comment">//github.com/tendermint/tendermint</span>
</code></pre><p>This will install the latest version of Tendermint. As I have tested my code against <code>v0.19.7</code>, let’s check out the specific release.</p>
<pre><code>cd tendermintgit checkout v0<span class="hljs-number">.19</span><span class="hljs-number">.7</span>
</code></pre><p>This will put you on v0.19.7. To proceed with the installation, run the following commands:</p>
<pre><code>make get_tools make get_vendor_depsmake install
</code></pre><p>Congrats! You have installed Tendermint successfully. If everything was installed as intended, the command <code>tendermint version</code> will print out the Tendermint version.</p>
<p>Now, you should go ahead and install <a target="_blank" href="https://docs.mongodb.com/manual/installation/">MongoDB</a>.</p>
<h3 id="heading-coding-the-blockchain">Coding the Blockchain</h3>
<p>If you want to understand how Tendermint works, go through <a target="_blank" href="http://tendermint.readthedocs.io/projects/tools/en/master/introduction.html#intro-to-abci">this guide</a>. You may also find the following diagram helpful.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/rJyiZxm-1rAXkSFkV9XY-TtVoqvoS2forja5" alt="Image" width="800" height="800" loading="lazy">
_Source: [Tendermint Docs](http://tendermint.readthedocs.io/projects/tools/en/master/introduction.html" rel="noopener" target="<em>blank" title=")</em></p>
<p>I’ll outline a few important concepts here:</p>
<ul>
<li>Tendermint core handles the consensus part.</li>
<li>You need to write an ABCI server that handles the business logic, validations, and so on. Although you can write this in any language, our language of choice will be Go.</li>
<li>Tendermint core will interact with your ABCI server via socket connections.</li>
<li>The ABCI server has many methods (JS developers can think of them as callbacks) that will be invoked by Tendermint core on various events.</li>
<li>Two important methods are: <code>CheckTx</code> and <code>DeliverTx</code>. The first one is called to validate a transaction, while the latter is called when the <code>Tx</code> is confirmed.</li>
<li><code>DeliverTx</code> helps you take necessary actions based on the confirmed transactions. In our case, we’ll use this to create and update our global state stored in MongoDB.</li>
<li>Tendermint uses BFT consensus. This means more than 2/3 of the validators need to have consensus in order to commit a transaction. So, even if 1/3 of the validators go rogue, the blockchain will still work.</li>
<li>In a real world scenario (at least in a public deployment), you will most likely add some sort of consensus such as PoS (Proof of State) in addition to BFT consensus. In this case, we’ll just go ahead with simple BFT consensus. I’ll leave adding PoS up to you.</li>
</ul>
<p>I suggest that you clone the blockchain ABCI server (code-named <a target="_blank" href="https://github.com/Hashnode/mint">mint</a>) from GitHub. But before we go ahead, we need to install a dependency management tool called <a target="_blank" href="https://github.com/golang/dep">dep</a>.</p>
<p>If you are on a Mac, you can just run <code>brew install dep</code> . For Ubuntu, run the following command.</p>
<pre><code>curl https:<span class="hljs-comment">//raw.githubusercontent.com/golang/dep/master/install.sh | sh</span>
</code></pre><p>Now you can clone the codebase of mint.</p>
<pre><code>cd $GOPATH/srcgit clone https:<span class="hljs-comment">//github.com/Hashnode/mintcd mintdep ensurego install mint</span>
</code></pre><p>Sweet! You have now installed mint, which is an ABCI server and works along with Tendermint core.</p>
<p>Now, let me walk you through the whole set-up and all the code.</p>
<h3 id="heading-entry-point">Entry Point</h3>
<p>You can find the code (and entry point) on GitHub <a target="_blank" href="https://github.com/Hashnode/mint/blob/master/mint.go">here</a>.</p>
<p>The entry point of the app is <code>mint.go</code> . The most important part of the file is the following section:</p>
<pre><code>app = jsonstore.NewJSONStoreApplication(db)srv, <span class="hljs-attr">err</span> := server.NewServer(<span class="hljs-string">"tcp://0.0.0.0:46658"</span>, <span class="hljs-string">"socket"</span>, app) <span class="hljs-keyword">if</span> err != nil {  <span class="hljs-keyword">return</span> err }
</code></pre><p>All the business logic, methods, and so on are defined in the package <code>jsonstore</code> . The above code simply creates a TCP server on port <code>46658</code> that accepts socket connections from Tendermint core.</p>
<p>Now let’s look at <code>jsonstore</code>package.</p>
<h3 id="heading-business-logic">Business Logic</h3>
<p><a target="_blank" href="https://github.com/Hashnode/mint/blob/master/jsonstore/jsonstore.go">Here’s</a> the <code>jsonstore</code> repo.</p>
<p>Our ABCI server does two important things:</p>
<ul>
<li>Validates incoming transactions. If a transaction is invalid, it returns an error code and the transaction is rejected.</li>
<li>Once a transaction is committed (confirmed by &gt; 2/3 of the validators) and stored in LevelDB, the ABCI server updates its global state stored in MongoDB.</li>
</ul>
<p>We’re going to use <a target="_blank" href="https://labix.org/mgo">mgo</a> for interacting with MongoDB. So, <code>jsonstore.go</code> defines 5 models that correspond to 5 different MongoDB collections.</p>
<p>The code looks like the following:</p>
<pre><code><span class="hljs-comment">// Post ...type Post struct {    ID          bson.ObjectId `bson:"_id" json:"_id"`    Title       string        `bson:"title" json:"title"`    URL         string        `bson:"url" json:"url"`    Text        string        `bson:"text" json:"text"`    Author      bson.ObjectId `bson:"author" json:"author"`    Upvotes     int           `bson:"upvotes" json:"upvotes"`    Date        time.Time     `bson:"date" json:"date"`    Score       float64       `bson:"score" json:"score"`    NumComments int           `bson:"numComments" json:"numComments"`    AskUH       bool          `bson:"askUH" json:"askUH"`    ShowUH      bool          `bson:"showUH" json:"showUH"`    Spam        bool          `bson:"spam" json:"spam"`}</span>
</code></pre><pre><code><span class="hljs-comment">// Comment ...type Comment struct {    ID              bson.ObjectId `bson:"_id" json:"_id"`    Content         string        `bson:"content" json:"content"`    Author          bson.ObjectId `bson:"author" json:"author"`    Upvotes         int           `bson:"upvotes" json:"upvotes"`    Score           float64       `bson:"score" json:"score"`    Date            time.Time    PostID          bson.ObjectId `bson:"postID" json:"postID"`    ParentCommentID bson.ObjectId `bson:"parentCommentId,omitempty" json:"parentCommentId"`}</span>
</code></pre><pre><code><span class="hljs-comment">// User ...type User struct {    ID        bson.ObjectId `bson:"_id" json:"_id"`    Name      string        `bson:"name" json:"name"`    Username  string        `bson:"username" json:"username"`    PublicKey string        `bson:"publicKey" json:"publicKey"`}</span>
</code></pre><pre><code><span class="hljs-comment">// UserPostVote ...type UserPostVote struct {    ID     bson.ObjectId `bson:"_id" json:"_id"`    UserID bson.ObjectId `bson:"userID" json:"userID"`    PostID bson.ObjectId `bson:"postID" json:"postID"`}</span>
</code></pre><pre><code><span class="hljs-comment">// UserCommentVote ...type UserCommentVote struct {    ID        bson.ObjectId `bson:"_id" json:"_id"`    UserID    bson.ObjectId `bson:"userID" json:"userID"`    CommentID bson.ObjectId `bson:"commentID" json:"commentID"`}</span>
</code></pre><p>We also define a few utility functions such as the following:</p>
<pre><code>func byteToHex(input []byte) string {    <span class="hljs-keyword">var</span> hexValue string    <span class="hljs-keyword">for</span> _, <span class="hljs-attr">v</span> := range input {        hexValue += fmt.Sprintf(<span class="hljs-string">"%02x"</span>, v)    }    <span class="hljs-keyword">return</span> hexValue}
</code></pre><pre><code>func findTotalDocuments(db *mgo.Database) int64 {    <span class="hljs-attr">collections</span> := [<span class="hljs-number">5</span>]string{<span class="hljs-string">"posts"</span>, <span class="hljs-string">"comments"</span>, <span class="hljs-string">"users"</span>, <span class="hljs-string">"userpostvotes"</span>, <span class="hljs-string">"usercommentvotes"</span>}    <span class="hljs-keyword">var</span> sum int64
</code></pre><pre><code><span class="hljs-keyword">for</span> _, <span class="hljs-attr">collection</span> := range collections {        count, <span class="hljs-attr">_</span> := db.C(collection).Find(nil).Count()        sum += int64(count)    }
</code></pre><pre><code><span class="hljs-keyword">return</span> sum}
</code></pre><pre><code>func hotScore(votes int, date time.Time) float64 {    <span class="hljs-attr">gravity</span> := <span class="hljs-number">1.8</span>    hoursAge := float64(date.Unix() * <span class="hljs-number">3600</span>)    <span class="hljs-keyword">return</span> float64(votes<span class="hljs-number">-1</span>) / math.Pow(hoursAge+<span class="hljs-number">2</span>, gravity)}
</code></pre><pre><code><span class="hljs-comment">// FindTimeFromObjectID ... Convert ObjectID string to Timefunc FindTimeFromObjectID(id string) time.Time {    ts, _ := strconv.ParseInt(id[0:8], 16, 64)    return time.Unix(ts, 0)}</span>
</code></pre><p>These will be used subsequently in the code.</p>
<h4 id="heading-inside-checktx">Inside CheckTx</h4>
<p>Now let’s come to the validation part. How do we accept or reject a transaction? Let’s say someone is trying to sign up, but doesn’t choose a valid username. How can our app validate this?</p>
<p>It’s done via <code>CheckTx</code> function. The signature looks like the following:</p>
<pre><code>func (app *JSONStoreApplication) CheckTx(tx []byte) types.ResponseCheckTx {
</code></pre><pre><code> <span class="hljs-comment">// ... Validation logic}</span>
</code></pre><p>When a Tendermint node receives a transaction, it invokes<code>CheckTx</code> of ABCI server and passes <code>tx</code> data as a <code>byte</code> array argument. If <code>CheckTx</code> returns a non-zero code, the transaction is rejected.</p>
<p>In our case, clients send Base64 encoded stringified JSON objects to the Tendermint node via an RPC request. So, it is our job to decode the tx and unmarshall the string into a JSON object.</p>
<p>It’s done like this:</p>
<pre><code><span class="hljs-keyword">var</span> temp interface{}err := json.Unmarshal(tx, &amp;temp)<span class="hljs-keyword">if</span> err != nil {  panic(err)}message := temp.(map[string]interface{})
</code></pre><p><code>message</code> object typically looks like the following:</p>
<pre><code>{  <span class="hljs-attr">body</span>: {... Message body},  <span class="hljs-attr">publicKey</span>: &lt;Public Key of Sender&gt;,  signature: &lt;message.body is signed with the Private Key&gt;}
</code></pre><p>First, we need to make sure that <strong>said</strong> <strong>person</strong> has indeed submitted the transaction to the blockchain, not someone else claiming to be that person.</p>
<p>The best way to validate is to ask clients to sign the message body with the user’s private key and attach both the public key and the signature to the payload. We’ll use <code>ed25519</code> algorithm to generate the keys and sign the message in the browser and hit the RPC endpoint. In the <code>CheckTx</code> function we’ll again use <code>ed25519</code> and verify the message with the help of the user’s public key.</p>
<p>It’s done like this:</p>
<pre><code>pubKeyBytes, <span class="hljs-attr">err</span> := base64.StdEncoding.DecodeString(message[<span class="hljs-string">"publicKey"</span>].(string))
</code></pre><pre><code>sigBytes, <span class="hljs-attr">err</span> := hex.DecodeString(message[<span class="hljs-string">"signature"</span>].(string))
</code></pre><pre><code>messageBytes := []byte(message[<span class="hljs-string">"body"</span>].(string))isCorrect := ed25519.Verify(pubKeyBytes, messageBytes, sigBytes)<span class="hljs-keyword">if</span> isCorrect != <span class="hljs-literal">true</span> {  <span class="hljs-keyword">return</span> types.ResponseCheckTx{<span class="hljs-attr">Code</span>: code.CodeTypeBadSignature}}
</code></pre><p>In the above example, we use the <code>ed25519</code> package to validate the message. Various codes such as <code>code.CodeTypeBadSignature</code> are defined inside <code>code</code> package. These are just integers. Just remember that if you want to reject a transaction, you have to return a non-zero code. In our case, if we detect that the message signature is not valid, we return <code>CodeTypeBadSignature</code> which is <code>4</code>.</p>
<p>The next section of <code>CheckTx</code> deals with various data validations, such as:</p>
<ul>
<li>If the user is sending any transaction other than “createUser (Sign up)”, we first check that the user’s public key is present in our database.</li>
<li>If the user is trying to create a post or comment, it should have valid data such as non-empty <code>title</code> , <code>content</code> , and so on.</li>
<li>If the user is trying to sign up, the username should have acceptable characters.</li>
</ul>
<p>The code looks like the following:</p>
<pre><code><span class="hljs-comment">// ==== Does the user really exist? ======if body["type"] != "createUser" { publicKey := strings.ToUpper(byteToHex(pubKeyBytes))</span>
</code></pre><pre><code> count, <span class="hljs-attr">_</span> := db.C(<span class="hljs-string">"users"</span>).Find(bson.M{<span class="hljs-string">"publicKey"</span>: publicKey}).Count()
</code></pre><pre><code> <span class="hljs-keyword">if</span> count == <span class="hljs-number">0</span> {  <span class="hljs-keyword">return</span> types.ResponseCheckTx{<span class="hljs-attr">Code</span>: code.CodeTypeBadData} }}<span class="hljs-comment">// ==== Does the user really exist? ======</span>
</code></pre><pre><code>codeType := code.CodeTypeOK
</code></pre><pre><code><span class="hljs-comment">// ===== Data Validation =======switch body["type"] {case "createPost": entity := body["entity"].(map[string]interface{})</span>
</code></pre><pre><code>  <span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"id"</span>] == nil) || (bson.IsObjectIdHex(entity[<span class="hljs-string">"id"</span>]. (string)) != <span class="hljs-literal">true</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }
</code></pre><pre><code><span class="hljs-keyword">if</span> entity[<span class="hljs-string">"title"</span>] == nil || strings.TrimSpace(entity[<span class="hljs-string">"title"</span>].(string)) == <span class="hljs-string">""</span> {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"url"</span>] != nil) &amp;&amp; (strings.TrimSpace(entity[<span class="hljs-string">"url"</span>].(string)) != <span class="hljs-string">""</span>) {  _, <span class="hljs-attr">err</span> := url.ParseRequestURI(entity[<span class="hljs-string">"url"</span>].(string))  <span class="hljs-keyword">if</span> err != nil {   codeType = code.CodeTypeBadData   <span class="hljs-keyword">break</span>  } }<span class="hljs-keyword">case</span> <span class="hljs-string">"createUser"</span>: entity := body[<span class="hljs-string">"entity"</span>].(map[string]interface{})
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"id"</span>] == nil) || (bson.IsObjectIdHex(entity[<span class="hljs-string">"id"</span>].(string)) != <span class="hljs-literal">true</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }
</code></pre><pre><code>r, <span class="hljs-attr">_</span> := regexp.Compile(<span class="hljs-string">"^[A-Za-z_0-9]+$"</span>)
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"username"</span>] == nil) || (strings.TrimSpace(entity[<span class="hljs-string">"username"</span>].(string)) == <span class="hljs-string">""</span>) || (r.MatchString(entity[<span class="hljs-string">"username"</span>].(string)) != <span class="hljs-literal">true</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"name"</span>] == nil) || (strings.TrimSpace(entity[<span class="hljs-string">"name"</span>].(string)) == <span class="hljs-string">""</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }<span class="hljs-keyword">case</span> <span class="hljs-string">"createComment"</span>: entity := body[<span class="hljs-string">"entity"</span>].(map[string]interface{})
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"id"</span>] == nil) || (bson.IsObjectIdHex(entity[<span class="hljs-string">"id"</span>].(string)) != <span class="hljs-literal">true</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"postId"</span>] == nil) || (bson.IsObjectIdHex(entity[<span class="hljs-string">"postId"</span>].(string)) != <span class="hljs-literal">true</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }
</code></pre><pre><code><span class="hljs-keyword">if</span> (entity[<span class="hljs-string">"content"</span>] == nil) || (strings.TrimSpace(entity[<span class="hljs-string">"content"</span>].(string)) == <span class="hljs-string">""</span>) {  codeType = code.CodeTypeBadData  <span class="hljs-keyword">break</span> }}
</code></pre><pre><code><span class="hljs-comment">// ===== Data Validation =======return types.ResponseCheckTx{Code: codeType}</span>
</code></pre><p>The code is really simple and pretty self-explanatory. So, I won’t go into the details, and will leave it up to you to read and explore further.</p>
<h4 id="heading-inside-delivertx">Inside DeliverTx</h4>
<p>Once a transaction is confirmed and applied to the blockchain, Tendermint core calls <code>DeliverTx</code> and passes the transaction as a byte array. The function signature looks like the following:</p>
<pre><code>func (app *JSONStoreApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {  <span class="hljs-comment">// ... Code goes here}</span>
</code></pre><p>We’ll use this function to construct a MongoDB-based global state. We do this so that our website users can read the data easily.</p>
<p>This function is big and has multiple cases. In this section I’ll just cover only one case which is “Post Creation”. As the rest of the code is similar, I’ll leave it up to you to dig deeper and explore the full code.</p>
<p>Firstly, we’ll go ahead and unmarshall the <code>tx</code>data into a JSON object:</p>
<pre><code><span class="hljs-keyword">var</span> temp interface{}err := json.Unmarshal(tx, &amp;temp)
</code></pre><pre><code><span class="hljs-keyword">if</span> err != nil { panic(err)}
</code></pre><pre><code>message := temp.(map[string]interface{})
</code></pre><pre><code><span class="hljs-keyword">var</span> bodyTemp interface{}
</code></pre><pre><code>errBody := json.Unmarshal([]byte(message[<span class="hljs-string">"body"</span>].(string)), &amp;bodyTemp)
</code></pre><pre><code><span class="hljs-keyword">if</span> errBody != nil { panic(errBody)}
</code></pre><pre><code>body := bodyTemp.(map[string]interface{})
</code></pre><p>For post creation, the message object looks like the following:</p>
<pre><code>{<span class="hljs-attr">body</span>: {  <span class="hljs-attr">type</span>: <span class="hljs-string">"createPost"</span>,  <span class="hljs-attr">entity</span>: {    <span class="hljs-attr">id</span>: id,    <span class="hljs-attr">title</span>: title,    <span class="hljs-attr">url</span>: url,    <span class="hljs-attr">text</span>: text,    <span class="hljs-attr">author</span>: author  }},<span class="hljs-attr">signature</span>: signature,<span class="hljs-attr">publicKey</span>: publicKey}
</code></pre><p>And here is how <code>DeliverTx</code> function creates a new entry in the database when a “createPost” transaction is committed:</p>
<pre><code>entity := body[<span class="hljs-string">"entity"</span>].(map[string]interface{})
</code></pre><pre><code><span class="hljs-keyword">var</span> post Postpost.ID = bson.ObjectIdHex(entity[<span class="hljs-string">"id"</span>].(string))post.Title = entity[<span class="hljs-string">"title"</span>].(string)
</code></pre><pre><code><span class="hljs-keyword">if</span> entity[<span class="hljs-string">"url"</span>] != nil { post.URL = entity[<span class="hljs-string">"url"</span>].(string)}<span class="hljs-keyword">if</span> entity[<span class="hljs-string">"text"</span>] != nil { post.Text = entity[<span class="hljs-string">"text"</span>].(string)}
</code></pre><pre><code><span class="hljs-keyword">if</span> strings.Index(post.Title, <span class="hljs-string">"Show UH:"</span>) == <span class="hljs-number">0</span> { post.ShowUH = <span class="hljs-literal">true</span>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> strings.Index(post.Title, <span class="hljs-string">"Ask UH:"</span>) == <span class="hljs-number">0</span> { post.AskUH = <span class="hljs-literal">true</span>}
</code></pre><pre><code>pubKeyBytes, <span class="hljs-attr">errDecode</span> := base64.StdEncoding.DecodeString(message[<span class="hljs-string">"publicKey"</span>].(string))
</code></pre><pre><code><span class="hljs-keyword">if</span> errDecode != nil { panic(errDecode)}
</code></pre><pre><code>publicKey := strings.ToUpper(byteToHex(pubKeyBytes))
</code></pre><pre><code><span class="hljs-keyword">var</span> user Usererr := db.C(<span class="hljs-string">"users"</span>).Find(bson.M{<span class="hljs-string">"publicKey"</span>: publicKey}).One(&amp;user)<span class="hljs-keyword">if</span> err != nil { panic(err)}post.Author = user.ID
</code></pre><pre><code>post.Date = FindTimeFromObjectID(post.ID.Hex())
</code></pre><pre><code>post.Upvotes = <span class="hljs-number">1</span>
</code></pre><pre><code>post.NumComments = <span class="hljs-number">0</span>
</code></pre><pre><code><span class="hljs-comment">// Calculate hot rankpost.Score = hotScore(post.Upvotes, post.Date)</span>
</code></pre><pre><code><span class="hljs-comment">// While replaying the transaction, check if it has been marked as spam</span>
</code></pre><pre><code>spamCount, <span class="hljs-attr">_</span> := db.C(<span class="hljs-string">"spams"</span>).Find(bson.M{<span class="hljs-string">"postID"</span>: post.ID}).Count()
</code></pre><pre><code><span class="hljs-keyword">if</span> spamCount &gt; <span class="hljs-number">0</span> { post.Spam = <span class="hljs-literal">true</span>}
</code></pre><pre><code>dbErr := db.C(<span class="hljs-string">"posts"</span>).Insert(post)
</code></pre><pre><code><span class="hljs-keyword">if</span> dbErr != nil { panic(dbErr)}
</code></pre><pre><code><span class="hljs-keyword">var</span> <span class="hljs-built_in">document</span> UserPostVotedocument.ID = bson.NewObjectId()<span class="hljs-built_in">document</span>.UserID = user.IDdocument.PostID = post.ID
</code></pre><pre><code>db.C(<span class="hljs-string">"userpostvotes"</span>).Insert(<span class="hljs-built_in">document</span>)
</code></pre><p>The actual code block has a switch statement that handles each type of transaction differently. Feel free to check out the code and play around. If something is unclear, feel free to write your queries in the comments below.</p>
<p>Now that we’ve examined two important aspects of the ABCI server, let’s try to run both Tendermint core and our server and see how to send transactions.</p>
<p>In order to run the app, run the following commands from two different terminals.</p>
<p>First, run:</p>
<pre><code>mint
</code></pre><p>If the command succeeds, you will see the following output in the terminal:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ai-JWS7ryQg6Ks0tavletYx274e-0i6830jS" alt="Image" width="800" height="425" loading="lazy">
<em>Mint Output</em></p>
<p>Make sure MongoDB is already running before starting <code>mint</code>. If your terminal is unable to recognize <code>mint</code> command, be sure to run <code>source ~/.profile</code> .</p>
<p>Then start Tendermint in a different terminal:</p>
<pre><code>tendermint node --consensus.create_empty_blocks=<span class="hljs-literal">false</span>
</code></pre><p>By default, Tendermint produces new blocks every 3 seconds, even if there are no transactions.</p>
<p>To prevent that we use the flag:</p>
<pre><code>consensus.create_empty_blocks=<span class="hljs-literal">false</span>
</code></pre><p>Now that Tendermint is running you can start sending the transactions to it. You need a client that can generate <code>ed25519</code> keys, sign your requests, and hit the RPC endpoint exposed by Tendermint.</p>
<p>An example request (Node.js) looks like this:</p>
<pre><code><span class="hljs-keyword">const</span> base64Data = req.body.base64Data;
</code></pre><pre><code><span class="hljs-keyword">let</span> headers = {    <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'text/plain'</span>,    <span class="hljs-string">'Accept'</span>:<span class="hljs-string">'application/json-rpc'</span>}
</code></pre><pre><code><span class="hljs-keyword">let</span> options = {    <span class="hljs-attr">url</span>: <span class="hljs-string">"http://localhost:46657"</span>,    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,    <span class="hljs-attr">headers</span>: headers,    <span class="hljs-attr">json</span>: <span class="hljs-literal">true</span>,    <span class="hljs-attr">body</span>: {<span class="hljs-string">"jsonrpc"</span>:<span class="hljs-string">"2.0"</span>,<span class="hljs-string">"method"</span>:<span class="hljs-string">"broadcast_tx_commit"</span>,<span class="hljs-string">"params"</span>: { <span class="hljs-string">"tx"</span> : base64Data } ,<span class="hljs-string">"id"</span>:<span class="hljs-string">"something"</span>}}
</code></pre><pre><code>request(options, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error, response, body</span>) </span>{    res.json({ <span class="hljs-attr">body</span>: response.body });});
</code></pre><p>Note that the RPC endpoint is exposed on port <code>46657</code> .</p>
<p>Forming and signing the requests manually can be tedious. So, I suggest that you use <a target="_blank" href="https://github.com/Hashnode/Uphack">Uphack</a> (a HackerNews style website that interacts with the blockchain) to get the full picture.</p>
<p>To install Uphack, follow the steps below:</p>
<pre><code>git clone https:<span class="hljs-comment">//github.com/Hashnode/Uphackcd Uphackyarngulp less // make sure gulp is installed globallynode server.js</span>
</code></pre><p>You can access the website on <code>http://localhost:3000</code> . It looks like this on my machine:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/r4KTf9O7sjlqQah6IgOJ5aNWRDME0mNlpR81" alt="Image" width="800" height="509" loading="lazy">
<em>Uphack</em></p>
<p>As you don’t have any data yet, it will look empty initially. Feel free to register an account and submit some posts to visualize the process.</p>
<p>While you are using the app, open up the network tab of your browser and check out the XHR section. The <code>/rpc</code> URL accepts the base64 data and makes request to Tendermint’s RPC endpoint server-side. You can copy the base64 data and paste it into a <a target="_blank" href="https://www.base64decode.org/">base64 decoder</a> to see the actual data that’s being sent.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/SAZpTI3shyASXIL89fVB4dvPP0ucvsNLI1FP" alt="Image" width="800" height="509" loading="lazy"></p>
<p>Going into the details of Uphack is out of the scope of this tutorial. However, as mentioned above, the code for Uphack (the client) is open source and the logic is straightforward. If you go through the <a target="_blank" href="https://github.com/Hashnode/Uphack">codebase</a> and examine various endpoints, you will develop a better understanding of the whole process.</p>
<h3 id="heading-wrapping-up">Wrapping up</h3>
<p>To summarize, we built a <strong>blockchain</strong> that stores JSON data on chain and accepts transactions in the form of base64. To demonstrate the usage, we also briefly examined Uphack, <strong>a HackerNews style website</strong> that interacts with the blockchain.</p>
<p>However, here are a few things you should be aware of:</p>
<ul>
<li>You have built a single node network. This means you are the only validator. If you are interested in multi-node deployment, check out <a target="_blank" href="https://github.com/Hashnode/mint">mint’s</a> documentation. We have deployed a 4-node network so far, and if you wish to become a validator and play around with the blockchain, feel free to reach out to me.</li>
<li>This arrangement uses BFT consensus. In a real world scenario you will need some consensus algorithm like Proof of Stake, Delegated Proof of Stake, and so on.</li>
<li>The blockchain RPC endpoint listens on <code>46657</code> and the ABCI server runs on <code>46658</code> . At any time you can check the blockchain status by visiting <code>localhost:46657/status</code> .</li>
<li>Right now there is no incentive for becoming a validator and producing blocks. In a (D)PoS setting, the block producers should be rewarded with some token every time they propose a block. It’s left as an exercise to you.</li>
<li>The ABCI server can be written in any language. For example, check <a target="_blank" href="https://github.com/tendermint/js-abci/">js-abci</a>.</li>
</ul>
<p>To conclude, I would like to make it clear that I am not a blockchain expert. I am a learner and I am just sharing things I find interesting. Storing data on chain fascinates me and I believe <strong>decentralized social communities</strong> are one of the prime use-cases of blockchain.</p>
<p>If you spot any inaccuracies anywhere in the codebase or article, feel free to point it out. I’ll appreciate if you use <a target="_blank" href="https://github.com/Hashnode/mint">mint</a> &amp; <a target="_blank" href="https://github.com/Hashnode/Uphack">Uphack</a> and provide your feedback. PRs are always welcome!</p>
<p>Let me know what you think in the comments below!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
