github.com/amazechain/amc@v0.1.3/internal/download/download.go (about) 1 // Copyright 2022 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The AmazeChain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package download 18 19 import ( 20 "context" 21 "fmt" 22 "github.com/amazechain/amc/utils" 23 "github.com/holiman/uint256" 24 "google.golang.org/protobuf/proto" 25 "hash" 26 "sync" 27 "sync/atomic" 28 "time" 29 30 "github.com/amazechain/amc/api/protocol/sync_proto" 31 "github.com/amazechain/amc/api/protocol/types_pb" 32 "github.com/amazechain/amc/common" 33 "github.com/amazechain/amc/log" 34 event "github.com/amazechain/amc/modules/event/v2" 35 "github.com/libp2p/go-libp2p/core/peer" 36 "go.uber.org/zap" 37 ) 38 39 var ( 40 ErrBusy = fmt.Errorf("busy") 41 ErrCanceled = fmt.Errorf("syncing canceled (requested)") 42 ErrSyncBlock = fmt.Errorf("err sync block") 43 ErrTimeout = fmt.Errorf("timeout") 44 ErrBadPeer = fmt.Errorf("bad peer error") 45 ErrNoPeers = fmt.Errorf("no peers to download") 46 ErrInvalidPubSub = fmt.Errorf("PubSub is nil") 47 ) 48 49 const ( 50 maxHeaderFetch = 192 //Get the number of headers at a time 51 maxBodiesFetch = 128 // Get the number of bodies at a time 52 maxResultsProcess = 2048 // Number of content download results to import at once into the chain 53 headerDownloadInterval = 3 * time.Second // header download interval 54 syncPeerCount = 6 55 syncTimeTick = time.Duration(10 * time.Second) 56 syncCheckTimes = 1 57 syncTimeOutPerRequest = time.Duration(1 * time.Minute) 58 syncPeerIntervalRequest = time.Duration(3 * time.Second) 59 syncPeerInfoTimeTick = time.Duration(10 * time.Second) 60 maxDifferenceNumber = 2 61 ) 62 63 type headerResponse struct { 64 taskID uint64 65 ok bool 66 headers []*types_pb.Header 67 } 68 69 type bodyResponse struct { 70 taskID uint64 71 ok bool 72 bodies []*types_pb.Block 73 } 74 75 type blockTask struct { 76 taskID uint64 77 ok bool 78 number []uint256.Int 79 } 80 81 type Task struct { 82 taskID uint64 83 Id peer.ID 84 H hash.Hash 85 TimeBegin time.Time 86 IsSync bool 87 IndexBegin uint256.Int 88 IndexEnd uint256.Int 89 } 90 91 type Downloader struct { 92 mode uint32 // sync mode , use d.getMode() to get the SyncMode 93 94 bc common.IBlockChain 95 network common.INetwork 96 isDownloading int32 97 98 highestNumber uint256.Int 99 100 ctx context.Context 101 cancel context.CancelFunc 102 cancelLock sync.RWMutex 103 cancelWg sync.WaitGroup // 104 once sync.Once 105 106 errorCh chan error 107 108 pubsub common.IPubSub 109 peersInfo *peersInfo 110 111 headerTasks []Task 112 headerProcessingTasks map[uint64]Task 113 headerResultStore map[uint256.Int]*types_pb.Header 114 headerTaskLock sync.Mutex 115 // 116 headerProcCh chan *headerResponse 117 118 // 119 //bodyTaskCh chan *blockTask 120 blockProcCh chan *bodyResponse 121 122 bodyTaskPoolLock sync.Mutex 123 bodyTaskPool []*blockTask 124 bodyProcessingTasks map[uint64]*blockTask 125 bodyResultStore map[uint256.Int]*types_pb.Block 126 } 127 128 func NewDownloader(ctx context.Context, bc common.IBlockChain, network common.INetwork, pubsub common.IPubSub, peers common.PeerMap) common.IDownloader { 129 c, cancel := context.WithCancel(ctx) 130 131 highestNumber := bc.CurrentBlock().Number64().Clone() 132 for _, peer := range peers { 133 if highestNumber.Uint64() < peer.CurrentHeight.Uint64() { 134 highestNumber = peer.CurrentHeight.Clone() 135 } 136 } 137 138 return &Downloader{ 139 mode: uint32(FullSync), 140 bc: bc, 141 network: network, 142 ctx: c, 143 cancel: cancel, 144 isDownloading: 0, 145 pubsub: pubsub, 146 errorCh: make(chan error, 10), 147 headerTasks: make([]Task, 0), 148 headerProcessingTasks: make(map[uint64]Task), 149 headerResultStore: make(map[uint256.Int]*types_pb.Header), 150 headerProcCh: make(chan *headerResponse, 10), 151 blockProcCh: make(chan *bodyResponse, 10), 152 bodyTaskPool: make([]*blockTask, 0), 153 bodyProcessingTasks: make(map[uint64]*blockTask), 154 bodyResultStore: make(map[uint256.Int]*types_pb.Block), 155 highestNumber: *highestNumber, 156 peersInfo: newPeersInfo(c, peers), 157 } 158 } 159 160 func (d *Downloader) getMode() SyncMode { 161 return SyncMode(atomic.LoadUint32(&d.mode)) 162 } 163 164 func (d *Downloader) FindBlock(number uint64, peerID peer.ID) (uint64, error) { 165 return 0, nil 166 } 167 168 func (d *Downloader) waitAvailablePeer() { 169 timer := time.NewTicker(1 * time.Second) 170 defer timer.Stop() 171 172 timeOutTimer := time.NewTicker(60 * time.Second) 173 defer timeOutTimer.Stop() 174 175 for { 176 select { 177 case <-d.ctx.Done(): 178 return 179 case <-timer.C: 180 peers := d.peersInfo.findPeers(new(uint256.Int).AddUint64(d.bc.CurrentBlock().Number64(), 1), 10) 181 if len(peers) > 0 { 182 return 183 } 184 case <-timeOutTimer.C: 185 log.Warn("Can not find Peers") 186 } 187 } 188 } 189 190 // Start Downloader 191 func (d *Downloader) Start() error { 192 // 193 go d.pubSubLoop() 194 // 195 if d.network.Bootstrapped() { 196 //todo 197 //log.Debugf("boot node") 198 event.GlobalEvent.Send(common.DownloaderFinishEvent{}) 199 return nil 200 } 201 202 go d.synchronise() 203 return nil 204 } 205 206 // Start 207 func (d *Downloader) doSync(mode SyncMode) error { 208 209 log.Info("do sync", zap.Int("SyncMode", int(mode))) 210 if !atomic.CompareAndSwapInt32(&d.isDownloading, 0, 1) { 211 return ErrBusy 212 } 213 defer atomic.StoreInt32(&d.isDownloading, 0) 214 215 // blockChain current block height 216 origin, err := d.findAncestor() 217 if err != nil { 218 return err 219 } 220 // downloader current height 221 latest, err := d.findHead() 222 if err != nil { 223 return err 224 } 225 226 var fetchers []func() error 227 228 switch mode { 229 case HeaderSync: 230 default: 231 fetchers = append(fetchers, func() error { return d.fetchHeaders(origin, latest) }) 232 fetchers = append(fetchers, func() error { return d.fetchBodies(latest) }) 233 fetchers = append(fetchers, func() error { return d.processHeaders() }) 234 } 235 236 // assemble 237 fetchers = append(fetchers, func() error { return d.processBodies() }) 238 fetchers = append(fetchers, func() error { return d.processChain() }) 239 240 return d.spawnSync(fetchers) 241 } 242 243 // spawnSync 244 func (d *Downloader) spawnSync(fetchers []func() error) error { 245 errc := make(chan error, len(fetchers)) 246 d.cancelWg.Add(len(fetchers)) 247 for _, fn := range fetchers { 248 fn := fn 249 go func() { defer d.cancelWg.Done(); errc <- fn() }() 250 } 251 var err error 252 for i := 0; i < len(fetchers); i++ { 253 if i == len(fetchers)-1 { 254 } 255 if err = <-errc; err != nil { 256 break 257 } 258 } 259 d.Close() 260 return err 261 } 262 263 func (d *Downloader) SyncHeader() error { 264 return d.doSync(HeaderSync) 265 } 266 267 func (d *Downloader) SyncBody() error { 268 return nil 269 } 270 271 func (d *Downloader) SyncTx() error { 272 return nil 273 } 274 275 func (d *Downloader) IsDownloading() bool { 276 ok := atomic.LoadInt32(&d.isDownloading) 277 if ok == 1 { 278 return true 279 } else if ok == 0 { 280 return false 281 } 282 return true 283 } 284 285 func (d *Downloader) findAncestor() (uint256.Int, error) { 286 return *d.bc.CurrentBlock().Number64(), nil 287 } 288 289 func (d *Downloader) findHead() (uint256.Int, error) { 290 //if d.highestNumber.IsEmpty { 291 // return d.highestNumber, ErrSyncBlock 292 //} 293 return d.highestNumber, nil 294 } 295 296 func (d *Downloader) pubSubLoop() { 297 defer func() { 298 close(d.errorCh) 299 }() 300 defer d.cancel() 301 302 highestBlockCh := make(chan common.ChainHighestBlock) 303 defer close(highestBlockCh) 304 highestSub := event.GlobalEvent.Subscribe(highestBlockCh) 305 defer highestSub.Unsubscribe() 306 307 for { 308 select { 309 case <-d.ctx.Done(): 310 return 311 case err := <-highestSub.Err(): 312 log.Debugf("receive a err from highestSub %v", err) 313 return 314 case highestBlock, ok := <-highestBlockCh: 315 if ok && highestBlock.Block.Number64().Uint64() > d.highestNumber.Uint64() { 316 log.Debugf("receive a new highestBlock block number: %d", highestBlock.Block.Number64().Uint64()) 317 d.highestNumber = *highestBlock.Block.Number64() 318 if highestBlock.Inserted { 319 d.peersInfo.peerInfoBroadcast(highestBlock.Block.Number64()) 320 } 321 //else { 322 // d.bodyResultStore[*highestBlock.Block.Number64()] = highestBlock.Block.ToProtoMessage().(*types_pb.PBlock) 323 //} 324 } 325 } 326 } 327 } 328 329 // runLoop 330 func (d *Downloader) synchronise() { 331 log.Info("start downloader") 332 defer log.Info("downloader finished") 333 // 334 d.waitAvailablePeer() 335 // 336 event.GlobalEvent.Send(common.DownloaderStartEvent{}) 337 defer event.GlobalEvent.Send(common.DownloaderFinishEvent{}) 338 339 defer d.cancel() 340 tick := time.NewTicker(syncTimeTick) 341 defer tick.Stop() 342 // checked := 1 343 344 for { 345 select { 346 case <-d.ctx.Done(): 347 return 348 case err, ok := <-d.errorCh: 349 if ok { 350 log.Errorf("failed to running downloader, err:%v", err) 351 } 352 return 353 case <-tick.C: 354 difference := new(uint256.Int).Sub(&d.highestNumber, d.bc.CurrentBlock().Number64()) 355 log.Tracef("highest: %d, current: %d", d.highestNumber.Uint64(), d.bc.CurrentBlock().Number64().Uint64()) 356 if difference.Uint64() > 1 { 357 log.Infof("start downloader Compare Loop remote highestNumber: %d, current number: %d, difference: %d", d.highestNumber.Uint64(), d.bc.CurrentBlock().Number64().Uint64(), difference.Uint64()) 358 err := d.doSync(d.getMode()) 359 if err != nil { 360 log.Errorf("failed to running downloader, err:%v", err) 361 } 362 return 363 } 364 //if d.highestNumber.Uint64() != 0 && difference.Uint64() ==0 { 365 // return 366 //} 367 //} else { 368 // if checked >= syncCheckTimes { 369 // return 370 // } 371 // checked++ 372 //} 373 tick.Reset(syncTimeTick) 374 } 375 } 376 } 377 378 func (d Downloader) calculateHeight(peer2 common.Peer) error { 379 if d.bc.CurrentBlock().Number64().Uint64() == 0 { 380 381 } 382 return nil 383 } 384 385 func (d *Downloader) ConnHandler(data []byte, ID peer.ID) error { 386 p, ok := d.peersInfo.get(ID) 387 if !ok { 388 return ErrBadPeer 389 } 390 391 syncTask := sync_proto.SyncTask{} 392 if err := proto.Unmarshal(data, &syncTask); err != nil { 393 log.Errorf("receive sync task(headersResponse) msg err: %v", err) 394 return err 395 } 396 397 taskID := syncTask.Id 398 params := make([]interface{}, 0) 399 params = append(params, "peerID", ID, "taskType", syncTask.SyncType, "taskID", taskID, "isOK", syncTask.Ok) 400 401 switch syncTask.SyncType { 402 403 case sync_proto.SyncType_HeaderRes: 404 headersResponse := syncTask.Payload.(*sync_proto.SyncTask_SyncHeaderResponse).SyncHeaderResponse 405 params = append(params, "headerCount", len(headersResponse.Headers), "headerNumberFrom", utils.ConvertH256ToUint256Int(headersResponse.Headers[0].Number).Uint64(), "headerNumberTo", utils.ConvertH256ToUint256Int(headersResponse.Headers[len(headersResponse.Headers)-1].Number).Uint64()) 406 d.headerProcCh <- &headerResponse{taskID: taskID, ok: syncTask.Ok, headers: headersResponse.Headers} 407 408 case sync_proto.SyncType_HeaderReq: 409 headerRequest := syncTask.Payload.(*sync_proto.SyncTask_SyncHeaderRequest).SyncHeaderRequest 410 params = append(params, "Amount", utils.ConvertH256ToUint256Int(headerRequest.Amount).Uint64(), "headerNumberFrom", utils.ConvertH256ToUint256Int(headerRequest.Number).Uint64()) 411 go d.responseHeaders(taskID, p, headerRequest) 412 413 case sync_proto.SyncType_BodyRes: 414 bodiesResponse := syncTask.Payload.(*sync_proto.SyncTask_SyncBlockResponse).SyncBlockResponse 415 params = append(params, "blocksCount", len(bodiesResponse.Blocks), "bodyNumberFrom", utils.ConvertH256ToUint256Int(bodiesResponse.Blocks[0].Header.Number).Uint64(), "bodyNumberTo", utils.ConvertH256ToUint256Int(bodiesResponse.Blocks[len(bodiesResponse.Blocks)-1].Header.Number).Uint64()) 416 d.blockProcCh <- &bodyResponse{taskID: taskID, ok: syncTask.Ok, bodies: bodiesResponse.Blocks} 417 418 case sync_proto.SyncType_BodyReq: 419 blockRequest := syncTask.Payload.(*sync_proto.SyncTask_SyncBlockRequest).SyncBlockRequest 420 params = append(params, "bodyNumberFrom", utils.ConvertH256ToUint256Int(blockRequest.Number[0]).Uint64(), "bodyNumberTo", utils.ConvertH256ToUint256Int(blockRequest.Number[len(blockRequest.Number)-1]).Uint64()) 421 go d.responseBlocks(taskID, p, blockRequest) 422 423 case sync_proto.SyncType_PeerInfoBroadcast: 424 peerInfoBroadcast := syncTask.Payload.(*sync_proto.SyncTask_SyncPeerInfoBroadcast).SyncPeerInfoBroadcast 425 // 426 currentNumber := utils.ConvertH256ToUint256Int(peerInfoBroadcast.Number) 427 currentDifficulty := utils.ConvertH256ToUint256Int(peerInfoBroadcast.Difficulty) 428 params = append(params, "Number", currentNumber, "Difficulty", currentDifficulty) 429 // 430 if currentNumber.Uint64() > d.highestNumber.Uint64() { 431 d.highestNumber.Set(currentNumber.Clone()) 432 } 433 d.peersInfo.update(p.ID(), currentNumber, currentDifficulty) 434 } 435 436 log.Info("receive sync task msg", params...) 437 438 return nil 439 } 440 441 func (d *Downloader) Close() error { 442 d.cancelLock.Lock() 443 defer d.cancelLock.Unlock() 444 d.cancel() 445 d.cancelWg.Wait() 446 return nil 447 }