mirror of
https://github.com/arnaucube/goBlockchainDataAnalysis.git
synced 2026-02-07 03:36:44 +01:00
updated to new version of btcsuite. Implemented blockchain stats on exploring blockchain, and show it in frontend
This commit is contained in:
@@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
## ToDo list
|
## ToDo list
|
||||||
|
|
||||||
- Sankey generation without loops
|
|
||||||
|
|
||||||
- Backend
|
- Backend
|
||||||
- Network Address generation avoiding infinite relation loops
|
|
||||||
- Sankey Address generation without loops
|
- Sankey Address generation without loops
|
||||||
- Frontend
|
- Frontend
|
||||||
- After Sankey visualization, go to Network Address visualization and render without Sankey dots
|
- After Sankey visualization, go to Network Address visualization and render without Sankey dots
|
||||||
@@ -31,3 +28,5 @@ other
|
|||||||
```
|
```
|
||||||
|
|
||||||
- mantain connection with wallet using websockets
|
- mantain connection with wallet using websockets
|
||||||
|
|
||||||
|
- num address evolution throught time
|
||||||
@@ -45,11 +45,7 @@ func upTree(address string, network NetworkModel) NetworkModel {
|
|||||||
|
|
||||||
//need to be fixed when there is a bucle between the addresses (A-->B, B-->C, C-->A)
|
//need to be fixed when there is a bucle between the addresses (A-->B, B-->C, C-->A)
|
||||||
fmt.Println(e.From + " - " + e.To)
|
fmt.Println(e.From + " - " + e.To)
|
||||||
//if e.From != e.To && e.From != upLevelEdge.To && e.To != upLevelEdge.From {
|
if edgeInEdges(network.Edges, edgeUpCheck) == false && endBranch == false && edgeUpCheck.BlockHeight <= e.BlockHeight && e.To != edgeUpCheck.From {
|
||||||
//if e.From != e.To {
|
|
||||||
fmt.Println(endBranch)
|
|
||||||
fmt.Println(edgeInEdges(network.Edges, edgeUpCheck))
|
|
||||||
if edgeInEdges(network.Edges, edgeUpCheck) == false && endBranch == false {
|
|
||||||
upNetwork = upTree(e.From, network)
|
upNetwork = upTree(e.From, network)
|
||||||
for _, upN := range upNetwork.Nodes {
|
for _, upN := range upNetwork.Nodes {
|
||||||
if nodeInNodes(network.Nodes, upN) == false {
|
if nodeInNodes(network.Nodes, upN) == false {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcrpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
func explore(client *btcrpcclient.Client, blockHash string) {
|
func explore(client *rpcclient.Client, blockHash string) {
|
||||||
var realBlocks int
|
var realBlocks int
|
||||||
/*var nOrigin NodeModel
|
/*var nOrigin NodeModel
|
||||||
nOrigin.Id = "origin"
|
nOrigin.Id = "origin"
|
||||||
@@ -39,9 +39,23 @@ func explore(client *btcrpcclient.Client, blockHash string) {
|
|||||||
newBlock.DateT = unixTimeToTime(block.Time)
|
newBlock.DateT = unixTimeToTime(block.Time)
|
||||||
newBlock.Date.Year, newBlock.Date.Month, newBlock.Date.Day, newBlock.Date.Hour = decomposeDate(block.Time)
|
newBlock.Date.Year, newBlock.Date.Month, newBlock.Date.Day, newBlock.Date.Hour = decomposeDate(block.Time)
|
||||||
|
|
||||||
|
//stats blocks
|
||||||
|
stats := getStats()
|
||||||
|
stats.BlockCount++
|
||||||
|
if len(block.Tx) > 1 {
|
||||||
|
stats.RealBlockCount++
|
||||||
|
}
|
||||||
|
updateStats(stats)
|
||||||
|
|
||||||
for k, txHash := range block.Tx {
|
for k, txHash := range block.Tx {
|
||||||
if k > 0 {
|
if k > 0 {
|
||||||
realBlocks++
|
realBlocks++
|
||||||
|
|
||||||
|
//stats txs
|
||||||
|
stats := getStats()
|
||||||
|
stats.TxCount++
|
||||||
|
updateStats(stats)
|
||||||
|
|
||||||
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: ")
|
||||||
|
|||||||
Binary file not shown.
8
main.go
8
main.go
@@ -10,10 +10,11 @@ import (
|
|||||||
mgo "gopkg.in/mgo.v2"
|
mgo "gopkg.in/mgo.v2"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
|
||||||
"github.com/btcsuite/btcrpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var statsCollection *mgo.Collection
|
||||||
var blockCollection *mgo.Collection
|
var blockCollection *mgo.Collection
|
||||||
var txCollection *mgo.Collection
|
var txCollection *mgo.Collection
|
||||||
var addressCollection *mgo.Collection
|
var addressCollection *mgo.Collection
|
||||||
@@ -31,6 +32,7 @@ func main() {
|
|||||||
//readMongodbConfig("./mongodbConfig.json")
|
//readMongodbConfig("./mongodbConfig.json")
|
||||||
session, err := getSession()
|
session, err := getSession()
|
||||||
check(err)
|
check(err)
|
||||||
|
statsCollection = getCollection(session, "stats")
|
||||||
blockCollection = getCollection(session, "blocks")
|
blockCollection = getCollection(session, "blocks")
|
||||||
txCollection = getCollection(session, "txs")
|
txCollection = getCollection(session, "txs")
|
||||||
addressCollection = getCollection(session, "address")
|
addressCollection = getCollection(session, "address")
|
||||||
@@ -42,7 +44,7 @@ func main() {
|
|||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
if os.Args[1] == "-explore" {
|
if os.Args[1] == "-explore" {
|
||||||
// create new client instance
|
// create new client instance
|
||||||
client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{
|
client, err := rpcclient.New(&rpcclient.ConnConfig{
|
||||||
HTTPPostMode: true,
|
HTTPPostMode: true,
|
||||||
DisableTLS: true,
|
DisableTLS: true,
|
||||||
Host: config.Host + ":" + config.Port,
|
Host: config.Host + ":" + config.Port,
|
||||||
@@ -77,7 +79,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
if os.Args[1] == "-continue" {
|
if os.Args[1] == "-continue" {
|
||||||
// create new client instance
|
// create new client instance
|
||||||
client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{
|
client, err := rpcclient.New(&rpcclient.ConnConfig{
|
||||||
HTTPPostMode: true,
|
HTTPPostMode: true,
|
||||||
DisableTLS: true,
|
DisableTLS: true,
|
||||||
Host: config.Host + ":" + config.Port,
|
Host: config.Host + ":" + config.Port,
|
||||||
|
|||||||
@@ -102,3 +102,10 @@ type DateCountModel struct {
|
|||||||
Date string `json:"date"`
|
Date string `json:"date"`
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
}
|
}
|
||||||
|
type StatsModel struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
RealBlockCount int `json:"realblockcount"`
|
||||||
|
BlockCount int `json:"blockcount"`
|
||||||
|
TxCount int `json:"txcount"`
|
||||||
|
AddrCount int `json:"addrcount"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,6 +117,11 @@ func saveAddress(address AddressModel) {
|
|||||||
//address not found, so let's add a new entry
|
//address not found, so let's add a new entry
|
||||||
err = addressCollection.Insert(address)
|
err = addressCollection.Insert(address)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
|
//stats addr
|
||||||
|
stats := getStats()
|
||||||
|
stats.AddrCount++
|
||||||
|
updateStats(stats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func saveTx(tx TxModel) {
|
func saveTx(tx TxModel) {
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ var routes = Routes{
|
|||||||
"/",
|
"/",
|
||||||
Index,
|
Index,
|
||||||
},
|
},
|
||||||
|
Route{
|
||||||
|
"Stats",
|
||||||
|
"Get",
|
||||||
|
"/stats",
|
||||||
|
Stats,
|
||||||
|
},
|
||||||
Route{
|
Route{
|
||||||
"AllAddresses",
|
"AllAddresses",
|
||||||
"Get",
|
"Get",
|
||||||
@@ -106,6 +112,16 @@ func NewUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintln(w, "new user added: ", newUser.ID)
|
fmt.Fprintln(w, "new user added: ", newUser.ID)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
func Stats(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ipFilter(w, r)
|
||||||
|
|
||||||
|
stats := getStats()
|
||||||
|
|
||||||
|
jsonResp, err := json.Marshal(stats)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
fmt.Fprintln(w, string(jsonResp))
|
||||||
|
}
|
||||||
func AllAddresses(w http.ResponseWriter, r *http.Request) {
|
func AllAddresses(w http.ResponseWriter, r *http.Request) {
|
||||||
ipFilter(w, r)
|
ipFilter(w, r)
|
||||||
|
|
||||||
@@ -154,6 +170,7 @@ func AddressNetwork(w http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintln(w, "not valid address")
|
fmt.Fprintln(w, "not valid address")
|
||||||
} else {
|
} else {
|
||||||
network := addressTree(address)
|
network := addressTree(address)
|
||||||
|
network.Nodes[0].Shape = "triangle"
|
||||||
|
|
||||||
//convert []resp struct to json
|
//convert []resp struct to json
|
||||||
jNetwork, err := json.Marshal(network)
|
jNetwork, err := json.Marshal(network)
|
||||||
|
|||||||
23
stats.go
Normal file
23
stats.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "gopkg.in/mgo.v2/bson"
|
||||||
|
|
||||||
|
func getStats() StatsModel {
|
||||||
|
var stats StatsModel
|
||||||
|
err := statsCollection.Find(bson.M{"title": "stats"}).One(&stats)
|
||||||
|
check(err)
|
||||||
|
stats.Title = "stats"
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateStats(stats StatsModel) {
|
||||||
|
var oldStats StatsModel
|
||||||
|
err := statsCollection.Find(bson.M{"title": "stats"}).One(&oldStats)
|
||||||
|
if err != nil {
|
||||||
|
err = statsCollection.Insert(stats)
|
||||||
|
check(err)
|
||||||
|
} else {
|
||||||
|
err = statsCollection.Update(bson.M{"title": "stats"}, &stats)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,45 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h4>{{stats.realblockcount}}/{{stats.blockcount}} Blocks with content</h4>
|
||||||
|
<div class="progress" style="margin:0;">
|
||||||
|
<div class="progress-bar c_blueGrey500" ng-style="blockProgress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h4>{{stats.txcount}} Txs</h4>
|
||||||
|
<div class="progress" style="margin:0;">
|
||||||
|
<div class="progress-bar c_blueGrey500" ng-style="txProgress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h4>{{stats.addrcount}} Addr</h4>
|
||||||
|
<div class="progress" style="margin:0;">
|
||||||
|
<div class="progress-bar c_blueGrey500" ng-style="txProgress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h4>300-500 Min-Max Block Size</h4>
|
||||||
|
<div class="progress" style="margin:0;">
|
||||||
|
<div class="progress-bar c_blueGrey500" ng-style="txProgress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
@@ -15,6 +57,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
|
<div class="panel">
|
||||||
<div class="panel-heading c_blueGrey300">
|
<div class="panel-heading c_blueGrey300">
|
||||||
<h3 class="panel-title">Last 24 hours Tx/Hour
|
<h3 class="panel-title">Last 24 hours Tx/Hour
|
||||||
<a ng-href="#!/dateAnalysis" class="pull-right c_blueGrey300">View more</a></h3>
|
<a ng-href="#!/dateAnalysis" class="pull-right c_blueGrey300">View more</a></h3>
|
||||||
@@ -23,6 +66,8 @@
|
|||||||
<canvas id="line" class="chart chart-line" chart-data="last24hour.data" chart-labels="last24hour.labels">
|
<canvas id="line" class="chart chart-line" chart-data="last24hour.data" chart-labels="last24hour.labels">
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel">
|
||||||
<div class="panel-heading c_blueGrey300">
|
<div class="panel-heading c_blueGrey300">
|
||||||
<h3 class="panel-title">Last 7 days Tx/Hour
|
<h3 class="panel-title">Last 7 days Tx/Hour
|
||||||
<a ng-href="#!/dateAnalysis" class="pull-right c_blueGrey300">View more</a></h3>
|
<a ng-href="#!/dateAnalysis" class="pull-right c_blueGrey300">View more</a></h3>
|
||||||
@@ -32,13 +77,14 @@
|
|||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-heading c_blueGrey300">
|
<div class="panel-heading c_blueGrey300">
|
||||||
<h3 class="panel-title">Hours</h3>
|
<h3 class="panel-title">Tx/Day Last 7 Days</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<canvas id="doughnut" class="chart chart-doughnut" chart-data="last24hour.data" chart-labels="last24hour.labels">
|
<canvas id="horizontal-bar" class="chart chart-horizontal-bar" chart-data="last7day.data" chart-labels="last7day.labels" chart-series="last7day.series">
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,7 +96,7 @@
|
|||||||
<div class="panel-heading c_blueGrey300">
|
<div class="panel-heading c_blueGrey300">
|
||||||
<h3 class="panel-title">Last Tx with amount</h3>
|
<h3 class="panel-title">Last Tx with amount</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body" style="max-height: 350px;overflow-y: scroll;">
|
<div class="panel-body" style="max-height: 200px;overflow-y: scroll;">
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<!--<colgroup>
|
<!--<colgroup>
|
||||||
<col class="col-md-2">
|
<col class="col-md-2">
|
||||||
|
|||||||
@@ -10,13 +10,28 @@ angular.module('app.main', ['ngRoute'])
|
|||||||
}])
|
}])
|
||||||
|
|
||||||
.controller('MainCtrl', function($scope, $http) {
|
.controller('MainCtrl', function($scope, $http) {
|
||||||
|
$scope.stats = [];
|
||||||
|
$scope.blockProgress={
|
||||||
|
"width": "0%"
|
||||||
|
};
|
||||||
|
$http.get(urlapi + 'stats')
|
||||||
|
.then(function(data, status, headers, config) {
|
||||||
|
console.log(data);
|
||||||
|
$scope.stats = data.data;
|
||||||
|
var tantpercent = ($scope.stats.realblockcount/$scope.stats.blockcount)*100;
|
||||||
|
$scope.blockProgress={
|
||||||
|
"width": tantpercent+"%"
|
||||||
|
};
|
||||||
|
}, function(data, status, headers, config) {
|
||||||
|
console.log('data error');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//last addr
|
//last addr
|
||||||
$scope.addresses = [];
|
$scope.addresses = [];
|
||||||
$http.get(urlapi + 'lastaddr')
|
$http.get(urlapi + 'lastaddr')
|
||||||
.then(function(data, status, headers, config) {
|
.then(function(data, status, headers, config) {
|
||||||
console.log('data success');
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
$scope.addresses = data.data;
|
$scope.addresses = data.data;
|
||||||
}, function(data, status, headers, config) {
|
}, function(data, status, headers, config) {
|
||||||
console.log('data error');
|
console.log('data error');
|
||||||
@@ -26,9 +41,7 @@ angular.module('app.main', ['ngRoute'])
|
|||||||
$scope.txs = [];
|
$scope.txs = [];
|
||||||
$http.get(urlapi + 'lasttx')
|
$http.get(urlapi + 'lasttx')
|
||||||
.then(function(data, status, headers, config) {
|
.then(function(data, status, headers, config) {
|
||||||
console.log('data success');
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
$scope.txs = data.data;
|
$scope.txs = data.data;
|
||||||
}, function(data, status, headers, config) {
|
}, function(data, status, headers, config) {
|
||||||
console.log('data error');
|
console.log('data error');
|
||||||
@@ -41,9 +54,7 @@ angular.module('app.main', ['ngRoute'])
|
|||||||
};
|
};
|
||||||
$http.get(urlapi + 'last24hour')
|
$http.get(urlapi + 'last24hour')
|
||||||
.then(function(data, status, headers, config) {
|
.then(function(data, status, headers, config) {
|
||||||
console.log('data success');
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
$scope.last24hour.data = data.data.data;
|
$scope.last24hour.data = data.data.data;
|
||||||
$scope.last24hour.labels = data.data.labels;
|
$scope.last24hour.labels = data.data.labels;
|
||||||
}, function(data, status, headers, config) {
|
}, function(data, status, headers, config) {
|
||||||
@@ -55,13 +66,27 @@ angular.module('app.main', ['ngRoute'])
|
|||||||
};
|
};
|
||||||
$http.get(urlapi + 'last7dayhour')
|
$http.get(urlapi + 'last7dayhour')
|
||||||
.then(function(data, status, headers, config) {
|
.then(function(data, status, headers, config) {
|
||||||
console.log('data success');
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
$scope.last7dayhour.data = data.data.data;
|
$scope.last7dayhour.data = data.data.data;
|
||||||
$scope.last7dayhour.labels = data.data.labels;
|
$scope.last7dayhour.labels = data.data.labels;
|
||||||
$scope.last7dayhour.series = data.data.series;
|
$scope.last7dayhour.series = data.data.series;
|
||||||
}, function(data, status, headers, config) {
|
}, function(data, status, headers, config) {
|
||||||
console.log('data error');
|
console.log('data error');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.last7day={
|
||||||
|
data: [],
|
||||||
|
labels: []
|
||||||
|
};
|
||||||
|
|
||||||
|
$http.get(urlapi + 'last7day')
|
||||||
|
.then(function(data, status, headers, config) {
|
||||||
|
console.log('data success');
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
$scope.last7day.data = data.data.data;
|
||||||
|
$scope.last7day.labels=data.data.labels;
|
||||||
|
}, function(data, status, headers, config) {
|
||||||
|
console.log('data error');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user