From abb1ca9b5d952af0faf13dd799053802ef2069e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 13:21:14 +0100 Subject: [PATCH 01/10] setup vscode project --- .gitignore | 2 ++ .vscode/tasks.json | 21 +++++++++++++++++++++ Readme.md | 11 +++++++++++ 3 files changed, 34 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/tasks.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4b94bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +go.sum \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..05a44fe --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "go", + "label": "go: build package", + "command": "build", + "args": [ + "-o", + "build/${fileBasenameNoExtension}" + ], + "problemMatcher": [ + "$go" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "group": "build" + } + ] +} \ No newline at end of file diff --git a/Readme.md b/Readme.md index 9e6ff90..c35f2e6 100644 --- a/Readme.md +++ b/Readme.md @@ -15,8 +15,19 @@ insecure and incomplete. you can learn the basic operation of the blockchain thr How to run ------ + + ## Build +Install deps: + + +```shell script +go mod tidy +``` + +build it: + ```shell script go build ./cmd/cli ``` From f3738491913815b52068b1b50207cb95937287ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 15:22:57 +0100 Subject: [PATCH 02/10] make it respect full addresses --- .gitignore | 4 +- .vscode/tasks.json | 17 +++---- Readme.md | 18 ++++++-- cmd/flags.go | 11 +++-- cmd/servercmd.go | 16 +++++-- server.go | 108 +++++++++------------------------------------ 6 files changed, 67 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index d4b94bb..d312145 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ build/ -go.sum \ No newline at end of file +go.sum +wallet_* +simpleBlockchain_*.db \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 05a44fe..664d83f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,20 +2,21 @@ "version": "2.0.0", "tasks": [ { - "type": "go", - "label": "go: build package", - "command": "build", - "args": [ - "-o", - "build/${fileBasenameNoExtension}" - ], + "type": "shell", + "label": "build", + "command": "go build cmd/cli/main.go && mkdir -p build && mv main build/main", "problemMatcher": [ "$go" ], "options": { "cwd": "${workspaceFolder}" }, - "group": "build" + "group": "build", + "presentation": { + "reveal": "silent", + "revealProblems": "onProblem", + "close": true + } } ] } \ No newline at end of file diff --git a/Readme.md b/Readme.md index c35f2e6..8b24363 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,4 @@ -Simple Blockchain ------- +# Simple Blockchain This repository contains the golang code of a simple blockchain implementation. @@ -12,9 +11,20 @@ There are many part are not like real blockchain because it's just simple implem insecure and incomplete. you can learn the basic operation of the blockchain through this project. -How to run ------- +# Notes: + +- This only supports two nodes. + + +## changes from zweieuro (author): +- The peers were saved in an array, but there are only ever 2 + - reduced to a single string, making management easier + - removed file that wrote the peers down, no reason to have this in this case +- Make the peers' address respect port or address, resolve THAT address + - Same functionality with non is given as before, localhost works as expected + +# How to run ## Build diff --git a/cmd/flags.go b/cmd/flags.go index ce899b6..ad80cf8 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -5,10 +5,15 @@ import ( ) var ( + peernodeaddressflag = &cli.StringFlag{ + Name: "partnerNodeAddress", + Usage: "partner node address, either addr:port or just port", + Required: true, + } nodeportFlag = &cli.IntFlag{ Name: "nodeport", - Usage: "nodeport", - Value: 3000, + Usage: "nodeport always runs on localhost, the node which your partner has uses as 'peer'", + Required: true, } apiportFlag = &cli.IntFlag{ Name: "apiport", @@ -31,7 +36,7 @@ var ( isminingFlag = &cli.BoolFlag{ Name: "ismining", Usage: "ismining", - Required: true, + Value: false, } toFlag = &cli.StringFlag{ Name: "to", diff --git a/cmd/servercmd.go b/cmd/servercmd.go index 109afe1..3c2d364 100644 --- a/cmd/servercmd.go +++ b/cmd/servercmd.go @@ -2,9 +2,11 @@ package cmd import ( "fmt" + "os" + "strconv" + "github.com/tn606024/simpleBlockchain" "github.com/urfave/cli/v2" - "os" ) var ( @@ -12,19 +14,27 @@ var ( Name: "start", Usage: "start blockchain server", Description: "start blockchain server", - ArgsUsage: "", + ArgsUsage: " ", Flags: []cli.Flag{ nodeportFlag, + peernodeaddressflag, apiportFlag, walletnameFlag, isminingFlag, }, Action: func(c *cli.Context) error { + // check if peerNodeAddressFlag is just a number (port) + // if so, prepend "localhost:" to it + peerNodeAddress := c.String("partnerNodeAddress") + if _, err := strconv.Atoi(peerNodeAddress); err == nil { + peerNodeAddress = "localhost:" + peerNodeAddress + } + nodeport := c.Int("nodeport") apiport := c.Int("apiport") walletname := c.String("walletname") ismining := c.Bool("ismining") - server := simpleBlockchain.NewServer(nodeport, apiport, walletname, ismining) + server := simpleBlockchain.NewServer(nodeport, peerNodeAddress, apiport, walletname, ismining) server.StartServer() return nil }, diff --git a/server.go b/server.go index fcde001..ed2f022 100644 --- a/server.go +++ b/server.go @@ -1,7 +1,6 @@ package simpleBlockchain import ( - "github.com/gin-gonic/gin" "bytes" "encoding/json" "fmt" @@ -10,6 +9,8 @@ import ( "net" "net/http" "sync" + + "github.com/gin-gonic/gin" ) const ( @@ -17,13 +18,10 @@ const ( protocal = "tcp" ) -var KnownNodes = []string{ - "localhost:3000", - "localhost:3001", -} - var knownNodeName = "knownnodes_%d.txt" +var knnownAddrFileName = "knownAddresses.txt" + type MessageHeader string const ( @@ -145,7 +143,7 @@ type Server struct { utxos []*UTXO nodeport int apiport int - knownNodes []string + peerNodeAddress string connectMap map[string]bool blockMap map[string]int blockchain *BlockChain @@ -155,82 +153,36 @@ type Server struct { -func NewServer(nodeport int, apiport int, walletName string, isMining bool) *Server{ - node := fmt.Sprintf("localhost:%d",nodeport) +func NewServer(nodeport int, peerNodeAddress string, apiport int, walletName string, isMining bool) *Server{ wallet, err := GetExistWallet(walletName) - addrs, _:=wallet.getAddresses() - blockchain := NewBlockChain(addrs[0],nodeport, isMining) - if err != nil { - panic(err) - } - knownNodes, err := NewKnownNodes(nodeport) if err != nil { panic(err) } + + addrs, _ := wallet.getAddresses() + blockchain := NewBlockChain(addrs[0],nodeport, isMining) + + var nodeAddress = fmt.Sprintf("localhost:%d", nodeport) + connectMap := make(map[string]bool,0) blockMap := make(map[string]int,0) utxos := make([]*UTXO,0) s:= &Server{ - node: node, + node: nodeAddress, wallet: wallet, utxos: utxos, nodeport: nodeport, apiport: apiport, - knownNodes: knownNodes, + peerNodeAddress: peerNodeAddress, blockchain: blockchain, connectMap: connectMap, blockMap: blockMap, } + s.ScanWalletUTXOs() return s } -func NewKnownNodes(port int) ([]string, error){ - var knownNodes []string - nodefile := fmt.Sprintf(knownNodeName,port) - if IsFileExists(nodefile) == false { - bkn, _ := json.Marshal(KnownNodes) - err := ioutil.WriteFile(nodefile, bkn, 0644) - if err != nil{ - return nil, err - } - } - b, err := ioutil.ReadFile(fmt.Sprintf(knownNodeName,port)) - if err != nil { - return nil, err - } - err = json.Unmarshal(b, &knownNodes) - if err != nil { - return nil, err - } - return knownNodes, nil -} - -func (s *Server) AddKnownNode(knownNode string) error{ - s.mutex.Lock() - s.knownNodes = append(s.knownNodes, knownNode) - bkn, _ := json.Marshal(s.knownNodes) - s.mutex.Unlock() - nodefile := fmt.Sprintf(knownNodeName, s.nodeport) - err := ioutil.WriteFile(nodefile, bkn, 0644) - if err != nil { - return err - } - return nil -} - -func (s *Server) SearchKnownNode(knownNode string) bool { - s.mutex.Lock() - for _, node := range s.knownNodes{ - if node == knownNode{ - s.mutex.Unlock() - return true - } - } - s.mutex.Unlock() - return false -} - func (s *Server) StartServer() { ln, err := net.Listen(protocal, s.node) if err != nil { @@ -436,28 +388,16 @@ func (s *Server) MiningEmptyBlockAndBroadcast() (*Block,error) { return blk, nil } func (s *Server) broadcastVersion(){ - for _, knownNode := range s.knownNodes { - if knownNode != s.node { - s.sendVersion(knownNode) - } - } + s.sendVersion(s.peerNodeAddress) } func (s *Server) broadcastBlock(block *Block){ - for _, knownNode := range s.knownNodes{ - if knownNode != s.node { - s.sendBlock(knownNode, []*Block{block}) - } - } + s.sendBlock(s.peerNodeAddress, []*Block{block}) } func (s *Server) broadcastTx(tx *Transaction){ - for _, knownNode := range s.knownNodes{ - if knownNode != s.node { - s.sendTx(knownNode, tx) - } - } + s.sendTx(s.peerNodeAddress, tx) } @@ -498,9 +438,6 @@ func (s *Server) handleVersion(payload json.RawMessage){ } logHandleMsg(VersionMsgHeader, &versionMsg) if versionMsg.Version == blockchainVersion { - if !s.SearchKnownNode(versionMsg.AddrFrom) { - s.AddKnownNode(versionMsg.AddrFrom) - } s.mutex.Lock() s.blockMap[versionMsg.AddrFrom] = versionMsg.StartHeight conn, ok := s.connectMap[versionMsg.AddrFrom] @@ -712,12 +649,7 @@ func (s *Server) handleTx(payload json.RawMessage) { Type: "block", Hash: []Hashes{blk.newHash()}, } - for _, knownNode := range s.knownNodes { - if knownNode != s.node { - s.sendInv(knownNode, &invMsg) - } - } - + s.sendInv(s.peerNodeAddress, &invMsg) } func (s *Server) sendVersion(addr string){ @@ -844,7 +776,7 @@ func (s *Server) send(addr string, data []byte) error{ delete(s.blockMap, addr) delete(s.connectMap, addr) //s.deleteKnownNodes(addr) - return fmt.Errorf("%s is not online \n", addr) + return fmt.Errorf("%s is not online ", addr) } defer conn.Close() _, err = io.Copy(conn, bytes.NewReader(data)) From bb2ef5259cf9b63898423ebf51ee5de0699524ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 15:32:22 +0100 Subject: [PATCH 03/10] setup docker compose and fix flag naming --- cmd/flags.go | 2 +- docker_compose/Dockerfile | 13 +++++++++++ docker_compose/docker-compose.yml | 29 +++++++++++++++++++++++++ docker_compose/existingWallets/.gitkeep | 0 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docker_compose/Dockerfile create mode 100644 docker_compose/docker-compose.yml create mode 100644 docker_compose/existingWallets/.gitkeep diff --git a/cmd/flags.go b/cmd/flags.go index ad80cf8..4658088 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -6,7 +6,7 @@ import ( var ( peernodeaddressflag = &cli.StringFlag{ - Name: "partnerNodeAddress", + Name: "peernodeaddressflag", Usage: "partner node address, either addr:port or just port", Required: true, } diff --git a/docker_compose/Dockerfile b/docker_compose/Dockerfile new file mode 100644 index 0000000..2d95426 --- /dev/null +++ b/docker_compose/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.23 + +WORKDIR /app + +RUN git clone https://github.com/ZweiEuro/simpleBlockchain + + +WORKDIR /app/simpleBlockchain +# download dependencies + +RUN go mod tidy + +RUN go build ./cmd/cli diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml new file mode 100644 index 0000000..4998a7e --- /dev/null +++ b/docker_compose/docker-compose.yml @@ -0,0 +1,29 @@ +services: + blockchain_alice: + build: + context: ./ + dockerfile: ./Dockerfile + container_name: blockchain_alice + ports: # redirect ports to some starting with 70 + - "7090:3000" # nodeport + - "7080:8080" # apiport + volumes: + - ./simpleBlockchain_alice.db:/app/simpleBlockchain/simpleBlockchain_3000.db + - ./existingWallets/wallet_alice:/app/simpleBlockchain/wallet_alice + command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7091 -walletname alice -ismining=true + blockchain_bob: + build: + context: ./ + dockerfile: ./Dockerfile + container_name: blockchain_bob + ports: # redirect ports to some starting with 70 + - "7091:3000" # nodeport + - "7081:8080" # apiport + volumes: + - ./simpleBlockchain_bank.db:/app/simpleBlockchain/simpleBlockchain_3000.db + - ./existingWallets/wallet_bank:/app/simpleBlockchain/wallet_bank + command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7090 -walletname bank + + # Alice also lives on our server, + # This is rather unrealistic since that means that the servers docker composer is doing + # the mining as well, but it makes it very portable \ No newline at end of file diff --git a/docker_compose/existingWallets/.gitkeep b/docker_compose/existingWallets/.gitkeep new file mode 100644 index 0000000..e69de29 From 7e997c136c0f52eb18e92ebad4771aa796d0a130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 16:02:53 +0100 Subject: [PATCH 04/10] also create a dir to mount back the actual db --- .gitignore | 3 ++- blockchain.go | 19 ++++++++++++++++--- cmd/flags.go | 2 +- docker_compose/docker-compose.yml | 10 +++------- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index d312145..d8981c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ go.sum wallet_* -simpleBlockchain_*.db \ No newline at end of file +simpleBlockchain_*.db +blockchain/ \ No newline at end of file diff --git a/blockchain.go b/blockchain.go index d0e2dc2..960efec 100644 --- a/blockchain.go +++ b/blockchain.go @@ -6,10 +6,12 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/boltdb/bolt" "log" "math/big" + "os" "sync" + + "github.com/boltdb/bolt" ) var genesisBlock = &Block{ @@ -70,9 +72,9 @@ var genesisBlock = &Block{ }, } +var dbFolderName = "blockchain" - -var dbSigName = "simpleBlockchain_%d.db" +var dbSigName = dbFolderName + "/simpleBlockchain_%d.db" type BlockChain struct { db *bolt.DB @@ -128,6 +130,17 @@ func NewBlockChain(address string, port int, isMining bool) *BlockChain { func CreateBlockChain(address string, port int, isMining bool) *BlockChain { dbName := fmt.Sprintf(dbSigName, port) + + // create the folder if it does not exist + stat, err := os.Stat(dbFolderName) + + if err != nil || stat == nil || stat.IsDir() == false { + err := os.Mkdir(dbFolderName, 0755) + if err != nil { + panic(err) + } + } + db, err := bolt.Open(dbName, 0600, nil) if err != nil { panic(err) diff --git a/cmd/flags.go b/cmd/flags.go index 4658088..914a620 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -6,7 +6,7 @@ import ( var ( peernodeaddressflag = &cli.StringFlag{ - Name: "peernodeaddressflag", + Name: "peernodeaddress", Usage: "partner node address, either addr:port or just port", Required: true, } diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index 4998a7e..9ff5737 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -8,7 +8,7 @@ services: - "7090:3000" # nodeport - "7080:8080" # apiport volumes: - - ./simpleBlockchain_alice.db:/app/simpleBlockchain/simpleBlockchain_3000.db + - ./blockchain_alice/:/app/simpleBlockchain/blockchain/ - ./existingWallets/wallet_alice:/app/simpleBlockchain/wallet_alice command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7091 -walletname alice -ismining=true blockchain_bob: @@ -20,10 +20,6 @@ services: - "7091:3000" # nodeport - "7081:8080" # apiport volumes: - - ./simpleBlockchain_bank.db:/app/simpleBlockchain/simpleBlockchain_3000.db + - ./blockchain_bob/:/app/simpleBlockchain/blockchain/ - ./existingWallets/wallet_bank:/app/simpleBlockchain/wallet_bank - command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7090 -walletname bank - - # Alice also lives on our server, - # This is rather unrealistic since that means that the servers docker composer is doing - # the mining as well, but it makes it very portable \ No newline at end of file + command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7090 -walletname bank \ No newline at end of file From 35df21f7bdf104dc029b7c76426e17925250c483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 16:07:08 +0100 Subject: [PATCH 05/10] fix error in arg param --- cmd/servercmd.go | 2 +- docker_compose/.gitignore | 1 + docker_compose/docker-compose.yml | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 docker_compose/.gitignore diff --git a/cmd/servercmd.go b/cmd/servercmd.go index 3c2d364..998c1fa 100644 --- a/cmd/servercmd.go +++ b/cmd/servercmd.go @@ -25,7 +25,7 @@ var ( Action: func(c *cli.Context) error { // check if peerNodeAddressFlag is just a number (port) // if so, prepend "localhost:" to it - peerNodeAddress := c.String("partnerNodeAddress") + peerNodeAddress := c.String("peernodeaddress") if _, err := strconv.Atoi(peerNodeAddress); err == nil { peerNodeAddress = "localhost:" + peerNodeAddress } diff --git a/docker_compose/.gitignore b/docker_compose/.gitignore new file mode 100644 index 0000000..0af9ead --- /dev/null +++ b/docker_compose/.gitignore @@ -0,0 +1 @@ +blockchain_*/ \ No newline at end of file diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index 9ff5737..6612596 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -10,7 +10,7 @@ services: volumes: - ./blockchain_alice/:/app/simpleBlockchain/blockchain/ - ./existingWallets/wallet_alice:/app/simpleBlockchain/wallet_alice - command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7091 -walletname alice -ismining=true + command: ./cli server start -nodeport 3000 -peernodeaddress blockchain_bob:7091 -walletname alice -ismining=true blockchain_bob: build: context: ./ @@ -22,4 +22,4 @@ services: volumes: - ./blockchain_bob/:/app/simpleBlockchain/blockchain/ - ./existingWallets/wallet_bank:/app/simpleBlockchain/wallet_bank - command: ./cli server start -nodeport 3000 -peernodeaddressflag blockchain_bob:7090 -walletname bank \ No newline at end of file + command: ./cli server start -nodeport 3000 -peernodeaddress blockchain_bob:7090 -walletname bank \ No newline at end of file From fabb24c0d3058716d5b236eb4c8edc644b365a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 16:26:27 +0100 Subject: [PATCH 06/10] Fix port error, allow changing of addr for localhost own port --- cmd/flags.go | 10 +++++----- cmd/servercmd.go | 15 ++++++++++----- docker_compose/docker-compose.yml | 26 ++++++++++++++----------- server.go | 32 ++++++++++++++++++++++++------- 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/cmd/flags.go b/cmd/flags.go index 914a620..6882180 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -5,15 +5,15 @@ import ( ) var ( - peernodeaddressflag = &cli.StringFlag{ + peernodeaddressFlag = &cli.StringFlag{ Name: "peernodeaddress", Usage: "partner node address, either addr:port or just port", Required: true, } - nodeportFlag = &cli.IntFlag{ - Name: "nodeport", - Usage: "nodeport always runs on localhost, the node which your partner has uses as 'peer'", - Required: true, + nodeaddressFlag = &cli.StringFlag{ + Name: "nodeaddress", + Usage: "what address is this node reachable under, addr:port or port (localhost)", + Required: true, } apiportFlag = &cli.IntFlag{ Name: "apiport", diff --git a/cmd/servercmd.go b/cmd/servercmd.go index 998c1fa..54b04c1 100644 --- a/cmd/servercmd.go +++ b/cmd/servercmd.go @@ -14,10 +14,10 @@ var ( Name: "start", Usage: "start blockchain server", Description: "start blockchain server", - ArgsUsage: " ", + ArgsUsage: " ", Flags: []cli.Flag{ - nodeportFlag, - peernodeaddressflag, + nodeaddressFlag, + peernodeaddressFlag, apiportFlag, walletnameFlag, isminingFlag, @@ -30,11 +30,16 @@ var ( peerNodeAddress = "localhost:" + peerNodeAddress } - nodeport := c.Int("nodeport") + nodeaddress := c.String("nodeaddress") + if _, err := strconv.Atoi(nodeaddress); err == nil { + nodeaddress = "localhost:" + nodeaddress + } + + apiport := c.Int("apiport") walletname := c.String("walletname") ismining := c.Bool("ismining") - server := simpleBlockchain.NewServer(nodeport, peerNodeAddress, apiport, walletname, ismining) + server := simpleBlockchain.NewServer(nodeaddress, peerNodeAddress, apiport, walletname, ismining) server.StartServer() return nil }, diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index 6612596..c30e927 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -4,22 +4,26 @@ services: context: ./ dockerfile: ./Dockerfile container_name: blockchain_alice - ports: # redirect ports to some starting with 70 - - "7090:3000" # nodeport - - "7080:8080" # apiport + expose: + - "3000" # nodeport, only needed between nodes + ports: + - "7080:8080" # apiport, accessed from your command line volumes: - - ./blockchain_alice/:/app/simpleBlockchain/blockchain/ - - ./existingWallets/wallet_alice:/app/simpleBlockchain/wallet_alice - command: ./cli server start -nodeport 3000 -peernodeaddress blockchain_bob:7091 -walletname alice -ismining=true + - ./blockchain_alice/:/app/simpleBlockchain/blockchain/ + - ./existingWallets/wallet_alice:/app/simpleBlockchain/wallet_alice + command: ./cli server start -nodeport blockchain_alice:3000 -peernodeaddress blockchain_bob:3000 -walletname alice -ismining=true blockchain_bob: build: context: ./ dockerfile: ./Dockerfile container_name: blockchain_bob - ports: # redirect ports to some starting with 70 - - "7091:3000" # nodeport - - "7081:8080" # apiport + expose: + - "3000" # nodeport, only needed between nodes + ports: + - "7081:8080" # apiport, accessed from your command line volumes: - ./blockchain_bob/:/app/simpleBlockchain/blockchain/ - - ./existingWallets/wallet_bank:/app/simpleBlockchain/wallet_bank - command: ./cli server start -nodeport 3000 -peernodeaddress blockchain_bob:7090 -walletname bank \ No newline at end of file + - ./existingWallets/wallet_bob:/app/simpleBlockchain/wallet_bob + command: ./cli server start -nodeport blockchain_bob:3000 -peernodeaddress blockchain_alice:3000 -walletname bob + + diff --git a/server.go b/server.go index ed2f022..54d06bf 100644 --- a/server.go +++ b/server.go @@ -8,6 +8,8 @@ import ( "io/ioutil" "net" "net/http" + "strconv" + "strings" "sync" "github.com/gin-gonic/gin" @@ -141,8 +143,8 @@ type Server struct { node string wallet *Wallet utxos []*UTXO - nodeport int apiport int + nodeaddress string peerNodeAddress string connectMap map[string]bool blockMap map[string]int @@ -153,27 +155,43 @@ type Server struct { -func NewServer(nodeport int, peerNodeAddress string, apiport int, walletName string, isMining bool) *Server{ +func NewServer(nodeaddress string, peernodeaddress string, apiport int, walletName string, isMining bool) *Server{ wallet, err := GetExistWallet(walletName) if err != nil { panic(err) } addrs, _ := wallet.getAddresses() - blockchain := NewBlockChain(addrs[0],nodeport, isMining) - var nodeAddress = fmt.Sprintf("localhost:%d", nodeport) + parts := strings.Split(nodeaddress, ":"); + portNumber := 0 + if len(parts) == 1 { + // convert the port to a number + portNumber, err = strconv.Atoi(parts[0]) + if err != nil { + panic(err) + } + + }else{ + portNumber, err = strconv.Atoi(parts[1]) + if err != nil { + panic(err) + } + } + + + blockchain := NewBlockChain(addrs[0], portNumber, isMining) connectMap := make(map[string]bool,0) blockMap := make(map[string]int,0) utxos := make([]*UTXO,0) s:= &Server{ - node: nodeAddress, + node: nodeaddress, wallet: wallet, utxos: utxos, - nodeport: nodeport, + nodeaddress: nodeaddress, apiport: apiport, - peerNodeAddress: peerNodeAddress, + peerNodeAddress: peernodeaddress, blockchain: blockchain, connectMap: connectMap, blockMap: blockMap, From 9581bc0bf8c2f434df27e165619f98d26481aa30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 16:35:28 +0100 Subject: [PATCH 07/10] Fix the internal commands --- docker_compose/docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker_compose/docker-compose.yml b/docker_compose/docker-compose.yml index c30e927..466a7dd 100644 --- a/docker_compose/docker-compose.yml +++ b/docker_compose/docker-compose.yml @@ -5,25 +5,25 @@ services: dockerfile: ./Dockerfile container_name: blockchain_alice expose: - - "3000" # nodeport, only needed between nodes + - "3000" # nodeaddress, only needed between nodes ports: - "7080:8080" # apiport, accessed from your command line volumes: - ./blockchain_alice/:/app/simpleBlockchain/blockchain/ - ./existingWallets/wallet_alice:/app/simpleBlockchain/wallet_alice - command: ./cli server start -nodeport blockchain_alice:3000 -peernodeaddress blockchain_bob:3000 -walletname alice -ismining=true + command: ./cli server start -nodeaddress blockchain_alice:3000 -peernodeaddress blockchain_bob:3000 -walletname alice -ismining=true blockchain_bob: build: context: ./ dockerfile: ./Dockerfile container_name: blockchain_bob expose: - - "3000" # nodeport, only needed between nodes + - "3000" # nodeaddress, only needed between nodes ports: - "7081:8080" # apiport, accessed from your command line volumes: - ./blockchain_bob/:/app/simpleBlockchain/blockchain/ - ./existingWallets/wallet_bob:/app/simpleBlockchain/wallet_bob - command: ./cli server start -nodeport blockchain_bob:3000 -peernodeaddress blockchain_alice:3000 -walletname bob + command: ./cli server start -nodeaddress blockchain_bob:3000 -peernodeaddress blockchain_alice:3000 -walletname bob From 988b5b7c2e376789bac8bca516cdda171fcf4a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 16:45:20 +0100 Subject: [PATCH 08/10] update readme --- Readme.md | 44 ++++++++++++++++++++++++---------------- docker_compose/README.md | 0 2 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 docker_compose/README.md diff --git a/Readme.md b/Readme.md index 8b24363..56594f3 100644 --- a/Readme.md +++ b/Readme.md @@ -6,22 +6,36 @@ This blockchain consists of three parts: - A simple wallet that you can get address, scan utxos, sign transaction. - A simple blockchain can sync block from other known nodes, mining new block, send transaction and broadcast to other node. - A simple restful server you can query blocks and utxos from blockchain. +- This project only supports two nodes. There are many part are not like real blockchain because it's just simple implementation, still insecure and incomplete. you can learn the basic operation of the blockchain through this project. +## changes from zweieuro (author): +- The peers were saved in an array, but there are only ever 2 + - reduced to a single string, making management easier + - removed file that wrote the peers down, no reason to have this in this case, looks like it has no other function, removed dead code +- Make the peers' and owns' address with respect to port or address:port arguments + - Same functionality as before when only the port is specified + -# Notes: +### Docker compose users: -- This only supports two nodes. +I re-implemented some of the addressing (really it was mostly arg parsing) so that the node and its peer +can have independent base addresses. This means they are now docker container compatible. +The folder `docker_compose` shows how this might be used in your `docker-compose.yml` file. +The `docker-compose.yml` expects `existingWallets/` to have two files: +- `alice_wallet` +- `bob_wallet` -## changes from zweieuro (author): -- The peers were saved in an array, but there are only ever 2 - - reduced to a single string, making management easier - - removed file that wrote the peers down, no reason to have this in this case -- Make the peers' address respect port or address, resolve THAT address - - Same functionality with non is given as before, localhost works as expected +Of course you can rename the files as you want if you change their occurrences. + +These wallets are copied to the individual container before they start up, they will instantly crash without them. +When binding, in order to retain DB information, both DB files are linked back into a folder for each node. This is mostly due to docker volume limitations as dual binding is not really a good idea (binding the same folder of the host to two different sub-containers), especially since we _want_ separate files. + +#### Docker compose address resolution +Containers that run in docker and are declared inside a `docker-compose.yml` have a built-in hostname resolution that can make them find other containers in the same service file. They are automatically available to any container. This is what this example files uses to route data between the two node instances. # How to run @@ -49,11 +63,11 @@ go build ./cmd/cli ./cli wallet create -walletname "bob" ``` -### Start two node +### Start two nodes/start server commands ```shell script -./cli server start -nodeport 3000 -apiport 8080 -walletname "alice" -ismining=true -./cli server start -nodeport 3001 -apiport 8081 -walletname "bob" -ismining=true +./cli server start -nodeaddress 3000 -peernodeaddress 3001 -apiport 8080 -walletname "alice" -ismining=true +./cli server start -nodeaddress 3001 -peernodeaddress 3000 -apiport 8081 -walletname "bob" -ismining=true ``` ### Mining empty block to get block reward @@ -66,7 +80,7 @@ go build ./cmd/cli ./cli server sendtransaction --apiport 8080 --to "172wJyiJZxXWyBW7CYSVddsR5e7ZMxtja9" -amount 100000 ``` -threr are still have other blockchain command, you can find out by type `./cli server`. +There are still have other blockchain command, you can find out by type `./cli server`. Example @@ -78,12 +92,6 @@ Example ./cli wallet create -walletname "alice" ``` -### Start blockchain server - - ```shell script - ./cli server start -nodeport 3000 -apiport 8080 -walletname "alice" -ismining=true - ``` - ### Get blocks ```shell script diff --git a/docker_compose/README.md b/docker_compose/README.md new file mode 100644 index 0000000..e69de29 From c6d2d34917880718ad801ca1d2c83547de1fcc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 16:45:32 +0100 Subject: [PATCH 09/10] remove dead readme --- docker_compose/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docker_compose/README.md diff --git a/docker_compose/README.md b/docker_compose/README.md deleted file mode 100644 index e69de29..0000000 From 49cbcd7993b5d35e445ade1ea66281b58d05db3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=B6lkel?= Date: Thu, 5 Dec 2024 17:09:41 +0100 Subject: [PATCH 10/10] add some more information to curl and manual sending of data --- Readme.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Readme.md b/Readme.md index 56594f3..d80dadb 100644 --- a/Readme.md +++ b/Readme.md @@ -29,15 +29,53 @@ The `docker-compose.yml` expects `existingWallets/` to have two files: - `alice_wallet` - `bob_wallet` +WARNING: If the wallet files are missing docker will attempt to bind directories instead! This will also crash. Additionally docker might make them write-protected. Remove them at your own discretion. + + Of course you can rename the files as you want if you change their occurrences. These wallets are copied to the individual container before they start up, they will instantly crash without them. + + When binding, in order to retain DB information, both DB files are linked back into a folder for each node. This is mostly due to docker volume limitations as dual binding is not really a good idea (binding the same folder of the host to two different sub-containers), especially since we _want_ separate files. + + #### Docker compose address resolution Containers that run in docker and are declared inside a `docker-compose.yml` have a built-in hostname resolution that can make them find other containers in the same service file. They are automatically available to any container. This is what this example files uses to route data between the two node instances. +## Running commands without compiling your own version: +Since you already have a node running inside docker containers, it seems a bit backwards to then compile again just to talk to it. +You can either: Start a shell inside your container and run it from there, which i find quite cumbersome. + +alternatively: You can run the commands raw. The commands are specified in `servercmd.go` and their respective endpoint can be found in `conn.go`. +This has the nice effect of letting us craft our own requests. +Here we also see the main security problem, the server is very unprotected, these requests have no kind of confirmation. + +One raw curl request might look like this: +```shell +curl -i -X POST \ + -H "Content-Type:application/json" \ + -d \ + '{ + "To": "1LHroFft5WAxZTqXizQJjBJrPwkVQFAcsa", + "Amount": 200 + }' \ + 'http://localhost:7080/wallet/send' + +``` + +Which read quite easily. Transfer 200 coins to the given public key. + +Mining is now a simple get request: +```shell +curl -i -X GET \ + 'http://localhost:7080/chain/mining' + ``` + + + # How to run