forked from elastos/Elastos.ELA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
version.go
173 lines (151 loc) · 4.57 KB
/
version.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package message
import (
"Elastos.ELA/common/config"
"Elastos.ELA/common/log"
"Elastos.ELA/core/ledger"
. "Elastos.ELA/net/protocol"
"bytes"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"time"
)
type version struct {
messageHeader
Body struct {
Version uint32
Services uint64
TimeStamp uint32
Port uint16
Nonce uint64
// TODO remove tempory to get serilization function passed
StartHeight uint64
// FIXME check with the specify relay type length
Relay uint8
}
}
func NewVersion(n Noder) ([]byte, error) {
log.Debug()
var msg version
msg.Body.Version = n.Version()
msg.Body.Services = n.Services()
// FIXME Time overflow
msg.Body.TimeStamp = uint32(time.Now().UTC().UnixNano())
msg.Body.Port = n.GetPort()
msg.Body.Nonce = n.GetID()
msg.Body.StartHeight = uint64(ledger.DefaultLedger.GetLocalBlockChainHeight())
if n.GetRelay() {
msg.Body.Relay = 1
} else {
msg.Body.Relay = 0
}
msg.Magic = config.Parameters.Magic
copy(msg.CMD[0:7], "version")
p := bytes.NewBuffer([]byte{})
err := binary.Write(p, binary.LittleEndian, &(msg.Body))
if err != nil {
log.Error("Binary Write failed at new Msg")
return nil, err
}
s := sha256.Sum256(p.Bytes())
s2 := s[:]
s = sha256.Sum256(s2)
buf := bytes.NewBuffer(s[:4])
binary.Read(buf, binary.LittleEndian, &(msg.Checksum))
msg.Length = uint32(len(p.Bytes()))
log.Debug("The message payload length is ", msg.Length)
m, err := msg.Serialization()
if err != nil {
log.Error("Error Convert net message ", err.Error())
return nil, err
}
return m, nil
}
func (msg version) Serialization() ([]byte, error) {
hdrBuf, err := msg.messageHeader.Serialization()
if err != nil {
return nil, err
}
buf := bytes.NewBuffer(hdrBuf)
err = binary.Write(buf, binary.LittleEndian, msg.Body)
if err != nil {
return nil, err
}
return buf.Bytes(), err
}
func (msg *version) Deserialization(p []byte) error {
buf := bytes.NewBuffer(p)
err := binary.Read(buf, binary.LittleEndian, &(msg.messageHeader))
if err != nil {
log.Warn("Parse version message hdr error")
return errors.New("Parse version message hdr error")
}
err = binary.Read(buf, binary.LittleEndian, &(msg.Body))
if err != nil {
log.Warn("Parse version Body message error")
return errors.New("Parse version Body message error")
}
return err
}
/*
* The node state switch table after rx message, there is time limitation for each action
* The Handshake status will switch to Init after TIMEOUT if not received the VerACK
* in this time window
* _______________________________________________________________________
* | | Init | HandShake | Establish | Inactive |
* |-----------------------------------------------------------------------|
* | version | HandShake(timer)| | | HandShake(timer)|
* | | if helloTime > 3| Tx verack | Depend on | if helloTime > 3|
* | | Tx version | | node update| Tx version |
* | | then Tx verack | | | then Tx verack |
* |-----------------------------------------------------------------------|
* | verack | | Establish | | |
* | | No Action | | No Action | No Action |
* |------------------------------------------------------------------------
*/
func (msg version) Handle(node Noder) error {
log.Debug()
localNode := node.LocalNode()
// Exclude the node itself
if msg.Body.Nonce == localNode.GetID() {
log.Warn("The node handshake with itself")
node.CloseConn()
return errors.New("The node handshake with itself")
}
s := node.GetState()
if s != Init && s != Hand {
log.Warn("Unknow status to receive version")
return errors.New("Unknow status to receive version")
}
// Obsolete node
n, ret := localNode.DelNbrNode(msg.Body.Nonce)
if ret == true {
log.Info(fmt.Sprintf("Node reconnect 0x%x", msg.Body.Nonce))
// Close the connection and release the node soure
n.SetState(Inactive)
n.CloseConn()
}
node.UpdateInfo(time.Now(), msg.Body.Version, msg.Body.Services,
msg.Body.Port, msg.Body.Nonce, msg.Body.Relay, msg.Body.StartHeight)
localNode.AddNbrNode(node)
ip, _ := node.GetAddr16()
addr := NodeAddr{
Time: node.GetTime(),
Services: msg.Body.Services,
IpAddr: ip,
Port: msg.Body.Port,
ID: msg.Body.Nonce,
}
localNode.AddAddressToKnownAddress(addr)
var buf []byte
if s == Init {
node.SetState(HandShake)
buf, _ = NewVersion(localNode)
} else if s == Hand {
node.SetState(HandShaked)
buf, _ = NewVerack()
}
node.Tx(buf)
return nil
}