diff --git a/api/worker.go b/api/worker.go index 8b07f805..51d5b19e 100644 --- a/api/worker.go +++ b/api/worker.go @@ -36,6 +36,9 @@ type Worker struct { metrics *common.Metrics } +// contractInfoCache is a temporary cache of contract information for ethereum token transfers +type contractInfoCache = map[string]*bchain.ContractInfo + // NewWorker creates new api worker func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState, fiatRates *fiat.FiatRates) (*Worker, error) { w := &Worker{ @@ -666,39 +669,49 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom } func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, addresses map[string]struct{}) []TokenTransfer { - sort.Sort(transfers) tokens := make([]TokenTransfer, len(transfers)) - for i := range transfers { - t := transfers[i] - typeName := bchain.EthereumTokenTypeMap[t.Type] - contractInfo, _, err := w.getContractInfo(t.Contract, typeName) - if err != nil { - glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract) - continue - } - var value *Amount - var values []MultiTokenValue - if t.Type == bchain.MultiToken { - values = make([]MultiTokenValue, len(t.MultiTokenValues)) - for j := range values { - values[j].Id = (*Amount)(&t.MultiTokenValues[j].Id) - values[j].Value = (*Amount)(&t.MultiTokenValues[j].Value) + if len(transfers) > 0 { + sort.Sort(transfers) + contractCache := make(contractInfoCache) + for i := range transfers { + t := transfers[i] + typeName := bchain.EthereumTokenTypeMap[t.Type] + var contractInfo *bchain.ContractInfo + if info, ok := contractCache[t.Contract]; ok { + contractInfo = info + } else { + info, _, err := w.getContractInfo(t.Contract, typeName) + if err != nil { + glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract) + continue + } + contractInfo = info + contractCache[t.Contract] = info + } + var value *Amount + var values []MultiTokenValue + if t.Type == bchain.MultiToken { + values = make([]MultiTokenValue, len(t.MultiTokenValues)) + for j := range values { + values[j].Id = (*Amount)(&t.MultiTokenValues[j].Id) + values[j].Value = (*Amount)(&t.MultiTokenValues[j].Value) + } + } else { + value = (*Amount)(&t.Value) + } + aggregateAddress(addresses, t.From) + aggregateAddress(addresses, t.To) + tokens[i] = TokenTransfer{ + Type: typeName, + Contract: t.Contract, + From: t.From, + To: t.To, + Value: value, + MultiTokenValues: values, + Decimals: contractInfo.Decimals, + Name: contractInfo.Name, + Symbol: contractInfo.Symbol, } - } else { - value = (*Amount)(&t.Value) - } - aggregateAddress(addresses, t.From) - aggregateAddress(addresses, t.To) - tokens[i] = TokenTransfer{ - Type: typeName, - Contract: t.Contract, - From: t.From, - To: t.To, - Value: value, - MultiTokenValues: values, - Decimals: contractInfo.Decimals, - Name: contractInfo.Name, - Symbol: contractInfo.Symbol, } } return tokens