mirror of
https://github.com/arnaucube/goBlockchainDataAnalysis.git
synced 2026-02-07 03:36:44 +01:00
date and hour analysis added
This commit is contained in:
64
dateAnalysis.go
Normal file
64
dateAnalysis.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func timeToDate(blockTime int64) string {
|
||||||
|
stringTime := strconv.FormatInt(blockTime, 10)
|
||||||
|
i, err := strconv.ParseInt(stringTime, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
tm := time.Unix(i, 0)
|
||||||
|
fmt.Println(tm)
|
||||||
|
stringDate := tm.String()
|
||||||
|
fmt.Println(stringDate)
|
||||||
|
return stringDate
|
||||||
|
}
|
||||||
|
func hourAnalysis(e EdgeModel, blockTime int64) {
|
||||||
|
fmt.Println(blockTime)
|
||||||
|
date := timeToDate(blockTime)
|
||||||
|
date_hour := strings.Split(date, " ")[1]
|
||||||
|
hour := strings.Split(date_hour, ":")[0]
|
||||||
|
|
||||||
|
hourCount := HourCountModel{}
|
||||||
|
err := hourCountCollection.Find(bson.M{"hour": hour}).One(&hourCount)
|
||||||
|
if err != nil {
|
||||||
|
//date not yet in DB
|
||||||
|
var hourCount HourCountModel
|
||||||
|
hourCount.Hour = hour
|
||||||
|
hourCount.Count = 1
|
||||||
|
err = hourCountCollection.Insert(hourCount)
|
||||||
|
check(err)
|
||||||
|
} else {
|
||||||
|
hourCount.Count++
|
||||||
|
err = hourCountCollection.Update(bson.M{"hour": hour}, &hourCount)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func dateAnalysis(e EdgeModel, blockTime int64) {
|
||||||
|
fmt.Println(blockTime)
|
||||||
|
date := timeToDate(blockTime)
|
||||||
|
|
||||||
|
dateCount := DateCountModel{}
|
||||||
|
err := dateCountCollection.Find(bson.M{"date": date}).One(&dateCount)
|
||||||
|
if err != nil {
|
||||||
|
//date not yet in DB
|
||||||
|
var dateCount DateCountModel
|
||||||
|
dateCount.Date = date
|
||||||
|
dateCount.Time = blockTime
|
||||||
|
dateCount.Count = 1
|
||||||
|
err = dateCountCollection.Insert(dateCount)
|
||||||
|
check(err)
|
||||||
|
} else {
|
||||||
|
dateCount.Count++
|
||||||
|
err = dateCountCollection.Update(bson.M{"date": date}, &dateCount)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,80 +26,84 @@ func explore(client *btcrpcclient.Client, blockHash string) {
|
|||||||
block, err := client.GetBlockVerbose(bh)
|
block, err := client.GetBlockVerbose(bh)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
//if len(block.Tx) < 10 {
|
if block.Height > 160 {
|
||||||
for k, txHash := range block.Tx {
|
for k, txHash := range block.Tx {
|
||||||
if k > 0 {
|
if k > 0 {
|
||||||
realBlocks++
|
realBlocks++
|
||||||
fmt.Print("Block Height: ")
|
fmt.Print("Block Height: ")
|
||||||
fmt.Print(block.Height)
|
fmt.Print(block.Height)
|
||||||
fmt.Print(", num of Tx: ")
|
fmt.Print(", num of Tx: ")
|
||||||
fmt.Print(k)
|
fmt.Print(k)
|
||||||
fmt.Print("/")
|
fmt.Print("/")
|
||||||
fmt.Println(len(block.Tx) - 1)
|
fmt.Println(len(block.Tx) - 1)
|
||||||
|
|
||||||
th, err := chainhash.NewHashFromStr(txHash)
|
th, err := chainhash.NewHashFromStr(txHash)
|
||||||
check(err)
|
|
||||||
tx, err := client.GetRawTransactionVerbose(th)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
var originAddresses []string
|
|
||||||
var outputAddresses []string
|
|
||||||
for _, Vo := range tx.Vout {
|
|
||||||
//if Vo.Value > 0 {
|
|
||||||
for _, outputAddr := range Vo.ScriptPubKey.Addresses {
|
|
||||||
outputAddresses = append(outputAddresses, outputAddr)
|
|
||||||
var n2 NodeModel
|
|
||||||
n2.Id = outputAddr
|
|
||||||
n2.Label = outputAddr
|
|
||||||
n2.Title = outputAddr
|
|
||||||
n2.Group = strconv.FormatInt(block.Height, 10)
|
|
||||||
n2.Value = 1
|
|
||||||
n2.Shape = "dot"
|
|
||||||
saveNode(nodeCollection, n2)
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
for _, Vi := range tx.Vin {
|
|
||||||
th, err := chainhash.NewHashFromStr(Vi.Txid)
|
|
||||||
check(err)
|
check(err)
|
||||||
txVi, err := client.GetRawTransactionVerbose(th)
|
tx, err := client.GetRawTransactionVerbose(th)
|
||||||
check(err)
|
check(err)
|
||||||
if len(txVi.Vout[Vi.Vout].ScriptPubKey.Addresses) > 0 {
|
|
||||||
for _, originAddr := range txVi.Vout[Vi.Vout].ScriptPubKey.Addresses {
|
|
||||||
originAddresses = append(originAddresses, originAddr)
|
|
||||||
var n1 NodeModel
|
|
||||||
n1.Id = originAddr
|
|
||||||
n1.Label = originAddr
|
|
||||||
n1.Title = originAddr
|
|
||||||
n1.Group = string(block.Height)
|
|
||||||
n1.Value = 1
|
|
||||||
n1.Shape = "dot"
|
|
||||||
saveNode(nodeCollection, n1)
|
|
||||||
|
|
||||||
for _, outputAddr := range outputAddresses {
|
var originAddresses []string
|
||||||
var e EdgeModel
|
var outputAddresses []string
|
||||||
e.From = originAddr
|
for _, Vo := range tx.Vout {
|
||||||
e.To = outputAddr
|
//if Vo.Value > 0 {
|
||||||
e.Label = txVi.Vout[Vi.Vout].Value
|
for _, outputAddr := range Vo.ScriptPubKey.Addresses {
|
||||||
e.Txid = tx.Txid
|
outputAddresses = append(outputAddresses, outputAddr)
|
||||||
e.Arrows = "to"
|
var n2 NodeModel
|
||||||
e.BlockHeight = block.Height
|
n2.Id = outputAddr
|
||||||
saveEdge(edgeCollection, e)
|
n2.Label = outputAddr
|
||||||
//fmt.Println(e)
|
n2.Title = outputAddr
|
||||||
}
|
n2.Group = strconv.FormatInt(block.Height, 10)
|
||||||
|
n2.Value = 1
|
||||||
|
n2.Shape = "dot"
|
||||||
|
saveNode(nodeCollection, n2)
|
||||||
}
|
}
|
||||||
} else {
|
//}
|
||||||
originAddresses = append(originAddresses, "origin")
|
|
||||||
}
|
}
|
||||||
|
for _, Vi := range tx.Vin {
|
||||||
|
th, err := chainhash.NewHashFromStr(Vi.Txid)
|
||||||
|
check(err)
|
||||||
|
txVi, err := client.GetRawTransactionVerbose(th)
|
||||||
|
check(err)
|
||||||
|
if len(txVi.Vout[Vi.Vout].ScriptPubKey.Addresses) > 0 {
|
||||||
|
for _, originAddr := range txVi.Vout[Vi.Vout].ScriptPubKey.Addresses {
|
||||||
|
originAddresses = append(originAddresses, originAddr)
|
||||||
|
var n1 NodeModel
|
||||||
|
n1.Id = originAddr
|
||||||
|
n1.Label = originAddr
|
||||||
|
n1.Title = originAddr
|
||||||
|
n1.Group = string(block.Height)
|
||||||
|
n1.Value = 1
|
||||||
|
n1.Shape = "dot"
|
||||||
|
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)
|
||||||
|
|
||||||
|
//date analysis
|
||||||
|
//dateAnalysis(e, tx.Time)
|
||||||
|
//hour analysis
|
||||||
|
hourAnalysis(e, tx.Time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
originAddresses = append(originAddresses, "origin")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fmt.Print("originAddresses: ")
|
||||||
|
fmt.Println(len(originAddresses))
|
||||||
|
fmt.Print("outputAddresses: ")
|
||||||
|
fmt.Println(len(outputAddresses))
|
||||||
}
|
}
|
||||||
fmt.Print("originAddresses: ")
|
|
||||||
fmt.Println(len(originAddresses))
|
|
||||||
fmt.Print("outputAddresses: ")
|
|
||||||
fmt.Println(len(outputAddresses))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
//set the next block
|
//set the next block
|
||||||
blockHash = block.NextHash
|
blockHash = block.NextHash
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 MiB |
BIN
goBlockchainDataAnalysis04.png
Normal file
BIN
goBlockchainDataAnalysis04.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
4
main.go
4
main.go
@@ -16,6 +16,8 @@ import (
|
|||||||
var blockCollection *mgo.Collection
|
var blockCollection *mgo.Collection
|
||||||
var nodeCollection *mgo.Collection
|
var nodeCollection *mgo.Collection
|
||||||
var edgeCollection *mgo.Collection
|
var edgeCollection *mgo.Collection
|
||||||
|
var dateCountCollection *mgo.Collection
|
||||||
|
var hourCountCollection *mgo.Collection
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//read goBlockchainDataAbalysis config
|
//read goBlockchainDataAbalysis config
|
||||||
@@ -28,6 +30,8 @@ func main() {
|
|||||||
blockCollection = getCollection(session, "blocks")
|
blockCollection = getCollection(session, "blocks")
|
||||||
nodeCollection = getCollection(session, "nodes")
|
nodeCollection = getCollection(session, "nodes")
|
||||||
edgeCollection = getCollection(session, "edges")
|
edgeCollection = getCollection(session, "edges")
|
||||||
|
dateCountCollection = getCollection(session, "dateCounts")
|
||||||
|
hourCountCollection = getCollection(session, "hourCounts")
|
||||||
|
|
||||||
// create new client instance
|
// create new client instance
|
||||||
client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{
|
client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{
|
||||||
|
|||||||
@@ -53,3 +53,17 @@ type SankeyModel struct {
|
|||||||
Nodes []SankeyNodeModel `json:"nodes"`
|
Nodes []SankeyNodeModel `json:"nodes"`
|
||||||
Links []SankeyLinkModel `json:"links"`
|
Links []SankeyLinkModel `json:"links"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HourCountModel struct {
|
||||||
|
Hour string `json:"hour"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
type HourAnalysisResp struct {
|
||||||
|
Labels []string `json:"labels"`
|
||||||
|
Data []int `json:"data"`
|
||||||
|
}
|
||||||
|
type DateCountModel struct {
|
||||||
|
Time int64 `json:"time"`
|
||||||
|
Date string `json:"date"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
|
||||||
@@ -43,6 +44,12 @@ var routes = Routes{
|
|||||||
"/map",
|
"/map",
|
||||||
NetworkMap,
|
NetworkMap,
|
||||||
},
|
},
|
||||||
|
Route{
|
||||||
|
"GetHourAnalysis",
|
||||||
|
"Get",
|
||||||
|
"/houranalysis",
|
||||||
|
GetHourAnalysis,
|
||||||
|
},
|
||||||
/*
|
/*
|
||||||
Route{
|
Route{
|
||||||
"SelectItem",
|
"SelectItem",
|
||||||
@@ -200,3 +207,26 @@ func SelectItem(w http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintln(w, "user: "+userid+", selects item: "+itemid)
|
fmt.Fprintln(w, "user: "+userid+", selects item: "+itemid)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
func GetHourAnalysis(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ipFilter(w, r)
|
||||||
|
|
||||||
|
hourAnalysis := []HourCountModel{}
|
||||||
|
iter := hourCountCollection.Find(bson.M{}).Limit(10000).Iter()
|
||||||
|
err := iter.All(&hourAnalysis)
|
||||||
|
|
||||||
|
//sort by hour
|
||||||
|
sort.Slice(hourAnalysis, func(i, j int) bool {
|
||||||
|
return hourAnalysis[i].Hour < hourAnalysis[j].Hour
|
||||||
|
})
|
||||||
|
|
||||||
|
var resp HourAnalysisResp
|
||||||
|
for _, d := range hourAnalysis {
|
||||||
|
resp.Labels = append(resp.Labels, d.Hour)
|
||||||
|
resp.Data = append(resp.Data, d.Count)
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert []resp struct to json
|
||||||
|
jsonResp, err := json.Marshal(resp)
|
||||||
|
check(err)
|
||||||
|
fmt.Fprintln(w, string(jsonResp))
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ angular.module('webApp', [
|
|||||||
'app.main',
|
'app.main',
|
||||||
'app.network',
|
'app.network',
|
||||||
'app.addressNetwork',
|
'app.addressNetwork',
|
||||||
'app.sankey'
|
'app.sankey',
|
||||||
|
'app.dateAnalysis'
|
||||||
]).
|
]).
|
||||||
config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
|
config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
|
||||||
$locationProvider.hashPrefix('!');
|
$locationProvider.hashPrefix('!');
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
<script src="views/network/network.js"></script>
|
<script src="views/network/network.js"></script>
|
||||||
<script src="views/addressNetwork/addressNetwork.js"></script>
|
<script src="views/addressNetwork/addressNetwork.js"></script>
|
||||||
<script src="views/sankey/sankey.js"></script>
|
<script src="views/sankey/sankey.js"></script>
|
||||||
|
<script src="views/dateAnalysis/dateAnalysis.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
13
web/views/dateAnalysis/dateAnalysis.html
Normal file
13
web/views/dateAnalysis/dateAnalysis.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<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">
|
||||||
|
</canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
27
web/views/dateAnalysis/dateAnalysis.js
Normal file
27
web/views/dateAnalysis/dateAnalysis.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('app.dateAnalysis', ['ngRoute', 'chart.js'])
|
||||||
|
|
||||||
|
.config(['$routeProvider', function($routeProvider) {
|
||||||
|
$routeProvider.when('/dateAnalysis', {
|
||||||
|
templateUrl: 'views/dateAnalysis/dateAnalysis.html',
|
||||||
|
controller: 'DateAnalysisCtrl'
|
||||||
|
});
|
||||||
|
}])
|
||||||
|
|
||||||
|
.controller('DateAnalysisCtrl', function($scope, $http, $routeParams) {
|
||||||
|
$scope.data=[];
|
||||||
|
$scope.labels=[];
|
||||||
|
|
||||||
|
$http.get(urlapi + 'houranalysis')
|
||||||
|
.then(function(data, status, headers, config) {
|
||||||
|
console.log('data success');
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
$scope.data = data.data.data;
|
||||||
|
$scope.labels=data.data.labels;
|
||||||
|
}, function(data, status, headers, config) {
|
||||||
|
console.log('data error');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -11,9 +11,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="navbar-collapse collapse navbar-responsive-collapse">
|
<div class="navbar-collapse collapse navbar-responsive-collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li class="active"><a href="#!/network">Network</a></li>
|
<li><a href="#!/network">Network</a></li>
|
||||||
<li><a href="#!/addressNetwork">Address Network</a></li>
|
<li><a href="#!/addressNetwork">Address Network</a></li>
|
||||||
<li><a href="#!/sankey">Sankey diagram</a></li>
|
<li><a href="#!/sankey">Sankey diagram</a></li>
|
||||||
|
<li class="active"><a href="#!/dateAnalysis">Date Analysis</a></li>
|
||||||
<li><a href="javascript:void(0)">Timeline</a></li>
|
<li><a href="javascript:void(0)">Timeline</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<form class="navbar-form navbar-left">
|
<form class="navbar-form navbar-left">
|
||||||
|
|||||||
@@ -22,7 +22,12 @@
|
|||||||
<h3 class="panel-title">Sankey</h3>
|
<h3 class="panel-title">Sankey</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<ng-sankey id="sankeyChart" options="options" data="data"></ng-sankey>
|
<!--<ng-sankey id="sankeyChart" options="options" data="data"></ng-sankey>
|
||||||
|
-->
|
||||||
|
<div id="sankeyChart">
|
||||||
|
<canvas></canvas>
|
||||||
|
<svg></svg>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user