From 3d4370b154eae24b1a586bbcab0a356e6a5c98b1 Mon Sep 17 00:00:00 2001 From: ThatBen Date: Fri, 15 Sep 2023 16:27:08 +0200 Subject: [PATCH] deploys codex contract --- .../CodexContractsContainerConfig.cs | 15 ++ .../CodexContractsContainerRecipe.cs | 25 +++ CodexContractsPlugin/CodexContractsPlugin.cs | 51 ++++++ .../CodexContractsPlugin.csproj | 14 ++ CodexContractsPlugin/CodexContractsStarter.cs | 99 ++++++++++++ .../ContractsContainerInfoExtractor.cs | 66 ++++++++ .../CoreInterfaceExtensions.cs | 18 +++ .../MarketplaceAccess.cs | 0 .../MarketplaceAccessFactory.cs | 0 CodexContractsPlugin/MarketplaceInfo.cs | 20 +++ .../MarketplaceInitialConfig.cs | 0 .../MarketplaceNetwork.cs | 0 .../CodexContractsContainerConfig.cs | 16 -- .../CodexContractsContainerRecipe.cs | 25 --- .../Marketplace/CodexContractsStarter.cs | 103 ------------ .../Marketplace/ContainerInfoExtractor.cs | 149 ------------------ ...actor.cs => GethContainerInfoExtractor.cs} | 6 +- GethPlugin/GethContainerRecipe.cs | 8 +- GethPlugin/GethNodeInfo.cs | 28 +++- GethPlugin/GethStarter.cs | 17 +- Nethereum/NethereumInteraction.cs | 4 +- Nethereum/NethereumInteractionCreator.cs | 4 +- Tests/BasicTests/ExampleTests.cs | 5 +- Tests/Tests.csproj | 1 + cs-codex-dist-testing.sln | 6 + 25 files changed, 359 insertions(+), 321 deletions(-) create mode 100644 CodexContractsPlugin/CodexContractsContainerConfig.cs create mode 100644 CodexContractsPlugin/CodexContractsContainerRecipe.cs create mode 100644 CodexContractsPlugin/CodexContractsPlugin.cs create mode 100644 CodexContractsPlugin/CodexContractsPlugin.csproj create mode 100644 CodexContractsPlugin/CodexContractsStarter.cs create mode 100644 CodexContractsPlugin/ContractsContainerInfoExtractor.cs create mode 100644 CodexContractsPlugin/CoreInterfaceExtensions.cs rename {CodexPlugin/Marketplace => CodexContractsPlugin}/MarketplaceAccess.cs (100%) rename {CodexPlugin/Marketplace => CodexContractsPlugin}/MarketplaceAccessFactory.cs (100%) create mode 100644 CodexContractsPlugin/MarketplaceInfo.cs rename {CodexPlugin/Marketplace => CodexContractsPlugin}/MarketplaceInitialConfig.cs (100%) rename {CodexPlugin/Marketplace => CodexContractsPlugin}/MarketplaceNetwork.cs (100%) delete mode 100644 CodexPlugin/Marketplace/CodexContractsContainerConfig.cs delete mode 100644 CodexPlugin/Marketplace/CodexContractsContainerRecipe.cs delete mode 100644 CodexPlugin/Marketplace/CodexContractsStarter.cs delete mode 100644 CodexPlugin/Marketplace/ContainerInfoExtractor.cs rename GethPlugin/{ContainerInfoExtractor.cs => GethContainerInfoExtractor.cs} (95%) diff --git a/CodexContractsPlugin/CodexContractsContainerConfig.cs b/CodexContractsPlugin/CodexContractsContainerConfig.cs new file mode 100644 index 0000000..ee710d1 --- /dev/null +++ b/CodexContractsPlugin/CodexContractsContainerConfig.cs @@ -0,0 +1,15 @@ +using GethPlugin; +using KubernetesWorkflow; + +namespace CodexContractsPlugin +{ + public class CodexContractsContainerConfig + { + public CodexContractsContainerConfig(IGethNodeInfo gethNode) + { + GethNode = gethNode; + } + + public IGethNodeInfo GethNode { get; } + } +} diff --git a/CodexContractsPlugin/CodexContractsContainerRecipe.cs b/CodexContractsPlugin/CodexContractsContainerRecipe.cs new file mode 100644 index 0000000..341502f --- /dev/null +++ b/CodexContractsPlugin/CodexContractsContainerRecipe.cs @@ -0,0 +1,25 @@ +using KubernetesWorkflow; + +namespace CodexContractsPlugin +{ + public class CodexContractsContainerRecipe : ContainerRecipeFactory + { + public const string MarketplaceAddressFilename = "/hardhat/deployments/codexdisttestnetwork/Marketplace.json"; + public const string MarketplaceArtifactFilename = "/hardhat/artifacts/contracts/Marketplace.sol/Marketplace.json"; + + public override string AppName => "codex-contracts"; + public override string Image => "codexstorage/codex-contracts-eth:latest-dist-tests"; + + protected override void Initialize(StartupConfig startupConfig) + { + var config = startupConfig.Get(); + + var ip = config.GethNode.RunningContainer.Pod.PodInfo.Ip; + var port = config.GethNode.HttpPort.Number; + + AddEnvVar("DISTTEST_NETWORK_URL", $"http://{ip}:{port}"); + AddEnvVar("HARDHAT_NETWORK", "codexdisttestnetwork"); + AddEnvVar("KEEP_ALIVE", "1"); + } + } +} diff --git a/CodexContractsPlugin/CodexContractsPlugin.cs b/CodexContractsPlugin/CodexContractsPlugin.cs new file mode 100644 index 0000000..312b6d1 --- /dev/null +++ b/CodexContractsPlugin/CodexContractsPlugin.cs @@ -0,0 +1,51 @@ +using Core; +using GethPlugin; + +namespace CodexContractsPlugin +{ + public class CodexContractsPlugin : IProjectPlugin, IHasLogPrefix, IHasMetadata + { + private readonly IPluginTools tools; + private readonly CodexContractsStarter starter; + + public CodexContractsPlugin(IPluginTools tools) + { + this.tools = tools; + starter = new CodexContractsStarter(tools); + } + + public string LogPrefix => "(CodexContracts) "; + + public void Announce() + { + //tools.GetLog().Log($"Loaded with Codex ID: '{codexStarter.GetCodexId()}'"); + } + + public void AddMetadata(IAddMetadata metadata) + { + //metadata.Add("codexid", codexStarter.GetCodexId()); + } + + public void Decommission() + { + } + + public IMarketplaceInfo DeployContracts(IGethNodeInfo gethNode) + { + return starter.Start(gethNode); + } + + //public RunningContainers[] StartCodexNodes(int numberOfNodes, Action setup) + //{ + // var codexSetup = new CodexSetup(numberOfNodes); + // codexSetup.LogLevel = defaultLogLevel; + // setup(codexSetup); + // return codexStarter.BringOnline(codexSetup); + //} + + //public ICodexNodeGroup WrapCodexContainers(RunningContainers[] containers) + //{ + // return codexStarter.WrapCodexContainers(containers); + //} + } +} diff --git a/CodexContractsPlugin/CodexContractsPlugin.csproj b/CodexContractsPlugin/CodexContractsPlugin.csproj new file mode 100644 index 0000000..f7a4e57 --- /dev/null +++ b/CodexContractsPlugin/CodexContractsPlugin.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/CodexContractsPlugin/CodexContractsStarter.cs b/CodexContractsPlugin/CodexContractsStarter.cs new file mode 100644 index 0000000..8f9600c --- /dev/null +++ b/CodexContractsPlugin/CodexContractsStarter.cs @@ -0,0 +1,99 @@ +using Core; +using GethPlugin; +using KubernetesWorkflow; +using Logging; +using Utils; + +namespace CodexContractsPlugin +{ + public class CodexContractsStarter + { + private readonly IPluginTools tools; + + public CodexContractsStarter(IPluginTools tools) + { + this.tools = tools; + } + + public IMarketplaceInfo Start(IGethNodeInfo gethNode) + { + Log("Deploying Codex Marketplace..."); + + var workflow = tools.CreateWorkflow(); + var startupConfig = CreateStartupConfig(gethNode); + + var containers = workflow.Start(1, Location.Unspecified, new CodexContractsContainerRecipe(), startupConfig); + if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Codex contracts container to be created. Test infra failure."); + var container = containers.Containers[0]; + + WaitUntil(() => + { + var logHandler = new ContractsReadyLogHandler(tools.GetLog()); + workflow.DownloadContainerLog(container, logHandler, null); + return logHandler.Found; + }); + Log("Contracts deployed. Extracting addresses..."); + + var extractor = new ContractsContainerInfoExtractor(tools.GetLog(), workflow, container); + var marketplaceAddress = extractor.ExtractMarketplaceAddress(); + var abi = extractor.ExtractMarketplaceAbi(); + + var interaction = gethNode.StartInteraction(tools.GetLog()); + var tokenAddress = interaction.GetTokenAddress(marketplaceAddress); + + Log("Extract completed. Marketplace deployed."); + + return new MarketplaceInfo(marketplaceAddress, abi, tokenAddress); + } + + private void Log(string msg) + { + tools.GetLog().Log(msg); + } + + private void WaitUntil(Func predicate) + { + Time.WaitUntil(predicate, TimeSpan.FromMinutes(3), TimeSpan.FromSeconds(2)); + } + + private StartupConfig CreateStartupConfig(IGethNodeInfo gethNode) + { + var startupConfig = new StartupConfig(); + var contractsConfig = new CodexContractsContainerConfig(gethNode); + startupConfig.Add(contractsConfig); + return startupConfig; + } + } + + public class ContractsReadyLogHandler : LogHandler + { + // Log should contain 'Compiled 15 Solidity files successfully' at some point. + private const string RequiredCompiledString = "Solidity files successfully"; + // When script is done, it prints the ready-string. + private const string ReadyString = "Done! Sleeping indefinitely..."; + private readonly ILog log; + + public ContractsReadyLogHandler(ILog log) + { + this.log = log; + + log.Debug($"Looking for '{RequiredCompiledString}' and '{ReadyString}' in container logs..."); + } + + public bool SeenCompileString { get; private set; } + public bool Found { get; private set; } + + protected override void ProcessLine(string line) + { + log.Debug(line); + if (line.Contains(RequiredCompiledString)) SeenCompileString = true; + if (line.Contains(ReadyString)) + { + if (!SeenCompileString) throw new Exception("CodexContracts deployment failed. " + + "Solidity files not compiled before process exited."); + + Found = true; + } + } + } +} diff --git a/CodexContractsPlugin/ContractsContainerInfoExtractor.cs b/CodexContractsPlugin/ContractsContainerInfoExtractor.cs new file mode 100644 index 0000000..78b3896 --- /dev/null +++ b/CodexContractsPlugin/ContractsContainerInfoExtractor.cs @@ -0,0 +1,66 @@ +using KubernetesWorkflow; +using Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Utils; + +namespace CodexContractsPlugin +{ + public class ContractsContainerInfoExtractor + { + private readonly ILog log; + private readonly IStartupWorkflow workflow; + private readonly RunningContainer container; + + public ContractsContainerInfoExtractor(ILog log, IStartupWorkflow workflow, RunningContainer container) + { + this.log = log; + this.workflow = workflow; + this.container = container; + } + + public string ExtractMarketplaceAddress() + { + log.Debug(); + var marketplaceAddress = Retry(FetchMarketplaceAddress); + if (string.IsNullOrEmpty(marketplaceAddress)) throw new InvalidOperationException("Unable to fetch marketplace account from codex-contracts node. Test infra failure."); + + return marketplaceAddress; + } + + public string ExtractMarketplaceAbi() + { + log.Debug(); + var marketplaceAbi = Retry(FetchMarketplaceAbi); + if (string.IsNullOrEmpty(marketplaceAbi)) throw new InvalidOperationException("Unable to fetch marketplace artifacts from codex-contracts node. Test infra failure."); + + return marketplaceAbi; + } + + private string FetchMarketplaceAddress() + { + var json = workflow.ExecuteCommand(container, "cat", CodexContractsContainerRecipe.MarketplaceAddressFilename); + var marketplace = JsonConvert.DeserializeObject(json); + return marketplace!.address; + } + + private string FetchMarketplaceAbi() + { + var json = workflow.ExecuteCommand(container, "cat", CodexContractsContainerRecipe.MarketplaceArtifactFilename); + + var artifact = JObject.Parse(json); + var abi = artifact["abi"]; + return abi!.ToString(Formatting.None); + } + + private static string Retry(Func fetch) + { + return Time.Retry(fetch, nameof(ContractsContainerInfoExtractor)); + } + } + + public class MarketplaceJson + { + public string address { get; set; } = string.Empty; + } +} diff --git a/CodexContractsPlugin/CoreInterfaceExtensions.cs b/CodexContractsPlugin/CoreInterfaceExtensions.cs new file mode 100644 index 0000000..80a97aa --- /dev/null +++ b/CodexContractsPlugin/CoreInterfaceExtensions.cs @@ -0,0 +1,18 @@ +using Core; +using GethPlugin; + +namespace CodexContractsPlugin +{ + public static class CoreInterfaceExtensions + { + public static IMarketplaceInfo DeployCodexContracts(this CoreInterface ci, IGethNodeInfo gethNode) + { + return Plugin(ci).DeployContracts(gethNode); + } + + private static CodexContractsPlugin Plugin(CoreInterface ci) + { + return ci.GetPlugin(); + } + } +} diff --git a/CodexPlugin/Marketplace/MarketplaceAccess.cs b/CodexContractsPlugin/MarketplaceAccess.cs similarity index 100% rename from CodexPlugin/Marketplace/MarketplaceAccess.cs rename to CodexContractsPlugin/MarketplaceAccess.cs diff --git a/CodexPlugin/Marketplace/MarketplaceAccessFactory.cs b/CodexContractsPlugin/MarketplaceAccessFactory.cs similarity index 100% rename from CodexPlugin/Marketplace/MarketplaceAccessFactory.cs rename to CodexContractsPlugin/MarketplaceAccessFactory.cs diff --git a/CodexContractsPlugin/MarketplaceInfo.cs b/CodexContractsPlugin/MarketplaceInfo.cs new file mode 100644 index 0000000..cac1983 --- /dev/null +++ b/CodexContractsPlugin/MarketplaceInfo.cs @@ -0,0 +1,20 @@ +namespace CodexContractsPlugin +{ + public interface IMarketplaceInfo + { + } + + public class MarketplaceInfo : IMarketplaceInfo + { + public MarketplaceInfo(string address, string abi, string tokenAddress) + { + Address = address; + Abi = abi; + TokenAddress = tokenAddress; + } + + public string Address { get; } + public string Abi { get; } + public string TokenAddress { get; } + } +} diff --git a/CodexPlugin/Marketplace/MarketplaceInitialConfig.cs b/CodexContractsPlugin/MarketplaceInitialConfig.cs similarity index 100% rename from CodexPlugin/Marketplace/MarketplaceInitialConfig.cs rename to CodexContractsPlugin/MarketplaceInitialConfig.cs diff --git a/CodexPlugin/Marketplace/MarketplaceNetwork.cs b/CodexContractsPlugin/MarketplaceNetwork.cs similarity index 100% rename from CodexPlugin/Marketplace/MarketplaceNetwork.cs rename to CodexContractsPlugin/MarketplaceNetwork.cs diff --git a/CodexPlugin/Marketplace/CodexContractsContainerConfig.cs b/CodexPlugin/Marketplace/CodexContractsContainerConfig.cs deleted file mode 100644 index f6e9896..0000000 --- a/CodexPlugin/Marketplace/CodexContractsContainerConfig.cs +++ /dev/null @@ -1,16 +0,0 @@ -//using KubernetesWorkflow; - -//namespace DistTestCore.Marketplace -//{ -// public class CodexContractsContainerConfig -// { -// public CodexContractsContainerConfig(string bootstrapNodeIp, Port jsonRpcPort) -// { -// BootstrapNodeIp = bootstrapNodeIp; -// JsonRpcPort = jsonRpcPort; -// } - -// public string BootstrapNodeIp { get; } -// public Port JsonRpcPort { get; } -// } -//} diff --git a/CodexPlugin/Marketplace/CodexContractsContainerRecipe.cs b/CodexPlugin/Marketplace/CodexContractsContainerRecipe.cs deleted file mode 100644 index db8e88f..0000000 --- a/CodexPlugin/Marketplace/CodexContractsContainerRecipe.cs +++ /dev/null @@ -1,25 +0,0 @@ -//using KubernetesWorkflow; - -//namespace DistTestCore.Marketplace -//{ -// public class CodexContractsContainerRecipe : DefaultContainerRecipe -// { -// public const string MarketplaceAddressFilename = "/hardhat/deployments/codexdisttestnetwork/Marketplace.json"; -// public const string MarketplaceArtifactFilename = "/hardhat/artifacts/contracts/Marketplace.sol/Marketplace.json"; - -// public override string AppName => "codex-contracts"; -// public override string Image => "codexstorage/codex-contracts-eth:latest-dist-tests"; - -// protected override void InitializeRecipe(StartupConfig startupConfig) -// { -// var config = startupConfig.Get(); - -// var ip = config.BootstrapNodeIp; -// var port = config.JsonRpcPort.Number; - -// AddEnvVar("DISTTEST_NETWORK_URL", $"http://{ip}:{port}"); -// AddEnvVar("HARDHAT_NETWORK", "codexdisttestnetwork"); -// AddEnvVar("KEEP_ALIVE", "1"); -// } -// } -//} diff --git a/CodexPlugin/Marketplace/CodexContractsStarter.cs b/CodexPlugin/Marketplace/CodexContractsStarter.cs deleted file mode 100644 index e09b1f1..0000000 --- a/CodexPlugin/Marketplace/CodexContractsStarter.cs +++ /dev/null @@ -1,103 +0,0 @@ -//using KubernetesWorkflow; -//using Utils; - -//namespace DistTestCore.Marketplace -//{ -// public class CodexContractsStarter : BaseStarter -// { - -// public CodexContractsStarter(TestLifecycle lifecycle) -// : base(lifecycle) -// { -// } - -// public MarketplaceInfo Start(GethBootstrapNodeInfo bootstrapNode) -// { -// LogStart("Deploying Codex Marketplace..."); - -// var workflow = lifecycle.WorkflowCreator.CreateWorkflow(); -// var startupConfig = CreateStartupConfig(bootstrapNode.RunningContainers.Containers[0]); - -// var containers = workflow.Start(1, Location.Unspecified, new CodexContractsContainerRecipe(), startupConfig); -// if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Codex contracts container to be created. Test infra failure."); -// var container = containers.Containers[0]; - -// WaitUntil(() => -// { -// var logHandler = new ContractsReadyLogHandler(Debug); -// workflow.DownloadContainerLog(container, logHandler, null); -// return logHandler.Found; -// }); -// Log("Contracts deployed. Extracting addresses..."); - -// var extractor = new ContainerInfoExtractor(lifecycle.Log, workflow, container); -// var marketplaceAddress = extractor.ExtractMarketplaceAddress(); -// var abi = extractor.ExtractMarketplaceAbi(); - -// var interaction = bootstrapNode.StartInteraction(lifecycle); -// var tokenAddress = interaction.GetTokenAddress(marketplaceAddress); - -// LogEnd("Extract completed. Marketplace deployed."); - -// return new MarketplaceInfo(marketplaceAddress, abi, tokenAddress); -// } - -// private void WaitUntil(Func predicate) -// { -// Time.WaitUntil(predicate, TimeSpan.FromMinutes(3), TimeSpan.FromSeconds(2)); -// } - -// private StartupConfig CreateStartupConfig(RunningContainer bootstrapContainer) -// { -// var startupConfig = new StartupConfig(); -// var contractsConfig = new CodexContractsContainerConfig(bootstrapContainer.Pod.PodInfo.Ip, bootstrapContainer.Recipe.GetPortByTag(GethContainerRecipe.HttpPortTag)); -// startupConfig.Add(contractsConfig); -// return startupConfig; -// } -// } - -// public class MarketplaceInfo -// { -// public MarketplaceInfo(string address, string abi, string tokenAddress) -// { -// Address = address; -// Abi = abi; -// TokenAddress = tokenAddress; -// } - -// public string Address { get; } -// public string Abi { get; } -// public string TokenAddress { get; } -// } - -// public class ContractsReadyLogHandler : LogHandler -// { -// // Log should contain 'Compiled 15 Solidity files successfully' at some point. -// private const string RequiredCompiledString = "Solidity files successfully"; -// // When script is done, it prints the ready-string. -// private const string ReadyString = "Done! Sleeping indefinitely..."; -// private readonly Action debug; - -// public ContractsReadyLogHandler(Action debug) -// { -// this.debug = debug; -// debug($"Looking for '{RequiredCompiledString}' and '{ReadyString}' in container logs..."); -// } - -// public bool SeenCompileString { get; private set; } -// public bool Found { get; private set; } - -// protected override void ProcessLine(string line) -// { -// debug(line); -// if (line.Contains(RequiredCompiledString)) SeenCompileString = true; -// if (line.Contains(ReadyString)) -// { -// if (!SeenCompileString) throw new Exception("CodexContracts deployment failed. " + -// "Solidity files not compiled before process exited."); - -// Found = true; -// } -// } -// } -//} diff --git a/CodexPlugin/Marketplace/ContainerInfoExtractor.cs b/CodexPlugin/Marketplace/ContainerInfoExtractor.cs deleted file mode 100644 index ced47e1..0000000 --- a/CodexPlugin/Marketplace/ContainerInfoExtractor.cs +++ /dev/null @@ -1,149 +0,0 @@ -//using KubernetesWorkflow; -//using Logging; -//using Newtonsoft.Json; -//using Newtonsoft.Json.Linq; -//using Utils; - -//namespace DistTestCore.Marketplace -//{ -// public class ContainerInfoExtractor -// { -// private readonly BaseLog log; -// private readonly StartupWorkflow workflow; -// private readonly RunningContainer container; - -// public ContainerInfoExtractor(BaseLog log, StartupWorkflow workflow, RunningContainer container) -// { -// this.log = log; -// this.workflow = workflow; -// this.container = container; -// } - -// public AllGethAccounts ExtractAccounts() -// { -// log.Debug(); -// var accountsCsv = Retry(() => FetchAccountsCsv()); -// if (string.IsNullOrEmpty(accountsCsv)) throw new InvalidOperationException("Unable to fetch accounts.csv for geth node. Test infra failure."); - -// var lines = accountsCsv.Split('\n'); -// return new AllGethAccounts(lines.Select(ParseLineToAccount).ToArray()); -// } - -// public string ExtractPubKey() -// { -// log.Debug(); -// var pubKey = Retry(FetchPubKey); -// if (string.IsNullOrEmpty(pubKey)) throw new InvalidOperationException("Unable to fetch enode from geth node. Test infra failure."); - -// return pubKey; -// } - -// public string ExtractMarketplaceAddress() -// { -// log.Debug(); -// var marketplaceAddress = Retry(FetchMarketplaceAddress); -// if (string.IsNullOrEmpty(marketplaceAddress)) throw new InvalidOperationException("Unable to fetch marketplace account from codex-contracts node. Test infra failure."); - -// return marketplaceAddress; -// } - -// public string ExtractMarketplaceAbi() -// { -// log.Debug(); -// var marketplaceAbi = Retry(FetchMarketplaceAbi); -// if (string.IsNullOrEmpty(marketplaceAbi)) throw new InvalidOperationException("Unable to fetch marketplace artifacts from codex-contracts node. Test infra failure."); - -// return marketplaceAbi; -// } - -// private string FetchAccountsCsv() -// { -// return workflow.ExecuteCommand(container, "cat", GethContainerRecipe.AccountsFilename); -// } - -// private string FetchMarketplaceAddress() -// { -// var json = workflow.ExecuteCommand(container, "cat", CodexContractsContainerRecipe.MarketplaceAddressFilename); -// var marketplace = JsonConvert.DeserializeObject(json); -// return marketplace!.address; -// } - -// private string FetchMarketplaceAbi() -// { -// var json = workflow.ExecuteCommand(container, "cat", CodexContractsContainerRecipe.MarketplaceArtifactFilename); - -// var artifact = JObject.Parse(json); -// var abi = artifact["abi"]; -// return abi!.ToString(Formatting.None); -// } - -// private string FetchPubKey() -// { -// var enodeFinder = new PubKeyFinder(s => log.Debug(s)); -// workflow.DownloadContainerLog(container, enodeFinder, null); -// return enodeFinder.GetPubKey(); -// } - -// private GethAccount ParseLineToAccount(string l) -// { -// var tokens = l.Replace("\r", "").Split(','); -// if (tokens.Length != 2) throw new InvalidOperationException(); -// var account = tokens[0]; -// var privateKey = tokens[1]; -// return new GethAccount(account, privateKey); -// } - -// private static string Retry(Func fetch) -// { -// return Time.Retry(fetch, nameof(ContainerInfoExtractor)); -// } -// } - -// public class PubKeyFinder : LogHandler, ILogHandler -// { -// private const string openTag = "self=enode://"; -// private const string openTagQuote = "self=\"enode://"; -// private readonly Action debug; -// private string pubKey = string.Empty; - -// public PubKeyFinder(Action debug) -// { -// this.debug = debug; -// debug($"Looking for '{openTag}' in container logs..."); -// } - -// public string GetPubKey() -// { -// if (string.IsNullOrEmpty(pubKey)) throw new Exception("Not found yet exception."); -// return pubKey; -// } - -// protected override void ProcessLine(string line) -// { -// debug(line); -// if (line.Contains(openTag)) -// { -// ExtractPubKey(openTag, line); -// } -// else if (line.Contains(openTagQuote)) -// { -// ExtractPubKey(openTagQuote, line); -// } -// } - -// private void ExtractPubKey(string tag, string line) -// { -// var openIndex = line.IndexOf(tag) + tag.Length; -// var closeIndex = line.IndexOf("@"); - -// pubKey = line.Substring( -// startIndex: openIndex, -// length: closeIndex - openIndex); -// } -// } - -// public class MarketplaceJson -// { -// public string address { get; set; } = string.Empty; -// } -//} diff --git a/GethPlugin/ContainerInfoExtractor.cs b/GethPlugin/GethContainerInfoExtractor.cs similarity index 95% rename from GethPlugin/ContainerInfoExtractor.cs rename to GethPlugin/GethContainerInfoExtractor.cs index fa7dc61..649da4f 100644 --- a/GethPlugin/ContainerInfoExtractor.cs +++ b/GethPlugin/GethContainerInfoExtractor.cs @@ -4,13 +4,13 @@ using Utils; namespace GethPlugin { - public class ContainerInfoExtractor + public class GethContainerInfoExtractor { private readonly ILog log; private readonly IStartupWorkflow workflow; private readonly RunningContainer container; - public ContainerInfoExtractor(ILog log, IStartupWorkflow workflow, RunningContainer container) + public GethContainerInfoExtractor(ILog log, IStartupWorkflow workflow, RunningContainer container) { this.log = log; this.workflow = workflow; @@ -93,7 +93,7 @@ namespace GethPlugin private static string Retry(Func fetch) { - return Time.Retry(fetch, nameof(ContainerInfoExtractor)); + return Time.Retry(fetch, nameof(GethContainerInfoExtractor)); } } diff --git a/GethPlugin/GethContainerRecipe.cs b/GethPlugin/GethContainerRecipe.cs index a3ad320..44673a8 100644 --- a/GethPlugin/GethContainerRecipe.cs +++ b/GethPlugin/GethContainerRecipe.cs @@ -8,6 +8,7 @@ namespace GethPlugin public const string HttpPortTag = "http_port"; public const string DiscoveryPortTag = "disc_port"; + public const string wsPortTag = "ws_port"; public const string AccountsFilename = "accounts.csv"; public override string AppName => "geth"; @@ -28,10 +29,11 @@ namespace GethPlugin if (config.IsMiner) AddEnvVar("ENABLE_MINER", "1"); UnlockAccounts(0, 1); - var exposedPort = AddExposedPort(tag: HttpPortTag); - var args = $"--http.addr 0.0.0.0 --http.port {exposedPort.Number} --port {discovery.Number} --discovery.port {discovery.Number} {defaultArgs}"; + var httpPort = AddExposedPort(tag: HttpPortTag); + var args = $"--http.addr 0.0.0.0 --http.port {httpPort.Number} --port {discovery.Number} --discovery.port {discovery.Number} {defaultArgs}"; var authRpc = AddInternalPort(); + var wsPort = AddInternalPort(tag: wsPortTag); if (config.BootstrapNode != null) { @@ -42,7 +44,7 @@ namespace GethPlugin args += bootstrapArg; } - return args + $" --authrpc.port {authRpc.Number} --ws --ws.addr 0.0.0.0 --ws.port {exposedPort.Number}"; + return args + $" --authrpc.port {authRpc.Number} --ws --ws.addr 0.0.0.0 --ws.port {wsPort.Number}"; } private void UnlockAccounts(int startIndex, int numberOfAccounts) diff --git a/GethPlugin/GethNodeInfo.cs b/GethPlugin/GethNodeInfo.cs index c6e958d..4bd6b11 100644 --- a/GethPlugin/GethNodeInfo.cs +++ b/GethPlugin/GethNodeInfo.cs @@ -1,20 +1,30 @@ using KubernetesWorkflow; +using Logging; +using NethereumWorkflow; namespace GethPlugin { public interface IGethNodeInfo { + RunningContainer RunningContainer { get; } + Port DiscoveryPort { get; } + Port HttpPort { get; } + Port WsPort { get; } + + NethereumInteraction StartInteraction(ILog log); } public class GethNodeInfo : IGethNodeInfo { - public GethNodeInfo(RunningContainer runningContainer, AllGethAccounts allAccounts, string pubKey, Port discoveryPort) + public GethNodeInfo(RunningContainer runningContainer, AllGethAccounts allAccounts, string pubKey, Port discoveryPort, Port httpPort, Port wsPort) { RunningContainer = runningContainer; AllAccounts = allAccounts; Account = allAccounts.Accounts[0]; PubKey = pubKey; DiscoveryPort = discoveryPort; + HttpPort = httpPort; + WsPort = wsPort; } public RunningContainer RunningContainer { get; } @@ -22,14 +32,16 @@ namespace GethPlugin public GethAccount Account { get; } public string PubKey { get; } public Port DiscoveryPort { get; } + public Port HttpPort { get; } + public Port WsPort { get; } - //public NethereumInteraction StartInteraction(TestLifecycle lifecycle) - //{ - // var address = lifecycle.Configuration.GetAddress(RunningContainers.Containers[0]); - // var account = Account; + public NethereumInteraction StartInteraction(ILog log) + { + var address = RunningContainer.Address; + var account = Account; - // var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, account.PrivateKey); - // return creator.CreateWorkflow(); - //} + var creator = new NethereumInteractionCreator(log, address.Host, address.Port, account.PrivateKey); + return creator.CreateWorkflow(); + } } } diff --git a/GethPlugin/GethStarter.cs b/GethPlugin/GethStarter.cs index d883ec8..8ce2b3b 100644 --- a/GethPlugin/GethStarter.cs +++ b/GethPlugin/GethStarter.cs @@ -7,16 +7,9 @@ namespace GethPlugin { private readonly IPluginTools tools; - //private readonly MarketplaceNetworkCache marketplaceNetworkCache; - //private readonly GethCompanionNodeStarter companionNodeStarter; - public GethStarter(IPluginTools tools) { this.tools = tools; - //marketplaceNetworkCache = new MarketplaceNetworkCache( - // new GethBootstrapNodeStarter(lifecycle), - // new CodexContractsStarter(lifecycle)); - //companionNodeStarter = new GethCompanionNodeStarter(lifecycle); } public IGethNodeInfo StartGeth(GethStartupConfig gethStartupConfig) @@ -32,12 +25,18 @@ namespace GethPlugin if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Geth bootstrap node to be created. Test infra failure."); var container = containers.Containers[0]; - var extractor = new ContainerInfoExtractor(tools.GetLog(), workflow, container); + var extractor = new GethContainerInfoExtractor(tools.GetLog(), workflow, container); var accounts = extractor.ExtractAccounts(); var pubKey = extractor.ExtractPubKey(); + var discoveryPort = container.Recipe.GetPortByTag(GethContainerRecipe.DiscoveryPortTag); if (discoveryPort == null) throw new Exception("Expected discovery port to be created."); - var result = new GethNodeInfo(container, accounts, pubKey, discoveryPort); + var httpPort = container.Recipe.GetPortByTag(GethContainerRecipe.HttpPortTag); + if (httpPort == null) throw new Exception("Expected http port to be created."); + var wsPort = container.Recipe.GetPortByTag(GethContainerRecipe.wsPortTag); + if (wsPort == null) throw new Exception("Expected ws port to be created."); + + var result = new GethNodeInfo(container, accounts, pubKey, discoveryPort, httpPort, wsPort); Log($"Geth bootstrap node started with account '{result.Account.Account}'"); diff --git a/Nethereum/NethereumInteraction.cs b/Nethereum/NethereumInteraction.cs index 624f20c..dad4633 100644 --- a/Nethereum/NethereumInteraction.cs +++ b/Nethereum/NethereumInteraction.cs @@ -10,10 +10,10 @@ namespace NethereumWorkflow { public class NethereumInteraction { - private readonly BaseLog log; + private readonly ILog log; private readonly Web3 web3; - internal NethereumInteraction(BaseLog log, Web3 web3) + internal NethereumInteraction(ILog log, Web3 web3) { this.log = log; this.web3 = web3; diff --git a/Nethereum/NethereumInteractionCreator.cs b/Nethereum/NethereumInteractionCreator.cs index ab5449c..bad1194 100644 --- a/Nethereum/NethereumInteractionCreator.cs +++ b/Nethereum/NethereumInteractionCreator.cs @@ -5,12 +5,12 @@ namespace NethereumWorkflow { public class NethereumInteractionCreator { - private readonly BaseLog log; + private readonly ILog log; private readonly string ip; private readonly int port; private readonly string privateKey; - public NethereumInteractionCreator(BaseLog log, string ip, int port, string privateKey) + public NethereumInteractionCreator(ILog log, string ip, int port, string privateKey) { this.log = log; this.ip = ip; diff --git a/Tests/BasicTests/ExampleTests.cs b/Tests/BasicTests/ExampleTests.cs index 9a79e89..3a5c1fc 100644 --- a/Tests/BasicTests/ExampleTests.cs +++ b/Tests/BasicTests/ExampleTests.cs @@ -1,4 +1,5 @@ -using CodexPlugin; +using CodexContractsPlugin; +using CodexPlugin; using DistTestCore; using GethPlugin; using MetricsPlugin; @@ -49,6 +50,8 @@ namespace Tests.BasicTests { var geth = Ci.StartGethNode(s => s.IsMiner().WithName("disttest-geth")); + var contracts = Ci.DeployCodexContracts(geth); + //var sellerInitialBalance = 234.TestTokens(); //var buyerInitialBalance = 1000.TestTokens(); //var fileSize = 10.MB(); diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index a735ca9..e6faada 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/cs-codex-dist-testing.sln b/cs-codex-dist-testing.sln index d0e90d0..92e1c82 100644 --- a/cs-codex-dist-testing.sln +++ b/cs-codex-dist-testing.sln @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetricsPlugin", "MetricsPlu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GethPlugin", "GethPlugin\GethPlugin.csproj", "{5A1EF1DD-9E81-4501-B44C-493C72D2B166}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodexContractsPlugin", "CodexContractsPlugin\CodexContractsPlugin.csproj", "{F315AEB1-C254-45FD-A0D2-5CEF401E0442}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -99,6 +101,10 @@ Global {5A1EF1DD-9E81-4501-B44C-493C72D2B166}.Debug|Any CPU.Build.0 = Debug|Any CPU {5A1EF1DD-9E81-4501-B44C-493C72D2B166}.Release|Any CPU.ActiveCfg = Release|Any CPU {5A1EF1DD-9E81-4501-B44C-493C72D2B166}.Release|Any CPU.Build.0 = Release|Any CPU + {F315AEB1-C254-45FD-A0D2-5CEF401E0442}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F315AEB1-C254-45FD-A0D2-5CEF401E0442}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F315AEB1-C254-45FD-A0D2-5CEF401E0442}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F315AEB1-C254-45FD-A0D2-5CEF401E0442}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE