Browse Source

first commit

master
arnaucode 6 years ago
parent
commit
51e2d00603
24 changed files with 1034 additions and 0 deletions
  1. +3
    -0
      README.md
  2. +4
    -0
      memory.md
  3. +1
    -0
      peer/.gitignore
  4. +73
    -0
      peer/README.md
  5. +20
    -0
      peer/blockchainlib/block.go
  6. +155
    -0
      peer/blockchainlib/blockchain.go
  7. +15
    -0
      peer/blockchainlib/errors.go
  8. +6
    -0
      peer/config.json
  9. +15
    -0
      peer/errors.go
  10. +24
    -0
      peer/log.go
  11. +48
    -0
      peer/main.go
  12. +81
    -0
      peer/p2plib/connections.go
  13. +15
    -0
      peer/p2plib/errors.go
  14. +43
    -0
      peer/p2plib/init.go
  15. +78
    -0
      peer/p2plib/messages.go
  16. +164
    -0
      peer/p2plib/peers.go
  17. +38
    -0
      peer/p2plib/utils.go
  18. BIN
      peer/peer
  19. +26
    -0
      peer/readConfig.go
  20. +47
    -0
      peer/restConfig.go
  21. +141
    -0
      peer/restRoutes.go
  22. +20
    -0
      peer/restServer.go
  23. +1
    -0
      peer/tests.sh
  24. +16
    -0
      runTmuxTestPeers.sh

+ 3
- 0
README.md

@ -0,0 +1,3 @@
# bc
Own p2p network and own blockchain libraries written in Go, to develop own decentralized apps.

+ 4
- 0
memory.md

@ -0,0 +1,4 @@
- p2plib/messages.go / MessageHandler
put in a way that the messages handlers can be created from the main code (not from the package)
- subsitute the REST functions by the messages in the MessageHandler

+ 1
- 0
peer/.gitignore

@ -0,0 +1 @@
*.data

+ 73
- 0
peer/README.md

@ -0,0 +1,73 @@
# Peer
To run as a normal peer:
```
./peer
```
To run as a p2p server:
```
./peer server
```
Needs the config.json file:
```json
{
"ip": "127.0.0.1",
"port": "3001",
"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 --> DONE with REST petitions, maybe is better with tcp conn
- Delete the peer from the peers list when the connection is closed --> DONE
- 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
- implement rsa encryption between peers
- store blockchain in a .data file

+ 20
- 0
peer/blockchainlib/block.go

@ -0,0 +1,20 @@
package blockchainlib
import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"log"
)
func HashBlock(b Block) string {
blockJson, err := json.Marshal(b)
if err != nil {
log.Println(err)
}
blockString := string(blockJson)
h := sha256.New()
h.Write([]byte(blockString))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
}

+ 155
- 0
peer/blockchainlib/blockchain.go

@ -0,0 +1,155 @@
package blockchainlib
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/fatih/color"
)
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 []string `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(data string) 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, data)
//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 bc.BlockExists(block) {
return errors.New("[Error adding Block]: Block already exists in the Blockchain")
}
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)
bc.SaveToDisk()
return nil
}
func (bc *Blockchain) ReconstructBlockchainFromBlock(urlAPI string, h string) {
color.Yellow("reconstructing the blockchain from last block in memory")
var block Block
var err error
block, err = bc.GetBlockByHash(h)
check(err)
if h == "" {
//no genesis block yet
color.Green(urlAPI + "/blocks/genesis")
res, err := http.Get(urlAPI + "/blocks/genesis")
check(err)
body, err := ioutil.ReadAll(res.Body)
check(err)
err = json.Unmarshal(body, &block)
check(err)
color.Yellow("[New Block]: " + block.Hash)
err = bc.AddBlock(block)
check(err)
} else {
block.NextHash = h
}
for block.NextHash != "" && block.Hash != "" {
res, err := http.Get(urlAPI + "/blocks/next/" + block.Hash)
check(err)
body, err := ioutil.ReadAll(res.Body)
check(err)
err = json.Unmarshal(body, &block)
check(err)
if block.Hash != "" {
color.Yellow("[New Block]: " + block.Hash)
err = bc.AddBlock(block)
check(err)
}
}
bc.Print()
}
func (bc *Blockchain) Print() {
color.Green("Printing Blockchain stored in memory")
color.Green("Genesis Block: " + bc.GenesisBlock)
for _, b := range bc.Blocks {
color.Green("Block height:")
fmt.Println(b.Height)
color.Green("Hash: " + b.Hash)
color.Green("Date: " + b.Date.String())
color.Green("---")
}
}
func (bc *Blockchain) ReadFromDisk() error {
file, err := ioutil.ReadFile("blockchain.data")
if err != nil {
return err
}
content := string(file)
json.Unmarshal([]byte(content), &bc)
return nil
}
func (bc *Blockchain) SaveToDisk() error {
bytesBlockchain, err := json.Marshal(bc)
if err != nil {
return err
}
err = ioutil.WriteFile("blockchain.data", bytesBlockchain, 0644)
if err != nil {
return err
}
return nil
}

