diff --git a/CodexPlugin/CodexContainerRecipe.cs b/CodexPlugin/CodexContainerRecipe.cs index 47680a0..15311c3 100644 --- a/CodexPlugin/CodexContainerRecipe.cs +++ b/CodexPlugin/CodexContainerRecipe.cs @@ -1,6 +1,4 @@ -//using DistTestCore.Marketplace; -using Core; -using KubernetesWorkflow; +using KubernetesWorkflow; using Utils; namespace CodexPlugin diff --git a/GethPlugin/ContainerInfoExtractor.cs b/GethPlugin/ContainerInfoExtractor.cs new file mode 100644 index 0000000..fa7dc61 --- /dev/null +++ b/GethPlugin/ContainerInfoExtractor.cs @@ -0,0 +1,147 @@ +using KubernetesWorkflow; +using Logging; +using Utils; + +namespace GethPlugin +{ + public class ContainerInfoExtractor + { + private readonly ILog log; + private readonly IStartupWorkflow workflow; + private readonly RunningContainer container; + + public ContainerInfoExtractor(ILog log, IStartupWorkflow 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/CoreInterfaceExtensions.cs b/GethPlugin/CoreInterfaceExtensions.cs index 6625d58..e5049a9 100644 --- a/GethPlugin/CoreInterfaceExtensions.cs +++ b/GethPlugin/CoreInterfaceExtensions.cs @@ -1,44 +1,17 @@ using Core; -using KubernetesWorkflow; namespace GethPlugin { public static class CoreInterfaceExtensions { - //public static RunningContainers[] StartCodexNodes(this CoreInterface ci, int number, Action setup) - //{ - // return Plugin(ci).StartCodexNodes(number, setup); - //} + public static IGethNodeInfo StartGethNode(this CoreInterface ci, Action setup) + { + return Plugin(ci).StartGeth(setup); + } - //public static ICodexNodeGroup WrapCodexContainers(this CoreInterface ci, RunningContainers[] containers) - //{ - // return Plugin(ci).WrapCodexContainers(containers); - //} - - //public static IOnlineCodexNode SetupCodexNode(this CoreInterface ci) - //{ - // return ci.SetupCodexNodes(1)[0]; - //} - - //public static IOnlineCodexNode SetupCodexNode(this CoreInterface ci, Action setup) - //{ - // return ci.SetupCodexNodes(1, setup)[0]; - //} - - //public static ICodexNodeGroup SetupCodexNodes(this CoreInterface ci, int number, Action setup) - //{ - // var rc = ci.StartCodexNodes(number, setup); - // return ci.WrapCodexContainers(rc); - //} - - //public static ICodexNodeGroup SetupCodexNodes(this CoreInterface ci, int number) - //{ - // return ci.SetupCodexNodes(number, s => { }); - //} - - //private static CodexPlugin Plugin(CoreInterface ci) - //{ - // return ci.GetPlugin(); - //} + private static GethPlugin Plugin(CoreInterface ci) + { + return ci.GetPlugin(); + } } } diff --git a/GethPlugin/GethAccount.cs b/GethPlugin/GethAccount.cs new file mode 100644 index 0000000..10974e2 --- /dev/null +++ b/GethPlugin/GethAccount.cs @@ -0,0 +1,24 @@ +namespace GethPlugin +{ + public class GethAccount + { + public GethAccount(string account, string privateKey) + { + Account = account; + PrivateKey = privateKey; + } + + public string Account { get; } + public string PrivateKey { get; } + } + + public class AllGethAccounts + { + public GethAccount[] Accounts { get; } + + public AllGethAccounts(GethAccount[] accounts) + { + Accounts = accounts; + } + } +} diff --git a/GethPlugin/GethBootstrapNodeInfo.cs b/GethPlugin/GethBootstrapNodeInfo.cs deleted file mode 100644 index 8dffbc9..0000000 --- a/GethPlugin/GethBootstrapNodeInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -using KubernetesWorkflow; -using NethereumWorkflow; - -namespace GethPlugin -{ - public class GethBootstrapNodeInfo - { - public GethBootstrapNodeInfo(RunningContainers runningContainers, AllGethAccounts allAccounts, string pubKey, Port discoveryPort) - { - RunningContainers = runningContainers; - AllAccounts = allAccounts; - Account = allAccounts.Accounts[0]; - PubKey = pubKey; - DiscoveryPort = discoveryPort; - } - - public RunningContainers RunningContainers { get; } - public AllGethAccounts AllAccounts { get; } - public GethAccount Account { get; } - public string PubKey { get; } - public Port DiscoveryPort { get; } - - public NethereumInteraction StartInteraction(TestLifecycle lifecycle) - { - var address = lifecycle.Configuration.GetAddress(RunningContainers.Containers[0]); - var account = Account; - - var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, account.PrivateKey); - return creator.CreateWorkflow(); - } - } - - public class AllGethAccounts - { - public GethAccount[] Accounts { get; } - - public AllGethAccounts(GethAccount[] accounts) - { - Accounts = accounts; - } - } -} diff --git a/GethPlugin/GethBootstrapNodeStarter.cs b/GethPlugin/GethBootstrapNodeStarter.cs deleted file mode 100644 index b18292a..0000000 --- a/GethPlugin/GethBootstrapNodeStarter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using KubernetesWorkflow; - -namespace GethPlugin -{ - public class GethBootstrapNodeStarter - { - public GethBootstrapNodeInfo StartGethBootstrapNode() - { - LogStart("Starting Geth bootstrap node..."); - var startupConfig = CreateBootstrapStartupConfig(); - - var workflow = lifecycle.WorkflowCreator.CreateWorkflow(); - var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), startupConfig); - if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Geth bootstrap node to be created. Test infra failure."); - var bootstrapContainer = containers.Containers[0]; - - var extractor = new ContainerInfoExtractor(lifecycle.Log, workflow, bootstrapContainer); - var accounts = extractor.ExtractAccounts(); - var pubKey = extractor.ExtractPubKey(); - var discoveryPort = bootstrapContainer.Recipe.GetPortByTag(GethContainerRecipe.DiscoveryPortTag); - var result = new GethBootstrapNodeInfo(containers, accounts, pubKey, discoveryPort); - - LogEnd($"Geth bootstrap node started with account '{result.Account.Account}'"); - - return result; - } - - private StartupConfig CreateBootstrapStartupConfig() - { - var config = new StartupConfig(); - config.Add(new GethStartupConfig(true, null!, 0, 0)); - return config; - } - } -} diff --git a/GethPlugin/GethCompanionNodeInfo.cs b/GethPlugin/GethCompanionNodeInfo.cs index 313271c..8c349c3 100644 --- a/GethPlugin/GethCompanionNodeInfo.cs +++ b/GethPlugin/GethCompanionNodeInfo.cs @@ -1,38 +1,26 @@ -using KubernetesWorkflow; -using NethereumWorkflow; +//using KubernetesWorkflow; +//using NethereumWorkflow; -namespace GethPlugin -{ - public class GethCompanionNodeInfo - { - public GethCompanionNodeInfo(RunningContainer runningContainer, GethAccount[] accounts) - { - RunningContainer = runningContainer; - Accounts = accounts; - } +//namespace GethPlugin +//{ +// public class GethCompanionNodeInfo +// { +// public GethCompanionNodeInfo(RunningContainer runningContainer, GethAccount[] accounts) +// { +// RunningContainer = runningContainer; +// Accounts = accounts; +// } - public RunningContainer RunningContainer { get; } - public GethAccount[] Accounts { get; } +// public RunningContainer RunningContainer { get; } +// public GethAccount[] Accounts { get; } - public NethereumInteraction StartInteraction(TestLifecycle lifecycle, GethAccount account) - { - var address = lifecycle.Configuration.GetAddress(RunningContainer); - var privateKey = account.PrivateKey; +// public NethereumInteraction StartInteraction(TestLifecycle lifecycle, GethAccount account) +// { +// var address = lifecycle.Configuration.GetAddress(RunningContainer); +// var privateKey = account.PrivateKey; - var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, privateKey); - return creator.CreateWorkflow(); - } - } - - public class GethAccount - { - public GethAccount(string account, string privateKey) - { - Account = account; - PrivateKey = privateKey; - } - - public string Account { get; } - public string PrivateKey { get; } - } -} +// var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, privateKey); +// return creator.CreateWorkflow(); +// } +// } +//} diff --git a/GethPlugin/GethCompanionNodeStarter.cs b/GethPlugin/GethCompanionNodeStarter.cs deleted file mode 100644 index 998e8f2..0000000 --- a/GethPlugin/GethCompanionNodeStarter.cs +++ /dev/null @@ -1,72 +0,0 @@ -using KubernetesWorkflow; -using Utils; - -namespace GethPlugin -{ - public class GethCompanionNodeStarter - { - private int companionAccountIndex = 0; - - public GethCompanionNodeInfo StartCompanionNodeFor(CodexSetup codexSetup, MarketplaceNetwork marketplace) - { - LogStart($"Initializing companion for {codexSetup.NumberOfNodes} Codex nodes."); - - var config = CreateCompanionNodeStartupConfig(marketplace.Bootstrap, codexSetup.NumberOfNodes); - - var workflow = lifecycle.WorkflowCreator.CreateWorkflow(); - var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), CreateStartupConfig(config)); - if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected one Geth companion node to be created. Test infra failure."); - var container = containers.Containers[0]; - - var node = CreateCompanionInfo(container, marketplace, config); - EnsureCompanionNodeIsSynced(node, marketplace); - - LogEnd($"Initialized one companion node for {codexSetup.NumberOfNodes} Codex nodes. Their accounts: [{string.Join(",", node.Accounts.Select(a => a.Account))}]"); - return node; - } - - private GethCompanionNodeInfo CreateCompanionInfo(RunningContainer container, MarketplaceNetwork marketplace, GethStartupConfig config) - { - var accounts = ExtractAccounts(marketplace, config); - return new GethCompanionNodeInfo(container, accounts); - } - - private static GethAccount[] ExtractAccounts(MarketplaceNetwork marketplace, GethStartupConfig config) - { - return marketplace.Bootstrap.AllAccounts.Accounts - .Skip(1 + config.CompanionAccountStartIndex) - .Take(config.NumberOfCompanionAccounts) - .ToArray(); - } - - private void EnsureCompanionNodeIsSynced(GethCompanionNodeInfo node, MarketplaceNetwork marketplace) - { - try - { - Time.WaitUntil(() => - { - var interaction = node.StartInteraction(lifecycle, node.Accounts.First()); - return interaction.IsSynced(marketplace.Marketplace.Address, marketplace.Marketplace.Abi); - }, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(3)); - } - catch (Exception e) - { - throw new Exception("Geth companion node did not sync within timeout. Test infra failure.", e); - } - } - - private GethStartupConfig CreateCompanionNodeStartupConfig(GethBootstrapNodeInfo bootstrapNode, int numberOfAccounts) - { - var config = new GethStartupConfig(false, bootstrapNode, companionAccountIndex, numberOfAccounts); - companionAccountIndex += numberOfAccounts; - return config; - } - - private StartupConfig CreateStartupConfig(GethStartupConfig gethConfig) - { - var config = new StartupConfig(); - config.Add(gethConfig); - return config; - } - } -} diff --git a/GethPlugin/GethContainerRecipe.cs b/GethPlugin/GethContainerRecipe.cs index 1c1b2e1..a3ad320 100644 --- a/GethPlugin/GethContainerRecipe.cs +++ b/GethPlugin/GethContainerRecipe.cs @@ -26,38 +26,23 @@ namespace GethPlugin { var discovery = AddInternalPort(tag: DiscoveryPortTag); - if (config.IsBootstrapNode) - { - return CreateBootstapArgs(discovery); - } - - return CreateCompanionArgs(discovery, config); - } - - private string CreateBootstapArgs(Port discovery) - { - AddEnvVar("ENABLE_MINER", "1"); + if (config.IsMiner) AddEnvVar("ENABLE_MINER", "1"); UnlockAccounts(0, 1); var exposedPort = AddExposedPort(tag: HttpPortTag); - return $"--http.port {exposedPort.Number} --port {discovery.Number} --discovery.port {discovery.Number} {defaultArgs}"; - } + var args = $"--http.addr 0.0.0.0 --http.port {exposedPort.Number} --port {discovery.Number} --discovery.port {discovery.Number} {defaultArgs}"; - private string CreateCompanionArgs(Port discovery, GethStartupConfig config) - { - UnlockAccounts( - config.CompanionAccountStartIndex + 1, - config.NumberOfCompanionAccounts); - - var port = AddInternalPort(); var authRpc = AddInternalPort(); - var httpPort = AddExposedPort(tag: HttpPortTag); - var bootPubKey = config.BootstrapNode.PubKey; - var bootIp = config.BootstrapNode.RunningContainers.Containers[0].Pod.PodInfo.Ip; - var bootPort = config.BootstrapNode.DiscoveryPort.Number; - var bootstrapArg = $"--bootnodes enode://{bootPubKey}@{bootIp}:{bootPort} --nat=extip:{bootIp}"; + if (config.BootstrapNode != null) + { + var bootPubKey = config.BootstrapNode.PublicKey; + var bootIp = config.BootstrapNode.IpAddress; + var bootPort = config.BootstrapNode.Port; + var bootstrapArg = $" --bootnodes enode://{bootPubKey}@{bootIp}:{bootPort} --nat=extip:{bootIp}"; + args += bootstrapArg; + } - return $"--port {port.Number} --discovery.port {discovery.Number} --authrpc.port {authRpc.Number} --http.addr 0.0.0.0 --http.port {httpPort.Number} --ws --ws.addr 0.0.0.0 --ws.port {httpPort.Number} {bootstrapArg} {defaultArgs}"; + return args + $" --authrpc.port {authRpc.Number} --ws --ws.addr 0.0.0.0 --ws.port {exposedPort.Number}"; } private void UnlockAccounts(int startIndex, int numberOfAccounts) diff --git a/GethPlugin/GethNodeInfo.cs b/GethPlugin/GethNodeInfo.cs new file mode 100644 index 0000000..c6e958d --- /dev/null +++ b/GethPlugin/GethNodeInfo.cs @@ -0,0 +1,35 @@ +using KubernetesWorkflow; + +namespace GethPlugin +{ + public interface IGethNodeInfo + { + } + + public class GethNodeInfo : IGethNodeInfo + { + public GethNodeInfo(RunningContainer runningContainer, AllGethAccounts allAccounts, string pubKey, Port discoveryPort) + { + RunningContainer = runningContainer; + AllAccounts = allAccounts; + Account = allAccounts.Accounts[0]; + PubKey = pubKey; + DiscoveryPort = discoveryPort; + } + + public RunningContainer RunningContainer { get; } + public AllGethAccounts AllAccounts { get; } + public GethAccount Account { get; } + public string PubKey { get; } + public Port DiscoveryPort { get; } + + //public NethereumInteraction StartInteraction(TestLifecycle lifecycle) + //{ + // var address = lifecycle.Configuration.GetAddress(RunningContainers.Containers[0]); + // var account = Account; + + // var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, account.PrivateKey); + // return creator.CreateWorkflow(); + //} + } +} diff --git a/GethPlugin/GethPlugin.cs b/GethPlugin/GethPlugin.cs index fcd15c2..08f36a4 100644 --- a/GethPlugin/GethPlugin.cs +++ b/GethPlugin/GethPlugin.cs @@ -6,11 +6,12 @@ namespace GethPlugin public class GethPlugin : IProjectPlugin, IHasLogPrefix, IHasMetadata { private readonly IPluginTools tools; + private readonly GethStarter starter; public GethPlugin(IPluginTools tools) { - //codexStarter = new CodexStarter(tools); this.tools = tools; + starter = new GethStarter(tools); } public string LogPrefix => "(Geth) "; @@ -29,6 +30,13 @@ namespace GethPlugin { } + public IGethNodeInfo StartGeth(Action setup) + { + var startupConfig = new GethStartupConfig(); + setup(startupConfig); + return starter.StartGeth(startupConfig); + } + //public RunningContainers[] StartCodexNodes(int numberOfNodes, Action setup) //{ // var codexSetup = new CodexSetup(numberOfNodes); diff --git a/GethPlugin/GethStartResult.cs b/GethPlugin/GethStartResult.cs index c098870..79a04a3 100644 --- a/GethPlugin/GethStartResult.cs +++ b/GethPlugin/GethStartResult.cs @@ -1,19 +1,19 @@ -using Newtonsoft.Json; +//using Newtonsoft.Json; -namespace GethPlugin -{ - public class GethStartResult - { - public GethStartResult(IMarketplaceAccessFactory marketplaceAccessFactory, MarketplaceNetwork marketplaceNetwork, GethCompanionNodeInfo companionNode) - { - MarketplaceAccessFactory = marketplaceAccessFactory; - MarketplaceNetwork = marketplaceNetwork; - CompanionNode = companionNode; - } +//namespace GethPlugin +//{ +// public class GethStartResult +// { +// public GethStartResult(IMarketplaceAccessFactory marketplaceAccessFactory, MarketplaceNetwork marketplaceNetwork, GethCompanionNodeInfo companionNode) +// { +// MarketplaceAccessFactory = marketplaceAccessFactory; +// MarketplaceNetwork = marketplaceNetwork; +// CompanionNode = companionNode; +// } - [JsonIgnore] - public IMarketplaceAccessFactory MarketplaceAccessFactory { get; } - public MarketplaceNetwork MarketplaceNetwork { get; } - public GethCompanionNodeInfo CompanionNode { get; } - } -} +// [JsonIgnore] +// public IMarketplaceAccessFactory MarketplaceAccessFactory { get; } +// public MarketplaceNetwork MarketplaceNetwork { get; } +// public GethCompanionNodeInfo CompanionNode { get; } +// } +//} diff --git a/GethPlugin/GethStarter.cs b/GethPlugin/GethStarter.cs index f9e2162..d883ec8 100644 --- a/GethPlugin/GethStarter.cs +++ b/GethPlugin/GethStarter.cs @@ -1,86 +1,121 @@ -namespace CodexPlugin +using Core; +using KubernetesWorkflow; + +namespace GethPlugin { public class GethStarter { - private readonly MarketplaceNetworkCache marketplaceNetworkCache; - private readonly GethCompanionNodeStarter companionNodeStarter; + private readonly IPluginTools tools; - public GethStarter(TestLifecycle lifecycle) - : base(lifecycle) + //private readonly MarketplaceNetworkCache marketplaceNetworkCache; + //private readonly GethCompanionNodeStarter companionNodeStarter; + + public GethStarter(IPluginTools tools) { - marketplaceNetworkCache = new MarketplaceNetworkCache( - new GethBootstrapNodeStarter(lifecycle), - new CodexContractsStarter(lifecycle)); - companionNodeStarter = new GethCompanionNodeStarter(lifecycle); + this.tools = tools; + //marketplaceNetworkCache = new MarketplaceNetworkCache( + // new GethBootstrapNodeStarter(lifecycle), + // new CodexContractsStarter(lifecycle)); + //companionNodeStarter = new GethCompanionNodeStarter(lifecycle); } - public GethStartResult BringOnlineMarketplaceFor(CodexSetup codexSetup) + public IGethNodeInfo StartGeth(GethStartupConfig gethStartupConfig) { - if (codexSetup.MarketplaceConfig == null) return CreateMarketplaceUnavailableResult(); + Log("Starting Geth bootstrap node..."); - var marketplaceNetwork = marketplaceNetworkCache.Get(); - var companionNode = StartCompanionNode(codexSetup, marketplaceNetwork); + var startupConfig = new StartupConfig(); + startupConfig.Add(gethStartupConfig); + startupConfig.NameOverride = gethStartupConfig.NameOverride; - LogStart("Setting up initial balance..."); - TransferInitialBalance(marketplaceNetwork, codexSetup.MarketplaceConfig, companionNode); - LogEnd($"Initial balance of {codexSetup.MarketplaceConfig.InitialTestTokens} set for {codexSetup.NumberOfNodes} nodes."); + var workflow = tools.CreateWorkflow(); + var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), startupConfig); + if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Geth bootstrap node to be created. Test infra failure."); + var container = containers.Containers[0]; - return CreateGethStartResult(marketplaceNetwork, companionNode); + var extractor = new ContainerInfoExtractor(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); + + Log($"Geth bootstrap node started with account '{result.Account.Account}'"); + + return result; } - private void TransferInitialBalance(MarketplaceNetwork marketplaceNetwork, MarketplaceInitialConfig marketplaceConfig, GethCompanionNodeInfo companionNode) + private void Log(string msg) { - if (marketplaceConfig.InitialTestTokens.Amount == 0) return; - - var interaction = marketplaceNetwork.StartInteraction(lifecycle); - var tokenAddress = marketplaceNetwork.Marketplace.TokenAddress; - - var accounts = companionNode.Accounts.Select(a => a.Account).ToArray(); - interaction.MintTestTokens(accounts, marketplaceConfig.InitialTestTokens.Amount, tokenAddress); + tools.GetLog().Log(msg); } - private GethStartResult CreateGethStartResult(MarketplaceNetwork marketplaceNetwork, GethCompanionNodeInfo companionNode) - { - return new GethStartResult(CreateMarketplaceAccessFactory(marketplaceNetwork), marketplaceNetwork, companionNode); - } + //public GethStartResult BringOnlineMarketplaceFor(CodexSetup codexSetup) + //{ + // if (codexSetup.MarketplaceConfig == null) return CreateMarketplaceUnavailableResult(); - private GethStartResult CreateMarketplaceUnavailableResult() - { - return new GethStartResult(new MarketplaceUnavailableAccessFactory(), null!, null!); - } + // var marketplaceNetwork = marketplaceNetworkCache.Get(); + // var companionNode = StartCompanionNode(codexSetup, marketplaceNetwork); - private IMarketplaceAccessFactory CreateMarketplaceAccessFactory(MarketplaceNetwork marketplaceNetwork) - { - return new GethMarketplaceAccessFactory(lifecycle, marketplaceNetwork); - } + // LogStart("Setting up initial balance..."); + // TransferInitialBalance(marketplaceNetwork, codexSetup.MarketplaceConfig, companionNode); + // LogEnd($"Initial balance of {codexSetup.MarketplaceConfig.InitialTestTokens} set for {codexSetup.NumberOfNodes} nodes."); - private GethCompanionNodeInfo StartCompanionNode(CodexSetup codexSetup, MarketplaceNetwork marketplaceNetwork) - { - return companionNodeStarter.StartCompanionNodeFor(codexSetup, marketplaceNetwork); - } + // return CreateGethStartResult(marketplaceNetwork, companionNode); + //} + + //private void TransferInitialBalance(MarketplaceNetwork marketplaceNetwork, MarketplaceInitialConfig marketplaceConfig, GethCompanionNodeInfo companionNode) + //{ + // if (marketplaceConfig.InitialTestTokens.Amount == 0) return; + + // var interaction = marketplaceNetwork.StartInteraction(lifecycle); + // var tokenAddress = marketplaceNetwork.Marketplace.TokenAddress; + + // var accounts = companionNode.Accounts.Select(a => a.Account).ToArray(); + // interaction.MintTestTokens(accounts, marketplaceConfig.InitialTestTokens.Amount, tokenAddress); + //} + + //private GethStartResult CreateGethStartResult(MarketplaceNetwork marketplaceNetwork, GethCompanionNodeInfo companionNode) + //{ + // return new GethStartResult(CreateMarketplaceAccessFactory(marketplaceNetwork), marketplaceNetwork, companionNode); + //} + + //private GethStartResult CreateMarketplaceUnavailableResult() + //{ + // return new GethStartResult(new MarketplaceUnavailableAccessFactory(), null!, null!); + //} + + //private IMarketplaceAccessFactory CreateMarketplaceAccessFactory(MarketplaceNetwork marketplaceNetwork) + //{ + // return new GethMarketplaceAccessFactory(lifecycle, marketplaceNetwork); + //} + + //private GethCompanionNodeInfo StartCompanionNode(CodexSetup codexSetup, MarketplaceNetwork marketplaceNetwork) + //{ + // return companionNodeStarter.StartCompanionNodeFor(codexSetup, marketplaceNetwork); + //} } - public class MarketplaceNetworkCache - { - private readonly GethBootstrapNodeStarter bootstrapNodeStarter; - private readonly CodexContractsStarter codexContractsStarter; - private MarketplaceNetwork? network; + //public class MarketplaceNetworkCache + //{ + // private readonly GethBootstrapNodeStarter bootstrapNodeStarter; + // private readonly CodexContractsStarter codexContractsStarter; + // private MarketplaceNetwork? network; - public MarketplaceNetworkCache(GethBootstrapNodeStarter bootstrapNodeStarter, CodexContractsStarter codexContractsStarter) - { - this.bootstrapNodeStarter = bootstrapNodeStarter; - this.codexContractsStarter = codexContractsStarter; - } + // public MarketplaceNetworkCache(GethBootstrapNodeStarter bootstrapNodeStarter, CodexContractsStarter codexContractsStarter) + // { + // this.bootstrapNodeStarter = bootstrapNodeStarter; + // this.codexContractsStarter = codexContractsStarter; + // } - public MarketplaceNetwork Get() - { - if (network == null) - { - var bootstrapInfo = bootstrapNodeStarter.StartGethBootstrapNode(); - var marketplaceInfo = codexContractsStarter.Start(bootstrapInfo); - network = new MarketplaceNetwork(bootstrapInfo, marketplaceInfo); - } - return network; - } - } + // public MarketplaceNetwork Get() + // { + // if (network == null) + // { + // var bootstrapInfo = bootstrapNodeStarter.StartGethBootstrapNode(); + // var marketplaceInfo = codexContractsStarter.Start(bootstrapInfo); + // network = new MarketplaceNetwork(bootstrapInfo, marketplaceInfo); + // } + // return network; + // } + //} } diff --git a/GethPlugin/GethStartupConfig.cs b/GethPlugin/GethStartupConfig.cs index d662a42..fb1991a 100644 --- a/GethPlugin/GethStartupConfig.cs +++ b/GethPlugin/GethStartupConfig.cs @@ -1,18 +1,48 @@ namespace GethPlugin { - public class GethStartupConfig + public interface IGethSetup { - public GethStartupConfig(bool isBootstrapNode, GethBootstrapNodeInfo bootstrapNode, int companionAccountStartIndex, int numberOfCompanionAccounts) + IGethSetup IsMiner(); + IGethSetup WithBootstrapNode(GethBootstrapNode node); + IGethSetup WithName(string name); + } + + public class GethStartupConfig : IGethSetup + { + public bool IsMiner { get; private set; } + public GethBootstrapNode? BootstrapNode { get; private set; } + public string? NameOverride { get; private set; } + + public IGethSetup WithBootstrapNode(GethBootstrapNode node) { - IsBootstrapNode = isBootstrapNode; - BootstrapNode = bootstrapNode; - CompanionAccountStartIndex = companionAccountStartIndex; - NumberOfCompanionAccounts = numberOfCompanionAccounts; + BootstrapNode = node; + return this; } - public bool IsBootstrapNode { get; } - public GethBootstrapNodeInfo BootstrapNode { get; } - public int CompanionAccountStartIndex { get; } - public int NumberOfCompanionAccounts { get; } + public IGethSetup WithName(string name) + { + NameOverride = name; + return this; + } + + IGethSetup IGethSetup.IsMiner() + { + IsMiner = true; + return this; + } + } + + public class GethBootstrapNode + { + public GethBootstrapNode(string publicKey, string ipAddress, int port) + { + PublicKey = publicKey; + IpAddress = ipAddress; + Port = port; + } + + public string PublicKey { get; } + public string IpAddress { get; } + public int Port { get; } } } diff --git a/KubernetesWorkflow/ContainerRecipeFactory.cs b/KubernetesWorkflow/ContainerRecipeFactory.cs index c8d26f7..bfd0919 100644 --- a/KubernetesWorkflow/ContainerRecipeFactory.cs +++ b/KubernetesWorkflow/ContainerRecipeFactory.cs @@ -51,16 +51,12 @@ namespace KubernetesWorkflow protected Port AddExposedPort(string tag = "") { - var p = factory.CreatePort(tag); - exposedPorts.Add(p); - return p; + return AddExposedPort(factory.CreatePort(tag)); } protected Port AddExposedPort(int number, string tag = "") { - var p = factory.CreatePort(number, tag); - exposedPorts.Add(p); - return p; + return AddExposedPort(factory.CreatePort(number, tag)); } protected Port AddInternalPort(string tag = "") @@ -112,5 +108,16 @@ namespace KubernetesWorkflow { additionals.Add(userData); } + + private Port AddExposedPort(Port port) + { + if (exposedPorts.Any()) + { + throw new NotImplementedException("Current implementation only support 1 exposed port per container recipe. " + + $"Methods for determining container addresses in {nameof(StartupWorkflow)} currently rely on this constraint."); + } + exposedPorts.Add(port); + return port; + } } } diff --git a/Tests/BasicTests/ExampleTests.cs b/Tests/BasicTests/ExampleTests.cs index 861a8af..9a79e89 100644 --- a/Tests/BasicTests/ExampleTests.cs +++ b/Tests/BasicTests/ExampleTests.cs @@ -1,5 +1,6 @@ using CodexPlugin; using DistTestCore; +using GethPlugin; using MetricsPlugin; using NUnit.Framework; using Utils; @@ -46,6 +47,8 @@ namespace Tests.BasicTests [Test] public void MarketplaceExample() { + var geth = Ci.StartGethNode(s => s.IsMiner().WithName("disttest-geth")); + //var sellerInitialBalance = 234.TestTokens(); //var buyerInitialBalance = 1000.TestTokens(); //var fileSize = 10.MB(); diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 27552d7..a735ca9 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -15,6 +15,7 @@ +