├── .cfignore ├── .gitignore ├── .project ├── README.md ├── app.js ├── build ├── binding.sln ├── binding.vcxproj ├── binding.vcxproj.filters └── config.gypi ├── chaincodes ├── chaincodes.zip └── query.go ├── config ├── express.js ├── hyperledgerfc.js ├── ibm-blockchain.js └── setup.js ├── docs ├── contractviolated.png ├── creatingAsset.png ├── dashboard.png ├── events.png ├── history.png ├── intro.png ├── payloads.png └── smartcontract.png ├── env ├── env.json ├── local_env.json ├── server_env.json └── uk_env.json ├── manifest.yml ├── package.json ├── public ├── images │ ├── CatToast1.gif │ ├── CatToast2.gif │ ├── Underground.png │ ├── blockchain.png │ ├── blockchain_icon.png │ ├── error.png │ ├── gears.gif │ ├── pallete.png │ ├── player1.png │ ├── player2.png │ └── player3.png ├── index.html ├── js │ ├── animation.js │ ├── demo.js │ └── mqttClient.js └── stylesheets │ └── style.css ├── rest ├── api.js ├── blockchain.js └── listener.js └── routes └── events.js /.cfignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | .vscode/ 4 | .project 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | .vscode/ 4 | .project 5 | env/ -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | nodejshelloworld 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | org.nodeclipse.ui.NodeNature 13 | org.eclipse.wst.jsdt.core.jsNature 14 | 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blockchain Go Demo 2 | 3 | ## About Blockchain Go 4 | - The underlying network for this application is the [Hyperledger Fabric](https://github.com/hyperledger/fabric/tree/master/docs), a Linux Foundation project. You may want to review these instructions to understand a bit about the Hyperledger Fabric. 5 | - **This demo purpose is to basically aid to any people to comprehend about how a blockchain network can be addressed into an existing business process model.** 6 | - **This demo uses Hyperledger Fabric v0.6 (Not supported anymore in bluemix).** 7 | 8 | # Application Background 9 | 10 | We have three companies whose handles the same package (asset) through their supply chains and, all of those agreed to comply with terms and rules 11 | to handle that asset. 12 | 13 | The challenge is on ensuring the integrity of these package through all the supply chain process, since it's hard to tell accuratelly who's the responsible party at real time, but we have a solution! 14 | 15 | ![](/docs/intro.png) 16 | 17 | First we create a new package for transport and eventual transfers: 18 | 19 | ![](/docs/creatingAsset.png) 20 | 21 | So getting hand over a "smart contract" adhered by all the participants companies (Industry, Shipping Company and the Customer) we apply the rules: 22 | 23 | ![](/docs/smartcontract.png) 24 | 25 | With simulated temperature sensors in our virtual package (We could - and did so - run it on real devices), we're publishing payloads to the subscriber application (You're watching the demo through it ): 26 | 27 | ![](/docs/payloads.png) 28 | 29 | This application perform requests to the service that holds communication with our blockchain network: 30 | 31 | ![](/docs/dashboard.png) ![](/docs/events.png) 32 | 33 | As our "Chain Participants" share the visibility about those information, our application notifies all of the participants about the events from the blockchain network: 34 | 35 | ![](/docs/contractviolated.png) 36 | 37 | We have available an immutable history about the transactions from the blockchain ledger: 38 | 39 | ![](/docs/history.png) 40 | 41 | 42 | Powered by IBM Blockchain 43 | 44 | Author: Vitor Diego 45 | - IBM Garage São Paulo 46 | 47 | 48 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * Node.js server for Blockchain-Go demo 4 | * first implementation by Vitor Diego 5 | *------------------------------------------------------------------------------*/ 6 | 7 | 'use strict' 8 | 9 | const app = require('./config/express')(); 10 | const rest = require('./rest/blockchain'); 11 | const start = require('./config/setup').startNetwork(); 12 | const cfenv = require('cfenv'); 13 | const appEnv = cfenv.getAppEnv(); 14 | //const start = require('./config/ibm-blockchain.js').startNetwork(); 15 | //const start = require('./config/hyperledgerfc.js').startNetwork(); 16 | 17 | app.get('/', function(req, res) { 18 | res.render("index"); 19 | }); 20 | 21 | app.post('/request', function(req, res) { 22 | if (req.body !== null && req.body !== undefined) { 23 | console.log(`[app] handling request: ${req}`); 24 | rest.action(req.body, res); 25 | } else { 26 | res.send('invalid request'); 27 | } 28 | }); 29 | 30 | //temporary way(without routes) 31 | setTimeout(function() { 32 | let deploy = 0; 33 | app.get('/blockchain', function(req, res) { 34 | let blockchain = require('./rest/listener').blockdata(); 35 | if (deploy < 1) { 36 | console.log(`isInit ${deploy}`); 37 | blockchain.isInit = true; 38 | deploy = 1; 39 | } 40 | res.send(blockchain); 41 | }); 42 | 43 | let genesis = require('./rest/listener').deployed(); 44 | app.get('/genesis', function(req, res) { 45 | genesis.isDeploy = true; 46 | res.send(genesis); 47 | }); 48 | }, 10000); 49 | 50 | // start server on the specified port and binding host appEnv.port 51 | app.listen(appEnv.port, '0.0.0.0', function() { 52 | // print a message when the server starts listening 53 | console.log("server starting on " + appEnv.url); 54 | }); 55 | 56 | -------------------------------------------------------------------------------- /build/binding.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2015 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "binding", "binding.vcxproj", "{93A34A77-B429-D1D5-D79D-88D2D03365AC}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|x64 = Debug|x64 8 | Release|x64 = Release|x64 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {93A34A77-B429-D1D5-D79D-88D2D03365AC}.Debug|x64.ActiveCfg = Debug|x64 12 | {93A34A77-B429-D1D5-D79D-88D2D03365AC}.Debug|x64.Build.0 = Debug|x64 13 | {93A34A77-B429-D1D5-D79D-88D2D03365AC}.Release|x64.ActiveCfg = Release|x64 14 | {93A34A77-B429-D1D5-D79D-88D2D03365AC}.Release|x64.Build.0 = Release|x64 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /build/binding.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {93A34A77-B429-D1D5-D79D-88D2D03365AC} 15 | Win32Proj 16 | binding 17 | true 18 | x64 19 | 20 | 21 | 22 | DynamicLibrary 23 | 24 | 25 | v140 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | $(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\ 36 | true 37 | $(Configuration)\obj\$(ProjectName)\ 38 | false 39 | true 40 | $(SolutionDir)$(Configuration)\ 41 | .node 42 | .node 43 | .node 44 | .node 45 | $(ProjectName) 46 | $(OutDir)\$(ProjectName).node 47 | 48 | 49 | 50 | C:\Users\IBM_ADMIN\.node-gyp\6.9.1\include\node;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\src;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\uv\include;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\v8\include;%(AdditionalIncludeDirectories) 51 | EnableFastChecks 52 | true 53 | false 54 | ProgramDatabase 55 | 4351;4355;4800;4251;%(DisableSpecificWarnings) 56 | false 57 | false 58 | false 59 | Disabled 60 | NotUsing 61 | NODE_GYP_MODULE_NAME=binding;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;BUILDING_NODE_EXTENSION;DEBUG;_DEBUG;%(PreprocessorDefinitions) 62 | MultiThreadedDebug 63 | true 64 | true 65 | false 66 | Level3 67 | 68 | 69 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;"C:\Users\IBM_ADMIN\.node-gyp\6.9.1\$(Configuration)\node.lib" 70 | /ignore:4199 %(AdditionalOptions) 71 | true 72 | true 73 | iojs.exe;node.exe;%(DelayLoadDLLs) 74 | true 75 | true 76 | true 77 | $(OutDir)$(ProjectName).node 78 | true 79 | true 80 | .node 81 | MachineX64 82 | 83 | 84 | C:\Users\IBM_ADMIN\.node-gyp\6.9.1\include\node;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\src;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\uv\include;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\v8\include;%(AdditionalIncludeDirectories) 85 | NODE_GYP_MODULE_NAME=binding;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;BUILDING_NODE_EXTENSION;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 86 | 87 | 88 | 89 | 90 | C:\Users\IBM_ADMIN\.node-gyp\6.9.1\include\node;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\src;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\uv\include;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\v8\include;%(AdditionalIncludeDirectories) 91 | /MP %(AdditionalOptions) 92 | true 93 | false 94 | ProgramDatabase 95 | 4351;4355;4800;4251;%(DisableSpecificWarnings) 96 | false 97 | Speed 98 | true 99 | AnySuitable 100 | true 101 | true 102 | Full 103 | NotUsing 104 | NODE_GYP_MODULE_NAME=binding;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;BUILDING_NODE_EXTENSION;%(PreprocessorDefinitions) 105 | MultiThreaded 106 | false 107 | true 108 | true 109 | false 110 | Level3 111 | true 112 | 113 | 114 | /LTCG %(AdditionalOptions) 115 | 116 | 117 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;"C:\Users\IBM_ADMIN\.node-gyp\6.9.1\$(Configuration)\node.lib" 118 | /ignore:4199 %(AdditionalOptions) 119 | true 120 | true 121 | iojs.exe;node.exe;%(DelayLoadDLLs) 122 | true 123 | true 124 | true 125 | UseLinkTimeCodeGeneration 126 | true 127 | true 128 | $(OutDir)$(ProjectName).node 129 | true 130 | true 131 | .node 132 | MachineX64 133 | 134 | 135 | C:\Users\IBM_ADMIN\.node-gyp\6.9.1\include\node;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\src;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\uv\include;C:\Users\IBM_ADMIN\.node-gyp\6.9.1\deps\v8\include;%(AdditionalIncludeDirectories) 136 | NODE_GYP_MODULE_NAME=binding;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;BUILDING_NODE_EXTENSION;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /build/binding.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 6 | 7 | 8 | {7B735499-E5DD-1C2B-6C26-70023832A1CF} 9 | 10 | 11 | {92EF4BA8-6BC2-65D1-451F-28EBD4AE726A} 12 | 13 | 14 | {A3C8E949-BCF6-0C67-6656-340A2A097708} 15 | 16 | 17 | {56DF7A98-063D-FB9D-485C-089023B4C16A} 18 | 19 | 20 | {741E0E76-39B2-B1AB-9FA1-F1A20B16F295} 21 | 22 | 23 | {56DF7A98-063D-FB9D-485C-089023B4C16A} 24 | 25 | 26 | {77348C0E-2034-7791-74D5-63C077DF5A3B} 27 | 28 | 29 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4} 30 | 31 | 32 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7} 33 | 34 | 35 | 36 | 37 | .. 38 | 39 | 40 | C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\src 41 | 42 | 43 | .. 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /build/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "debug_devtools": "node", 13 | "force_dynamic_crt": 0, 14 | "host_arch": "x64", 15 | "icu_data_file": "icudt57l.dat", 16 | "icu_data_in": "..\\..\\deps/icu-small\\source/data/in\\icudt57l.dat", 17 | "icu_endianness": "l", 18 | "icu_gyp_path": "tools/icu/icu-generic.gyp", 19 | "icu_locales": "en,root", 20 | "icu_path": "deps/icu-small", 21 | "icu_small": "true", 22 | "icu_ver_major": "57", 23 | "node_byteorder": "little", 24 | "node_enable_d8": "false", 25 | "node_enable_v8_vtunejit": "false", 26 | "node_install_npm": "true", 27 | "node_module_version": 48, 28 | "node_no_browser_globals": "false", 29 | "node_prefix": "/usr/local", 30 | "node_release_urlbase": "https://nodejs.org/download/release/", 31 | "node_shared": "false", 32 | "node_shared_cares": "false", 33 | "node_shared_http_parser": "false", 34 | "node_shared_libuv": "false", 35 | "node_shared_openssl": "false", 36 | "node_shared_zlib": "false", 37 | "node_tag": "", 38 | "node_use_bundled_v8": "true", 39 | "node_use_dtrace": "false", 40 | "node_use_etw": "true", 41 | "node_use_lttng": "false", 42 | "node_use_openssl": "true", 43 | "node_use_perfctr": "true", 44 | "node_use_v8_platform": "true", 45 | "openssl_fips": "", 46 | "openssl_no_asm": 0, 47 | "shlib_suffix": "so.48", 48 | "target_arch": "x64", 49 | "v8_enable_gdbjit": 0, 50 | "v8_enable_i18n_support": 1, 51 | "v8_inspector": "true", 52 | "v8_no_strict_aliasing": 1, 53 | "v8_optimized_debug": 0, 54 | "v8_random_seed": 0, 55 | "v8_use_snapshot": "true", 56 | "want_separate_host_toolset": 0, 57 | "nodedir": "C:\\Users\\IBM_ADMIN\\.node-gyp\\6.9.1", 58 | "copy_dev_lib": "true", 59 | "standalone_static_library": 1, 60 | "access": "", 61 | "also": "", 62 | "always_auth": "", 63 | "bin_links": "true", 64 | "browser": "", 65 | "ca": "", 66 | "cache": "C:\\Users\\IBM_ADMIN\\AppData\\Roaming\\npm-cache", 67 | "cache_lock_retries": "10", 68 | "cache_lock_stale": "60000", 69 | "cache_lock_wait": "10000", 70 | "cache_max": "Infinity", 71 | "cache_min": "10", 72 | "cert": "", 73 | "color": "true", 74 | "depth": "Infinity", 75 | "description": "true", 76 | "dev": "", 77 | "dry_run": "", 78 | "editor": "notepad.exe", 79 | "engine_strict": "", 80 | "fetch_retries": "2", 81 | "fetch_retry_factor": "10", 82 | "fetch_retry_maxtimeout": "60000", 83 | "fetch_retry_mintimeout": "10000", 84 | "force": "", 85 | "git": "git", 86 | "git_tag_version": "true", 87 | "global": "", 88 | "globalconfig": "C:\\Users\\IBM_ADMIN\\AppData\\Roaming\\npm\\etc\\npmrc", 89 | "globalignorefile": "C:\\Users\\IBM_ADMIN\\AppData\\Roaming\\npm\\etc\\npmignore", 90 | "global_style": "", 91 | "group": "", 92 | "heading": "npm", 93 | "https_proxy": "", 94 | "if_present": "", 95 | "ignore_scripts": "", 96 | "init_author_email": "", 97 | "init_author_name": "", 98 | "init_author_url": "", 99 | "init_license": "ISC", 100 | "init_module": "C:\\Users\\IBM_ADMIN\\.npm-init.js", 101 | "init_version": "1.0.0", 102 | "json": "", 103 | "key": "", 104 | "legacy_bundling": "", 105 | "link": "", 106 | "local_address": "", 107 | "long": "", 108 | "maxsockets": "50", 109 | "message": "%s", 110 | "node_version": "6.9.1", 111 | "npat": "", 112 | "onload_script": "", 113 | "only": "", 114 | "optional": "true", 115 | "parseable": "", 116 | "prefix": "C:\\Users\\IBM_ADMIN\\AppData\\Roaming\\npm", 117 | "production": "", 118 | "progress": "true", 119 | "proprietary_attribs": "true", 120 | "rebuild_bundle": "true", 121 | "registry": "https://registry.npmjs.org/", 122 | "rollback": "true", 123 | "save": "", 124 | "save_bundle": "", 125 | "save_dev": "", 126 | "save_exact": "", 127 | "save_optional": "", 128 | "save_prefix": "^", 129 | "scope": "", 130 | "searchexclude": "", 131 | "searchopts": "", 132 | "searchsort": "name", 133 | "shell": "C:\\windows\\system32\\cmd.exe", 134 | "shrinkwrap": "true", 135 | "sign_git_tag": "", 136 | "strict_ssl": "true", 137 | "tag": "latest", 138 | "tag_version_prefix": "v", 139 | "tmp": "C:\\windows\\TEMP", 140 | "umask": "0000", 141 | "unicode": "", 142 | "unsafe_perm": "true", 143 | "usage": "", 144 | "user": "", 145 | "userconfig": "C:\\Users\\IBM_ADMIN\\.npmrc", 146 | "user_agent": "npm/3.10.8 node/v6.9.1 win32 x64", 147 | "version": "", 148 | "versions": "", 149 | "viewer": "browser" 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /chaincodes/chaincodes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/chaincodes/chaincodes.zip -------------------------------------------------------------------------------- /chaincodes/query.go: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, 11 | software distributed under the License is distributed on an 12 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations 15 | under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "encoding/json" 22 | "errors" 23 | "fmt" 24 | "strconv" 25 | "strings" 26 | "time" 27 | 28 | "github.com/hyperledger/fabric/core/chaincode/shim" 29 | ) 30 | 31 | // SimpleChaincode example simple Chaincode implementation 32 | type SimpleChaincode struct { 33 | } 34 | 35 | var assetIndexStr = "_assetindex" //Description for the key/value that will store a list of all known Assets 36 | var openTradesStr = "_opentrades" //Description for the key/value that will store all open trades 37 | 38 | type Asset struct { 39 | Description string `json:"description"` //the fieldtags are needed to keep case from bouncing around 40 | LastTransaction string `json:"lastTransaction"` 41 | Temperature int `json:"temperature"` 42 | Status bool `json:"status"` 43 | ID int `json:"id"` 44 | User string `json:"user"` 45 | } 46 | 47 | type Description struct { 48 | LastTransaction string `json:"lastTransaction"` 49 | ID int `json:"id"` 50 | } 51 | 52 | type AnOpenTrade struct { 53 | User string `json:"user"` //user who created the open trade order 54 | Timestamp int64 `json:"timestamp"` //utc timestamp of creation 55 | Want Description `json:"want"` //description of desired Asset 56 | Willing []Description `json:"willing"` //array of Assets willing to trade away 57 | } 58 | 59 | type AllTrades struct { 60 | OpenTrades []AnOpenTrade `json:"open_trades"` 61 | } 62 | 63 | // =========================================================================================================== ================= 64 | // Main 65 | // =========================================================================================================== ================= 66 | func main() { 67 | err := shim.Start(new(SimpleChaincode)) 68 | if err != nil { 69 | fmt.Printf("Error starting Simple chaincode: %s", err) 70 | } 71 | } 72 | 73 | // =========================================================================================================== ================= 74 | // Init - reset all the things 75 | // =========================================================================================================== ================= 76 | func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 77 | var Aval int 78 | var err error 79 | 80 | if len(args) != 1 { 81 | return nil, errors.New("Incorrect number of arguments. Expecting 1") 82 | } 83 | 84 | // Initialize the chaincode 85 | Aval, err = strconv.Atoi(args[0]) 86 | if err != nil { 87 | return nil, errors.New("Expecting integer value for asset holding") 88 | } 89 | 90 | // Write the state to the ledger 91 | err = stub.PutState("abc", []byte(strconv.Itoa(Aval))) //making a test var "abc", I find it handy to read/write to it right away to test the network 92 | if err != nil { 93 | return nil, err 94 | } 95 | 96 | var empty []string 97 | jsonAsBytes, _ := json.Marshal(empty) //marshal an emtpy array of strings to clear the index 98 | err = stub.PutState(assetIndexStr, jsonAsBytes) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | var trades AllTrades 104 | jsonAsBytes, _ = json.Marshal(trades) //clear the open trade struct 105 | err = stub.PutState(openTradesStr, jsonAsBytes) 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | return nil, nil 111 | } 112 | 113 | // =========================================================================================================== ================= 114 | // Run - Our entry point for Invocations - [LEGACY] obc-peer 4/25/2016 115 | // =========================================================================================================== ================= 116 | func (t *SimpleChaincode) Run(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 117 | fmt.Println("run is running " + function) 118 | return t.Invoke(stub, function, args) 119 | } 120 | 121 | // =========================================================================================================== ================= 122 | // Invoke - Our entry point for Invocations 123 | // =========================================================================================================== ================= 124 | func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 125 | fmt.Println("invoke is running " + function) 126 | 127 | // Handle different functions 128 | if function == "init" { //initialize the chaincode state, used as reset 129 | return t.Init(stub, "init", args) 130 | } else if function == "delete" { //deletes an entity from its state 131 | res, err := t.Delete(stub, args) 132 | cleanTrades(stub) //lets make sure all open trades are still valid 133 | return res, err 134 | } else if function == "write" { //writes a value to the chaincode state 135 | return t.Write(stub, args) 136 | } else if function == "init_asset" { //create a new Asset 137 | return t.init_Asset(stub, args) 138 | } else if function == "set_user" { //change owner of a Asset 139 | res, err := t.set_user(stub, args) 140 | cleanTrades(stub) //lets make sure all open trades are still valid 141 | return res, err 142 | } else if function == "open_trade" { //create a new trade order 143 | return t.open_trade(stub, args) 144 | } else if function == "perform_trade" { //forfill an open trade order 145 | res, err := t.perform_trade(stub, args) 146 | cleanTrades(stub) //lets clean just in case 147 | return res, err 148 | } else if function == "remove_trade" { //cancel an open trade order 149 | return t.remove_trade(stub, args) 150 | } 151 | fmt.Println("invoke did not find func: " + function) //error 152 | 153 | return nil, errors.New("Received unknown function invocation") 154 | } 155 | 156 | // =========================================================================================================== ================= 157 | // Query - Our entry point for Queries 158 | // =========================================================================================================== ================= 159 | func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 160 | fmt.Println("query is running " + function) 161 | 162 | // Handle different functions 163 | if function == "read" { //read a variable 164 | return t.read(stub, args) 165 | } 166 | fmt.Println("query did not find func: " + function) //error 167 | 168 | return nil, errors.New("Received unknown function query") 169 | } 170 | 171 | // =========================================================================================================== ================= 172 | // Read - read a variable from chaincode state 173 | // =========================================================================================================== ================= 174 | func (t *SimpleChaincode) read(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 175 | var Description, jsonResp string 176 | var err error 177 | 178 | if len(args) != 1 { 179 | return nil, errors.New("Incorrect number of arguments. Expecting Description of the var to query") 180 | } 181 | 182 | Description = args[0] 183 | fmt.Print("Description " + Description) 184 | valAsbytes, err := stub.GetState(Description) //get the var from chaincode state 185 | if err != nil { 186 | jsonResp = "{\"Error\":\"Failed to get state for " + Description + "\"}" 187 | return nil, errors.New(jsonResp) 188 | } 189 | 190 | var infoIndex []string 191 | json.Unmarshal(valAsbytes, &infoIndex) 192 | 193 | for i, val := range infoIndex { 194 | fmt.Println("got: " + infoIndex[i] + " " + val) 195 | } 196 | 197 | return valAsbytes, nil //send it onward 198 | } 199 | 200 | // =========================================================================================================== ================= 201 | // Delete - remove a key/value pair from state 202 | // =========================================================================================================== ================= 203 | func (t *SimpleChaincode) Delete(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 204 | if len(args) != 1 { 205 | return nil, errors.New("Incorrect number of arguments. Expecting 1") 206 | } 207 | 208 | Description := args[0] 209 | err := stub.DelState(Description) //remove the key from chaincode state 210 | if err != nil { 211 | return nil, errors.New("Failed to delete state") 212 | } 213 | 214 | //get the Asset index 215 | AssetsAsBytes, err := stub.GetState(assetIndexStr) 216 | if err != nil { 217 | return nil, errors.New("Failed to get Asset index") 218 | } 219 | var AssetIndex []string 220 | json.Unmarshal(AssetsAsBytes, &AssetIndex) //un stringify it aka JSON.parse() 221 | 222 | //remove Asset from index 223 | for i, val := range AssetIndex { 224 | fmt.Println(strconv.Itoa(i) + " - looking at " + val + " for " + Description) 225 | if val == Description { //find the correct Asset 226 | fmt.Println("found Asset") 227 | AssetIndex = append(AssetIndex[:i], AssetIndex[i+1:]...) //remove it 228 | for x := range AssetIndex { //debug prints... 229 | fmt.Println(string(x) + " - " + AssetIndex[x]) 230 | } 231 | break 232 | } 233 | } 234 | jsonAsBytes, _ := json.Marshal(AssetIndex) //save new index 235 | err = stub.PutState(assetIndexStr, jsonAsBytes) 236 | return nil, nil 237 | } 238 | 239 | // =========================================================================================================== ================= 240 | // Write - write variable into chaincode state 241 | // =========================================================================================================== ================= 242 | func (t *SimpleChaincode) Write(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 243 | var description, value string // Entities 244 | var err error 245 | fmt.Println("running write()") 246 | 247 | if len(args) != 2 { 248 | return nil, errors.New("Incorrect number of arguments. Expecting 2. Description of the variable and value to set") 249 | } 250 | 251 | description = args[0] //reDescription for funsies 252 | value = args[1] 253 | err = stub.PutState(description, []byte(value)) //write the variable into the chaincode state 254 | if err != nil { 255 | return nil, err 256 | } 257 | return nil, nil 258 | } 259 | 260 | // =========================================================================================================== ================= 261 | // Init Asset - create a new Asset, store into chaincode state 262 | // =========================================================================================================== ================= 263 | func (t *SimpleChaincode) init_Asset(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 264 | var err error 265 | 266 | // 0 1 2 3 267 | // "asdf", "blue", "35", "bob" 268 | if len(args) != 5 { 269 | fmt.Println("- Incorrect number of arguments. Expecting 5") 270 | return nil, errors.New("Incorrect number of arguments. Expecting 5") 271 | } 272 | 273 | //input sanitation 274 | fmt.Println("- start init Asset") 275 | if len(args[0]) <= 0 { 276 | return nil, errors.New("1st argument must be a non-empty string") 277 | } 278 | if len(args[1]) <= 0 { 279 | return nil, errors.New("2nd argument must be a non-empty string") 280 | } 281 | if len(args[2]) <= 0 { 282 | return nil, errors.New("3rd argument must be a non-empty string") 283 | } 284 | if len(args[3]) <= 0 { 285 | return nil, errors.New("4th argument must be a non-empty string") 286 | } 287 | if len(args[4]) <= 0 { 288 | return nil, errors.New("5th argument must be a non-empty string") 289 | } 290 | 291 | //fmt.Print("Assigning first values...") 292 | description := args[0] 293 | lastTransaction := strings.ToLower(args[1]) 294 | user := strings.ToLower(args[2]) 295 | temperature := strings.ToLower(args[3]) 296 | id := strings.ToLower(args[4]) 297 | status := strings.ToLower("false") 298 | 299 | //check if Asset already exists 300 | AssetAsBytes, err := stub.GetState(description) 301 | if err != nil { 302 | fmt.Println("Failed to get Asset Description") 303 | return nil, errors.New("Failed to get Asset Description") 304 | } 305 | res := Asset{} 306 | json.Unmarshal(AssetAsBytes, &res) 307 | if res.Description == description { 308 | fmt.Println("This Asset arleady exists: " + description) 309 | fmt.Println(res) 310 | return nil, errors.New("This Asset already exists") //all stop a Asset by this Description exists 311 | } 312 | 313 | //build the Asset json string manually 314 | str := `{"description": "` + description + `", "lastTransaction": "` + lastTransaction + `", "temperature": "` + temperature + `", "status": "` + status + `", "id": "` + id + `", "user": "` + user + `"}` 315 | err = stub.PutState(description, []byte(str)) //store Asset with id as key 316 | if err != nil { 317 | fmt.Println("error [init_asset] str.PutState! ") 318 | return nil, err 319 | } 320 | 321 | //get the Asset index 322 | AssetsAsBytes, err := stub.GetState(assetIndexStr) 323 | if err != nil { 324 | return nil, errors.New("Failed to get Asset index") 325 | } 326 | var AssetIndex []string 327 | json.Unmarshal(AssetsAsBytes, &AssetIndex) //un stringify it aka JSON.parse() 328 | 329 | //append 330 | AssetIndex = append(AssetIndex, description) //add Asset Description to index list 331 | fmt.Println("! Asset index: ", AssetIndex) 332 | jsonAsBytes, _ := json.Marshal(AssetIndex) 333 | err = stub.PutState(assetIndexStr, jsonAsBytes) //store Description of Asset 334 | 335 | fmt.Println("- end init Asset") 336 | return nil, nil 337 | } 338 | 339 | // =========================================================================================================== ================= 340 | // Set User Permission on Asset 341 | // =========================================================================================================== ================= 342 | func (t *SimpleChaincode) set_user(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 343 | var err error 344 | 345 | // 0 1 346 | // "Description", "bob" 347 | if len(args) < 3 { 348 | return nil, errors.New("Incorrect number of arguments. Expecting 2") 349 | } 350 | 351 | fmt.Println("- start set user") 352 | fmt.Println(args[0] + " - " + args[1] + " - " + args[2]) 353 | AssetAsBytes, err := stub.GetState(args[0]) 354 | if err != nil { 355 | return nil, errors.New("Failed to get thing") 356 | } 357 | 358 | res := Asset{} 359 | json.Unmarshal(AssetAsBytes, &res) //un stringify it aka JSON.parse() 360 | temp, err := strconv.Atoi(args[2]) 361 | if err != nil { 362 | msg := "Temperature needs to be a numeric string " + args[2] 363 | fmt.Println(msg) 364 | return nil, errors.New(msg) 365 | } 366 | 367 | fmt.Println("Current temperature " + strconv.Itoa(temp)) 368 | if temp > 24 { 369 | fmt.Println("[Smart Contract] Asset need to be verified " + strconv.Itoa(temp)) 370 | res.Status = true 371 | } else { 372 | fmt.Println("[Smart Contract] Satisfied! " + strconv.Itoa(temp)) 373 | tmp, err := strconv.Atoi(args[2]) 374 | if err != nil { 375 | msg := "Temperature needs to be a numeric string " + args[2] 376 | fmt.Println(msg) 377 | return nil, errors.New(msg) 378 | } 379 | 380 | res.Status = false 381 | res.Temperature = tmp 382 | res.User = args[1] //change the user 383 | 384 | jsonAsBytes, _ := json.Marshal(res) 385 | err = stub.PutState(args[0], jsonAsBytes) //rewrite the Asset with id as key 386 | if err != nil { 387 | return nil, err 388 | } 389 | 390 | fmt.Println("- end set user") 391 | return nil, nil 392 | } 393 | 394 | jsonAsBytes, _ := json.Marshal(res) 395 | err = stub.PutState(args[0], jsonAsBytes) //rewrite the Asset with id as key 396 | if err != nil { 397 | return nil, err 398 | } 399 | 400 | fmt.Println("- infraction applied to the ledger state") 401 | return nil, nil 402 | } 403 | 404 | // =========================================================================================================== ================= 405 | // Open Trade - create an open trade for a Asset you want with Assets you have 406 | // =========================================================================================================== ================= 407 | func (t *SimpleChaincode) open_trade(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 408 | var err error 409 | var will_id int 410 | var trade_away Description 411 | 412 | // 0 1 2 3 4 5 6 413 | //["bob", "blue", "16", "red", "16"] *"blue", "35* 414 | if len(args) < 5 { 415 | return nil, errors.New("Incorrect number of arguments. Expecting like 5?") 416 | } 417 | if len(args)%2 == 0 { 418 | return nil, errors.New("Incorrect number of arguments. Expecting an odd number") 419 | } 420 | 421 | id, err := strconv.Atoi(args[2]) 422 | if err != nil { 423 | return nil, errors.New("3rd argument must be a numeric string") 424 | } 425 | 426 | open := AnOpenTrade{} 427 | open.User = args[0] 428 | open.Timestamp = makeTimestamp() //use timestamp as an ID 429 | open.Want.LastTransaction = args[1] 430 | open.Want.ID = id 431 | fmt.Println("- start open trade") 432 | jsonAsBytes, _ := json.Marshal(open) 433 | err = stub.PutState("_debug1", jsonAsBytes) 434 | 435 | for i := 3; i < len(args); i++ { //create and append each willing trade 436 | will_id, err = strconv.Atoi(args[i+1]) 437 | if err != nil { 438 | msg := "is not a numeric string " + args[i+1] 439 | fmt.Println(msg) 440 | return nil, errors.New(msg) 441 | } 442 | 443 | trade_away = Description{} 444 | trade_away.LastTransaction = args[i] 445 | trade_away.ID = will_id 446 | fmt.Println("! created trade_away: " + args[i]) 447 | jsonAsBytes, _ = json.Marshal(trade_away) 448 | err = stub.PutState("_debug2", jsonAsBytes) 449 | 450 | open.Willing = append(open.Willing, trade_away) 451 | fmt.Println("! appended willing to open") 452 | i++ 453 | } 454 | 455 | //get the open trade struct 456 | tradesAsBytes, err := stub.GetState(openTradesStr) 457 | if err != nil { 458 | return nil, errors.New("Failed to get opentrades") 459 | } 460 | var trades AllTrades 461 | json.Unmarshal(tradesAsBytes, &trades) //un stringify it aka JSON.parse() 462 | 463 | trades.OpenTrades = append(trades.OpenTrades, open) //append to open trades 464 | fmt.Println("! appended open to trades") 465 | jsonAsBytes, _ = json.Marshal(trades) 466 | err = stub.PutState(openTradesStr, jsonAsBytes) //rewrite open orders 467 | if err != nil { 468 | return nil, err 469 | } 470 | fmt.Println("- end open trade") 471 | return nil, nil 472 | } 473 | 474 | // =========================================================================================================== ================= 475 | // Perform Trade - close an open trade and move ownership 476 | // =========================================================================================================== ================= 477 | func (t *SimpleChaincode) perform_trade(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 478 | var err error 479 | 480 | // 0 1 2 3 4 5 481 | //[data.id, data.closer.user, data.closer.Description, data.opener.user, data.opener.LastTransaction, data.opener.Weight] 482 | if len(args) < 6 { 483 | return nil, errors.New("Incorrect number of arguments. Expecting 6") 484 | } 485 | 486 | fmt.Println("- start close trade") 487 | timestamp, err := strconv.ParseInt(args[0], 10, 64) 488 | if err != nil { 489 | return nil, errors.New("1st argument must be a numeric string") 490 | } 491 | 492 | id, err := strconv.Atoi(args[5]) 493 | if err != nil { 494 | return nil, errors.New("6th argument must be a numeric string") 495 | } 496 | 497 | //get the open trade struct 498 | tradesAsBytes, err := stub.GetState(openTradesStr) 499 | if err != nil { 500 | return nil, errors.New("Failed to get opentrades") 501 | } 502 | var trades AllTrades 503 | json.Unmarshal(tradesAsBytes, &trades) //un stringify it aka JSON.parse() 504 | 505 | for i := range trades.OpenTrades { //look for the trade 506 | fmt.Println("looking at " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10) + " for " + strconv.FormatInt(timestamp, 10)) 507 | if trades.OpenTrades[i].Timestamp == timestamp { 508 | fmt.Println("found the trade") 509 | 510 | AssetAsBytes, err := stub.GetState(args[2]) 511 | if err != nil { 512 | return nil, errors.New("Failed to get thing") 513 | } 514 | closersAsset := Asset{} 515 | json.Unmarshal(AssetAsBytes, &closersAsset) //un stringify it aka JSON.parse() 516 | 517 | //verify if Asset meets trade requirements 518 | if closersAsset.LastTransaction != trades.OpenTrades[i].Want.LastTransaction || closersAsset.ID != trades.OpenTrades[i].Want.ID { 519 | msg := "Asset in input does not meet trade requriements" 520 | fmt.Println(msg) 521 | return nil, errors.New(msg) 522 | } 523 | 524 | Asset, e := findAsset4Trade(stub, trades.OpenTrades[i].User, args[4], id) //find a Ass et that is suitable from opener 525 | if e == nil { 526 | fmt.Println("! no errors, proceeding") 527 | 528 | t.set_user(stub, []string{args[2], trades.OpenTrades[i].User}) //change owner of selected Asset, closer -> opener 529 | t.set_user(stub, []string{Asset.Description, args[1]}) //change owner of selected Asset, opener -> closer 530 | 531 | trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...) //remove trade 532 | jsonAsBytes, _ := json.Marshal(trades) 533 | err = stub.PutState(openTradesStr, jsonAsBytes) //rewrite open orders 534 | if err != nil { 535 | return nil, err 536 | } 537 | } 538 | } 539 | } 540 | fmt.Println("- end close trade") 541 | return nil, nil 542 | } 543 | 544 | // =========================================================================================================== ================= 545 | // findAsset4Trade - look for a matching Asset that this user owns and return it 546 | // =========================================================================================================== ================= 547 | func findAsset4Trade(stub shim.ChaincodeStubInterface, user string, LastTransaction string, id int) (m Asset, err error) { 548 | var fail Asset 549 | fmt.Println("- start find Asset 4 trade") 550 | fmt.Println("looking for " + user + ", " + LastTransaction + ", " + strconv.Itoa(id)) 551 | 552 | //get the Asset index 553 | AssetsAsBytes, err := stub.GetState(assetIndexStr) 554 | if err != nil { 555 | return fail, errors.New("Failed to get Asset index") 556 | } 557 | var AssetIndex []string 558 | json.Unmarshal(AssetsAsBytes, &AssetIndex) //un stringify it aka JSON.parse() 559 | 560 | for i := range AssetIndex { //iter through all the Assets 561 | //fmt.Println("looking @ Asset Description: " + AssetIndex[i]); 562 | 563 | AssetAsBytes, err := stub.GetState(AssetIndex[i]) //grab this Asset 564 | if err != nil { 565 | return fail, errors.New("Failed to get Asset") 566 | } 567 | res := Asset{} 568 | json.Unmarshal(AssetAsBytes, &res) //un stringify it aka JSON.parse() 569 | //fmt.Println("looking @ " + res.User + ", " + res.LastTransaction + ", " + strconv.Itoa(res.W eight)); 570 | 571 | //check for user && LastTransaction && Weight 572 | if strings.ToLower(res.User) == strings.ToLower(user) && strings.ToLower(res.LastTransaction) == strings.ToLower(LastTransaction) && res.ID == id { 573 | fmt.Println("found a Asset: " + res.Description) 574 | fmt.Println("! end find Asset 4 trade") 575 | return res, nil 576 | } 577 | } 578 | 579 | fmt.Println("- end find Asset 4 trade - error") 580 | return fail, errors.New("Did not find Asset to use in this trade") 581 | } 582 | 583 | // =========================================================================================================== ================= 584 | // Make Timestamp - create a timestamp in ms 585 | // =========================================================================================================== ================= 586 | func makeTimestamp() int64 { 587 | return time.Now().UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) 588 | } 589 | 590 | // =========================================================================================================== ================= 591 | // Remove Open Trade - close an open trade 592 | // =========================================================================================================== ================= 593 | func (t *SimpleChaincode) remove_trade(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 594 | var err error 595 | 596 | // 0 597 | //[data.id] 598 | if len(args) < 1 { 599 | return nil, errors.New("Incorrect number of arguments. Expecting 1") 600 | } 601 | 602 | fmt.Println("- start remove trade") 603 | timestamp, err := strconv.ParseInt(args[0], 10, 64) 604 | if err != nil { 605 | return nil, errors.New("1st argument must be a numeric string") 606 | } 607 | 608 | //get the open trade struct 609 | tradesAsBytes, err := stub.GetState(openTradesStr) 610 | if err != nil { 611 | return nil, errors.New("Failed to get opentrades") 612 | } 613 | var trades AllTrades 614 | json.Unmarshal(tradesAsBytes, &trades) //un stringify it aka JSON.parse() 615 | 616 | for i := range trades.OpenTrades { //look for the trade 617 | //fmt.Println("looking at " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10) + " for " + strconv.FormatInt(timestamp, 10)) 618 | if trades.OpenTrades[i].Timestamp == timestamp { 619 | fmt.Println("found the trade") 620 | trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...) //remove this trade 621 | jsonAsBytes, _ := json.Marshal(trades) 622 | err = stub.PutState(openTradesStr, jsonAsBytes) //rewrite open orders 623 | if err != nil { 624 | return nil, err 625 | } 626 | break 627 | } 628 | } 629 | 630 | fmt.Println("- end remove trade") 631 | return nil, nil 632 | } 633 | 634 | // =========================================================================================================== ================= 635 | // Clean Up Open Trades - make sure open trades are still possible, remove choices that are no longer possible , remove trades that have no valid choices 636 | // =========================================================================================================== ================= 637 | func cleanTrades(stub shim.ChaincodeStubInterface) (err error) { 638 | var didWork = false 639 | fmt.Println("- start clean trades") 640 | 641 | //get the open trade struct 642 | tradesAsBytes, err := stub.GetState(openTradesStr) 643 | if err != nil { 644 | return errors.New("Failed to get opentrades") 645 | } 646 | var trades AllTrades 647 | json.Unmarshal(tradesAsBytes, &trades) //un stringify it aka JSON.parse() 648 | 649 | fmt.Println("# trades " + strconv.Itoa(len(trades.OpenTrades))) 650 | for i := 0; i < len(trades.OpenTrades); { //iter over all the known open trades 651 | fmt.Println(strconv.Itoa(i) + ": looking at trade " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10)) 652 | 653 | fmt.Println("# options " + strconv.Itoa(len(trades.OpenTrades[i].Willing))) 654 | for x := 0; x < len(trades.OpenTrades[i].Willing); { //find a Asset that is suitable 655 | fmt.Println("! on next option " + strconv.Itoa(i) + ":" + strconv.Itoa(x)) 656 | _, e := findAsset4Trade(stub, trades.OpenTrades[i].User, trades.OpenTrades[i].Willing[x].LastTransaction, trades.OpenTrades[i].Willing[x].ID) 657 | if e != nil { 658 | fmt.Println("! errors with this option, removing option") 659 | didWork = true 660 | trades.OpenTrades[i].Willing = append(trades.OpenTrades[i].Willing[:x], trades.OpenTrades[i].Willing[x+1:]...) //remove this option 661 | x-- 662 | } else { 663 | fmt.Println("! this option is fine") 664 | } 665 | 666 | x++ 667 | fmt.Println("! x:" + strconv.Itoa(x)) 668 | if x >= len(trades.OpenTrades[i].Willing) { //things might have shifted, recalcuate 669 | break 670 | } 671 | } 672 | 673 | if len(trades.OpenTrades[i].Willing) == 0 { 674 | fmt.Println("! no more options for this trade, removing trade") 675 | didWork = true 676 | trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...) //remove this trade 677 | i-- 678 | } 679 | 680 | i++ 681 | fmt.Println("! i:" + strconv.Itoa(i)) 682 | if i >= len(trades.OpenTrades) { //things might have shifted, recalcuate 683 | break 684 | } 685 | } 686 | 687 | if didWork { 688 | fmt.Println("! saving open trade changes") 689 | jsonAsBytes, _ := json.Marshal(trades) 690 | err = stub.PutState(openTradesStr, jsonAsBytes) //rewrite open orders 691 | if err != nil { 692 | return err 693 | } 694 | } else { 695 | fmt.Println("! all open trades are fine") 696 | } 697 | 698 | fmt.Println("- end clean trades") 699 | return nil 700 | } 701 | -------------------------------------------------------------------------------- /config/express.js: -------------------------------------------------------------------------------- 1 | /*Express basic configuration as module */ 2 | 3 | module.exports = function () { 4 | 'use strict' 5 | 6 | const express = require('express'); 7 | const app = express(); 8 | const bodyParser = require('body-parser'); 9 | const logger = require('morgan'); 10 | let listen = require('../routes/events'); 11 | 12 | app.use(logger('dev')); 13 | app.use(bodyParser.json()); 14 | app.use(express.static('public'));//__dirname + 15 | app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded 16 | /*routes - not working yet**/ 17 | //app.get('/events/:id', listen); 18 | 19 | return app; 20 | 21 | } -------------------------------------------------------------------------------- /config/hyperledgerfc.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp 2016 All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | * A simple application utilizing the Node.js Client SDK to: 19 | * 1) Enroll a user 20 | * 2) User deploys chaincode 21 | * 3) User queries chaincode 22 | */ 23 | // "HFC" stands for "Hyperledger Fabric Client" 24 | var hfc = require("hfc"); 25 | 26 | //const env = require('../rest/local_env.json'); 27 | const env = require('../env.json'); 28 | console.log(`getting environment variables \n ${env.peers[0].api_port_tls}`); 29 | 30 | // get the addresses from the docker-compose environment 31 | var PEER_ADDRESS = env.peers;//process.env.CORE_PEER_ADDRESS; 32 | var MEMBERSRVC_ADDRESS = env.ca;//process.env.MEMBERSRVC_ADDRESS; 33 | console.log(JSON.stringify(MEMBERSRVC_ADDRESS)); 34 | 35 | var chain, chaincodeID; 36 | 37 | function configureHfc() { 38 | 39 | // Create a chain object used to interact with the chain. 40 | // You can name it anything you want as it is only used by client. 41 | chain = hfc.newChain("mySpecialChain"); 42 | // Initialize the place to store sensitive private key information 43 | //chain.setKeyValStore(hfc.newFileKeyValStore('/tmp/keyValStore')); 44 | // Set the URL to membership services and to the peer 45 | console.log("member services address =" + MEMBERSRVC_ADDRESS.type); 46 | console.log("peer address =" + PEER_ADDRESS); 47 | chain.setMemberServicesUrl("grpc://" + MEMBERSRVC_ADDRESS); 48 | chain.setKeyValStore(hfc.newFileKeyValStore('./keyValStore')); 49 | chain.addPeer("grpc://" + PEER_ADDRESS); 50 | 51 | // The following is required when the peer is started in dev mode 52 | // (i.e. with the '--peer-chaincodedev' option) 53 | var mode = process.env['DEPLOY_MODE']; 54 | console.log("DEPLOY_MODE=" + mode); 55 | if (mode === 'dev') { 56 | chain.setDevMode(true); 57 | //Deploy will not take long as the chain should already be running 58 | chain.setDeployWaitTime(10); 59 | } else { 60 | chain.setDevMode(false); 61 | //Deploy will take much longer in network mode 62 | chain.setDeployWaitTime(60); 63 | } 64 | 65 | chain.setInvokeWaitTime(10); 66 | 67 | // Begin by enrolling the user 68 | enroll(); 69 | 70 | // Enroll a user. 71 | function enroll() { 72 | console.log("enrolling user admin ..."); 73 | // Enroll "admin" which is preregistered in the membersrvc.yaml 74 | chain.enroll("WebAppAdmin", "DJY27pEnl16d", function (err, admin) { 75 | if (err) { 76 | console.log("ERROR: failed to register admin: %s", err); 77 | process.exit(1); 78 | } 79 | // Set this user as the chain's registrar which is authorized to register other users. 80 | chain.setRegistrar(admin); 81 | 82 | var userName = "bob"; 83 | // registrationRequest 84 | var registrationRequest = { 85 | enrollmentID: userName, 86 | affiliation: "bank_a" 87 | }; 88 | chain.registerAndEnroll(registrationRequest, function (error, user) { 89 | if (error) throw Error(" Failed to register and enroll " + userName + ": " + error); 90 | console.log("Enrolled %s successfully\n", userName); 91 | deploy(user); 92 | }); 93 | }); 94 | } 95 | 96 | // Deploy chaincode 97 | function deploy(user) { 98 | console.log("deploying chaincode; please wait ..."); 99 | // Construct the deploy request 100 | var deployRequest = { 101 | chaincodeName: process.env.CORE_CHAINCODE_ID_NAME, 102 | fcn: "init", 103 | args: ["99"] 104 | }; 105 | // where is the chain code, ignored in dev mode 106 | deployRequest.chaincodePath = "github.com/VitorSousaCode/chaincodes/experimental"; 107 | 108 | // Issue the deploy request and listen for events 109 | var tx = user.deploy(deployRequest); 110 | tx.on('complete', function (results) { 111 | // Deploy request completed successfully 112 | console.log("deploy complete; results: %j", results); 113 | // Set the testChaincodeID for subsequent tests 114 | chaincodeID = results.chaincodeID; 115 | invoke(user); 116 | }); 117 | tx.on('error', function (error) { 118 | console.log("Failed to deploy chaincode: request=%j, error=%k", deployRequest, error); 119 | process.exit(1); 120 | }); 121 | 122 | } 123 | 124 | // Query chaincode 125 | function query(user) { 126 | console.log("querying chaincode ..."); 127 | // Construct a query request 128 | var queryRequest = { 129 | chaincodeID: chaincodeID, 130 | fcn: "query", 131 | args: ["99"] 132 | }; 133 | // Issue the query request and listen for events 134 | var tx = user.query(queryRequest); 135 | tx.on('complete', function (results) { 136 | console.log("query completed successfully; results=%j", results); 137 | process.exit(0); 138 | }); 139 | tx.on('error', function (error) { 140 | console.log("Failed to query chaincode: request=%j, error=%k", queryRequest, error); 141 | process.exit(1); 142 | }); 143 | } 144 | 145 | //Invoke chaincode 146 | function invoke(user) { 147 | console.log("invoke chaincode ..."); 148 | // Construct a query request 149 | var invokeRequest = { 150 | chaincodeID: chaincodeID, 151 | fcn: "invoke", 152 | args: ["a", "b", "1"] 153 | }; 154 | // Issue the invoke request and listen for events 155 | var tx = user.invoke(invokeRequest); 156 | tx.on('submitted', function (results) { 157 | console.log("invoke submitted successfully; results=%j", results); 158 | }); 159 | tx.on('complete', function (results) { 160 | console.log("invoke completed successfully; results=%j", results); 161 | query(user); 162 | }); 163 | tx.on('error', function (error) { 164 | console.log("Failed to invoke chaincode: request=%j, error=%k", invokeRequest, error); 165 | process.exit(1); 166 | }); 167 | } 168 | } 169 | 170 | module.exports.startNetwork = function () { 171 | return configureHfc(); 172 | } 173 | -------------------------------------------------------------------------------- /config/ibm-blockchain.js: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | /* Copyright 2016 IBM Corp. All Rights Reserved. 3 | * blockchain instance setup using ibc-js sdk 4 | * first implementation by Vitor Diego 5 | */ 6 | //------------------------------------------------------------------------------ 7 | 'use strict' 8 | 9 | //loads environment variables for blockchain setup (USA server - blockchain-go) 10 | //const env = require('../env.json'); //env.json(for usa servers) 11 | //const env = require('../rest/local_env.json'); 12 | const env = require('../rest/server_env.json'); 13 | console.log(`getting environment variables \n ${env.peers[0].api_port_tls}`); 14 | const peers = env.peers; 15 | const users = env.users; 16 | const django = env.chaincodepath; 17 | const Ibc1 = require('ibm-blockchain-js'); 18 | const ibc = new Ibc1(); 19 | var chaincode; 20 | 21 | // ================================== 22 | // configure ibc-js sdk 23 | // ================================== 24 | function configureIbcJs() { 25 | let options = { 26 | network: { 27 | peers: [peers[0]], //2 28 | users: users, //3 [users[1]] 29 | options: { //this is optional 30 | quiet: false, //detailed debug messages on/off true/false 31 | tls: false, //should app to peer communication use tls? 32 | maxRetry: 2 //how many times should we retry register before giving up 33 | } 34 | }, 35 | chaincode: { 36 | zip_url: 'https://github.com/VitorSousaCode/chaincodes/archive/master.zip', 37 | unzip_dir: 'chaincodes-master/experimental', 38 | git_url: 'https://github.com/VitorSousaCode/chaincodes/experimental' 39 | } 40 | }; 41 | 42 | ibc.network(peers, { quiet: false, timeout: 120000 }); 43 | //if the peer has stoped we can use: ibc.switchPeer(peers[x]); 44 | //loads chaincode with options above 45 | ibc.load(options, cb_ready); 46 | 47 | /* function cb_ready(err,cc) 48 | * @param {Object} err - error object for handling 49 | * @param {Object} cc - chaincode object deployed Successfully */ 50 | function cb_ready(err, cc) { 51 | if (err != null) { 52 | console.log('! looks like an error loading the chaincode, app will fail\n', err); 53 | if (!process.error) process.error = { type: 'load', msg: err.details }; //if it already exist, keep the last error 54 | } 55 | else { 56 | chaincode = cc; 57 | //decide if I need to deploy or not - fix 58 | if (!cc.details.deployed_name || cc.details.deployed_name === "") { 59 | cc.deploy('init', ['99'], { delay_ms: 40000 }, function (err, success) { 60 | if (err) return; 61 | }); //{delay_ms: 60000} 62 | console.log("deploying chaincode..."); 63 | console.log(JSON.stringify(cc)); 64 | } 65 | else { 66 | console.log('chaincode summary file indicates chaincode has been previously deployed'); 67 | } 68 | console.log("chaincode " + JSON.stringify(chaincode)); 69 | return chaincode; 70 | } 71 | } 72 | } 73 | 74 | module.exports.chain = function () { 75 | console.log(`chaincode ${chaincode}`); 76 | return chaincode; 77 | }; 78 | 79 | module.exports.startNetwork = function () { 80 | return configureIbcJs(); 81 | } 82 | 83 | module.exports.monitor = { 84 | stats: ibc 85 | } -------------------------------------------------------------------------------- /config/setup.js: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | /* Copyright 2016 IBM Corp. All Rights Reserved. 3 | * blockchain instance setup using ibc-js sdk 4 | * first implementation by Vitor Diego 5 | */ 6 | //------------------------------------------------------------------------------ 7 | 'use strict' 8 | 9 | //loads environment variables for blockchain setup (USA server - blockchain-go) 10 | const env = require('../env/uk_env.json'); //env.json(for usa servers) 11 | //const env = require('../env/local_env.json'); 12 | const api = require('../rest/api.js'); 13 | console.log(`getting environment variables \n ${env.peers[0].api_port_tls}`); 14 | const peers = env.peers; 15 | const users = env.users; 16 | var chaincode; 17 | 18 | function runNetwork() { 19 | 20 | //index of users[] to be registered 21 | let x = 4; 22 | let rest = api(peers[0].api_host, peers[0].api_port_tls); 23 | let admin = { 24 | user: env.users[x].enrollId, 25 | secret: env.users[x].enrollSecret 26 | }; 27 | 28 | let getRegistrar = function (req) { 29 | rest.invoke.registrar(req.user, req.secret); 30 | chaincode = rest; 31 | } 32 | 33 | getRegistrar(admin); 34 | 35 | } 36 | 37 | 38 | module.exports.chain = function () { 39 | console.log(`chaincode ${chaincode}`); 40 | return chaincode; 41 | }; 42 | 43 | module.exports.startNetwork = function () { 44 | return runNetwork(); 45 | } -------------------------------------------------------------------------------- /docs/contractviolated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/contractviolated.png -------------------------------------------------------------------------------- /docs/creatingAsset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/creatingAsset.png -------------------------------------------------------------------------------- /docs/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/dashboard.png -------------------------------------------------------------------------------- /docs/events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/events.png -------------------------------------------------------------------------------- /docs/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/history.png -------------------------------------------------------------------------------- /docs/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/intro.png -------------------------------------------------------------------------------- /docs/payloads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/payloads.png -------------------------------------------------------------------------------- /docs/smartcontract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/docs/smartcontract.png -------------------------------------------------------------------------------- /env/env.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | { 4 | "discovery_host": "eaab7b0654764c6bae29701bde20c887-vp1.us.blockchain.ibm.com", 5 | "discovery_port": 30002, 6 | "api_host": "eaab7b0654764c6bae29701bde20c887-vp1.us.blockchain.ibm.com", 7 | "api_port_tls": 5002, 8 | "api_port": 5002, 9 | "event_host": "eaab7b0654764c6bae29701bde20c887-vp1.us.blockchain.ibm.com", 10 | "event_port": 31002, 11 | "type": "peer", 12 | "network_id": "eaab7b0654764c6bae29701bde20c887", 13 | "container_id": "fd3153c7c26cf26eb731c6fccec046651c27fc4b1e815b6fd4b55180ff05b362", 14 | "id": "eaab7b0654764c6bae29701bde20c887-vp1", 15 | "api_url": "http://eaab7b0654764c6bae29701bde20c887-vp1.us.blockchain.ibm.com:5002" 16 | }, 17 | { 18 | "discovery_host": "eaab7b0654764c6bae29701bde20c887-vp2.us.blockchain.ibm.com", 19 | "discovery_port": 30002, 20 | "api_host": "eaab7b0654764c6bae29701bde20c887-vp2.us.blockchain.ibm.com", 21 | "api_port_tls": 5002, 22 | "api_port": 5002, 23 | "event_host": "eaab7b0654764c6bae29701bde20c887-vp2.us.blockchain.ibm.com", 24 | "event_port": 31002, 25 | "type": "peer", 26 | "network_id": "eaab7b0654764c6bae29701bde20c887", 27 | "container_id": "34f01b72dc5fcd2f4b2d0f07f2e2bd085876ee5ee22faa46f4e5709d4210d826", 28 | "id": "eaab7b0654764c6bae29701bde20c887-vp2", 29 | "api_url": "http://eaab7b0654764c6bae29701bde20c887-vp2.us.blockchain.ibm.com:5002" 30 | }, 31 | { 32 | "discovery_host": "eaab7b0654764c6bae29701bde20c887-vp0.us.blockchain.ibm.com", 33 | "discovery_port": 30002, 34 | "api_host": "eaab7b0654764c6bae29701bde20c887-vp0.us.blockchain.ibm.com", 35 | "api_port_tls": 5002, 36 | "api_port": 5002, 37 | "event_host": "eaab7b0654764c6bae29701bde20c887-vp0.us.blockchain.ibm.com", 38 | "event_port": 31002, 39 | "type": "peer", 40 | "network_id": "eaab7b0654764c6bae29701bde20c887", 41 | "container_id": "2f73d4d5eceff20c41b6a741d22e31324522d22b5a8069332f9f38d79c38fc28", 42 | "id": "eaab7b0654764c6bae29701bde20c887-vp0", 43 | "api_url": "http://eaab7b0654764c6bae29701bde20c887-vp0.us.blockchain.ibm.com:5002" 44 | }, 45 | { 46 | "discovery_host": "eaab7b0654764c6bae29701bde20c887-vp3.us.blockchain.ibm.com", 47 | "discovery_port": 30002, 48 | "api_host": "eaab7b0654764c6bae29701bde20c887-vp3.us.blockchain.ibm.com", 49 | "api_port_tls": 5002, 50 | "api_port": 5002, 51 | "event_host": "eaab7b0654764c6bae29701bde20c887-vp3.us.blockchain.ibm.com", 52 | "event_port": 31002, 53 | "type": "peer", 54 | "network_id": "eaab7b0654764c6bae29701bde20c887", 55 | "container_id": "22072968211ddd579f7585512b66eb20bf284b3cad691b1095b2cc02b1746c20", 56 | "id": "eaab7b0654764c6bae29701bde20c887-vp3", 57 | "api_url": "http://eaab7b0654764c6bae29701bde20c887-vp3.us.blockchain.ibm.com:5002" 58 | } 59 | ], 60 | "ca": { 61 | "eaab7b0654764c6bae29701bde20c887-ca": { 62 | "url": "eaab7b0654764c6bae29701bde20c887-ca.us.blockchain.ibm.com:30002", 63 | "discovery_host": "eaab7b0654764c6bae29701bde20c887-ca.us.blockchain.ibm.com", 64 | "discovery_port": 30002, 65 | "api_host": "eaab7b0654764c6bae29701bde20c887-ca.us.blockchain.ibm.com", 66 | "api_port_tls": 30002, 67 | "api_port": 30002, 68 | "type": "ca", 69 | "network_id": "eaab7b0654764c6bae29701bde20c887", 70 | "container_id": "da1d4223aa99ae2249b059e67f07ba1c99593bd5144d37288d0f22ea5bd34c2e" 71 | } 72 | }, 73 | "users": [ 74 | { 75 | "enrollId": "admin", 76 | "enrollSecret": "b070ab4061", 77 | "affiliation": "group1", 78 | "username": "admin", 79 | "secret": "b070ab4061" 80 | }, 81 | { 82 | "enrollId": "WebAppAdmin", 83 | "enrollSecret": "0c23acff41", 84 | "affiliation": "group1", 85 | "username": "WebAppAdmin", 86 | "secret": "0c23acff41" 87 | }, 88 | { 89 | "enrollId": "user_type1_0", 90 | "enrollSecret": "cd32958ec5", 91 | "affiliation": "group1", 92 | "username": "user_type1_0", 93 | "secret": "cd32958ec5" 94 | }, 95 | { 96 | "enrollId": "user_type1_1", 97 | "enrollSecret": "c9461e186a", 98 | "affiliation": "group1", 99 | "username": "user_type1_1", 100 | "secret": "c9461e186a" 101 | }, 102 | { 103 | "enrollId": "user_type1_2", 104 | "enrollSecret": "9427f90f09", 105 | "affiliation": "group1", 106 | "username": "user_type1_2", 107 | "secret": "9427f90f09" 108 | }, 109 | { 110 | "enrollId": "user_type1_3", 111 | "enrollSecret": "b968f6223a", 112 | "affiliation": "group1", 113 | "username": "user_type1_3", 114 | "secret": "b968f6223a" 115 | }, 116 | { 117 | "enrollId": "user_type1_4", 118 | "enrollSecret": "51716ba5a9", 119 | "affiliation": "group1", 120 | "username": "user_type1_4", 121 | "secret": "51716ba5a9" 122 | }, 123 | { 124 | "enrollId": "user_type2_0", 125 | "enrollSecret": "578bcbc53c", 126 | "affiliation": "group1", 127 | "username": "user_type2_0", 128 | "secret": "578bcbc53c" 129 | }, 130 | { 131 | "enrollId": "user_type2_1", 132 | "enrollSecret": "ef7a68fc4e", 133 | "affiliation": "group1", 134 | "username": "user_type2_1", 135 | "secret": "ef7a68fc4e" 136 | }, 137 | { 138 | "enrollId": "user_type2_2", 139 | "enrollSecret": "4cef77b2af", 140 | "affiliation": "group1", 141 | "username": "user_type2_2", 142 | "secret": "4cef77b2af" 143 | }, 144 | { 145 | "enrollId": "user_type2_3", 146 | "enrollSecret": "8878710f86", 147 | "affiliation": "group1", 148 | "username": "user_type2_3", 149 | "secret": "8878710f86" 150 | }, 151 | { 152 | "enrollId": "user_type2_4", 153 | "enrollSecret": "79e226a2d4", 154 | "affiliation": "group1", 155 | "username": "user_type2_4", 156 | "secret": "79e226a2d4" 157 | }, 158 | { 159 | "enrollId": "user_type4_0", 160 | "enrollSecret": "cb37a3595f", 161 | "affiliation": "group1", 162 | "username": "user_type4_0", 163 | "secret": "cb37a3595f" 164 | }, 165 | { 166 | "enrollId": "user_type4_1", 167 | "enrollSecret": "475e900687", 168 | "affiliation": "group1", 169 | "username": "user_type4_1", 170 | "secret": "475e900687" 171 | }, 172 | { 173 | "enrollId": "user_type4_2", 174 | "enrollSecret": "3884f9e3c7", 175 | "affiliation": "group1", 176 | "username": "user_type4_2", 177 | "secret": "3884f9e3c7" 178 | }, 179 | { 180 | "enrollId": "user_type4_3", 181 | "enrollSecret": "daa8e51a62", 182 | "affiliation": "group1", 183 | "username": "user_type4_3", 184 | "secret": "daa8e51a62" 185 | }, 186 | { 187 | "enrollId": "user_type4_4", 188 | "enrollSecret": "8d9dacbaa7", 189 | "affiliation": "group1", 190 | "username": "user_type4_4", 191 | "secret": "8d9dacbaa7" 192 | }, 193 | { 194 | "enrollId": "user_type8_0", 195 | "enrollSecret": "95faa6fc14", 196 | "affiliation": "group1", 197 | "username": "user_type8_0", 198 | "secret": "95faa6fc14" 199 | }, 200 | { 201 | "enrollId": "user_type8_1", 202 | "enrollSecret": "8c93138916", 203 | "affiliation": "group1", 204 | "username": "user_type8_1", 205 | "secret": "8c93138916" 206 | }, 207 | { 208 | "enrollId": "user_type8_2", 209 | "enrollSecret": "eb4db1d75d", 210 | "affiliation": "group1", 211 | "username": "user_type8_2", 212 | "secret": "eb4db1d75d" 213 | }, 214 | { 215 | "enrollId": "user_type8_3", 216 | "enrollSecret": "57e801a1c3", 217 | "affiliation": "group1", 218 | "username": "user_type8_3", 219 | "secret": "57e801a1c3" 220 | }, 221 | { 222 | "enrollId": "user_type8_4", 223 | "enrollSecret": "888a70c1a8", 224 | "affiliation": "group1", 225 | "username": "user_type8_4", 226 | "secret": "888a70c1a8" 227 | } 228 | ], 229 | "cert": "https://blockchain-certs.mybluemix.net/us.blockchain.ibm.com.cert", 230 | "cert_path": "/certs/peer/cert.pem" 231 | } -------------------------------------------------------------------------------- /env/local_env.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | { 4 | "discovery_port": 7051, 5 | "api_host": "localhost", 6 | "api_port": 7050, 7 | "api_port_tls": 7050, 8 | "type": "peer", 9 | "network_id": "dev", 10 | "id": "jdoe", 11 | "api_url": "http://localhost:7050" 12 | } 13 | ], 14 | "ca": { 15 | "discovery_port": 7051, 16 | "api_host": "localhost", 17 | "api_port_tls": 7051, 18 | "api_port": 7051, 19 | "type": "ca", 20 | "network_id": "dev", 21 | "url": "http://localhost:7051" 22 | }, 23 | "users": [ 24 | { 25 | "enrollId": "test_user3", 26 | "enrollSecret": "vWdLCE00vJy0" 27 | } 28 | ], 29 | "cert": "https://blockchain-certs.mybluemix.net/us.blockchain.ibm.com.cert", 30 | "chaincodepath": "./chaincodes/query.go" 31 | } -------------------------------------------------------------------------------- /env/server_env.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | { 4 | "discovery_port": 7056, 5 | "api_host": "10.17.1.100", 6 | "api_port": 7055, 7 | "api_port_tls": 7055, 8 | "type": "peer", 9 | "network_id": "dev", 10 | "id": "jdoe", 11 | "api_url": "10.17.1.100:7055" 12 | } 13 | ], 14 | "ca": { 15 | "discovery_port": 7056, 16 | "api_host": "10.17.1.100", 17 | "api_port_tls": 7056, 18 | "api_port": 7056, 19 | "type": "ca", 20 | "network_id": "dev", 21 | "url": "10.17.1.100:7056" 22 | }, 23 | "users": [ 24 | { 25 | "enrollId": "bob", 26 | "enrollSecret": "NOE63pEQbL25" 27 | } 28 | ], 29 | "cert": "https://blockchain-certs.mybluemix.net/us.blockchain.ibm.com.cert", 30 | "chaincodepath": "./chaincodes/query.go" 31 | } -------------------------------------------------------------------------------- /env/uk_env.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [{ 3 | "discovery_host": "d169eb482e1f43c38fe579b83da9e68f-vp0.us.blockchain.ibm.com", 4 | "discovery_port": 30003, 5 | "api_host": "d169eb482e1f43c38fe579b83da9e68f-vp0.us.blockchain.ibm.com", 6 | "api_port_tls": 5003, 7 | "api_port": 5003, 8 | "event_host": "d169eb482e1f43c38fe579b83da9e68f-vp0.us.blockchain.ibm.com", 9 | "event_port": 31003, 10 | "type": "peer", 11 | "network_id": "d169eb482e1f43c38fe579b83da9e68f", 12 | "container_id": "c43faa1fa3f8370da775419a1ac1533f23ef5d3fdad3a92169b57bdec5a0661f", 13 | "id": "d169eb482e1f43c38fe579b83da9e68f-vp0", 14 | "api_url": "http://d169eb482e1f43c38fe579b83da9e68f-vp0.us.blockchain.ibm.com:5003" 15 | }, 16 | { 17 | "discovery_host": "d169eb482e1f43c38fe579b83da9e68f-vp2.us.blockchain.ibm.com", 18 | "discovery_port": 30003, 19 | "api_host": "d169eb482e1f43c38fe579b83da9e68f-vp2.us.blockchain.ibm.com", 20 | "api_port_tls": 5003, 21 | "api_port": 5003, 22 | "event_host": "d169eb482e1f43c38fe579b83da9e68f-vp2.us.blockchain.ibm.com", 23 | "event_port": 31003, 24 | "type": "peer", 25 | "network_id": "d169eb482e1f43c38fe579b83da9e68f", 26 | "container_id": "5e76e4c65679bc7fc0c26a9a45aa3f7275aff8a81e4f876d230e22763e000c17", 27 | "id": "d169eb482e1f43c38fe579b83da9e68f-vp2", 28 | "api_url": "http://d169eb482e1f43c38fe579b83da9e68f-vp2.us.blockchain.ibm.com:5003" 29 | }, 30 | { 31 | "discovery_host": "d169eb482e1f43c38fe579b83da9e68f-vp1.us.blockchain.ibm.com", 32 | "discovery_port": 30003, 33 | "api_host": "d169eb482e1f43c38fe579b83da9e68f-vp1.us.blockchain.ibm.com", 34 | "api_port_tls": 5003, 35 | "api_port": 5003, 36 | "event_host": "d169eb482e1f43c38fe579b83da9e68f-vp1.us.blockchain.ibm.com", 37 | "event_port": 31003, 38 | "type": "peer", 39 | "network_id": "d169eb482e1f43c38fe579b83da9e68f", 40 | "container_id": "8676e75eedd59532b2aee26b86f7fc24391dbabd9255201e196ca9783b58e41c", 41 | "id": "d169eb482e1f43c38fe579b83da9e68f-vp1", 42 | "api_url": "http://d169eb482e1f43c38fe579b83da9e68f-vp1.us.blockchain.ibm.com:5003" 43 | }, 44 | { 45 | "discovery_host": "d169eb482e1f43c38fe579b83da9e68f-vp3.us.blockchain.ibm.com", 46 | "discovery_port": 30003, 47 | "api_host": "d169eb482e1f43c38fe579b83da9e68f-vp3.us.blockchain.ibm.com", 48 | "api_port_tls": 5003, 49 | "api_port": 5003, 50 | "event_host": "d169eb482e1f43c38fe579b83da9e68f-vp3.us.blockchain.ibm.com", 51 | "event_port": 31003, 52 | "type": "peer", 53 | "network_id": "d169eb482e1f43c38fe579b83da9e68f", 54 | "container_id": "fc3de29a5c72e561722a5ff7f150f83ce1348784fd0eb06f377e2d1f511c6539", 55 | "id": "d169eb482e1f43c38fe579b83da9e68f-vp3", 56 | "api_url": "http://d169eb482e1f43c38fe579b83da9e68f-vp3.us.blockchain.ibm.com:5003" 57 | } 58 | ], 59 | "ca": { 60 | "d169eb482e1f43c38fe579b83da9e68f-ca": { 61 | "url": "d169eb482e1f43c38fe579b83da9e68f-ca.us.blockchain.ibm.com:30003", 62 | "discovery_host": "d169eb482e1f43c38fe579b83da9e68f-ca.us.blockchain.ibm.com", 63 | "discovery_port": 30003, 64 | "api_host": "d169eb482e1f43c38fe579b83da9e68f-ca.us.blockchain.ibm.com", 65 | "api_port_tls": 30003, 66 | "api_port": 30003, 67 | "type": "ca", 68 | "network_id": "d169eb482e1f43c38fe579b83da9e68f", 69 | "container_id": "df87ae92f776790c427ab07fd387b3262001943fe4ec2c3ec48c63e576d29e33" 70 | } 71 | }, 72 | "users": [{ 73 | "enrollId": "admin", 74 | "enrollSecret": "eb470d3f0b", 75 | "affiliation": "group1", 76 | "username": "admin", 77 | "secret": "eb470d3f0b" 78 | }, 79 | { 80 | "enrollId": "WebAppAdmin", 81 | "enrollSecret": "c9ac727401", 82 | "affiliation": "group1", 83 | "username": "WebAppAdmin", 84 | "secret": "c9ac727401" 85 | }, 86 | { 87 | "enrollId": "user_type1_0", 88 | "enrollSecret": "3d3aae343e", 89 | "affiliation": "group1", 90 | "username": "user_type1_0", 91 | "secret": "3d3aae343e" 92 | }, 93 | { 94 | "enrollId": "user_type1_1", 95 | "enrollSecret": "d310b2f46e", 96 | "affiliation": "group1", 97 | "username": "user_type1_1", 98 | "secret": "d310b2f46e" 99 | }, 100 | { 101 | "enrollId": "user_type1_2", 102 | "enrollSecret": "01b463f57d", 103 | "affiliation": "group1", 104 | "username": "user_type1_2", 105 | "secret": "01b463f57d" 106 | }, 107 | { 108 | "enrollId": "user_type1_3", 109 | "enrollSecret": "69fe1f34b9", 110 | "affiliation": "group1", 111 | "username": "user_type1_3", 112 | "secret": "69fe1f34b9" 113 | }, 114 | { 115 | "enrollId": "user_type1_4", 116 | "enrollSecret": "9e8dafaa6a", 117 | "affiliation": "group1", 118 | "username": "user_type1_4", 119 | "secret": "9e8dafaa6a" 120 | }, 121 | { 122 | "enrollId": "user_type2_0", 123 | "enrollSecret": "521ee25192", 124 | "affiliation": "group1", 125 | "username": "user_type2_0", 126 | "secret": "521ee25192" 127 | }, 128 | { 129 | "enrollId": "user_type2_1", 130 | "enrollSecret": "18fd941968", 131 | "affiliation": "group1", 132 | "username": "user_type2_1", 133 | "secret": "18fd941968" 134 | }, 135 | { 136 | "enrollId": "user_type2_2", 137 | "enrollSecret": "aebecc0db6", 138 | "affiliation": "group1", 139 | "username": "user_type2_2", 140 | "secret": "aebecc0db6" 141 | }, 142 | { 143 | "enrollId": "user_type2_3", 144 | "enrollSecret": "2415f86984", 145 | "affiliation": "group1", 146 | "username": "user_type2_3", 147 | "secret": "2415f86984" 148 | }, 149 | { 150 | "enrollId": "user_type2_4", 151 | "enrollSecret": "3ce9bb70ba", 152 | "affiliation": "group1", 153 | "username": "user_type2_4", 154 | "secret": "3ce9bb70ba" 155 | }, 156 | { 157 | "enrollId": "user_type4_0", 158 | "enrollSecret": "26e3f4d8ce", 159 | "affiliation": "group1", 160 | "username": "user_type4_0", 161 | "secret": "26e3f4d8ce" 162 | }, 163 | { 164 | "enrollId": "user_type4_1", 165 | "enrollSecret": "a9e498c832", 166 | "affiliation": "group1", 167 | "username": "user_type4_1", 168 | "secret": "a9e498c832" 169 | }, 170 | { 171 | "enrollId": "user_type4_2", 172 | "enrollSecret": "b9c905f7ef", 173 | "affiliation": "group1", 174 | "username": "user_type4_2", 175 | "secret": "b9c905f7ef" 176 | }, 177 | { 178 | "enrollId": "user_type4_3", 179 | "enrollSecret": "3a05edfe07", 180 | "affiliation": "group1", 181 | "username": "user_type4_3", 182 | "secret": "3a05edfe07" 183 | }, 184 | { 185 | "enrollId": "user_type4_4", 186 | "enrollSecret": "a8cba8d969", 187 | "affiliation": "group1", 188 | "username": "user_type4_4", 189 | "secret": "a8cba8d969" 190 | }, 191 | { 192 | "enrollId": "user_type8_0", 193 | "enrollSecret": "a92650648a", 194 | "affiliation": "group1", 195 | "username": "user_type8_0", 196 | "secret": "a92650648a" 197 | }, 198 | { 199 | "enrollId": "user_type8_1", 200 | "enrollSecret": "998c72714f", 201 | "affiliation": "group1", 202 | "username": "user_type8_1", 203 | "secret": "998c72714f" 204 | }, 205 | { 206 | "enrollId": "user_type8_2", 207 | "enrollSecret": "6761de8ee0", 208 | "affiliation": "group1", 209 | "username": "user_type8_2", 210 | "secret": "6761de8ee0" 211 | }, 212 | { 213 | "enrollId": "user_type8_3", 214 | "enrollSecret": "37c8778063", 215 | "affiliation": "group1", 216 | "username": "user_type8_3", 217 | "secret": "37c8778063" 218 | }, 219 | { 220 | "enrollId": "user_type8_4", 221 | "enrollSecret": "3f84a79c79", 222 | "affiliation": "group1", 223 | "username": "user_type8_4", 224 | "secret": "3f84a79c79" 225 | } 226 | ], 227 | "cert": "https://blockchain-certs.mybluemix.net/us.blockchain.ibm.com.cert", 228 | "cert_path": "/certs/peer/cert.pem" 229 | } -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - path: . 3 | memory: 256M 4 | instances: 1 5 | domain: mybluemix.net 6 | name: Blockchain-Go 7 | host: ibm-blockchain-demo 8 | disk_quota: 1024M 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BlockchainNodeApp", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node app.js" 7 | }, 8 | "dependencies": { 9 | "express": "~4.13.3", 10 | "cfenv": "1.0.x", 11 | "fs": "0.0.2", 12 | "body-parser": "", 13 | "request-promise": "^2.0.1", 14 | "morgan": "" 15 | }, 16 | "repository": {}, 17 | "engines": { 18 | "node": "4.x" 19 | } 20 | } -------------------------------------------------------------------------------- /public/images/CatToast1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/CatToast1.gif -------------------------------------------------------------------------------- /public/images/CatToast2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/CatToast2.gif -------------------------------------------------------------------------------- /public/images/Underground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/Underground.png -------------------------------------------------------------------------------- /public/images/blockchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/blockchain.png -------------------------------------------------------------------------------- /public/images/blockchain_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/blockchain_icon.png -------------------------------------------------------------------------------- /public/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/error.png -------------------------------------------------------------------------------- /public/images/gears.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/gears.gif -------------------------------------------------------------------------------- /public/images/pallete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/pallete.png -------------------------------------------------------------------------------- /public/images/player1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/player1.png -------------------------------------------------------------------------------- /public/images/player2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/player2.png -------------------------------------------------------------------------------- /public/images/player3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-blockchain/blockchain-go/93d8aad7e29c73e1cda4d7fed3cde4e0b671f611/public/images/player3.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | blockchain-go 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 |
24 |
25 |