+ 15
- 0
peer/blockchainlib/errors.go

@ -0,0 +1,15 @@
package blockchainlib
import (
"log"
"runtime"
)
func check(err error) {
if err != nil {
_, fn, line, _ := runtime.Caller(1)
log.Println(line)
log.Println(fn)
log.Println(err)
}
}

+ 6
- 0
peer/config.json

@ -0,0 +1,6 @@
{
"ip": "127.0.0.1",
"serverip": "127.0.0.1",
"serverport": "3000",
"serverrestport": "3002"
}

+ 15
- 0
peer/errors.go

@ -0,0 +1,15 @@
package main
import (
"log"
"runtime"
)
func check(err error) {
if err != nil {
_, fn, line, _ := runtime.Caller(1)
log.Println(line)
log.Println(fn)
log.Println(err)
}
}

+ 24
- 0
peer/log.go

@ -0,0 +1,24 @@
package main
import (
"io"
"log"
"os"
"strings"
"time"
)
func savelog() {
timeS := time.Now().String()
_ = os.Mkdir("logs", os.ModePerm)
//next 3 lines are to avoid windows filesystem errors
timeS = strings.Replace(timeS, " ", "_", -1)
timeS = strings.Replace(timeS, ".", "-", -1)
timeS = strings.Replace(timeS, ":", "-", -1)
logFile, err := os.OpenFile("logs/log-"+timeS+".log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
panic(err)
}
mw := io.MultiWriter(os.Stdout, logFile)
log.SetOutput(mw)
}

+ 48
- 0
peer/main.go

@ -0,0 +1,48 @@
package main
import (
"fmt"
"os"
"time"
blockchainlib "./blockchainlib"
p2plib "./p2plib"
"github.com/fatih/color"
)
var tp p2plib.ThisPeer
var blockchain blockchainlib.Blockchain
func main() {
if len(os.Args) < 3 {
color.Red("need to call:")
color.Red("./peer client 3001 3002")
os.Exit(3)
}
color.Blue("Starting Peer")
//read configuration file
readConfig("config.json")
//read the stored blockchain
err := blockchain.ReadFromDisk()
check(err)
blockchain.Print()
tp = p2plib.InitializePeer(os.Args[1], "127.0.0.1",
os.Args[2], os.Args[3], config.ServerIP, config.ServerPort)
if tp.RunningPeer.Role == "client" {
color.Red("http://" + config.IP + ":" + config.ServerRESTPort)
fmt.Println(blockchain.GenesisBlock)
blockchain.ReconstructBlockchainFromBlock("http://"+config.IP+":"+config.ServerRESTPort, blockchain.GenesisBlock)
}
color.Blue("initialized")
go runRestServer()
fmt.Println(tp.Running)
for tp.Running {
time.Sleep(1000 * time.Millisecond)
}
}

+ 81
- 0
peer/p2plib/connections.go

