mirror of
https://github.com/codex-storage/cs-codex-dist-tests.git
synced 2025-02-13 20:46:37 +00:00
Can start Geth
This commit is contained in:
parent
f2a8c123a5
commit
4cc93eba73
@ -1,6 +1,4 @@
|
|||||||
//using DistTestCore.Marketplace;
|
using KubernetesWorkflow;
|
||||||
using Core;
|
|
||||||
using KubernetesWorkflow;
|
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
namespace CodexPlugin
|
namespace CodexPlugin
|
||||||
|
147
GethPlugin/ContainerInfoExtractor.cs
Normal file
147
GethPlugin/ContainerInfoExtractor.cs
Normal file
@ -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<MarketplaceJson>(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<string> 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<string> debug;
|
||||||
|
private string pubKey = string.Empty;
|
||||||
|
|
||||||
|
public PubKeyFinder(Action<string> 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;
|
||||||
|
//}
|
||||||
|
}
|
@ -1,44 +1,17 @@
|
|||||||
using Core;
|
using Core;
|
||||||
using KubernetesWorkflow;
|
|
||||||
|
|
||||||
namespace GethPlugin
|
namespace GethPlugin
|
||||||
{
|
{
|
||||||
public static class CoreInterfaceExtensions
|
public static class CoreInterfaceExtensions
|
||||||
{
|
{
|
||||||
//public static RunningContainers[] StartCodexNodes(this CoreInterface ci, int number, Action<ICodexSetup> setup)
|
public static IGethNodeInfo StartGethNode(this CoreInterface ci, Action<IGethSetup> setup)
|
||||||
//{
|
{
|
||||||
// return Plugin(ci).StartCodexNodes(number, setup);
|
return Plugin(ci).StartGeth(setup);
|
||||||
//}
|
}
|
||||||
|
|
||||||
//public static ICodexNodeGroup WrapCodexContainers(this CoreInterface ci, RunningContainers[] containers)
|
private static GethPlugin Plugin(CoreInterface ci)
|
||||||
//{
|
{
|
||||||
// return Plugin(ci).WrapCodexContainers(containers);
|
return ci.GetPlugin<GethPlugin>();
|
||||||
//}
|
}
|
||||||
|
|
||||||
//public static IOnlineCodexNode SetupCodexNode(this CoreInterface ci)
|
|
||||||
//{
|
|
||||||
// return ci.SetupCodexNodes(1)[0];
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public static IOnlineCodexNode SetupCodexNode(this CoreInterface ci, Action<ICodexSetup> setup)
|
|
||||||
//{
|
|
||||||
// return ci.SetupCodexNodes(1, setup)[0];
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public static ICodexNodeGroup SetupCodexNodes(this CoreInterface ci, int number, Action<ICodexSetup> 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<CodexPlugin>();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
GethPlugin/GethAccount.cs
Normal file
24
GethPlugin/GethAccount.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +1,26 @@
|
|||||||
using KubernetesWorkflow;
|
//using KubernetesWorkflow;
|
||||||
using NethereumWorkflow;
|
//using NethereumWorkflow;
|
||||||
|
|
||||||
namespace GethPlugin
|
//namespace GethPlugin
|
||||||
{
|
//{
|
||||||
public class GethCompanionNodeInfo
|
// public class GethCompanionNodeInfo
|
||||||
{
|
// {
|
||||||
public GethCompanionNodeInfo(RunningContainer runningContainer, GethAccount[] accounts)
|
// public GethCompanionNodeInfo(RunningContainer runningContainer, GethAccount[] accounts)
|
||||||
{
|
// {
|
||||||
RunningContainer = runningContainer;
|
// RunningContainer = runningContainer;
|
||||||
Accounts = accounts;
|
// Accounts = accounts;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public RunningContainer RunningContainer { get; }
|
// public RunningContainer RunningContainer { get; }
|
||||||
public GethAccount[] Accounts { get; }
|
// public GethAccount[] Accounts { get; }
|
||||||
|
|
||||||
public NethereumInteraction StartInteraction(TestLifecycle lifecycle, GethAccount account)
|
// public NethereumInteraction StartInteraction(TestLifecycle lifecycle, GethAccount account)
|
||||||
{
|
// {
|
||||||
var address = lifecycle.Configuration.GetAddress(RunningContainer);
|
// var address = lifecycle.Configuration.GetAddress(RunningContainer);
|
||||||
var privateKey = account.PrivateKey;
|
// var privateKey = account.PrivateKey;
|
||||||
|
|
||||||
var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, privateKey);
|
// var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, privateKey);
|
||||||
return creator.CreateWorkflow();
|
// return creator.CreateWorkflow();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
public class GethAccount
|
|
||||||
{
|
|
||||||
public GethAccount(string account, string privateKey)
|
|
||||||
{
|
|
||||||
Account = account;
|
|
||||||
PrivateKey = privateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Account { get; }
|
|
||||||
public string PrivateKey { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,38 +26,23 @@ namespace GethPlugin
|
|||||||
{
|
{
|
||||||
var discovery = AddInternalPort(tag: DiscoveryPortTag);
|
var discovery = AddInternalPort(tag: DiscoveryPortTag);
|
||||||
|
|
||||||
if (config.IsBootstrapNode)
|
if (config.IsMiner) AddEnvVar("ENABLE_MINER", "1");
|
||||||
{
|
|
||||||
return CreateBootstapArgs(discovery);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateCompanionArgs(discovery, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CreateBootstapArgs(Port discovery)
|
|
||||||
{
|
|
||||||
AddEnvVar("ENABLE_MINER", "1");
|
|
||||||
UnlockAccounts(0, 1);
|
UnlockAccounts(0, 1);
|
||||||
var exposedPort = AddExposedPort(tag: HttpPortTag);
|
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}";
|
||||||
|
|
||||||
|
var authRpc = AddInternalPort();
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateCompanionArgs(Port discovery, GethStartupConfig config)
|
return args + $" --authrpc.port {authRpc.Number} --ws --ws.addr 0.0.0.0 --ws.port {exposedPort.Number}";
|
||||||
{
|
|
||||||
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}";
|
|
||||||
|
|
||||||
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}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnlockAccounts(int startIndex, int numberOfAccounts)
|
private void UnlockAccounts(int startIndex, int numberOfAccounts)
|
||||||
|
35
GethPlugin/GethNodeInfo.cs
Normal file
35
GethPlugin/GethNodeInfo.cs
Normal file
@ -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();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
@ -6,11 +6,12 @@ namespace GethPlugin
|
|||||||
public class GethPlugin : IProjectPlugin, IHasLogPrefix, IHasMetadata
|
public class GethPlugin : IProjectPlugin, IHasLogPrefix, IHasMetadata
|
||||||
{
|
{
|
||||||
private readonly IPluginTools tools;
|
private readonly IPluginTools tools;
|
||||||
|
private readonly GethStarter starter;
|
||||||
|
|
||||||
public GethPlugin(IPluginTools tools)
|
public GethPlugin(IPluginTools tools)
|
||||||
{
|
{
|
||||||
//codexStarter = new CodexStarter(tools);
|
|
||||||
this.tools = tools;
|
this.tools = tools;
|
||||||
|
starter = new GethStarter(tools);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LogPrefix => "(Geth) ";
|
public string LogPrefix => "(Geth) ";
|
||||||
@ -29,6 +30,13 @@ namespace GethPlugin
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IGethNodeInfo StartGeth(Action<IGethSetup> setup)
|
||||||
|
{
|
||||||
|
var startupConfig = new GethStartupConfig();
|
||||||
|
setup(startupConfig);
|
||||||
|
return starter.StartGeth(startupConfig);
|
||||||
|
}
|
||||||
|
|
||||||
//public RunningContainers[] StartCodexNodes(int numberOfNodes, Action<ICodexSetup> setup)
|
//public RunningContainers[] StartCodexNodes(int numberOfNodes, Action<ICodexSetup> setup)
|
||||||
//{
|
//{
|
||||||
// var codexSetup = new CodexSetup(numberOfNodes);
|
// var codexSetup = new CodexSetup(numberOfNodes);
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
using Newtonsoft.Json;
|
//using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace GethPlugin
|
//namespace GethPlugin
|
||||||
{
|
//{
|
||||||
public class GethStartResult
|
// public class GethStartResult
|
||||||
{
|
// {
|
||||||
public GethStartResult(IMarketplaceAccessFactory marketplaceAccessFactory, MarketplaceNetwork marketplaceNetwork, GethCompanionNodeInfo companionNode)
|
// public GethStartResult(IMarketplaceAccessFactory marketplaceAccessFactory, MarketplaceNetwork marketplaceNetwork, GethCompanionNodeInfo companionNode)
|
||||||
{
|
// {
|
||||||
MarketplaceAccessFactory = marketplaceAccessFactory;
|
// MarketplaceAccessFactory = marketplaceAccessFactory;
|
||||||
MarketplaceNetwork = marketplaceNetwork;
|
// MarketplaceNetwork = marketplaceNetwork;
|
||||||
CompanionNode = companionNode;
|
// CompanionNode = companionNode;
|
||||||
}
|
// }
|
||||||
|
|
||||||
[JsonIgnore]
|
// [JsonIgnore]
|
||||||
public IMarketplaceAccessFactory MarketplaceAccessFactory { get; }
|
// public IMarketplaceAccessFactory MarketplaceAccessFactory { get; }
|
||||||
public MarketplaceNetwork MarketplaceNetwork { get; }
|
// public MarketplaceNetwork MarketplaceNetwork { get; }
|
||||||
public GethCompanionNodeInfo CompanionNode { get; }
|
// public GethCompanionNodeInfo CompanionNode { get; }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
@ -1,86 +1,121 @@
|
|||||||
namespace CodexPlugin
|
using Core;
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
|
||||||
|
namespace GethPlugin
|
||||||
{
|
{
|
||||||
public class GethStarter
|
public class GethStarter
|
||||||
{
|
{
|
||||||
private readonly MarketplaceNetworkCache marketplaceNetworkCache;
|
private readonly IPluginTools tools;
|
||||||
private readonly GethCompanionNodeStarter companionNodeStarter;
|
|
||||||
|
|
||||||
public GethStarter(TestLifecycle lifecycle)
|
//private readonly MarketplaceNetworkCache marketplaceNetworkCache;
|
||||||
: base(lifecycle)
|
//private readonly GethCompanionNodeStarter companionNodeStarter;
|
||||||
|
|
||||||
|
public GethStarter(IPluginTools tools)
|
||||||
{
|
{
|
||||||
marketplaceNetworkCache = new MarketplaceNetworkCache(
|
this.tools = tools;
|
||||||
new GethBootstrapNodeStarter(lifecycle),
|
//marketplaceNetworkCache = new MarketplaceNetworkCache(
|
||||||
new CodexContractsStarter(lifecycle));
|
// new GethBootstrapNodeStarter(lifecycle),
|
||||||
companionNodeStarter = new GethCompanionNodeStarter(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 startupConfig = new StartupConfig();
|
||||||
var companionNode = StartCompanionNode(codexSetup, marketplaceNetwork);
|
startupConfig.Add(gethStartupConfig);
|
||||||
|
startupConfig.NameOverride = gethStartupConfig.NameOverride;
|
||||||
|
|
||||||
LogStart("Setting up initial balance...");
|
var workflow = tools.CreateWorkflow();
|
||||||
TransferInitialBalance(marketplaceNetwork, codexSetup.MarketplaceConfig, companionNode);
|
var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), startupConfig);
|
||||||
LogEnd($"Initial balance of {codexSetup.MarketplaceConfig.InitialTestTokens} set for {codexSetup.NumberOfNodes} nodes.");
|
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;
|
tools.GetLog().Log(msg);
|
||||||
|
|
||||||
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)
|
//public GethStartResult BringOnlineMarketplaceFor(CodexSetup codexSetup)
|
||||||
{
|
//{
|
||||||
return new GethStartResult(CreateMarketplaceAccessFactory(marketplaceNetwork), marketplaceNetwork, companionNode);
|
// if (codexSetup.MarketplaceConfig == null) return CreateMarketplaceUnavailableResult();
|
||||||
|
|
||||||
|
// var marketplaceNetwork = marketplaceNetworkCache.Get();
|
||||||
|
// var companionNode = StartCompanionNode(codexSetup, marketplaceNetwork);
|
||||||
|
|
||||||
|
// LogStart("Setting up initial balance...");
|
||||||
|
// TransferInitialBalance(marketplaceNetwork, codexSetup.MarketplaceConfig, companionNode);
|
||||||
|
// LogEnd($"Initial balance of {codexSetup.MarketplaceConfig.InitialTestTokens} set for {codexSetup.NumberOfNodes} nodes.");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GethStartResult CreateMarketplaceUnavailableResult()
|
//public class MarketplaceNetworkCache
|
||||||
{
|
//{
|
||||||
return new GethStartResult(new MarketplaceUnavailableAccessFactory(), null!, null!);
|
// private readonly GethBootstrapNodeStarter bootstrapNodeStarter;
|
||||||
}
|
// private readonly CodexContractsStarter codexContractsStarter;
|
||||||
|
// private MarketplaceNetwork? network;
|
||||||
|
|
||||||
private IMarketplaceAccessFactory CreateMarketplaceAccessFactory(MarketplaceNetwork marketplaceNetwork)
|
// public MarketplaceNetworkCache(GethBootstrapNodeStarter bootstrapNodeStarter, CodexContractsStarter codexContractsStarter)
|
||||||
{
|
// {
|
||||||
return new GethMarketplaceAccessFactory(lifecycle, marketplaceNetwork);
|
// this.bootstrapNodeStarter = bootstrapNodeStarter;
|
||||||
}
|
// this.codexContractsStarter = codexContractsStarter;
|
||||||
|
// }
|
||||||
|
|
||||||
private GethCompanionNodeInfo StartCompanionNode(CodexSetup codexSetup, MarketplaceNetwork marketplaceNetwork)
|
// public MarketplaceNetwork Get()
|
||||||
{
|
// {
|
||||||
return companionNodeStarter.StartCompanionNodeFor(codexSetup, marketplaceNetwork);
|
// if (network == null)
|
||||||
}
|
// {
|
||||||
}
|
// var bootstrapInfo = bootstrapNodeStarter.StartGethBootstrapNode();
|
||||||
|
// var marketplaceInfo = codexContractsStarter.Start(bootstrapInfo);
|
||||||
public class MarketplaceNetworkCache
|
// network = new MarketplaceNetwork(bootstrapInfo, marketplaceInfo);
|
||||||
{
|
// }
|
||||||
private readonly GethBootstrapNodeStarter bootstrapNodeStarter;
|
// return network;
|
||||||
private readonly CodexContractsStarter codexContractsStarter;
|
// }
|
||||||
private MarketplaceNetwork? network;
|
//}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,48 @@
|
|||||||
namespace GethPlugin
|
namespace GethPlugin
|
||||||
{
|
{
|
||||||
public class GethStartupConfig
|
public interface IGethSetup
|
||||||
{
|
{
|
||||||
public GethStartupConfig(bool isBootstrapNode, GethBootstrapNodeInfo bootstrapNode, int companionAccountStartIndex, int numberOfCompanionAccounts)
|
IGethSetup IsMiner();
|
||||||
{
|
IGethSetup WithBootstrapNode(GethBootstrapNode node);
|
||||||
IsBootstrapNode = isBootstrapNode;
|
IGethSetup WithName(string name);
|
||||||
BootstrapNode = bootstrapNode;
|
|
||||||
CompanionAccountStartIndex = companionAccountStartIndex;
|
|
||||||
NumberOfCompanionAccounts = numberOfCompanionAccounts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsBootstrapNode { get; }
|
public class GethStartupConfig : IGethSetup
|
||||||
public GethBootstrapNodeInfo BootstrapNode { get; }
|
{
|
||||||
public int CompanionAccountStartIndex { get; }
|
public bool IsMiner { get; private set; }
|
||||||
public int NumberOfCompanionAccounts { get; }
|
public GethBootstrapNode? BootstrapNode { get; private set; }
|
||||||
|
public string? NameOverride { get; private set; }
|
||||||
|
|
||||||
|
public IGethSetup WithBootstrapNode(GethBootstrapNode node)
|
||||||
|
{
|
||||||
|
BootstrapNode = node;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,16 +51,12 @@ namespace KubernetesWorkflow
|
|||||||
|
|
||||||
protected Port AddExposedPort(string tag = "")
|
protected Port AddExposedPort(string tag = "")
|
||||||
{
|
{
|
||||||
var p = factory.CreatePort(tag);
|
return AddExposedPort(factory.CreatePort(tag));
|
||||||
exposedPorts.Add(p);
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Port AddExposedPort(int number, string tag = "")
|
protected Port AddExposedPort(int number, string tag = "")
|
||||||
{
|
{
|
||||||
var p = factory.CreatePort(number, tag);
|
return AddExposedPort(factory.CreatePort(number, tag));
|
||||||
exposedPorts.Add(p);
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Port AddInternalPort(string tag = "")
|
protected Port AddInternalPort(string tag = "")
|
||||||
@ -112,5 +108,16 @@ namespace KubernetesWorkflow
|
|||||||
{
|
{
|
||||||
additionals.Add(userData);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using CodexPlugin;
|
using CodexPlugin;
|
||||||
using DistTestCore;
|
using DistTestCore;
|
||||||
|
using GethPlugin;
|
||||||
using MetricsPlugin;
|
using MetricsPlugin;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Utils;
|
using Utils;
|
||||||
@ -46,6 +47,8 @@ namespace Tests.BasicTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void MarketplaceExample()
|
public void MarketplaceExample()
|
||||||
{
|
{
|
||||||
|
var geth = Ci.StartGethNode(s => s.IsMiner().WithName("disttest-geth"));
|
||||||
|
|
||||||
//var sellerInitialBalance = 234.TestTokens();
|
//var sellerInitialBalance = 234.TestTokens();
|
||||||
//var buyerInitialBalance = 1000.TestTokens();
|
//var buyerInitialBalance = 1000.TestTokens();
|
||||||
//var fileSize = 10.MB();
|
//var fileSize = 10.MB();
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodexPlugin\CodexPlugin.csproj" />
|
<ProjectReference Include="..\CodexPlugin\CodexPlugin.csproj" />
|
||||||
<ProjectReference Include="..\DistTestCore\DistTestCore.csproj" />
|
<ProjectReference Include="..\DistTestCore\DistTestCore.csproj" />
|
||||||
|
<ProjectReference Include="..\GethPlugin\GethPlugin.csproj" />
|
||||||
<ProjectReference Include="..\MetricsPlugin\MetricsPlugin.csproj" />
|
<ProjectReference Include="..\MetricsPlugin\MetricsPlugin.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user