public static async Task <LocalTestNet> Setup() { var localTestNet = new LocalTestNet(); try { // Bootstrap local testnode // TODO: check cmd args for account options localTestNet.TestNodeServer = new TestNodeServer(); localTestNet.TestNodeServer.RpcServer.Start(); // Setup rpcclient // TODO: check cmd args for gas options localTestNet.RpcClient = JsonRpcClient.Create( localTestNet.TestNodeServer.RpcServer.ServerAddress, ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); // Enable Meadow debug RPC features. await localTestNet.RpcClient.SetTracingEnabled(true); // Configure Meadow rpc error formatter. localTestNet.RpcClient.ErrorFormatter = GetExecutionTraceException; // Get accounts. localTestNet.Accounts = await localTestNet.RpcClient.Accounts(); } catch { localTestNet.Dispose(); throw; } return(localTestNet); }
public RpcServerProxy(Uri targetHost, int?proxyServerPort = null, IPAddress address = null) { _proxyClient = JsonRpcClient.Create(targetHost, ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); _httpServer = new JsonRpcHttpServer(_proxyClient, ConfigureWebHost, proxyServerPort, address); //var undefinedRpcMethods = this.GetUndefinedRpcMethods(); //Console.WriteLine("Warning: following RPC methods are not defined: \n" + string.Join(", ", undefinedRpcMethods.Select(r => r.Value()))); }
public RpcApp() { Server = new MockServerApp(); Server.RpcServer.WebHost.Start(); var port = Server.RpcServer.ServerPort; HttpClient = JsonRpcClient.Create(new Uri($"http://{IPAddress.Loopback}:{port}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); WebSocketClient = JsonRpcClient.Create(new Uri($"ws://{IPAddress.Loopback}:{port}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); }
/// <summary> /// The default constructor, creates a test chain for tests to share. /// </summary> public TestChainFixture() { // Create a test node on this port. Server = new Meadow.TestNode.TestNodeServer(); Server.RpcServer.Start(); int port = Server.RpcServer.ServerPort; // Create our client and grab our account list. Client = JsonRpcClient.Create(new Uri($"http://{IPAddress.Loopback}:{port}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); }
static async Task CreateRunIteration() { using (var server = new TestNodeServer()) { await server.RpcServer.StartAsync(); int port = server.RpcServer.ServerPort; var client = JsonRpcClient.Create(new Uri($"http://{IPAddress.Loopback}:{port}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); await client.SetCoverageEnabled(true); var accounts = await client.Accounts(); var contract = await BasicContract.New($"TestName", true, 34, client, new TransactionParams { From = accounts[0], Gas = 4712388 }, accounts[0]); var snapshotID = await client.Snapshot(); var initialValCounter = await contract.getValCounter().Call(); await contract.incrementValCounter(); var valCounter2 = await contract.getValCounter().Call(); await client.Revert(snapshotID); var finalValCounter = await contract.getValCounter().Call(); Assert.Equal(0, initialValCounter); Assert.Equal(2, valCounter2); Assert.Equal(0, finalValCounter); var snapshotID2 = await client.Snapshot(); var contract2 = await BasicContract.New($"TestName", true, 34, client, new TransactionParams { From = accounts[0], Gas = 4712388 }, accounts[0]); await contract2.incrementValCounter(); await client.Revert(snapshotID2); var coverage = await client.GetCoverageMap(contract.ContractAddress); } }
public async Task ProxyIntegrationTest(string protocol) { // create test node server using (var server = new TestNodeServer()) { await server.RpcServer.StartAsync(); // create proxy server pointed to test node server var httpServerEndPoint = new Uri($"{protocol}://{IPAddress.Loopback}:{server.RpcServer.ServerPort}"); using (var proxyServer = new RpcServerProxy(httpServerEndPoint)) { await proxyServer.StartServerAsync(); // create rpc client pointed to proxy server var proxyServerUri = new Uri($"{protocol}://{IPAddress.Loopback}:{proxyServer.ProxyServerPort}"); using (var client = JsonRpcClient.Create(proxyServerUri, 100, 100)) { var version = await client.Version(); } } } }
public void FullEndToEnd() { // Find the solution directory (start at this assembly directory and move up). string solutionDir = Util.FindSolutionDirectory(); string testAppDir = Path.Combine(solutionDir, "Meadow.SolCodeGen.TestApp"); string testProjPath = Path.Combine(testAppDir, "Meadow.SolCodeGen.TestApp.csproj"); string solCodeGenDir = Path.Combine(solutionDir, "Meadow.SolCodeGen"); string outputDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()) + Path.DirectorySeparatorChar; // Build the Meadow.SolCodeGen project get its generated nupkg file for install. string packageDir; string packageVer = DateTime.UtcNow.ToString("yyMM.ddHH.mmss", CultureInfo.InvariantCulture); void BuildPackage() { var output = RunDotnet("build", solCodeGenDir, "-c", "Release", "--no-incremental", "/p:PackageVersion=" + packageVer, "-o", outputDir); // Successfully created package 'C:\Users\matt\Projects\Meadow.Core\Meadow.SolCodeGen\bin\Debug\Meadow.SolCodeGen.0.2.1.nupkg'. var pubLine = output.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).Last(line => line.Contains(".nupkg", StringComparison.OrdinalIgnoreCase) && line.Contains("Meadow.SolCodeGen", StringComparison.OrdinalIgnoreCase) && line.Contains("created package", StringComparison.OrdinalIgnoreCase)); packageDir = pubLine.Split("created package '")[1].Split("Meadow.SolCodeGen.")[0]; } BuildPackage(); // Delete any existing generated contracts. string generatedContractsDir = Path.Combine(testAppDir, "GeneratedContracts"); if (Directory.Exists(generatedContractsDir)) { Directory.Delete(generatedContractsDir, recursive: true); } // Install the Meadow.SolCodeGen nupkg into the test project. void InstallPackage() { RunDotnet("add", testProjPath, "package", "-s", outputDir, /*packageDir,*/ "-v", packageVer, "Meadow.SolCodeGen"); } InstallPackage(); // Build the test project (which triggers code generation). string compiledAssemblyPath; void CompileGeneratedCode() { // First build command trigger the code generation, but the generated source files do not // get added the assembly. var output = RunDotnet("build", testProjPath, "-c", "Release", "--no-incremental"); var lines = output.Split(new char[] { '\n', '\r' }); var assemblyLine = lines.Last(p => p.Contains("Meadow.SolCodeGen.TestApp -> ", StringComparison.OrdinalIgnoreCase)); compiledAssemblyPath = assemblyLine.Split("Meadow.SolCodeGen.TestApp -> ")[1]; } CompileGeneratedCode(); // Load the compiled assembly at runtime and use reflection to test the generated types. void LoadCompiledAssembly() { var compiledAsm = Assembly.LoadFrom(compiledAssemblyPath); var solcData = GeneratedSolcData.Create(compiledAsm).GetSolcData(); Assert.True(solcData.SolcBytecodeInfo.Length > 0); Assert.True(solcData.SolcSourceInfo.Length > 0); // var compiledAsm = AssemblyLoadContext.Default.LoadFromAssemblyPath(compiledAssemblyPath); var exampleContractType = compiledAsm.GetType("Meadow.SolCodeGen.TestApp.ExampleContract", throwOnError: true); Type addressType = GetTypeByName("Meadow.Core", "Meadow.Core.EthTypes.Address"); Type jsonRpcClientType = GetTypeByName("Meadow.JsonRpc.Client", "Meadow.JsonRpc.Client.JsonRpcClient"); Type baseContractType = GetTypeByName("Meadow.Contract", "Meadow.Contract.BaseContract"); object contractAddr = Activator.CreateInstance(addressType, "0x0"); object fromAccount = Activator.CreateInstance(addressType, "0x0"); var rpcClient = JsonRpcClient.Create(new Uri("http://localhost"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); var atMethod = exampleContractType.GetMethod("At", BindingFlags.Static | BindingFlags.Public); dynamic contractAtTask = atMethod.Invoke(null, new object[] { rpcClient, contractAddr, fromAccount }); object instance = contractAtTask.Result; Assert.True(baseContractType.IsAssignableFrom(instance.GetType())); } LoadCompiledAssembly(); // Cleanup - remove nuget package void UninstallNugetPackage() { RunDotnet("remove", testProjPath, "package", "Meadow.SolCodeGen"); } UninstallNugetPackage(); // Cleanup - delete generated contact source files if (Directory.Exists(generatedContractsDir)) { Directory.Delete(generatedContractsDir, recursive: true); } }
public async Task DirectImplementionMethod() { IRpcControllerMinimal client = JsonRpcClient.Create(new Uri($"http://{IPAddress.Loopback}:{44999}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); await Assert.ThrowsAsync <HttpRequestException>(async() => await client.GetTransactionReceipt(Hash.Zero)); }
public async Task DynamicMethodLookup() { var client = JsonRpcClient.Create(new Uri($"http://{IPAddress.Loopback}:{44999}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); await Assert.ThrowsAsync <HttpRequestException>(async() => await client.Accounts()); }
public void InitializeClient() { var client = JsonRpcClient.Create(new Uri($"http://{IPAddress.Loopback}:{9999}"), ArbitraryDefaults.DEFAULT_GAS_LIMIT, ArbitraryDefaults.DEFAULT_GAS_PRICE); }
static async Task Main(string[] args) { Console.WriteLine("Starting..."); int port; bool meadow = true; if (!meadow) { port = 7545; } else { // Bootstrap our meadow test node server. var testNode = new Meadow.TestNode.TestNodeServer(); // Print our undefined rpc methods. var undefinedRpcMethods = testNode.GetUndefinedRpcMethods(); Console.WriteLine("Warning: following RPC methods are not defined: \n" + string.Join(", ", undefinedRpcMethods.Select(r => r.Value()))); // Start up the server and obtain the port. await testNode.RpcServer.StartAsync(); port = testNode.RpcServer.ServerPort; } async Task <Exception> GetExecutionTraceException(IJsonRpcClient rpcClient, JsonRpcError error) { if (meadow) { var executionTrace = await rpcClient.GetExecutionTrace(); var traceAnalysis = new ExecutionTraceAnalysis(executionTrace); // Build our aggregate exception var aggregateException = traceAnalysis.GetAggregateException(error.ToException()); return(aggregateException); } else { if (error != null) { throw error.ToException(); } else { throw new Exception("Execution exception"); } } } // Connect our client to the server. var client = JsonRpcClient.Create( new Uri($"http://{IPAddress.Loopback}:{port}"), defaultGasLimit: 6_000_000, defaultGasPrice: 0); client.ErrorFormatter = GetExecutionTraceException; // If we're testing meadow, we enable special coverage/tracing options. if (meadow) { await client.SetCoverageEnabled(true); await client.SetTracingEnabled(true); } //var missingConstructorContract = await MissingConstructorChild.New(client); //var someNum = await missingConstructorContract.someNum().Call(); #region ErrorContract // Try deploying the error generating contract and test some calls. var errorContract = await ErrorContract.New(client, new TransactionParams { Gas = 4712388 }); //await errorContract.doRevert().ExpectRevertTransaction(); //await errorContract.doAssert().ExpectRevertTransaction(); //await errorContract.doThrow().ExpectRevertCall(); #endregion #region Inheritance Tests // Test inheritance with an inherited contract. var inheritedContract = await InheritedContract.New(client, new TransactionParams { Gas = 4712388 }); await inheritedContract.testFunction(); await inheritedContract.testFunctionWithInheritedModifier(); // Test inheritance with a seperate file which we inherited from. var multiInheritedContract = await MultifileInheritedContract.New(client, new TransactionParams { Gas = 4712388 }); await multiInheritedContract.testFunction(); await multiInheritedContract.testFunctionWithInheritedModifier(); #endregion try { await FailDeploymentContract.New(client); } catch { } #region Callstack Tests // Try throwing asserts in further call depth and spanning more than one file. await multiInheritedContract.testInheritedAssertThrow().ExpectRevertTransaction(); if (meadow) { // Test parsing an execution trace of the last call/transaction. var executionTrace = await client.GetExecutionTrace(); ExecutionTraceAnalysis traceAnalysis = new ExecutionTraceAnalysis(executionTrace); // Testing: Build our aggregate exception var aggregateException = traceAnalysis.GetAggregateException(); try { throw aggregateException; } catch { } } #endregion #region ExampleContract Tests // Deploy our main example contract var exContract = await ExampleContract.New($"TestName", true, 34, client, new TransactionParams { Gas = 4712388 }); await exContract.testRevert().ExpectRevertTransaction(); await exContract.testBranchCoverage().ExpectRevertTransaction(); if (meadow) { // Test parsing an execution trace of the last call/transaction. var executionTrace = await client.GetExecutionTrace(); ExecutionTraceAnalysis traceAnalysis = new ExecutionTraceAnalysis(executionTrace); // Testing: Build our aggregate exception var aggregateException = traceAnalysis.GetAggregateException(); try { throw aggregateException; } catch { } } // Test the modexp precompile. var modExpTestBytes = await exContract.testModExp( BigIntegerConverter.GetBytes(BigInteger.Parse("1212121323543453245345678346345737475734753745737774573475377734577", CultureInfo.InvariantCulture)), BigIntegerConverter.GetBytes(BigInteger.Parse("3", CultureInfo.InvariantCulture)), BigIntegerConverter.GetBytes(BigInteger.Parse("4345328123928357434573234217343477", CultureInfo.InvariantCulture))) .Call(); var modExpTest = BigIntegerConverter.GetBigInteger(modExpTestBytes, false, modExpTestBytes.Length); // should be 856753145937825219130387866259147 // Test events var eventTest = await exContract.emitDataEvent(1, 2, 3).TransactionReceipt(); var eventLogFirst = eventTest.FirstEventLog <ExampleContract.DataEvent>(); var eventLogLast = eventTest.LastEventLog <ExampleContract.DataEvent>(); var eventLogAll = eventTest.EventLogs <ExampleContract.DataEvent>(); var eventLogsBase = eventTest.EventLogs(); // Test for chris var result = await exContract.getFirstByteFromByte32(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }).Call(); // Try testing branch coverage (which ends in an assert being thrown) await exContract.testBranchCoverage().ExpectRevertTransaction(); //await exContract.noopFunc(); var echoGasEst = await exContract.echoInt24(34).EstimateGas(); await exContract.testInstructions1().TransactionReceipt(); var transactionReceipt = await exContract.echoInt24(22).TransactionReceipt(); #endregion #region Performance Tests // Define start time for an execution loop to test performance of a few basic calls. DateTime start = DateTime.Now; DateTime iteration = start; // Note: Change the loop condition here as needed. for (int i = 0; i < 1; i++) { var addr = await exContract.echoAddress(new Address(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 })); var int24Test = await exContract.echoInt24(7777); var stringTest = await exContract.echoString("This is a string."); var enabledThingTest = await exContract.enabledThing(); var isNineTest = await exContract.myFunc(9); var givenName = await exContract.givenName(); // Precompile hash tests var sha256HashTest = await exContract.sha256str("hello world"); // should be 0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 var ripemd160HashTest = await exContract.ripemd160str("hello world"); // should be 0x98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f // This ECRecover test should yield 0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd. This test data is taken from SigningTests.cs var ecRecoverTest = await exContract.testECRecover( new byte[] { 0xc9, 0xf1, 0xc7, 0x66, 0x85, 0x84, 0x5e, 0xa8, 0x1c, 0xac, 0x99, 0x25, 0xa7, 0x56, 0x58, 0x87, 0xb7, 0x77, 0x1b, 0x34, 0xb3, 0x5e, 0x64, 0x1c, 0xca, 0x85, 0xdb, 0x9f, 0xef, 0xd0, 0xe7, 0x1f }, 0x1c, BigIntegerConverter.GetBytes(BigInteger.Parse("68932463183462156574914988273446447389145511361487771160486080715355143414637", CultureInfo.InvariantCulture)), BigIntegerConverter.GetBytes(BigInteger.Parse("47416572686988136438359045243120473513988610648720291068939984598262749281683", CultureInfo.InvariantCulture))); Console.WriteLine($"#{i}: {DateTime.Now - iteration}"); iteration = DateTime.Now; } DateTime end = DateTime.Now; #endregion // If this is meadow, we do special post-execution tasks. if (meadow) { // Test obtaining coverage maps, disabling them, clearing them. var coverageMaps = await client.GetAllCoverageMaps(); await client.SetCoverageEnabled(false); await client.ClearCoverage(); // Obtain our generated solc data, create a report, and open it. var solcData = GeneratedSolcData.Default.GetSolcData(); // Match coverage contract addresses with deployed contracts that the client keeps track of. var contractInstances = GeneratedSolcData.Default.MatchCoverageData(coverageMaps); var reportPath = Path.GetFullPath("Report"); MiscUtil.ResetDirectory(reportPath); ReportGenerator.CreateReport(GeneratedSolcData.Default.SolidityCompilerVersion, contractInstances, solcData.SolcSourceInfo, solcData.SolcBytecodeInfo, null, null, reportPath); MiscUtil.OpenBrowser(Path.Join(reportPath, ReportGenerator.REPORT_INDEX_FILE)); } // Output our execution loop time. Console.WriteLine($"Total Time: {end - start}"); Console.ReadLine(); }
protected override void EndProcessing() { // Configure Out-Default to automatically place set last command output into variable "$__" // See: https://tommymaynard.com/three-ways-to-set-psdefaultparametervalues-2017/ var psDefaultParameterValues = SessionState.PSVariable.Get("PSDefaultParameterValues"); var paramDict = (DefaultParameterDictionary)psDefaultParameterValues.Value; paramDict["Out-Default:OutVariable"] = "__"; if (Setup.Equals(WORKSPACE_MANUAL, StringComparison.OrdinalIgnoreCase)) { if (!CheckManualSetup()) { return; } } if (!Config.CheckFileExists(SessionState.Path.CurrentLocation.Path)) { var configResult = this.Execute <ConfigCommand>((nameof(ConfigCommand.Workspace), Setup)); } var config = this.ReadConfig(); string rpcServerUri; if (Setup.Equals(WORKSPACE_DEVELOPMENT, StringComparison.OrdinalIgnoreCase)) { var startTestServerResult = this.Execute <StartTestServerCommand>(); rpcServerUri = GlobalVariables.TestNodeServer.RpcServer.ServerAddresses[0]; } else { var networkHost = config.NetworkHost; if (!networkHost.StartsWith("http:", StringComparison.OrdinalIgnoreCase) && !networkHost.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) { networkHost = "http://" + networkHost; } if (!Uri.TryCreate(networkHost, UriKind.Absolute, out var hostUri)) { Host.UI.WriteErrorLine($"Invalid network host / URI specified: '{networkHost}'"); return; } var uriBuilder = new UriBuilder(hostUri); bool portSpecifiedInHost = config.NetworkHost.Contains(":" + uriBuilder.Port, StringComparison.Ordinal); if (config.NetworkPort == 0 && !portSpecifiedInHost) { Host.UI.WriteWarningLine($"The RPC server port is not specified in '{nameof(Config.NetworkHost)}' or '{nameof(Config.NetworkPort)}' config. The default port {uriBuilder.Uri.Port} for {uriBuilder.Scheme} will be used."); } if (config.NetworkPort != 0) { if (portSpecifiedInHost) { Host.UI.WriteWarningLine($"A network port is specified in both config options {nameof(Config.NetworkHost)}={uriBuilder.Port} and {nameof(Config.NetworkPort)}={config.NetworkPort}. Only {uriBuilder.Port} will be used."); } else { uriBuilder.Port = (int)config.NetworkPort; } } rpcServerUri = $"{uriBuilder.Scheme}://{uriBuilder.Host}:{uriBuilder.Port}"; } var jsonRpcClient = JsonRpcClient.Create( new Uri(rpcServerUri), defaultGasLimit: config.DefaultGasLimit, defaultGasPrice: config.DefaultGasPrice); // Perform a json rpc version check to ensure rpc server is reachable try { var networkVersion = jsonRpcClient.Version().GetResultSafe(); Host.UI.WriteLine($"RPC client connected to server {rpcServerUri}. Network version: {networkVersion}"); } catch (Exception ex) { Host.UI.WriteErrorLine(ex.ToString()); Host.UI.WriteErrorLine($"RPC client could not connect to RPC server at {rpcServerUri}. Check your network configuration with '{CmdLetExtensions.GetCmdletName<ConfigCommand>()}'."); if (Setup.Equals(WORKSPACE_MANUAL, StringComparison.OrdinalIgnoreCase)) { if (GlobalVariables.TestNodeServer != null) { Host.UI.WriteErrorLine($"A test RPC server is running at {GlobalVariables.TestNodeServer.RpcServer.ServerAddresses.First()}."); } else { Host.UI.WriteErrorLine($"To start an test RPC server run '{CmdLetExtensions.GetCmdletName<StartTestServerCommand>()}'."); } } return; } SessionState.SetRpcClient(jsonRpcClient); Address[] accounts; if (config.UseLocalAccounts) { uint chainID; if (config.ChainID != 0) { chainID = config.ChainID; } else { try { var verString = jsonRpcClient.Version().GetResultSafe(); chainID = uint.Parse(verString, CultureInfo.InvariantCulture); } catch (Exception ex) { Host.UI.WriteErrorLine(ex.ToString()); Host.UI.WriteErrorLine($"Could not detect chainID from server. Set '{nameof(Config.ChainID)}' using with '{CmdLetExtensions.GetCmdletName<ConfigCommand>()}'."); Host.UI.WriteLine($"Use {nameof(Config.ChainID)} of 1 for mainnet. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids for more information."); return; } } if ((GlobalVariables.AccountKeys?.Length).GetValueOrDefault() == 0) { var localAcountsFile = LocalAccountsUtil.GetDefaultFilePath(SessionState.Path.CurrentLocation.Path); if (File.Exists(localAcountsFile)) { if (LocalAccountsUtil.IsEncrypted(localAcountsFile)) { WriteWarning($"Local account files exists but is encrypted. The session must be started manually to load encryped accounts. New accounts will be generated in memory instead."); var newAccountsResult = this.Execute <NewAccountsCommand>(); } else { var loadAccountsResult = this.Execute <LoadAccountsCommand>(); } } else { var newAccountsResult = this.Execute <NewAccountsCommand>(); } } accounts = GlobalVariables.AccountKeys.Select(a => a.Address).ToArray(); GlobalVariables.ChainID = chainID; jsonRpcClient.RawTransactionSigner = CreateRawTransactionSigner(); jsonRpcClient.TransactionReceiptPollInterval = TimeSpan.FromMilliseconds(500); } else { accounts = jsonRpcClient.Accounts().GetResultSafe(); } SessionState.SetAccounts(accounts); string solSourceDir = Util.GetSolSourcePath(config, SessionState); if (!Directory.Exists(solSourceDir)) { Directory.CreateDirectory(solSourceDir); } if (Directory.EnumerateFiles(solSourceDir, "*.sol", SearchOption.AllDirectories).Any()) { var compileSolResult = this.Execute <CompileSolidityCommand>(); } var watchSolResult = this.Execute <WatchSolidityCommand>(); bool failed = false; if (failed) { Environment.Exit(-1); } }