diff --git a/.gitignore b/.gitignore index 57f3879..eb614c3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /*.conf /*.json +*.mp4 diff --git a/README.md b/README.md index 277ec67..87fd807 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,70 @@ # goBlockchainDataAnalysis blockchain data analysis, written in Go +### Install +1. Nodejs & NPM https://nodejs.org/ +2. MongoDB https://www.mongodb.com/ +3. Faircoin wallet https://download.faircoin.world/ +4. goBlockchainDataAnalysis https://github.com/arnaucode/goBlockchainDataAnalysis +### Configure +- Wallet /home/user/.faircoin2/faircoin.conf: +``` +rpcuser=usernamerpc +rpcpassword=password +rpcport=3021 +rpcworkqueue=2000 +server=1 +rpcbind=127.0.0.1 +rpcallowip=127.0.0.1 +``` + +- goBlockchainDataAnalysis/config.json: +```json +{ + "user": "usernamerpc", + "pass": "password", + "host": "127.0.0.1", + "port": "3021", + "genesisTx": "7c27ade2c28e67ed3077f8f77b8ea6d36d4f5eba04c099be3c9faa9a4a04c046", + "genesisBlock": "beed44fa5e96150d95d56ebd5d2625781825a9407a5215dd7eda723373a0a1d7" +} +``` + +### Run -## Run +1. Start MongoDB +``` +sudo service mongod start +``` + +2. Start wallet +``` +./faircoind -txindex -reindex-chainstate +``` -- First run explorer +3. Run explorer, to fill the database ``` ./goBlockchainDataAnalysis -explore ``` + + 3.1. The next runs, once the database have data, can just run: +``` +./goBlockchainDataAnalysis +``` + +4. Run the webserver, in the /web directory +``` +npm start +``` +Webapp will run on 127.0.0.1:8080 + + + +### Additional info +- Backend + - Go lang https://golang.org/ + - MongoDB https://www.mongodb.com/ +- Frontend + - AngularJS https://angularjs.org/ + - Angular-Bootstrap-Material https://tilwinjoy.github.io/angular-bootstrap-material diff --git a/goBlockchainDataAbalysis.gif b/goBlockchainDataAbalysis.gif new file mode 100644 index 0000000..e322fc2 Binary files /dev/null and b/goBlockchainDataAbalysis.gif differ diff --git a/goBlockchainDataAnalysis01.png b/goBlockchainDataAnalysis01.png new file mode 100644 index 0000000..a0a81b2 Binary files /dev/null and b/goBlockchainDataAnalysis01.png differ diff --git a/goBlockchainDataAnalysis02.png b/goBlockchainDataAnalysis02.png new file mode 100644 index 0000000..56dc4e5 Binary files /dev/null and b/goBlockchainDataAnalysis02.png differ diff --git a/mongoModels.go b/mongoModels.go index f14642d..8964092 100644 --- a/mongoModels.go +++ b/mongoModels.go @@ -28,7 +28,7 @@ type EdgeModel struct { Txid string `json:"txid"` From string `json:"from"` To string `json:"to"` - Label float64 `json:"label"` + Label float64 `json:"label"` //the value of transaction Arrows string `json:"arrows"` BlockHeight int64 `json:"blockheight"` } @@ -36,3 +36,20 @@ type NetworkModel struct { Nodes []NodeModel `json:"nodes"` Edges []EdgeModel `json:"edges"` } + +type SankeyNodeModel struct { + //StringNode string `json:"stringnode"` + Node int `json:"node"` + Name string `json:"name"` +} +type SankeyLinkModel struct { + //StringSource string `json:"stringsource"` + Source int `json:"source"` + //StringTarget string `json:"stringtarget"` + Target int `json:"target"` + Value float64 `json:"value"` +} +type SankeyModel struct { + Nodes []SankeyNodeModel `json:"nodes"` + Links []SankeyLinkModel `json:"links"` +} diff --git a/serverRoutes.go b/serverRoutes.go index 2a0dcee..9987b70 100644 --- a/serverRoutes.go +++ b/serverRoutes.go @@ -31,6 +31,12 @@ var routes = Routes{ "/address/network/{address}", AddressNetwork, }, + Route{ + "AddressSankey", + "GET", + "/address/sankey/{address}", + AddressSankey, + }, Route{ "NetworkMap", "Get", @@ -99,6 +105,45 @@ func AddressNetwork(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, string(jNetwork)) } } +func AddressSankey(w http.ResponseWriter, r *http.Request) { + ipFilter(w, r) + + vars := mux.Vars(r) + address := vars["address"] + if address == "undefined" { + fmt.Fprintln(w, "not valid address") + } else { + network := addressTree(address) + var sankey SankeyModel + + fmt.Println("network generated") + mapNodeK := make(map[string]int) + for k, n := range network.Nodes { + var sankeyNode SankeyNodeModel + //sankeyNode.StringNode = n.Id + sankeyNode.Node = k + sankeyNode.Name = n.Id + sankey.Nodes = append(sankey.Nodes, sankeyNode) + mapNodeK[n.Id] = k + } + for _, e := range network.Edges { + var sankeyLink SankeyLinkModel + //sankeyLink.StringSource = e.From + sankeyLink.Source = mapNodeK[e.From] + //sankeyLink.StringTarget = e.To + sankeyLink.Target = mapNodeK[e.To] + sankeyLink.Value = e.Label + sankey.Links = append(sankey.Links, sankeyLink) + } + fmt.Println("Sankey generated") + + //convert []resp struct to json + jsonSankey, err := json.Marshal(sankey) + check(err) + + fmt.Fprintln(w, string(jsonSankey)) + } +} func NetworkMap(w http.ResponseWriter, r *http.Request) { ipFilter(w, r) diff --git a/web/bower.json b/web/bower.json index 6f06acd..7ebcd36 100644 --- a/web/bower.json +++ b/web/bower.json @@ -1,19 +1,19 @@ { - "name": "goBlockchainDataAnalysis", - "description": "goBlockchainDataAnalysis", - "version": "0.0.0", - "homepage": "https://github.com/arnaucode/goBlockchainDataAnalysis", - "license": "MIT", - "private": true, - "dependencies": { - "angular": "^1.6.2", - "angular-route": "^1.6.1", - "angular-chart.js": "^1.1.1", - "vis": "^4.18.1", - "mui": "^0.9.20", - "angular-bootstrap-material": "abm#^0.1.4", - "angular-bootstrap": "^2.5.0", - "angular-messages": "^1.6.5", - "components-font-awesome": "^4.7.0" - } + "name": "goBlockchainDataAnalysis", + "description": "goBlockchainDataAnalysis", + "version": "0.0.0", + "homepage": "https://github.com/arnaucode/goBlockchainDataAnalysis", + "license": "MIT", + "private": true, + "dependencies": { + "angular": "^1.6.2", + "angular-route": "^1.6.1", + "angular-chart.js": "^1.1.1", + "vis": "^4.18.1", + "angular-bootstrap-material": "abm#^0.1.4", + "angular-bootstrap": "^2.5.0", + "angular-messages": "^1.6.5", + "components-font-awesome": "^4.7.0", + "sankeyjs": "^1.2.2" + } } diff --git a/web/index.html b/web/index.html index 60abf90..a6d06e4 100644 --- a/web/index.html +++ b/web/index.html @@ -77,6 +77,10 @@ + + + + diff --git a/web/views/addressNetwork/addressNetwork.html b/web/views/addressNetwork/addressNetwork.html index df6d7b0..398a287 100644 --- a/web/views/addressNetwork/addressNetwork.html +++ b/web/views/addressNetwork/addressNetwork.html @@ -19,7 +19,7 @@
-

Network

+

Address history Network Map

diff --git a/web/views/sankey/sankey.html b/web/views/sankey/sankey.html index 1b623f0..bb7ffd8 100644 --- a/web/views/sankey/sankey.html +++ b/web/views/sankey/sankey.html @@ -1,11 +1,28 @@
-
+
+
+

All addresses

+
+
+
+ +
+
+
+

{{node.id}}

+ + +
+
+
+
+

Sankey

- +
diff --git a/web/views/sankey/sankey.js b/web/views/sankey/sankey.js index ee2bb77..8be33f3 100644 --- a/web/views/sankey/sankey.js +++ b/web/views/sankey/sankey.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('app.sankey', ['ngRoute']) +angular.module('app.sankey', ['ngRoute', 'ngSankey']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/sankey', { @@ -10,6 +10,43 @@ angular.module('app.sankey', ['ngRoute']) }]) .controller('SankeyCtrl', function($scope, $http, $routeParams) { - + $scope.options = { + chart: '#sankeyChart', + width: 960, + height: 500, + margin: {top: 1, right: 1, bottom: 6, left: 1}, + node: {width: 15, padding :10, showValue: false}, + value: {format: ',.0f', unit : ''}, + dynamicLinkColor: true, + trafficInLinks: true + }; + $scope.data={ + nodes: [], + links: [] + }; + + $http.get(urlapi + 'alladdresses') + .then(function(data, status, headers, config) { + console.log('data success'); + console.log(data); + $scope.addresses = data.data; + }, function(data, status, headers, config) { + console.log('data error'); + }); + $scope.getAddressSankey = function(address) { + console.log(address); + $http.get(urlapi + 'address/sankey/' + address.id) + .then(function(data, status, headers, config) { + console.log('data success'); + console.log(data); + $scope.data.nodes = data.data.nodes; + $scope.data.links = data.data.links; + console.log($scope.data); + let chart = new d3.sankeyChart(data.data, $scope.options); + //$scope.data = data.data; + }, function(data, status, headers, config) { + console.log('data error'); + }); + }; });