github.com/amazechain/amc@v0.1.3/internal/txspool/txs_fetcher.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 txspool 18 19 import ( 20 "context" 21 "fmt" 22 "google.golang.org/protobuf/proto" 23 "math/rand" 24 "time" 25 26 "github.com/amazechain/amc/api/protocol/sync_proto" 27 "github.com/amazechain/amc/api/protocol/types_pb" 28 "github.com/amazechain/amc/common" 29 "github.com/amazechain/amc/common/message" 30 "github.com/amazechain/amc/common/transaction" 31 "github.com/amazechain/amc/common/types" 32 "github.com/amazechain/amc/log" 33 "github.com/libp2p/go-libp2p/core/peer" 34 "go.uber.org/zap" 35 ) 36 37 const ( 38 BloomFetcherMaxTime = 10 * time.Minute 39 BloomSendTransactionTime = 10 * time.Second 40 BloomSendMaxTransactions = 100 41 ) 42 43 var ( 44 ErrBadPeer = fmt.Errorf("bad peer error") 45 ) 46 47 // txsRequest 48 type txsRequest struct { 49 hashes hashes // 50 bloom *types.Bloom // 51 peer peer.ID // 52 } 53 54 type hashes []types.Hash 55 56 func (h hashes) pop() types.Hash { 57 old := h 58 n := len(old) 59 x := old[n-1] 60 h = old[0 : n-1] 61 return x 62 } 63 64 type TxsFetcher struct { 65 quit chan struct{} 66 67 finished bool 68 peers common.PeerMap 69 p2pServer common.INetwork 70 71 peerRequests map[peer.ID]*txsRequest // other peer requests 72 73 bloom *types.Bloom 74 fetched map[types.Hash]bool // 75 76 getTx func(hash types.Hash) *transaction.Transaction 77 addTxs func([]*transaction.Transaction) []error 78 pendingTxs func(enforceTips bool) map[types.Address][]*transaction.Transaction 79 80 // fetchTxs 81 //fetchTxs func(string, []types.Hash) 82 // ch 83 peerJoinCh chan *common.PeerJoinEvent 84 peerDropCh chan *common.PeerDropEvent 85 // 86 87 ctx context.Context 88 cancel context.CancelFunc 89 } 90 91 func NewTxsFetcher(ctx context.Context, getTx func(hash types.Hash) *transaction.Transaction, addTxs func([]*transaction.Transaction) []error, pendingTxs func(enforceTips bool) map[types.Address][]*transaction.Transaction, p2pServer common.INetwork, peers common.PeerMap, bloom *types.Bloom) *TxsFetcher { 92 93 c, cancel := context.WithCancel(ctx) 94 f := &TxsFetcher{ 95 quit: make(chan struct{}), 96 peers: peers, 97 peerRequests: make(map[peer.ID]*txsRequest), 98 fetched: make(map[types.Hash]bool), 99 p2pServer: p2pServer, 100 addTxs: addTxs, 101 getTx: getTx, 102 pendingTxs: pendingTxs, 103 bloom: bloom, 104 peerJoinCh: make(chan *common.PeerJoinEvent, 10), 105 peerDropCh: make(chan *common.PeerDropEvent, 10), 106 finished: false, 107 108 ctx: c, 109 cancel: cancel, 110 } 111 112 return f 113 } 114 115 func (f TxsFetcher) Start() error { 116 go f.sendBloomTransactionLoop() 117 go f.bloomBroadcastLoop() 118 return nil 119 } 120 121 // sendBloomTransactionLoop 122 func (f TxsFetcher) sendBloomTransactionLoop() { 123 tick := time.NewTicker(BloomSendTransactionTime) 124 125 select { 126 case <-tick.C: 127 for ID, req := range f.peerRequests { 128 if p, ok := f.peers[ID]; ok == true { 129 130 var txs []*types_pb.Transaction 131 132 for i := 0; i < BloomSendMaxTransactions; i++ { 133 hash := req.hashes.pop() 134 tx := f.getTx(hash) 135 txs = append(txs, tx.ToProtoMessage().(*types_pb.Transaction)) 136 } 137 msg := &sync_proto.SyncTask{ 138 Id: rand.Uint64(), 139 Ok: true, 140 SyncType: sync_proto.SyncType_TransactionRes, 141 Payload: &sync_proto.SyncTask_SyncTransactionResponse{ 142 SyncTransactionResponse: &sync_proto.SyncTransactionResponse{ 143 Transactions: txs, 144 }, 145 }, 146 } 147 data, _ := proto.Marshal(msg) 148 p.WriteMsg(message.MsgTransaction, data) 149 } 150 } 151 case <-f.ctx.Done(): 152 return 153 } 154 } 155 156 func (f TxsFetcher) bloomBroadcastLoop() { 157 if f.bloom == nil { 158 return 159 } 160 tick := time.NewTicker(BloomFetcherMaxTime) 161 bloom, err := f.bloom.Marshal() 162 if err != nil { 163 log.Warn("txs fetcher bloom Marshal err", zap.Error(err)) 164 return 165 } 166 167 msg := &sync_proto.SyncTask{ 168 Id: rand.Uint64(), 169 Ok: true, 170 SyncType: sync_proto.SyncType_TransactionReq, 171 Payload: &sync_proto.SyncTask_SyncTransactionRequest{ 172 SyncTransactionRequest: &sync_proto.SyncTransactionRequest{ 173 Bloom: bloom, 174 }, 175 }, 176 } 177 request, _ := proto.Marshal(msg) 178 select { 179 case peerId := <-f.peerJoinCh: 180 f.peers[peerId.Peer].WriteMsg(message.MsgTransaction, request) 181 case <-tick.C: 182 case <-f.ctx.Done(): 183 return 184 } 185 } 186 187 // ConnHandler handler peer message 188 func (f TxsFetcher) ConnHandler(data []byte, ID peer.ID) error { 189 _, ok := f.peers[ID] 190 if !ok { 191 return ErrBadPeer 192 } 193 194 syncTask := sync_proto.SyncTask{} 195 if err := proto.Unmarshal(data, &syncTask); err != nil { 196 log.Errorf("receive sync task(headersResponse) msg err: %v", err) 197 return err 198 } 199 200 //taskID := syncTask.Id 201 log.Debugf("receive synctask msg from :%v, task type: %v, ok:%v", ID, syncTask.SyncType, syncTask.Ok) 202 203 switch syncTask.SyncType { 204 205 case sync_proto.SyncType_TransactionReq: 206 request := syncTask.Payload.(*sync_proto.SyncTask_SyncTransactionRequest).SyncTransactionRequest 207 if _, ok := f.peerRequests[ID]; ok == false { 208 209 bloom := new(types.Bloom) 210 err := bloom.UnMarshalBloom(request.Bloom) 211 if err == nil { 212 var txs []*transaction.Transaction 213 var hashes []types.Hash 214 pending := f.pendingTxs(false) 215 for _, batch := range pending { 216 txs = append(txs, batch...) 217 } 218 for _, tx := range txs { 219 hash := tx.Hash() 220 if !bloom.Contain(hash.Bytes()) { 221 hashes = append(hashes, hash) 222 } 223 } 224 f.peerRequests[ID] = &txsRequest{ 225 bloom: bloom, 226 hashes: hashes, 227 peer: ID, 228 } 229 } 230 } 231 232 case sync_proto.SyncType_TransactionRes: 233 //response := syncTask.Payload.(*sync_proto.SyncTask_SyncTransactionResponse).SyncTransactionResponse 234 //var txs []*transaction.Transaction 235 //for _, tranPb := range response.Transactions { 236 //if _, ok := f.fetched[utils.ConvertH256ToHash(tranPb.Hash)]; ok == false { 237 // f.fetched[utils.ConvertH256ToHash(tranPb.Hash)] = true 238 // tx, err := transaction.FromProtoMessage(tranPb) 239 // if err == nil { 240 // txs = append(txs, tx) 241 // } 242 //} 243 //} 244 //if len(txs) > 0 { 245 // f.addTxs(txs) 246 //} 247 } 248 return nil 249 }