@ -0,0 +1,81 @@
package p2plib
import (
"bufio"
"fmt"
"log"
"net"
"github.com/fatih/color"
)
func (tp *ThisPeer) AcceptPeers(peer Peer) {
fmt.Println("accepting peers at: " + peer.Port)
l, err := net.Listen("tcp", peer.IP+":"+peer.Port)
if err != nil {
log.Println("Error accepting peers. Listening port: " + peer.Port)
tp.Running = false
}
for tp.Running {
conn, err := l.Accept()
if err != nil {
log.Println("Error accepting peers. Error accepting connection")
tp.Running = false
}
var newPeer Peer
newPeer.IP = GetIPFromConn(conn)
newPeer.Port = GetPortFromConn(conn)
newPeer.Conn = conn
globalTP.PeersConnections.Incoming = AppendPeerIfNoExist(globalTP.PeersConnections.Incoming, newPeer)
go HandleConn(conn, newPeer)
}
}
func ConnectToPeer(peer Peer) {
color.Green("connecting to new peer")
log.Println("Connecting to new peer: " + peer.IP + ":" + peer.Port)
conn, err := net.Dial("tcp", peer.IP+":"+peer.Port)
if err != nil {
log.Println("Error connecting to: " + peer.IP + ":" + peer.Port)
return
}
peer.Conn = conn
globalTP.PeersConnections.Outcoming = AppendPeerIfNoExist(globalTP.PeersConnections.Outcoming, peer)
go HandleConn(conn, peer)
}
func HandleConn(conn net.Conn, connPeer Peer) {
connRunning := true
log.Println("handling conn: " + conn.RemoteAddr().String())
//reply to the conn, send the peerList
var msg Msg
msg.Construct("PeersList", "here my outcomingPeersList")
msg.PeersList = globalTP.PeersConnections.Outcoming
msgB := msg.ToBytes()
_, err := conn.Write(msgB)
if err != nil {
log.Println(err)
}
for connRunning {
/*
buffer := make([]byte, 1024)
bytesRead, err := conn.Read(buffer)
*/
newmsg, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
log.Println(err)
connRunning = false
} else {
var msg Msg
//msg = msg.createFromBytes([]byte(string(buffer[0:bytesRead])))
msg = msg.CreateFromBytes([]byte(newmsg))
MessageHandler(connPeer, msg)
}
}
//TODO add that if the peer closed is the p2p server, show a warning message at the peer
log.Println("Peer: " + conn.RemoteAddr().String() + " connection closed")
conn.Close()
//TODO delete the peer from the outcomingPeersList --> DONE
DeletePeerFromPeersList(connPeer, &globalTP.PeersConnections.Outcoming)
/*color.Yellow("peer deleted, current peerList:")
PrintPeersList()*/
}

+ 15
- 0
peer/p2plib/errors.go

@ -0,0 +1,15 @@
package p2plib
import (
"log"
"runtime"
)
func check(err error) {
if err != nil {
_, fn, line, _ := runtime.Caller(1)
log.Println(line)
log.Println(fn)
log.Println(err)
}
}

+ 43
- 0
peer/p2plib/init.go

@ -0,0 +1,43 @@
package p2plib
import (
"fmt"
"math/rand"
"time"
)
func InitializePeer(role, ip, port, restport, serverip, serverport string) ThisPeer {
//initialize some vars
rand.Seed(time.Now().Unix())
var tp ThisPeer
tp.Running = true
tp.RunningPeer.Role = role
tp.RunningPeer.Port = port
tp.RunningPeer.RESTPort = restport
tp.RunningPeer.ID = HashPeer(tp.RunningPeer)
tp.ID = tp.RunningPeer.ID
globalTP.PeersConnections.Outcoming.PeerID = tp.RunningPeer.ID
fmt.Println(tp.RunningPeer)
//outcomingPeersList.Peers = append(outcomingPeersList.Peers, peer.RunningPeer)
globalTP.PeersConnections.Outcoming = AppendPeerIfNoExist(globalTP.PeersConnections.Outcoming, tp.RunningPeer)
fmt.Println(globalTP.PeersConnections.Outcoming)
if tp.RunningPeer.Role == "server" {
go tp.AcceptPeers(tp.RunningPeer)
}
if tp.RunningPeer.Role == "client" {
var serverPeer Peer
serverPeer.IP = serverip
serverPeer.Port = serverport
serverPeer.Role = "server"
serverPeer.ID = HashPeer(serverPeer)
go tp.AcceptPeers(tp.RunningPeer)
ConnectToPeer(serverPeer)
}
globalTP = tp
return tp
}

