Setting up multiple-contracts test
This commit is contained in:
parent
92d504ef9c
commit
dfa2322127
@ -1,7 +1,6 @@
|
||||
using CodexContractsPlugin;
|
||||
using CodexPlugin;
|
||||
using GethPlugin;
|
||||
using Nethereum.Hex.HexConvertors.Extensions;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
@ -11,12 +10,12 @@ namespace CodexReleaseTests.MarketTests
|
||||
public class ContractSuccessfulTest : MarketplaceAutoBootstrapDistTest
|
||||
{
|
||||
private const int FilesizeMb = 10;
|
||||
private const int PricePerSlotPerSecondTSTWei = 10;
|
||||
|
||||
protected override int NumberOfHosts => 4;
|
||||
protected override int NumberOfClients => 1;
|
||||
protected override ByteSize HostAvailabilitySize => (5 * FilesizeMb).MB();
|
||||
protected override TimeSpan HostAvailabilityMaxDuration => Get8TimesConfiguredPeriodDuration();
|
||||
private readonly TestToken pricePerSlotPerSecond = 10.TstWei();
|
||||
|
||||
[Test]
|
||||
public void ContractSuccessful()
|
||||
@ -34,89 +33,11 @@ namespace CodexReleaseTests.MarketTests
|
||||
|
||||
request.WaitForStorageContractFinished(GetContracts());
|
||||
|
||||
AssertClientHasPaidForContract(client, request, hosts);
|
||||
AssertHostsWerePaidForContract(request, hosts);
|
||||
AssertClientHasPaidForContract(pricePerSlotPerSecond, client, request, hosts);
|
||||
AssertHostsWerePaidForContract(pricePerSlotPerSecond, request, hosts);
|
||||
AssertHostsCollateralsAreUnchanged(hosts);
|
||||
}
|
||||
|
||||
private void AssertContractIsOnChain(IStoragePurchaseContract contract)
|
||||
{
|
||||
AssertOnChainEvents(events =>
|
||||
{
|
||||
var onChainRequests = events.GetStorageRequests();
|
||||
if (onChainRequests.Any(r => r.Id == contract.PurchaseId)) return;
|
||||
throw new Exception($"OnChain request {contract.PurchaseId} not found...");
|
||||
}, nameof(AssertContractIsOnChain));
|
||||
}
|
||||
|
||||
private void AssertContractSlotsAreFilledByHosts(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var activeHosts = new Dictionary<int, SlotFill>();
|
||||
|
||||
Time.Retry(() =>
|
||||
{
|
||||
var fills = GetOnChainSlotFills(hosts, contract.PurchaseId);
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
var index = (int)fill.SlotFilledEvent.SlotIndex;
|
||||
if (!activeHosts.ContainsKey(index))
|
||||
{
|
||||
activeHosts.Add(index, fill);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeHosts.Count != contract.Purchase.MinRequiredNumberOfNodes) throw new Exception("Not all slots were filled...");
|
||||
|
||||
}, nameof(AssertContractSlotsAreFilledByHosts));
|
||||
}
|
||||
|
||||
private void AssertClientHasPaidForContract(ICodexNode client, IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var balance = GetTstBalance(client);
|
||||
var expectedBalance = StartingBalanceTST.Tst() - GetContractFinalCost(contract, hosts);
|
||||
|
||||
Assert.That(balance, Is.EqualTo(expectedBalance), "Client balance incorrect.");
|
||||
}
|
||||
|
||||
private void AssertHostsWerePaidForContract(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var fills = GetOnChainSlotFills(hosts);
|
||||
var submitUtc = GetContractOnChainSubmittedUtc(contract);
|
||||
var finishUtc = submitUtc + contract.Purchase.Duration;
|
||||
var expectedBalances = new Dictionary<EthAddress, TestToken>();
|
||||
foreach (var host in hosts) expectedBalances.Add(host.EthAddress, StartingBalanceTST.Tst());
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
var slotDuration = finishUtc - fill.SlotFilledEvent.Block.Utc;
|
||||
expectedBalances[fill.Host.EthAddress] += GetContractCostPerSlot(slotDuration);
|
||||
}
|
||||
|
||||
foreach (var pair in expectedBalances)
|
||||
{
|
||||
var balance = GetTstBalance(pair.Key);
|
||||
Assert.That(balance, Is.EqualTo(pair.Value), "Host was not paid for storage.");
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertHostsCollateralsAreUnchanged(ICodexNodeGroup hosts)
|
||||
{
|
||||
// There is no separate collateral location yet.
|
||||
// All host balances should be equal to or greater than the starting balance.
|
||||
foreach (var host in hosts)
|
||||
{
|
||||
Assert.That(GetTstBalance(host), Is.GreaterThanOrEqualTo(StartingBalanceTST.Tst()));
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertOnChainEvents(Action<ICodexContractsEvents> onEvents, string description)
|
||||
{
|
||||
Time.Retry(() =>
|
||||
{
|
||||
var events = GetContracts().GetEvents(GetTestRunTimeRange());
|
||||
onEvents(events);
|
||||
}, description);
|
||||
}
|
||||
|
||||
private IStoragePurchaseContract CreateStorageRequest(ICodexNode client)
|
||||
{
|
||||
var cid = client.UploadFile(GenerateTestFile(FilesizeMb.MB()));
|
||||
@ -127,40 +48,12 @@ namespace CodexReleaseTests.MarketTests
|
||||
Expiry = GetContractExpiry(),
|
||||
MinRequiredNumberOfNodes = (uint)NumberOfHosts,
|
||||
NodeFailureTolerance = (uint)(NumberOfHosts / 2),
|
||||
PricePerSlotPerSecond = PricePerSlotPerSecondTSTWei.TstWei(),
|
||||
PricePerSlotPerSecond = pricePerSlotPerSecond,
|
||||
ProofProbability = 20,
|
||||
RequiredCollateral = 1.Tst()
|
||||
});
|
||||
}
|
||||
|
||||
private TestToken GetContractFinalCost(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var fills = GetOnChainSlotFills(hosts);
|
||||
var result = 0.Tst();
|
||||
var submitUtc = GetContractOnChainSubmittedUtc(contract);
|
||||
var finishUtc = submitUtc + contract.Purchase.Duration;
|
||||
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
var slotDuration = finishUtc - fill.SlotFilledEvent.Block.Utc;
|
||||
result += GetContractCostPerSlot(slotDuration);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private DateTime GetContractOnChainSubmittedUtc(IStoragePurchaseContract contract)
|
||||
{
|
||||
var events = GetContracts().GetEvents(GetTestRunTimeRange());
|
||||
var submitEvent = events.GetStorageRequests().Single(e => e.RequestId.ToHex(false) == contract.PurchaseId);
|
||||
return submitEvent.Block.Utc;
|
||||
}
|
||||
|
||||
private TestToken GetContractCostPerSlot(TimeSpan slotDuration)
|
||||
{
|
||||
return PricePerSlotPerSecondTSTWei.TstWei() * (int)slotDuration.TotalSeconds;
|
||||
}
|
||||
|
||||
private TimeSpan GetContractExpiry()
|
||||
{
|
||||
return GetContractDuration() / 2;
|
||||
|
@ -121,6 +121,112 @@ namespace CodexReleaseTests.MarketTests
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
protected void AssertClientHasPaidForContract(TestToken pricePerSlotPerSecond, ICodexNode client, IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var balance = GetTstBalance(client);
|
||||
var expectedBalance = StartingBalanceTST.Tst() - GetContractFinalCost(pricePerSlotPerSecond, contract, hosts);
|
||||
|
||||
Assert.That(balance, Is.EqualTo(expectedBalance), "Client balance incorrect.");
|
||||
}
|
||||
|
||||
protected void AssertHostsWerePaidForContract(TestToken pricePerSlotPerSecond, IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var fills = GetOnChainSlotFills(hosts);
|
||||
var submitUtc = GetContractOnChainSubmittedUtc(contract);
|
||||
var finishUtc = submitUtc + contract.Purchase.Duration;
|
||||
var expectedBalances = new Dictionary<EthAddress, TestToken>();
|
||||
foreach (var host in hosts) expectedBalances.Add(host.EthAddress, StartingBalanceTST.Tst());
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
var slotDuration = finishUtc - fill.SlotFilledEvent.Block.Utc;
|
||||
expectedBalances[fill.Host.EthAddress] += GetContractCostPerSlot(pricePerSlotPerSecond, slotDuration);
|
||||
}
|
||||
|
||||
foreach (var pair in expectedBalances)
|
||||
{
|
||||
var balance = GetTstBalance(pair.Key);
|
||||
Assert.That(balance, Is.EqualTo(pair.Value), "Host was not paid for storage.");
|
||||
}
|
||||
}
|
||||
|
||||
protected void AssertHostsCollateralsAreUnchanged(ICodexNodeGroup hosts)
|
||||
{
|
||||
// There is no separate collateral location yet.
|
||||
// All host balances should be equal to or greater than the starting balance.
|
||||
foreach (var host in hosts)
|
||||
{
|
||||
Assert.That(GetTstBalance(host), Is.GreaterThanOrEqualTo(StartingBalanceTST.Tst()));
|
||||
}
|
||||
}
|
||||
|
||||
private TestToken GetContractFinalCost(TestToken pricePerSlotPerSecond, IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var fills = GetOnChainSlotFills(hosts);
|
||||
var result = 0.Tst();
|
||||
var submitUtc = GetContractOnChainSubmittedUtc(contract);
|
||||
var finishUtc = submitUtc + contract.Purchase.Duration;
|
||||
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
var slotDuration = finishUtc - fill.SlotFilledEvent.Block.Utc;
|
||||
result += GetContractCostPerSlot(pricePerSlotPerSecond, slotDuration);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private DateTime GetContractOnChainSubmittedUtc(IStoragePurchaseContract contract)
|
||||
{
|
||||
var events = GetContracts().GetEvents(GetTestRunTimeRange());
|
||||
var submitEvent = events.GetStorageRequests().Single(e => e.RequestId.ToHex(false) == contract.PurchaseId);
|
||||
return submitEvent.Block.Utc;
|
||||
}
|
||||
|
||||
private TestToken GetContractCostPerSlot(TestToken pricePerSlotPerSecond, TimeSpan slotDuration)
|
||||
{
|
||||
return pricePerSlotPerSecond * (int)slotDuration.TotalSeconds;
|
||||
}
|
||||
|
||||
protected void AssertContractSlotsAreFilledByHosts(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
|
||||
{
|
||||
var activeHosts = new Dictionary<int, SlotFill>();
|
||||
|
||||
Time.Retry(() =>
|
||||
{
|
||||
var fills = GetOnChainSlotFills(hosts, contract.PurchaseId);
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
var index = (int)fill.SlotFilledEvent.SlotIndex;
|
||||
if (!activeHosts.ContainsKey(index))
|
||||
{
|
||||
activeHosts.Add(index, fill);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeHosts.Count != contract.Purchase.MinRequiredNumberOfNodes) throw new Exception("Not all slots were filled...");
|
||||
|
||||
}, nameof(AssertContractSlotsAreFilledByHosts));
|
||||
}
|
||||
|
||||
protected void AssertContractIsOnChain(IStoragePurchaseContract contract)
|
||||
{
|
||||
AssertOnChainEvents(events =>
|
||||
{
|
||||
var onChainRequests = events.GetStorageRequests();
|
||||
if (onChainRequests.Any(r => r.Id == contract.PurchaseId)) return;
|
||||
throw new Exception($"OnChain request {contract.PurchaseId} not found...");
|
||||
}, nameof(AssertContractIsOnChain));
|
||||
}
|
||||
|
||||
protected void AssertOnChainEvents(Action<ICodexContractsEvents> onEvents, string description)
|
||||
{
|
||||
Time.Retry(() =>
|
||||
{
|
||||
var events = GetContracts().GetEvents(GetTestRunTimeRange());
|
||||
onEvents(events);
|
||||
}, description);
|
||||
}
|
||||
|
||||
public class SlotFill
|
||||
{
|
||||
public SlotFill(SlotFilledEventDTO slotFilledEvent, ICodexNode host)
|
||||
|
@ -1,12 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CodexContractsPlugin;
|
||||
using CodexPlugin;
|
||||
using GethPlugin;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
namespace CodexReleaseTests.MarketTests
|
||||
{
|
||||
internal class MultipleContractsTest
|
||||
[TestFixture]
|
||||
public class MultipleContractsTest : MarketplaceAutoBootstrapDistTest
|
||||
{
|
||||
private const int FilesizeMb = 10;
|
||||
|
||||
protected override int NumberOfHosts => 8;
|
||||
protected override int NumberOfClients => 3;
|
||||
protected override ByteSize HostAvailabilitySize => (5 * FilesizeMb).MB();
|
||||
protected override TimeSpan HostAvailabilityMaxDuration => Get8TimesConfiguredPeriodDuration();
|
||||
private readonly TestToken pricePerSlotPerSecond = 10.TstWei();
|
||||
|
||||
[Test]
|
||||
public void MultipleSuccessfulContracts()
|
||||
{
|
||||
var hosts = StartHosts();
|
||||
var clients = StartClients();
|
||||
|
||||
var requests = clients.Select(c => CreateStorageRequest(c)).ToArray();
|
||||
|
||||
All(requests, r =>
|
||||
{
|
||||
r.WaitForStorageContractSubmitted();
|
||||
AssertContractIsOnChain(r);
|
||||
});
|
||||
|
||||
All(requests, r => r.WaitForStorageContractStarted());
|
||||
All(requests, r => AssertContractSlotsAreFilledByHosts(r, hosts));
|
||||
|
||||
All(requests, r => r.WaitForStorageContractFinished(GetContracts()));
|
||||
|
||||
// todo:
|
||||
//AssertClientHasPaidForContract(pricePerSlotPerSecond, client, request, hosts);
|
||||
//AssertHostsWerePaidForContract(pricePerSlotPerSecond, request, hosts);
|
||||
//AssertHostsCollateralsAreUnchanged(hosts);
|
||||
}
|
||||
|
||||
private void All(IStoragePurchaseContract[] requests, Action<IStoragePurchaseContract> action)
|
||||
{
|
||||
foreach (var r in requests) action(r);
|
||||
}
|
||||
|
||||
private IStoragePurchaseContract CreateStorageRequest(ICodexNode client)
|
||||
{
|
||||
var cid = client.UploadFile(GenerateTestFile(FilesizeMb.MB()));
|
||||
var config = GetContracts().Deployment.Config;
|
||||
return client.Marketplace.RequestStorage(new StoragePurchaseRequest(cid)
|
||||
{
|
||||
Duration = GetContractDuration(),
|
||||
Expiry = GetContractExpiry(),
|
||||
MinRequiredNumberOfNodes = (uint)NumberOfHosts,
|
||||
NodeFailureTolerance = (uint)(NumberOfHosts / 2),
|
||||
PricePerSlotPerSecond = pricePerSlotPerSecond,
|
||||
ProofProbability = 20,
|
||||
RequiredCollateral = 1.Tst()
|
||||
});
|
||||
}
|
||||
|
||||
private TimeSpan GetContractExpiry()
|
||||
{
|
||||
return GetContractDuration() / 2;
|
||||
}
|
||||
|
||||
private TimeSpan GetContractDuration()
|
||||
{
|
||||
return Get8TimesConfiguredPeriodDuration() / 2;
|
||||
}
|
||||
|
||||
private TimeSpan Get8TimesConfiguredPeriodDuration()
|
||||
{
|
||||
var config = GetContracts().Deployment.Config;
|
||||
return TimeSpan.FromSeconds(((double)config.Proofs.Period) * 8.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user