void GenerateSources() { Stopwatch sw = new Stopwatch(); sw.Start(); string[] solFiles; if (!string.IsNullOrEmpty(_solSourceSingleFile)) { solFiles = new[] { _solSourceSingleFile }; } else { solFiles = GetSolContractFiles(_solSourceDirectory); } var outputFlags = new[] { OutputType.Abi, OutputType.EvmBytecodeObject, OutputType.EvmBytecodeOpcodes, OutputType.EvmBytecodeSourceMap, OutputType.EvmDeployedBytecodeObject, OutputType.EvmDeployedBytecodeOpcodes, OutputType.EvmDeployedBytecodeSourceMap, OutputType.DevDoc, OutputType.UserDoc, OutputType.Metadata, OutputType.Ast }; var solcOptimizerSettings = new Optimizer(); if (_solcOptimzer > 0) { solcOptimizerSettings.Enabled = true; solcOptimizerSettings.Runs = _solcOptimzer; } _logger("Compiling solidity files in " + _solSourceDirectory); var soliditySourceContent = new Dictionary <string, string>(); var solcOutput = _solcLib.Compile(solFiles, outputFlags, solcOptimizerSettings, soliditySourceFileContent: soliditySourceContent); sw.Stop(); _logger($"Compiling solidity completed in {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); #region Generated hashes for solidity sources sw.Restart(); // Calculate a deterministic hash of the solidity source code base, including file paths and the Meadow assembly version. var codeBaseHash = KeccakHash.FromString(string.Join('|', soliditySourceContent .OrderBy(k => k.Key) .SelectMany(k => new[] { k.Key, k.Value }) .Concat(new[] { _assemblyVersion }))); _genResults.SolcCodeBaseHash = HexUtil.GetHexFromBytes(codeBaseHash); var flattenedContracts = solcOutput.ContractsFlattened.OrderBy(c => c.SolFile).ToArray(); ContractInfo[] contractInfos = new ContractInfo[solcOutput.ContractsFlattened.Length]; for (var i = 0; i < contractInfos.Length; i++) { var c = flattenedContracts[i]; // Check if any previous contracts have the same name as this one. int dupNames = 0; for (var f = 0; f < i; f++) { if (flattenedContracts[f].ContractName == c.ContractName) { dupNames++; } } string generatedContractName = c.ContractName; // If there are duplicate contract names, prepend a unique amount of underscore suffixes. if (dupNames > 0) { generatedContractName += new string(Enumerable.Repeat('_', dupNames).ToArray()); } contractInfos[i] = new ContractInfo( Util.GetRelativeFilePath(_solSourceDirectory, c.SolFile), generatedContractName, c.Contract, GetSourceHashesXor(c.Contract), c.Contract.Evm.Bytecode.Object); } _logger($"Generated sol source file hashes in {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); sw.Stop(); #endregion _logger("Writing generated output to directory: " + _generatedContractsDirectory); #region Output directory cleanup if (!Directory.Exists(_generatedContractsDirectory)) { _logger("Creating directory: " + _generatedContractsDirectory); Directory.CreateDirectory(_generatedContractsDirectory); } else { var expectedFiles = contractInfos .Select(c => c.ContractName) .Concat(new[] { EventHelperFile, SolcOutputDataHelperFile }) .Select(c => NormalizePath($"{_generatedContractsDirectory}/{c}{G_CS_FILE_EXT}")) .ToArray(); var existingFiles = Directory .GetFiles(_generatedContractsDirectory, $"*{G_CS_FILE_EXT}", SearchOption.TopDirectoryOnly) .Where(f => f.EndsWith(".sol.cs", StringComparison.Ordinal) || f.EndsWith(".sol.resx", StringComparison.Ordinal)) .Select(f => NormalizePath(f)) .ToArray(); // Delete existing files with no corresponding file that can be generated foreach (var existingFile in existingFiles) { bool found = false; foreach (var expected in expectedFiles) { if (expected.Equals(existingFile, StringComparison.InvariantCultureIgnoreCase)) { found = true; break; } } if (!found) { _logger("Deleting outdated file: " + existingFile); File.Delete(existingFile); } } } #endregion #region AST output generation sw.Restart(); GenerateSolcOutputDataFiles(solcOutput, soliditySourceContent, codeBaseHash); sw.Stop(); _logger($"Resx file for solc output generation took: {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); #endregion #region sw.Restart(); var generatedEvents = new List <GeneratedEventMetadata>(); GeneratedContractSourceFiles(contractInfos, generatedEvents); GenerateEventHelper(generatedEvents); sw.Stop(); _logger($"Contract and event source code generation took: {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); #endregion }
void GenerateSources() { Stopwatch sw = new Stopwatch(); sw.Start(); var solFiles = GetSolContractFiles(_solSourceDirectory); var outputFlags = new[] { OutputType.Abi, OutputType.EvmBytecodeObject, OutputType.EvmBytecodeOpcodes, OutputType.EvmBytecodeSourceMap, OutputType.EvmDeployedBytecodeObject, OutputType.EvmDeployedBytecodeOpcodes, OutputType.EvmDeployedBytecodeSourceMap, OutputType.DevDoc, OutputType.UserDoc, OutputType.Metadata, OutputType.Ast }; var solcOptimizerSettings = new Optimizer(); if (_solcOptimzer > 0) { solcOptimizerSettings.Enabled = true; solcOptimizerSettings.Runs = _solcOptimzer; } Console.WriteLine("Compiling solidity files in " + _solSourceDirectory); var soliditySourceContent = new Dictionary <string, string>(); var solcOutput = _solcLib.Compile(solFiles, outputFlags, solcOptimizerSettings, soliditySourceFileContent: soliditySourceContent); sw.Stop(); Console.WriteLine($"Compiling solidity completed in {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); Console.WriteLine("Writing generated output to directory: " + _generatedContractsDirectory); #region Output directory cleanup if (!Directory.Exists(_generatedContractsDirectory)) { Console.WriteLine("Creating directory: " + _generatedContractsDirectory); Directory.CreateDirectory(_generatedContractsDirectory); } else { var expectedFiles = solcOutput.Contracts.Values .SelectMany(c => c.Keys) .Concat(new[] { EventHelperFile, SolcOutputDataHelperFile }) .Select(c => NormalizePath($"{_generatedContractsDirectory}/{c}{G_CS_FILE_EXT}")) .ToArray(); var existingFiles = Directory .GetFiles(_generatedContractsDirectory, $"*{G_CS_FILE_EXT}", SearchOption.TopDirectoryOnly) .Select(f => NormalizePath(f)) .ToArray(); // Delete existing files with no corresponding file that can be generated foreach (var existingFile in existingFiles) { bool found = false; foreach (var expected in expectedFiles) { if (expected.Equals(existingFile, StringComparison.InvariantCultureIgnoreCase)) { found = true; break; } } if (!found) { Console.WriteLine("Deleting outdated file: " + existingFile); File.Delete(existingFile); } } } #endregion #region Generated hashes for solidity sources sw.Restart(); ContractInfo[] contractInfos = new ContractInfo[solcOutput.ContractsFlattened.Length]; var flattenedContracts = solcOutput.ContractsFlattened.OrderBy(c => c.SolFile).ToArray(); for (var i = 0; i < contractInfos.Length; i++) { // Check if any previous contracts have the same name as this one. var c = flattenedContracts[i]; int dupNames = 0; for (var f = 0; f < i; f++) { if (flattenedContracts[f].ContractName == c.ContractName) { dupNames++; } } // If there are duplicate contract names, prepend a unique amount of underscore suffixes. string dupeNameSuffix; if (dupNames > 0) { dupeNameSuffix = new string(Enumerable.Repeat('_', dupNames).ToArray()); } else { dupeNameSuffix = string.Empty; } contractInfos[i] = new ContractInfo( Util.GetRelativeFilePath(_solSourceDirectory, c.SolFile), c.ContractName + dupeNameSuffix, c.Contract, GetSourceHashesXor(c.Contract), c.Contract.Evm.Bytecode.Object); } for (var i = 0; i < contractInfos.Length; i++) { var cur = contractInfos[i]; for (var j = 0; j < contractInfos.Length; j++) { if (i == j) { continue; } var other = contractInfos[j]; if (cur.ContractName.Equals(other.ContractName, StringComparison.OrdinalIgnoreCase)) { throw new Exception($"Duplicate contract names: '{cur.ContractName}' in {cur.SolFile} and '{other.ContractName}' in {other.SolFile}"); } } } var contractPathsHash = KeccakHashString(string.Join("\n", contractInfos.SelectMany(c => new[] { c.SolFile, c.ContractName }))); var codeBaseHash = XorAllHashes(contractInfos.Select(c => c.Hash).Concat(new[] { contractPathsHash }).ToArray()); Console.WriteLine($"Generated sol source file hashes in {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); sw.Stop(); #endregion #region AST output generation sw.Restart(); GenerateSolcOutputDataFiles(solcOutput, soliditySourceContent, codeBaseHash); sw.Stop(); Console.WriteLine($"Resx file for solc output generation took: {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); #endregion #region sw.Restart(); var generatedEvents = new List <GeneratedEventMetadata>(); GeneratedContractSourceFiles(contractInfos, generatedEvents); GenerateEventHelper(generatedEvents); sw.Stop(); Console.WriteLine($"Contract and event source code generation took: {Math.Round(sw.Elapsed.TotalSeconds, 2)} seconds"); #endregion }