Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

feat: add claiming endpoint to anlytics/v2 #692

Merged
merged 3 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 41 additions & 3 deletions documentation/api/api-analytics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,24 @@ paths:
$ref: "#/components/responses/BadRequest"
"500":
$ref: "#/components/responses/InternalError"
/api/analytics/v2/activity/claimed-tokens:
get:
tags:
- activity
summary: Returns claiming activity.
description: >-
Returns the amount of tokens claimed within the specified milestone.
parameters:
- $ref: "#/components/parameters/ledgerIndex"
responses:
"200":
$ref: "#/components/responses/Claiming"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NoResults"
"500":
$ref: "#/components/responses/InternalError"
/api/analytics/v2/activity/milestones/{milestoneId}:
get:
tags:
Expand Down Expand Up @@ -406,9 +424,9 @@ components:
properties:
address:
oneOf:
- $ref: "https://raw.githubusercontent.com/iotaledger/tips/stardust-api/tips/TIP-0025/core-rest-api.yaml#/components/schemas/Ed25519Address"
- $ref: "https://raw.githubusercontent.com/iotaledger/tips/stardust-api/tips/TIP-0025/core-rest-api.yaml#/components/schemas/AliasAddress"
- $ref: "https://raw.githubusercontent.com/iotaledger/tips/stardust-api/tips/TIP-0025/core-rest-api.yaml#/components/schemas/NFTAddress"
- $ref: "https://raw.githubusercontent.com/iotaledger/tips/main/tips/TIP-0025/core-rest-api.yaml#/components/schemas/Ed25519Address"
- $ref: "https://raw.githubusercontent.com/iotaledger/tips/main/tips/TIP-0025/core-rest-api.yaml#/components/schemas/AliasAddress"
- $ref: "https://raw.githubusercontent.com/iotaledger/tips/main/tips/TIP-0025/core-rest-api.yaml#/components/schemas/NFTAddress"
balance:
type: string
description: The total balance within this range.
Expand Down Expand Up @@ -449,6 +467,14 @@ components:
- totalBalance
required:
- distribution
ClaimedTokensAnalyticsResponse:
description: Compiled statistics about claimed tokens.
properties:
count:
type: string
description: The total number of claimed tokens.
required:
- count
responses:
Output:
description: Successful operation.
Expand All @@ -468,6 +494,15 @@ components:
examples:
default:
$ref: "#/components/examples/addresses-example"
Claiming:
description: Successful operation.
content:
application/json:
schema:
$ref: "#/components/schemas/ClaimedTokensAnalyticsResponse"
examples:
default:
$ref: "#/components/examples/claiming-example"
StorageDeposit:
description: Successful operation.
content:
Expand Down Expand Up @@ -626,3 +661,6 @@ components:
addressCount: "27"
totalBalance: "25486528000"
ledgerIndex: 1005429
claiming-example:
value:
count: 567543
8 changes: 8 additions & 0 deletions src/bin/inx-chronicle/api/stardust/analytics/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,11 @@ pub struct ActivityPerInclusionStateDto {
}

impl_success_response!(MilestoneAnalyticsResponse);

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ClaimedTokensAnalyticsResponse {
pub count: String,
}

impl_success_response!(ClaimedTokensAnalyticsResponse);
19 changes: 17 additions & 2 deletions src/bin/inx-chronicle/api/stardust/analytics/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ use super::{
extractors::{LedgerIndex, MilestoneRange, RichestAddressesQuery},
responses::{
ActivityPerInclusionStateDto, ActivityPerPayloadTypeDto, AddressAnalyticsResponse, AddressStatDto,
MilestoneAnalyticsResponse, OutputAnalyticsResponse, OutputDiffAnalyticsResponse, RichestAddressesResponse,
StorageDepositAnalyticsResponse, TokenDistributionResponse,
ClaimedTokensAnalyticsResponse, MilestoneAnalyticsResponse, OutputAnalyticsResponse,
OutputDiffAnalyticsResponse, RichestAddressesResponse, StorageDepositAnalyticsResponse,
TokenDistributionResponse,
},
};
use crate::api::{error::InternalApiError, router::Router, ApiError, ApiResult};
Expand All @@ -44,6 +45,7 @@ pub fn routes() -> Router {
"/activity",
Router::new()
.route("/addresses", get(address_activity_analytics))
.route("/claimed-tokens", get(claimed_tokens_analytics))
.nest(
"/milestones",
Router::new()
Expand Down Expand Up @@ -299,3 +301,16 @@ async fn resolve_ledger_index(database: &MongoDb, ledger_index: Option<Milestone
.ok_or(ApiError::NoResults)?
})
}

