public async Task GetResource_Test() { var transaction = new Transaction { From = Address.Generate(), To = Address.Generate(), Params = ByteString.CopyFromUtf8("test"), MethodName = "TestMethod" }; var result = await _resourceUsageDetectionService.GetResources(transaction); result.Count().ShouldBe(2); result.Contains($"test1.{transaction.From.GetFormatted()}").ShouldBeTrue(); result.Contains("test2"); }
//TODO: for testnet we only have a single chain, thus grouper only take care of txList in one chain (hence Process has chainId as parameter) public async Task <Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> > > ProcessNaive(int chainId, List <Transaction> transactions) { var txResourceHandle = new Dictionary <Transaction, string>(); var failedTxs = new Dictionary <Transaction, Exception>(); if (transactions.Count == 0) { return(new Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> >(new List <List <Transaction> >(), failedTxs)); } Dictionary <string, UnionFindNode> resourceUnionSet = new Dictionary <string, UnionFindNode>(); //set up the union find set as the representation of graph and the connected components will be the resulting groups foreach (var tx in transactions) { UnionFindNode first = null; List <string> resources; try { resources = (await _resourceUsageDetectionService.GetResources(tx)).ToList(); } catch (Exception e) { failedTxs.Add(tx, e); continue; } //Logger.LogDebug(string.Format("tx {0} have resource [{1}]", tx.From, string.Join(" ||| ", resources))); foreach (var resource in resources) { if (!resourceUnionSet.TryGetValue(resource, out var node)) { node = new UnionFindNode(); resourceUnionSet.Add(resource, node); } if (first == null) { first = node; txResourceHandle.Add(tx, resource); } else { node.Union(first); } } } Dictionary <int, List <Transaction> > grouped = new Dictionary <int, List <Transaction> >(); List <List <Transaction> > result = new List <List <Transaction> >(); foreach (var tx in transactions) { if (txResourceHandle.TryGetValue(tx, out var firstResource)) { int nodeId = resourceUnionSet[firstResource].Find().NodeId; if (!grouped.TryGetValue(nodeId, out var group)) { group = new List <Transaction>(); grouped.Add(nodeId, group); } group.Add(tx); } else { if (!failedTxs.ContainsKey(tx)) { //each "resource-free" transaction have its own group result.Add(new List <Transaction>() { tx }); } } } result.AddRange(grouped.Values); Logger.LogInformation(string.Format( "Grouper on chainId \"{0}\" group [{1}] transactions into [{2}] groups with sizes [{3}], There are also {4} transactions failed retriving resource", ChainHelpers.ConvertChainIdToBase58(chainId), transactions.Count, result.Count, string.Join(", ", result.Select(a => a.Count)), failedTxs.Count)); return(new Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> >(result, failedTxs)); }