diff --git a/README.md b/README.md index 18ab09268..3adddc6db 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ ___ ### Indexer -Verify `packages/indexer/.env` with your PostgreSQL credentials and Tenderdash RPC URL, then do: +Verify `packages/indexer/.env` with your PostgreSQL credentials and Core RPC URL, Tenderdash RPC URL, then do: ```bash cd packages/indexer cargo run diff --git a/packages/api/test/utils/drop.js b/packages/api/test/utils/drop.js index 4d9aa5672..f6e8ab54c 100644 --- a/packages/api/test/utils/drop.js +++ b/packages/api/test/utils/drop.js @@ -2,7 +2,7 @@ const { getKnex } = require('../../src/utils') const knex = getKnex() -const tables = ['transfers', 'documents', 'identities', 'data_contracts', 'state_transitions', 'blocks', 'validators', 'refinery_schema_history'] +const tables = ['transfers', 'documents', 'identity_aliases', 'identities', 'data_contracts', 'state_transitions', 'blocks', 'validators', 'refinery_schema_history'] const sql = tables.reduce((acc, table) => acc + `DROP TABLE IF EXISTS ${table};`, '') diff --git a/packages/indexer/migrations/V39__add_identity_aliases.sql b/packages/indexer/migrations/V39__add_identity_aliases.sql new file mode 100644 index 000000000..c8b8a52a6 --- /dev/null +++ b/packages/indexer/migrations/V39__add_identity_aliases.sql @@ -0,0 +1,7 @@ +CREATE TABLE identity_aliases ( + id SERIAL PRIMARY KEY, + identity_identifier varchar(44) NOT NULL, + alias varchar(64) NOT NULL +); + +CREATE UNIQUE INDEX identity_aliases_alias ON identity_aliases(alias); diff --git a/packages/indexer/src/entities/identity.rs b/packages/indexer/src/entities/identity.rs index f10f2b7e3..dcc2b5319 100644 --- a/packages/indexer/src/entities/identity.rs +++ b/packages/indexer/src/entities/identity.rs @@ -9,6 +9,8 @@ use dpp::state_transition::identity_update_transition::accessors::IdentityUpdate use dpp::state_transition::identity_update_transition::IdentityUpdateTransition; use dashcore_rpc::{Auth, Client, RpcApi}; use dpp::dashcore::{Txid}; +use dpp::platform_value::string_encoding::Encoding::Base58; +use tokio_postgres::Row; #[derive(Clone)] pub struct Identity { @@ -17,7 +19,7 @@ pub struct Identity { pub owner: Identifier, pub revision: Revision, pub balance: Option, - pub is_system: bool + pub is_system: bool, } impl From for Identity { @@ -92,7 +94,26 @@ impl From for Identity { revision: 0, balance: None, is_system: true, - } + }; + } +} + +impl From for Identity { + fn from(row: Row) -> Self { + let id: i32 = row.get(0); + let owner: String = row.get(1); + let identifier: String = row.get(2); + let revision: i32 = row.get(3); + let is_system: bool = row.get(4); + + return Identity { + id: Some(id as u32), + owner: Identifier::from_string(&owner.trim(), Base58).unwrap(), + revision: Revision::from(revision as u64), + identifier: Identifier::from_string(&identifier.trim(), Base58).unwrap(), + is_system, + balance: None, + }; } } diff --git a/packages/indexer/src/processor/psql/dao/mod.rs b/packages/indexer/src/processor/psql/dao/mod.rs index 274888f0a..d79bc41ee 100644 --- a/packages/indexer/src/processor/psql/dao/mod.rs +++ b/packages/indexer/src/processor/psql/dao/mod.rs @@ -177,6 +177,23 @@ impl PostgresDAO { Ok(()) } + pub async fn create_identity_alias(&self, identity: Identity, alias: String) -> Result<(), PoolError> { + let client = self.connection_pool.get().await.unwrap(); + + let query = "INSERT INTO identity_aliases(identity_identifier,alias) VALUES ($1, $2);"; + + let stmt = client.prepare_cached(query).await.unwrap(); + + client.query(&stmt, &[ + &identity.identifier.to_string(Base58), + &alias, + ]).await.unwrap(); + + println!("Created Identity Alias {} -> {}", identity.identifier.to_string(Base58), alias); + + Ok(()) + } + pub async fn create_transfer(&self, transfer: Transfer, st_hash: String) -> Result<(), PoolError> { let amount = transfer.amount as i64; @@ -295,6 +312,26 @@ impl PostgresDAO { Ok(validators.first().cloned()) } + pub async fn get_identity_by_identifier(&self, identifier: String) -> Result, PoolError> { + let client = self.connection_pool.get().await?; + + let stmt = client.prepare_cached("SELECT id, owner, identifier, revision, \ + is_system FROM identities where identifier = $1 LIMIT 1;") + .await.unwrap(); + + let rows: Vec = client.query(&stmt, &[ + &identifier + ]).await.unwrap(); + + let identities: Vec = rows + .into_iter() + .map(|row| { + row.into() + }).collect::>(); + + Ok(identities.first().cloned()) + } + pub async fn create_validator(&self, validator: Validator) -> Result<(), PoolError> { let client = self.connection_pool.get().await.unwrap(); diff --git a/packages/indexer/src/processor/psql/mod.rs b/packages/indexer/src/processor/psql/mod.rs index c99c44dea..f6bbc28a6 100644 --- a/packages/indexer/src/processor/psql/mod.rs +++ b/packages/indexer/src/processor/psql/mod.rs @@ -1,5 +1,6 @@ mod dao; +use std::convert::identity; use std::num::ParseIntError; use dpp::state_transition::{StateTransition, StateTransitionLike}; use deadpool_postgres::{PoolError}; @@ -8,18 +9,21 @@ use crate::processor::psql::dao::PostgresDAO; use base64::{Engine as _, engine::{general_purpose}}; use data_contracts::SystemDataContract; use dpp::identifier::Identifier; -use dpp::platform_value::{platform_value, BinaryData}; +use dpp::platform_value::{platform_value, BinaryData, Value}; +use dpp::platform_value::btreemap_extensions::BTreeValueMapPathHelper; use dpp::platform_value::string_encoding::Encoding::Base58; use dpp::serialization::PlatformSerializable; use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; use dpp::state_transition::documents_batch_transition::{DocumentsBatchTransition}; use sha256::digest; use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition; +use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransitionV0Methods; use dpp::state_transition::identity_create_transition::IdentityCreateTransition; use dpp::state_transition::identity_credit_transfer_transition::IdentityCreditTransferTransition; use dpp::state_transition::identity_credit_withdrawal_transition::IdentityCreditWithdrawalTransition; use dpp::state_transition::identity_topup_transition::IdentityTopUpTransition; use dpp::state_transition::identity_update_transition::IdentityUpdateTransition; +use dpp::util::json_value::JsonValueExt; use crate::decoder::decoder::StateTransitionDecoder; use crate::entities::block::Block; use crate::entities::data_contract::DataContract; @@ -85,6 +89,43 @@ impl PSQLProcessor { for (_, document_transition) in transitions.iter().enumerate() { let document = Document::from(document_transition.clone()); + let document_type = document_transition.document_type_name(); + + if document_type == "domain" && document_transition.data_contract_id() == SystemDataContract::DPNS.id() { + let label = document_transition + .data() + .unwrap() + .get_str_at_path("label") + .unwrap(); + + let normalizedParentDomainName = document_transition + .data() + .unwrap() + .get_str_at_path("normalizedParentDomainName") + .unwrap(); + + let primary_alias = document_transition + .data() + .unwrap() + .get_optional_at_path("records.dashUniqueIdentityId").unwrap(); + + let identity_identifier = match primary_alias { + None => { + document_transition + .data() + .unwrap() + .get_optional_at_path("records.dashAliasIdentityId").unwrap() + .expect("Could not find dashAliasIdentityId") + } + Some(value) => value + }; + + let identity_identifier = Identifier::from_bytes(&identity_identifier.clone().into_identifier_bytes().unwrap()).unwrap().to_string(Base58); + let identity = self.dao.get_identity_by_identifier(identity_identifier.clone()).await.unwrap().expect(&format!("Could not find identity with identifier {}", identity_identifier)); + let alias = format!("{}.{}", label, normalizedParentDomainName); + + self.dao.create_identity_alias(identity, alias).await.unwrap(); + } self.dao.create_document(document, Some(st_hash.clone())).await.unwrap(); @@ -97,7 +138,7 @@ impl PSQLProcessor { id: None, sender: None, recipient: Some(identity.identifier), - amount: identity.balance.expect("Balance missing from identity") + amount: identity.balance.expect("Balance missing from identity"), }; self.dao.create_identity(identity, Some(st_hash.clone())).await.unwrap();