Skip to content

Commit 51352f1

Browse files
authored
Merge pull request #607 from Atralupus/store-blocks
Store blocks
2 parents b29dc5d + 346d492 commit 51352f1

18 files changed

Lines changed: 561 additions & 86 deletions

File tree

Lib9c.Models/Block/Action.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using MongoDB.Bson.Serialization.Attributes;
2+
3+
namespace Lib9c.Models.Block;
4+
5+
/// <summary>
6+
/// <see cref="Action"/>
7+
/// </summary>
8+
[BsonIgnoreExtraElements]
9+
public record class Action
10+
{
11+
public string Raw { get; set; }
12+
public string Inspection { get; set; }
13+
}

Lib9c.Models/Block/Block.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using MongoDB.Bson.Serialization.Attributes;
2+
3+
namespace Lib9c.Models.Block;
4+
5+
/// <summary>
6+
/// <see cref="Block"/>
7+
/// </summary>
8+
[BsonIgnoreExtraElements]
9+
public record class Block
10+
{
11+
public long Index { get; set; }
12+
public string Hash { get; set; }
13+
public string Miner { get; set; }
14+
public string StateRootHash { get; set; }
15+
public string Timestamp { get; set; }
16+
public List<Transaction> Transactions { get; set; }
17+
}

Lib9c.Models/Block/Transaction.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using MongoDB.Bson.Serialization.Attributes;
2+
3+
namespace Lib9c.Models.Block;
4+
5+
/// <summary>
6+
/// <see cref="Transaction"/>
7+
/// </summary>
8+
[BsonIgnoreExtraElements]
9+
public record class Transaction
10+
{
11+
public List<Action> Actions { get; set; }
12+
public string Id { get; set; }
13+
public long Nonce { get; set; }
14+
public string PublicKey { get; set; }
15+
public string Signature { get; set; }
16+
public string Signer { get; set; }
17+
public string Timestamp { get; set; }
18+
public List<string> UpdatedAddresses { get; set; }
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Lib9c.Models.Block;
2+
using MongoDB.Bson.Serialization.Attributes;
3+
using Newtonsoft.Json;
4+
5+
namespace Mimir.MongoDB.Bson;
6+
7+
/// <summary>
8+
/// Not MongoDB collection, it is a NineChronicles' collection state.
9+
/// </summary>
10+
/// <param name="Object"></param>
11+
[BsonIgnoreExtraElements]
12+
public record BlockDocument(
13+
[property: BsonIgnore, JsonIgnore] long StoredBlockIndex,
14+
[property: BsonIgnore, JsonIgnore] string BlockHash,
15+
Block Object
16+
) : MimirBsonDocument(BlockHash, new DocumentMetadata(1, StoredBlockIndex));

Mimir.MongoDB/CollectionNames.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ private static void RegisterCollectionAndStateMappings()
112112
CollectionAndStateTypeMappings.Add(typeof(ItemSlotDocument), "item_slot");
113113
CollectionAndStateTypeMappings.Add(typeof(InventoryDocument), "inventory");
114114
CollectionAndStateTypeMappings.Add(typeof(MetadataDocument), "metadata");
115+
CollectionAndStateTypeMappings.Add(typeof(BlockDocument), "block");
115116
CollectionAndStateTypeMappings.Add(typeof(PetStateDocument), "pet_state");
116117
CollectionAndStateTypeMappings.Add(typeof(PledgeDocument), "pledge");
117118
CollectionAndStateTypeMappings.Add(typeof(ProductsStateDocument), "products");
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Mimir.MongoDB.Bson;
2+
using Mimir.MongoDB.Exceptions;
3+
using Mimir.MongoDB.Services;
4+
using MongoDB.Driver;
5+
6+
namespace Mimir.MongoDB.Repositories;
7+
8+
public interface IBlockRepository
9+
{
10+
Task<BlockDocument> GetByIndexAsync(long index);
11+
}
12+
13+
public class BlockRepository(IMongoDbService dbService) : IBlockRepository
14+
{
15+
public async Task<BlockDocument> GetByIndexAsync(long index)
16+
{
17+
var collection = dbService.GetCollection<BlockDocument>(
18+
CollectionNames.GetCollectionName<BlockDocument>()
19+
);
20+
return await GetBlockInfoAsync(collection, index);
21+
}
22+
23+
private static async Task<BlockDocument> GetBlockInfoAsync(
24+
IMongoCollection<BlockDocument> collection,
25+
long index
26+
)
27+
{
28+
var builder = Builders<BlockDocument>.Filter;
29+
var filter = builder.Eq("Object.Index", (int)index);
30+
31+
var doc = await collection.Find(filter).FirstOrDefaultAsync();
32+
if (doc is null)
33+
{
34+
throw new DocumentNotFoundInMongoCollectionException(
35+
collection.CollectionNamespace.CollectionName,
36+
$"'index' equals to '{index}'"
37+
);
38+
}
39+
40+
return doc;
41+
}
42+
}

Mimir.Worker/Client/HeadlessGQLClient.cs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,22 @@ private string GenerateJwtToken(string secret, string issuer)
5858
string query,
5959
object? variables,
6060
CancellationToken stoppingToken = default,
61-
ILogger? contextualLogger = null
61+
ILogger? contextualLogger = null,
62+
bool useExplorer = false
6263
)
6364
{
6465
var logger = contextualLogger is null ? _logger : contextualLogger;
6566

6667
for (int attempt = 0; attempt < RetryAttempts; attempt++)
6768
{
68-
foreach (var url in _urls)
69+
foreach (var _url in _urls)
6970
{
71+
Uri url = _url;
72+
if (useExplorer)
73+
{
74+
url = new Uri(_url, "graphql/explorer");
75+
}
76+
7077
try
7178
{
7279
logger.Debug(
@@ -81,7 +88,7 @@ private string GenerateJwtToken(string secret, string issuer)
8188

8289
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, url)
8390
{
84-
Content = content
91+
Content = content,
8592
};
8693

8794
if (_secret is not null && _issuer is not null)
@@ -101,7 +108,11 @@ private string GenerateJwtToken(string secret, string issuer)
101108
jsonResponse
102109
);
103110

104-
if (graphQLResponse is null || graphQLResponse.Data is null || graphQLResponse.Errors is not null)
111+
if (
112+
graphQLResponse is null
113+
|| graphQLResponse.Data is null
114+
|| graphQLResponse.Errors is not null
115+
)
105116
{
106117
throw new HttpRequestException("Response data is null.");
107118
}
@@ -171,7 +182,7 @@ private string GenerateJwtToken(string secret, string issuer)
171182
{
172183
baseIndex,
173184
changedIndex,
174-
accountAddress
185+
accountAddress,
175186
},
176187
stoppingToken,
177188
contextualLogger
@@ -219,22 +230,45 @@ public async Task<GetTransactionsResponse> GetTransactionsAsync(
219230
blockIndex,
220231
async index =>
221232
{
222-
var (response, jsonResponse) = await PostGraphQLRequestAsync<GetTransactionsResponse>(
223-
GraphQLQueries.GetTransactions,
224-
new { blockIndex = index },
225-
stoppingToken
226-
);
233+
var (response, jsonResponse) =
234+
await PostGraphQLRequestAsync<GetTransactionsResponse>(
235+
GraphQLQueries.GetTransactions,
236+
new { blockIndex = index },
237+
stoppingToken
238+
);
227239

228240
// Validate `GetTransactionsResponse` is valid.
229-
if (response.Transaction?.NCTransactions is null ||
230-
response.Transaction.NCTransactions.Any(t => t is null || t.Actions.Any(a => a is null)))
241+
if (
242+
response.Transaction?.NCTransactions is null
243+
|| response.Transaction.NCTransactions.Any(t =>
244+
t is null || t.Actions.Any(a => a is null)
245+
)
246+
)
231247
{
232-
throw new InvalidOperationException("Invalid transactions response." +
233-
$" blockIndex: {index}" +
234-
$" response: {jsonResponse}");
248+
throw new InvalidOperationException(
249+
"Invalid transactions response."
250+
+ $" blockIndex: {index}"
251+
+ $" response: {jsonResponse}"
252+
);
235253
}
236254

237255
return response;
238-
});
256+
}
257+
);
258+
}
259+
260+
public async Task<(GetBlocksResponse response, string jsonResponse)> GetBlocksAsync(
261+
int offset,
262+
int limit,
263+
CancellationToken stoppingToken
264+
)
265+
{
266+
return await PostGraphQLRequestAsync<GetBlocksResponse>(
267+
GraphQLQueries.GetBlocks,
268+
new { offset, limit },
269+
stoppingToken,
270+
null,
271+
true
272+
);
239273
}
240274
}

