wip
This commit is contained in:
parent
fd3567347b
commit
e7a59de207
@ -46,6 +46,16 @@ namespace CodexContractsPlugin
|
||||
return new TestToken(a.TstWei + b.TstWei);
|
||||
}
|
||||
|
||||
public static TestToken operator -(TestToken a, TestToken b)
|
||||
{
|
||||
return new TestToken(a.TstWei - b.TstWei);
|
||||
}
|
||||
|
||||
public static TestToken operator *(TestToken a, int b)
|
||||
{
|
||||
return new TestToken(a.TstWei * b);
|
||||
}
|
||||
|
||||
public static bool operator <(TestToken a, TestToken b)
|
||||
{
|
||||
return a.TstWei < b.TstWei;
|
||||
|
@ -1,11 +1,7 @@
|
||||
using CodexContractsPlugin;
|
||||
using CodexPlugin;
|
||||
using GethPlugin;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Utils;
|
||||
|
||||
namespace CodexReleaseTests.MarketTests
|
||||
@ -15,14 +11,135 @@ namespace CodexReleaseTests.MarketTests
|
||||
{
|
||||
private const int NumberOfHosts = 4;
|
||||
private const int FilesizeMb = 10;
|
||||
private const int PricePerSlotPerSecondTSTWei = 10;
|
||||
|
||||
[Test]
|
||||
public void ContractSuccessful()
|
||||
{
|
||||
var hosts = StartHosts();
|
||||
|
||||
var client = StartCodex(s => s.WithName("client"));
|
||||
|
||||
var contract = CreateStorageRequest(client);
|
||||
|
||||
contract.WaitForStorageContractSubmitted();
|
||||
AssertContractIsOnChain(contract);
|
||||
|
||||
contract.WaitForStorageContractStarted();
|
||||
var slotFills = AssertContractSlotsAreFilledByHosts(contract, hosts);
|
||||
|
||||
contract.WaitForStorageContractFinished();
|
||||
AssertClientHasPaidForContract(client, contract);
|
||||
AssertHostsWerePaidForContract(contract, hosts, slotFills);
|
||||
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 SlotFill[] 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));
|
||||
|
||||
return activeHosts.Values.ToArray();
|
||||
}
|
||||
|
||||
private void AssertClientHasPaidForContract(ICodexNode client, IStoragePurchaseContract contract)
|
||||
{
|
||||
var balance = GetContracts().GetTestTokenBalance(client);
|
||||
var expectedBalance = StartingBalanceTST.Tst() - GetContractTotalCost();
|
||||
|
||||
Assert.That(balance, Is.EqualTo(expectedBalance));
|
||||
}
|
||||
|
||||
private TestToken GetContractTotalCost()
|
||||
{
|
||||
return GetContractCostPerSlot() * NumberOfHosts;
|
||||
}
|
||||
|
||||
private TestToken GetContractCostPerSlot()
|
||||
{
|
||||
var duration = GetContractDuration();
|
||||
return PricePerSlotPerSecondTSTWei.TstWei() * ((int)duration.TotalSeconds);
|
||||
}
|
||||
|
||||
private void AssertHostsWerePaidForContract(IStoragePurchaseContract contract, ICodexNodeGroup hosts, SlotFill[] fills)
|
||||
{
|
||||
var expectedBalances = new Dictionary<EthAddress, TestToken>();
|
||||
foreach (var host in hosts) expectedBalances.Add(host.EthAddress, StartingBalanceTST.Tst());
|
||||
foreach (var fill in fills)
|
||||
{
|
||||
expectedBalances[fill.Host.EthAddress] += GetContractCostPerSlot();
|
||||
}
|
||||
|
||||
foreach (var pair in expectedBalances)
|
||||
{
|
||||
var balance = GetContracts().GetTestTokenBalance(pair.Key);
|
||||
Assert.That(balance, Is.EqualTo(pair.Value));
|
||||
}
|
||||
}
|
||||
|
||||
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(GetContracts().GetTestTokenBalance(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()));
|
||||
var config = GetContracts().Deployment.Config;
|
||||
return client.Marketplace.RequestStorage(new StoragePurchaseRequest(cid)
|
||||
{
|
||||
Duration = GetContractDuration(),
|
||||
Expiry = TimeSpan.FromSeconds(((double)config.Proofs.Period) * 1.0),
|
||||
MinRequiredNumberOfNodes = NumberOfHosts,
|
||||
NodeFailureTolerance = NumberOfHosts / 2,
|
||||
PricePerSlotPerSecond = PricePerSlotPerSecondTSTWei.TstWei(),
|
||||
ProofProbability = 20,
|
||||
RequiredCollateral = 1.Tst()
|
||||
});
|
||||
}
|
||||
|
||||
private TimeSpan GetContractDuration()
|
||||
{
|
||||
var config = GetContracts().Deployment.Config;
|
||||
return TimeSpan.FromSeconds(((double)config.Proofs.Period) * 2.0);
|
||||
}
|
||||
|
||||
private ICodexNodeGroup StartHosts()
|
||||
|
@ -1,8 +1,10 @@
|
||||
using CodexContractsPlugin;
|
||||
using CodexContractsPlugin.Marketplace;
|
||||
using CodexPlugin;
|
||||
using CodexTests;
|
||||
using DistTestCore;
|
||||
using GethPlugin;
|
||||
using Nethereum.Hex.HexConvertors.Extensions;
|
||||
|
||||
namespace CodexReleaseTests.MarketTests
|
||||
{
|
||||
@ -41,6 +43,37 @@ namespace CodexReleaseTests.MarketTests
|
||||
return handles[Get()].Contracts;
|
||||
}
|
||||
|
||||
public SlotFill[] GetOnChainSlotFills(ICodexNodeGroup possibleHosts, string purchaseId)
|
||||
{
|
||||
return GetOnChainSlotFills(possibleHosts)
|
||||
.Where(f => f.SlotFilledEvent.RequestId.ToHex(true) == purchaseId)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public SlotFill[] GetOnChainSlotFills(ICodexNodeGroup possibleHosts)
|
||||
{
|
||||
var events = GetContracts().GetEvents(GetTestRunTimeRange());
|
||||
var fills = events.GetSlotFilledEvents();
|
||||
return fills.Select(f =>
|
||||
{
|
||||
var host = possibleHosts.Single(h => h.EthAddress == f.Host);
|
||||
return new SlotFill(f, host);
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
public class SlotFill
|
||||
{
|
||||
public SlotFill(SlotFilledEventDTO slotFilledEvent, ICodexNode host)
|
||||
{
|
||||
SlotFilledEvent = slotFilledEvent;
|
||||
Host = host;
|
||||
}
|
||||
|
||||
public SlotFilledEventDTO SlotFilledEvent { get; }
|
||||
public ICodexNode Host { get; }
|
||||
}
|
||||
|
||||
private class MarketplaceHandle
|
||||
{
|
||||
public MarketplaceHandle(IGethNode geth, ICodexContracts contracts)
|
||||
|
Loading…
x
Reference in New Issue
Block a user