fixed generation of tx and address relations structure. Improved webapp layout. Not finished addressTree generation algorithm
arnaucode idoctnef@openmailbox.org
Mon, 14 Aug 2017 21:19:12 +0200
16 files changed,
346 insertions(+),
209 deletions(-)
jump to
M
README.md
→
README.md
@@ -2,21 +2,10 @@ # goBlockchainDataAnalysis
blockchain data analysis, written in Go - - - - - - - - - - - ### Install -1. Nodejs & NPM https://nodejs.org/ +1. Nodejs & NPM https://nodejs.org/ --> to serve the web, not necessary if the web files are in a webserver 2. MongoDB https://www.mongodb.com/ -3. Faircoin wallet https://download.faircoin.world/ +3. Faircoin wallet https://download.faircoin.world/, or the Cryptocurrency desired wallet 4. goBlockchainDataAnalysis https://github.com/arnaucode/goBlockchainDataAnalysis ### Configure@@ -54,6 +43,7 @@ 2. Start wallet
``` ./faircoind -txindex -reindex-chainstate ``` +Wait until the entire blockchain is downloaded. 3. Run explorer, to fill the database ```@@ -80,3 +70,18 @@ - MongoDB https://www.mongodb.com/
- Frontend - AngularJS https://angularjs.org/ - Angular-Bootstrap-Material https://tilwinjoy.github.io/angular-bootstrap-material + + +### Some screenshots + + + + + + + + + + + +
M
addressTree.go
→
addressTree.go
@@ -1,6 +1,8 @@
package main import ( + "fmt" + "gopkg.in/mgo.v2/bson" )@@ -19,7 +21,6 @@ //get edges before the address
edges := []EdgeModel{} err = edgeCollection.Find(bson.M{"to": address}).All(&edges) check(err) - for _, e := range edges { if edgeInEdges(network.Edges, e) == false { network.Edges = append(network.Edges, e)@@ -31,6 +32,7 @@ err := nodeCollection.Find(bson.M{"id": }).All(&edges)
check(err) */ + fmt.Println(e.From + " - " + e.To) if e.From != e.To { upNetwork = upTree(e.From, network) for _, upN := range upNetwork.Nodes {
M
dateAnalysis.go
→
dateAnalysis.go
@@ -16,13 +16,13 @@ if err != nil {
panic(err) } tm := time.Unix(i, 0) - fmt.Println(tm) + //fmt.Println(tm) stringDate := tm.String() - fmt.Println(stringDate) + //fmt.Println(stringDate) return stringDate } func hourAnalysis(e EdgeModel, blockTime int64) { - fmt.Println(blockTime) + //fmt.Println(blockTime) date := timeToDate(blockTime) date_hour := strings.Split(date, " ")[1] hour := strings.Split(date_hour, ":")[0]
M
exploreBlockchain.go
→
exploreBlockchain.go
@@ -26,7 +26,7 @@ check(err)
block, err := client.GetBlockVerbose(bh) check(err) - if block.Height > 160 { + if block.Height > 0 { for k, txHash := range block.Tx { if k > 0 { realBlocks++@@ -42,12 +42,25 @@ check(err)
tx, err := client.GetRawTransactionVerbose(th) check(err) + //save Tx + var nTx NodeModel + nTx.Id = txHash + nTx.Label = txHash + nTx.Title = txHash + nTx.Group = strconv.FormatInt(block.Height, 10) + nTx.Value = 1 + nTx.Shape = "square" + nTx.Type = "tx" + saveNode(nodeCollection, nTx) + var originAddresses []string var outputAddresses []string + var outputAmount []float64 for _, Vo := range tx.Vout { //if Vo.Value > 0 { for _, outputAddr := range Vo.ScriptPubKey.Addresses { outputAddresses = append(outputAddresses, outputAddr) + outputAmount = append(outputAmount, Vo.Value) var n2 NodeModel n2.Id = outputAddr n2.Label = outputAddr@@ -55,6 +68,7 @@ n2.Title = outputAddr
n2.Group = strconv.FormatInt(block.Height, 10) n2.Value = 1 n2.Shape = "dot" + n2.Type = "address" saveNode(nodeCollection, n2) } //}@@ -71,25 +85,35 @@ var n1 NodeModel
n1.Id = originAddr n1.Label = originAddr n1.Title = originAddr - n1.Group = string(block.Height) + n1.Group = strconv.FormatInt(block.Height, 10) n1.Value = 1 n1.Shape = "dot" + n1.Type = "address" saveNode(nodeCollection, n1) - for _, outputAddr := range outputAddresses { - var e EdgeModel - e.From = originAddr - e.To = outputAddr - e.Label = txVi.Vout[Vi.Vout].Value - e.Txid = tx.Txid - e.Arrows = "to" - e.BlockHeight = block.Height - saveEdge(edgeCollection, e) + for k, outputAddr := range outputAddresses { + var eIn EdgeModel + eIn.From = originAddr + eIn.To = txHash + eIn.Label = txVi.Vout[Vi.Vout].Value + eIn.Txid = tx.Txid + eIn.Arrows = "to" + eIn.BlockHeight = block.Height + saveEdge(edgeCollection, eIn) + + var eOut EdgeModel + eOut.From = txHash + eOut.To = outputAddr + eOut.Label = outputAmount[k] + eOut.Txid = tx.Txid + eOut.Arrows = "to" + eOut.BlockHeight = block.Height + saveEdge(edgeCollection, eOut) //date analysis //dateAnalysis(e, tx.Time) //hour analysis - hourAnalysis(e, tx.Time) + hourAnalysis(eIn, tx.Time) } } } else {
M
mongoModels.go
→
mongoModels.go
@@ -22,6 +22,7 @@ Title string `json:"title"`
Group string `json:"group"` Value int `json:"value"` Shape string `json:"shape"` + Type string `json:"type"` } type EdgeModel struct {
M
serverRoutes.go
→
serverRoutes.go
@@ -27,6 +27,12 @@ "/alladdresses",
AllAddresses, }, Route{ + "GetLastAddr", + "Get", + "/lastaddr", + GetLastAddr, + }, + Route{ "GetLastTx", "Get", "/lasttx",@@ -93,7 +99,7 @@ check(err)
fmt.Fprintln(w, string(jsonNodes)) } -func GetLastTx(w http.ResponseWriter, r *http.Request) { +func GetLastAddr(w http.ResponseWriter, r *http.Request) { ipFilter(w, r) nodes := []NodeModel{}@@ -106,6 +112,19 @@ check(err)
fmt.Fprintln(w, string(jNodes)) } +func GetLastTx(w http.ResponseWriter, r *http.Request) { + ipFilter(w, r) + + edges := []EdgeModel{} + err := edgeCollection.Find(bson.M{}).Limit(10).Sort("-$natural").All(&edges) + check(err) + + //convert []resp struct to json + jsonData, err := json.Marshal(edges) + check(err) + + fmt.Fprintln(w, string(jsonData)) +} func AddressNetwork(w http.ResponseWriter, r *http.Request) { ipFilter(w, r)@@ -125,7 +144,6 @@ }
} func AddressSankey(w http.ResponseWriter, r *http.Request) { ipFilter(w, r) - vars := mux.Vars(r) address := vars["address"] if address == "undefined" {
A
web/css/style.css
@@ -0,0 +1,39 @@
+#mynetwork { + /*background: black;*/ +} + +.o-height600 { + max-height: 600px!important; +} + +.o-height500 { + max-height: 500px!important; +} + +.o-height300 { + max-height: 300px!important; +} + +.o-overflowScroll { + /*max-height: 600px;*/ + overflow-y: scroll; +} + +.o-mouseoverGrey { + background: white; + cursor: pointer; +} + +.o-mouseoverGrey:hover { + background: #cccccc; +} + + +/* sidebar */ +.o_sidebar a{ + color: white; +} +.o_sidebar a:hover{ + background: #9E9E9E!important; + color: white; +}
M
web/index.html
→
web/index.html
@@ -14,48 +14,25 @@
<link rel="stylesheet" href="bower_components/components-font-awesome/css/font-awesome.min.css"> + <link href="css/style.css" rel="stylesheet"> <link href="css/colors.css" rel="stylesheet"> <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above <link href="css/ionic.app.css" rel="stylesheet"> --> - <style type="text/css"> - #mynetwork { - /*background: black;*/ - } - - .o-height600 { - max-height: 600px!important; - } - - .o-height500 { - max-height: 500px!important; - } - - .o-height300 { - max-height: 300px!important; - } - - .o-overflowScroll { - /*max-height: 600px;*/ - overflow-y: scroll; - } - - .o-mouseoverGrey { - background: white; - cursor: pointer; - } - - .o-mouseoverGrey:hover { - background: #cccccc; - } - </style> </head> -<body ng-app="webApp"> +<body ng-app="webApp" style="overflow-x:scroll;"> <div ng-include="'views/navbar.html'"></div> + <div class="row" style="padding-right:10px;"> + <div class="col-md-2"> + <div ng-include="'views/sidebar.html'"></div> + </div> + <div class="col-md-10"> + <div ng-view></div> + </div> + </div> - <div ng-view></div>
M
web/views/addressNetwork/addressNetwork.html
→
web/views/addressNetwork/addressNetwork.html
@@ -1,29 +1,27 @@
-<div class="container"> - <div class="row"> - <div class="col-sm-3"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">All addresses</h3> +<div class="row"> + <div class="col-sm-3"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">All addresses</h3> + </div> + <div class="panel-body" style="max-height: 500px;overflow-y: scroll;"> + <div class="form-group label-floating"> + <input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text"> </div> - <div class="panel-body" style="max-height: 500px;overflow-y: scroll;"> - <div class="form-group label-floating"> - <input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text"> - </div> - <div ng-click="getAddressNetwork(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress"> - <div class="row-content"> - <p class="list-group-item-text">{{node.id}}</p> + <div ng-click="getAddressNetwork(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress"> + <div class="row-content"> + <p class="list-group-item-text">{{node.id}}</p> - <!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>--> - </div> + <!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>--> </div> </div> </div> - <div class="col-sm-9"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Address history Network Map</h3> - </div> - <div class="panel-body"> - <div id="mynetwork" style="height:800px;"></div> - </div> + </div> + <div class="col-sm-9"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Address history Network Map</h3> + </div> + <div class="panel-body"> + <div id="mynetwork" style="height:800px;"></div> </div> </div> </div>
M
web/views/dateAnalysis/dateAnalysis.html
→
web/views/dateAnalysis/dateAnalysis.html
@@ -1,13 +1,11 @@
-<div class="container"> - <div class="row"> - <div class="col-sm-12"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Tx for each Hour</h3> - </div> - <div class="panel-body"> - <canvas id="bar" class="chart chart-bar" chart-data="data" chart-labels="labels"> +<div class="row"> + <div class="col-md-12"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Tx for each Hour</h3> + </div> + <div class="panel-body"> + <canvas id="bar" class="chart chart-bar" chart-data="data" chart-labels="labels"> </canvas> - </div> </div> </div> </div>
M
web/views/main/main.html
→
web/views/main/main.html
@@ -1,57 +1,75 @@
-<div class="container"> - <div class="row"> - <div class="col-sm-4"> - <div class="panel"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Last addresses</h3> - </div> - <div class="panel-body" style="max-height: 500px;overflow-y: scroll;"> - <div class="list-group-item" ng-repeat="node in addresses"> - <div class="row-content"> - <p class="list-group-item-text">{{node.id}}</p> - </div> +<div class="row"> + <div class="col-sm-4"> + <div class="panel"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Last addresses</h3> + </div> + <div class="panel-body" style="max-height: 300px;overflow-y: scroll;"> + <div class="list-group-item" ng-repeat="node in addresses"> + <div class="row-content"> + <p class="list-group-item-text">{{node.id}}</p> </div> </div> </div> </div> - <div class="col-sm-4"> - <div class="panel"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Last transactions</h3> - </div> - <div class="panel-body" style="max-height: 500px;overflow-y: scroll;"> - <table class="table table-striped table-hover "> - <thead> - <tr> - <th>Hash</th> - <th>From</th> - <th>Date</th> - <th>nºSubtx</th> - <th></th> - </tr> - </thead> - <tbody> - <tr ng-repeat="tx in txs"> - <td> - txhash - </td> - <td>{{tx.f}}</td> - <td>{{tx.date}}</td> - <td>{{tx.subtx.length}}</td> - <td><a ng-href="#!/tx/{{tx.id}}">View</a></td> - </tr> - </tbody> - </table> - </div> + + </div> + <div class="col-sm-4"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Tx/Hour</h3> + </div> + <div class="panel-body"> + <canvas id="line" class="chart chart-line" chart-data="data" chart-labels="labels"> + </canvas> + </div> + </div> + <div class="col-sm-4"> + <div class="panel"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Other</h3> + </div> + <div class="panel-body"> + <canvas id="doughnut" class="chart chart-doughnut" chart-data="data" chart-labels="labels"> + </canvas> </div> </div> - <div class="col-sm-4"> - <div class="panel"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Other</h3> - </div> - <div class="panel-body"> - </div> + </div> +</div> +<div class="row"> + <div class="col-md-12"> + <div class="panel"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Last Tx with amount</h3> + </div> + <div class="panel-body" style="max-height: 350px;overflow-y: scroll;"> + <table class="table table-striped table-hover"> + <colgroup> + <col class="col-md-2"> + <col class="col-md-2"> + <col class="col-md-2"> + <col class="col-md-2"> + <col class="col-md-2"> + <col class="col-md-2"> + </colgroup> + <thead> + <tr> + <th>BlockHeight</th> + <th>From</th> + <th>To</th> + <th>Amount</th> + <th></th> + </tr> + </thead> + <tbody> + <tr ng-repeat="tx in txs"> + <td>{{tx.blockheight}}</td> + <td style="max-width:100px;overflow-x:hidden;">{{tx.from}}</td> + <td style="max-width:100px;overflow-x:hidden;">{{tx.to}}</td> + <td>{{tx.label}}</td> + <td><a ng-href="#!/tx/{{tx.id}}">View</a></td> + </tr> + </tbody> + </table> </div> </div> </div>
M
web/views/main/main.js
→
web/views/main/main.js
@@ -2,22 +2,49 @@ 'use strict';
angular.module('app.main', ['ngRoute']) -.config(['$routeProvider', function($routeProvider) { - $routeProvider.when('/main', { - templateUrl: 'views/main/main.html', - controller: 'MainCtrl' - }); -}]) + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/main', { + templateUrl: 'views/main/main.html', + controller: 'MainCtrl' + }); + }]) + + .controller('MainCtrl', function($scope, $http) { + //last addr + $scope.addresses = []; + $http.get(urlapi + 'lastaddr') + .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'); + }); + + //last tx + $scope.txs = []; + $http.get(urlapi + 'lasttx') + .then(function(data, status, headers, config) { + console.log('data success'); + console.log(data); + + $scope.txs = data.data; + }, function(data, status, headers, config) { + console.log('data error'); + }); -.controller('MainCtrl', function($scope, $http) { - $scope.addresses = []; - $http.get(urlapi + 'lasttx') - .then(function(data, status, headers, config) { - console.log('data success'); - console.log(data); + //date analysis + $scope.data = []; + $scope.labels = []; + $http.get(urlapi + 'houranalysis') + .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.data = data.data.data; + $scope.labels = data.data.labels; + }, function(data, status, headers, config) { + console.log('data error'); + }); + });
M
web/views/network/network.html
→
web/views/network/network.html
@@ -1,32 +1,30 @@
-<div class="container"> - <div class="row"> - <div class="col-sm-3"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Nodes</h3> - </div> - <div class="panel-body" style="max-height: 300px;overflow-y: scroll;"> - <div ng-click="focusNode(node)" class="list-group-item" ng-repeat="node in nodes"> - <div class="row-content"> - <p class="list-group-item-text">{{node.id}}</p> +<div class="row"> + <div class="col-sm-3"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Nodes</h3> + </div> + <div class="panel-body" style="max-height: 300px;overflow-y: scroll;"> + <div ng-click="focusNode(node)" class="list-group-item" ng-repeat="node in nodes"> + <div class="row-content"> + <p class="list-group-item-text">{{node.id}}</p> - <!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>--> - </div> + <!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>--> </div> </div> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Selected node</h3> - </div> - <div class="panel-body" style="max-height: 200px;overflow-y: scroll;"> - {{selectedNode.nodes}} - </div> </div> - <div class="col-sm-9"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Network</h3> - </div> - <div class="panel-body"> - <div id="mynetwork" style="height:500px;"></div> - </div> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Selected node</h3> + </div> + <div class="panel-body" style="max-height: 200px;overflow-y: scroll;"> + {{selectedNode.nodes}} + </div> + </div> + <div class="col-sm-9"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Network</h3> + </div> + <div class="panel-body"> + <div id="mynetwork" style="height:500px;"></div> </div> </div> </div>
M
web/views/sankey/sankey.html
→
web/views/sankey/sankey.html
@@ -1,33 +1,31 @@
-<div class="container"> - <div class="row"> - <div class="col-sm-2"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">All addresses</h3> +<div class="row"> + <div class="col-sm-2"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">All addresses</h3> + </div> + <div class="panel-body" style="max-height: 500px;overflow-y: scroll;"> + <div class="form-group label-floating"> + <input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text"> </div> - <div class="panel-body" style="max-height: 500px;overflow-y: scroll;"> - <div class="form-group label-floating"> - <input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text"> - </div> - <div ng-click="getAddressSankey(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress"> - <div class="row-content"> - <p class="list-group-item-text">{{node.id}}</p> + <div ng-click="getAddressSankey(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress"> + <div class="row-content"> + <p class="list-group-item-text">{{node.id}}</p> - <!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>--> - </div> + <!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>--> </div> </div> </div> - <div class="col-sm-10"> - <div class="panel-heading c_blueGrey300"> - <h3 class="panel-title">Sankey - address {{selectedAddress}}</h3> - </div> - <div class="panel-body"> - <!--<ng-sankey id="sankeyChart" options="options" data="data"></ng-sankey> + </div> + <div class="col-sm-8"> + <div class="panel-heading c_blueGrey300"> + <h3 class="panel-title">Sankey - address {{selectedAddress}}</h3> + </div> + <div class="panel-body"> + <!--<ng-sankey id="sankeyChart" options="options" data="data"></ng-sankey> --> - <div id="sankeyChart"> - <canvas></canvas> - <svg></svg> - </div> + <div id="sankeyChart"> + <canvas></canvas> + <svg></svg> </div> </div> </div>