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

Implement DataContractUpdate state transition #61

Merged
merged 5 commits into from
Oct 6, 2023
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
22 changes: 13 additions & 9 deletions packages/api/src/controllers/DataContractsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,33 @@ class DataContractsController {
}

getDataContracts = async (request, response) => {
const dataContracts = await this.knex
.select('data_contracts.identifier as identifier')
.from('data_contracts')
.orderBy('id', 'desc')
.limit(30)
const subquery = this.knex('data_contracts')
.select(this.knex.raw('data_contracts.id as id, data_contracts.identifier as identifier, data_contracts.version as version, rank() over (partition by identifier order by version desc) rank'))
.as('data_contracts')

const rows = await this.knex(subquery)
.select('id', 'identifier', 'version', 'rank')
.where('rank', '=', 1)

response.send(dataContracts.map(dataContract => DataContract.fromJSON(dataContract)));
response.send(rows.map(dataContract => DataContract.fromJSON(dataContract)));
}

getDataContractByIdentifier = async (request, response) => {
const {identifier} = request.params

const rows = await this.knex('data_contracts')
.select('data_contracts.identifier as identifier', 'data_contracts.schema as schema')
.where('data_contracts.identifier', identifier);
.select('data_contracts.identifier as identifier', 'data_contracts.schema as schema', 'data_contracts.version as version')
.where('data_contracts.identifier', identifier)
.orderBy('id', 'desc')
.limit(1);

const [row] = rows

if (!row) {
response.status(404).send({message: 'not found'})
}

response.send({identifier: row.identifier, schema: row.schema});
response.send({identifier: row.identifier, schema: row.schema, version: row.version});
}
}