+ 78
- 0
peer/p2plib/messages.go

@ -0,0 +1,78 @@
package p2plib
import (
"encoding/json"
"fmt"
"log"
"time"
"github.com/fatih/color"
)
type Msg struct {
Type string `json:"type"`
Date time.Time `json:"date"`
Content string `json:"content"`
PeersList PeersList `json:"peerslist"`
Data []byte `json:"data"`
}
func MessageHandler(peer Peer, msg Msg) {
log.Println("[New msg]")
log.Println(msg)
switch msg.Type {
case "Hi":
color.Yellow(msg.Type)
color.Green(msg.Content)
break
case "PeersList":
color.Blue("newPeerslist")
fmt.Println(msg.PeersList)
color.Red("PeersList")
UpdateNetworkPeersList(peer.Conn, msg.PeersList)
PropagatePeersList(peer)
PrintPeersList()
break
case "PeersList_Response":
//for the moment is not beeing used
color.Blue("newPeerslist, from PeersList_Response")
fmt.Println(msg.PeersList)
color.Red("PeersList_Response")
UpdateNetworkPeersList(peer.Conn, msg.PeersList)
PropagatePeersList(peer)
PrintPeersList()
break
case "Block":
/*//TODO check if the block is signed by an autorized emitter
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) {
msg.Type = msgtype
msg.Content = msgcontent
msg.Date = time.Now()
}
func (msg Msg) ToBytes() []byte {
msgS, err := json.Marshal(msg)
check(err)
l := string(msgS) + "\n"
r := []byte(l)
return r
}
func (msg Msg) CreateFromBytes(bytes []byte) Msg {
err := json.Unmarshal(bytes, &msg)
check(err)
return msg
}

+ 164
- 0
peer/p2plib/peers.go

@ -0,0 +1,164 @@
package p2plib
import (
"fmt"
"net"
"time"
"github.com/fatih/color"
)
type Peer struct {
ID string `json:"id"` //in the future, this will be the peer hash
IP string `json:"ip"`
Port string `json:"port"`
RESTPort string `json:"restport"`
Role string `json:"role"` //client or server
Conn net.Conn `json:"conn"`
}
type PeersList struct {
PeerID string
Peers []Peer `json:"peerslist"`
Date time.Time `json:"date"`
}
type PeersConnections struct {
Incoming PeersList
Outcoming PeersList
Network PeersList //the peers that have been received in the lists from other peers
}
type ThisPeer struct {
Running bool
ID string
RunningPeer Peer
PeersConnections PeersConnections
}
var globalTP ThisPeer
func PeerIsInPeersList(p Peer, pl []Peer) int {
r := -1
for i, peer := range pl {
if peer.IP+":"+peer.Port == p.IP+":"+p.Port {
r = i
}
}
return r
}
func DeletePeerFromPeersList(p Peer, pl *PeersList) {
i := PeerIsInPeersList(p, pl.Peers)
if i != -1 {
//delete peer from pl.Peers
pl.Peers = append(pl.Peers[:i], pl.Peers[i+1:]...)
}
}
func AppendPeerIfNoExist(pl PeersList, p Peer) PeersList {
i := PeerIsInPeersList(p, pl.Peers)
if i == -1 {
pl.Peers = append(pl.Peers, p)
}
return pl
}
func UpdateNetworkPeersList(conn net.Conn, newPeersList PeersList) {
for _, peer := range newPeersList.Peers {
if GetIPPortFromConn(conn) == peer.IP+":"+peer.Port {
peer.ID = newPeersList.PeerID
color.Yellow(peer.ID)
}
i := PeerIsInPeersList(peer, globalTP.PeersConnections.Network.Peers)
if i == -1 {
globalTP.PeersConnections.Network.Peers = append(globalTP.PeersConnections.Network.Peers, peer)
} else {
fmt.Println(globalTP.PeersConnections.Network.Peers[i])
globalTP.PeersConnections.Network.Peers[i].ID = peer.ID
}
}
}
func SearchPeerAndUpdate(p Peer) {
for _, peer := range globalTP.PeersConnections.Outcoming.Peers {
color.Red(p.IP + ":" + p.Port)
color.Yellow(peer.IP + ":" + peer.Port)
if p.IP+":"+p.Port == peer.IP+":"+peer.Port {
peer.ID = p.ID
}
}
}
//send the outcomingPeersList to all the peers except the peer p that has send the outcomingPeersList
func PropagatePeersList(p Peer) {
for _, peer := range globalTP.PeersConnections.Network.Peers {
if peer.Conn != nil {
if peer.ID != p.ID && p.ID != "" {
color.Yellow(peer.ID + " - " + p.ID)
var msg Msg
msg.Construct("PeersList", "here my outcomingPeersList")
msg.PeersList = globalTP.PeersConnections.Outcoming
msgB := msg.ToBytes()
_, err := peer.Conn.Write(msgB)
check(err)
} else {
/*
for the moment, this is not being called, due that in the IncomingPeersList,
there is no peer.ID, so in the comparation wih the peer that has send the
peersList, is comparing ID with "", so nevere enters this 'else' section
maybe it's not needed. TODO check if it's needed the PeerList_Response
For the moment is working without it
*/
//to the peer that has sent the peerList, we send our PeersList
var msg Msg
msg.Construct("PeersList_Response", "here my outcomingPeersList")
msg.PeersList = globalTP.PeersConnections.Outcoming
msgB := msg.ToBytes()
_, err := peer.Conn.Write(msgB)
check(err)
}
} else {
//connect to peer
if peer.ID != p.ID && peer.ID != globalTP.RunningPeer.ID {
if PeerIsInPeersList(peer, globalTP.PeersConnections.Outcoming.Peers) == -1 {
color.Red("no connection, connecting to peer: " + peer.Port)
ConnectToPeer(peer)
}
}
}
}
}
func PrintPeersList() {
fmt.Println("")
color.Blue("runningPeer.ID: " + globalTP.RunningPeer.ID)
color.Green("OUTCOMING PEERSLIST:")
for _, peer := range globalTP.PeersConnections.Outcoming.Peers {
fmt.Println(peer)
}
color.Green("INCOMING PEERSLIST:")
for _, peer := range globalTP.PeersConnections.Incoming.Peers {
fmt.Println(peer)
}
color.Green("NETWORK PEERSLIST:")
for _, peer := range globalTP.PeersConnections.Network.Peers {
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)
}
}
}*/

