github.com/aergoio/aergo@v1.3.1/chain/signVerifier.go (about) 1 package chain 2 3 import ( 4 "errors" 5 "time" 6 7 "github.com/aergoio/aergo-actor/actor" 8 "github.com/aergoio/aergo/account/key" 9 "github.com/aergoio/aergo/contract/name" 10 "github.com/aergoio/aergo/internal/enc" 11 "github.com/aergoio/aergo/message" 12 "github.com/aergoio/aergo/pkg/component" 13 "github.com/aergoio/aergo/state" 14 "github.com/aergoio/aergo/types" 15 ) 16 17 type SignVerifier struct { 18 comm component.IComponentRequester 19 20 sdb *state.ChainStateDB 21 22 workerCnt int 23 workCh chan verifyWork 24 doneCh chan verifyWorkRes 25 resultCh chan *VerifyResult 26 27 useMempool bool 28 skipMempool bool /* when sync */ 29 totalHit int 30 } 31 32 type verifyWork struct { 33 idx int 34 tx *types.Tx 35 useMempool bool // not to use aop for performance 36 } 37 38 type verifyWorkRes struct { 39 work *verifyWork 40 err error 41 hit bool 42 } 43 44 type VerifyResult struct { 45 failed bool 46 errs []error 47 } 48 49 var ( 50 ErrTxFormatInvalid = errors.New("tx invalid format") 51 dfltUseMempool = true 52 //logger = log.NewLogger("signverifier") 53 ) 54 55 func NewSignVerifier(comm component.IComponentRequester, sdb *state.ChainStateDB, workerCnt int, useMempool bool) *SignVerifier { 56 sv := &SignVerifier{ 57 comm: comm, 58 sdb: sdb, 59 workerCnt: workerCnt, 60 workCh: make(chan verifyWork, workerCnt), 61 doneCh: make(chan verifyWorkRes, workerCnt), 62 resultCh: make(chan *VerifyResult, 1), 63 useMempool: useMempool, 64 } 65 66 for i := 0; i < workerCnt; i++ { 67 go sv.verifyTxLoop(i) 68 } 69 70 return sv 71 } 72 73 func (sv *SignVerifier) Stop() { 74 close(sv.workCh) 75 close(sv.doneCh) 76 } 77 78 func (sv *SignVerifier) verifyTxLoop(workerNo int) { 79 logger.Debug().Int("worker", workerNo).Msg("verify worker run") 80 81 for txWork := range sv.workCh { 82 //logger.Debug().Int("worker", workerNo).Int("idx", txWork.idx).Msg("get work to verify tx") 83 hit, err := sv.verifyTx(sv.comm, txWork.tx, txWork.useMempool) 84 85 if err != nil { 86 logger.Error().Int("worker", workerNo).Bool("hit", hit).Str("hash", enc.ToString(txWork.tx.GetHash())). 87 Err(err).Msg("error verify tx") 88 } 89 90 sv.doneCh <- verifyWorkRes{work: &txWork, err: err, hit: hit} 91 } 92 93 logger.Debug().Int("worker", workerNo).Msg("verify worker stop") 94 } 95 96 func (sv *SignVerifier) isExistInMempool(comm component.IComponentRequester, tx *types.Tx) (bool, error) { 97 if !sv.useMempool { 98 return false, nil 99 } 100 101 result, err := comm.RequestToFutureResult(message.MemPoolSvc, &message.MemPoolExist{Hash: tx.GetHash()}, time.Second, 102 "chain/signverifier/verifytx") 103 if err != nil { 104 logger.Error().Err(err).Msg("failed to get verify from mempool") 105 if err == actor.ErrTimeout { 106 return false, nil 107 } 108 return false, err 109 } 110 111 msg := result.(*message.MemPoolExistRsp) 112 if msg.Tx != nil { 113 return true, nil 114 } 115 116 return false, nil 117 } 118 119 func (sv *SignVerifier) verifyTx(comm component.IComponentRequester, tx *types.Tx, useMempool bool) (hit bool, err error) { 120 account := tx.GetBody().GetAccount() 121 if account == nil { 122 return false, ErrTxFormatInvalid 123 } 124 125 if useMempool { 126 if hit, err = sv.isExistInMempool(comm, tx); err != nil { 127 return false, err 128 } 129 if hit { 130 return hit, nil 131 } 132 } 133 134 if tx.NeedNameVerify() { 135 cs, err := sv.sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte(types.AergoName))) 136 if err != nil { 137 logger.Error().Err(err).Msg("failed to get verify because of openning contract error") 138 return false, err 139 } 140 address := name.GetOwner(cs, tx.Body.Account) 141 err = key.VerifyTxWithAddress(tx, address) 142 if err != nil { 143 return false, err 144 } 145 } else { 146 err := key.VerifyTx(tx) 147 if err != nil { 148 return false, err 149 } 150 } 151 return false, nil 152 } 153 154 func (sv *SignVerifier) RequestVerifyTxs(txlist *types.TxList) { 155 txs := txlist.GetTxs() 156 txLen := len(txs) 157 158 if txLen == 0 { 159 sv.resultCh <- &VerifyResult{failed: false, errs: nil} 160 return 161 } 162 163 errs := make([]error, txLen, txLen) 164 165 //logger.Debug().Int("txlen", txLen).Msg("verify tx start") 166 useMempool := sv.useMempool && !sv.skipMempool 167 168 go func() { 169 for i, tx := range txs { 170 //logger.Debug().Int("idx", i).Msg("push tx start") 171 sv.workCh <- verifyWork{idx: i, tx: tx, useMempool: useMempool} 172 } 173 }() 174 175 go func() { 176 var doneCnt = 0 177 failed := false 178 sv.totalHit = 0 179 180 start := time.Now() 181 LOOP: 182 for { 183 select { 184 case result := <-sv.doneCh: 185 doneCnt++ 186 //logger.Debug().Int("donecnt", doneCnt).Msg("verify tx done") 187 188 if result.work.idx < 0 || result.work.idx >= txLen { 189 logger.Error().Int("idx", result.work.idx).Msg("Invalid Verify Result Index") 190 continue 191 } 192 193 errs[result.work.idx] = result.err 194 195 if result.err != nil { 196 logger.Error().Err(result.err).Int("txno", result.work.idx). 197 Msg("verifing tx failed") 198 failed = true 199 } 200 201 if result.hit { 202 sv.totalHit++ 203 } 204 205 if doneCnt == txLen { 206 break LOOP 207 } 208 } 209 } 210 sv.resultCh <- &VerifyResult{failed: failed, errs: errs} 211 212 end := time.Now() 213 avg := end.Sub(start) / time.Duration(txLen) 214 newAvg := types.AvgTxVerifyTime.UpdateAverage(avg) 215 216 logger.Debug().Int("hit", sv.totalHit).Int64("curavg", avg.Nanoseconds()).Int64("newavg", newAvg.Nanoseconds()).Msg("verify tx done") 217 }() 218 return 219 } 220 221 func (sv *SignVerifier) WaitDone() (bool, []error) { 222 select { 223 case res := <-sv.resultCh: 224 logger.Debug().Msg("wait verify tx") 225 return res.failed, res.errs 226 } 227 } 228 229 func (sv *SignVerifier) verifyTxsInplace(txlist *types.TxList) (bool, []error) { 230 txs := txlist.GetTxs() 231 txLen := len(txs) 232 errs := make([]error, txLen, txLen) 233 failed := false 234 var hit bool 235 236 logger.Debug().Int("txlen", txLen).Msg("verify tx inplace start") 237 238 for i, tx := range txs { 239 hit, errs[i] = sv.verifyTx(sv.comm, tx, false) 240 failed = true 241 242 if hit { 243 sv.totalHit++ 244 } 245 } 246 247 logger.Debug().Int("totalhit", sv.totalHit).Msg("verify tx inplace done") 248 return failed, errs 249 } 250 251 func (sv *SignVerifier) SetSkipMempool(val bool) { 252 sv.skipMempool = val 253 }