Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd9edd3931 | ||
|
|
82ce11e848 | ||
|
|
2155634414 | ||
|
|
0e342adcdf | ||
|
|
255dc127c8 | ||
|
|
83d907152a | ||
|
|
c833a29de5 | ||
|
|
abcb4725cd | ||
|
|
059c15d9de | ||
|
|
a1d9756403 | ||
|
|
8ffa1fde4a |
@@ -5,8 +5,7 @@ namespace DistTestCore.Codex
|
||||
{
|
||||
public class CodexContainerRecipe : ContainerRecipeFactory
|
||||
{
|
||||
private const string DefaultDockerImage = "codexstorage/nim-codex:sha-7efa917";
|
||||
|
||||
public const string DefaultDockerImage = "codexstorage/nim-codex:sha-5141d85";
|
||||
public const string MetricsPortTag = "metrics_port";
|
||||
public const string DiscoveryPortTag = "discovery-port";
|
||||
|
||||
@@ -31,7 +30,7 @@ namespace DistTestCore.Codex
|
||||
|
||||
AddEnvVar("CODEX_DATA_DIR", $"datadir{ContainerNumber}");
|
||||
AddInternalPortAndVar("CODEX_DISC_PORT", DiscoveryPortTag);
|
||||
AddEnvVar("CODEX_LOG_LEVEL", config.LogLevel.ToString()!.ToUpperInvariant());
|
||||
AddEnvVar("CODEX_LOG_LEVEL", config.LogLevelWithTopics());
|
||||
|
||||
// This makes the node announce itself to its local (pod) IP address.
|
||||
AddEnvVar("NAT_IP_AUTO", "true");
|
||||
@@ -58,6 +57,14 @@ namespace DistTestCore.Codex
|
||||
AddInternalPortAndVar("CODEX_METRICS_PORT", tag: MetricsPortTag);
|
||||
}
|
||||
|
||||
if (config.SimulateProofFailures != null)
|
||||
{
|
||||
AddEnvVar("CODEX_SIMULATE_PROOF_FAILURES", config.SimulateProofFailures.ToString()!);
|
||||
}
|
||||
// if (config.EnableValidator == true)
|
||||
// {
|
||||
// AddEnvVar("CODEX_VALIDATOR", "true");
|
||||
// }
|
||||
if (config.MarketplaceConfig != null)
|
||||
{
|
||||
var gethConfig = startupConfig.Get<GethStartResult>();
|
||||
@@ -75,8 +82,15 @@ namespace DistTestCore.Codex
|
||||
|
||||
if (config.MarketplaceConfig.IsValidator)
|
||||
{
|
||||
AddEnvVar("CODEX_VALIDATOR", "true");
|
||||
AddEnvVar("CODEX_VALIDATOR", "true");
|
||||
}
|
||||
}
|
||||
// if (config.MarketplaceConfig != null) {
|
||||
// AddEnvVar("CODEX_PERSISTENCE", "true");
|
||||
// }
|
||||
|
||||
if(!string.IsNullOrEmpty(config.NameOverride)) {
|
||||
AddEnvVar("CODEX_NODENAME", config.NameOverride);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,26 @@ namespace DistTestCore.Codex
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
|
||||
public string LogLevelWithTopics()
|
||||
{
|
||||
var level = LogLevel.ToString()!.ToUpperInvariant();
|
||||
if (LogTopics != null && LogTopics.Count() > 0)
|
||||
{
|
||||
level = $"INFO;{level}: {string.Join(",", LogTopics.Where(s => !string.IsNullOrEmpty(s)))}";
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
public string? NameOverride { get; set; }
|
||||
public Location Location { get; set; }
|
||||
public CodexLogLevel LogLevel { get; }
|
||||
public CodexLogLevel LogLevel { get; set; }
|
||||
public string[]? LogTopics { get; set; }
|
||||
public ByteSize? StorageQuota { get; set; }
|
||||
public bool MetricsEnabled { get; set; }
|
||||
public MarketplaceInitialConfig? MarketplaceConfig { get; set; }
|
||||
public string? BootstrapSpr { get; set; }
|
||||
public int? BlockTTL { get; set; }
|
||||
public uint? SimulateProofFailures { get; set; }
|
||||
public bool? EnableValidator { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ namespace DistTestCore
|
||||
{
|
||||
ICodexSetup WithName(string name);
|
||||
ICodexSetup At(Location location);
|
||||
ICodexSetup WithLogLevel(CodexLogLevel level);
|
||||
/// <summary>
|
||||
/// Sets the log level for codex. The default level is INFO and the
|
||||
/// log level is applied only to the supplied topics.
|
||||
/// </summary>
|
||||
ICodexSetup WithLogLevel(CodexLogLevel level, params string[] topics);
|
||||
ICodexSetup WithBootstrapNode(IOnlineCodexNode node);
|
||||
ICodexSetup WithStorageQuota(ByteSize storageQuota);
|
||||
ICodexSetup WithBlockTTL(TimeSpan duration);
|
||||
@@ -15,8 +21,16 @@ namespace DistTestCore
|
||||
ICodexSetup EnableMarketplace(TestToken initialBalance);
|
||||
ICodexSetup EnableMarketplace(TestToken initialBalance, Ether initialEther);
|
||||
ICodexSetup EnableMarketplace(TestToken initialBalance, Ether initialEther, bool isValidator);
|
||||
/// <summary>
|
||||
/// Provides an invalid proof every N proofs
|
||||
/// </summary>
|
||||
ICodexSetup WithSimulateProofFailures(uint failEveryNProofs);
|
||||
/// <summary>
|
||||
/// Enables the validation module in the node
|
||||
/// </summary>
|
||||
// ICodexSetup WithValidator();
|
||||
}
|
||||
|
||||
|
||||
public class CodexSetup : CodexStartupConfig, ICodexSetup
|
||||
{
|
||||
public int NumberOfNodes { get; }
|
||||
@@ -45,6 +59,19 @@ namespace DistTestCore
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICodexSetup WithLogLevel(CodexLogLevel level)
|
||||
{
|
||||
LogLevel = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICodexSetup WithLogLevel(CodexLogLevel level, params string[] topics)
|
||||
{
|
||||
LogLevel = level;
|
||||
LogTopics = topics;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICodexSetup WithStorageQuota(ByteSize storageQuota)
|
||||
{
|
||||
StorageQuota = storageQuota;
|
||||
@@ -70,7 +97,7 @@ namespace DistTestCore
|
||||
|
||||
public ICodexSetup EnableMarketplace(TestToken initialBalance, Ether initialEther)
|
||||
{
|
||||
return EnableMarketplace(initialBalance, initialEther, false);
|
||||
return EnableMarketplace(initialBalance, initialEther, false);
|
||||
}
|
||||
|
||||
public ICodexSetup EnableMarketplace(TestToken initialBalance, Ether initialEther, bool isValidator)
|
||||
@@ -79,6 +106,18 @@ namespace DistTestCore
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICodexSetup WithSimulateProofFailures(uint failEveryNProofs)
|
||||
{
|
||||
SimulateProofFailures = failEveryNProofs;
|
||||
return this;
|
||||
}
|
||||
|
||||
// public ICodexSetup WithValidator()
|
||||
// {
|
||||
// EnableValidator = true;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public string Describe()
|
||||
{
|
||||
var args = string.Join(',', DescribeArgs());
|
||||
@@ -87,9 +126,11 @@ namespace DistTestCore
|
||||
|
||||
private IEnumerable<string> DescribeArgs()
|
||||
{
|
||||
yield return $"LogLevel={LogLevel}";
|
||||
yield return $"LogLevel={LogLevelWithTopics()}";
|
||||
if (BootstrapSpr != null) yield return $"BootstrapNode={BootstrapSpr}";
|
||||
if (StorageQuota != null) yield return $"StorageQuote={StorageQuota}";
|
||||
if (StorageQuota != null) yield return $"StorageQuota={StorageQuota}";
|
||||
if (SimulateProofFailures != null) yield return $"SimulateProofFailures={SimulateProofFailures}";
|
||||
if (MarketplaceConfig != null) yield return $"IsValidator={MarketplaceConfig.IsValidator}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace DistTestCore
|
||||
LogSeparator();
|
||||
LogStart($"Starting {codexSetup.Describe()}...");
|
||||
var gethStartResult = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup);
|
||||
gethStartResult = lifecycle.GethStarter.BringOnlineValidatorFor(codexSetup, gethStartResult);
|
||||
|
||||
var startupConfig = CreateStartupConfig(gethStartResult, codexSetup);
|
||||
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
<RootNamespace>DistTestCore</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsArm64 Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'Arm64'">true</IsArm64>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(IsArm64)'=='true'">
|
||||
<DefineConstants>Arm64</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -30,6 +30,17 @@ namespace DistTestCore
|
||||
return CreateGethStartResult(marketplaceNetwork, companionNode);
|
||||
}
|
||||
|
||||
public GethStartResult BringOnlineValidatorFor(CodexSetup codexSetup, GethStartResult previousResult)
|
||||
{
|
||||
// allow marketplace and validator to be enabled on the same Codex node
|
||||
if (previousResult.CompanionNode != null || (codexSetup.EnableValidator ?? false) == false) return previousResult;
|
||||
|
||||
var marketplaceNetwork = marketplaceNetworkCache.Get();
|
||||
var companionNode = StartCompanionNode(codexSetup, marketplaceNetwork);
|
||||
|
||||
return CreateGethStartResult(marketplaceNetwork, companionNode);
|
||||
}
|
||||
|
||||
private void TransferInitialBalance(MarketplaceNetwork marketplaceNetwork, MarketplaceInitialConfig marketplaceConfig, GethCompanionNodeInfo companionNode)
|
||||
{
|
||||
if (marketplaceConfig.InitialTestTokens.Amount == 0) return;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace DistTestCore.Marketplace
|
||||
public const string MarketplaceArtifactFilename = "/hardhat/artifacts/contracts/Marketplace.sol/Marketplace.json";
|
||||
|
||||
public override string AppName => "codex-contracts";
|
||||
public override string Image => "codexstorage/dist-tests-codex-contracts-eth:sha-d6fbfdc";
|
||||
public override string Image => "codexstorage/codex-contracts-eth:latest-dist-tests";
|
||||
|
||||
protected override void Initialize(StartupConfig startupConfig)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace DistTestCore.Marketplace
|
||||
public const string AccountsFilename = "accounts.csv";
|
||||
|
||||
public override string AppName => "geth";
|
||||
public override string Image => "codexstorage/dist-tests-geth:sha-b788a2d";
|
||||
public override string Image => "codexstorage/dist-tests-geth:latest";
|
||||
|
||||
protected override void Initialize(StartupConfig startupConfig)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace DistTestCore.Metrics
|
||||
public class PrometheusContainerRecipe : ContainerRecipeFactory
|
||||
{
|
||||
public override string AppName => "prometheus";
|
||||
public override string Image => "codexstorage/dist-tests-prometheus:sha-f97d7fd";
|
||||
public override string Image => "codexstorage/dist-tests-prometheus:latest";
|
||||
|
||||
protected override void Initialize(StartupConfig startupConfig)
|
||||
{
|
||||
|
||||
@@ -58,6 +58,16 @@
|
||||
{
|
||||
return $"{Amount} TestTokens";
|
||||
}
|
||||
|
||||
public static TestToken operator - (TestToken t1, int amount)
|
||||
{
|
||||
return t1 - Convert.ToDecimal(amount);
|
||||
}
|
||||
|
||||
public static TestToken operator - (TestToken t1, decimal amount)
|
||||
{
|
||||
return (t1.Amount - amount).TestTokens();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TokensIntExtensions
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
namespace Tests.BasicTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class MarketplaceTests : DistTest
|
||||
{
|
||||
[Test]
|
||||
public void HostThatMissesProofsIsPaidOutLessThanHostThatDoesNotMissProofs()
|
||||
{
|
||||
var sellerInitialBalance = 234.TestTokens();
|
||||
var buyerInitialBalance = 1000.TestTokens();
|
||||
|
||||
var seller = SetupCodexNode(s => s
|
||||
.WithLogLevel(CodexLogLevel.Trace, "marketplace", "sales", "proving", "reservations")
|
||||
.WithStorageQuota(20.GB())
|
||||
.EnableMarketplace(sellerInitialBalance)
|
||||
.WithName("seller"));
|
||||
|
||||
var sellerWithFailures = SetupCodexNode(s => s
|
||||
.WithLogLevel(CodexLogLevel.Trace, "marketplace", "sales", "proving", "reservations")
|
||||
.WithStorageQuota(20.GB())
|
||||
.WithBootstrapNode(seller)
|
||||
.WithSimulateProofFailures(2)
|
||||
.EnableMarketplace(sellerInitialBalance)
|
||||
.WithName("seller with failures"));
|
||||
|
||||
var buyer = SetupCodexNode(s => s
|
||||
.WithLogLevel(CodexLogLevel.Trace, "marketplace", "purchasing", "node", "restapi")
|
||||
.WithBootstrapNode(seller)
|
||||
.EnableMarketplace(buyerInitialBalance)
|
||||
.WithName("buyer"));
|
||||
|
||||
var validator = SetupCodexNode(s => s
|
||||
.WithLogLevel(CodexLogLevel.Trace, "validator")
|
||||
.WithBootstrapNode(seller)
|
||||
// .WithValidator()
|
||||
.EnableMarketplace(0.TestTokens(), 2.Eth(), true)
|
||||
.WithName("validator"));
|
||||
|
||||
seller.Marketplace.AssertThatBalance(Is.EqualTo(sellerInitialBalance));
|
||||
sellerWithFailures.Marketplace.AssertThatBalance(Is.EqualTo(sellerInitialBalance));
|
||||
buyer.Marketplace.AssertThatBalance(Is.EqualTo(buyerInitialBalance));
|
||||
|
||||
seller.Marketplace.MakeStorageAvailable(
|
||||
size: 10.GB(),
|
||||
minPricePerBytePerSecond: 1.TestTokens(),
|
||||
maxCollateral: 20.TestTokens(),
|
||||
maxDuration: TimeSpan.FromMinutes(3));
|
||||
|
||||
sellerWithFailures.Marketplace.MakeStorageAvailable(
|
||||
size: 10.GB(),
|
||||
minPricePerBytePerSecond: 1.TestTokens(),
|
||||
maxCollateral: 20.TestTokens(),
|
||||
maxDuration: TimeSpan.FromMinutes(3));
|
||||
|
||||
seller.Marketplace.MakeStorageAvailable(
|
||||
size: 10.GB(),
|
||||
minPricePerBytePerSecond: 1.TestTokens(),
|
||||
maxCollateral: 20.TestTokens(),
|
||||
maxDuration: TimeSpan.FromMinutes(3));
|
||||
|
||||
sellerWithFailures.Marketplace.MakeStorageAvailable(
|
||||
size: 10.GB(),
|
||||
minPricePerBytePerSecond: 1.TestTokens(),
|
||||
maxCollateral: 20.TestTokens(),
|
||||
maxDuration: TimeSpan.FromMinutes(3));
|
||||
|
||||
var fileSize = 10.MB();
|
||||
var testFile = GenerateTestFile(fileSize);
|
||||
var contentId = buyer.UploadFile(testFile);
|
||||
|
||||
var purchaseContract = buyer.Marketplace.RequestStorage(
|
||||
contentId,
|
||||
pricePerSlotPerSecond: 2.TestTokens(),
|
||||
requiredCollateral: 10.TestTokens(),
|
||||
minRequiredNumberOfNodes: 2,
|
||||
proofProbability: 2,
|
||||
duration: TimeSpan.FromMinutes(3));
|
||||
|
||||
// Time.Sleep(TimeSpan.FromMinutes(1));
|
||||
|
||||
// seller.Marketplace.AssertThatBalance(Is.LessThan(sellerInitialBalance), "Collateral was not placed.");
|
||||
|
||||
purchaseContract.WaitForStorageContractStarted(fileSize);
|
||||
purchaseContract.WaitForStorageContractFinished();
|
||||
|
||||
var sellerBalance = seller.Marketplace.GetBalance();
|
||||
sellerWithFailures.Marketplace.AssertThatBalance(Is.LessThan(sellerBalance), "Seller that was slashed should have less balance than seller that was not slashed.");
|
||||
|
||||
new List<IOnlineCodexNode>(){seller, sellerWithFailures, buyer, validator}.ForEach(node => node.DownloadLog());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user