async fn claimed_tokens_analytics(
database: Extension<MongoDb>,
LedgerIndex { ledger_index }: LedgerIndex,
) -> ApiResult<ClaimedTokensAnalyticsResponse> {
let res = database
.collection::<OutputCollection>()
.get_claimed_token_analytics(ledger_index)
.await?
.ok_or(ApiError::NoResults)?;

Ok(ClaimedTokensAnalyticsResponse { count: res.count })
}
39 changes: 39 additions & 0 deletions src/db/collections/outputs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,3 +863,42 @@ impl OutputCollection {
Ok(TokenDistribution { distribution })
}
}

#[derive(Clone, Debug, Default, Deserialize)]
#[allow(missing_docs)]
pub struct ClaimedTokensResult {
pub count: String,
}

impl OutputCollection {
/// Gets the number of claimed tokens.
pub async fn get_claimed_token_analytics(
&self,
index: Option<MilestoneIndex>,
) -> Result<Option<ClaimedTokensResult>, Error> {
let spent_query = match index {
Some(index) => doc! { "$eq": index },
None => doc! { "$exists": true },
};

self.aggregate(
vec![
doc! { "$match": {
"metadata.booked.milestone_index": { "$eq": 0 },
"metadata.spent_metadata.spent.milestone_index": spent_query,
} },
doc! { "$group": {
"_id": null,
"count": { "$sum": { "$toDecimal": "$output.amount" } },
} },
doc! { "$project": {
"count": { "$toString": "$count" },
} },
],
None,
)
.await?
.try_next()
.await
}
}
89 changes: 89 additions & 0 deletions tests/claiming.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

mod common;

#[cfg(feature = "rand")]
mod test_rand {

use chronicle::{
db::collections::OutputCollection,
types::{
ledger::{LedgerOutput, LedgerSpent, MilestoneIndexTimestamp, SpentMetadata},
stardust::block::{
output::{BasicOutput, OutputAmount, OutputId},
payload::TransactionId,
BlockId, Output,
},
},
};

use super::common::connect_to_test_db;

fn rand_output_with_value(amount: OutputAmount) -> Output {
// We use `BasicOutput`s in the genesis.
let mut output = BasicOutput::rand();
output.amount = amount;
Output::Basic(output)
}

#[tokio::test]
async fn test_claiming() {
let db = connect_to_test_db("test-claiming").await.unwrap();
db.clear().await.unwrap();
let collection = db.collection::<OutputCollection>();
collection.create_indexes().await.unwrap();

let unspent_outputs = (1..=5)
.map(|i| LedgerOutput {
output_id: OutputId::rand(),
output: rand_output_with_value(i.into()),
block_id: BlockId::rand(),
booked: MilestoneIndexTimestamp {
milestone_index: 0.into(),
milestone_timestamp: 0.into(),
},
})
.collect::<Vec<_>>();

collection.insert_unspent_outputs(&unspent_outputs).await.unwrap();

let spent_outputs = unspent_outputs
.into_iter()
.take(4) // we spent only the first 4 outputs
.map(|output| {
let i = output.output.amount().0;
LedgerSpent {
output,
spent_metadata: SpentMetadata {
transaction_id: TransactionId::rand(),
spent: MilestoneIndexTimestamp {
milestone_index: (i as u32).into(),
milestone_timestamp: (i as u32 + 10000).into(),
},
},
}
})
.collect::<Vec<_>>();

collection.update_spent_outputs(&spent_outputs).await.unwrap();

let total = collection
.get_claimed_token_analytics(None)
.await
.unwrap()
.unwrap()
.count;
assert_eq!(total, (1 + 2 + 3 + 4).to_string());

let third = collection
.get_claimed_token_analytics(Some(3.into()))
.await
.unwrap()
.unwrap()
.count;
assert_eq!(third, "3");

db.drop().await.unwrap();
}
}