Skip to content

Peerism's Peer.ai API built with Truffle, Node.js, Express.js, Solidity, and Ethereum TestRPC

License

Notifications You must be signed in to change notification settings

peerism/peerai-api

Repository files navigation

README


PEER-AI

  • About - Peerism API built with Truffle, Node.js, Express.js, Mongoose, MongoDB, Solidity, and Ganache CLI (TestRPC).

  • Instructions - Setup instructions (for macOS) are provided in the Quick Start Guide shown below.

  • Usage Capabilities - Use cURL to simulate a HTTP POST request to a Peerism API endpoint (instead of sending a request from the Peerism React Native ÐApp https://github.com/peerism/peer.ai). Alternatively allows triggering Middleware functions individually. API routes use an Express.js Middleware Chain that allow a request to compile the Peerism Smart Contract using Solidity Compiler (Solc) and Ether Pudding, then deploy it to the Ethereum TestRPC test network blockchain and responds with the contract address.

Table of Contents

Quick Start Guide

  • Terminal Tab #1 - Install dependencies including Ganache CLI (TestRPC from the Truffle Suite)

    nvm install v9.3.0;
    nvm use;
    nvm use v9.3.0;
    yarn install;
    npm install -g ganache-cli
    
  • Terminal Tab #1 - Run MongoDB Server in a separate Terminal tab

    mongod
    
  • Terminal Tab #2 - Run Ethereum Client using Ganache CLI (TestRPC).

rm -rf ./db;
mkdir -p db/chaindb;
ganache-cli --account '0x0000000000000000000000000000000000000000000000000000000000000001, 10002471238800000000000' \
  --account '0x0000000000000000000000000000000000000000000000000000000000000002, 10004471238800000000000' \
  --unlock '0x0000000000000000000000000000000000000000000000000000000000000001' \
  --unlock '0x0000000000000000000000000000000000000000000000000000000000000002' \
  --unlock '0x7e5f4552091a69125d5dfcb7b8c2659029395bdf' \
  --unlock '0x2b5ad5c4795c026514f8317c7a215e218dccd6cf' \
  --blocktime 0 \
  --deterministic true \
  --port 8545 \
  --hostname localhost \
  --gasPrice 20000000000 \
  --gasLimit 0x8000000 \
  --debug true \
  --mem true \
  --networkId 1337 \
  --db './db/chaindb'
  • Terminal Tab #3 - Compile and Deploy Smart Contracts to TestRPC blockchain

    • Compile Smart Contracts

      • Option 1: Generates build/contracts/Peerism.sol.js

        node lib/compileContract.js Peerism
        
      • Option 2: Genertes build/contracts/Peerism.json (DEPRECATED)

        truffle compile --compile-all;
        
    • Deploy Smart Contracts

      • Option 1: Deploy without Truffle

        • Modify Bitcore dependency before running the next command to avoid error Error: More than one instance of bitcore-lib found. Please make sure to require bitcore-lib and check that submodules do not also include their own bitcore-lib dependency., as described here: bitpay/bitcore#1454, by opening node_modules/bitcore-mnemonic/node_modules/bitcore-lib/index.js and commented out the following lines of code to avoid an error.
          bitcore.versionGuard = function(version) {
            // if (version !== undefined) {
            //   var message = 'More than one instance of bitcore-lib found. ' +
            //     'Please make sure to require bitcore-lib and check that submodules do' +
            //     ' not also include their own bitcore-lib dependency.';
            //   throw new Error(message);
            // }
          };
          
        node lib/deployContract.js Peerism
        
      • Option 2: Deploy with Truffle (DEPRECATED)

        truffle migrate --reset --network development;
        
      • Note: Watch the deployment transactions being send to the blockchain in Terminal Tab #2

  • Terminal Tab #3 - Run Tests

    truffle test;
    
  • Terminal Tab #4 - Drop the server. Run server, then try cURL requests

    yarn run drop; yarn run dev;
    
  • Terminal Tab #4 - Send request to server and receive response for authentication and authorisation to access specific API endpoints.

    • cURL
      • Register with email/password. JWT provided in response (i.e. {"token":"xyz"})
        curl -v -X POST http://localhost:7000/users/auth/register -d "[email protected]&password=123456&name=Luke" -H "Content-Type: application/x-www-form-urlencoded"
        curl -v -X POST http://localhost:7000/users/auth/register -d '{"email":"[email protected]", "password":"123456", "name":"Gavin"}' -H "Content-Type: application/json"
        
      • Sign in with email/password. JWT provided in response (i.e. {"token":"xyz"})
        curl -v -X POST http://localhost:7000/users/auth -d "[email protected]&password=123456" -H "Content-Type: application/x-www-form-urlencoded"
        curl -v -X POST http://localhost:7000/users/auth -d '{"email":"[email protected]", "password":"123456"}' -H "Content-Type: application/json"
        
      • Access a restricted endpoint by providing JWT
        curl -v -X GET http://localhost:7000/users -H "Content-Type: application/json" -H "Authorization: Bearer <INSERT_TOKEN>"
        
      • Create user by providing JWT
        curl -v -X POST http://localhost:7000/users/create --data '[{"email":"[email protected]", "name":"Test"}]' -H "Content-Type: application/json" -H "Authorization: JWT <INSERT_TOKEN>"
        curl -v -X POST http://localhost:7000/users/create -d "[email protected]&name=Test2" -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: JWT <INSERT_TOKEN>"
        
  • Terminal Tab #4 - Send request to server with Smart Contract Name to be Compiled and Deployed to the Ethereum TestRPC and receive response with the Contract Address.

    • cURL
      curl -v -X POST http://localhost:7000/contracts/generate -d '{"contractName":"Peerism"}' -H "Content-Type: application/json"
      
  • Terminal Tab #4 - Experiment in REPL

    • Use Truffle Console

      • Run Truffle Console

        truffle console --network development;
        
      • Run commands

        web3
        web3.currentProvider
        web3.eth.getBalance('0x7e5f4552091a69125d5dfcb7b8c2659029395bdf')
        
    • Attach to EthereumJS TestRPC using Go Ethereum (Geth)

      • Install Geth

      • Start Geth JavaScript console

        geth attach rpc:http://localhost:8545
        
      • Run commands

        web3
        web3.currentProvider
        web3.eth.getBalance('0x7e5f4552091a69125d5dfcb7b8c2659029395bdf')
        eth.accounts
        
    • Optional: Try to perform RPC calls to Ganache TestRPC using cURL. trufflesuite/ganache#383

  • Terminal Tab #5 - Run Tests on port 7111

    yarn run drop; yarn run test-watch
    
  • Terminal Tab #1 - Drop the database. Seed the database

    yarn run drop;
    yarn run seed;
    

Log

  • Initial setup

    git init; touch README.md; touch .gitignore;
    code .;
    
  • Setup API

    yarn init -y; 
    yarn add express body-parser;
    yarn add nodemon --dev;
    touch server.js;
    
  • Add boilerplate contents to server.js

  • Add "dev" in "scripts" section of package.json

  • Add Mongoose

    yarn add mongoose;
    mkdir models; touch models/init.js;
    touch models/User.js;
    touch models/seeds.js;
    touch models/drop.js
    
  • Create Models for Mongoose

  • Add boilerplate contents to models

  • Add scripts to package.json

  • Run MongoDB Server

    mongod
    
  • MongoDB Client

    mongo
    
    show dbs
    use peerai
    show collections
    db.users.find({})
    db.skills.find({})
    
  • Create routes

    mkdir routes
    
  • Modify server.js. Add routes/users.js

  • Add authentication with Passport, Passport-Local, and Passport-Local-Mongoose:

    yarn add passport passport-local passport-local-mongoose
    
  • Rename Person and people to User and users

  • Add User Registration route

  • Add User Sign in route

  • Add JWT library to return a token instead of a user

    yarn add jsonwebtoken;
    
  • Add Passport JWT library

    yarn add passport-jwt
    
  • Add restricted endpoint that requires valid JWT to access

  • Add Controllers https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes

  • Add Route Tests

    yarn add mocha chai chai-http --dev;
    mkdir -p test/routes;
    touch test/routes/users_test.js;
    
  • Add Model Tests

    mkdir test/models;
    touch test/models/users_test.js
    
  • Add Dotenv library to use different database in development and testing

    yarn add lodash;
    yarn add dotenv --dev;
    touch .sample-env;
    echo 'NODE_ENV=development' >> ./.sample-env;
    
  • Add Ethereum dependencies including TestRPC

    yarn add [email protected] [email protected] [email protected] [email protected];
    yarn add ethereumjs-testrpc --dev;
    yarn add solc ether-pudding --dev;
    yarn add truffle-artifactor --dev;
    
  • Problem: Tried to manually compile using Solc with node lib/compileContract.js ConvertLib, which generates ConvertLib.solc.js in build/contracts. However it does not compile MetaCoin.sol, as it returns error 1:27: ParserError: Source "ConvertLib.sol" not found: File not supplied initially.\n ... import "./ConvertLib.sol".

    • Solution: Use Truffle to compile Solidity contracts with truffle compile --compile-all
  • Run shell script in new Terminal tab (copy from https://github.com/ltfschoen/solidity_test/blob/master/testrpc.sh)

    rm -rf ./db;
    mkdir db && mkdir db/chaindb;
    cd ~/code/blockchain/solidity_test; testrpc --account '0x0000000000000000000000000000000000000000000000000000000000000001, 10002471238800000000000' \
      --account '0x0000000000000000000000000000000000000000000000000000000000000002, 10004471238800000000000' \
      --account '0x0000000000000000000000000000000000000000000000000000000000000003, 10004471238800000000000' \
      --account '0x0000000000000000000000000000000000000000000000000000000000000004, 10004471238800000000000' \
      --account '0x0000000000000000000000000000000000000000000000000000000000000005, 10004471238800000000000' \
      --account '0x0000000000000000000000000000000000000000000000000000000000000006, 10004471238800000000000' \
      --account '0x0000000000000000000000000000000000000000000000000000000000000007, 10004471238800000000000' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000001' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000002' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000003' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000004' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000005' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000006' \
      --unlock '0x0000000000000000000000000000000000000000000000000000000000000007' \
      --unlock '0x7e5f4552091a69125d5dfcb7b8c2659029395bdf' \
      --unlock '0x2b5ad5c4795c026514f8317c7a215e218dccd6cf' \
      --blocktime 0 \
      --deterministic true \
      --port 8545 \
      --hostname localhost \
      --gasPrice 20000000000 \
      --gasLimit 1000000 \
      --debug true \
      --mem true \
      --db './db/chaindb'
    
  • Install Truffle

    npm install -g truffle;
    truffle init;
    
  • Run Truffle Unbox in separate directory to get template Metacoin example and move relevant boilerplate contracts and tests into the the root folder

  • Update package.json tests script to run tests for Smart Contracts and API tests:

    "test": "truffle test; NODE_ENV=testing mocha --recursive test/**/*_test.js",
    
  • Remove truffle-config.js and add the following to truffle.js:

    module.exports = {
      // http://truffleframework.com/docs/advanced/configuration
      networks: {
        development: {
          host: "localhost",
          port: 8545,
          network_id: "*" // Match any network id
        }
      }
    };
    
  • Add ethpm.json for EthPM Package Management

    {
      "package_name": "truffle-box-peerism-api-node-express",
      "version": "0.0.1",
      "description": "Truffle Box of Peerism API built with Truffle, Node.js, Express.js,
    Solidity, Ether Pudding, and Ethereum TestRPC",
      "authors": [
        "Luke Schoen <[email protected]>"
      ],
      "keywords": [
        "ethereum",
        "express.js",
        "node.js",
        "middleware",
        "api"
      ],
      "license": "MIT"
    }
    
  • Open node_modules/bitcore-mnemonic/node_modules/bitcore-lib/index.js and commented out the following lines of code to avoid an error.

    bitcore.versionGuard = function(version) {
      // if (version !== undefined) {
      //   var message = 'More than one instance of bitcore-lib found. ' +
      //     'Please make sure to require bitcore-lib and check that submodules do' +
      //     ' not also include their own bitcore-lib dependency.';
      //   throw new Error(message);
      // }
    };
    
  • Run Truffle Console experimentation

    truffle console --network development;
    
  • Build script for Smart Contract (generates .sol.js file in build/contracts/)

    mkdir lib;
    node lib/compileContract.js Peerism
    
    • Alternatively compile with Truffle
  • Deployment script for Smart Contract

    touch lib/deployContract.js;
    node lib/deployContract.js Peerism;
    

FAQ

  • How to understand how to use Passport JWT library?
    • Refer to the library codebase on Github or in node_modules/jsonwebtoken/ i.e. verify.js
    • Use breakpoints
    • Experiment using Node. i.e. Run node then
      npm install jsonwebtoken
      
      const JWT = require('jsonwebtoken');
      JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Imx0ZnNjaG9lbkBnbWFpbC5jb20iLCJpYXQiOjE1MTMwNjY3NTEsImV4cCI6MTUxMzY3MTU1MSwic3ViIjoiNWEyZjkwZmZiNTI5YjI0YzM5MTA1NWM3In0.MkcCR1YD2c21x_WOQObyY-UPAQDWTcooOiO69saUVMI")
      

References

TODO