Expand Down
8 changes: 5 additions & 3 deletions packages/api/src/models/DataContract.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
module.exports = class DataContract {
identifier
version

constructor(identifier) {
constructor(identifier, version) {
this.identifier = identifier;
this.version = version;
}

static fromJSON({identifier}) {
return new DataContract(identifier)
static fromJSON({identifier, version}) {
return new DataContract(identifier, version)
}
}
1 change: 0 additions & 1 deletion packages/frontend/src/routes/block/block.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ function BlockRoute() {
const {block} = useLoaderData();

const txHashes = block?.txs || [];
console.log(block)

return (
<div className="container">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ function DataContractRoute() {
return (
<div className="container">
<div className={"data_contract_identifier"}>
Identifier: {dataContract.identifier}
<span>Identifier: {dataContract.identifier}</span>
<span>Version: {dataContract.version}</span>
</div>
<div className={"data_contract_schema"}>
{JSON.stringify(dataContract.schema, null, 2)}
Expand Down
7 changes: 7 additions & 0 deletions packages/frontend/src/routes/dataContract/data_contract.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
word-wrap: break-word;
max-width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}

.data_contract_identifier span {
padding: 10px;
}

.data_contract_schema {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ALTER TABLE data_contracts
DROP CONSTRAINT identifier_unique;

ALTER TABLE data_contracts
ADD COLUMN "version" int not null;

CREATE INDEX data_contract_id_identifier ON data_contracts(id,identifier);
63 changes: 63 additions & 0 deletions packages/indexer/src/entities/data_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::collections::BTreeMap;
use std::time::SystemTime;
use chrono::{DateTime, Utc};
use dpp::data_contract::DocumentName;
use dpp::data_contract::serialized_version::DataContractInSerializationFormat;
use dpp::identifier::Identifier;
use dpp::platform_value::string_encoding::Encoding;
use dpp::platform_value::Value;
use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition;
use dpp::state_transition::data_contract_update_transition::accessors::DataContractUpdateTransitionAccessorsV0;
use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition;
use dpp::state_transition::StateTransition;
use tokio_postgres::Row;

#[derive(Clone)]
pub struct DataContract {
pub identifier: Identifier,
pub schema: BTreeMap<DocumentName, Value>,
pub version: u32,
}

impl From<DataContractCreateTransition> for DataContract {
fn from(state_transition: DataContractCreateTransition) -> Self {

match state_transition {
DataContractCreateTransition::V0(data_contract_create_transition) => {
let data_contract = data_contract_create_transition.data_contract;

match data_contract {
DataContractInSerializationFormat::V0(data_contract) => {
let id = data_contract.id;
let version = data_contract.version;
let schema = data_contract.document_schemas;

return DataContract{ identifier: id, schema, version };
}
}
}
}
}
}

impl From<DataContractUpdateTransition> for DataContract {
fn from(state_transition: DataContractUpdateTransition) -> Self {

match state_transition {
DataContractUpdateTransition::V0(data_contract_update_transition) => {
let data_contract = data_contract_update_transition.data_contract;

match data_contract {
DataContractInSerializationFormat::V0(data_contract) => {
let id = data_contract.id;
let version = data_contract.version;
let schema = data_contract.document_schemas;

return DataContract{ identifier: id, schema, version };
}
}
}
}
}
}

1 change: 1 addition & 0 deletions packages/indexer/src/entities/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod block_header;
pub mod block;
pub mod data_contract;
1 change: 0 additions & 1 deletion packages/indexer/src/indexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ impl Indexer {

match result {
Ok(_) => {
println!("Successfully indexed block with height {}", block_height);
break;
}
Err(err) => {
Expand Down
13 changes: 8 additions & 5 deletions packages/indexer/src/processor/psql/dao/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use dpp::state_transition::data_contract_create_transition::DataContractCreateTr
use sha256::{digest};
use base64::{Engine as _, engine::{general_purpose}};
use crate::entities::block_header::BlockHeader;
use crate::entities::data_contract::DataContract;

pub struct PostgresDAO {
connection_pool: Pool,
Expand Down Expand Up @@ -45,18 +46,20 @@ impl PostgresDAO {
client.query(&stmt, &[&hash, &data, &st_type, &index, &block_hash]).await.unwrap();
}

pub async fn create_data_contract(&self, state_transition: DataContractCreateTransition) {
let id = state_transition.data_contract().id();
pub async fn create_data_contract(&self, data_contract: DataContract) {
let id = data_contract.identifier;
let id_str = id.to_string(Encoding::Base58);

let schema = state_transition.data_contract().document_schemas().clone();
let schema = data_contract.schema;
let schema_decoded = serde_json::to_value(schema).unwrap();

let query = "INSERT INTO data_contracts(identifier, schema) VALUES ($1, $2);";
let version = data_contract.version as i32;

let query = "INSERT INTO data_contracts(identifier, schema, version) VALUES ($1, $2, $3);";

let client = self.connection_pool.get().await.unwrap();
let stmt = client.prepare_cached(query).await.unwrap();
client.query(&stmt, &[&id_str, &schema_decoded]).await.unwrap();
client.query(&stmt, &[&id_str, &schema_decoded, &version]).await.unwrap();
}

pub async fn get_block_header_by_height(&self, block_height: i32) -> Result<Option<BlockHeader>, PoolError> {
Expand Down
22 changes: 18 additions & 4 deletions packages/indexer/src/processor/psql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ use dpp::state_transition::data_contract_create_transition::DataContractCreateTr
use crate::processor::psql::dao::PostgresDAO;
use base64::{Engine as _, engine::{general_purpose}};
use dpp::serialization::PlatformSerializable;
use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition;
use crate::decoder::decoder::StateTransitionDecoder;
use crate::entities::block::Block;
use crate::entities::data_contract::DataContract;

pub enum ProcessorError {
DatabaseError,
Expand Down Expand Up @@ -50,7 +52,15 @@ impl PSQLProcessor {
}

pub async fn handle_data_contract_create(&self, state_transition: DataContractCreateTransition) -> () {
self.dao.create_data_contract(state_transition).await;
let data_contract = DataContract::from(state_transition);

self.dao.create_data_contract(data_contract).await;
}

pub async fn handle_data_contract_update(&self, state_transition: DataContractUpdateTransition) -> () {
let data_contract = DataContract::from(state_transition);

self.dao.create_data_contract(data_contract).await;
}

pub async fn handle_st(&self, block_hash: String, index: i32,state_transition: StateTransition) -> () {
Expand All @@ -64,13 +74,19 @@ impl PSQLProcessor {
st.clone()
)).unwrap();

self.handle_data_contract_create(st).await
self.handle_data_contract_create(st).await;

println!("Processed DataContractCreate at block hash {}", block_hash);
}
StateTransition::DataContractUpdate(st) => {
st_type = st.state_transition_type() as i32;
bytes = PlatformSerializable::serialize_to_bytes(&StateTransition::DataContractUpdate(
st.clone()
)).unwrap();

self.handle_data_contract_update(st).await;

println!("Processed DataContractUpdate at block hash {}", block_hash);
}
StateTransition::DocumentsBatch(st) => {
st_type = st.state_transition_type() as i32;
Expand Down Expand Up @@ -135,8 +151,6 @@ impl PSQLProcessor {
let state_transition = st_result.unwrap();

self.handle_st(block_hash.clone(), i as i32, state_transition).await;

println!("Processed DataContractCreate at height {}", block_height);
}

Ok(())
Expand Down