github.com/aergoio/aergo@v1.3.1/syncer/stubsyncer.go (about) 1 package syncer 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/aergoio/aergo/p2p/p2putil" 12 13 "github.com/aergoio/aergo-actor/actor" 14 "github.com/aergoio/aergo/chain" 15 "github.com/aergoio/aergo/message" 16 "github.com/aergoio/aergo/pkg/component" 17 "github.com/aergoio/aergo/types" 18 "github.com/stretchr/testify/assert" 19 ) 20 21 type StubSyncer struct { 22 realSyncer *Syncer 23 stubRequester *StubRequester 24 25 localChain *chain.StubBlockChain 26 remoteChain *chain.StubBlockChain 27 28 stubPeers []*StubPeer 29 30 t *testing.T 31 32 waitGroup *sync.WaitGroup 33 34 cfg *SyncerConfig 35 36 checkResultFn TestResultFn 37 getAnchorsHookFn GetAnchorsHookFn 38 getSyncAncestorHookFn GetSyncAncestorHookFn 39 } 40 41 type TestResultFn func(stubSyncer *StubSyncer) 42 type GetAnchorsHookFn func(stubSyncer *StubSyncer) 43 type GetSyncAncestorHookFn func(stubSyncer *StubSyncer, msg *message.GetSyncAncestor) 44 45 var ( 46 targetPeerID = types.PeerID([]byte(fmt.Sprintf("peer-%d", 0))) 47 ) 48 49 func makeStubPeerSet(remoteChains []*chain.StubBlockChain) []*StubPeer { 50 stubPeers := make([]*StubPeer, len(remoteChains)) 51 52 for i, chain := range remoteChains { 53 stubPeers[i] = NewStubPeer(i, uint64(chain.Best), chain) 54 } 55 56 return stubPeers 57 } 58 59 func NewTestSyncer(t *testing.T, localChain *chain.StubBlockChain, remoteChain *chain.StubBlockChain, peers []*StubPeer, cfg *SyncerConfig) *StubSyncer { 60 syncer := NewSyncer(nil, localChain, cfg) 61 testsyncer := &StubSyncer{realSyncer: syncer, localChain: localChain, remoteChain: remoteChain, stubPeers: peers, cfg: cfg, t: t} 62 63 testsyncer.stubRequester = NewStubRequester() 64 65 syncer.SetRequester(testsyncer.stubRequester) 66 67 return testsyncer 68 } 69 70 func (stubSyncer *StubSyncer) start() { 71 stubSyncer.waitGroup = &sync.WaitGroup{} 72 stubSyncer.waitGroup.Add(1) 73 74 go func() { 75 defer stubSyncer.waitGroup.Done() 76 77 for { 78 msg := stubSyncer.stubRequester.recvMessage() 79 isStop := stubSyncer.handleMessage(msg) 80 if isStop { 81 return 82 } 83 } 84 }() 85 } 86 87 func (stubSyncer *StubSyncer) waitStop() { 88 logger.Info().Msg("test syncer wait to stop") 89 stubSyncer.waitGroup.Wait() 90 logger.Info().Msg("test syncer stopped") 91 } 92 93 func isOtherActorRequest(msg interface{}) bool { 94 switch msg.(type) { 95 case *message.GetSyncAncestor: 96 return true 97 case *message.GetAnchors: 98 return true 99 case *message.GetAncestor: 100 return true 101 case *message.GetHashByNo: 102 return true 103 case *message.GetHashes: 104 return true 105 case *message.GetPeers: 106 return true 107 case *message.GetBlockChunks: 108 return true 109 case *message.AddBlock: 110 return true 111 } 112 113 return false 114 } 115 116 func (stubSyncer *StubSyncer) handleMessage(msg interface{}) bool { 117 //prefix handle 118 switch resmsg := msg.(type) { 119 case *message.FinderResult: 120 if resmsg.Ancestor != nil && resmsg.Err == nil && resmsg.Ancestor.No >= 0 { 121 stubSyncer.localChain.Rollback(resmsg.Ancestor) 122 } 123 case *message.CloseFetcher: 124 if resmsg.FromWho == NameHashFetcher { 125 if stubSyncer.cfg.debugContext.debugHashFetcher { 126 assert.Equal(stubSyncer.t, stubSyncer.realSyncer.hashFetcher.lastBlockInfo.No, stubSyncer.cfg.debugContext.targetNo, "invalid hash target") 127 } 128 } else { 129 assert.Fail(stubSyncer.t, "invalid closefetcher") 130 } 131 case *message.SyncStop: 132 if stubSyncer.cfg.debugContext.expErrResult != nil { 133 assert.Equal(stubSyncer.t, stubSyncer.cfg.debugContext.expErrResult, resmsg.Err, "expected syncer stop error") 134 } 135 //check final result 136 if stubSyncer.checkResultFn != nil { 137 stubSyncer.checkResultFn(stubSyncer) 138 } 139 default: 140 } 141 142 if isOtherActorRequest(msg) { 143 logger.Debug().Msg("msg is for testsyncer") 144 145 stubSyncer.handleActorMsg(msg) 146 } else { 147 148 logger.Debug().Msg("msg is for syncer") 149 stubSyncer.realSyncer.handleMessage(msg) 150 } 151 152 //check stop 153 switch resmsg := msg.(type) { 154 case *message.SyncStop: 155 return true 156 case *message.FinderResult: 157 if stubSyncer.cfg.debugContext.expAncestor >= 0 { 158 assert.Equal(stubSyncer.t, uint64(stubSyncer.cfg.debugContext.expAncestor), resmsg.Ancestor.No, "ancestor mismatch") 159 } else if !stubSyncer.realSyncer.isRunning { 160 assert.Equal(stubSyncer.t, stubSyncer.cfg.debugContext.expAncestor, -1, "ancestor mismatch") 161 return true 162 } 163 164 if stubSyncer.cfg.debugContext.debugFinder { 165 return true 166 } 167 case *message.CloseFetcher: 168 if stubSyncer.cfg.debugContext.debugHashFetcher { 169 return true 170 } 171 default: 172 return false 173 } 174 175 return false 176 } 177 178 func (stubSyncer *StubSyncer) handleActorMsg(inmsg interface{}) { 179 switch msg := inmsg.(type) { 180 case *message.GetAnchors: 181 stubSyncer.GetAnchors(msg) 182 case *message.GetSyncAncestor: 183 stubSyncer.GetSyncAncestor(msg) 184 case *message.GetHashByNo: 185 stubSyncer.GetHashByNo(msg) 186 187 case *message.GetHashes: 188 stubSyncer.GetHashes(msg, nil) 189 190 case *message.GetPeers: 191 stubSyncer.GetPeers(msg) 192 193 case *message.GetBlockChunks: 194 stubSyncer.GetBlockChunks(msg) 195 196 case *message.AddBlock: 197 stubSyncer.AddBlock(msg, nil) 198 199 case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing 200 201 default: 202 str := fmt.Sprintf("Missed message. (%v) %s", reflect.TypeOf(msg), msg) 203 stubSyncer.t.Fatal(str) 204 } 205 } 206 207 //reply to requestFuture() 208 func (syncer *StubSyncer) GetAnchors(msg *message.GetAnchors) { 209 if syncer.getAnchorsHookFn != nil { 210 syncer.getAnchorsHookFn(syncer) 211 } 212 213 go func() { 214 if syncer.cfg.debugContext.debugFinder { 215 if syncer.stubPeers[0].timeDelaySec > 0 { 216 logger.Debug().Str("peer", p2putil.ShortForm(types.PeerID(syncer.stubPeers[0].addr.PeerID))).Msg("slow target peer sleep") 217 time.Sleep(syncer.stubPeers[0].timeDelaySec) 218 logger.Debug().Str("peer", p2putil.ShortForm(types.PeerID(syncer.stubPeers[0].addr.PeerID))).Msg("slow target peer wakeup") 219 } 220 } 221 222 hashes, lastno, err := syncer.localChain.GetAnchors() 223 224 rspMsg := message.GetAnchorsRsp{Seq: msg.Seq, Hashes: hashes, LastNo: lastno, Err: err} 225 syncer.stubRequester.sendReply(StubRequestResult{rspMsg, nil}) 226 }() 227 } 228 229 func (syncer *StubSyncer) GetPeers(msg *message.GetPeers) { 230 rspMsg := makePeerReply(syncer.stubPeers) 231 syncer.stubRequester.sendReply(StubRequestResult{rspMsg, nil}) 232 } 233 234 func (syncer *StubSyncer) SendGetSyncAncestorRsp(msg *message.GetSyncAncestor) { 235 //find peer 236 stubPeer := syncer.findStubPeer(msg.ToWhom) 237 ancestor := stubPeer.blockChain.GetAncestorWithHashes(msg.Hashes) 238 239 rspMsg := &message.GetSyncAncestorRsp{Seq: msg.Seq, Ancestor: ancestor} 240 syncer.stubRequester.TellTo(message.SyncerSvc, rspMsg) //TODO refactoring: stubcompRequesterresult 241 } 242 243 func (syncer *StubSyncer) GetSyncAncestor(msg *message.GetSyncAncestor) { 244 if syncer.getSyncAncestorHookFn != nil { 245 syncer.getSyncAncestorHookFn(syncer, msg) 246 } 247 248 syncer.SendGetSyncAncestorRsp(msg) 249 } 250 251 func (syncer *StubSyncer) GetHashByNo(msg *message.GetHashByNo) { 252 //targetPeer = 0 253 hash, err := syncer.stubPeers[0].blockChain.GetHashByNo(msg.BlockNo) 254 rsp := &message.GetHashByNoRsp{Seq: msg.Seq, BlockHash: hash, Err: err} 255 syncer.stubRequester.TellTo(message.SyncerSvc, rsp) 256 } 257 func (syncer *StubSyncer) GetHashes(msg *message.GetHashes, responseErr error) { 258 blkHashes, _ := syncer.remoteChain.GetHashes(msg.PrevInfo, msg.Count) 259 260 assert.Equal(syncer.t, len(blkHashes), int(msg.Count)) 261 rsp := &message.GetHashesRsp{Seq: msg.Seq, PrevInfo: msg.PrevInfo, Hashes: blkHashes, Count: uint64(len(blkHashes)), Err: responseErr} 262 263 syncer.stubRequester.TellTo(message.SyncerSvc, rsp) 264 } 265 266 func (syncer *StubSyncer) GetBlockChunks(msg *message.GetBlockChunks) { 267 stubPeer := syncer.findStubPeer(msg.ToWhom) 268 stubPeer.blockFetched = true 269 270 assert.True(syncer.t, stubPeer != nil, "peer exist") 271 272 if stubPeer.HookGetBlockChunkRsp != nil { 273 stubPeer.HookGetBlockChunkRsp(msg) 274 return 275 } 276 go func() { 277 if stubPeer.timeDelaySec > 0 { 278 logger.Debug().Str("peer", p2putil.ShortForm(types.PeerID(stubPeer.addr.PeerID))).Msg("slow peer sleep") 279 time.Sleep(stubPeer.timeDelaySec) 280 logger.Debug().Str("peer", p2putil.ShortForm(types.PeerID(stubPeer.addr.PeerID))).Msg("slow peer wakeup") 281 } 282 283 //send reply 284 blocks, err := stubPeer.blockChain.GetBlocks(msg.Hashes) 285 286 rsp := &message.GetBlockChunksRsp{Seq: msg.Seq, ToWhom: msg.ToWhom, Blocks: blocks, Err: err} 287 syncer.stubRequester.TellTo(message.SyncerSvc, rsp) 288 }() 289 } 290 291 //ChainService 292 func (syncer *StubSyncer) AddBlock(msg *message.AddBlock, responseErr error) { 293 err := syncer.localChain.AddBlock(msg.Block) 294 295 rsp := &message.AddBlockRsp{BlockNo: msg.Block.GetHeader().BlockNo, BlockHash: msg.Block.GetHash(), Err: err} 296 logger.Debug().Uint64("no", msg.Block.GetHeader().BlockNo).Msg("add block succeed") 297 syncer.stubRequester.TellTo(message.SyncerSvc, rsp) 298 } 299 300 func (syncer *StubSyncer) findStubPeer(peerID types.PeerID) *StubPeer { 301 for _, tmpPeer := range syncer.stubPeers { 302 peerIDStr := string(tmpPeer.addr.PeerID) 303 logger.Info().Str("tmp", peerIDStr).Msg("peer is") 304 if strings.Compare(peerIDStr, string(peerID)) == 0 { 305 return tmpPeer 306 } 307 } 308 309 logger.Error().Str("peer", p2putil.ShortForm(peerID)).Msg("can't find peer") 310 panic("peer find fail") 311 return nil 312 } 313 314 func makePeerReply(stubPeers []*StubPeer) *message.GetPeersRsp { 315 count := len(stubPeers) 316 now := time.Now() 317 peers := make([]*message.PeerInfo, count) 318 for i, p := range stubPeers { 319 peerInfo := &message.PeerInfo{ 320 Addr: p.addr, CheckTime: now, State: p.state, LastBlockHash: p.lastBlk.BlockHash, LastBlockNumber: p.lastBlk.BlockNo, 321 } 322 peers[i] = peerInfo 323 } 324 325 return &message.GetPeersRsp{Peers: peers} 326 } 327 328 //test block fetcher only 329 func (stubSyncer *StubSyncer) runTestBlockFetcher(ctx *types.SyncContext) { 330 stubSyncer.realSyncer.blockFetcher = newBlockFetcher(ctx, stubSyncer.realSyncer.getCompRequester(), stubSyncer.cfg) 331 stubSyncer.realSyncer.blockFetcher.Start() 332 } 333 334 func (stubSyncer *StubSyncer) sendHashSetToBlockFetcher(hashSet *HashSet) { 335 logger.Debug().Uint64("no", hashSet.StartNo).Msg("test syncer pushed hashset to blockfetcher") 336 337 stubSyncer.realSyncer.blockFetcher.hfCh <- hashSet 338 }