forked from TrueCloudLab/neoneo-go
Implemented NetMode type.
This commit is contained in:
parent
536a499236
commit
b94c9b4b57
3 changed files with 72 additions and 47 deletions
|
@ -10,6 +10,7 @@ import (
|
||||||
var (
|
var (
|
||||||
port = flag.String("port", ":3000", "port the TCP listener will listen on.")
|
port = flag.String("port", ":3000", "port the TCP listener will listen on.")
|
||||||
seed = flag.String("seed", "", "initial seed servers.")
|
seed = flag.String("seed", "", "initial seed servers.")
|
||||||
|
net = flag.Int("net", 56753, "the mode the server will operate in.")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Simple dirty and quick bootstrapping for the sake of development.
|
// Simple dirty and quick bootstrapping for the sake of development.
|
||||||
|
@ -19,7 +20,7 @@ var (
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
s := network.NewServer(network.ModeTestNet)
|
s := network.NewServer(network.NetMode(*net))
|
||||||
seeds := strings.Split(*seed, ",")
|
seeds := strings.Split(*seed, ",")
|
||||||
if len(seeds) == 0 {
|
if len(seeds) == 0 {
|
||||||
seeds = []string{*seed}
|
seeds = []string{*seed}
|
||||||
|
|
|
@ -8,11 +8,33 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// The minimum size of a valid message.
|
||||||
|
minMessageSize = 24
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetMode type that is compatible with netModes below.
|
||||||
|
type NetMode uint32
|
||||||
|
|
||||||
|
// String implements the stringer interface.
|
||||||
|
func (n NetMode) String() string {
|
||||||
|
switch n {
|
||||||
|
case ModeDevNet:
|
||||||
|
return "devnet"
|
||||||
|
case ModeTestNet:
|
||||||
|
return "testnet"
|
||||||
|
case ModeMainNet:
|
||||||
|
return "mainnet"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Values used for the magic field, according to the docs.
|
// Values used for the magic field, according to the docs.
|
||||||
const (
|
const (
|
||||||
ModeMainNet = 0x00746e41 // 7630401
|
ModeMainNet NetMode = 0x00746e41 // 7630401
|
||||||
ModeTestNet = 0x74746e41 // 1953787457
|
ModeTestNet = 0x74746e41 // 1953787457
|
||||||
// ModeDevNet = 0xDEADBEAF
|
ModeDevNet = 56753 // docker privnet
|
||||||
)
|
)
|
||||||
|
|
||||||
// Message is the complete message send between nodes.
|
// Message is the complete message send between nodes.
|
||||||
|
@ -25,7 +47,7 @@ const (
|
||||||
// 4 Checksum uint32 Checksum
|
// 4 Checksum uint32 Checksum
|
||||||
// length Payload uint8[length] Content of message
|
// length Payload uint8[length] Content of message
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Magic uint32
|
Magic NetMode
|
||||||
// Command is utf8 code, of which the length is 12 bytes,
|
// Command is utf8 code, of which the length is 12 bytes,
|
||||||
// the extra part is filled with 0.
|
// the extra part is filled with 0.
|
||||||
Command []byte
|
Command []byte
|
||||||
|
@ -55,7 +77,7 @@ const (
|
||||||
cmdTX = "tx"
|
cmdTX = "tx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newMessage(magic uint32, cmd commandType, payload []byte) *Message {
|
func newMessage(magic NetMode, cmd commandType, payload []byte) *Message {
|
||||||
sum := sumSHA256(sumSHA256(payload))[:4]
|
sum := sumSHA256(sumSHA256(payload))[:4]
|
||||||
sumuint32 := binary.LittleEndian.Uint32(sum)
|
sumuint32 := binary.LittleEndian.Uint32(sum)
|
||||||
|
|
||||||
|
@ -100,12 +122,12 @@ func (m *Message) commandType() commandType {
|
||||||
// decode a Message from the given reader.
|
// decode a Message from the given reader.
|
||||||
func (m *Message) decode(r io.Reader) error {
|
func (m *Message) decode(r io.Reader) error {
|
||||||
// 24 bytes for the fixed sized fields.
|
// 24 bytes for the fixed sized fields.
|
||||||
buf := make([]byte, 24)
|
buf := make([]byte, minMessageSize)
|
||||||
if _, err := r.Read(buf); err != nil {
|
if _, err := r.Read(buf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Magic = binary.LittleEndian.Uint32(buf[0:4])
|
m.Magic = NetMode(binary.LittleEndian.Uint32(buf[0:4]))
|
||||||
m.Command = buf[4:16]
|
m.Command = buf[4:16]
|
||||||
m.Length = binary.LittleEndian.Uint32(buf[16:20])
|
m.Length = binary.LittleEndian.Uint32(buf[16:20])
|
||||||
m.Checksum = binary.LittleEndian.Uint32(buf[20:24])
|
m.Checksum = binary.LittleEndian.Uint32(buf[20:24])
|
||||||
|
@ -128,9 +150,9 @@ func (m *Message) decode(r io.Reader) error {
|
||||||
// encode a Message to any given io.Writer.
|
// encode a Message to any given io.Writer.
|
||||||
func (m *Message) encode(w io.Writer) error {
|
func (m *Message) encode(w io.Writer) error {
|
||||||
// 24 bytes for the fixed sized fields + the length of the payload.
|
// 24 bytes for the fixed sized fields + the length of the payload.
|
||||||
buf := make([]byte, 24+m.Length)
|
buf := make([]byte, minMessageSize+m.Length)
|
||||||
|
|
||||||
binary.LittleEndian.PutUint32(buf[0:4], m.Magic)
|
binary.LittleEndian.PutUint32(buf[0:4], uint32(m.Magic))
|
||||||
copy(buf[4:16], m.Command)
|
copy(buf[4:16], m.Command)
|
||||||
binary.LittleEndian.PutUint32(buf[16:20], m.Length)
|
binary.LittleEndian.PutUint32(buf[16:20], m.Length)
|
||||||
binary.LittleEndian.PutUint32(buf[20:24], m.Checksum)
|
binary.LittleEndian.PutUint32(buf[20:24], m.Checksum)
|
||||||
|
|
|
@ -6,15 +6,20 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "0.0.1"
|
// node version
|
||||||
|
version = "2.6.0"
|
||||||
|
// official ports according to the protocol.
|
||||||
portMainNet = 10333
|
portMainNet = 10333
|
||||||
portTestNet = 20333
|
portTestNet = 20333
|
||||||
// make sure we can run a server without consuming
|
)
|
||||||
// docker privnet ports.
|
|
||||||
portDevNet = 3000
|
var (
|
||||||
|
// rpcLogger used for debugging RPC messages between nodes.
|
||||||
|
rpcLogger = log.New(os.Stdout, "RPC :: ", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageTuple struct {
|
type messageTuple struct {
|
||||||
|
@ -26,11 +31,15 @@ type messageTuple struct {
|
||||||
type Server struct {
|
type Server struct {
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
|
|
||||||
|
// the port the TCP listener is listening on.
|
||||||
|
port uint16
|
||||||
|
|
||||||
// userAgent of the server.
|
// userAgent of the server.
|
||||||
userAgent string
|
userAgent string
|
||||||
// The "magic" mode the server is currently running on.
|
// The "magic" mode the server is currently running on.
|
||||||
// This can either be 0x00746e41 or 0x74746e41 for main or test net.
|
// This can either be 0x00746e41 or 0x74746e41 for main or test net.
|
||||||
netMode uint32
|
// Or 56753 to work with the docker privnet.
|
||||||
|
net NetMode
|
||||||
// map that holds all connected peers to this server.
|
// map that holds all connected peers to this server.
|
||||||
peers map[*Peer]bool
|
peers map[*Peer]bool
|
||||||
|
|
||||||
|
@ -48,16 +57,14 @@ type Server struct {
|
||||||
|
|
||||||
// TCP listener of the server
|
// TCP listener of the server
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
|
|
||||||
dev bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer returns a pointer to a new server.
|
// NewServer returns a pointer to a new server.
|
||||||
func NewServer(mode uint32) *Server {
|
func NewServer(net NetMode) *Server {
|
||||||
logger := log.New(os.Stdout, "NEO SERVER :: ", 0)
|
logger := log.New(os.Stdout, "NEO SERVER :: ", 0)
|
||||||
|
|
||||||
if mode != ModeTestNet && mode != ModeMainNet {
|
if net != ModeTestNet && net != ModeMainNet && net != ModeDevNet {
|
||||||
logger.Fatalf("invalid network mode %d", mode)
|
logger.Fatalf("invalid network mode %d", net)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
|
@ -68,7 +75,7 @@ func NewServer(mode uint32) *Server {
|
||||||
unregister: make(chan *Peer),
|
unregister: make(chan *Peer),
|
||||||
message: make(chan messageTuple),
|
message: make(chan messageTuple),
|
||||||
relay: true,
|
relay: true,
|
||||||
netMode: mode,
|
net: net,
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +84,15 @@ func NewServer(mode uint32) *Server {
|
||||||
|
|
||||||
// Start run's the server.
|
// Start run's the server.
|
||||||
func (s *Server) Start(port string, seeds []string) {
|
func (s *Server) Start(port string, seeds []string) {
|
||||||
|
p, err := strconv.Atoi(port[1:len(port)])
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Fatalf("could not convert port to integer: %s", err)
|
||||||
|
}
|
||||||
|
s.port = uint16(p)
|
||||||
|
|
||||||
fmt.Println(logo())
|
fmt.Println(logo())
|
||||||
s.logger.Printf("running %s on %s - relay: %v", s.userAgent, "testnet", s.relay)
|
s.logger.Printf("running %s on %s - TCP %d - relay: %v",
|
||||||
|
s.userAgent, s.net, int(s.port), s.relay)
|
||||||
|
|
||||||
go listenTCP(s, port)
|
go listenTCP(s, port)
|
||||||
|
|
||||||
|
@ -109,15 +123,18 @@ func (s *Server) loop() {
|
||||||
select {
|
select {
|
||||||
case peer := <-s.register:
|
case peer := <-s.register:
|
||||||
s.logger.Printf("peer registered from address %s", peer.conn.RemoteAddr())
|
s.logger.Printf("peer registered from address %s", peer.conn.RemoteAddr())
|
||||||
resp, err := s.handlePeerConnected()
|
|
||||||
if err != nil {
|
// only respond with the version mesage if the peer initiated the connection.
|
||||||
s.logger.Fatalf("handling initial peer connection failed: %s", err)
|
if peer.initiater {
|
||||||
|
resp, err := s.handlePeerConnected()
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Fatalf("handling initial peer connection failed: %s", err)
|
||||||
|
}
|
||||||
|
peer.send <- resp
|
||||||
}
|
}
|
||||||
peer.send <- resp
|
|
||||||
case peer := <-s.unregister:
|
case peer := <-s.unregister:
|
||||||
s.logger.Printf("peer %s disconnected", peer.conn.RemoteAddr())
|
s.logger.Printf("peer %s disconnected", peer.conn.RemoteAddr())
|
||||||
case tuple := <-s.message:
|
case tuple := <-s.message:
|
||||||
s.logger.Printf("new incomming message %s", string(tuple.msg.Command))
|
|
||||||
if err := s.processMessage(tuple.msg, tuple.peer); err != nil {
|
if err := s.processMessage(tuple.msg, tuple.peer); err != nil {
|
||||||
s.logger.Fatalf("failed to process message: %s", err)
|
s.logger.Fatalf("failed to process message: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -130,6 +147,8 @@ func (s *Server) loop() {
|
||||||
// TODO: unregister peers on error.
|
// TODO: unregister peers on error.
|
||||||
// processMessage processes the received message from a remote node.
|
// processMessage processes the received message from a remote node.
|
||||||
func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
||||||
|
rpcLogger.Printf("IN :: %+v", msg)
|
||||||
|
|
||||||
switch msg.commandType() {
|
switch msg.commandType() {
|
||||||
case cmdVersion:
|
case cmdVersion:
|
||||||
v, _ := msg.decodePayload()
|
v, _ := msg.decodePayload()
|
||||||
|
@ -159,12 +178,12 @@ func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
||||||
// No further communication should been made before both sides has received
|
// No further communication should been made before both sides has received
|
||||||
// the version of eachother.
|
// the version of eachother.
|
||||||
func (s *Server) handlePeerConnected() (*Message, error) {
|
func (s *Server) handlePeerConnected() (*Message, error) {
|
||||||
payload := newVersionPayload(s.port(), s.userAgent, 0, s.relay)
|
payload := newVersionPayload(s.port, s.userAgent, 0, s.relay)
|
||||||
b, err := payload.encode()
|
b, err := payload.encode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
msg := newMessage(ModeTestNet, cmdVersion, b)
|
msg := newMessage(s.net, cmdVersion, b)
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,27 +193,10 @@ func (s *Server) handleVersionCmd(v *Version) (*Message, error) {
|
||||||
// TODO: check version and verify to trust that node.
|
// TODO: check version and verify to trust that node.
|
||||||
|
|
||||||
// Empty payload for the verack message.
|
// Empty payload for the verack message.
|
||||||
fmt.Printf("%+v\n", v)
|
msg := newMessage(s.net, cmdVerack, nil)
|
||||||
|
|
||||||
msg := newMessage(s.netMode, cmdVerack, nil)
|
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) port() uint16 {
|
|
||||||
if s.dev {
|
|
||||||
return portDevNet
|
|
||||||
}
|
|
||||||
if s.netMode == ModeMainNet {
|
|
||||||
return portMainNet
|
|
||||||
}
|
|
||||||
if s.netMode == ModeTestNet {
|
|
||||||
return portTestNet
|
|
||||||
}
|
|
||||||
|
|
||||||
s.logger.Fatalf("the server dont know what ports it running, yikes.")
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func logo() string {
|
func logo() string {
|
||||||
return `
|
return `
|
||||||
_ ____________ __________
|
_ ____________ __________
|
||||||
|
|
Loading…
Reference in a new issue