Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Index DAL Attestations #178

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fdf0eb5
[DAL] Keep track of DAL attestations (#14)
spalmer25 Aug 2, 2024
e32576b
add protocol constants related to dal (#18)
ajinkyaraj-23 Aug 8, 2024
bf7a1e8
[data] create a DalCommitments table
spalmer25 Aug 8, 2024
f86f0d7
[dal-commitment] index DAL commitments on applied publishment
spalmer25 Aug 5, 2024
474b92c
[api] add a parameter template for DAL commitment hash
spalmer25 Aug 5, 2024
6c95f99
[api] add an endpoint to count DAL commitments
spalmer25 Aug 5, 2024
67da31c
[api] add an endpoint to get DAL commitment information
spalmer25 Aug 6, 2024
3b7082f
[api] add an endpoint to get DAL commitment information by hash
spalmer25 Aug 6, 2024
8b3fe34
Merge pull request #17 from trilitech/palmer@functori@DAL-commitment-…
spalmer25 Aug 9, 2024
3733997
[DAL] Index DAL attestations (#21)
spalmer25 Aug 13, 2024
107f27b
[DAL] compute dal shards distribution (#19)
spalmer25 Aug 13, 2024
714ab6a
[DAL] Expose DAL shards in DAL attestation (#22)
spalmer25 Aug 13, 2024
ffc0c6e
update shards count in dal commitment status (#23)
ajinkyaraj-23 Sep 2, 2024
1efa243
[dal] rename DalAttestationStatus to DalAttestation (#30)
spalmer25 Sep 23, 2024
58d1bc7
[DAL] update dal commitment attestations during attestations handling…
spalmer25 Sep 26, 2024
d1383b0
[api] add filter parameters to /dal/commitments/ api endpoint (#34)
spalmer25 Sep 26, 2024
ac64621
[dal] remove DAL attestation from EndorsementOperation (#32)
spalmer25 Sep 26, 2024
ff770b9
26 Add Dal commitment status fields in DalPublishCommitmentOps (#36)
ajinkyaraj-23 Oct 4, 2024
3d5e5b0
Split DAL rights from Baking rights (#35)
spalmer25 Oct 4, 2024
7f86d18
Merge all migration related to dal support (#37)
spalmer25 Oct 4, 2024
d586ecf
Merge remote-tracking branch 'bb-tzkt/master' into dal-support
ajinkyaraj-23 Oct 7, 2024
0c8b7a6
Merge pull request #38 from trilitech/merge-tzkt-base-branch
ajinkyaraj-23 Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
304 changes: 304 additions & 0 deletions Tzkt.Api/Controllers/DalController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Tzkt.Api.Models;
using Tzkt.Api.Repositories;

namespace Tzkt.Api.Controllers
{
[ApiController]
[Route("v1/dal")]
public class DalController : ControllerBase
{
private readonly DalRepository Dal;

public DalController(DalRepository dal)
{
Dal = dal;
}

#region commiments
/// <summary>
/// Get DAL commitments count
/// </summary>
/// <remarks>
/// Returns total number of DAL commitments published.
/// </remarks>
/// <param name="hash">Filters by DAL commitment hash</param>
/// <param name="level">Filters by level</param>
/// <param name="slotIndex">Filters by slot-index</param>
/// <param name="publisher">Filters by DAL commitment publisher</param>
/// <param name="shardsAttested">Filters by number of shards attested</param>
/// <param name="attested">Filters by if the commitment has been attested</param>
/// <returns></returns>
[HttpGet("commitments/count")]
public async Task<int> GetDalCommitmentsCount(
DalCommitmentHashParameter hash,
Int32Parameter level,
Int32Parameter slotIndex,
AccountParameter publisher,
Int32Parameter shardsAttested,
BoolParameter attested)
{
return await Dal.GetCommitmentsCount(hash, level, slotIndex, publisher, shardsAttested, attested);
}

/// <summary>
/// Get DAL commitments information
/// </summary>
/// <remarks>
/// Returns information of the DAL commitments published.
/// </remarks>
/// <param name="hash">Filters by DAL commitment hash</param>
/// <param name="level">Filters by level</param>
/// <param name="slotIndex">Filters by slot-index</param>
/// <param name="publisher">Filters by DAL commitment publisher</param>
/// <param name="shardsAttested">Filters by number of shards attested</param>
/// <param name="attested">Filters by if the commitment has been attested</param>
/// <param name="select">Specify comma-separated list of fields to include into response or leave it undefined to return full object. If you select single field, response will be an array of values in both `.fields` and `.values` modes.</param>
/// <param name="sort">Sorts DAL commitments by specified field. Supported fields: `level` (default), `slotIndex`.</param>
/// <param name="offset">Specifies which or how many items should be skipped</param>
/// <param name="limit">Maximum number of items to return</param>
/// <returns></returns>
[HttpGet("commitments")]
public async Task<ActionResult<IEnumerable<DalCommitment>>> GetDalCommitments(
DalCommitmentHashParameter hash,
Int32Parameter level,
Int32Parameter slotIndex,
AccountParameter publisher,
Int32Parameter shardsAttested,
BoolParameter attested,
SelectParameter select,
SortParameter sort,
OffsetParameter offset,
[Range(0, 10000)] int limit = 100)
{
#region validate
if (sort != null && !sort.Validate("level", "slotIndex"))
return new BadRequest($"{nameof(sort)}", "Sorting by the specified field is not allowed.");
#endregion

if (select == null)
return Ok(await Dal.GetCommitments(hash, level, slotIndex, publisher, shardsAttested, attested, sort, offset, limit));

if (select.Values != null)
{
if (select.Values.Length == 1)
return Ok(await Dal.GetCommitments(hash, level, slotIndex, publisher, shardsAttested, attested, sort, offset, limit, select.Values[0]));
else
return Ok(await Dal.GetCommitments(hash, level, slotIndex, publisher, shardsAttested, attested, sort, offset, limit, select.Values));
}
else
{
if (select.Fields.Length == 1)
return Ok(await Dal.GetCommitments(hash, level, slotIndex, publisher, shardsAttested, attested, sort, offset, limit, select.Fields[0]));
else
{
return Ok(new SelectionResponse
{
Cols = select.Fields,
Rows = await Dal.GetCommitments(hash, level, slotIndex, publisher, shardsAttested, attested, sort, offset, limit, select.Fields)
});
}
}
}

/// <summary>
/// Get DAL commitments information by hash
/// </summary>
/// <remarks>
/// Returns information of the DAL commitments published with the specified hash.
/// </remarks>
/// <param name="hash">DAL commitment hash</param>
/// <param name="level">Filters by level</param>
/// <param name="slotIndex">Filters by slot-index</param>
/// <param name="publisher">Filters by DAL commitment publisher</param>
/// <param name="shardsAttested">Filters by number of shards attested</param>
/// <param name="attested">Filters by if the commitment has been attested</param>
/// <param name="select">Specify comma-separated list of fields to include into response or leave it undefined to return full object. If you select single field, response will be an array of values in both `.fields` and `.values` modes.</param>
/// <param name="sort">Sorts DAL commitments by specified field. Supported fields: `level` (default), `slotIndex`.</param>
/// <param name="offset">Specifies which or how many items should be skipped</param>
/// <param name="limit">Maximum number of items to return</param>
/// <returns></returns>
[HttpGet("commitments/{hash}")]
public async Task<ActionResult<IEnumerable<DalCommitment>>> GetDalCommitmentsByHash(
[Required][DalCommitmentHash] string hash,
Int32Parameter level,
Int32Parameter slotIndex,
AccountParameter publisher,
Int32Parameter shardsAttested,
BoolParameter attested,
SelectParameter select,
SortParameter sort,
OffsetParameter offset,
[Range(0, 10000)] int limit = 100)
=>
await GetDalCommitments(new DalCommitmentHashParameter { Eq = hash }, level, slotIndex, publisher, shardsAttested, attested, select, sort, offset, limit);
#endregion

#region attestations
/// <summary>
/// Get DAL attestations count
/// </summary>
/// <remarks>
/// Returns total number of DAL attestations.
/// </remarks>
/// <param name="commitment">Filters by DAL commitment hash</param>
/// <param name="publishLevel">Filters by level at which the commitment has been published</param>
/// <param name="slotIndex">Filters by slot-index</param>
/// <param name="attester">Filters by attester</param>
/// <param name="shardsCount">Filters by number of shards</param>
/// <param name="attested">Filters by if the slot has been attested</param>
/// <returns></returns>
[HttpGet("attestations/count")]
public async Task<int> GetDalAttestationsCount(
DalCommitmentHashParameter commitment,
Int32Parameter publishLevel,
Int32Parameter slotIndex,
Int32Parameter shardsCount,
AccountParameter attester,
BoolParameter attested)
{
return await Dal.GetAttestationsCount(commitment, publishLevel, slotIndex, attester, shardsCount, attested);
}

/// <summary>
/// Get DAL attestations information
/// </summary>
/// <remarks>
/// Returns information of the DAL attestations.
/// </remarks>
/// <param name="commitment">Filters by DAL commitment hash</param>
/// <param name="publishLevel">Filters by level at which the commitment has been published</param>
/// <param name="slotIndex">Filters by slot-index</param>
/// <param name="attester">Filters by attester</param>
/// <param name="shardsCount">Filters by number of shards</param>
/// <param name="attested">Filters if the shards are attested</param>
/// <param name="select">Specify comma-separated list of fields to include into response or leave it undefined to return full object. If you select single field, response will be an array of values in both `.fields` and `.values` modes.</param>
/// <param name="sort">Sorts DAL commitments by specified field. Supported fields: `publishLevel` (default), `slotIndex`, `shardsCount`.</param>
/// <param name="offset">Specifies which or how many items should be skipped</param>
/// <param name="limit">Maximum number of items to return</param>
/// <returns></returns>
[HttpGet("attestations")]
public async Task<ActionResult<IEnumerable<DalAttestation>>> GetDalAttestations(
DalCommitmentHashParameter commitment,
Int32Parameter publishLevel,
Int32Parameter slotIndex,
AccountParameter attester,
Int32Parameter shardsCount,
BoolParameter attested,
SelectParameter select,
SortParameter sort,
OffsetParameter offset,
[Range(0, 10000)] int limit = 100)
{
#region validate
if (sort != null && !sort.Validate("publishLevel", "slotIndex", "shardsCount"))
return new BadRequest($"{nameof(sort)}", "Sorting by the specified field is not allowed.");
#endregion

if (select == null)
return Ok(await Dal.GetAttestations(commitment, publishLevel, slotIndex, attester, shardsCount, attested, sort, offset, limit));

if (select.Values != null)
{
if (select.Values.Length == 1)
return Ok(await Dal.GetAttestations(commitment, publishLevel, slotIndex, attester, shardsCount, attested, sort, offset, limit, select.Values[0]));
else
return Ok(await Dal.GetAttestations(commitment, publishLevel, slotIndex, attester, shardsCount, attested, sort, offset, limit, select.Values));
}
else
{
if (select.Fields.Length == 1)
return Ok(await Dal.GetAttestations(commitment, publishLevel, slotIndex, attester, shardsCount, attested, sort, offset, limit, select.Fields[0]));
else
{
return Ok(new SelectionResponse
{
Cols = select.Fields,
Rows = await Dal.GetAttestations(commitment, publishLevel, slotIndex, attester, shardsCount, attested, sort, offset, limit, select.Fields)
});
}
}
}
#endregion

#region rights
/// <summary>
/// Get DAL rights count
/// </summary>
/// <remarks>
/// Returns the total number of stored DAL rights.
/// </remarks>
/// <param name="delegate">Filters rights by delegate</param>
/// <param name="cycle">Filters rights by cycle</param>
/// <param name="level">Filters rights by level</param>
/// <param name="shards">Filters rights by shards</param>
/// <returns></returns>
[HttpGet("rights/count")]
public Task<int> GetRightsCount(
AccountParameter @delegate,
Int32Parameter cycle,
Int32Parameter level,
Int32Parameter shards)
{
return Dal.GetRightsCount(@delegate, cycle, level, shards);
}

/// <summary>
/// Get DAL rights
/// </summary>
/// <remarks>
/// Returns a list of DAL rights.
/// </remarks>
/// <param name="delegate">Filters rights by delegate</param>
/// <param name="cycle">Filters rights by cycle</param>
/// <param name="level">Filters rights by level</param>
/// <param name="shards">Filters rights by shards</param>
/// <param name="select">Specify comma-separated list of fields to include into response or leave it undefined to return full object. If you select single field, response will be an array of values in both `.fields` and `.values` modes.</param>
/// <param name="sort">Sorts rights by specified field. Supported fields: `level` (default), `shards`.</param>
/// <param name="offset">Specifies which or how many items should be skipped</param>
/// <param name="limit">Maximum number of items to return</param>
/// <returns></returns>
[HttpGet("rights")]
public async Task<ActionResult<IEnumerable<DalRight>>> GetRights(
AccountParameter @delegate,
Int32Parameter cycle,
Int32Parameter level,
Int32Parameter shards,
SelectParameter select,
SortParameter sort,
OffsetParameter offset,
[Range(0, 10000)] int limit = 100)
{
#region validate
if (sort != null && !sort.Validate("level", "shards"))
return new BadRequest($"{nameof(sort)}", "Sorting by the specified field is not allowed.");
#endregion

if (select == null)
return Ok(await Dal.GetRights(@delegate, cycle, level, shards, sort, offset, limit));

if (select.Values != null)
{
if (select.Values.Length == 1)
return Ok(await Dal.GetRights(@delegate, cycle, level, shards, sort, offset, limit, select.Values[0]));
else
return Ok(await Dal.GetRights(@delegate, cycle, level, shards, sort, offset, limit, select.Values));
}
else
{
if (select.Fields.Length == 1)
return Ok(await Dal.GetRights(@delegate, cycle, level, shards, sort, offset, limit, select.Fields[0]));
else
{
return Ok(new SelectionResponse
{
Cols = select.Fields,
Rows = await Dal.GetRights(@delegate, cycle, level, shards, sort, offset, limit, select.Fields)
});
}
}
}
#endregion
}
}
61 changes: 61 additions & 0 deletions Tzkt.Api/Extensions/ModelBindingContextExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,67 @@ public static bool TryGetEpochStatusList(this ModelBindingContext bindingContext
return true;
}

public static bool TryGetDalCommitmentHash(this ModelBindingContext bindingContext, string name, ref bool hasValue, out string result)
{
result = null;
var valueObject = bindingContext.ValueProvider.GetValue(name);

if (valueObject != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(name, valueObject);
if (!string.IsNullOrEmpty(valueObject.FirstValue))
{
if (!Regex.IsMatch(valueObject.FirstValue, "^sh[0-9A-Za-z]{72}$"))
{
bindingContext.ModelState.TryAddModelError(name, "Invalid DAL commitment hash.");
return false;
}

hasValue = true;
result = valueObject.FirstValue;
}
}

return true;
}

public static bool TryGetDalCommitmentHashList(this ModelBindingContext bindingContext, string name, ref bool hasValue, out List<string> result)
{
result = null;
var valueObject = bindingContext.ValueProvider.GetValue(name);

if (valueObject != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(name, valueObject);
if (!string.IsNullOrEmpty(valueObject.FirstValue))
{
var rawValues = valueObject.FirstValue.Split(',', StringSplitOptions.RemoveEmptyEntries);

if (rawValues.Length == 0)
{
bindingContext.ModelState.TryAddModelError(name, "List should contain at least one item.");
return false;
}

hasValue = true;
result = new List<string>(rawValues.Length);

foreach (var rawValue in rawValues)
{
if (!Regex.IsMatch(rawValue, "^sh[0-9A-Za-z]{72}$"))
{
bindingContext.ModelState.TryAddModelError(name, "List contains invalid DAL commitment hash.");
return false;
}

result.Add(rawValue);
}
}
}

return true;
}

public static bool TryGetContractKind(this ModelBindingContext bindingContext, string name, ref bool hasValue, out int? result)
{
result = null;
Expand Down
Loading