+ 38
- 0
peer/p2plib/utils.go

@ -0,0 +1,38 @@
package p2plib
import (
"crypto/sha256"
"encoding/base64"
"math/rand"
"net"
"strings"
)
func GetIPPortFromConn(conn net.Conn) string {
ip := GetIPFromConn(conn)
port := GetPortFromConn(conn)
return ip + ":" + port
}
func GetIPFromConn(conn net.Conn) string {
s := conn.RemoteAddr().String()
s = strings.Split(s, ":")[0]
s = strings.Trim(s, ":")
return s
}
func GetPortFromConn(conn net.Conn) string {
s := conn.RemoteAddr().String()
s = strings.Split(s, ":")[1]
s = strings.Trim(s, ":")
return s
}
func RandInt(min int, max int) int {
r := rand.Intn(max-min) + min
return r
}
func HashPeer(p Peer) string {
peerString := p.IP + ":" + p.Port
h := sha256.New()
h.Write([]byte(peerString))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
}

BIN
peer/peer


+ 26
- 0
peer/readConfig.go

@ -0,0 +1,26 @@
package main
import (
"encoding/json"
"io/ioutil"
)
//Config reads the config
type Config struct {
IP string `json:"ip"`
Port string `json:"port"`
RestIP string `json:"restip"`
RESTPort string `json:"restport"`
ServerIP string `json:"serverip"`
ServerPort string `json:"serverport"`
ServerRESTPort string `json:"serverrestport"`
}
var config Config
func readConfig(path string) {
file, err := ioutil.ReadFile(path)
check(err)
content := string(file)
json.Unmarshal([]byte(content), &config)
}

+ 47
- 0
peer/restConfig.go

@ -0,0 +1,47 @@
package main
import (
"log"
"net/http"
"time"
"github.com/gorilla/mux"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
func Logger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
name,
time.Since(start),
)
})
}
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, route.Name)
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
}
return router
}

