/// <summary> /// Try to update the calling graph when updating the function. /// If some functions have unknow reference of foreign edge(call other contract's function), the update will not be approved and nothing will take effect /// </summary> /// <param name=""></param> /// <param name="contractAddress"></param> /// <param name="callingGraph"></param> /// <param name="contractMetadataTemplate"></param> /// <returns>The new calling graph</returns> /// <exception cref="FunctionMetadataException"></exception> public CallGraph TryUpdateAndGetCallingGraph(Address contractAddress, CallGraph callingGraph, ContractMetadataTemplate contractMetadataTemplate) { List <Edge <string> > outEdgesToAdd = new List <Edge <string> >(); //check for unknown reference foreach (var kvPair in contractMetadataTemplate.MethodMetadataTemplates) { var sourceFunc = Replacement.ReplaceValueIntoReplacement(kvPair.Key, Replacement.This, contractAddress.GetFormatted()); foreach (var calledFunc in kvPair.Value.CallingSet) { if (!calledFunc.Contains(Replacement.This)) { Replacement.TryGetReplacementWithIndex(calledFunc, 0, out var memberReplacement); var referenceAddress = contractMetadataTemplate.ContractReferences[ Replacement.Value( memberReplacement)]; //FunctionMetadataTemplate itself ensure this value exist var globalCalledFunc = Replacement.ReplaceValueIntoReplacement(calledFunc, memberReplacement, referenceAddress.GetFormatted()); if (!callingGraph.ContainsVertex(globalCalledFunc)) { throw new FunctionMetadataException( "Unknow reference of the foreign target in edge <" + sourceFunc + "," + calledFunc + "> when trying to add contract " + contractMetadataTemplate.FullName + " into calling graph, consider the target function does not exist in the metadata"); } outEdgesToAdd.Add(new Edge <string>(sourceFunc, globalCalledFunc)); } } } //Merge local calling graph, mind that there are functions that call nothing, they also need to appear in the call graph (to be called in future) foreach (var localVertex in contractMetadataTemplate.LocalCallingGraph.Vertices) { var globalVertex = Replacement.ReplaceValueIntoReplacement(localVertex, Replacement.This, contractAddress.GetFormatted()); callingGraph.AddVertex(globalVertex); foreach (var outEdge in contractMetadataTemplate.LocalCallingGraph.OutEdges(localVertex)) { var toVertex = Replacement.ReplaceValueIntoReplacement(outEdge.Target, Replacement.This, contractAddress.GetFormatted()); callingGraph.AddVerticesAndEdge(new Edge <string>(globalVertex, toVertex)); } } //add foreign edges callingGraph.AddEdgeRange(outEdgesToAdd); return(callingGraph); }
public CallGraph TryRemoveAndGetCallingGraph(Address contractAddress, CallGraph callingGraph, ContractMetadataTemplate contractMetadataTemplate) { foreach (var kvPair in contractMetadataTemplate.MethodMetadataTemplates) { var sourceFunc = Replacement.ReplaceValueIntoReplacement(kvPair.Key, Replacement.This, contractAddress.GetFormatted()); foreach (var calledFunc in kvPair.Value.CallingSet) { if (!calledFunc.Contains(Replacement.This)) { Replacement.TryGetReplacementWithIndex(calledFunc, 0, out var memberReplacement); var referenceAddress = contractMetadataTemplate.ContractReferences[ Replacement.Value( memberReplacement)]; //FunctionMetadataTemplate itself ensure this value exist var globalCalledFunc = Replacement.ReplaceValueIntoReplacement(calledFunc, memberReplacement, referenceAddress.GetFormatted()); if (!callingGraph.ContainsVertex(globalCalledFunc)) { throw new FunctionMetadataException( "Unknow reference of the foreign target in edge <" + sourceFunc + "," + calledFunc + "> when trying to add contract " + contractMetadataTemplate.FullName + " into calling graph, consider the target function does not exist in the metadata"); } callingGraph.RemoveEdge(new Edge <string>(sourceFunc, globalCalledFunc)); } } } foreach (var localVertex in contractMetadataTemplate.LocalCallingGraph.Vertices) { var globalVertex = Replacement.ReplaceValueIntoReplacement(localVertex, Replacement.This, contractAddress.GetFormatted()); callingGraph.AddVertex(globalVertex); foreach (var outEdge in contractMetadataTemplate.LocalCallingGraph.OutEdges(localVertex)) { var toVertex = Replacement.ReplaceValueIntoReplacement(outEdge.Target, Replacement.This, contractAddress.GetFormatted()); callingGraph.RemoveEdge(new Edge <string>(globalVertex, toVertex)); callingGraph.RemoveVertex(globalVertex); callingGraph.RemoveVertex(toVertex); } callingGraph.RemoveVertex(globalVertex); } return(callingGraph); }
public async Task UpdateContract(Address contractAddr, ContractMetadataTemplate oldContractMetadataTemplate, ContractMetadataTemplate newContractMetadataTemplate) { // remove old metadata Dictionary <string, FunctionMetadata> tempMap = new Dictionary <string, FunctionMetadata>(); try { var globalCallGraph = await GetCallingGraphForChain(); var newCallGraph = TryRemoveAndGetCallingGraph(contractAddr, globalCallGraph, oldContractMetadataTemplate); await _functionMetadataManager.AddCallGraphAsync(SerializeCallingGraph(newCallGraph)); foreach (var localFuncName in oldContractMetadataTemplate.ProcessFunctionOrder) { var funcNameWithAddr = Replacement.ReplaceValueIntoReplacement(localFuncName, Replacement.This, contractAddr.GetFormatted()); var funcMetadata = await GetMetadataForNewFunction(funcNameWithAddr, oldContractMetadataTemplate.MethodMetadataTemplates[localFuncName], contractAddr, oldContractMetadataTemplate.ContractReferences, tempMap); tempMap.Add(funcNameWithAddr, funcMetadata); } foreach (var functionMetadata in tempMap) { await _functionMetadataManager.RemoveMetadataAsync(functionMetadata.Key); FunctionMetadataMap.Remove(functionMetadata.Key); } // deploy newm etadata await DeployNewContract(contractAddr, newContractMetadataTemplate); } catch (FunctionMetadataException e) { Logger.LogError(e, "Exception while deploy new contract."); throw; } }
/// <summary> /// //TODO: in fact, only public interface of contact need to be added into FunctionMetadataMap /// </summary> /// <param name="contractAddr"></param> /// <param name="contractMetadataTemplate"></param> /// <exception cref="FunctionMetadataException"></exception> public async Task DeployNewContract(Address contractAddr, ContractMetadataTemplate contractMetadataTemplate) { Dictionary <string, FunctionMetadata> tempMap = new Dictionary <string, FunctionMetadata>(); try { var globalCallGraph = await GetCallingGraphForChain(); var newCallGraph = TryUpdateAndGetCallingGraph(contractAddr, globalCallGraph, contractMetadataTemplate); foreach (var localFuncName in contractMetadataTemplate.ProcessFunctionOrder) { var funcNameWithAddr = Replacement.ReplaceValueIntoReplacement(localFuncName, Replacement.This, contractAddr.GetFormatted()); var funcMetadata = await GetMetadataForNewFunction(funcNameWithAddr, contractMetadataTemplate.MethodMetadataTemplates[localFuncName], contractAddr, contractMetadataTemplate.ContractReferences, tempMap); tempMap.Add(funcNameWithAddr, funcMetadata); } //if no exception is thrown, merge the tempMap into FunctionMetadataMap and update call graph in database await _functionMetadataManager.AddCallGraphAsync(SerializeCallingGraph(newCallGraph)); foreach (var functionMetadata in tempMap) { FunctionMetadataMap.Add(functionMetadata.Key, functionMetadata.Value); await _functionMetadataManager.AddMetadataAsync(functionMetadata.Key, functionMetadata.Value); } } catch (FunctionMetadataException e) { Logger.LogError(e, "Exception while deploy new contract."); throw; } }