Mimir.Worker/Client/IHeadlessGQLClient.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ public interface IHeadlessGQLClient
1010
Address accountAddress,
1111
CancellationToken stoppingToken
1212
);
13+
Task<(GetBlocksResponse response, string jsonResponse)> GetBlocksAsync(
14+
int offset,
15+
int limit,
16+
CancellationToken stoppingToken);
1317
Task<(GetTipResponse response, string jsonResponse)> GetTipAsync(
1418
CancellationToken stoppingToken,
1519
Address? accountAddress);

Mimir.Worker/Client/Models.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,75 @@ public class GetAccountDiffsResponse
2626
public List<AccountDiff> AccountDiffs { get; set; }
2727
}
2828

29+
public class GetBlocksResponse
30+
{
31+
[JsonPropertyName("blockQuery")]
32+
public BlockQuery BlockQuery { get; set; }
33+
}
34+
35+
public class BlockQuery
36+
{
37+
[JsonPropertyName("blocks")]
38+
public List<Block> Blocks { get; set; }
39+
}
40+
41+
public class Block
42+
{
43+
[JsonPropertyName("index")]
44+
public long Index { get; set; }
45+
46+
[JsonPropertyName("hash")]
47+
public string Hash { get; set; }
48+
49+
[JsonPropertyName("miner")]
50+
public string Miner { get; set; }
51+
52+
[JsonPropertyName("stateRootHash")]
53+
public string StateRootHash { get; set; }
54+
55+
[JsonPropertyName("timestamp")]
56+
public string Timestamp { get; set; }
57+
58+
[JsonPropertyName("transactions")]
59+
public List<BlockTransaction> Transactions { get; set; }
60+
}
61+
62+
public class BlockTransaction
63+
{
64+
[JsonPropertyName("actions")]
65+
public List<BlockAction> Actions { get; set; }
66+
67+
[JsonPropertyName("id")]
68+
public string Id { get; set; }
69+
70+
[JsonPropertyName("nonce")]
71+
public long Nonce { get; set; }
72+
73+
[JsonPropertyName("publicKey")]
74+
public string PublicKey { get; set; }
75+
76+
[JsonPropertyName("signature")]
77+
public string Signature { get; set; }
78+
79+
[JsonPropertyName("signer")]
80+
public string Signer { get; set; }
81+
82+
[JsonPropertyName("timestamp")]
83+
public string Timestamp { get; set; }
84+
85+
[JsonPropertyName("updatedAddresses")]
86+
public List<string> UpdatedAddresses { get; set; }
87+
}
88+
89+
public class BlockAction
90+
{
91+
[JsonPropertyName("raw")]
92+
public string Raw { get; set; }
93+
94+
[JsonPropertyName("inspection")]
95+
public string Inspection { get; set; }
96+
}
97+
2998
public class AccountDiff
3099
{
31100
[JsonPropertyName("path")]

Mimir.Worker/Client/Queries.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@ namespace Mimir.Worker.Client;
22

33
public static class GraphQLQueries
44
{
5+
public const string GetBlocks =
6+
@"
7+
query getBlock($offset: Int!, $limit: Int!) {
8+
blockQuery {
9+
blocks(offset: $offset, limit: $limit) {
10+
index
11+
hash
12+
miner
13+
stateRootHash
14+
timestamp
15+
transactions {
16+
actions {
17+
raw
18+
inspection
19+
}
20+
id
21+
nonce
22+
publicKey
23+
signature
24+
signer
25+
timestamp
26+
updatedAddresses
27+
}
28+
}
29+
}
30+
}";
531
public const string GetAccountDiffs =
632
@"
733
query GetAccountDiffs($baseIndex: Long!, $changedIndex: Long!, $accountAddress: Address!) {

0 commit comments

Comments
 (0)