+ 141
- 0
peer/restRoutes.go

@ -0,0 +1,141 @@
package main
import (
"encoding/json"
"fmt"
"net/http"
blockchainlib "./blockchainlib"
p2plib "./p2plib"
"github.com/fatih/color"
"github.com/gorilla/mux"
)
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
Route{
"GetPeers",
"GET",
"/peers",
GetPeers,
},
Route{
"PostUser",
"POST",
"/register",
PostUser,
},
Route{
"GenesisBlock",
"GET",
"/blocks/genesis",
GenesisBlock,
},
Route{
"NextBlock",
"GET",
"/blocks/next/{blockhash}",
NextBlock,
},
Route{
"LastBlock",
"GET",
"/blocks/last",
LastBlock,
},
}
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, tp.ID)
}
func GetPeers(w http.ResponseWriter, r *http.Request) {
jResp, err := json.Marshal(tp.PeersConnections.Outcoming)
check(err)
fmt.Fprintln(w, string(jResp))
}
func PostUser(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
var address string
err := decoder.Decode(&address)
if err != nil {
panic(err)
}
defer r.Body.Close()
fmt.Println(address)
color.Blue(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))
}
func PropagateBlock(b blockchainlib.Block) {
//prepare the msg to send to all connected peers
var msg p2plib.Msg
msg.Construct("Block", "new block")
bJson, err := json.Marshal(b)
check(err)
msg.Data = []byte(bJson)
msgB := msg.ToBytes()
for _, peer := range tp.PeersConnections.Outcoming.Peers {
if peer.Conn != nil {
_, err := peer.Conn.Write(msgB)
check(err)
}
}
}
func GenesisBlock(w http.ResponseWriter, r *http.Request) {
var genesis blockchainlib.Block
if len(blockchain.Blocks) >= 0 {
genesis = blockchain.Blocks[0]
}
jResp, err := json.Marshal(genesis)
check(err)
fmt.Fprintln(w, string(jResp))
}
func NextBlock(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
blockhash := vars["blockhash"]
currBlock, err := blockchain.GetBlockByHash(blockhash)
check(err)
nextBlock, err := blockchain.GetBlockByHash(currBlock.NextHash)
check(err)
jResp, err := json.Marshal(nextBlock)
check(err)
fmt.Fprintln(w, string(jResp))
}
func LastBlock(w http.ResponseWriter, r *http.Request) {
var genesis blockchainlib.Block
if len(blockchain.Blocks) > 0 {
genesis = blockchain.Blocks[len(blockchain.Blocks)-1]
}
jResp, err := json.Marshal(genesis)
check(err)
fmt.Fprintln(w, string(jResp))
}

+ 20
- 0
peer/restServer.go

@ -0,0 +1,20 @@
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
)
func runRestServer() {
//run API
log.Println("server running")
log.Print("port: ")
log.Println(config.RESTPort)
router := NewRouter()
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Access-Control-Allow-Origin"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
log.Fatal(http.ListenAndServe(":"+config.RESTPort, handlers.CORS(originsOk, headersOk, methodsOk)(router)))
}

+ 1
- 0
peer/tests.sh

@ -0,0 +1 @@
curl -X POST http://127.0.0.1:3002/register -d '{\"address\": \"sampleaddress\"}'

+ 16
- 0
runTmuxTestPeers.sh

@ -0,0 +1,16 @@
SESSION='peersTest'
tmux new-session -d -s $SESSION
tmux split-window -d -t 0 -v
tmux split-window -d -t 1 -h
tmux split-window -d -t 0 -h
tmux send-keys -t 0 'cd peer && go run *.go server 3001 3002' enter
sleep 2
tmux send-keys -t 1 "curl -X POST http://127.0.0.1:3002/register -d '{\"address\": \"firstaddress\"}'" enter
sleep 1
tmux send-keys -t 1 'cd peer && go run *.go client 3003 3004' enter
tmux send-keys -t 2 'cd peer && go run *.go client 3005 3006' enter
tmux send-keys -t 3 'cd peer && go run *.go client 3007 3008' enter
tmux attach

Loading…
Cancel
Save