diff --git a/CodexDistTestCore/Marketplace/MarketplaceController.cs b/CodexDistTestCore/Marketplace/MarketplaceController.cs index 21bfc08d..8bab9e93 100644 --- a/CodexDistTestCore/Marketplace/MarketplaceController.cs +++ b/CodexDistTestCore/Marketplace/MarketplaceController.cs @@ -1,7 +1,4 @@ using CodexDistTestCore.Config; -using Nethereum.Web3; -using Nethereum.Web3.Accounts; -using Nethereum.Web3.Accounts.Managed; using NUnit.Framework; using System.Numerics; using System.Text; @@ -22,138 +19,6 @@ namespace CodexDistTestCore.Marketplace this.k8sManager = k8sManager; } - public GethCompanionGroup BringOnlineMarketplace(OfflineCodexNodes offline) - { - if (bootstrapInfo == null) - { - BringOnlineBootstrapNode(); - } - log.Log($"Initializing companions for {offline.NumberOfNodes} Codex nodes."); - - var group = new GethCompanionGroup(companionGroupNumberSource.GetNextNumber(), CreateCompanionContainers(offline)); - group.Pod = k8sManager.BringOnlineGethCompanionGroup(bootstrapInfo!, group); - companionGroups.Add(group); - - log.Log("Initialized companion nodes."); - return group; - } - - private void BringOnlineBootstrapNode() - { - log.Log("Starting Geth bootstrap node..."); - var spec = k8sManager.CreateGethBootstrapNodeSpec(); - var pod = k8sManager.BringOnlineGethBootstrapNode(spec); - var (account, genesisJson) = ExtractAccountAndGenesisJson(pod); - bootstrapInfo = new GethBootstrapInfo(spec, pod, account, genesisJson); - log.Log($"Geth boothstrap node started."); - } - - private GethCompanionNodeContainer[] CreateCompanionContainers(OfflineCodexNodes offline) - { - var numberSource = new NumberSource(8080); - var result = new List(); - for (var i = 0; i < offline.NumberOfNodes; i++) result.Add(CreateGethNodeContainer(numberSource, i)); - return result.ToArray(); - } - - private GethCompanionNodeContainer CreateGethNodeContainer(NumberSource numberSource, int n) - { - return new GethCompanionNodeContainer( - name: $"geth-node{n}", - apiPort: numberSource.GetNextNumber(), - authRpcPort: numberSource.GetNextNumber(), - rpcPort: numberSource.GetNextNumber(), - containerPortName: $"geth-{n}" - ); - } - - private readonly K8sCluster k8sCluster = new K8sCluster(); - - public void AddToBalance(string account, decimal amount) - { - if (amount < 1 || string.IsNullOrEmpty(account)) Assert.Fail("Invalid arguments for AddToBalance"); - - // call the bootstrap node and convince it to give 'account' 'amount' tokens somehow. - - var web3 = CreateWeb3(); - - //var blockNumber1 = Utils.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync()); - //Thread.Sleep(TimeSpan.FromSeconds(5)); - //var blockNumber2 = Utils.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync()); - - //var bootstrapBalance = Utils.Wait(web3.Eth.GetBalance.SendRequestAsync(bootstrapInfo.Account)); - - - var bigint = new BigInteger(amount); - var str = bigint.ToString("X"); - var value = new Nethereum.Hex.HexTypes.HexBigInteger(str); - var aaa = Utils.Wait(web3.Eth.TransactionManager.SendTransactionAsync(bootstrapInfo!.Account, account, value)); - var receipt = Utils.Wait(web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(aaa)); - - //var receipt = Utils.Wait(web3.Eth.GetEtherTransferService().TransferEtherAndWaitForReceiptAsync(account, amount)); - //var targetBalance = Utils.Wait(web3.Eth.GetBalance.SendRequestAsync(account)); - } - - public decimal GetBalance(string account) - { - var web3 = CreateWeb3(); - var bigInt = Utils.Wait(web3.Eth.GetBalance.SendRequestAsync(account)); - return (decimal)bigInt.Value; - } - - private Web3 CreateWeb3() - { - var ip = k8sCluster.GetIp(); - var port = bootstrapInfo!.Spec.ServicePort; - //var bootstrapaccount = new ManagedAccount(bootstrapInfo.Account, "qwerty!@#$%^"); - return new Web3($"http://{ip}:{port}"); - } - - private (string, string) ExtractAccountAndGenesisJson(PodInfo pod) - { - var (account, genesisJson) = FetchAccountAndGenesisJson(pod); - if (string.IsNullOrEmpty(account) || string.IsNullOrEmpty(genesisJson)) - { - Thread.Sleep(TimeSpan.FromSeconds(15)); - (account, genesisJson) = FetchAccountAndGenesisJson(pod); - } - - Assert.That(account, Is.Not.Empty, "Unable to fetch account for geth bootstrap node. Test infra failure."); - Assert.That(genesisJson, Is.Not.Empty, "Unable to fetch genesis-json for geth bootstrap node. Test infra failure."); - - var encoded = Convert.ToBase64String(Encoding.ASCII.GetBytes(genesisJson)); - - log.Log($"Initialized geth bootstrap node with account '{account}'"); - return (account, encoded); - } - - private (string, string) FetchAccountAndGenesisJson(PodInfo pod) - { - var bootstrapAccount = ExecuteCommand(pod, "cat", GethDockerImage.AccountFilename); - var bootstrapGenesisJson = ExecuteCommand(pod, "cat", GethDockerImage.GenesisFilename); - return (bootstrapAccount, bootstrapGenesisJson); - } - - private string ExecuteCommand(PodInfo pod, string command, params string[] arguments) - { - return k8sManager.ExecuteCommand(pod, K8sGethBoostrapSpecs.ContainerName, command, arguments); - } - } - - public class GethBootstrapInfo - { - public GethBootstrapInfo(K8sGethBoostrapSpecs spec, PodInfo pod, string account, string genesisJsonBase64) - { - Spec = spec; - Pod = pod; - Account = account; - GenesisJsonBase64 = genesisJsonBase64; - } - - public K8sGethBoostrapSpecs Spec { get; } - public PodInfo Pod { get; } - public string Account { get; } - public string GenesisJsonBase64 { get; } } } diff --git a/CodexDistTestCore/Marketplace/MarketplaceInitialConfig.cs b/CodexDistTestCore/Marketplace/MarketplaceInitialConfig.cs index f7761f5d..23ad25f7 100644 --- a/CodexDistTestCore/Marketplace/MarketplaceInitialConfig.cs +++ b/CodexDistTestCore/Marketplace/MarketplaceInitialConfig.cs @@ -1,12 +1,4 @@ namespace CodexDistTestCore.Marketplace { - public class MarketplaceInitialConfig - { - public MarketplaceInitialConfig(int initialBalance) - { - InitialBalance = initialBalance; - } - public int InitialBalance { get; } - } } diff --git a/DistTestCore/Codex/CodexContainerRecipe.cs b/DistTestCore/Codex/CodexContainerRecipe.cs index e49dd841..31a9a7fd 100644 --- a/DistTestCore/Codex/CodexContainerRecipe.cs +++ b/DistTestCore/Codex/CodexContainerRecipe.cs @@ -1,4 +1,5 @@ -using KubernetesWorkflow; +using DistTestCore.Marketplace; +using KubernetesWorkflow; namespace DistTestCore.Codex { @@ -32,6 +33,20 @@ namespace DistTestCore.Codex AddEnvVar("METRICS_ADDR", "0.0.0.0"); AddInternalPortAndVar("METRICS_PORT", tag: MetricsPortTag); } + + if (config.MarketplaceConfig != null) + { + var gethConfig = startupConfig.Get(); + var companionNode = gethConfig.CompanionNodes[Index]; + + // Bootstrap node access from within the cluster: + //var ip = gethConfig.BootstrapNode.RunningContainers.RunningPod.Ip; + //var port = gethConfig.BootstrapNode.RunningContainers.Containers[0].Recipe.GetPortByTag(GethContainerRecipe.HttpPortTag); + + //AddEnvVar("ETH_PROVIDER", "todo"); + //AddEnvVar("ETH_ACCOUNT", companionNode.Account); + //AddEnvVar("ETH_DEPLOYMENT", "todo"); + } } } } diff --git a/DistTestCore/Codex/CodexStartupConfig.cs b/DistTestCore/Codex/CodexStartupConfig.cs index f83d629d..915d4b93 100644 --- a/DistTestCore/Codex/CodexStartupConfig.cs +++ b/DistTestCore/Codex/CodexStartupConfig.cs @@ -1,4 +1,5 @@ -using KubernetesWorkflow; +using DistTestCore.Marketplace; +using KubernetesWorkflow; namespace DistTestCore.Codex { @@ -8,8 +9,8 @@ namespace DistTestCore.Codex public CodexLogLevel? LogLevel { get; set; } public ByteSize? StorageQuota { get; set; } public bool MetricsEnabled { get; set; } + public MarketplaceInitialConfig? MarketplaceConfig { get; set; } //public IOnlineCodexNode? BootstrapNode { get; private set; } - //public MarketplaceInitialConfig? MarketplaceConfig { get; private set; } } } diff --git a/DistTestCore/CodexNodeFactory.cs b/DistTestCore/CodexNodeFactory.cs index 3dce8aad..83201110 100644 --- a/DistTestCore/CodexNodeFactory.cs +++ b/DistTestCore/CodexNodeFactory.cs @@ -1,4 +1,5 @@ using DistTestCore.Codex; +using DistTestCore.Marketplace; using DistTestCore.Metrics; namespace DistTestCore @@ -12,17 +13,20 @@ namespace DistTestCore { private readonly TestLifecycle lifecycle; private readonly IMetricsAccessFactory metricsAccessFactory; + private readonly IMarketplaceAccessFactory marketplaceAccessFactory; - public CodexNodeFactory(TestLifecycle lifecycle, IMetricsAccessFactory metricsAccessFactory) + public CodexNodeFactory(TestLifecycle lifecycle, IMetricsAccessFactory metricsAccessFactory, IMarketplaceAccessFactory marketplaceAccessFactory) { this.lifecycle = lifecycle; this.metricsAccessFactory = metricsAccessFactory; + this.marketplaceAccessFactory = marketplaceAccessFactory; } public OnlineCodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group) { var metricsAccess = metricsAccessFactory.CreateMetricsAccess(access.Container); - return new OnlineCodexNode(lifecycle, access, group, metricsAccess); + var marketplaceAccess = marketplaceAccessFactory.CreateMarketplaceAccess(); + return new OnlineCodexNode(lifecycle, access, group, metricsAccess, marketplaceAccess); } } } diff --git a/DistTestCore/CodexSetup.cs b/DistTestCore/CodexSetup.cs index ddc6ef00..5acedcb1 100644 --- a/DistTestCore/CodexSetup.cs +++ b/DistTestCore/CodexSetup.cs @@ -1,4 +1,5 @@ using DistTestCore.Codex; +using DistTestCore.Marketplace; using KubernetesWorkflow; namespace DistTestCore @@ -10,7 +11,7 @@ namespace DistTestCore //ICodexStartupConfig WithBootstrapNode(IOnlineCodexNode node); ICodexSetup WithStorageQuota(ByteSize storageQuota); ICodexSetup EnableMetrics(); - //ICodexSetupConfig EnableMarketplace(int initialBalance); + ICodexSetup EnableMarketplace(int initialBalance); ICodexNodeGroup BringOnline(); } @@ -61,11 +62,11 @@ namespace DistTestCore return this; } - //public ICodexSetupConfig EnableMarketplace(int initialBalance) - //{ - // MarketplaceConfig = new MarketplaceInitialConfig(initialBalance); - // return this; - //} + public ICodexSetup EnableMarketplace(int initialBalance) + { + MarketplaceConfig = new MarketplaceInitialConfig(initialBalance); + return this; + } public string Describe() { diff --git a/DistTestCore/CodexStarter.cs b/DistTestCore/CodexStarter.cs index b85fba4d..e6d44846 100644 --- a/DistTestCore/CodexStarter.cs +++ b/DistTestCore/CodexStarter.cs @@ -18,16 +18,21 @@ namespace DistTestCore public ICodexNodeGroup BringOnline(CodexSetup codexSetup) { - var something = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup); + Log($"Starting {codexSetup.Describe()}..."); + var gethStartResult = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup); - var containers = StartCodexContainers(codexSetup); + var startupConfig = new StartupConfig(); + startupConfig.Add(codexSetup); + startupConfig.Add(gethStartResult); + + var containers = StartCodexContainers(startupConfig, codexSetup.NumberOfNodes, codexSetup.Location); var metricAccessFactory = lifecycle.PrometheusStarter.CollectMetricsFor(codexSetup, containers); - var codexNodeFactory = new CodexNodeFactory(lifecycle, metricAccessFactory); + var codexNodeFactory = new CodexNodeFactory(lifecycle, metricAccessFactory, gethStartResult.MarketplaceAccessFactory); var group = CreateCodexGroup(codexSetup, containers, codexNodeFactory); - + Log($"Started at '{group.Containers.RunningPod.Ip}'"); return group; } @@ -54,15 +59,10 @@ namespace DistTestCore workflow.DownloadContainerLog(container, logHandler); } - private RunningContainers StartCodexContainers(CodexSetup codexSetup) + private RunningContainers StartCodexContainers(StartupConfig startupConfig, int numberOfNodes, Location location) { - Log($"Starting {codexSetup.Describe()}..."); - var workflow = CreateWorkflow(); - var startupConfig = new StartupConfig(); - startupConfig.Add(codexSetup); - - return workflow.Start(codexSetup.NumberOfNodes, codexSetup.Location, new CodexContainerRecipe(), startupConfig); + return workflow.Start(numberOfNodes, location, new CodexContainerRecipe(), startupConfig); } private CodexNodeGroup CreateCodexGroup(CodexSetup codexSetup, RunningContainers runningContainers, CodexNodeFactory codexNodeFactory) @@ -70,7 +70,6 @@ namespace DistTestCore var group = new CodexNodeGroup(lifecycle, codexSetup, runningContainers, codexNodeFactory); RunningGroups.Add(group); - Log($"Started at '{group.Containers.RunningPod.Ip}'"); return group; } diff --git a/DistTestCore/DistTestCore.csproj b/DistTestCore/DistTestCore.csproj index c57463de..944e7480 100644 --- a/DistTestCore/DistTestCore.csproj +++ b/DistTestCore/DistTestCore.csproj @@ -8,7 +8,6 @@ - @@ -17,5 +16,6 @@ + diff --git a/DistTestCore/GethStarter.cs b/DistTestCore/GethStarter.cs index bf26523e..c0db9274 100644 --- a/DistTestCore/GethStarter.cs +++ b/DistTestCore/GethStarter.cs @@ -6,23 +6,43 @@ namespace DistTestCore public class GethStarter { private readonly TestLifecycle lifecycle; - private readonly WorkflowCreator workflowCreator; private readonly GethBootstrapNodeStarter bootstrapNodeStarter; + private readonly GethCompanionNodeStarter companionNodeStarter; private GethBootstrapNodeInfo? bootstrapNode; public GethStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) { this.lifecycle = lifecycle; - this.workflowCreator = workflowCreator; bootstrapNodeStarter = new GethBootstrapNodeStarter(lifecycle, workflowCreator); + companionNodeStarter = new GethCompanionNodeStarter(lifecycle, workflowCreator); } - public object BringOnlineMarketplaceFor(CodexSetup codexSetup) + public GethStartResult BringOnlineMarketplaceFor(CodexSetup codexSetup) { + if (codexSetup.MarketplaceConfig == null) return CreateMarketplaceUnavailableResult(); + EnsureBootstrapNode(); - StartCompanionNodes(codexSetup); - return null!; + var companionNodes = StartCompanionNodes(codexSetup); + + TransferInitialBalance(codexSetup.MarketplaceConfig.InitialBalance, bootstrapNode, companionNodes); + + return new GethStartResult(CreateMarketplaceAccessFactory(), bootstrapNode!, companionNodes); + } + + private void TransferInitialBalance(int initialBalance, GethBootstrapNodeInfo? bootstrapNode, GethCompanionNodeInfo[] companionNodes) + { + aaaa + } + + private GethStartResult CreateMarketplaceUnavailableResult() + { + return new GethStartResult(new MarketplaceUnavailableAccessFactory(), null!, Array.Empty()); + } + + private IMarketplaceAccessFactory CreateMarketplaceAccessFactory() + { + throw new NotImplementedException(); } private void EnsureBootstrapNode() @@ -31,14 +51,9 @@ namespace DistTestCore bootstrapNode = bootstrapNodeStarter.StartGethBootstrapNode(); } - private void StartCompanionNodes(CodexSetup codexSetup) + private GethCompanionNodeInfo[] StartCompanionNodes(CodexSetup codexSetup) { - throw new NotImplementedException(); - } - - private void Log(string msg) - { - lifecycle.Log.Log(msg); + return companionNodeStarter.StartCompanionNodesFor(codexSetup, bootstrapNode!); } } } diff --git a/DistTestCore/Marketplace/GethContainerRecipe.cs b/DistTestCore/Marketplace/GethContainerRecipe.cs index 3df72f6e..2db85298 100644 --- a/DistTestCore/Marketplace/GethContainerRecipe.cs +++ b/DistTestCore/Marketplace/GethContainerRecipe.cs @@ -5,6 +5,7 @@ namespace DistTestCore.Marketplace public class GethContainerRecipe : ContainerRecipeFactory { protected override string Image => "thatbenbierens/geth-confenv:latest"; + public const string HttpPortTag = "http_port"; public const string AccountFilename = "account_string.txt"; public const string GenesisFilename = "genesis.json"; @@ -30,7 +31,7 @@ namespace DistTestCore.Marketplace var port = AddInternalPort(); var discovery = AddInternalPort(); var authRpc = AddInternalPort(); - var httpPort = AddInternalPort(); + var httpPort = AddInternalPort(tag: HttpPortTag); return $"--port {port.Number} --discovery.port {discovery.Number} --authrpc.port {authRpc.Number} --http.port {httpPort.Number}"; } } diff --git a/DistTestCore/Marketplace/GethStartResult.cs b/DistTestCore/Marketplace/GethStartResult.cs new file mode 100644 index 00000000..f1d9c977 --- /dev/null +++ b/DistTestCore/Marketplace/GethStartResult.cs @@ -0,0 +1,16 @@ +namespace DistTestCore.Marketplace +{ + public class GethStartResult + { + public GethStartResult(IMarketplaceAccessFactory marketplaceAccessFactory, GethBootstrapNodeInfo bootstrapNode, GethCompanionNodeInfo[] companionNodes) + { + MarketplaceAccessFactory = marketplaceAccessFactory; + BootstrapNode = bootstrapNode; + CompanionNodes = companionNodes; + } + + public IMarketplaceAccessFactory MarketplaceAccessFactory { get; } + public GethBootstrapNodeInfo BootstrapNode { get; } + public GethCompanionNodeInfo[] CompanionNodes { get; } + } +} diff --git a/DistTestCore/Marketplace/MarketplaceAccess.cs b/DistTestCore/Marketplace/MarketplaceAccess.cs new file mode 100644 index 00000000..aa55cbfd --- /dev/null +++ b/DistTestCore/Marketplace/MarketplaceAccess.cs @@ -0,0 +1,85 @@ +using Logging; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace DistTestCore.Marketplace +{ + public interface IMarketplaceAccess + { + void MakeStorageAvailable(ByteSize size, int minPricePerBytePerSecond, float maxCollateral); + void RequestStorage(ContentId contentId, int pricePerBytePerSecond, float requiredCollateral, float minRequiredNumberOfNodes); + void AssertThatBalance(IResolveConstraint constraint, string message = ""); + decimal GetBalance(); + } + + public class MarketplaceAccess : IMarketplaceAccess + { + private readonly TestLog log; + private readonly CodexNodeGroup group; + + public MarketplaceAccess(TestLog log, CodexNodeGroup group) + { + this.log = log; + this.group = group; + } + + public void Initialize() + { + EnsureAccount(); + + marketplaceController.AddToBalance(container.Account, group.Origin.MarketplaceConfig!.InitialBalance); + + log.Log($"Initialized Geth companion node with account '{container.Account}' and initial balance {group.Origin.MarketplaceConfig!.InitialBalance}"); + } + + public void RequestStorage(ContentId contentId, int pricePerBytePerSecond, float requiredCollateral, float minRequiredNumberOfNodes) + { + throw new NotImplementedException(); + } + + public void MakeStorageAvailable(ByteSize size, int minPricePerBytePerSecond, float maxCollateral) + { + throw new NotImplementedException(); + } + + public void AssertThatBalance(IResolveConstraint constraint, string message = "") + { + throw new NotImplementedException(); + } + + public decimal GetBalance() + { + return marketplaceController.GetBalance(container.Account); + } + } + + public class MarketplaceUnavailable : IMarketplaceAccess + { + public void RequestStorage(ContentId contentId, int pricePerBytePerSecond, float requiredCollateral, float minRequiredNumberOfNodes) + { + Unavailable(); + } + + public void MakeStorageAvailable(ByteSize size, int minPricePerBytePerSecond, float maxCollateral) + { + Unavailable(); + } + + public void AssertThatBalance(IResolveConstraint constraint, string message = "") + { + Unavailable(); + } + + public decimal GetBalance() + { + Unavailable(); + return 0; + } + + private void Unavailable() + { + Assert.Fail("Incorrect test setup: Marketplace was not enabled for this group of Codex nodes. Add 'EnableMarketplace(...)' after 'SetupCodexNodes()' to enable it."); + throw new InvalidOperationException(); + } + } +} diff --git a/DistTestCore/Marketplace/MarketplaceAccessFactory.cs b/DistTestCore/Marketplace/MarketplaceAccessFactory.cs new file mode 100644 index 00000000..e3de573d --- /dev/null +++ b/DistTestCore/Marketplace/MarketplaceAccessFactory.cs @@ -0,0 +1,24 @@ +namespace DistTestCore.Marketplace +{ + public interface IMarketplaceAccessFactory + { + IMarketplaceAccess CreateMarketplaceAccess(); + } + + public class MarketplaceUnavailableAccessFactory : IMarketplaceAccessFactory + { + public IMarketplaceAccess CreateMarketplaceAccess() + { + return new MarketplaceUnavailable(); + } + } + + public class GethMarketplaceAccessFactory : IMarketplaceAccessFactory + { + public IMarketplaceAccess CreateMarketplaceAccess() + { + + return new MarketplaceAccess(query, codexContainer); + } + } +} diff --git a/DistTestCore/Marketplace/MarketplaceInitialConfig.cs b/DistTestCore/Marketplace/MarketplaceInitialConfig.cs new file mode 100644 index 00000000..a815842e --- /dev/null +++ b/DistTestCore/Marketplace/MarketplaceInitialConfig.cs @@ -0,0 +1,12 @@ +namespace DistTestCore.Marketplace +{ + public class MarketplaceInitialConfig + { + public MarketplaceInitialConfig(int initialBalance) + { + InitialBalance = initialBalance; + } + + public int InitialBalance { get; } + } +} diff --git a/DistTestCore/OnlineCodexNode.cs b/DistTestCore/OnlineCodexNode.cs index 76ab592c..7075ef36 100644 --- a/DistTestCore/OnlineCodexNode.cs +++ b/DistTestCore/OnlineCodexNode.cs @@ -1,5 +1,6 @@ using DistTestCore.Codex; using DistTestCore.Logs; +using DistTestCore.Marketplace; using DistTestCore.Metrics; using NUnit.Framework; @@ -13,7 +14,7 @@ namespace DistTestCore void ConnectToPeer(IOnlineCodexNode node); ICodexNodeLog DownloadLog(); IMetricsAccess Metrics { get; } - //IMarketplaceAccess Marketplace { get; } + IMarketplaceAccess Marketplace { get; } } public class OnlineCodexNode : IOnlineCodexNode @@ -22,17 +23,19 @@ namespace DistTestCore private const string UploadFailedMessage = "Unable to store block"; private readonly TestLifecycle lifecycle; - public OnlineCodexNode(TestLifecycle lifecycle, CodexAccess codexAccess, CodexNodeGroup group, IMetricsAccess metricsAccess) + public OnlineCodexNode(TestLifecycle lifecycle, CodexAccess codexAccess, CodexNodeGroup group, IMetricsAccess metricsAccess, IMarketplaceAccess marketplaceAccess) { this.lifecycle = lifecycle; CodexAccess = codexAccess; Group = group; Metrics = metricsAccess; + Marketplace = marketplaceAccess; } public CodexAccess CodexAccess { get; } public CodexNodeGroup Group { get; } public IMetricsAccess Metrics { get; } + public IMarketplaceAccess Marketplace { get; } public string GetName() { diff --git a/KubernetesWorkflow/ContainerRecipeFactory.cs b/KubernetesWorkflow/ContainerRecipeFactory.cs index 6c6a3ee4..136b2095 100644 --- a/KubernetesWorkflow/ContainerRecipeFactory.cs +++ b/KubernetesWorkflow/ContainerRecipeFactory.cs @@ -7,10 +7,11 @@ private readonly List envVars = new List(); private RecipeComponentFactory factory = null!; - public ContainerRecipe CreateRecipe(int containerNumber, RecipeComponentFactory factory, StartupConfig config) + public ContainerRecipe CreateRecipe(int index, int containerNumber, RecipeComponentFactory factory, StartupConfig config) { this.factory = factory; ContainerNumber = containerNumber; + Index = index; Initialize(config); @@ -26,6 +27,7 @@ protected abstract string Image { get; } protected int ContainerNumber { get; private set; } = 0; + protected int Index { get; private set; } = 0; protected abstract void Initialize(StartupConfig config); protected Port AddExposedPort(string tag = "") diff --git a/KubernetesWorkflow/StartupWorkflow.cs b/KubernetesWorkflow/StartupWorkflow.cs index e78a5b2a..f575b15a 100644 --- a/KubernetesWorkflow/StartupWorkflow.cs +++ b/KubernetesWorkflow/StartupWorkflow.cs @@ -68,7 +68,7 @@ var result = new List(); for (var i = 0; i < numberOfContainers; i++) { - result.Add(recipeFactory.CreateRecipe(numberSource.GetContainerNumber(), componentFactory, startupConfig)); + result.Add(recipeFactory.CreateRecipe(i ,numberSource.GetContainerNumber(), componentFactory, startupConfig)); } return result.ToArray(); diff --git a/Nethereum/NethereumWorkflow.cs b/Nethereum/NethereumWorkflow.cs new file mode 100644 index 00000000..795ef27b --- /dev/null +++ b/Nethereum/NethereumWorkflow.cs @@ -0,0 +1,41 @@ +using Nethereum.Hex.HexTypes; +using Nethereum.Web3; +using System.Numerics; +using Utils; + +namespace NethereumWorkflow +{ + public class NethereumWorkflow + { + private readonly Web3 web3; + private readonly string rootAccount; + + internal NethereumWorkflow(Web3 web3, string rootAccount) + { + this.web3 = web3; + this.rootAccount = rootAccount; + } + + public void AddToBalance(string account, decimal amount) + { + if (amount < 1 || string.IsNullOrEmpty(account)) throw new ArgumentException("Invalid arguments for AddToBalance"); + + var value = ToHexBig(amount); + var transactionId = Time.Wait(web3.Eth.TransactionManager.SendTransactionAsync(rootAccount, account, value)); + Time.Wait(web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(transactionId)); + } + + public decimal GetBalance(string account) + { + var bigInt = Time.Wait(web3.Eth.GetBalance.SendRequestAsync(account)); + return (decimal)bigInt.Value; + } + + private HexBigInteger ToHexBig(decimal amount) + { + var bigint = new BigInteger(amount); + var str = bigint.ToString("X"); + return new HexBigInteger(str); + } + } +} diff --git a/Nethereum/NethereumWorkflow.csproj b/Nethereum/NethereumWorkflow.csproj new file mode 100644 index 00000000..99771c5a --- /dev/null +++ b/Nethereum/NethereumWorkflow.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + NethereumWorkflow + enable + enable + + + + + + + + + + + + diff --git a/Nethereum/NethereumWorkflowCreator.cs b/Nethereum/NethereumWorkflowCreator.cs new file mode 100644 index 00000000..33ebf922 --- /dev/null +++ b/Nethereum/NethereumWorkflowCreator.cs @@ -0,0 +1,29 @@ +using Nethereum.Web3; + +namespace NethereumWorkflow +{ + public class NethereumWorkflowCreator + { + private readonly string ip; + private readonly int port; + private readonly string rootAccount; + + public NethereumWorkflowCreator(string ip, int port, string rootAccount) + { + this.ip = ip; + this.port = port; + this.rootAccount = rootAccount; + } + + public NethereumWorkflow CreateWorkflow() + { + return new NethereumWorkflow(CreateWeb3(), rootAccount); + } + + private Web3 CreateWeb3() + { + //var bootstrapaccount = new ManagedAccount(bootstrapInfo.Account, "qwerty!@#$%^"); + return new Web3($"http://{ip}:{port}"); + } + } +} diff --git a/cs-codex-dist-testing.sln b/cs-codex-dist-testing.sln index de9f58fd..b47da0c2 100644 --- a/cs-codex-dist-testing.sln +++ b/cs-codex-dist-testing.sln @@ -9,13 +9,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestsLong", "LongTests\Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodexDistTestCore", "CodexDistTestCore\CodexDistTestCore.csproj", "{19306DE1-CEE5-4F7B-AA5D-FD91926D853D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistTestCore", "DistTestCore\DistTestCore.csproj", "{47F31305-6E68-4827-8E39-7B41DAA1CE7A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DistTestCore", "DistTestCore\DistTestCore.csproj", "{47F31305-6E68-4827-8E39-7B41DAA1CE7A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesWorkflow", "KubernetesWorkflow\KubernetesWorkflow.csproj", "{359123AA-3D9B-4442-80F4-19E32E3EC9EA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesWorkflow", "KubernetesWorkflow\KubernetesWorkflow.csproj", "{359123AA-3D9B-4442-80F4-19E32E3EC9EA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils.csproj", "{957DE3B8-9571-450A-8609-B267DCA8727C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils.csproj", "{957DE3B8-9571-450A-8609-B267DCA8727C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging", "Logging\Logging.csproj", "{8481A4A6-4BDD-41B0-A3EB-EF53F7BD40D1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging", "Logging\Logging.csproj", "{8481A4A6-4BDD-41B0-A3EB-EF53F7BD40D1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethereum", "Nethereum\Nethereum.csproj", "{D6C3555E-D52D-4993-A87B-71AB650398FD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -51,6 +53,10 @@ Global {8481A4A6-4BDD-41B0-A3EB-EF53F7BD40D1}.Debug|Any CPU.Build.0 = Debug|Any CPU {8481A4A6-4BDD-41B0-A3EB-EF53F7BD40D1}.Release|Any CPU.ActiveCfg = Release|Any CPU {8481A4A6-4BDD-41B0-A3EB-EF53F7BD40D1}.Release|Any CPU.Build.0 = Release|Any CPU + {D6C3555E-D52D-4993-A87B-71AB650398FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6C3555E-D52D-4993-A87B-71AB650398FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6C3555E-D52D-4993-A87B-71AB650398FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6C3555E-D52D-4993-A87B-71AB650398FD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE