-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: implemented the bootloading node | @jim-nnamdi will be proud
- Loading branch information
1 parent
e9beddc
commit 80b928d
Showing
8 changed files
with
275 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
.idea | ||
.idea | ||
|
||
explanation.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,59 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"github.com/theghostmac/pluto/internal/network" | ||
"github.com/theghostmac/pluto/internal/server" | ||
"log" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
) | ||
|
||
func main() { | ||
listenAddr := flag.String("listenAddress", ":8080", "listening on the default port") | ||
flag.Parse() | ||
// two testing nodes. | ||
node1 := network.NewLocalTransport("LOCAL NODE 1") | ||
node2 := network.NewLocalTransport("LOCAL NODE 2") | ||
|
||
startServer := server.RunServer{ | ||
ListenAddr: *listenAddr, | ||
// Creating the bootloading node with a specific address | ||
bootloadingNode := network.NewLocalTransport("BOOTLOADER") | ||
// Remember to: | ||
// Initialize the blockchain next, and other networks | ||
// blockchain := InitializeBlockchain() | ||
// consensus := InitializeConsensusMechanism() | ||
// I can set any node to be the second node: | ||
err := bootloadingNode.Connect(node1) | ||
if err != nil { | ||
return | ||
} | ||
// TODO: delete the bootloadingNode impl. | ||
|
||
err = node1.Connect(node2) | ||
if err != nil { | ||
return | ||
} | ||
err = node2.Connect(node1) | ||
if err != nil { | ||
return | ||
} | ||
|
||
go func() { | ||
err := startServer.Run() | ||
if err != nil { | ||
log.Fatalf("Server failed to start: %v", err) | ||
for { | ||
err := node2.SendAMessage(node1.Address(), []byte("Hey, Node1, I need some cash!")) | ||
if err != nil { | ||
fmt.Printf("Failed to send a message to node 2 due to: %v", err) | ||
} | ||
time.Sleep(1 * time.Second) | ||
} | ||
}() | ||
|
||
stopChan := make(chan os.Signal, 1) | ||
signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM) | ||
<-stopChan | ||
// ------> RPC Server <------ | ||
ops := server.ServerOperations{ | ||
Transports: []network.Transporter{node1}, | ||
} | ||
|
||
serve := server.NewServer(ops) | ||
|
||
// Run server in a separate goroutine, add go in front of this: | ||
serve.StartServer() | ||
|
||
startServer.Shutdown() | ||
// Send a signal to the quitChannel to stop the server. | ||
serve.QuitChannel <- struct{}{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,88 @@ | ||
# Explanation | ||
# Blockchain Engineering from first principles | ||
This article is for people who already know what the blockchain is, and probably already build software | ||
around it. It is inspired by my journey to relearn blockchain technology beyond the surface. While I do | ||
this, I try to build a blockchain from scratch using the Go programming language. | ||
|
||
The runner and server (learned from a friend) is a way to startup and shut down a server gracefully. | ||
# Introducing blockchain | ||
Blockchain is a peer-to-peer, distributed ledger that is cryptographically secure, append-only, immutable, | ||
and update-able only via consensus among peers. | ||
## Definition of terms. | ||
1. Peer-to-peer means there is no central controller of the network, and all participants (called nodes) | ||
talk to each other directly. | ||
2. Distributed ledger means that the ledger is spread across the network among all peers in the network, | ||
each peer holding a copy of the complete ledger. | ||
3. Cryptographically secure means that the ledger is secured from tampering and misuse using | ||
cryptographic algorithms. | ||
4. Append-only means that data can only be added, and not modified or tampered. Also, the data | ||
is added to the blockchain in time-sequential order. | ||
5. Update-able via consensus means that a consensus mechanism is used to enable decentralization | ||
on the blockchain. | ||
|
||
Nodes communicate via remote procedure calls (RPCs), so the local blockchain network will use RPC. Benefit is that | ||
it abstracts network details, supports interoperability (bridging communication between nodes), serialize & deserialize, etc. | ||
From the following fundamental definition of blockchain, it is obvious that a blockchain | ||
engineer must be versed in: | ||
1. distributed systems - I recommend Distributed Systems for Practitioners book | ||
2. writing immutable code, | ||
3. cryptography - I recommend Cryptographic Algorithms | ||
4. mathematics, and | ||
5. computer networking. | ||
|
||
In addition to all of these recommendations, you can add Wikipedia, and any other resources you find. | ||
It's helpful to listen to experts talk, so videos might be good too. | ||
|
||
# Blockchain Architecture | ||
Blockchain is a network with different layers. It is similar to HTTP, FTP, etc., which | ||
runs on the TCP/IP model. Just as the TCP/IP networking model has 4 layers, the blockchain networking model | ||
has 6 layers: | ||
- Application: | ||
- Smart contracts | ||
- Decentralized applications | ||
- Decentralized autonomous organizations | ||
- Autonomous agents | ||
- Execution: | ||
- Virtual machines | ||
- Blocks | ||
- Transactions | ||
- Consensus: | ||
- State machine replication | ||
- Proof-based consensus | ||
- Traditional Byzantine fault-tolerant protocols | ||
- Cryptography: | ||
- Public key cryptography | ||
- Digital signatures | ||
- Hash functions | ||
- P2P: | ||
- Gossip protocols / Epidemic protocols | ||
- Routing protocols | ||
- Flooding protocols | ||
- Network: | ||
- The internet | ||
- TCP/IP | ||
|
||
From the list, it is obvious that the Network layer is the lowest layer. So in building a | ||
blockchain from scratch, it is best to start from the Network layer. | ||
|
||
## The Network layer | ||
Blockchain nodes communicate using remote procedure calls. | ||
|
||
Network connections are also built on top of hardware that will also fail at some | ||
point and we should design our systems accordingly. | ||
|
||
### Basics and Mechanics | ||
The mechanics of the blockchain can be broken down into the following: | ||
|
||
1. **Node Communication**: In a blockchain, nodes communicate via a peer-to-peer network protocol. While it's not exactly like a normal web server, you can think of it as a distributed network where nodes share information directly. | ||
|
||
2. **Initial Information**: New nodes can bootstrap by connecting to existing nodes, which provide them with information about the blockchain's current state. | ||
|
||
3. **Coin Transactions**: People buy coins by interacting with the blockchain's protocol. In some cases, they might exchange value through these interactions. | ||
|
||
4. **Storing Data**: The blockchain's data structure stores transaction data in blocks, which are linked together in a chain. Each node maintains a copy of this data. | ||
|
||
5. **RPC Endpoints**: RPC endpoints allow external applications to communicate with nodes for retrieving data or submitting transactions. | ||
|
||
6. **Central Servers**: While blockchains are decentralized, the concept of a central server doesn't apply in the same way. However, some blockchains might have centralized components like explorer websites that display blockchain data. | ||
|
||
7. **Data Propagation**: Nodes in a blockchain network communicate to propagate new transactions and blocks. This is done through a consensus protocol, ensuring that all nodes eventually agree on the state of the blockchain. | ||
|
||
8. **Writing Code**: Writing code is indeed an essential part of becoming a blockchain engineer, but understanding the underlying concepts is equally important. You're on the right track by digging into the fundamentals. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,53 @@ | ||
package server | ||
|
||
import ( | ||
"errors" | ||
"github.com/gorilla/mux" | ||
"github.com/sirupsen/logrus" | ||
"net/http" | ||
"os" | ||
"fmt" | ||
"github.com/theghostmac/pluto/internal/network" | ||
"time" | ||
) | ||
|
||
type GracefulShutdown struct { | ||
ListenAddr string | ||
BaseHandler http.Handler | ||
httpServer *http.Server | ||
type ServerOperations struct { | ||
Transports []network.Transporter | ||
} | ||
|
||
func (server *GracefulShutdown) getRouter() *mux.Router { | ||
router := mux.NewRouter() | ||
router.SkipClean(true) | ||
router.Handle("/", server.BaseHandler) | ||
return router | ||
type Server struct { | ||
ServerOperations | ||
RPCChannel chan network.RPC | ||
QuitChannel chan struct{} | ||
} | ||
|
||
func (server *GracefulShutdown) Start() { | ||
router := server.getRouter() | ||
server.httpServer = &http.Server{ | ||
Addr: server.ListenAddr, | ||
Handler: router, | ||
func NewServer(operations ServerOperations) *Server { | ||
return &Server{ | ||
ServerOperations: operations, | ||
RPCChannel: make(chan network.RPC), | ||
QuitChannel: make(chan struct{}, 1), | ||
} | ||
logrus.Infof("Server listening on %s ", server.ListenAddr) | ||
logrus.Info("Pluto is active 🚀") | ||
} | ||
|
||
func (s *Server) StartServer() { | ||
s.InitializeTransports() | ||
ticker := time.NewTicker(5 * time.Second) | ||
|
||
if err := server.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { | ||
logrus.Fatalf("Server error: %v", err) | ||
free: | ||
for { | ||
select { | ||
case rpc := <-s.RPCChannel: | ||
fmt.Printf("%+v", rpc) | ||
case <-s.QuitChannel: | ||
break free | ||
case <-ticker.C: | ||
fmt.Println("Interacting with blocks every 500 milli seconds.") | ||
} | ||
} | ||
fmt.Println("Server shutdown...") | ||
} | ||
|
||
func (server *GracefulShutdown) Shutdown() { | ||
logrus.Info("Shutting down server...") | ||
|
||
if err := server.httpServer.Shutdown(nil); err != nil { | ||
logrus.Errorf("Error during server shutdown: %v", err) | ||
func (s *Server) InitializeTransports() { | ||
for _, trans := range s.Transports { | ||
go func(trans network.Transporter) { | ||
for rpc := range trans.Consume() { | ||
s.RPCChannel <- rpc | ||
} | ||
}(trans) | ||
} | ||
logrus.Info("Server shutdown complete.") | ||
os.Exit(0) | ||
} |
Oops, something went wrong.