arnaucube
arnaucube/blockchainIDsystemPublic Self-hosted repository
implemented the blockchain, implemented the blocks propagation throught peers, implemented REST GetPeers and PostUser (address, pubK). Everything without any kind of blockchain verification. No cryptography yet.
arnaucode arnaucode@gmail.com
Sat, 25 Nov 2017 19:14:20 +0100
commit

c5fc0a53a7ef7b53995dd9caa7d685f89ea3e288

parent

2a01ef03948783f2087fef64ea9ca1474c1fcb60

A .gitignore

@@ -0,0 +1,1 @@

+tests
M peer/README.md → peer/README.md

@@ -19,3 +19,53 @@ "serverip": "127.0.0.1",

"serverport": "3000" } ``` + + +## Peer REST API +- GET / + - Returns the peer.ID (where peer.ID = hash(peer.IP + ":" + peer.Port)) + + +- GET /peers + - Returns the peer outcomingPeersList (the peers which the peer have connection) + +```json +{ + "PeerID": "VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo=", + "peerslist": [ + { + "id": "VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo=", + "ip": "127.0.0.1", + "port": "3000", + "role": "server", + "conn": null + }, + { + "id": "Lk9jEP1YcOAzl51yY61GdWADNe35_g5Teh12JeguHhA=", + "ip": "127.0.0.1", + "port": "3003", + "role": "client", + "conn": {} + }, + { + "id": "xj78wuyN2_thFBsXOUXnwij4L8vualxQ9GnVRK6RS4c=", + "ip": "127.0.0.1", + "port": "3005", + "role": "client", + "conn": {} + } + ], + "date": "0001-01-01T00:00:00Z" +} +``` + +- POST /register + - Adds the address (pubK of the user) to the blockchain + + +## TODO +- When a peer connects to the network, sends his last Block, and receives the new Blocks from this last Block +- Delete the peer from the peers list when the connection is closed +- REST: + - endpoint to get if the address is in the blockchain (to verify users) +- parameters Date or LastUpdate on the structs needs to be updated values
A peer/blockchain.go

@@ -0,0 +1,69 @@

+package main + +import ( + "errors" + "time" +) + +type Block struct { + Hash string `json:"hash"` + Height int64 `json:"height"` + Date time.Time `json:"date"` + PreviousHash string `json:"previoushash"` + NextHash string `json:"nexthash"` + Data []Address `json:"data"` + Emitter string `json:"emitter"` //the ID of the peer that has emmited the block +} + +type Blockchain struct { + GenesisBlock string `json:"genesisblock"` + LastUpdate time.Time `json:"lastupdate"` + Blocks []Block `json:"blocks"` +} + +var blockchain Blockchain + +func (bc *Blockchain) getBlockByHash(hash string) (Block, error) { + for _, block := range bc.Blocks { + if block.Hash == hash { + return block, nil + } + } + var b Block + return b, errors.New("Block Hash not found") +} + +func (bc *Blockchain) createBlock(address Address) Block { + var b Block + b.Height = int64(len(bc.Blocks)) + if len(bc.Blocks) == 0 { + b.Height = 0 + } else { + b.PreviousHash = bc.Blocks[len(bc.Blocks)-1].Hash + } + b.Date = time.Now() + b.Data = append(b.Data, address) + b.Emitter = runningPeer.ID + + b.Hash = hashBlock(b) + return b +} + +func (bc *Blockchain) blockExists(block Block) bool { + for _, b := range bc.Blocks { + if b.Hash == block.Hash { + return true + } + } + return false +} +func (bc *Blockchain) addBlock(block Block) error { + if len(bc.Blocks) > 0 { + bc.Blocks[len(bc.Blocks)-1].NextHash = block.Hash + } else { + bc.GenesisBlock = block.Hash + } + bc.Blocks = append(bc.Blocks, block) + + return nil +}
M peer/connections.go → peer/connections.go

@@ -57,7 +57,8 @@ connRunning := true

log.Println("handling conn: " + conn.RemoteAddr().String()) //reply to the conn, send the peerList var msg Msg - msg = msg.construct("PeersList", "here my outcomingPeersList", outcomingPeersList) + msg.construct("PeersList", "here my outcomingPeersList") + msg.PeersList = outcomingPeersList msgB := msg.toBytes() _, err := conn.Write(msgB) check(err)
M peer/main.go → peer/main.go

@@ -5,7 +5,6 @@ "fmt"

"math/rand" "net" "os" - "strconv" "time" "github.com/fatih/color"

@@ -32,9 +31,10 @@ color.Blue("Starting Peer")

//read configuration file readConfig("config.json") - runningPeer.ID = strconv.Itoa(randInt(1, 1000)) //0 is reserved for server + //runningPeer.ID = strconv.Itoa(randInt(1, 1000)) //0 is reserved for server runningPeer.IP = config.IP runningPeer.Port = config.Port + runningPeer.ID = hashPeer(runningPeer) runningPeer.Role = "client" go runRestServer()

@@ -45,7 +45,8 @@ if os.Args[1] == "server" {

color.Yellow("Running as p2p server") runningPeer.Role = "server" runningPeer.Port = config.ServerPort - runningPeer.ID = "0" + runningPeer.ID = hashPeer(runningPeer) + //runningPeer.ID = "0" } } thisPeerID = runningPeer.ID

@@ -58,12 +59,13 @@ if runningPeer.Role == "server" {

go acceptPeers(runningPeer) } if runningPeer.Role == "client" { - var newPeer Peer - newPeer.ID = "0" - newPeer.IP = config.ServerIP - newPeer.Port = config.ServerPort - newPeer.Role = "server" - connectToPeer(newPeer) + var serverPeer Peer + //serverPeer.ID = "0" + serverPeer.IP = config.ServerIP + serverPeer.Port = config.ServerPort + serverPeer.ID = hashPeer(serverPeer) + serverPeer.Role = "server" + connectToPeer(serverPeer) go acceptPeers(runningPeer) }
M peer/messages.go → peer/messages.go

@@ -14,6 +14,7 @@ Type string `json:"type"`

Date time.Time `json:"date"` Content string `json:"content"` PeersList PeersList `json:"peerslist"` + Block Block `json:"block"` } func messageHandler(peer Peer, msg Msg) {

@@ -57,18 +58,22 @@ propagatePeersList(peer)

*/ printPeersList() break + case "Block": + if !blockchain.blockExists(msg.Block) { + blockchain.addBlock(msg.Block) + propagateBlock(msg.Block) + } + break default: log.Println("Msg.Type not supported") break } } -func (msg Msg) construct(msgtype string, msgcontent string, peersList PeersList) Msg { +func (msg *Msg) construct(msgtype string, msgcontent string) { msg.Type = msgtype msg.Content = msgcontent - msg.PeersList = peersList msg.Date = time.Now() - return msg } func (msg Msg) toBytes() []byte { msgS, err := json.Marshal(msg)
M peer/peersList.go → peer/peers.go

@@ -74,22 +74,16 @@ if peer.Conn != nil {

if peer.ID != p.ID && p.ID != "" { color.Yellow(peer.ID + " - " + p.ID) var msg Msg - msg = msg.construct("PeersList", "here my outcomingPeersList", outcomingPeersList) + msg.construct("PeersList", "here my outcomingPeersList") + msg.PeersList = outcomingPeersList msgB := msg.toBytes() _, err := peer.Conn.Write(msgB) check(err) } else { - //to the peer that has sent the peerList, we send our ID - /* - var msg Msg - var pl PeersList - msg = msg.construct("MyID", runningPeer.ID, pl) - msgB := msg.toBytes() - _, err := p.Conn.Write(msgB) - check(err) - */ + //to the peer that has sent the peerList, we send our PeersList var msg Msg - msg = msg.construct("PeersList_Response", "here my outcomingPeersList", outcomingPeersList) + msg.construct("PeersList_Response", "here my outcomingPeersList") + msg.PeersList = outcomingPeersList msgB := msg.toBytes() _, err := peer.Conn.Write(msgB) check(err)

@@ -123,3 +117,18 @@ fmt.Println(peer)

} fmt.Println("") } + +//send the block to all the peers of the outcomingPeersList +func propagateBlock(b Block) { + //prepare the msg to send to all connected peers + var msg Msg + msg.construct("Block", "new block") + msg.Block = b + msgB := msg.toBytes() + for _, peer := range outcomingPeersList.Peers { + if peer.Conn != nil { + _, err := peer.Conn.Write(msgB) + check(err) + } + } +}
A peer/restRoutes.go

@@ -0,0 +1,67 @@

+package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/fatih/color" +) + +type Routes []Route + +var routes = Routes{ + Route{ + "Index", + "GET", + "/", + Index, + }, + Route{ + "GetPeers", + "GET", + "/peers", + GetPeers, + }, + Route{ + "PostUser", + "POST", + "/register", + PostUser, + }, +} + +type Address struct { + Address string `json:"address"` //the pubK of the user, to perform logins +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, runningPeer.ID) +} +func GetPeers(w http.ResponseWriter, r *http.Request) { + jResp, err := json.Marshal(outcomingPeersList) + check(err) + fmt.Fprintln(w, string(jResp)) +} +func PostUser(w http.ResponseWriter, r *http.Request) { + + decoder := json.NewDecoder(r.Body) + var address Address + err := decoder.Decode(&address) + if err != nil { + panic(err) + } + defer r.Body.Close() + fmt.Println(address) + color.Blue(address.Address) + + //TODO add the verification of the address, to decide if it's accepted to create a new Block + block := blockchain.createBlock(address) + blockchain.addBlock(block) + + go propagateBlock(block) + + jResp, err := json.Marshal(blockchain) + check(err) + fmt.Fprintln(w, string(jResp)) +}
D peer/restServerRoutes.go

@@ -1,22 +0,0 @@

-package main - -import ( - "fmt" - "net/http" -) - -type Routes []Route - -var routes = Routes{ - Route{ - "Index", - "GET", - "/", - Index, - }, -} - -func Index(w http.ResponseWriter, r *http.Request) { - //ipFilter(w, r) - fmt.Fprintln(w, runningPeer.ID) -}
A peer/tests.sh

@@ -0,0 +1,1 @@

+curl -X POST -F address="thisisasampleaddress" http://127.0.0.1:3002/register
M peer/utils.go → peer/utils.go

@@ -1,6 +1,9 @@

package main import ( + "crypto/sha256" + "encoding/base64" + "encoding/json" "math/rand" "net" "strings"

@@ -27,3 +30,22 @@ func randInt(min int, max int) int {

r := rand.Intn(max-min) + min return r } +func hashPeer(p Peer) string { + /*peerJson, err := json.Marshal(p) + check(err) + peerString := string(peerJson)*/ + peerString := p.IP + ":" + p.Port + + h := sha256.New() + h.Write([]byte(peerString)) + return base64.URLEncoding.EncodeToString(h.Sum(nil)) +} +func hashBlock(b Block) string { + blockJson, err := json.Marshal(b) + check(err) + blockString := string(blockJson) + + h := sha256.New() + h.Write([]byte(blockString)) + return base64.URLEncoding.EncodeToString(h.Sum(nil)) +}