contract successful test passed

This commit is contained in:
Ben 2024-11-25 15:45:09 +01:00
parent d032b77abe
commit 4990bb2282
No known key found for this signature in database
GPG Key ID: 0F16E812E736C24B
8 changed files with 100 additions and 59 deletions

View File

@ -25,7 +25,7 @@ namespace CodexContractsPlugin
ICodexContractsEvents GetEvents(BlockInterval blockInterval);
EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex);
RequestState GetRequestState(Request request);
void WithdrawFunds(string purchaseId, EthAddress address);
void WaitUntilNextPeriod();
}
[JsonConverter(typeof(StringEnumConverter))]
@ -116,24 +116,13 @@ namespace CodexContractsPlugin
return gethNode.Call<RequestStateFunction, RequestState>(Deployment.MarketplaceAddress, func);
}
public void WithdrawFunds(string purchaseId, EthAddress address)
public void WaitUntilNextPeriod()
{
try
{
log.Log("withdrawing funds....");
var func = new WithdrawFundsFunction
{
RequestId = purchaseId.HexToByteArray(),
FromAddress = address.Address
};
var response = gethNode.Call<WithdrawFundsFunction, string>(Deployment.MarketplaceAddress, func);
log.Log("got response: " + response);
}
catch (Exception ex)
{
log.Log("Got exception: " + ex);
}
log.Log("Waiting until next proof period...");
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var periodSeconds = (int)Deployment.Config.Proofs.Period;
var secondsLeft = now % periodSeconds;
Thread.Sleep(TimeSpan.FromSeconds(secondsLeft + 1));
}
private ContractInteractions StartInteraction()

View File

@ -20,7 +20,7 @@ namespace CodexPlugin
public void Announce()
{
tools.GetLog().Log($"Loaded with Codex ID: '{codexStarter.GetCodexId()}' - Revision: {codexStarter.GetCodexRevision()}");
Log($"Loaded with Codex ID: '{codexStarter.GetCodexId()}' - Revision: {codexStarter.GetCodexRevision()}");
}
public void AddMetadata(IAddMetadata metadata)
@ -55,6 +55,10 @@ namespace CodexPlugin
{
mconfig.GethNode.SendEth(node, mconfig.MarketplaceSetup.InitialEth);
mconfig.CodexContracts.MintTestTokens(node, mconfig.MarketplaceSetup.InitialTestTokens);
Log($"Send {mconfig.MarketplaceSetup.InitialEth} and " +
$"minted {mconfig.MarketplaceSetup.InitialTestTokens} for " +
$"{node.GetName()} (address: {node.EthAddress})");
}
}
@ -70,5 +74,10 @@ namespace CodexPlugin
setup(codexSetup);
return codexSetup;
}
private void Log(string msg)
{
tools.GetLog().Log(msg);
}
}
}

View File

