diff --git a/dateAnalysis.go b/dateAnalysis.go new file mode 100644 index 0000000..d633203 --- /dev/null +++ b/dateAnalysis.go @@ -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) + } +} diff --git a/exploreBlockchain.go b/exploreBlockchain.go index 7caf7cc..8057aa9 100644 --- a/exploreBlockchain.go +++ b/exploreBlockchain.go @@ -26,80 +26,84 @@ func explore(client *btcrpcclient.Client, blockHash string) { block, err := client.GetBlockVerbose(bh) check(err) - //if len(block.Tx) < 10 { - for k, txHash := range block.Tx { - if k > 0 { - realBlocks++ - fmt.Print("Block Height: ") - fmt.Print(block.Height) - fmt.Print(", num of Tx: ") - fmt.Print(k) - fmt.Print("/") - fmt.Println(len(block.Tx) - 1) + if block.Height > 160 { + for k, txHash := range block.Tx { + if k > 0 { + realBlocks++ + fmt.Print("Block Height: ") + fmt.Print(block.Height) + fmt.Print(", num of Tx: ") + fmt.Print(k) + fmt.Print("/") + fmt.Println(len(block.Tx) - 1) - 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) + th, err := chainhash.NewHashFromStr(txHash) check(err) - txVi, err := client.GetRawTransactionVerbose(th) + tx, 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) - //fmt.Println(e) - } + 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) } - } 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 blockHash = block.NextHash } diff --git a/goBlockchainDataAbalysis.gif b/goBlockchainDataAbalysis.gif deleted file mode 100644 index e322fc2..0000000 Binary files a/goBlockchainDataAbalysis.gif and /dev/null differ diff --git a/goBlockchainDataAnalysis04.png b/goBlockchainDataAnalysis04.png new file mode 100644 index 0000000..a62c4f8 Binary files /dev/null and b/goBlockchainDataAnalysis04.png differ diff --git a/main.go b/main.go index a067a59..8b5d156 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,8 @@ import ( var blockCollection *mgo.Collection var nodeCollection *mgo.Collection var edgeCollection *mgo.Collection +var dateCountCollection *mgo.Collection +var hourCountCollection *mgo.Collection func main() { //read goBlockchainDataAbalysis config @@ -28,6 +30,8 @@ func main() { blockCollection = getCollection(session, "blocks") nodeCollection = getCollection(session, "nodes") edgeCollection = getCollection(session, "edges") + dateCountCollection = getCollection(session, "dateCounts") + hourCountCollection = getCollection(session, "hourCounts") // create new client instance client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{ diff --git a/mongoModels.go b/mongoModels.go index 8964092..c4f79fb 100644 --- a/mongoModels.go +++ b/mongoModels.go @@ -53,3 +53,17 @@ type SankeyModel struct { Nodes []SankeyNodeModel `json:"nodes"` 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"` +} diff --git a/serverRoutes.go b/serverRoutes.go index 9987b70..28734ad 100644 --- a/serverRoutes.go +++ b/serverRoutes.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "sort" "gopkg.in/mgo.v2/bson" @@ -43,6 +44,12 @@ var routes = Routes{ "/map", NetworkMap, }, + Route{ + "GetHourAnalysis", + "Get", + "/houranalysis", + GetHourAnalysis, + }, /* Route{ "SelectItem", @@ -200,3 +207,26 @@ func SelectItem(w http.ResponseWriter, r *http.Request) { 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)) +} diff --git a/web/app.js b/web/app.js index c940c2b..8b27851 100644 --- a/web/app.js +++ b/web/app.js @@ -12,7 +12,8 @@ angular.module('webApp', [ 'app.main', 'app.network', 'app.addressNetwork', - 'app.sankey' + 'app.sankey', + 'app.dateAnalysis' ]). config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { $locationProvider.hashPrefix('!'); diff --git a/web/index.html b/web/index.html index a6d06e4..8fe287d 100644 --- a/web/index.html +++ b/web/index.html @@ -95,6 +95,7 @@ + diff --git a/web/views/dateAnalysis/dateAnalysis.html b/web/views/dateAnalysis/dateAnalysis.html new file mode 100644 index 0000000..a03f74b --- /dev/null +++ b/web/views/dateAnalysis/dateAnalysis.html @@ -0,0 +1,13 @@ +
+
+
+
+

Tx for each Hour

+
+
+ + +
+
+
+
diff --git a/web/views/dateAnalysis/dateAnalysis.js b/web/views/dateAnalysis/dateAnalysis.js new file mode 100644 index 0000000..d25f58c --- /dev/null +++ b/web/views/dateAnalysis/dateAnalysis.js @@ -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'); + }); + + }); diff --git a/web/views/navbar.html b/web/views/navbar.html index 594b4aa..a171768 100644 --- a/web/views/navbar.html +++ b/web/views/navbar.html @@ -11,9 +11,10 @@
- + +
+ + +