From f9262f72a11182c75f708022929a28ebc8d4002a Mon Sep 17 00:00:00 2001 From: arnaucode Date: Thu, 27 Jul 2017 13:57:05 +0200 Subject: [PATCH] implemented generation of network map of address history, not finished --- exploreBlockchain.go | 180 ++++++++++--------- main.go | 4 + mongoModels.go | 11 +- mongoOperations.go | 21 ++- serverRoutes.go | 53 +++++- web/app.js | 1 + web/index.html | 3 +- web/views/addressNetwork/addressNetwork.html | 29 +++ web/views/addressNetwork/addressNetwork.js | 104 +++++++++++ web/views/navbar.html | 65 +++---- web/views/network/network.html | 22 ++- web/views/network/network.js | 54 +++++- 12 files changed, 402 insertions(+), 145 deletions(-) create mode 100644 web/views/addressNetwork/addressNetwork.html create mode 100644 web/views/addressNetwork/addressNetwork.js diff --git a/exploreBlockchain.go b/exploreBlockchain.go index dc36aa9..7dd7be5 100644 --- a/exploreBlockchain.go +++ b/exploreBlockchain.go @@ -3,13 +3,15 @@ package main import ( "fmt" + "gopkg.in/mgo.v2/bson" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcrpcclient" + "github.com/fatih/color" ) func explore(client *btcrpcclient.Client, blockHash string) { var realBlocks int - var nOrigin NodeModel nOrigin.Id = "origin" nOrigin.Label = "origin" @@ -26,116 +28,122 @@ func explore(client *btcrpcclient.Client, blockHash string) { block, err := client.GetBlockVerbose(bh) check(err) - var newBlock BlockModel - newBlock.Hash = block.Hash - newBlock.Height = block.Height - newBlock.Confirmations = block.Confirmations - - //get Fee value - th, err := chainhash.NewHashFromStr(block.Tx[0]) - check(err) - tx, err := client.GetRawTransactionVerbose(th) - check(err) - var totalFee float64 - for _, Vo := range tx.Vout { - totalFee = totalFee + Vo.Value - } - newBlock.Fee = totalFee - - //for each Tx, get the Tx value - var totalAmount float64 - /*inside each block, there are []Tx - inside each Tx, if is the Tx[0], is the Fees - in the Tx[n] where n>0, each Tx is independent, - and inside each Tx there are []Vout. - Usually Vout[0] is the real Tx value - and the Vout[1] is the rest of the amount in the original wallet. - Each Tx moves all the wallet amount, and the realTx amount is sent to the destination - and the rest of the wallet amount, is send to another owned wallet - */ //if len(block.Tx) < 10 { for k, txHash := range block.Tx { - //first Tx is the Fee - //after first Tx is the Sent Amount 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 originAddress string + + var originAddresses []string + var outputAddresses []string for _, Vi := range tx.Vin { th, err := chainhash.NewHashFromStr(Vi.Txid) check(err) txVi, err := client.GetRawTransactionVerbose(th) check(err) - if len(txVi.Vout[0].ScriptPubKey.Addresses) > 0 { - originAddress = txVi.Vout[0].ScriptPubKey.Addresses[0] + 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) + } } else { - originAddress = "origin" + originAddresses = append(originAddresses, "origin") } } for _, Vo := range tx.Vout { - totalAmount = totalAmount + Vo.Value - - var blockTx TxModel - blockTx.Txid = tx.Txid - blockTx.Amount = Vo.Value - blockTx.From = originAddress - blockTx.To = Vo.ScriptPubKey.Addresses[0] - newBlock.Tx = append(newBlock.Tx, blockTx) + //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 = string(block.Height) + n2.Value = 1 + n2.Shape = "dot" + saveNode(nodeCollection, n2) + + for _, originAddr := range originAddresses { + var e EdgeModel + e.From = originAddr + e.To = outputAddr + e.Label = Vo.Value + e.Txid = tx.Txid + e.Arrows = "to" + e.BlockHeight = block.Height + saveEdge(edgeCollection, e) + //fmt.Println(e) + } + } + //} } + fmt.Print("originAddresses: ") + fmt.Println(len(originAddresses)) + fmt.Print("outputAddresses: ") + fmt.Println(len(outputAddresses)) } } - - if totalAmount > 0 { - newBlock.Amount = totalAmount - saveBlock(blockCollection, newBlock) - fmt.Print("Height: ") - fmt.Println(newBlock.Height) - fmt.Print("Amount: ") - fmt.Println(newBlock.Amount) - fmt.Print("Fee: ") - fmt.Println(newBlock.Fee) - fmt.Println("-----") - realBlocks++ - } //} - //set the next block blockHash = block.NextHash - - //analyze block creator - for _, t := range newBlock.Tx { - var n1 NodeModel - var n2 NodeModel - n1.Id = t.From - n1.Label = t.From - n1.Title = t.From - n1.Group = newBlock.Hash - n1.Value = 1 - n1.Shape = "dot" - n2.Id = t.To - n2.Label = t.To - n2.Title = t.To - n2.Group = newBlock.Hash - n2.Value = 1 - n2.Shape = "dot" - - var e EdgeModel - e.From = t.From - e.To = t.To - e.Label = t.Amount - e.Txid = t.Txid - e.Arrows = "to" - - saveNode(nodeCollection, n1) - saveNode(nodeCollection, n2) - saveEdge(edgeCollection, e) - } - } + fmt.Print("realBlocks (blocks with Fee and Amount values): ") fmt.Println(realBlocks) fmt.Println("reached the end of blockchain") } +func addressTree(address string) NetworkModel { + var network NetworkModel + + var currentEdge EdgeModel + currentEdge.From = "a" + currentEdge.To = "b" + for currentEdge.From != currentEdge.To { + color.Green("for") + fmt.Println(address) + //get edges before the address + edges := []EdgeModel{} + err := edgeCollection.Find(bson.M{"to": address}).All(&edges) + check(err) + for _, edge := range edges { + network.Edges = append(network.Edges, edge) + fmt.Println(edge) + } + //get all nodes from edges + for _, edge := range edges { + node := NodeModel{} + err := nodeCollection.Find(bson.M{"id": edge.From}).One(&node) + check(err) + if nodeInNodes(network.Nodes, node) == false { + network.Nodes = append(network.Nodes, node) + } + + err = nodeCollection.Find(bson.M{"id": edge.To}).One(&node) + check(err) + if nodeInNodes(network.Nodes, node) == false { + network.Nodes = append(network.Nodes, node) + } + } + address = edges[0].From + currentEdge = edges[0] + } + return network +} diff --git a/main.go b/main.go index 4383571..a067a59 100644 --- a/main.go +++ b/main.go @@ -55,6 +55,10 @@ func main() { color.Blue("starting to explore blockchain") explore(client, config.GenesisBlock) } + /*if os.Args[1] == "-tree" { + color.Blue("starting to make tree") + addressTree(client, "fY3HZxu7HFKRcYzVSTXRZpAJMP4qba2oR6") + }*/ } // Get the current block count. diff --git a/mongoModels.go b/mongoModels.go index 3c61927..f14642d 100644 --- a/mongoModels.go +++ b/mongoModels.go @@ -25,11 +25,12 @@ type NodeModel struct { } type EdgeModel struct { - Txid string `json:"txid"` - From string `json:"from"` - To string `json:"to"` - Label float64 `json:"label"` - Arrows string `json:"arrows"` + Txid string `json:"txid"` + From string `json:"from"` + To string `json:"to"` + Label float64 `json:"label"` + Arrows string `json:"arrows"` + BlockHeight int64 `json:"blockheight"` } type NetworkModel struct { Nodes []NodeModel `json:"nodes"` diff --git a/mongoOperations.go b/mongoOperations.go index 30bd24b..3a4919b 100644 --- a/mongoOperations.go +++ b/mongoOperations.go @@ -66,7 +66,7 @@ func saveBlock(c *mgo.Collection, block BlockModel) { func getAllNodes() ([]NodeModel, error) { result := []NodeModel{} - iter := nodeCollection.Find(bson.M{}).Limit(100).Iter() + iter := nodeCollection.Find(bson.M{}).Limit(10000).Iter() err := iter.All(&result) return result, err } @@ -74,13 +74,13 @@ func getAllNodes() ([]NodeModel, error) { func saveNode(c *mgo.Collection, node NodeModel) { //first, check if the node already exists result := NodeModel{} - err := c.Find(bson.M{"id": node.Id}).One(&result) + err := c.Find(bson.M{"id": node.Id, "group": node.Group}).One(&result) if err != nil { //node not found, so let's add a new entry err = c.Insert(node) check(err) } else { - err = c.Update(bson.M{"id": node.Id}, &node) + err = c.Update(bson.M{"id": node.Id, "group": node.Group}, &node) if err != nil { log.Fatal(err) } @@ -89,22 +89,31 @@ func saveNode(c *mgo.Collection, node NodeModel) { func getAllEdges() ([]EdgeModel, error) { result := []EdgeModel{} - iter := edgeCollection.Find(bson.M{}).Limit(100).Iter() + iter := edgeCollection.Find(bson.M{}).Limit(10000).Iter() err := iter.All(&result) return result, err } func saveEdge(c *mgo.Collection, edge EdgeModel) { //first, check if the edge already exists result := EdgeModel{} - err := c.Find(bson.M{"txid": edge.Txid}).One(&result) + err := c.Find(bson.M{"txid": edge.Txid, "to": edge.To, "from": edge.From, "blockheight": edge.BlockHeight, "label": edge.Label}).One(&result) if err != nil { //edge not found, so let's add a new entry err = c.Insert(edge) check(err) } else { - err = c.Update(bson.M{"txid": edge.Txid}, &edge) + err = c.Update(bson.M{"txid": edge.Txid, "to": edge.To, "from": edge.From, "blockheight": edge.BlockHeight, "label": edge.Label}, &edge) if err != nil { log.Fatal(err) } } } + +func nodeInNodes(nodes []NodeModel, node NodeModel) bool { + for _, n := range nodes { + if n.Id == node.Id { + return true + } + } + return false +} diff --git a/serverRoutes.go b/serverRoutes.go index 13ee30e..2a0dcee 100644 --- a/serverRoutes.go +++ b/serverRoutes.go @@ -4,6 +4,10 @@ import ( "encoding/json" "fmt" "net/http" + + "gopkg.in/mgo.v2/bson" + + "github.com/gorilla/mux" ) type Routes []Route @@ -15,13 +19,18 @@ var routes = Routes{ "/", Index, }, - /* Route{ - "Recommendations", - "GET", - "/r/{userid}/{nrec}", - Recommendations, - }, - */ + Route{ + "AllAddresses", + "Get", + "/alladdresses", + AllAddresses, + }, + Route{ + "AddressNetwork", + "GET", + "/address/network/{address}", + AddressNetwork, + }, Route{ "NetworkMap", "Get", @@ -60,6 +69,36 @@ func NewUser(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "new user added: ", newUser.ID) } */ +func AllAddresses(w http.ResponseWriter, r *http.Request) { + ipFilter(w, r) + + nodes := []NodeModel{} + iter := nodeCollection.Find(bson.M{}).Limit(10000).Iter() + err := iter.All(&nodes) + + //convert []resp struct to json + jsonNodes, err := json.Marshal(nodes) + check(err) + + fmt.Fprintln(w, string(jsonNodes)) +} +func AddressNetwork(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) + + //convert []resp struct to json + jNetwork, err := json.Marshal(network) + check(err) + + fmt.Fprintln(w, string(jNetwork)) + } +} func NetworkMap(w http.ResponseWriter, r *http.Request) { ipFilter(w, r) diff --git a/web/app.js b/web/app.js index 81b5837..c940c2b 100644 --- a/web/app.js +++ b/web/app.js @@ -11,6 +11,7 @@ angular.module('webApp', [ 'app.navbar', 'app.main', 'app.network', + 'app.addressNetwork', 'app.sankey' ]). config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { diff --git a/web/index.html b/web/index.html index febbe7f..60abf90 100644 --- a/web/index.html +++ b/web/index.html @@ -21,7 +21,7 @@ -->