cs-codex-dist-tests/Tests/CodexTests/BasicTests/MarketplaceTests.cs

197 lines
7.9 KiB
C#
Raw Normal View History

2024-04-01 09:00:52 +00:00
using CodexContractsPlugin;
using CodexContractsPlugin.Marketplace;
using CodexPlugin;
2024-07-01 13:59:08 +00:00
using FileUtils;
2024-04-01 09:00:52 +00:00
using GethPlugin;
using NUnit.Framework;
using Utils;
namespace CodexTests.BasicTests
{
[TestFixture]
public class MarketplaceTests : AutoBootstrapDistTest
{
[Test]
2024-07-02 08:44:15 +00:00
[Combinatorial]
public void MarketplaceExample(
2024-07-24 14:06:45 +00:00
[Values(4, 8, 16 /* 1mb */, 32, 64)] int numBlocks,
[Values(-3, -2, -1, 0, 1, 2, 3)] int plusSizeKb,
[Values(-3, -2, -1, 0, 1, 2, 3)] int plusSizeBytes
2024-07-02 08:44:15 +00:00
)
2024-04-01 09:00:52 +00:00
{
var hostInitialBalance = 234.TstWei();
var clientInitialBalance = 100000.TstWei();
2024-07-02 08:44:15 +00:00
var fileSize = new ByteSize(
numBlocks * (64 * 1024) +
2024-07-24 14:06:45 +00:00
plusSizeKb * 1024 +
plusSizeBytes
2024-07-02 08:44:15 +00:00
);
2024-04-01 09:00:52 +00:00
var geth = Ci.StartGethNode(s => s.IsMiner().WithName("disttest-geth"));
var contracts = Ci.StartCodexContracts(geth);
var numberOfHosts = 5;
2024-05-09 07:32:48 +00:00
var hosts = StartCodex(numberOfHosts, s => s
.WithName("Host")
.WithLogLevel(CodexLogLevel.Trace, new CodexLogCustomTopics(CodexLogLevel.Error, CodexLogLevel.Error, CodexLogLevel.Warn)
{
ContractClock = CodexLogLevel.Trace,
})
.WithStorageQuota(11.GB())
.EnableMarketplace(geth, contracts, m => m
.WithInitial(10.Eth(), hostInitialBalance)
.AsStorageNode()
.AsValidator()));
2024-04-01 09:00:52 +00:00
foreach (var host in hosts)
{
AssertBalance(contracts, host, Is.EqualTo(hostInitialBalance));
2024-04-01 13:31:54 +00:00
var availability = new StorageAvailability(
totalSpace: 10.GB(),
maxDuration: TimeSpan.FromMinutes(30),
minPriceForTotalSpace: 1.TstWei(),
maxCollateral: 20.TstWei()
);
2024-04-01 13:31:54 +00:00
host.Marketplace.MakeStorageAvailable(availability);
}
2024-04-01 09:00:52 +00:00
2024-07-01 13:59:08 +00:00
var testFile = CreateFile(fileSize);
2024-04-01 09:00:52 +00:00
2024-05-09 07:32:48 +00:00
var client = StartCodex(s => s
2024-04-01 13:31:54 +00:00
.WithName("Client")
2024-04-01 09:00:52 +00:00
.EnableMarketplace(geth, contracts, m => m
2024-04-01 13:31:54 +00:00
.WithInitial(10.Eth(), clientInitialBalance)));
AssertBalance(contracts, client, Is.EqualTo(clientInitialBalance));
2024-04-01 09:00:52 +00:00
2024-07-02 08:44:15 +00:00
var uploadCid = client.UploadFile(testFile);
2024-04-01 09:00:52 +00:00
2024-07-02 08:44:15 +00:00
var purchase = new StoragePurchaseRequest(uploadCid)
2024-04-01 09:00:52 +00:00
{
PricePerSlotPerSecond = 2.TstWei(),
RequiredCollateral = 10.TstWei(),
2024-04-01 09:00:52 +00:00
MinRequiredNumberOfNodes = 5,
NodeFailureTolerance = 2,
ProofProbability = 5,
2024-05-24 13:34:42 +00:00
Duration = TimeSpan.FromMinutes(6),
Expiry = TimeSpan.FromMinutes(5)
2024-04-01 09:00:52 +00:00
};
2024-04-01 13:31:54 +00:00
var purchaseContract = client.Marketplace.RequestStorage(purchase);
2024-07-02 08:44:15 +00:00
var contractCid = purchaseContract.ContentId;
Assert.That(uploadCid.Id, Is.Not.EqualTo(contractCid.Id));
// Download both from client.
testFile.AssertIsEqual(client.DownloadContent(uploadCid));
testFile.AssertIsEqual(client.DownloadContent(contractCid));
// Download both from another node.
var downloader = StartCodex(s => s.WithName("Downloader"));
testFile.AssertIsEqual(downloader.DownloadContent(uploadCid));
testFile.AssertIsEqual(downloader.DownloadContent(contractCid));
2024-04-01 09:00:52 +00:00
2024-04-01 13:31:54 +00:00
WaitForAllSlotFilledEvents(contracts, purchase, geth);
2024-04-01 09:00:52 +00:00
2024-04-01 13:31:54 +00:00
purchaseContract.WaitForStorageContractStarted();
2024-04-01 13:31:54 +00:00
var request = GetOnChainStorageRequest(contracts, geth);
AssertStorageRequest(request, purchase, contracts, client);
AssertContractSlot(contracts, request, 0);
2024-04-01 09:00:52 +00:00
purchaseContract.WaitForStorageContractFinished();
2024-04-01 13:31:54 +00:00
AssertBalance(contracts, client, Is.LessThan(clientInitialBalance), "Buyer was not charged for storage.");
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Finished));
2024-04-01 09:00:52 +00:00
}
[Test]
2024-07-02 08:44:15 +00:00
[Ignore("Integrated into MarketplaceExample to speed up testing.")]
public void CanDownloadContentFromContractCid()
{
var fileSize = 10.MB();
var geth = Ci.StartGethNode(s => s.IsMiner().WithName("disttest-geth"));
var contracts = Ci.StartCodexContracts(geth);
2024-07-01 13:59:08 +00:00
var testFile = CreateFile(fileSize);
var client = StartCodex(s => s
.WithName("Client")
.EnableMarketplace(geth, contracts, m => m
.WithInitial(10.Eth(), 10.Tst())));
var uploadCid = client.UploadFile(testFile);
var purchase = new StoragePurchaseRequest(uploadCid)
{
PricePerSlotPerSecond = 2.TstWei(),
RequiredCollateral = 10.TstWei(),
MinRequiredNumberOfNodes = 5,
NodeFailureTolerance = 2,
ProofProbability = 5,
Duration = TimeSpan.FromMinutes(5),
Expiry = TimeSpan.FromMinutes(4)
};
var purchaseContract = client.Marketplace.RequestStorage(purchase);
var contractCid = purchaseContract.ContentId;
Assert.That(uploadCid.Id, Is.Not.EqualTo(contractCid.Id));
2024-06-14 07:05:56 +00:00
// Download both from client.
testFile.AssertIsEqual(client.DownloadContent(uploadCid));
testFile.AssertIsEqual(client.DownloadContent(contractCid));
2024-06-14 07:05:56 +00:00
// Download both from another node.
var downloader = StartCodex(s => s.WithName("Downloader"));
testFile.AssertIsEqual(downloader.DownloadContent(uploadCid));
testFile.AssertIsEqual(downloader.DownloadContent(contractCid));
}
2024-07-01 13:59:08 +00:00
private TrackedFile CreateFile(ByteSize fileSize)
{
var segmentSize = new ByteSize(fileSize.SizeInBytes / 4);
return GenerateTestFile(o => o
.Random(segmentSize)
.ByteRepeat(new byte[] { 0xaa }, segmentSize)
.Random(segmentSize)
.ByteRepeat(new byte[] { 0xee }, segmentSize)
);
}
2024-04-01 13:31:54 +00:00
private void WaitForAllSlotFilledEvents(ICodexContracts contracts, StoragePurchaseRequest purchase, IGethNode geth)
2024-04-01 09:00:52 +00:00
{
Time.Retry(() =>
{
var events = contracts.GetEvents(GetTestRunTimeRange());
var slotFilledEvents = events.GetSlotFilledEvents();
2024-04-01 09:00:52 +00:00
var msg = $"SlotFilledEvents: {slotFilledEvents.Length} - NumSlots: {purchase.MinRequiredNumberOfNodes}";
Debug(msg);
if (slotFilledEvents.Length != purchase.MinRequiredNumberOfNodes) throw new Exception(msg);
}, purchase.Expiry + TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(5), "Checking SlotFilled events");
2024-04-01 09:00:52 +00:00
}
private void AssertStorageRequest(Request request, StoragePurchaseRequest purchase, ICodexContracts contracts, ICodexNode buyer)
{
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Started));
Assert.That(request.ClientAddress, Is.EqualTo(buyer.EthAddress));
Assert.That(request.Ask.Slots, Is.EqualTo(purchase.MinRequiredNumberOfNodes));
}
2024-04-01 13:31:54 +00:00
private Request GetOnChainStorageRequest(ICodexContracts contracts, IGethNode geth)
{
var events = contracts.GetEvents(GetTestRunTimeRange());
var requests = events.GetStorageRequests();
2024-04-01 13:31:54 +00:00
Assert.That(requests.Length, Is.EqualTo(1));
return requests.Single();
}
2024-04-01 09:00:52 +00:00
2024-04-01 13:31:54 +00:00
private void AssertContractSlot(ICodexContracts contracts, Request request, int contractSlotIndex)
2024-04-01 09:00:52 +00:00
{
var slotHost = contracts.GetSlotHost(request, contractSlotIndex);
2024-04-01 13:31:54 +00:00
Assert.That(slotHost?.Address, Is.Not.Null);
2024-04-01 09:00:52 +00:00
}
}
}