@ -1,4 +1,6 @@
using CodexPlugin.Hooks;
using CodexContractsPlugin;
using CodexPlugin.Hooks;
using GethPlugin;
using Logging;
using Newtonsoft.Json;
using Utils;
@ -12,7 +14,7 @@ namespace CodexPlugin
ContentId ContentId { get; }
void WaitForStorageContractSubmitted();
void WaitForStorageContractStarted();
void WaitForStorageContractFinished();
void WaitForStorageContractFinished(ICodexContracts contracts);
}
public class StoragePurchaseContract : IStoragePurchaseContract
@ -62,7 +64,7 @@ namespace CodexPlugin
AssertDuration(SubmittedToStarted, timeout, nameof(SubmittedToStarted));
}
public void WaitForStorageContractFinished()
public void WaitForStorageContractFinished(ICodexContracts contracts)
{
if (!contractStartedUtc.HasValue)
{
@ -74,6 +76,12 @@ namespace CodexPlugin
contractFinishedUtc = DateTime.UtcNow;
LogFinishedDuration();
AssertDuration(SubmittedToFinished, timeout, nameof(SubmittedToFinished));
contracts.WaitUntilNextPeriod();
var blocks = 3;
Log($"Waiting {blocks} blocks for nodes to process payouts...");
Thread.Sleep(GethContainerRecipe.BlockInterval * blocks);
}
public StoragePurchase GetPurchaseStatus(string purchaseId)

View File

@ -6,6 +6,7 @@ namespace GethPlugin
public class GethContainerRecipe : ContainerRecipeFactory
{
public static string DockerImage { get; } = "codexstorage/dist-tests-geth:latest";
public static TimeSpan BlockInterval { get; } = TimeSpan.FromSeconds(1.0);
private const string defaultArgs = "--ipcdisable --syncmode full";
public const string HttpPortTag = "http_port";

View File

@ -1,6 +1,7 @@
using CodexContractsPlugin;
using CodexPlugin;
using GethPlugin;
using Nethereum.Hex.HexConvertors.Extensions;
using NUnit.Framework;
using Utils;
@ -15,7 +16,7 @@ namespace CodexReleaseTests.MarketTests
protected override int NumberOfHosts => 4;
protected override int NumberOfClients => 1;
protected override ByteSize HostAvailabilitySize => (5 * FilesizeMb).MB();
protected override TimeSpan HostAvailabilityMaxDuration => GetHostAvailabilityDuration();
protected override TimeSpan HostAvailabilityMaxDuration => Get8TimesConfiguredPeriodDuration();
[Test]
public void ContractSuccessful()
@ -29,26 +30,15 @@ namespace CodexReleaseTests.MarketTests
AssertContractIsOnChain(request);
request.WaitForStorageContractStarted();
var slotFills = AssertContractSlotsAreFilledByHosts(request, hosts);
AssertContractSlotsAreFilledByHosts(request, hosts);
request.WaitForStorageContractFinished();
//EveryoneWithdrawsFunds(hosts, client);
request.WaitForStorageContractFinished(GetContracts());
GetContracts().WithdrawFunds(request.PurchaseId, client.EthAddress);
foreach (var host in hosts)
GetContracts().WithdrawFunds(request.PurchaseId, host.EthAddress);
AssertClientHasPaidForContract(client, request);
AssertHostsWerePaidForContract(request, hosts, slotFills);
AssertClientHasPaidForContract(client, request, hosts);
AssertHostsWerePaidForContract(request, hosts);
AssertHostsCollateralsAreUnchanged(hosts);
}
//private void EveryoneWithdrawsFunds(ICodexNodeGroup hosts, ICodexNode client)
//{
// foreach (var host in hosts) host.Marketplace.WithdrawFunds();
// client.Marketplace.WithdrawFunds();
//}
private void AssertContractIsOnChain(IStoragePurchaseContract contract)
{
AssertOnChainEvents(events =>
@ -59,7 +49,7 @@ namespace CodexReleaseTests.MarketTests
}, nameof(AssertContractIsOnChain));
}
private SlotFill[] AssertContractSlotsAreFilledByHosts(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
private void AssertContractSlotsAreFilledByHosts(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
{
var activeHosts = new Dictionary<int, SlotFill>();
@ -78,30 +68,32 @@ namespace CodexReleaseTests.MarketTests
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)
private void AssertClientHasPaidForContract(ICodexNode client, IStoragePurchaseContract contract, ICodexNodeGroup hosts)
{
var balance = GetContracts().GetTestTokenBalance(client);
var expectedBalance = StartingBalanceTST.Tst() - GetContractTotalCost();
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, SlotFill[] fills)
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)
{
expectedBalances[fill.Host.EthAddress] += GetContractCostPerSlot();
var slotDuration = finishUtc - fill.SlotFilledEvent.Block.Utc;
expectedBalances[fill.Host.EthAddress] += GetContractCostPerSlot(slotDuration);
}
foreach (var pair in expectedBalances)
{
var balance = GetContracts().GetTestTokenBalance(pair.Key);
var balance = GetTstBalance(pair.Key);
Assert.That(balance, Is.EqualTo(pair.Value), "Host was not paid for storage.");
}
}
@ -112,7 +104,7 @@ namespace CodexReleaseTests.MarketTests
// 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()));
Assert.That(GetTstBalance(host), Is.GreaterThanOrEqualTo(StartingBalanceTST.Tst()));
}
}
@ -141,15 +133,32 @@ namespace CodexReleaseTests.MarketTests
});
}
private TestToken GetContractTotalCost()
private TestToken GetContractFinalCost(IStoragePurchaseContract contract, ICodexNodeGroup hosts)
{
return GetContractCostPerSlot() * NumberOfHosts;
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 TestToken GetContractCostPerSlot()
private DateTime GetContractOnChainSubmittedUtc(IStoragePurchaseContract contract)
{
var duration = GetContractDuration();
return PricePerSlotPerSecondTSTWei.TstWei() * ((int)duration.TotalSeconds);
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()
@ -159,10 +168,10 @@ namespace CodexReleaseTests.MarketTests
private TimeSpan GetContractDuration()
{
return GetHostAvailabilityDuration() / 2;
return Get8TimesConfiguredPeriodDuration() / 2;
}
private TimeSpan GetHostAvailabilityDuration()
private TimeSpan Get8TimesConfiguredPeriodDuration()
{
var config = GetContracts().Deployment.Config;
return TimeSpan.FromSeconds(((double)config.Proofs.Period) * 8.0);

View File

@ -5,6 +5,7 @@ using CodexTests;
using DistTestCore;
using GethPlugin;
using Nethereum.Hex.HexConvertors.Extensions;
using NUnit.Framework;
using Utils;
namespace CodexReleaseTests.MarketTests
@ -13,6 +14,7 @@ namespace CodexReleaseTests.MarketTests
{
private readonly Dictionary<TestLifecycle, MarketplaceHandle> handles = new Dictionary<TestLifecycle, MarketplaceHandle>();
protected const int StartingBalanceTST = 1000;
protected const int StartingBalanceEth = 10;
protected override void LifecycleStart(TestLifecycle lifecycle)
{
@ -48,7 +50,7 @@ namespace CodexReleaseTests.MarketTests
var hosts = StartCodex(NumberOfHosts, s => s
.WithName("host")
.EnableMarketplace(GetGeth(), GetContracts(), m => m
.WithInitial(10.Eth(), StartingBalanceTST.Tst())
.WithInitial(StartingBalanceEth.Eth(), StartingBalanceTST.Tst())
.AsStorageNode()
)
);
@ -56,6 +58,9 @@ namespace CodexReleaseTests.MarketTests
var config = GetContracts().Deployment.Config;
foreach (var host in hosts)
{
Assert.That(GetTstBalance(host).TstWei, Is.EqualTo(StartingBalanceTST.Tst().TstWei));
Assert.That(GetEthBalance(host).Wei, Is.EqualTo(StartingBalanceEth.Eth().Wei));
host.Marketplace.MakeStorageAvailable(new CodexPlugin.StorageAvailability(
totalSpace: HostAvailabilitySize,
maxDuration: HostAvailabilityMaxDuration,
@ -66,12 +71,32 @@ namespace CodexReleaseTests.MarketTests
return hosts;
}
public TestToken GetTstBalance(ICodexNode node)
{
return GetContracts().GetTestTokenBalance(node);
}
public TestToken GetTstBalance(EthAddress address)
{
return GetContracts().GetTestTokenBalance(address);
}
public Ether GetEthBalance(ICodexNode node)
{
return GetGeth().GetEthBalance(node);
}
public Ether GetEthBalance(EthAddress address)
{
return GetGeth().GetEthBalance(address);
}
public ICodexNodeGroup StartClients()
{
return StartCodex(NumberOfClients, s => s
.WithName("client")
.EnableMarketplace(GetGeth(), GetContracts(), m => m
.WithInitial(10.Eth(), StartingBalanceTST.Tst())
.WithInitial(StartingBalanceEth.Eth(), StartingBalanceTST.Tst())
)
);
}

View File

@ -107,7 +107,7 @@ namespace CodexTests.BasicTests
AssertStorageRequest(request, purchase, contracts, client);
AssertContractSlot(contracts, request, 0);
purchaseContract.WaitForStorageContractFinished();
purchaseContract.WaitForStorageContractFinished(contracts);
AssertBalance(contracts, client, Is.LessThan(clientInitialBalance), "Buyer was not charged for storage.");
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Finished));

View File

@ -45,7 +45,7 @@ namespace CodexTests.UtilityTests
var purchaseContract = ClientPurchasesStorage(client);
purchaseContract.WaitForStorageContractStarted();
purchaseContract.WaitForStorageContractFinished();
purchaseContract.WaitForStorageContractFinished(contracts);
Thread.Sleep(rewarderInterval * 3);
apiCalls.Stop();