26 | If the temperature exceeds 24ºC,
the package must be inspected. 27 | The party responsible
for the package at the time of the temperature 28 | increase
is held accountable for all losses.
29 |
30 |
31 |
32 |

33 |
34 | 35 |
36 |

Status Monitor

37 |
38 |
39 |
40 |
41 |
42 |
46 | 47 |
48 | 49 |
50 |
51 | 52 |
53 | 54 | 55 | 56 | 72 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /public/js/animation.js: -------------------------------------------------------------------------------- 1 | /*creating animated blocks for monitor*/ 2 | let block = 0; 3 | let space = 32, currentPayload; 4 | let blocksArray = []; 5 | 6 | function getStats() { 7 | $.get('/blockchain', function(data) { 8 | let found = false; 9 | blocksArray.forEach(function(seekAndDestroy) { 10 | if (seekAndDestroy.height === data.height) { 11 | console.log(`block allready exists ${data.height}`); 12 | found = true; 13 | return; 14 | } 15 | }); 16 | if (!found) { 17 | blocksArray.push(data); 18 | let appendToHistory = payloadHistory[payloadHistory.length - 1]; 19 | appendToHistory.height = data.height; 20 | //console.log("data.height: " + data.height + "last \n" + JSON.stringify(payloadHistory[payloadHistory.length - 1].height)); 21 | block = block + 1; 22 | $(".animationDiv").append("
" + data.height + "
"); 23 | $('.block:last').animate({ opacity: 1, left: (block * space) }, 1000, function() { 24 | $('.lastblock').removeClass('lastblock'); 25 | if (appendToHistory.temperature > 24) { //appendToHistory.status === true && 26 | console.log(`getStats - status(return): ${appendToHistory.status} && ${appendToHistory.temperature}`); 27 | $('.block:last').addClass('alertBlock'); 28 | } else { 29 | $('.block:last').addClass('lastblock'); 30 | } 31 | }); 32 | //console.log(JSON.stringify(data) + typeof (data)); 33 | block++; 34 | } 35 | }); 36 | } 37 | 38 | function sendBlocks(payload) { 39 | payload.user = currentPlayer.getTitle(); 40 | payload.action = "transfer"; 41 | doTransaction(payload); 42 | //console.log("sendBlocks: " + JSON.stringify(payload)); 43 | } 44 | 45 | function getDeploymentBlock() { 46 | $.get('/genesis', function(deployed) { 47 | blocksArray.push(deployed); 48 | payloadHistory.push(deployed); 49 | block = block + 1; 50 | $(".animationDiv").append("
" + deployed.height + "
"); 51 | $('.block:last').animate({ opacity: 1, left: (block * space) }, 1000, function() { 52 | $('.lastblock').removeClass('lastblock'); 53 | $('.block:last').addClass('lastblock'); 54 | }); 55 | block++; 56 | }); 57 | } 58 | 59 | 60 | $(document).on('mouseover', '.block', function(event) { 61 | let height = Number($(this).html()); 62 | //console.log(`let height = Number($(this).html() ${height}`); 63 | payloadHistory.forEach(function(dataHistory) { 64 | //console.log("dataHistory " + JSON.stringify(dataHistory)); 65 | if (dataHistory.height === height) { 66 | currentPayload = dataHistory; 67 | } 68 | }); 69 | show_details(event, height, currentPayload); 70 | }); 71 | 72 | $(document).on('mouseleave', '.block', function() { 73 | $('#details').fadeOut(); 74 | }); 75 | 76 | //Missing payload info 77 | function show_details(event, id, message) { 78 | let currentBlock; 79 | var left, html, deploy = false; 80 | blocksArray.forEach(function(current) { 81 | if (current.height === id) { 82 | currentBlock = current; 83 | //console.log(currentBlock.height + " || " + id + " || " + message.height + " all " + JSON.stringify(currentBlock)); 84 | } 85 | if (message.isDeploy) { 86 | message = { deployment: "first block!", created: message.lastTransaction } 87 | currentBlock.consensusMetadata = "genesis"; 88 | deploy = true; 89 | } else if (message.isInit) { 90 | console.log(`isInit: ${message.isInit}`); 91 | message.action = "init"; 92 | } 93 | }); 94 | 95 | left = event.pageX - $('#details').parent().offset().left - 120; 96 | 97 | if (left < 0) left = 0; 98 | html = '

Ledger Block Height: ' + currentBlock.height + '

'; 99 | html += '

Created:  ' + formatDate(currentBlock.created * 1000, '%M-%d-%Y %I:%m%p') + '

'; 100 | html += ' UUID:    ' + currentBlock.uuid.slice(0, 17); 101 | //html += '

Type:   ' + message.type + '

'; 102 | html += '

Consensus Metadata:     ' + currentBlock.consensusMetadata + '

'; 103 | if (!deploy) { 104 | if (message.action === undefined) { 105 | message.action = "update"; 106 | } 107 | html += ' Action:     ' + message.action + '
'; 108 | html += ' Description:     ' + message.description + '
'; 109 | html += ' Owner:     ' + message.user + '
'; 110 | html += ' Temperature:     ' + message.temperature + ' C.°
'; 111 | } else { 112 | html += ' Payload:
' + JSON.stringify(message) + '
'; 113 | } 114 | if (message.temperature > 24) { 115 | console.log("alert details"); 116 | $('#details').addClass('alertDetails'); 117 | 118 | } 119 | $('#details').html(html).css('left', left).fadeIn(); 120 | 121 | } 122 | 123 | function formatDate(date, fmt) { 124 | date = new Date(date); 125 | function pad(value) { 126 | return (value.toString().length < 2) ? '0' + value : value; 127 | } 128 | return fmt.replace(/%([a-zA-Z])/g, function(_, fmtCode) { 129 | var tmp; 130 | switch (fmtCode) { 131 | case 'Y': //Year 132 | return date.getUTCFullYear(); 133 | case 'M': //Month 0 padded 134 | return pad(date.getUTCMonth() + 1); 135 | case 'd': //Date 0 padded 136 | return pad(date.getUTCDate()); 137 | case 'H': //24 Hour 0 padded 138 | return pad(date.getUTCHours()); 139 | case 'I': //12 Hour 0 padded 140 | tmp = date.getUTCHours(); 141 | if (tmp === 0) tmp = 12; //00:00 should be seen as 12:00am 142 | else if (tmp > 12) tmp -= 12; 143 | return pad(tmp); 144 | case 'p': //am / pm 145 | tmp = date.getUTCHours(); 146 | if (tmp >= 12) return 'pm'; 147 | return 'am'; 148 | case 'P': //AM / PM 149 | tmp = date.getUTCHours(); 150 | if (tmp >= 12) return 'PM'; 151 | return 'AM'; 152 | case 'm': //Minutes 0 padded 153 | return pad(date.getUTCMinutes()); 154 | case 's': //Seconds 0 padded 155 | return pad(date.getUTCSeconds()); 156 | case 'r': //Milliseconds 0 padded 157 | return pad(date.getUTCMilliseconds(), 3); 158 | case 'q': //UTC timestamp 159 | return date.getTime(); 160 | default: 161 | throw new Error('Unsupported format code: ' + fmtCode); 162 | } 163 | }); 164 | } -------------------------------------------------------------------------------- /public/js/demo.js: -------------------------------------------------------------------------------- 1 | var map, 2 | uuid, 3 | marker, 4 | route, 5 | markers, 6 | trigger, 7 | trigger$, 8 | mqttClient, 9 | currentPlayer, 10 | dataInfo, 11 | infowindow, 12 | humidity, 13 | verifyValue, 14 | verifyOwner = "No", 15 | temperature = 21, 16 | payloadHistory = [], 17 | heldAccountable = false, 18 | count = 1, steps = 0, 19 | status = 'Satisfied', 20 | rand = Math.floor((Math.random() * 8000) + 1), 21 | pack = "Asset Package " + rand, 22 | now = new Date().toLocaleString(), 23 | data = { description: pack, user: "Industry", action: "create", temperature: temperature, lastTransaction: now }; 24 | 25 | 26 | var defaultCoordinates = [{ 27 | "lat": -23.56996189423875, 28 | "lng": -46.65141653365975 29 | }, { 30 | "lat": -23.57997497987705, 31 | "lng": -46.6491940773286 32 | }, { 33 | "lat": -23.581153, 34 | "lng": -46.663667 35 | }, { 36 | "lat": -23.581645286215887, 37 | "lng": -46.64944620296468 38 | }]; 39 | 40 | var playerSet = [ 41 | ['Industry', defaultCoordinates[0].lat, defaultCoordinates[0].lng, 2], 42 | ['Shipping Company', defaultCoordinates[1].lat, defaultCoordinates[1].lng, 3], 43 | ['Customer', defaultCoordinates[2].lat, defaultCoordinates[2].lng, 4] 44 | ]; 45 | 46 | //---------------------//----------------------------//----------------// 47 | 48 | /*{@Object data} 49 | *On ready callback controls all the elements and order on tracking 50 | **/ 51 | $(document).ready(function () { 52 | 53 | $('#myModal').modal('show'); 54 | 55 | /*@{Object data} creates an asset triggering createAsset & doTransaction*/ 56 | $('.btn-primary').click(function () { 57 | currentPlayer = markers[0]; 58 | getDeploymentBlock(); 59 | createAsset(data); 60 | }); 61 | 62 | $('#startDemo').click(function () { 63 | $(".assetContainer").fadeOut("slow"); 64 | setupTracking(); 65 | seePackage(); 66 | $(this).fadeOut(); 67 | }); 68 | 69 | $("#btnUpTemp").click(function () { 70 | temperature++; 71 | data.temperature = temperature; 72 | $("#lblTemperature").text(`${temperature} ºC`); 73 | console.log(data.temperature); 74 | }); 75 | 76 | $("#btnDownTemp").click(function () { 77 | temperature--; 78 | data.temperature = temperature; 79 | $("#lblTemperature").text(`${temperature} ºC`); 80 | console.log(data.temperature); 81 | }); 82 | }); 83 | 84 | //------------------//-------------------------//--------------------// 85 | 86 | /*@{Object data} - Rest functions*/ 87 | function doTransaction(action) { 88 | //console.log("[doTransaction]request: ${action} " + JSON.stringify(action)); 89 | $.post('/request', action).done(function onSuccess(res) { 90 | data = res; 91 | console.log(`[doTransaction]success ${res.description}`); 92 | if (data.temperature > 24) { 93 | console.log(`doTransaction - status(return): ${data.status}`); 94 | data.status = true; 95 | } 96 | payloadHistory.push(data); 97 | getStats(payloadHistory); 98 | if (data.status === true && data.user === currentPlayer.getTitle()) { 99 | console.log(`${currentPlayer.getTitle()} = ${data.user}`); 100 | heldAccountable = true; 101 | checkStatus(data); 102 | } else { 103 | heldAccountable = false; 104 | data.status === false; 105 | } 106 | }).fail(function onError(error) { 107 | console.log(`error requesting ${error}`); 108 | }); 109 | } 110 | 111 | function checkStatus(context) { 112 | //console.log(`checkStatus ${context.status}`); 113 | statsEventListenner(context); 114 | if (temperature > 24) { //heldAccountable || 115 | status = "Verify Package! " + currentPlayer.getTitle() + ""; 116 | let alertMsg = ""; 117 | infowindow.setContent(alertMsg); 118 | infowindow.open(map, currentPlayer); 119 | verifyValue = temperature; 120 | data.status === false; 121 | console.log(`verifyValue: (checkStatus) ${verifyValue}`); 122 | console.log(`status: (false?) ${data.status}`); 123 | for (var i = 1; i < playerSet.length - 1; i++) { 124 | if (playerSet[i][0] === currentPlayer.getTitle()) { 125 | verifyOwner = playerSet[i][0]; 126 | } 127 | } 128 | } else { 129 | verifyValue = undefined; 130 | heldAccountable = false; 131 | data.status = false; 132 | } 133 | } 134 | 135 | /*@{Function data} - starting animation(executes once - calls playTracking() => interval)*/ 136 | function setupTracking() { 137 | //info balloon notification 138 | dataInfo = currentPlayer.getTitle() + " is shipping assets"; 139 | infowindow = new google.maps.InfoWindow({ 140 | content: dataInfo, 141 | maxWidth: 250, 142 | maxHeight: 80 143 | }); 144 | 145 | infowindow.open(map, currentPlayer); 146 | trigger = setInterval(function () { 147 | playTracking(data) 148 | }, 1000); 149 | 150 | trigger$ = setInterval(function () { 151 | sendBlocks(data); 152 | }, 9000) 153 | //ensuring it has valid objects 154 | markers.forEach(function (icon) { 155 | console.log(`marker ${icon.getTitle()}`); 156 | }); 157 | } 158 | 159 | /*@{Function data} this function "animates" the icons through the route*/ 160 | function playTracking(values) { 161 | 162 | let package = values; //fix error VM311 163 | //set of variables to hold current and next lat/long(comparision) 164 | let currentLat = currentPlayer.getPosition().lat(); 165 | let nextLat = markers[count].getPosition().lat(); 166 | let currentLng = currentPlayer.getPosition().lng(); 167 | let nextLng = markers[count].getPosition().lng(); 168 | if (verifyValue !== undefined) { 169 | package.temperature = verifyValue 170 | console.log(`Verifying value ${verifyValue} || infractors?: ${verifyOwner} heldAccountable ${heldAccountable}`); 171 | } 172 | 173 | /*console.log(`heldAccountable ${heldAccountable}`); 174 | console.log(`status now ${data.status}`);*/ 175 | 176 | //update stats window 177 | checkStatus(package); 178 | currentPlayer.setPosition(route[steps + 15]); 179 | //console.log(`steps ${steps}`); 180 | if (currentLat - nextLat < 0.0000013522 && currentLng - nextLng < 0.0000013522) { 181 | console.log(`count ${count}`); 182 | currentPlayer = markers[count]; 183 | package.user = currentPlayer.getTitle(); 184 | package.action = "transfer"; 185 | 186 | //current package's owner 187 | /*console.log(`interval ${package.user}`);*/ 188 | 189 | //request to server 190 | doTransaction(package); 191 | 192 | //delay to update all UI elements with the new state 193 | setTimeout(function () { 194 | $('#currentPlayer').html(currentPlayer.getTitle()); 195 | infowindow.setContent(package.user + " is shipping assets"); 196 | infowindow.open(map, currentPlayer); 197 | count++; 198 | if (count === 3) { 199 | package.user = currentPlayer.getTitle(); 200 | package.action = "transfer"; 201 | doTransaction(package); 202 | stopTracking(trigger, trigger$); 203 | checkStatus(package); 204 | infowindow.setContent("Order finished"); 205 | } 206 | }, 500); 207 | } 208 | steps++; 209 | } 210 | 211 | /*@{Object data} - stops playTracking()*/ 212 | function stopTracking(interval, interval$) { 213 | clearInterval(interval$); 214 | clearInterval(interval); 215 | finalSummary(); 216 | //console.log("payloadHistory " + JSON.stringify(payloadHistory)); 217 | } 218 | 219 | //--------------------------------------------//------------------------------------------------ 220 | 221 | /*Drawing Map*/ 222 | function initMap() { 223 | directionsService = new google.maps.DirectionsService; 224 | directionsDisplay = new google.maps.DirectionsRenderer({ 225 | draggable: true, 226 | suppressMarkers: true 227 | }); 228 | 229 | var mapCenter = new google.maps.LatLng( 230 | defaultCoordinates[defaultCoordinates.length - 1].lat, 231 | defaultCoordinates[defaultCoordinates.length - 1].lng); 232 | 233 | var mapOptions = { 234 | center: mapCenter, 235 | zoom: 14, 236 | mapTypeId: google.maps.MapTypeId.HYBRID 237 | }; 238 | 239 | map = new google.maps.Map(document.getElementById('map'), mapOptions); 240 | 241 | directionsDisplay.setMap(map); 242 | calculateAndDisplayRoute(directionsService, directionsDisplay); 243 | setMarkers(map); 244 | } 245 | 246 | function setMarkers(map) { 247 | let image, img; 248 | markers = []; 249 | for (var x = 0; x < playerSet.length; x++) { 250 | let actors = playerSet[x]; 251 | img = x + 1; 252 | image = 'images/player' + img + '.png'; 253 | marker = new google.maps.Marker({ 254 | position: { lat: actors[1], lng: actors[2] }, 255 | map: map, 256 | icon: image, 257 | animation: google.maps.Animation.DROP, 258 | title: actors[0], 259 | zIndex: actors[3], 260 | draggable: false 261 | }); 262 | markers.push(marker); 263 | marker.addListener('dragend', function () { 264 | let player = this.getTitle(); 265 | for (var y in playerSet) { 266 | if (playerSet[y][0] === player) { 267 | playerSet[y][1] = this.getPosition().lat(); 268 | playerSet[y][2] = this.getPosition().lng(); 269 | } 270 | } 271 | calculateAndDisplayRoute(directionsService, directionsDisplay); 272 | }); 273 | } 274 | } 275 | 276 | function calculateAndDisplayRoute(directionsService, directionsDisplay) { 277 | var waypts = []; 278 | 279 | for (var i = 1; i < playerSet.length - 1; i++) { 280 | var position = { "lat": playerSet[i][1], "lng": playerSet[i][2] }; 281 | waypts.push({ 282 | location: position, 283 | stopover: true 284 | }); 285 | } 286 | 287 | directionsService.route({ 288 | origin: { lat: playerSet[0][1], lng: playerSet[0][2] }, 289 | destination: { lat: playerSet[playerSet.length - 1][1], lng: playerSet[playerSet.length - 1][2] }, 290 | waypoints: waypts, 291 | optimizeWaypoints: true, 292 | travelMode: google.maps.TravelMode.DRIVING 293 | }, function (data, status) { 294 | if (status === google.maps.DirectionsStatus.OK) { 295 | //preserveViewport: true => solved the zoom issue 296 | directionsDisplay.setOptions({ preserveViewport: true }); 297 | directionsDisplay.setDirections(data); 298 | route = data.routes[0].overview_path; 299 | 300 | } 301 | }); 302 | //map.setZoom(2); 303 | //console.log(`maps zoom: ${map.getZoom()}`); 304 | } 305 | 306 | /*--------------//-----------------------------------//---------------------*/ 307 | 308 | /*UI events listenner*/ 309 | 310 | function onLoadAsset() { 311 | $('.modal-content').empty(); 312 | $('.modal-content').append('

Creating Asset...

'); 313 | $(".loading").fadeIn(); 314 | } 315 | 316 | function createAsset(init) { 317 | onLoadAsset(); 318 | doTransaction(init); 319 | let assetContainerBody = $('.assetContainerBody'); 320 | let animationDiv = $('.animationDiv'); 321 | let blockchainInfoDiv = $('.blockchainInfo'); 322 | let assetContainer = $('.assetContainer'); 323 | let btnStart = $('assetContainerBody button'); 324 | 325 | setTimeout(function () { 326 | if (data !== null && data !== undefined) { 327 | 328 | $('.modal-backdrop').fadeOut(); 329 | $('.modal-dialog').fadeOut("slow"); 330 | $('#myModal').modal('hide'); 331 | 332 | assetContainerBody.append('

' + 333 | '

Asset created

' + 334 | '
Owner: ' + data.user.toUpperCase() + 335 | '
Description: ' + data.description + 336 | '
Registered: ' + data.lastTransaction); 337 | 338 | blockchainInfoDiv.fadeIn("slow"); 339 | animationDiv.fadeIn("slow"); 340 | assetContainer.fadeIn("slow"); 341 | assetContainer.addClass("extendContainer"); 342 | assetContainerBody.fadeIn("slow"); 343 | btnStart.fadeIn("slow"); 344 | checkStatus(init); 345 | } 346 | else { 347 | return alert("error creating asset.please try again"); 348 | } 349 | }, 3000); 350 | } 351 | 352 | function seePackage() { 353 | $("#showPackage").mouseover(function () { 354 | $(".assetContainer").fadeIn("slow"); 355 | }); 356 | 357 | $("#showPackage").mouseout(function () { 358 | $(".assetContainer").fadeOut("slow"); 359 | }); 360 | } 361 | 362 | function finalSummary() { 363 | 364 | let content = $('.modal-content'); 365 | let c = 1; 366 | content.empty(); 367 | content.append('' + 368 | ''); 370 | 371 | payloadHistory.forEach(function (log) { 372 | //console.log("generating summary " + JSON.stringify(log)); 373 | if (log.description !== undefined) { 374 | $('.modal-body').append('
Description:\n ' 375 | + log.description + ' User: ' + log.user + ' temperature: ' + log.temperature + ' C.°

'); 376 | 377 | if (log.temperature > 24) { 378 | let thisElem = "#historyLog" + c; 379 | console.log(`temperature$ ${log.temperature}`); 380 | $(thisElem).addClass("infractorData"); 381 | } 382 | c++; 383 | } 384 | }); 385 | 386 | //showing final summary 387 | console.log(`modal-fade:`); 388 | $('.modal-dialog').modal(); 389 | $('#myModal').modal("show"); 390 | 391 | $('.hideModal').click(function () { 392 | $('.modal-dialog').modal("hide"); 393 | $('#myModal').modal("hide"); 394 | }); 395 | } 396 | 397 | /*@{Object data} - listenner to blockchain events*/ 398 | function statsEventListenner(context) { 399 | let currenTime = new Date().toLocaleString(); 400 | console.log(`temp changing: ${context.temperature} || ${temperature}`); 401 | if (context.temperature !== temperature) { 402 | context.temperature = temperature; 403 | } 404 | $("#lblTemperature").text(`${temperature} ºC`); 405 | $("#lblTime").text(`${currenTime}`); 406 | $("#lastTransactionTime").text(`${context.lastTransaction}`); 407 | $("#lblDescription").text(`${context.description}`); 408 | $("#lblOwner").text(`${currentPlayer.getTitle()}`); 409 | $("#lblStatus").text(`${status}`); 410 | } -------------------------------------------------------------------------------- /public/js/mqttClient.js: -------------------------------------------------------------------------------- 1 | //Mqtt Client functions 2 | 3 | // Create a client instance 4 | mqttClient = new Paho.MQTT.Client("b6kg16.messaging.internetofthings.ibmcloud.com", 1883, "a:b6kg16:mapui"); 5 | 6 | // set callback handlers 7 | mqttClient.onConnectionLost = onConnectionLost; 8 | mqttClient.onMessageArrived = onMessageArrived; 9 | 10 | // connect the mqttClient 11 | mqttClient.connect({ 12 | onSuccess: onConnect, 13 | userName: "a-b6kg16-makbfawlct", 14 | password: "xEQKOkZ+SL@TT5zXp&" 15 | }); 16 | 17 | 18 | // called when the mqttClient connects 19 | function onConnect() { 20 | // Once a connection has been made, make a subscription and send a message. 21 | 22 | mqttClient.subscribe("iot-2/type/+/id/linkitone01/evt/telemetry/fmt/json"); 23 | mqttClient.subscribe("iot-2/type/+/id/fake_device/evt/telemetry/fmt/json"); 24 | message = new Paho.MQTT.Message("Hello"); 25 | message.destinationName = "/World"; 26 | mqttClient.send(message); 27 | } 28 | 29 | // called when the mqttClient loses its connection 30 | function onConnectionLost(responseObject) { 31 | if (responseObject.errorCode !== 0) { 32 | console.log(`error connecting to mqtt ${responseObject.errorCode}`); 33 | } 34 | } 35 | 36 | // called when a message arrives 37 | function onMessageArrived(message) { 38 | payload = JSON.parse(message.payloadString); 39 | payload.timestamp = new Date().getTime(); 40 | temperature = Number((payload.t - 273).toFixed(2)); 41 | console.log(`connected ${message.payloadString}`); 42 | //validating contract 43 | 44 | } -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | #map { 8 | height: 100%; 9 | } 10 | 11 | .hideModal { 12 | position: absolute; 13 | cursor: pointer; 14 | left: 5%; 15 | } 16 | 17 | #introBlockChain { 18 | text-align: center; 19 | } 20 | 21 | body .modal-dialog { 22 | width: 80%; 23 | align-content: center; 24 | } 25 | 26 | body .modal-dialog img { 27 | width: 80%; 28 | position: relative; 29 | left: 10%; 30 | } 31 | 32 | .assetContainerBody { 33 | display: none; 34 | } 35 | 36 | #packageImg { 37 | width: 30%; 38 | max-width: 45%; 39 | height: 30%; 40 | max-height: 45%; 41 | } 42 | 43 | .smartContract { 44 | border-radius: 8px; 45 | align-items: center; 46 | width: auto; 47 | min-width: 10%; 48 | height: auto; 49 | min-height: 10%; 50 | } 51 | 52 | .smartContract span { 53 | border-radius: 4px; 54 | color: #ffffff; 55 | font-size: 120%; 56 | } 57 | 58 | #gearsLoad { 59 | position: absolute; 60 | left: 45%; 61 | width: 20%; 62 | height: 15%; 63 | color: darkorange; 64 | border-right: 25px #222832 solid; 65 | border-left: 25px #222832 solid; 66 | border-top-right-radius: 10px; 67 | border-top-left-radius: 10px; 68 | border-bottom-right-radius: 10px; 69 | border-bottom-left-radius: 10px; 70 | } 71 | 72 | .assetContainer { 73 | width: auto; 74 | max-width: 40%; 75 | height: auto; 76 | max-height: 70%; 77 | position: absolute; 78 | right: 0; 79 | top: 45px; 80 | color: #7E90A0; 81 | background: #222832; 82 | align-items: center; 83 | padding: 30px 0; 84 | border-left: 25px #222832 solid; 85 | border-top-left-radius: 10px; 86 | border-bottom-left-radius: 10px; 87 | text-align: center; 88 | } 89 | 90 | .loadAsset { 91 | width: 25%; 92 | } 93 | 94 | .finalsummary { 95 | border-top-right-radius: 10px; 96 | border-top-left-radius: 10px; 97 | border-bottom-right-radius: 10px; 98 | border-bottom-left-radius: 10px; 99 | background: cornflowerblue; 100 | color: white; 101 | align-items: center; 102 | text-align: center; 103 | min-width: 30%; 104 | } 105 | 106 | .fullbody { 107 | background: #222832; 108 | color: #7E90A0; 109 | } 110 | 111 | .infractorData { 112 | color: orangered; 113 | } 114 | 115 | .btn-primary { 116 | right: 2%; 117 | bottom: 2%; 118 | position: absolute; 119 | } 120 | 121 | .btn-warning { 122 | width: 5px; 123 | height: 5px; 124 | align-content: center; 125 | } 126 | 127 | #myModal { 128 | width: 80%; 129 | top: 10%; 130 | position: absolute; 131 | left: 10%; 132 | } 133 | 134 | .blockchainInfo { 135 | width: auto; 136 | max-width: 55%; 137 | height: auto; 138 | max-height: 85%; 139 | position: absolute; 140 | left: 2%; 141 | top: 10%; 142 | color: #7E90A0; 143 | background: #222832; 144 | align-items: center; 145 | padding: 30px 0; 146 | border-right: 25px #222832 solid; 147 | border-left: 25px #222832 solid; 148 | border-top-right-radius: 10px; 149 | border-top-left-radius: 10px; 150 | border-bottom-right-radius: 10px; 151 | border-bottom-left-radius: 10px; 152 | text-align: center; 153 | } 154 | 155 | .blockchainInfo label { 156 | width: auto; 157 | height: auto; 158 | } 159 | 160 | .assetContainerBody button { 161 | top: 70%; 162 | width: auto; 163 | height: auto; 164 | } 165 | 166 | .assetContainerBody label { 167 | width: auto; 168 | height: auto; 169 | } 170 | 171 | .extendContainer { 172 | height: 67%; 173 | transition-duration: 1.5; 174 | } 175 | 176 | .stats { 177 | font: 30%; 178 | color: darkorange; 179 | align-self: center; 180 | } 181 | 182 | #showPackage:hover { 183 | cursor: pointer; 184 | } 185 | 186 | .alert { 187 | align-self: center; 188 | font-size: 130%; 189 | color: red; 190 | } 191 | 192 | .animationDiv { 193 | position: absolute; 194 | width: 70%; 195 | background: #222832; 196 | height: 7%; 197 | bottom: 2%; 198 | left: 15%; 199 | align-self: center; 200 | border-right: 25px #222832 solid; 201 | border-left: 25px #222832 solid; 202 | border-top-right-radius: 10px; 203 | border-top-left-radius: 10px; 204 | border-bottom-right-radius: 10px; 205 | border-bottom-left-radius: 10px; 206 | } 207 | 208 | .alertDetails { 209 | background: #222832; 210 | color: darkorange; 211 | display: none; 212 | position: absolute; 213 | top: -400%; 214 | width: 270px; 215 | min-width: 130px; 216 | min-height: 80px; 217 | max-height: 350px; 218 | border-radius: 10px; 219 | padding: 15px 30px; 220 | word-break: break-all; 221 | font-size: 12px; 222 | } 223 | 224 | #details { 225 | background: #222832; 226 | color: #2EB9D6; 227 | display: none; 228 | position: relative; 229 | top: -400%; 230 | width: 270px; 231 | min-width: 130px; 232 | min-height: 80px; 233 | max-height: 350px; 234 | border-radius: 10px; 235 | padding: 15px 30px; 236 | word-break: break-all; 237 | font-size: 12px; 238 | } 239 | 240 | .block:hover { 241 | cursor: pointer; 242 | } 243 | 244 | .block { 245 | line-height: 30px; 246 | color: #2EB9D6; 247 | text-align: center; 248 | position: absolute; 249 | top: 5%; 250 | left: 110%; 251 | height: 90%; 252 | width: 62px; 253 | border-radius: 4px; 254 | opacity: 5; 255 | border: #2EB9D6 solid 1px; 256 | font-size: 12px; 257 | transition: background-color 0.5s ease; 258 | font-weight: bold; 259 | } 260 | 261 | .alertBlock { 262 | transition: background-color 1s ease; 263 | background: #222832; 264 | color: darkorange; 265 | border-color: red; 266 | } 267 | 268 | .lastblock { 269 | transition: background-color 1s ease; 270 | background: #2EB9D6; 271 | color: #222832; 272 | border-color: #2EB9D6; 273 | } 274 | 275 | .block:hover { 276 | border: #22697A solid 1px; 277 | color: #22697A; 278 | } -------------------------------------------------------------------------------- /rest/api.js: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * Rest module for interaction with a blockchain network. 4 | * First implementation by Vitor Diego 5 | * ************************************/ 6 | 'use strict' 7 | 8 | const request = require('request-promise'); 9 | const blockchain = require('../rest/listenner')(); 10 | 11 | module.exports = function (host, port) { 12 | 13 | var chaincodeId, secureContextId; 14 | 15 | function registrar(user, secret) { 16 | console.log(`registrar() =>`); 17 | let url = "https://" + host + ":" + port 18 | var options = { 19 | //"method": 'POST', 20 | "url": url + '/registrar', 21 | "headers": { 22 | 'Accept': 'application/json', 23 | 'Content-Type': 'application/json' 24 | }, 25 | "body": JSON.stringify({ 26 | "enrollId": user, 27 | "enrollSecret": secret 28 | }) 29 | }; 30 | 31 | request.post(options).then(function (response) { 32 | console.log(`[registrar] success: ${response}`); 33 | secureContextId = user; 34 | blockchain.getListener(host, port); 35 | return init(); 36 | }).catch(function (err) { 37 | if (err) { 38 | console.log(`[registrar] error: ${err}`); 39 | return err; 40 | } 41 | }); 42 | } 43 | 44 | function init() { 45 | console.log(`init() =>`); 46 | let url = "https://" + host + ":" + port 47 | var options = { 48 | //"method": 'POST', 49 | "url": url + '/chaincode', 50 | "headers": { 51 | 'Accept': 'application/json', 52 | 'Content-Type': 'application/json' 53 | }, 54 | "body": JSON.stringify({ 55 | "jsonrpc": "2.0", 56 | "method": "deploy", 57 | "params": { 58 | "type": 1, 59 | "chaincodeID": { 60 | "path": "https://github.com/VitorSousaCode/chaincodes/experimental", 61 | "name": "chaincodeMain" 62 | }, 63 | "ctorMsg": { 64 | "function": "init", 65 | "args": [ 66 | "99" 67 | ] 68 | }, 69 | "secureContext": secureContextId 70 | }, 71 | "id": 1 72 | }) 73 | }; 74 | 75 | request.post(options).then(function (response) { 76 | //console.log("$%& " + typeof (response)); 77 | console.log(`[init] success:${response}`); 78 | let id = JSON.parse(response); 79 | chaincodeId = id.result.message; 80 | return; 81 | }).catch(function (err) { 82 | if (err) { 83 | console.log(`[init] error: ${err}`); 84 | return err; 85 | } 86 | }); 87 | } 88 | 89 | function init_asset(params, callback) { 90 | console.log(`init_asset() =>`); 91 | let url = "https://" + host + ":" + port 92 | var options = { 93 | "method": 'POST', 94 | "url": url + '/chaincode', 95 | "headers": { 96 | 'Accept': 'application/json', 97 | 'Content-Type': 'application/json' 98 | }, 99 | "body": JSON.stringify({ 100 | "jsonrpc": "2.0", 101 | "method": "invoke", 102 | "params": { 103 | "type": 1, 104 | "chaincodeID": { 105 | "name": chaincodeId 106 | }, 107 | "ctorMsg": { 108 | "function": "init_asset", 109 | "args": params 110 | 111 | }, 112 | "secureContext": secureContextId 113 | }, 114 | "id": 1 115 | }) 116 | }; 117 | 118 | request(options).then(function (response) { 119 | console.log(`[init_asset] success: ${response}`); 120 | return callback(null, response); 121 | }).catch(function (err) { 122 | console.log(`[init_asset] error: ${err}`); 123 | return callback(err); 124 | }); 125 | } 126 | 127 | function set_user(params, callback) { 128 | console.log(`set_user() =>`); 129 | let url = "https://" + host + ":" + port 130 | var options = { 131 | "method": 'POST', 132 | "url": url + '/chaincode', 133 | "headers": { 134 | 'Accept': 'application/json', 135 | 'Content-Type': 'application/json' 136 | }, 137 | "body": JSON.stringify({ 138 | "jsonrpc": "2.0", 139 | "method": "invoke", 140 | "params": { 141 | "type": 1, 142 | "chaincodeID": { 143 | //"path": chaincodeId, 144 | "name": chaincodeId 145 | }, 146 | "ctorMsg": { 147 | "function": "set_user", 148 | "args": params 149 | 150 | }, 151 | "secureContext": secureContextId 152 | }, 153 | "id": 1 154 | }) 155 | }; 156 | 157 | request(options).then(function (response) { 158 | console.log(`[set_user] success: ${response}`); 159 | return callback(null, response); 160 | }).catch(function (err) { 161 | console.log(`[set_user] error: ${err}`); 162 | return callback(err); 163 | }); 164 | } 165 | 166 | function read(params, callback) { 167 | console.log(`[api] read() => ${params}`); 168 | //params = ["Asset Package 18"]; 169 | let url = "https://" + host + ":" + port 170 | var options = { 171 | "method": 'POST', 172 | "url": url + '/chaincode', 173 | "headers": { 174 | 'Accept': 'application/json', 175 | 'Content-Type': 'application/json' 176 | }, 177 | "body": JSON.stringify({ 178 | "jsonrpc": "2.0", 179 | "method": "query", 180 | "params": { 181 | "type": 1, 182 | "chaincodeID": { 183 | "name": chaincodeId 184 | }, 185 | "ctorMsg": { 186 | "function": "read", 187 | "args": params 188 | 189 | }, 190 | "secureContext": secureContextId 191 | }, 192 | "id": 1 193 | }) 194 | }; 195 | 196 | request(options).then(function (response) { 197 | console.log(`[read] success: ${response}`); 198 | return callback(null, response); 199 | }).catch(function (err) { 200 | console.log(`[read] error: ${err}`); 201 | return callback(err); 202 | }); 203 | } 204 | 205 | var restModule = { 206 | 207 | invoke: { 208 | init: init, 209 | init_asset: init_asset, 210 | set_user: set_user, 211 | registrar: registrar 212 | }, 213 | query: { 214 | read: read 215 | } 216 | } 217 | 218 | return restModule; 219 | 220 | } -------------------------------------------------------------------------------- /rest/blockchain.js: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | /* Copyright 2016 IBM Corp. All Rights Reserved. 3 | * rest implementation for Blockchain-Go demo 4 | * first implementation by Vitor Diego 5 | */ 6 | //------------------------------------------------------------------------------ 7 | 8 | 'use strict' 9 | 10 | //const Promise = require('bluebird'); 11 | let chaincode; 12 | let response = ''; 13 | 14 | module.exports.action = function (params, callback) { 15 | chaincode = require('../config/setup').chain(); 16 | return chainInteraction(params, callback); 17 | } 18 | 19 | function chainInteraction(request, callback) { 20 | 21 | console.log(`[blockchain] request: ${request.action}`); 22 | console.log(typeof request); 23 | var timeout = 4000; 24 | 25 | //return new Promise(function) 26 | if (request.action === 'create') { 27 | request.id = makeid(); 28 | //invoke.init_asset 29 | chaincode.invoke.init_asset( 30 | [request.description, 31 | request.lastTransaction, 32 | request.user, 33 | request.temperature, 34 | request.id], function (err, res) { 35 | if (!err) { 36 | setTimeout(function () { 37 | console.log(`[blockchain] init_asset() => ${request.description}`); 38 | return reading(request.description, callback); 39 | }, timeout); 40 | } 41 | }); 42 | } else if (request.action === 'transfer') { 43 | //invoke.set_user 44 | chaincode.invoke.set_user( 45 | [request.description, 46 | request.user, 47 | request.temperature], function (err, res) { 48 | if (!err) { 49 | setTimeout(function () { 50 | console.log(`[set_user] set_user() => ${request.description}`); 51 | return reading(request.description, callback); 52 | }, timeout); 53 | } 54 | }); 55 | } else if (request.action === 'read') { 56 | return reading(request.description, callback); 57 | } else { 58 | response = 'function not listed'; 59 | return response; 60 | } 61 | } 62 | 63 | let reading = function query(description, callback) { 64 | chaincode.query.read([description], function (err, res) { 65 | if (!err) response = JSON.parse(res); 66 | //("merchant_id" in thisSession)==false 67 | if (response === undefined) { 68 | console.log(`invoking recursive resource`); 69 | query(description, callback); 70 | return; 71 | } 72 | //console.log(vars`Variables: ${{foo, bar, baz}}`); 73 | delete response.id; 74 | console.log(`[blockchain] read() => ${response.result.message}`); 75 | callback.send(JSON.parse(response.result.message)); 76 | }); 77 | } 78 | 79 | /*function makeid() 80 | *@returns {String} text - random numeric string -id's for assets(temporary way - replace for permanent id's into chaincode) 81 | */ 82 | function makeid() { 83 | var text = ""; 84 | var possible = "0123456789"; 85 | for (var i = 0; i < 10; i++) { 86 | text += + possible.charAt(Math.floor(Math.random() * possible.length)); 87 | } 88 | return text; 89 | } -------------------------------------------------------------------------------- /rest/listener.js: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * This module listen to blockchain events. 4 | * First implementation by Vitor Diego 5 | * 6 | * ************************************/ 7 | 8 | 'use strict' 9 | 10 | const request = require('request-promise'); 11 | var blockdata = {}, chaincode = {}; 12 | 13 | module.exports = function() { 14 | 15 | /********************************************** 16 | * returns:{ 17 | "height": 0, 18 | "currentBlockHash": "string", 19 | "previousBlockHash": "string" 20 | } 21 | ***********************************************/ 22 | function getChain(host, port, callback) { 23 | // console.log("[blackbird] /chain: "); 24 | let url = "https://" + host + ":" + port 25 | var options = { 26 | "method": 'GET', 27 | "url": url + '/chain', 28 | "headers": { 29 | 'Accept': 'application/json', 30 | 'Content-Type': 'application/json' 31 | } 32 | }; 33 | 34 | request(options).then(function(response) { 35 | console.log(`[success] getChain() `); 36 | return callback(JSON.parse(response)); 37 | }).catch(function(err) { 38 | if (err) { 39 | console.log("[err] error getChain()"); 40 | return err; 41 | } 42 | }); 43 | } 44 | 45 | 46 | /********************************************** 47 | * returns:{ 48 | "proposerID": "string", 49 | "timestamp": { 50 | "seconds": 0, 51 | "nanos": 0 52 | }, 53 | "transactions": [ 54 | { 55 | "type": 0, 56 | "chaincodeID": "string", 57 | "payload": "string", 58 | "uuid": "string", 59 | "timestamp": { 60 | "seconds": 0, 61 | "nanos": 0 62 | }, 63 | "confidentialityLevel": "PUBLIC", 64 | "nonce": "string", 65 | "cert": "string", 66 | "signature": "string" 67 | } 68 | ], 69 | "stateHash": "string", 70 | "previousBlockHash": "string", 71 | "consensusMetadata": "string", 72 | "nonHashData": "string" 73 | } 74 | ***********************************************/ 75 | function getChainblocks(host, port, last, callback) { 76 | //console.log("[blackbird] /chain/blocks: " + last); 77 | let url = "https://" + host + ":" + port 78 | var options = { 79 | "method": 'GET', 80 | "url": url + '/chain/blocks/' + last, 81 | "headers": { 82 | 'Accept': 'application/json', 83 | 'Content-Type': 'application/json' 84 | } 85 | }; 86 | 87 | request(options).then(function(response, err) { 88 | console.log(`[success] getChainblocks()`); 89 | return callback(null, JSON.parse(response)); 90 | }).catch(function(err) { 91 | console.log("[err] error getChainblocks() " + err); 92 | return err; 93 | 94 | }); 95 | } 96 | 97 | 98 | /********************************************** 99 | * returns:{ 100 | "type": 0, 101 | "chaincodeID": "string", 102 | "payload": "string", 103 | "uuid": "string", 104 | "timestamp": { 105 | "seconds": 0, 106 | "nanos": 0 107 | }, 108 | "confidentialityLevel": "PUBLIC", 109 | "nonce": "string", 110 | "cert": "string", 111 | "signature": "string" 112 | } 113 | ***********************************************/ 114 | function getTransaction(host, port, uuid, callback) { 115 | //console.log("[blackbird] /transactions: "); 116 | let url = "https://" + host + ":" + port 117 | var options = { 118 | "method": 'GET', 119 | "url": url + '/transactions/' + uuid, 120 | "headers": { 121 | 'Accept': 'application/json', 122 | 'Content-Type': 'application/json' 123 | } 124 | }; 125 | 126 | request(options).then(function(response) { 127 | console.log(`[success] getTransaction()`); 128 | return callback(null, JSON.parse(response)); 129 | }).catch(function(err) { 130 | console.log("[err] error getTransaction() " + err); 131 | return err; 132 | }); 133 | } 134 | 135 | /************************** 136 | * Calls each function sync 137 | * My version for monitor_blockheight -ibc 138 | **************************/ 139 | function getListener(host, port) { 140 | let deployed = false 141 | /*Fetching blockchain data*/ 142 | setInterval(function() { 143 | getChain(host, port, function(chain) { 144 | console.log("[listener] getChain() => height: " + chain.height); 145 | blockdata.currentBlockHash = chain.currentBlockHash; 146 | blockdata.height = chain.height; 147 | getChainblocks(host, port, blockdata.height - 1, function(err, stats) { 148 | if (stats.transactions) { 149 | blockdata.uuid = stats.transactions[0].txid; 150 | blockdata.consensusMetadata = stats.consensusMetadata; 151 | console.log("[listener] getChainblocks() => UUID: " + stats.transactions[0].txid); 152 | getTransaction(host, port, blockdata.uuid, function(err, data) { 153 | console.log("[listener] getTransaction() " + chain.height); 154 | if (!deployed) { 155 | data.uuid = blockdata.uuid; 156 | data.created = data.timestamp.seconds; 157 | console.log(` *___* deployment block: ${data}`); 158 | getDeploymentBlock(chain, stats, data); 159 | deployed = true; 160 | } else if (!err) { 161 | blockdata.type = data.type; 162 | blockdata.created = data.timestamp.seconds; 163 | } else { 164 | console.log(`[listener] error getTransaction() ${err}`); 165 | } 166 | }); 167 | } 168 | }); 169 | }); 170 | 171 | }, 5000); 172 | 173 | /*************************************** 174 | * @returns Object{} - deployment block 175 | * Holding deployment info 176 | **************************************/ 177 | function getDeploymentBlock(chain, stats, data) { 178 | chaincode.currentBlockHash = chain.currentBlockHash; 179 | chaincode.height = chain.height; 180 | chaincode.uuid = data.uuid; 181 | chaincode.consensusMetadata = data.consensusMetadata; 182 | chaincode.type = data.type; 183 | chaincode.created = data.created; 184 | console.log("[getDeploymentBlock] " + JSON.stringify(chaincode)); 185 | } 186 | 187 | } 188 | 189 | let rest = { 190 | getChain, 191 | getChainblocks, 192 | getTransaction, 193 | getListener 194 | } 195 | return rest; 196 | } 197 | 198 | module.exports.deployed = function() { 199 | return chaincode; 200 | } 201 | 202 | module.exports.blockdata = function() { 203 | return blockdata; 204 | } 205 | -------------------------------------------------------------------------------- /routes/events.js: -------------------------------------------------------------------------------- 1 | /** 2 | *Routes to listenner events 3 | */ 4 | 5 | const express = require('express'); 6 | const events = require('../rest/listenner'); 7 | 8 | module.exports = function () { 9 | console.log(`/events middleware running...`); 10 | var app = express.Router(); 11 | 12 | app.get('/', function (req, res, next) { 13 | console.log(`/events middleware ${req.params.id}`); 14 | var response; 15 | if (req.params.id === 1) { 16 | response = events.chaincode; 17 | } else if (req.params.id === 2) { 18 | response = events.blockdata; 19 | } else { 20 | console.log(`invalid parameter!`); 21 | return; 22 | } 23 | res.send(response); 24 | next() 25 | }); 26 | 27 | return app; 28 | } 29 | --------------------------------------------------------------------------------