Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
link33
plugin
Commits
10c93e40
Commit
10c93e40
authored
Nov 02, 2021
by
libangzhu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update code
parent
81bf3dbb
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
29 additions
and
48 deletions
+29
-48
monitor.go
plugin/p2p/gossip/monitor.go
+8
-24
netaddress.go
plugin/p2p/gossip/netaddress.go
+1
-1
node.go
plugin/p2p/gossip/node.go
+4
-4
p2pcli.go
plugin/p2p/gossip/p2pcli.go
+9
-9
peer.go
plugin/p2p/gossip/peer.go
+2
-3
tls.go
plugin/p2p/gossip/tls.go
+5
-7
No files found.
plugin/p2p/gossip/monitor.go
View file @
10c93e40
...
@@ -7,7 +7,6 @@ package gossip
...
@@ -7,7 +7,6 @@ package gossip
import
(
import
(
"bytes"
"bytes"
"io"
"io"
"math/big"
"net/http"
"net/http"
"strings"
"strings"
"time"
"time"
...
@@ -635,41 +634,26 @@ func (n *Node) monitorCerts() {
...
@@ -635,41 +634,26 @@ func (n *Node) monitorCerts() {
log
.
Debug
(
"monitorCerts"
,
"resp"
,
resp
)
log
.
Debug
(
"monitorCerts"
,
"resp"
,
resp
)
tempCerts
:=
getSerials
()
tempCerts
:=
getSerials
()
for
_
,
serialNum
:=
range
resp
{
for
_
,
serialNum
:=
range
resp
{
//被吊销的证书序列号
var
ok
bool
sNum
:=
big
.
NewInt
(
1
)
sNum
,
ok
=
sNum
.
SetString
(
serialNum
,
10
)
if
!
ok
{
log
.
Error
(
"monitorCerts"
,
"big.Int Setstring err"
,
serialNum
)
continue
}
//设置证书序列号状态
//设置证书序列号状态
certinfo
:=
updateCertSerial
(
sNum
,
true
)
certinfo
:=
updateCertSerial
(
serialNum
,
true
)
delete
(
tempCerts
,
sNum
.
String
())
delete
(
tempCerts
,
serialNum
)
if
certinfo
!=
nil
{
for
pname
,
peer
:=
range
n
.
nodeInfo
.
peerInfos
.
GetPeerInfos
()
{
for
pname
,
peer
:=
range
n
.
nodeInfo
.
peerInfos
.
GetPeerInfos
()
{
if
peer
.
GetAddr
()
==
certinfo
.
ip
{
if
peer
.
GetAddr
()
==
certinfo
.
ip
{
v
,
ok
:=
latestSerials
.
Load
(
certinfo
.
ip
)
v
,
ok
:=
latestSerials
.
Load
(
certinfo
.
ip
)
if
ok
&&
v
.
(
string
)
==
serialNum
{
if
ok
&&
v
.
(
string
)
==
serialNum
{
n
.
remove
(
pname
)
//断开已经连接的节点
n
.
remove
(
pname
)
//断开已经连接的节点
}
}
}
}
}
}
}
}
}
log
.
Debug
(
"monitorCert"
,
"tempCerts"
,
tempCerts
)
log
.
Debug
(
"monitorCert"
,
"tempCerts"
,
tempCerts
)
//处理解除吊销的节点
//处理解除吊销的节点
for
serialNum
,
info
:=
range
tempCerts
{
for
serialNum
,
info
:=
range
tempCerts
{
if
info
.
revoke
{
if
info
.
revoke
{
// 被撤销的证书恢复正常
// 被撤销的证书恢复正常
sNum
:=
big
.
NewInt
(
1
)
updateCertSerial
(
serialNum
,
!
info
.
revoke
)
sNum
,
_
=
sNum
.
SetString
(
serialNum
,
10
)
updateCertSerial
(
sNum
,
!
info
.
revoke
)
}
}
}
}
}
}
...
...
plugin/p2p/gossip/netaddress.go
View file @
10c93e40
...
@@ -212,7 +212,7 @@ func (na *NetAddress) DialTimeout(version int32, creds credentials.TransportCred
...
@@ -212,7 +212,7 @@ func (na *NetAddress) DialTimeout(version int32, creds credentials.TransportCred
//判断是否对方是否支持压缩
//判断是否对方是否支持压缩
cli
:=
pb
.
NewP2PgserviceClient
(
conn
)
cli
:=
pb
.
NewP2PgserviceClient
(
conn
)
_
,
err
=
cli
.
GetHeaders
(
context
.
Background
(),
&
pb
.
P2PGetHeaders
{
StartHeight
:
0
,
EndHeight
:
0
,
Version
:
version
},
grpc
.
WaitForReady
(
tru
e
))
_
,
err
=
cli
.
GetHeaders
(
context
.
Background
(),
&
pb
.
P2PGetHeaders
{
StartHeight
:
0
,
EndHeight
:
0
,
Version
:
version
},
grpc
.
WaitForReady
(
fals
e
))
if
err
!=
nil
&&
!
isCompressSupport
(
err
)
{
if
err
!=
nil
&&
!
isCompressSupport
(
err
)
{
//compress not support
//compress not support
log
.
Error
(
"compress not supprot , rollback to uncompress version"
,
"addr"
,
na
.
String
())
log
.
Error
(
"compress not supprot , rollback to uncompress version"
,
"addr"
,
na
.
String
())
...
...
plugin/p2p/gossip/node.go
View file @
10c93e40
...
@@ -134,24 +134,24 @@ func NewNode(mgr *p2p.Manager, mcfg *subConfig) (*Node, error) {
...
@@ -134,24 +134,24 @@ func NewNode(mgr *p2p.Manager, mcfg *subConfig) (*Node, error) {
//不需要CA
//不需要CA
node
.
nodeInfo
.
cliCreds
,
err
=
credentials
.
NewClientTLSFromFile
(
mcfg
.
CertFile
,
""
)
node
.
nodeInfo
.
cliCreds
,
err
=
credentials
.
NewClientTLSFromFile
(
mcfg
.
CertFile
,
""
)
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
err
)
panic
(
fmt
.
Sprintf
(
"NewClientTLSFromFile panic:%v"
,
err
.
Error
())
)
}
}
node
.
nodeInfo
.
servCreds
,
err
=
credentials
.
NewServerTLSFromFile
(
mcfg
.
CertFile
,
mcfg
.
KeyFile
)
node
.
nodeInfo
.
servCreds
,
err
=
credentials
.
NewServerTLSFromFile
(
mcfg
.
CertFile
,
mcfg
.
KeyFile
)
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
err
)
panic
(
fmt
.
Sprintf
(
"NewServerTLSFromFile panic:%v"
,
err
.
Error
())
)
}
}
}
else
{
}
else
{
//CA
//CA
cert
,
err
:=
tls
.
LoadX509KeyPair
(
mcfg
.
CertFile
,
mcfg
.
KeyFile
)
cert
,
err
:=
tls
.
LoadX509KeyPair
(
mcfg
.
CertFile
,
mcfg
.
KeyFile
)
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
err
)
panic
(
fmt
.
Sprintf
(
"LoadX509KeyPair panic:%v"
,
err
.
Error
())
)
}
}
certPool
:=
x509
.
NewCertPool
()
certPool
:=
x509
.
NewCertPool
()
//添加CA校验
//添加CA校验
//把CA证书读进去,动态更新CA中的吊销列表
//把CA证书读进去,动态更新CA中的吊销列表
ca
,
err
:=
ioutil
.
ReadFile
(
mcfg
.
CaCert
)
ca
,
err
:=
ioutil
.
ReadFile
(
mcfg
.
CaCert
)
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
err
)
panic
(
fmt
.
Sprintf
(
"readFile ca panic:%v"
,
err
.
Error
())
)
}
}
if
ok
:=
certPool
.
AppendCertsFromPEM
(
ca
);
!
ok
{
if
ok
:=
certPool
.
AppendCertsFromPEM
(
ca
);
!
ok
{
...
...
plugin/p2p/gossip/p2pcli.go
View file @
10c93e40
...
@@ -110,7 +110,7 @@ func (m *Cli) GetMemPool(msg *queue.Message, taskindex int64) {
...
@@ -110,7 +110,7 @@ func (m *Cli) GetMemPool(msg *queue.Message, taskindex int64) {
for
_
,
peer
:=
range
peers
{
for
_
,
peer
:=
range
peers
{
//获取远程 peer invs
//获取远程 peer invs
resp
,
err
:=
peer
.
mconn
.
gcli
.
GetMemPool
(
context
.
Background
(),
resp
,
err
:=
peer
.
mconn
.
gcli
.
GetMemPool
(
context
.
Background
(),
&
pb
.
P2PGetMempool
{
Version
:
m
.
network
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
tru
e
))
&
pb
.
P2PGetMempool
{
Version
:
m
.
network
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
peer
)
P2pComm
.
CollectPeerStat
(
err
,
peer
)
if
err
!=
nil
{
if
err
!=
nil
{
if
err
==
pb
.
ErrVersion
{
if
err
==
pb
.
ErrVersion
{
...
@@ -142,7 +142,7 @@ func (m *Cli) GetMemPool(msg *queue.Message, taskindex int64) {
...
@@ -142,7 +142,7 @@ func (m *Cli) GetMemPool(msg *queue.Message, taskindex int64) {
}
}
//获取真正的交易Tx call GetData
//获取真正的交易Tx call GetData
datacli
,
dataerr
:=
peer
.
mconn
.
gcli
.
GetData
(
context
.
Background
(),
datacli
,
dataerr
:=
peer
.
mconn
.
gcli
.
GetData
(
context
.
Background
(),
&
pb
.
P2PGetData
{
Invs
:
ableInv
,
Version
:
m
.
network
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
tru
e
))
&
pb
.
P2PGetData
{
Invs
:
ableInv
,
Version
:
m
.
network
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
dataerr
,
peer
)
P2pComm
.
CollectPeerStat
(
dataerr
,
peer
)
if
dataerr
!=
nil
{
if
dataerr
!=
nil
{
continue
continue
...
@@ -174,7 +174,7 @@ func (m *Cli) GetMemPool(msg *queue.Message, taskindex int64) {
...
@@ -174,7 +174,7 @@ func (m *Cli) GetMemPool(msg *queue.Message, taskindex int64) {
func
(
m
*
Cli
)
GetAddr
(
peer
*
Peer
)
([]
string
,
error
)
{
func
(
m
*
Cli
)
GetAddr
(
peer
*
Peer
)
([]
string
,
error
)
{
resp
,
err
:=
peer
.
mconn
.
gcli
.
GetAddr
(
context
.
Background
(),
&
pb
.
P2PGetAddr
{
Nonce
:
int64
(
rand
.
Int31n
(
102040
))},
resp
,
err
:=
peer
.
mconn
.
gcli
.
GetAddr
(
context
.
Background
(),
&
pb
.
P2PGetAddr
{
Nonce
:
int64
(
rand
.
Int31n
(
102040
))},
grpc
.
WaitForReady
(
tru
e
))
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
peer
)
P2pComm
.
CollectPeerStat
(
err
,
peer
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
@@ -192,7 +192,7 @@ func (m *Cli) GetInPeersNum(peer *Peer) (int, error) {
...
@@ -192,7 +192,7 @@ func (m *Cli) GetInPeersNum(peer *Peer) (int, error) {
}
}
resp
,
err
:=
peer
.
mconn
.
gcli
.
CollectInPeers
(
context
.
Background
(),
ping
,
resp
,
err
:=
peer
.
mconn
.
gcli
.
CollectInPeers
(
context
.
Background
(),
ping
,
grpc
.
WaitForReady
(
tru
e
))
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
peer
)
P2pComm
.
CollectPeerStat
(
err
,
peer
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -210,7 +210,7 @@ func (m *Cli) GetAddrList(peer *Peer) (map[string]*pb.P2PPeerInfo, error) {
...
@@ -210,7 +210,7 @@ func (m *Cli) GetAddrList(peer *Peer) (map[string]*pb.P2PPeerInfo, error) {
return
addrlist
,
fmt
.
Errorf
(
"pointer is nil"
)
return
addrlist
,
fmt
.
Errorf
(
"pointer is nil"
)
}
}
resp
,
err
:=
peer
.
mconn
.
gcli
.
GetAddrList
(
context
.
Background
(),
&
pb
.
P2PGetAddr
{
Nonce
:
int64
(
rand
.
Int31n
(
102040
))},
resp
,
err
:=
peer
.
mconn
.
gcli
.
GetAddrList
(
context
.
Background
(),
&
pb
.
P2PGetAddr
{
Nonce
:
int64
(
rand
.
Int31n
(
102040
))},
grpc
.
WaitForReady
(
tru
e
))
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
peer
)
P2pComm
.
CollectPeerStat
(
err
,
peer
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -272,7 +272,7 @@ func (m *Cli) SendVersion(peer *Peer, nodeinfo *NodeInfo) (string, error) {
...
@@ -272,7 +272,7 @@ func (m *Cli) SendVersion(peer *Peer, nodeinfo *NodeInfo) (string, error) {
resp
,
err
:=
peer
.
mconn
.
gcli
.
Version2
(
context
.
Background
(),
&
pb
.
P2PVersion
{
Version
:
nodeinfo
.
channelVersion
,
Service
:
int64
(
nodeinfo
.
ServiceTy
()),
Timestamp
:
pb
.
Now
()
.
Unix
(),
resp
,
err
:=
peer
.
mconn
.
gcli
.
Version2
(
context
.
Background
(),
&
pb
.
P2PVersion
{
Version
:
nodeinfo
.
channelVersion
,
Service
:
int64
(
nodeinfo
.
ServiceTy
()),
Timestamp
:
pb
.
Now
()
.
Unix
(),
AddrRecv
:
peer
.
Addr
(),
AddrFrom
:
addrfrom
,
Nonce
:
int64
(
rand
.
Int31n
(
102040
)),
AddrRecv
:
peer
.
Addr
(),
AddrFrom
:
addrfrom
,
Nonce
:
int64
(
rand
.
Int31n
(
102040
)),
UserAgent
:
hex
.
EncodeToString
(
in
.
Sign
.
GetPubkey
()),
StartHeight
:
blockheight
},
grpc
.
WaitForReady
(
tru
e
))
UserAgent
:
hex
.
EncodeToString
(
in
.
Sign
.
GetPubkey
()),
StartHeight
:
blockheight
},
grpc
.
WaitForReady
(
fals
e
))
log
.
Debug
(
"SendVersion"
,
"resp"
,
resp
,
"from"
,
addrfrom
,
"to"
,
peer
.
Addr
())
log
.
Debug
(
"SendVersion"
,
"resp"
,
resp
,
"from"
,
addrfrom
,
"to"
,
peer
.
Addr
())
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Error
(
"SendVersion"
,
"Verson"
,
err
.
Error
(),
"peer"
,
peer
.
Addr
())
log
.
Error
(
"SendVersion"
,
"Verson"
,
err
.
Error
(),
"peer"
,
peer
.
Addr
())
...
@@ -317,7 +317,7 @@ func (m *Cli) SendPing(peer *Peer, nodeinfo *NodeInfo) error {
...
@@ -317,7 +317,7 @@ func (m *Cli) SendPing(peer *Peer, nodeinfo *NodeInfo) error {
return
err
return
err
}
}
r
,
err
:=
peer
.
mconn
.
gcli
.
Ping
(
context
.
Background
(),
ping
,
grpc
.
WaitForReady
(
tru
e
))
r
,
err
:=
peer
.
mconn
.
gcli
.
Ping
(
context
.
Background
(),
ping
,
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
peer
)
P2pComm
.
CollectPeerStat
(
err
,
peer
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -395,7 +395,7 @@ func (m *Cli) GetHeaders(msg *queue.Message, taskindex int64) {
...
@@ -395,7 +395,7 @@ func (m *Cli) GetHeaders(msg *queue.Message, taskindex int64) {
if
peer
,
ok
:=
peers
[
pid
[
0
]];
ok
&&
peer
!=
nil
{
if
peer
,
ok
:=
peers
[
pid
[
0
]];
ok
&&
peer
!=
nil
{
var
err
error
var
err
error
headers
,
err
:=
peer
.
mconn
.
gcli
.
GetHeaders
(
context
.
Background
(),
&
pb
.
P2PGetHeaders
{
StartHeight
:
req
.
GetStart
(),
EndHeight
:
req
.
GetEnd
(),
headers
,
err
:=
peer
.
mconn
.
gcli
.
GetHeaders
(
context
.
Background
(),
&
pb
.
P2PGetHeaders
{
StartHeight
:
req
.
GetStart
(),
EndHeight
:
req
.
GetEnd
(),
Version
:
m
.
network
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
tru
e
))
Version
:
m
.
network
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
peer
)
P2pComm
.
CollectPeerStat
(
err
,
peer
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Error
(
"GetBlocks"
,
"Err"
,
err
.
Error
())
log
.
Error
(
"GetBlocks"
,
"Err"
,
err
.
Error
())
...
@@ -587,7 +587,7 @@ func (m *Cli) CheckSelf(addr string, nodeinfo *NodeInfo) bool {
...
@@ -587,7 +587,7 @@ func (m *Cli) CheckSelf(addr string, nodeinfo *NodeInfo) bool {
cli
:=
pb
.
NewP2PgserviceClient
(
conn
)
cli
:=
pb
.
NewP2PgserviceClient
(
conn
)
resp
,
err
:=
cli
.
GetPeerInfo
(
context
.
Background
(),
resp
,
err
:=
cli
.
GetPeerInfo
(
context
.
Background
(),
&
pb
.
P2PGetPeerInfo
{
Version
:
nodeinfo
.
channelVersion
},
grpc
.
WaitForReady
(
tru
e
))
&
pb
.
P2PGetPeerInfo
{
Version
:
nodeinfo
.
channelVersion
},
grpc
.
WaitForReady
(
fals
e
))
if
err
!=
nil
{
if
err
!=
nil
{
return
false
return
false
}
}
...
...
plugin/p2p/gossip/peer.go
View file @
10c93e40
...
@@ -55,7 +55,6 @@ type Peer struct {
...
@@ -55,7 +55,6 @@ type Peer struct {
taskChan
chan
interface
{}
//tx block
taskChan
chan
interface
{}
//tx block
inBounds
int32
//连接此节点的客户端节点数量
inBounds
int32
//连接此节点的客户端节点数量
IsMaxInbouds
bool
IsMaxInbouds
bool
serialNnum
string
}
}
// NewPeer produce a peer object
// NewPeer produce a peer object
...
@@ -171,7 +170,7 @@ func (p *Peer) GetInBouns() int32 {
...
@@ -171,7 +170,7 @@ func (p *Peer) GetInBouns() int32 {
// GetPeerInfo get peer information of peer
// GetPeerInfo get peer information of peer
func
(
p
*
Peer
)
GetPeerInfo
()
(
*
pb
.
P2PPeerInfo
,
error
)
{
func
(
p
*
Peer
)
GetPeerInfo
()
(
*
pb
.
P2PPeerInfo
,
error
)
{
return
p
.
mconn
.
gcli
.
GetPeerInfo
(
context
.
Background
(),
&
pb
.
P2PGetPeerInfo
{
Version
:
p
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
FailFast
(
tru
e
))
return
p
.
mconn
.
gcli
.
GetPeerInfo
(
context
.
Background
(),
&
pb
.
P2PGetPeerInfo
{
Version
:
p
.
node
.
nodeInfo
.
channelVersion
},
grpc
.
WaitForReady
(
fals
e
))
}
}
func
(
p
*
Peer
)
sendStream
()
{
func
(
p
*
Peer
)
sendStream
()
{
...
@@ -300,7 +299,7 @@ func (p *Peer) readStream() {
...
@@ -300,7 +299,7 @@ func (p *Peer) readStream() {
log
.
Error
(
"readStream"
,
"err:"
,
err
.
Error
(),
"peerIp"
,
p
.
Addr
())
log
.
Error
(
"readStream"
,
"err:"
,
err
.
Error
(),
"peerIp"
,
p
.
Addr
())
continue
continue
}
}
resp
,
err
:=
p
.
mconn
.
gcli
.
ServerStreamSend
(
context
.
Background
(),
ping
,
grpc
.
WaitForReady
(
tru
e
))
resp
,
err
:=
p
.
mconn
.
gcli
.
ServerStreamSend
(
context
.
Background
(),
ping
,
grpc
.
WaitForReady
(
fals
e
))
P2pComm
.
CollectPeerStat
(
err
,
p
)
P2pComm
.
CollectPeerStat
(
err
,
p
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Error
(
"readStream"
,
"serverstreamsend,err:"
,
err
,
"peer"
,
p
.
Addr
())
log
.
Error
(
"readStream"
,
"serverstreamsend,err:"
,
err
,
"peer"
,
p
.
Addr
())
...
...
plugin/p2p/gossip/tls.go
View file @
10c93e40
...
@@ -41,19 +41,17 @@ func addCertSerial(serial *big.Int, ip string) {
...
@@ -41,19 +41,17 @@ func addCertSerial(serial *big.Int, ip string) {
serials
[
serial
.
String
()]
=
&
certInfo
{
false
,
ip
,
serial
.
String
()}
serials
[
serial
.
String
()]
=
&
certInfo
{
false
,
ip
,
serial
.
String
()}
}
}
func
updateCertSerial
(
serial
*
big
.
Int
,
revoke
bool
)
*
certInfo
{
func
updateCertSerial
(
serial
string
,
revoke
bool
)
certInfo
{
revokeLock
.
Lock
()
revokeLock
.
Lock
()
defer
revokeLock
.
Unlock
()
defer
revokeLock
.
Unlock
()
v
,
ok
:=
serials
[
serial
.
String
()
]
v
,
ok
:=
serials
[
serial
]
if
ok
{
if
ok
{
v
.
revoke
=
revoke
v
.
revoke
=
revoke
}
else
{
return
*
v
return
nil
}
}
serials
[
serial
.
String
()]
=
v
return
v
//serials[serial.String()] = v
return
certInfo
{}
}
}
func
isRevoke
(
serial
*
big
.
Int
)
bool
{
func
isRevoke
(
serial
*
big
.
Int
)
bool
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment