Implemented NetMode type.

This commit is contained in:
anthdm 2018-01-26 21:39:34 +01:00
parent 536a499236
commit b94c9b4b57
3 changed files with 72 additions and 47 deletions

View file

@ -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}

View file

@ -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)

View file

@ -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 `
_ ____________ __________ _ ____________ __________