Cleanup marketplace-access methods
This commit is contained in:
parent
32f56e8213
commit
a6c2bf5230
|
@ -2,15 +2,13 @@
|
|||
using Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Utils;
|
||||
using System.Numerics;
|
||||
|
||||
namespace CodexPlugin
|
||||
{
|
||||
public interface IMarketplaceAccess
|
||||
{
|
||||
string MakeStorageAvailable(ByteSize size, TestToken minPriceForTotalSpace, TestToken maxCollateral, TimeSpan maxDuration);
|
||||
StoragePurchaseContract RequestStorage(ContentId contentId, TestToken pricePerSlotPerSecond, TestToken requiredCollateral, uint minRequiredNumberOfNodes, int proofProbability, TimeSpan duration);
|
||||
StoragePurchaseContract RequestStorage(ContentId contentId, TestToken pricePerSlotPerSecond, TestToken requiredCollateral, uint minRequiredNumberOfNodes, int proofProbability, TimeSpan duration, TimeSpan expiry);
|
||||
string MakeStorageAvailable(StorageAvailability availability);
|
||||
StoragePurchaseContract RequestStorage(StoragePurchase purchase);
|
||||
}
|
||||
|
||||
public class MarketplaceAccess : IMarketplaceAccess
|
||||
|
@ -24,35 +22,12 @@ namespace CodexPlugin
|
|||
this.codexAccess = codexAccess;
|
||||
}
|
||||
|
||||
public StoragePurchaseContract RequestStorage(ContentId contentId, TestToken pricePerSlotPerSecond, TestToken requiredCollateral, uint minRequiredNumberOfNodes, int proofProbability, TimeSpan duration)
|
||||
public StoragePurchaseContract RequestStorage(StoragePurchase purchase)
|
||||
{
|
||||
return RequestStorage(contentId, pricePerSlotPerSecond, requiredCollateral, minRequiredNumberOfNodes, proofProbability, duration, duration / 2);
|
||||
}
|
||||
purchase.Log(log);
|
||||
var request = purchase.ToApiRequest();
|
||||
|
||||
public StoragePurchaseContract RequestStorage(ContentId contentId, TestToken pricePerSlotPerSecond, TestToken requiredCollateral, uint minRequiredNumberOfNodes, int proofProbability, TimeSpan duration, TimeSpan expiry)
|
||||
{
|
||||
var expireUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + expiry.TotalSeconds;
|
||||
|
||||
var request = new CodexSalesRequestStorageRequest
|
||||
{
|
||||
duration = ToDecInt(duration.TotalSeconds),
|
||||
proofProbability = ToDecInt(proofProbability),
|
||||
reward = ToDecInt(pricePerSlotPerSecond),
|
||||
collateral = ToDecInt(requiredCollateral),
|
||||
expiry = ToDecInt(expireUtc),
|
||||
nodes = minRequiredNumberOfNodes,
|
||||
tolerance = null,
|
||||
};
|
||||
|
||||
Log($"Requesting storage for: {contentId.Id}... (" +
|
||||
$"pricePerSlotPerSecond: {pricePerSlotPerSecond}, " +
|
||||
$"requiredCollateral: {requiredCollateral}, " +
|
||||
$"minRequiredNumberOfNodes: {minRequiredNumberOfNodes}, " +
|
||||
$"proofProbability: {proofProbability}, " +
|
||||
$"expiry: {Time.FormatDuration(expiry)}, " +
|
||||
$"duration: {Time.FormatDuration(duration)})");
|
||||
|
||||
var response = codexAccess.RequestStorage(request, contentId.Id);
|
||||
var response = codexAccess.RequestStorage(request, purchase.ContentId.Id);
|
||||
|
||||
if (response == "Purchasing not available" ||
|
||||
response == "Expiry required" ||
|
||||
|
@ -64,24 +39,13 @@ namespace CodexPlugin
|
|||
|
||||
Log($"Storage requested successfully. PurchaseId: '{response}'.");
|
||||
|
||||
return new StoragePurchaseContract(log, codexAccess, response, duration);
|
||||
return new StoragePurchaseContract(log, codexAccess, response, purchase);
|
||||
}
|
||||
|
||||
public string MakeStorageAvailable(ByteSize totalSpace, TestToken minPriceForTotalSpace, TestToken maxCollateral, TimeSpan maxDuration)
|
||||
public string MakeStorageAvailable(StorageAvailability availability)
|
||||
{
|
||||
var request = new CodexSalesAvailabilityRequest
|
||||
{
|
||||
size = ToDecInt(totalSpace.SizeInBytes),
|
||||
duration = ToDecInt(maxDuration.TotalSeconds),
|
||||
maxCollateral = ToDecInt(maxCollateral),
|
||||
minPrice = ToDecInt(minPriceForTotalSpace)
|
||||
};
|
||||
|
||||
Log($"Making storage available... (" +
|
||||
$"size: {totalSpace}, " +
|
||||
$"minPriceForTotalSpace: {minPriceForTotalSpace}, " +
|
||||
$"maxCollateral: {maxCollateral}, " +
|
||||
$"maxDuration: {Time.FormatDuration(maxDuration)})");
|
||||
availability.Log(log);
|
||||
var request = availability.ToApiRequest();
|
||||
|
||||
var response = codexAccess.SalesAvailability(request);
|
||||
|
||||
|
@ -90,18 +54,6 @@ namespace CodexPlugin
|
|||
return response.id;
|
||||
}
|
||||
|
||||
private string ToDecInt(double d)
|
||||
{
|
||||
var i = new BigInteger(d);
|
||||
return i.ToString("D");
|
||||
}
|
||||
|
||||
public string ToDecInt(TestToken t)
|
||||
{
|
||||
var i = new BigInteger(t.Amount);
|
||||
return i.ToString("D");
|
||||
}
|
||||
|
||||
private void Log(string msg)
|
||||
{
|
||||
log.Log($"{codexAccess.Container.Name} {msg}");
|
||||
|
@ -110,22 +62,16 @@ namespace CodexPlugin
|
|||
|
||||
public class MarketplaceUnavailable : IMarketplaceAccess
|
||||
{
|
||||
public StoragePurchaseContract RequestStorage(ContentId contentId, TestToken pricePerBytePerSecond, TestToken requiredCollateral, uint minRequiredNumberOfNodes, int proofProbability, TimeSpan duration)
|
||||
{
|
||||
Unavailable();
|
||||
return null!;
|
||||
}
|
||||
|
||||
public StoragePurchaseContract RequestStorage(ContentId contentId, TestToken pricePerSlotPerSecond, TestToken requiredCollateral, uint minRequiredNumberOfNodes, int proofProbability, TimeSpan duration, TimeSpan expiry)
|
||||
public string MakeStorageAvailable(StorageAvailability availability)
|
||||
{
|
||||
Unavailable();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string MakeStorageAvailable(ByteSize size, TestToken minPricePerBytePerSecond, TestToken maxCollateral, TimeSpan duration)
|
||||
public StoragePurchaseContract RequestStorage(StoragePurchase purchase)
|
||||
{
|
||||
Unavailable();
|
||||
return string.Empty;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void Unavailable()
|
||||
|
@ -141,16 +87,16 @@ namespace CodexPlugin
|
|||
private readonly CodexAccess codexAccess;
|
||||
private DateTime? contractStartUtc;
|
||||
|
||||
public StoragePurchaseContract(ILog log, CodexAccess codexAccess, string purchaseId, TimeSpan contractDuration)
|
||||
public StoragePurchaseContract(ILog log, CodexAccess codexAccess, string purchaseId, StoragePurchase purchase)
|
||||
{
|
||||
this.log = log;
|
||||
this.codexAccess = codexAccess;
|
||||
PurchaseId = purchaseId;
|
||||
ContractDuration = contractDuration;
|
||||
Purchase = purchase;
|
||||
}
|
||||
|
||||
public string PurchaseId { get; }
|
||||
public TimeSpan ContractDuration { get; }
|
||||
public StoragePurchase Purchase { get; }
|
||||
|
||||
public void WaitForStorageContractStarted()
|
||||
{
|
||||
|
@ -165,7 +111,7 @@ namespace CodexPlugin
|
|||
}
|
||||
var gracePeriod = TimeSpan.FromSeconds(10);
|
||||
var currentContractTime = DateTime.UtcNow - contractStartUtc!.Value;
|
||||
var timeout = (ContractDuration - currentContractTime) + gracePeriod;
|
||||
var timeout = (Purchase.Duration - currentContractTime) + gracePeriod;
|
||||
WaitForStorageContractState(timeout, "finished");
|
||||
}
|
||||
|
||||
|
@ -177,7 +123,7 @@ namespace CodexPlugin
|
|||
}
|
||||
var gracePeriod = TimeSpan.FromSeconds(10);
|
||||
var currentContractTime = DateTime.UtcNow - contractStartUtc!.Value;
|
||||
var timeout = (ContractDuration - currentContractTime) + gracePeriod;
|
||||
var timeout = (Purchase.Duration - currentContractTime) + gracePeriod;
|
||||
WaitForStorageContractState(timeout, "finished");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
using CodexContractsPlugin;
|
||||
using Logging;
|
||||
using System.Numerics;
|
||||
using Utils;
|
||||
|
||||
namespace CodexPlugin
|
||||
{
|
||||
public class StoragePurchase : MarketplaceType
|
||||
{
|
||||
public StoragePurchase(ContentId cid)
|
||||
{
|
||||
ContentId = cid;
|
||||
}
|
||||
|
||||
public ContentId ContentId { get; set; }
|
||||
public TestToken PricePerSlotPerSecond { get; set; } = 1.TestTokens();
|
||||
public TestToken RequiredCollateral { get; set; } = 1.TestTokens();
|
||||
public uint MinRequiredNumberOfNodes { get; set; }
|
||||
public uint NodeFailureTolerance { get; set; }
|
||||
public int ProofProbability { get; set; }
|
||||
public TimeSpan Duration { get; set; }
|
||||
public TimeSpan Expiry { get; set; }
|
||||
|
||||
public CodexSalesRequestStorageRequest ToApiRequest()
|
||||
{
|
||||
return new CodexSalesRequestStorageRequest
|
||||
{
|
||||
duration = ToDecInt(Duration.TotalSeconds),
|
||||
proofProbability = ToDecInt(ProofProbability),
|
||||
reward = ToDecInt(PricePerSlotPerSecond),
|
||||
collateral = ToDecInt(RequiredCollateral),
|
||||
expiry = ToDecInt(DateTimeOffset.UtcNow.ToUnixTimeSeconds() + Expiry.TotalSeconds),
|
||||
nodes = MinRequiredNumberOfNodes,
|
||||
tolerance = NodeFailureTolerance
|
||||
};
|
||||
}
|
||||
|
||||
public void Log(ILog log)
|
||||
{
|
||||
log.Log($"Requesting storage for: {ContentId.Id}... (" +
|
||||
$"pricePerSlotPerSecond: {PricePerSlotPerSecond}, " +
|
||||
$"requiredCollateral: {RequiredCollateral}, " +
|
||||
$"minRequiredNumberOfNodes: {MinRequiredNumberOfNodes}, " +
|
||||
$"nodeFailureTolerance: {NodeFailureTolerance}, " +
|
||||
$"proofProbability: {ProofProbability}, " +
|
||||
$"expiry: {Time.FormatDuration(Expiry)}, " +
|
||||
$"duration: {Time.FormatDuration(Duration)})");
|
||||
}
|
||||
}
|
||||
|
||||
public class StorageAvailability : MarketplaceType
|
||||
{
|
||||
public StorageAvailability(ByteSize totalSpace, TimeSpan maxDuration, TestToken minPriceForTotalSpace, TestToken maxCollateral)
|
||||
{
|
||||
TotalSpace = totalSpace;
|
||||
MaxDuration = maxDuration;
|
||||
MinPriceForTotalSpace = minPriceForTotalSpace;
|
||||
MaxCollateral = maxCollateral;
|
||||
}
|
||||
|
||||
public ByteSize TotalSpace { get; }
|
||||
public TimeSpan MaxDuration { get; }
|
||||
public TestToken MinPriceForTotalSpace { get; }
|
||||
public TestToken MaxCollateral { get; }
|
||||
|
||||
public CodexSalesAvailabilityRequest ToApiRequest()
|
||||
{
|
||||
return new CodexSalesAvailabilityRequest
|
||||
{
|
||||
size = ToDecInt(TotalSpace.SizeInBytes),
|
||||
duration = ToDecInt(MaxDuration.TotalSeconds),
|
||||
maxCollateral = ToDecInt(MaxCollateral),
|
||||
minPrice = ToDecInt(MinPriceForTotalSpace)
|
||||
};
|
||||
}
|
||||
|
||||
public void Log(ILog log)
|
||||
{
|
||||
log.Log($"Making storage available... (" +
|
||||
$"size: {TotalSpace}, " +
|
||||
$"maxDuration: {Time.FormatDuration(MaxDuration)})" +
|
||||
$"minPriceForTotalSpace: {MinPriceForTotalSpace}, " +
|
||||
$"maxCollateral: {MaxCollateral}, ");
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class MarketplaceType
|
||||
{
|
||||
protected string ToDecInt(double d)
|
||||
{
|
||||
var i = new BigInteger(d);
|
||||
return i.ToString("D");
|
||||
}
|
||||
|
||||
protected string ToDecInt(TestToken t)
|
||||
{
|
||||
var i = new BigInteger(t.Amount);
|
||||
return i.ToString("D");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,13 +33,16 @@ namespace CodexTests.BasicTests
|
|||
|
||||
var rc = Ci.DeployMetricsCollector(nodes);
|
||||
|
||||
var availability = new StorageAvailability(
|
||||
totalSpace: 500.MB(),
|
||||
maxDuration: TimeSpan.FromMinutes(5),
|
||||
minPriceForTotalSpace: 500.TestTokens(),
|
||||
maxCollateral: 1024.TestTokens()
|
||||
);
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
node.Marketplace.MakeStorageAvailable(
|
||||
size: 500.MB(),
|
||||
minPriceForTotalSpace: 500.TestTokens(),
|
||||
maxCollateral: 1024.TestTokens(),
|
||||
maxDuration: TimeSpan.FromMinutes(5));
|
||||
node.Marketplace.MakeStorageAvailable(availability);
|
||||
}
|
||||
|
||||
var endTime = DateTime.UtcNow + TimeSpan.FromHours(10);
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace CodexTests.BasicTests
|
|||
public void MarketplaceExample()
|
||||
{
|
||||
var sellerInitialBalance = 234.TestTokens();
|
||||
var buyerInitialBalance = 1000.TestTokens();
|
||||
var buyerInitialBalance = 100000.TestTokens();
|
||||
var fileSize = 10.MB();
|
||||
|
||||
var geth = Ci.StartGethNode(s => s.IsMiner().WithName("disttest-geth"));
|
||||
|
@ -69,11 +69,14 @@ namespace CodexTests.BasicTests
|
|||
.AsValidator()));
|
||||
|
||||
AssertBalance(contracts, seller, Is.EqualTo(sellerInitialBalance));
|
||||
seller.Marketplace.MakeStorageAvailable(
|
||||
size: 10.GB(),
|
||||
|
||||
var availability = new StorageAvailability(
|
||||
totalSpace: 10.GB(),
|
||||
maxDuration: TimeSpan.FromMinutes(30),
|
||||
minPriceForTotalSpace: 1.TestTokens(),
|
||||
maxCollateral: 20.TestTokens(),
|
||||
maxDuration: TimeSpan.FromMinutes(30));
|
||||
maxCollateral: 20.TestTokens()
|
||||
);
|
||||
seller.Marketplace.MakeStorageAvailable(availability);
|
||||
|
||||
var testFile = GenerateTestFile(fileSize);
|
||||
|
||||
|
@ -85,20 +88,26 @@ namespace CodexTests.BasicTests
|
|||
AssertBalance(contracts, buyer, Is.EqualTo(buyerInitialBalance));
|
||||
|
||||
var contentId = buyer.UploadFile(testFile);
|
||||
var purchaseContract = buyer.Marketplace.RequestStorage(contentId,
|
||||
pricePerSlotPerSecond: 2.TestTokens(),
|
||||
requiredCollateral: 10.TestTokens(),
|
||||
minRequiredNumberOfNodes: 1,
|
||||
proofProbability: 5,
|
||||
duration: TimeSpan.FromMinutes(5),
|
||||
expiry: TimeSpan.FromMinutes(4));
|
||||
|
||||
var purchase = new StoragePurchase(contentId)
|
||||
{
|
||||
PricePerSlotPerSecond = 2.TestTokens(),
|
||||
RequiredCollateral = 10.TestTokens(),
|
||||
MinRequiredNumberOfNodes = 5,
|
||||
NodeFailureTolerance = 2,
|
||||
ProofProbability = 5,
|
||||
Duration = TimeSpan.FromMinutes(5),
|
||||
Expiry = TimeSpan.FromMinutes(4)
|
||||
};
|
||||
|
||||
var purchaseContract = buyer.Marketplace.RequestStorage(purchase);
|
||||
|
||||
purchaseContract.WaitForStorageContractStarted(TimeSpan.FromMinutes(4));
|
||||
|
||||
AssertBalance(contracts, seller, Is.LessThan(sellerInitialBalance), "Collateral was not placed.");
|
||||
|
||||
var request = GetOnChainStorageRequest(contracts);
|
||||
AssertStorageRequest(request, contracts, buyer);
|
||||
AssertStorageRequest(request, purchase, contracts, buyer);
|
||||
AssertSlotFilledEvents(contracts, request, seller);
|
||||
AssertContractSlot(contracts, request, 0, seller);
|
||||
|
||||
|
@ -141,11 +150,11 @@ namespace CodexTests.BasicTests
|
|||
Assert.That(filledSlotEvent.Host, Is.EqualTo(seller.EthAddress));
|
||||
}
|
||||
|
||||
private void AssertStorageRequest(Request request, ICodexContracts contracts, ICodexNode buyer)
|
||||
private void AssertStorageRequest(Request request, StoragePurchase 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(1));
|
||||
Assert.That(request.Ask.Slots, Is.EqualTo(purchase.MinRequiredNumberOfNodes));
|
||||
}
|
||||
|
||||
private Request GetOnChainStorageRequest(ICodexContracts contracts)
|
||||
|
|
|
@ -67,11 +67,14 @@ namespace CodexNetDeployer
|
|||
|
||||
if (config.ShouldMakeStorageAvailable)
|
||||
{
|
||||
var response = codexNode.Marketplace.MakeStorageAvailable(
|
||||
size: config.StorageSell!.Value.MB(),
|
||||
var availability = new StorageAvailability(
|
||||
totalSpace: config.StorageSell!.Value.MB(),
|
||||
maxDuration: TimeSpan.FromSeconds(config.MaxDuration),
|
||||
minPriceForTotalSpace: config.MinPrice.TestTokens(),
|
||||
maxCollateral: config.MaxCollateral.TestTokens(),
|
||||
maxDuration: TimeSpan.FromSeconds(config.MaxDuration));
|
||||
maxCollateral: config.MaxCollateral.TestTokens()
|
||||
);
|
||||
|
||||
var response = codexNode.Marketplace.MakeStorageAvailable(availability);
|
||||
|
||||
if (!string.IsNullOrEmpty(response))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue