forked from yinchengtsinghua/golang-bitcoin-chinese
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
3143 lines (2763 loc) · 89.8 KB
/
server.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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//此源码被清华学神尹成大魔王专业翻译分析并修改
//尹成QQ77025077
//尹成微信18510341407
//尹成所在QQ群721929980
//尹成邮箱 [email protected]
//尹成毕业于清华大学,微软区块链领域全球最有价值专家
//https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
//版权所有(c)2013-2017 BTCSuite开发者
//版权所有(c)2015-2018法令开发商
//此源代码的使用由ISC控制
//可以在许可文件中找到的许可证。
package main
import (
"bytes"
"crypto/rand"
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
"math"
"net"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/btcsuite/btcd/addrmgr"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/blockchain/indexers"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/connmgr"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/mempool"
"github.com/btcsuite/btcd/mining"
"github.com/btcsuite/btcd/mining/cpuminer"
"github.com/btcsuite/btcd/netsync"
"github.com/btcsuite/btcd/peer"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/bloom"
)
const (
//DefaultServices描述由支持的默认服务
//服务器。
defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom |
wire.SFNodeWitness | wire.SFNodeCF
//DefaultRequiredServices描述的是
//需要出站对等机支持。
defaultRequiredServices = wire.SFNodeNetwork
//DefaultTargetOutbound是目标的默认出站对等数。
defaultTargetOutbound = 8
//ConnectionRetryInterval是介于
//连接到持久对等时重试。它是由
//重试次数,使重试后退。
connectionRetryInterval = time.Second * 5
)
var (
//user agent name是用户代理名称,用于帮助识别
//我们和其他比特币同行。
userAgentName = "btcd"
//user agent version是用户代理版本,用于帮助
//向其他比特币同行表明自己的身份。
userAgentVersion = fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)
)
//zero hash是零值哈希(全部为零)。它被定义为一种便利。
var zeroHash chainhash.Hash
//onionaddr实现net.addr接口并表示一个tor地址。
type onionAddr struct {
addr string
}
//字符串返回洋葱地址。
//
//这是net.addr接口的一部分。
func (oa *onionAddr) String() string {
return oa.addr
}
//网络返回“洋葱”。
//
//这是net.addr接口的一部分。
func (oa *onionAddr) Network() string {
return "onion"
}
//确保onionaddr实现net.addr接口。
var _ net.Addr = (*onionAddr)(nil)
//simpleaddr使用两个结构字段实现net.addr接口
type simpleAddr struct {
net, addr string
}
//字符串返回地址。
//
//这是net.addr接口的一部分。
func (a simpleAddr) String() string {
return a.addr
}
//网络返回网络。
//
//这是net.addr接口的一部分。
func (a simpleAddr) Network() string {
return a.net
}
//确保simpleaddr实现net.addr接口。
var _ net.Addr = simpleAddr{}
//Broadcastmsg提供存储待广播比特币消息的功能
//所有连接的对等机,指定排除的对等机除外。
type broadcastMsg struct {
message wire.Message
excludePeers []*serverPeer
}
//BroadcastInventoryAdd是用于声明其包含的invvect的类型
//需要添加到重播地图
type broadcastInventoryAdd relayMsg
//BroadcastInventoryDel是用于声明其包含的invVect的类型
//需要从重播地图中删除
type broadcastInventoryDel *wire.InvVect
//relaymsg将一个库存向量与新发现的
//因此中继可以访问该信息。
type relayMsg struct {
invVect *wire.InvVect
data interface{}
}
//updatepeerHeightsmsg是从BlockManager发送到服务器的消息
//接受新块后。消息的目的是更新
//在我们之前,大家都知道宣布封锁的同龄人的高度
//把它连接到主链上,或者把它识别为孤立的。用这些
//更新,对等高度将保持最新,允许在
//选择同步同行候选资格。
type updatePeerHeightsMsg struct {
newHash *chainhash.Hash
newHeight int32
originPeer *peer.Peer
}
//PeerState还维护入站、持久、出站对等的状态
//作为被禁止的同龄人和出境团体。
type peerState struct {
inboundPeers map[int32]*serverPeer
outboundPeers map[int32]*serverPeer
persistentPeers map[int32]*serverPeer
banned map[string]time.Time
outboundGroups map[string]int
}
//count返回所有已知对等方的计数。
func (ps *peerState) Count() int {
return len(ps.inboundPeers) + len(ps.outboundPeers) +
len(ps.persistentPeers)
}
//foralloutboundpeers是一个在所有出站上运行闭包的助手函数
//对等国已知的对等方。
func (ps *peerState) forAllOutboundPeers(closure func(sp *serverPeer)) {
for _, e := range ps.outboundPeers {
closure(e)
}
for _, e := range ps.persistentPeers {
closure(e)
}
}
//forallpeers是一个助手函数,它在已知的所有对等机上运行闭包。
//彼得的
func (ps *peerState) forAllPeers(closure func(sp *serverPeer)) {
for _, e := range ps.inboundPeers {
closure(e)
}
ps.forAllOutboundPeers(closure)
}
//cfheaderkv是一个过滤器头及其相关块散列的元组。这个
//结构用于缓存cfcheckpt响应。
type cfHeaderKV struct {
blockHash chainhash.Hash
filterHeader chainhash.Hash
}
//服务器提供比特币服务器,用于处理与之之间的通信。
//比特币同行。
type server struct {
//以下变量只能原子地使用。
//首先放置uint64使它们与32位系统64位对齐。
bytesReceived uint64 //自启动后从所有对等方接收的总字节数。
bytesSent uint64 //自启动后所有对等方发送的总字节数。
started int32
shutdown int32
shutdownSched int32
startupTime int64
chainParams *chaincfg.Params
addrManager *addrmgr.AddrManager
connManager *connmgr.ConnManager
sigCache *txscript.SigCache
hashCache *txscript.HashCache
rpcServer *rpcServer
syncManager *netsync.SyncManager
chain *blockchain.BlockChain
txMemPool *mempool.TxPool
cpuMiner *cpuminer.CPUMiner
modifyRebroadcastInv chan interface{}
newPeers chan *serverPeer
donePeers chan *serverPeer
banPeers chan *serverPeer
query chan interface{}
relayInv chan relayMsg
broadcast chan broadcastMsg
peerHeightsUpdate chan updatePeerHeightsMsg
wg sync.WaitGroup
quit chan struct{}
nat NAT
db database.DB
timeSource blockchain.MedianTimeSource
services wire.ServiceFlag
//以下字段用于可选索引。他们将是零
//如果未启用关联索引。这些字段是在
//服务器的初始创建,之后从未更改,因此它们
//不需要对并发访问进行保护。
txIndex *indexers.TxIndex
addrIndex *indexers.AddrIndex
cfIndex *indexers.CfIndex
//费用估算器跟踪交易的剩余时间。
//在他们被开采成块之前。
feeEstimator *mempool.FeeEstimator
//cfcheckptcaches为cfcheckpt存储一个过滤器头的缓存切片
//每个筛选器类型的消息。
cfCheckptCaches map[wire.FilterType][]cfHeaderKV
cfCheckptCachesMtx sync.RWMutex
}
//server peer扩展对等机以维护服务器共享的状态,并
//块管理器。
type serverPeer struct {
//以下变量只能原子地使用
feeFilter int64
*peer.Peer
connReq *connmgr.ConnReq
server *server
persistent bool
continueHash *chainhash.Hash
relayMtx sync.Mutex
disableRelayTx bool
sentAddrs bool
isWhitelisted bool
filter *bloom.Filter
knownAddresses map[string]struct{}
banScore connmgr.DynamicBanScore
quit chan struct{}
//以下通道用于同步BlockManager和服务器。
txProcessed chan struct{}
blockProcessed chan struct{}
}
//NewServerPeer返回新的ServerPeer实例。对等机需要由
//呼叫者。
func newServerPeer(s *server, isPersistent bool) *serverPeer {
return &serverPeer{
server: s,
persistent: isPersistent,
filter: bloom.LoadFilter(nil),
knownAddresses: make(map[string]struct{}),
quit: make(chan struct{}),
txProcessed: make(chan struct{}, 1),
blockProcessed: make(chan struct{}, 1),
}
}
//newestblock使用格式返回当前最佳块哈希和高度
//对等包的配置所需。
func (sp *serverPeer) newestBlock() (*chainhash.Hash, int32, error) {
best := sp.server.chain.BestSnapshot()
return &best.Hash, best.Height, nil
}
//addknownaddress将给定地址添加到已知地址集
//防止发送重复地址的对等机。
func (sp *serverPeer) addKnownAddresses(addresses []*wire.NetAddress) {
for _, na := range addresses {
sp.knownAddresses[addrmgr.NetAddressKey(na)] = struct{}{}
}
}
//如果给定的地址已经为对等方所知,那么address known为true。
func (sp *serverPeer) addressKnown(na *wire.NetAddress) bool {
_, exists := sp.knownAddresses[addrmgr.NetAddressKey(na)]
return exists
}
//setDisableRelayTx为给定对等机切换事务的中继。
//它对于并发访问是安全的。
func (sp *serverPeer) setDisableRelayTx(disable bool) {
sp.relayMtx.Lock()
sp.disableRelayTx = disable
sp.relayMtx.Unlock()
}
//relaysDisabled返回给定事务的中继
//对等机已禁用。
//它对于并发访问是安全的。
func (sp *serverPeer) relayTxDisabled() bool {
sp.relayMtx.Lock()
isDisabled := sp.disableRelayTx
sp.relayMtx.Unlock()
return isDisabled
}
//pushaddrmsg使用提供的
//地址。
func (sp *serverPeer) pushAddrMsg(addresses []*wire.NetAddress) {
//筛选器地址已为对等方所知。
addrs := make([]*wire.NetAddress, 0, len(addresses))
for _, addr := range addresses {
if !sp.addressKnown(addr) {
addrs = append(addrs, addr)
}
}
known, err := sp.PushAddrMsg(addrs)
if err != nil {
peerLog.Errorf("Can't push address message to %s: %v", sp.Peer, err)
sp.Disconnect()
return
}
sp.addKnownAddresses(known)
}
//addbanscore增加了持久和衰退的ban score字段
//作为参数传递的值。如果结果分数超过禁令的一半
//阈值,记录一条警告,包括提供的原因。此外,如果
//分数高于禁令阈值,同行将被禁止,并且
//断开的。
func (sp *serverPeer) addBanScore(persistent, transient uint32, reason string) {
//如果禁用禁止,则不会记录警告,也不会计算分数。
if cfg.DisableBanning {
return
}
if sp.isWhitelisted {
peerLog.Debugf("Misbehaving whitelisted peer %s: %s", sp, reason)
return
}
warnThreshold := cfg.BanThreshold >> 1
if transient == 0 && persistent == 0 {
//分数没有增加,但警告信息仍然存在
//如果分数高于警告阈值,则记录。
score := sp.banScore.Int()
if score > warnThreshold {
peerLog.Warnf("Misbehaving peer %s: %s -- ban score is %d, "+
"it was not increased this time", sp, reason, score)
}
return
}
score := sp.banScore.Increase(persistent, transient)
if score > warnThreshold {
peerLog.Warnf("Misbehaving peer %s: %s -- ban score increased to %d",
sp, reason, score)
if score > cfg.BanThreshold {
peerLog.Warnf("Misbehaving peer %s -- banning and disconnecting",
sp)
sp.server.BanPeer(sp)
sp.Disconnect()
}
}
}
//HasServices返回所提供的公布服务标志是否具有
//所有提供的所需服务标志集。
func hasServices(advertised, desired wire.ServiceFlag) bool {
return advertised&desired == desired
}
//当对等端收到版本比特币消息时调用onversion
//用于协商协议版本详细信息以及启动
//通信。
func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
//使用发布的出站服务更新地址管理器
//连接以防更改。对于入站未执行此操作
//连接以帮助防止恶意行为,并在
//在模拟测试网络上运行,因为它仅用于
//连接到指定的对等点并积极避免广告和
//连接到发现的对等机。
//
//注意:这是在拒绝年龄太大而不能确保
//无论新的最低协议版本是什么,它都会更新。
//已强制,远程节点尚未升级。
isInbound := sp.Inbound()
remoteAddr := sp.NA()
addrManager := sp.server.addrManager
if !cfg.SimNet && !isInbound {
addrManager.SetServices(remoteAddr, msg.Services)
}
//忽略具有太旧的Protcol版本的对等机。同辈
//协商逻辑将在回调返回后断开它。
if msg.ProtocolVersion < int32(peer.MinAcceptableProtocolVersion) {
return nil
}
//拒绝不是完整节点的出站对等端。
wantServices := wire.SFNodeNetwork
if !isInbound && !hasServices(msg.Services, wantServices) {
missingServices := wantServices & ^msg.Services
srvrLog.Debugf("Rejecting peer %s with services %v due to not "+
"providing desired services %v", sp.Peer, msg.Services,
missingServices)
reason := fmt.Sprintf("required services %#x not offered",
uint64(missingServices))
return wire.NewMsgReject(msg.Command(), wire.RejectNonstandard, reason)
}
//更新地址管理器并从
//出站连接的远程对等机。运行时跳过此项
//在模拟测试网络上,因为它只用于连接
//向指定的同行,并积极避免广告和连接到
//发现了对等点。
if !cfg.SimNet && !isInbound {
//软分叉激活后,只进行出站
//与同龄人的联系,如果他们标记自己是赛格威特
//启用。
chain := sp.server.chain
segwitActive, err := chain.IsDeploymentActive(chaincfg.DeploymentSegwit)
if err != nil {
peerLog.Errorf("Unable to query for segwit soft-fork state: %v",
err)
return nil
}
if segwitActive && !sp.IsWitnessEnabled() {
peerLog.Infof("Disconnecting non-segwit peer %v, isn't segwit "+
"enabled and we need more segwit enabled peers", sp)
sp.Disconnect()
return nil
}
//当服务器接受传入时公布本地地址
//它相信自己与最著名的提示很接近。
if !cfg.DisableListen && sp.server.syncManager.IsCurrent() {
//获取最匹配的地址。
lna := addrManager.GetBestLocalAddress(remoteAddr)
if addrmgr.IsRoutable(lna) {
//对等方已经知道的筛选器地址。
addresses := []*wire.NetAddress{lna}
sp.pushAddrMsg(addresses)
}
}
//如果服务器地址管理器需要,请求已知地址
//更多,并且对等端的协议版本足够新
//包括带有地址的时间戳。
hasTimestamp := sp.ProtocolVersion() >= wire.NetAddressTimeVersion
if addrManager.NeedMoreAddresses() && hasTimestamp {
sp.QueueMessage(wire.NewMsgGetAddr(), nil)
}
//将地址标记为已知的好地址。
addrManager.Good(remoteAddr)
}
//添加远程对等时间作为创建偏移的示例
//保持网络时间同步的本地时钟。
sp.server.timeSource.AddTimeSample(sp.Addr(), msg.Timestamp)
//向同步管理器发送信号此对等方是新的同步候选。
sp.server.syncManager.NewPeer(sp.Peer)
//选择是否在筛选命令之前中继事务
//收到。
sp.setDisableRelayTx(msg.DisableRelayTx)
//向服务器添加有效的对等机。
sp.server.AddPeer(sp)
return nil
}
//当对等端收到mempool比特币消息时,调用onmempool。
//它创建并发送带有内存内容的清单消息
//最多可容纳每条消息的最大库存量。当对方有
//布卢姆过滤器加载后,内容物会相应过滤。
func (sp *serverPeer) OnMemPool(_ *peer.Peer, msg *wire.MsgMemPool) {
//仅当服务器具有Bloom筛选时才允许mempool请求
//启用。
if sp.server.services&wire.SFNodeBloom != wire.SFNodeBloom {
peerLog.Debugf("peer %v sent mempool request with bloom "+
"filtering disabled -- disconnecting", sp)
sp.Disconnect()
return
}
//为了防止洪水泛滥,禁令分数不断提高。
//如果出现以下情况,禁令分数将累积并通过禁令阈值:
//mempool消息来自对等机。分数每分钟递减到
//价值的一半。
sp.addBanScore(0, 33, "mempool")
//使用中的可用交易记录生成库存消息
//事务内存池。限制在允许的最大库存
//每个消息。newmsginvsizehint函数自动限制
//传递的提示达到了允许的最大值,因此可以安全地传递它
//这里不需要再检查。
txMemPool := sp.server.txMemPool
txDescs := txMemPool.TxDescs()
invMsg := wire.NewMsgInvSizeHint(uint(len(txDescs)))
for _, txDesc := range txDescs {
//或者在没有Bloom筛选器时添加所有事务,
//或者只有符合筛选条件的事务
//一个。
if !sp.filter.IsLoaded() || sp.filter.MatchTxAndUpdate(txDesc.Tx) {
iv := wire.NewInvVect(wire.InvTypeTx, txDesc.Tx.Hash())
invMsg.AddInvVect(iv)
if len(invMsg.InvList)+1 > wire.MaxInvPerMsg {
break
}
}
}
//如果有要发送的内容,则发送库存消息。
if len(invMsg.InvList) > 0 {
sp.QueueMessage(invMsg, nil)
}
}
//当对等端收到Tx比特币消息时,会调用OnTx。信息块
//直到比特币交易被完全处理。解除锁定
//处理程序这不会通过单个线程序列化所有事务
//事务不依赖于前一个事务,而采用类似块的线性方式。
func (sp *serverPeer) OnTx(_ *peer.Peer, msg *wire.MsgTx) {
if cfg.BlocksOnly {
peerLog.Tracef("Ignoring tx %v from %v - blocksonly enabled",
msg.TxHash(), sp)
return
}
//将事务添加到对等机的已知清单中。
//将原始msgtx转换为bcutil.tx,这提供了一些便利
//方法和事物,如哈希缓存。
tx := btcutil.NewTx(msg)
iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash())
sp.AddKnownInventory(iv)
//将要由同步管理器处理的事务排队,然后
//有意阻止进一步接收,直到交易完成
//处理过的和已知的好的或坏的。这有助于防止恶意对等
//在断开连接之前排队处理一堆坏事务(或
//断开连接)和浪费内存。
sp.server.syncManager.QueueTx(tx, sp.Peer, sp.txProcessed)
<-sp.txProcessed
}
//当对等端接收到块比特币消息时,会调用onblock。它
//块,直到比特币块被完全处理。
func (sp *serverPeer) OnBlock(_ *peer.Peer, msg *wire.MsgBlock, buf []byte) {
//将原始msgblock转换为bcutil.block,它提供
//便利的方法和诸如哈希缓存之类的东西。
block := btcutil.NewBlockFromBlockAndBytes(msg, buf)
//将块添加到对等机的已知清单中。
iv := wire.NewInvVect(wire.InvTypeBlock, block.Hash())
sp.AddKnownInventory(iv)
//将要由块处理的块排队
//经理故意阻止进一步接收
//直到比特币块被完全处理和知道
//好与坏。这有助于防止恶意对等
//从排队之前的一堆坏街区
//断开(或断开)和浪费
//记忆。此外,这种行为还取决于
//至少通过试块验收测试工具作为
//参考实现过程块
//线程,因此阻止更多消息,直到
//比特币区块已完全处理。
sp.server.syncManager.QueueBlock(block, sp.Peer, sp.blockProcessed)
<-sp.blockProcessed
}
//当一个对等方接收到一条INV比特币消息时,会调用OnInV,并且
//用于检查远程对等机公布的清单并作出反应
//因此。我们将消息传递给BlockManager,它将调用
//带有任何适当响应的队列消息。
func (sp *serverPeer) OnInv(_ *peer.Peer, msg *wire.MsgInv) {
if !cfg.BlocksOnly {
if len(msg.InvList) > 0 {
sp.server.syncManager.QueueInv(msg, sp.Peer)
}
return
}
newInv := wire.NewMsgInvSizeHint(uint(len(msg.InvList)))
for _, invVect := range msg.InvList {
if invVect.Type == wire.InvTypeTx {
peerLog.Tracef("Ignoring tx %v in inv from %v -- "+
"blocksonly enabled", invVect.Hash, sp)
if sp.ProtocolVersion() >= wire.BIP0037Version {
peerLog.Infof("Peer %v is announcing "+
"transactions -- disconnecting", sp)
sp.Disconnect()
return
}
continue
}
err := newInv.AddInvVect(invVect)
if err != nil {
peerLog.Errorf("Failed to add inventory vector: %v", err)
break
}
}
if len(newInv.InvList) > 0 {
sp.server.syncManager.QueueInv(newInv, sp.Peer)
}
}
//当对等端收到头比特币时调用OnHeaders
//消息。消息将传递给同步管理器。
func (sp *serverPeer) OnHeaders(_ *peer.Peer, msg *wire.MsgHeaders) {
sp.server.syncManager.QueueHeaders(msg, sp.Peer)
}
//当对等端接收到getdata比特币消息并且
//用于传递块和事务信息。
func (sp *serverPeer) OnGetData(_ *peer.Peer, msg *wire.MsgGetData) {
numAdded := 0
notFound := wire.NewMsgNotFound()
length := len(msg.InvList)
//为防止资源枯竭,采用了一种逐渐降低的禁令分数。
//异常大的库存查询。
//在短时间内请求超过最大库存向量长度
//时间段产生的分数高于默认禁止阈值。持续的
//突发的小请求不会受到惩罚,因为这可能会禁止
//执行IBD的对等机。
//这个增量分数每分钟衰减到其值的一半。
sp.addBanScore(0, uint32(length)*99/wire.MaxInvPerMsg, "getdata")
//我们定期等待这个等待通道以防止排队
//比我们在合理时间内发送的数据多得多,浪费了内存。
//在数据库提取后等待下一个
//提供一点管道。
var waitChan chan struct{}
doneChan := make(chan struct{}, 1)
for i, iv := range msg.InvList {
var c chan struct{}
//如果这是我们最后发送的信息。
if i == length-1 && len(notFound.InvList) == 0 {
c = doneChan
} else if (i+1)%3 == 0 {
//缓冲以避免发送goroutine块。
c = make(chan struct{}, 1)
}
var err error
switch iv.Type {
case wire.InvTypeWitnessTx:
err = sp.server.pushTxMsg(sp, &iv.Hash, c, waitChan, wire.WitnessEncoding)
case wire.InvTypeTx:
err = sp.server.pushTxMsg(sp, &iv.Hash, c, waitChan, wire.BaseEncoding)
case wire.InvTypeWitnessBlock:
err = sp.server.pushBlockMsg(sp, &iv.Hash, c, waitChan, wire.WitnessEncoding)
case wire.InvTypeBlock:
err = sp.server.pushBlockMsg(sp, &iv.Hash, c, waitChan, wire.BaseEncoding)
case wire.InvTypeFilteredWitnessBlock:
err = sp.server.pushMerkleBlockMsg(sp, &iv.Hash, c, waitChan, wire.WitnessEncoding)
case wire.InvTypeFilteredBlock:
err = sp.server.pushMerkleBlockMsg(sp, &iv.Hash, c, waitChan, wire.BaseEncoding)
default:
peerLog.Warnf("Unknown type in inventory request %d",
iv.Type)
continue
}
if err != nil {
notFound.AddInvVect(iv)
//当获取最终条目失败时
//完成的频道是因为那里才被发送进来的
//未发现未清存货,消耗
//因为现在没有找到存货
//这将暂时使用通道。
if i == len(msg.InvList)-1 && c != nil {
<-c
}
}
numAdded++
waitChan = c
}
if len(notFound.InvList) != 0 {
sp.QueueMessage(notFound, doneChan)
}
//等待消息发送。我们可以发送大量的数据
//这将使对等机在相当长的时间内保持忙碌。
//在这段时间内,我们不会通过他们处理任何其他事情,以便
//想一想我们什么时候应该收到他们的回信-否则就是闲人
//当我们只完成了一半发送块时,超时可能会触发。
if numAdded > 0 {
<-doneChan
}
}
//当对等端收到getBlocks比特币时调用ongetBlocks。
//消息。
func (sp *serverPeer) OnGetBlocks(_ *peer.Peer, msg *wire.MsgGetBlocks) {
//根据块在最佳链中查找最新的已知块
//定位并获取所有块散列,直到
//Wire.MaxBlocksPerMsg已被提取或提供的停止哈希为
//遇到。
//
//如果Genesis块后面没有其他块,
//提供的定位器是已知的。这确实意味着客户端将启动
//如果提供未知区块定位器,则与Genesis区块一起结束。
//
//这反映了引用实现中的行为。
chain := sp.server.chain
hashList := chain.LocateBlocks(msg.BlockLocatorHashes, &msg.HashStop,
wire.MaxBlocksPerMsg)
//生成库存消息。
invMsg := wire.NewMsgInv()
for i := range hashList {
iv := wire.NewInvVect(wire.InvTypeBlock, &hashList[i])
invMsg.AddInvVect(iv)
}
//如果有要发送的内容,则发送库存消息。
if len(invMsg.InvList) > 0 {
invListLen := len(invMsg.InvList)
if invListLen == wire.MaxBlocksPerMsg {
//故意使用最终哈希的副本,因此
//不是库存切片的引用,
//将阻止整个切片符合条件
//一旦发送给GC。
continueHash := invMsg.InvList[invListLen-1].Hash
sp.continueHash = &continueHash
}
sp.QueueMessage(invMsg, nil)
}
}
//OnGetHeaders是在对等端接收到GetHeaders比特币时调用的。
//消息。
func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) {
//如果不同步,则忽略GetHeaders请求。
if !sp.server.syncManager.IsCurrent() {
return
}
//根据块在最佳链中查找最新的已知块
//定位并在其之后获取所有头文件,直到
//已获取Wire.MaxBlockHeadersPermsg或提供的停止
//遇到哈希。
//
//如果Genesis块后面没有其他块,
//提供的定位器是已知的。这确实意味着客户端将启动
//如果提供未知区块定位器,则与Genesis区块一起结束。
//
//这反映了引用实现中的行为。
chain := sp.server.chain
headers := chain.LocateHeaders(msg.BlockLocatorHashes, &msg.HashStop)
//将找到的头发送到请求的对等端。
blockHeaders := make([]*wire.BlockHeader, len(headers))
for i := range headers {
blockHeaders[i] = &headers[i]
}
sp.QueueMessage(&wire.MsgHeaders{Headers: blockHeaders}, nil)
}
//当对等端收到getfilters比特币消息时,调用ongetcfilters。
func (sp *serverPeer) OnGetCFilters(_ *peer.Peer, msg *wire.MsgGetCFilters) {
//如果不同步,忽略getcpilters请求。
if !sp.server.syncManager.IsCurrent() {
return
}
//我们还将确保远程方正在请求
//我们目前实际维护的过滤器。
switch msg.FilterType {
case wire.GCSFilterRegular:
break
default:
peerLog.Debug("Filter request for unknown filter: %v",
msg.FilterType)
return
}
hashes, err := sp.server.chain.HeightToHashRange(
int32(msg.StartHeight), &msg.StopHash, wire.MaxGetCFiltersReqRange,
)
if err != nil {
peerLog.Debugf("Invalid getcfilters request: %v", err)
return
}
//从[]chainhash.hash创建[]*chainhash.hash传递给
//筛选yblockhashes。
hashPtrs := make([]*chainhash.Hash, len(hashes))
for i := range hashes {
hashPtrs[i] = &hashes[i]
}
filters, err := sp.server.cfIndex.FiltersByBlockHashes(
hashPtrs, msg.FilterType,
)
if err != nil {
peerLog.Errorf("Error retrieving cfilters: %v", err)
return
}
for i, filterBytes := range filters {
if len(filterBytes) == 0 {
peerLog.Warnf("Could not obtain cfilter for %v",
hashes[i])
return
}
filterMsg := wire.NewMsgCFilter(
msg.FilterType, &hashes[i], filterBytes,
)
sp.QueueMessage(filterMsg, nil)
}
}
//当对等端收到getcfheader比特币消息时,调用ongetcfheaders。
func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) {
//如果不同步,忽略getcFilterHeader请求。
if !sp.server.syncManager.IsCurrent() {
return
}
//我们还将确保远程方正在请求
//当前实际维护的过滤器的标题。
switch msg.FilterType {
case wire.GCSFilterRegular:
break
default:
peerLog.Debug("Filter request for unknown headers for "+
"filter: %v", msg.FilterType)
return
}
startHeight := int32(msg.StartHeight)
maxResults := wire.MaxCFHeadersPerMsg
//如果startheight为正,则获取前置块哈希,以便
//无法填充PrevFilterHeader字段。
if msg.StartHeight > 0 {
startHeight--
maxResults++
}
//从块索引中获取哈希。
hashList, err := sp.server.chain.HeightToHashRange(
startHeight, &msg.StopHash, maxResults,
)
if err != nil {
peerLog.Debugf("Invalid getcfheaders request: %v", err)
}
//如果startheight大于
//stophash,我们提取一个有效的哈希范围,包括前面的
//过滤头。
if len(hashList) == 0 || (msg.StartHeight > 0 && len(hashList) == 1) {
peerLog.Debug("No results for getcfheaders request")
return
}
//从[]chainhash.hash创建[]*chainhash.hash传递给
//FilterHeadersByBlockHashes。
hashPtrs := make([]*chainhash.Hash, len(hashList))
for i := range hashList {
hashPtrs[i] = &hashList[i]
}
//从数据库中获取所有块的原始筛选器哈希字节。
filterHashes, err := sp.server.cfIndex.FilterHashesByBlockHashes(
hashPtrs, msg.FilterType,
)
if err != nil {
peerLog.Errorf("Error retrieving cfilter hashes: %v", err)
return
}
//生成并发送cfheaders消息。
headersMsg := wire.NewMsgCFHeaders()
//填充PrevFilterHeader字段。
if msg.StartHeight > 0 {
prevBlockHash := &hashList[0]
//从中获取原始提交的筛选器头字节
//数据库。
headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash(
prevBlockHash, msg.FilterType)
if err != nil {
peerLog.Errorf("Error retrieving CF header: %v", err)
return
}
if len(headerBytes) == 0 {
peerLog.Warnf("Could not obtain CF header for %v", prevBlockHash)
return
}
//将哈希反序列化为PrevFilterHeader。
err = headersMsg.PrevFilterHeader.SetBytes(headerBytes)
if err != nil {
peerLog.Warnf("Committed filter header deserialize "+
"failed: %v", err)
return
}
hashList = hashList[1:]
filterHashes = filterHashes[1:]
}
//填充头饰。
for i, hashBytes := range filterHashes {
if len(hashBytes) == 0 {
peerLog.Warnf("Could not obtain CF hash for %v", hashList[i])
return
}
//反序列化哈希。
filterHash, err := chainhash.NewHash(hashBytes)
if err != nil {
peerLog.Warnf("Committed filter hash deserialize "+
"failed: %v", err)
return
}
headersMsg.AddCFHash(filterHash)
}
headersMsg.FilterType = msg.FilterType
headersMsg.StopHash = msg.StopHash
sp.QueueMessage(headersMsg, nil)
}
//当对等端收到getcfcheckpt比特币消息时,调用ongetcfcheckpt。
func (sp *serverPeer) OnGetCFCheckpt(_ *peer.Peer, msg *wire.MsgGetCFCheckpt) {
//如果不同步,忽略getcfcheckpt请求。
if !sp.server.syncManager.IsCurrent() {
return
}
//我们还将确保远程方正在请求
//我们目前实际维护的过滤器的检查点。
switch msg.FilterType {
case wire.GCSFilterRegular:
break
default:
peerLog.Debug("Filter request for unknown checkpoints for "+
"filter: %v", msg.FilterType)
return
}
//现在我们知道客户机正在获取我们知道的过滤器,
//我们将获取每个检查点间隔的块哈希,以便
//与缓存进行比较,必要时创建新的检查点。
blockHashes, err := sp.server.chain.IntervalBlockHashes(
&msg.StopHash, wire.CFCheckptInterval,
)
if err != nil {
peerLog.Debugf("Invalid getcfilters request: %v", err)
return
}
checkptMsg := wire.NewMsgCFCheckpt(