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

Add contract and module events #269

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open

Conversation

DOBEN
Copy link
Member

@DOBEN DOBEN commented Oct 15, 2024

Purpose

Addresses #253

Changes

  • Add contractEvents fields.
  • Add logic to decode input_parameter/message if an embedded smart contract schema exists.
  • Add logic to decode contract logs if an embedded smart contract schema exists.

@DOBEN DOBEN changed the base branch from main to rust-backend-modules October 15, 2024 14:59
Base automatically changed from rust-backend-modules to rust-backend October 21, 2024 17:31
Base automatically changed from rust-backend to main October 24, 2024 09:51
Copy link
Contributor

@Victor-N-Suadicani Victor-N-Suadicani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Various stylistic comments and suggestions, nothing blocking.

backend-rust/src/graphql_api.rs Show resolved Hide resolved
backend-rust/src/graphql_api.rs Show resolved Hide resolved
backend-rust/src/graphql_api.rs Show resolved Hide resolved
backend-rust/src/graphql_api.rs Show resolved Hide resolved
backend-rust/src/graphql_api.rs Show resolved Hide resolved
backend-rust/src/graphql_api.rs Show resolved Hide resolved
Comment on lines +984 to +991
struct PreparedEventData {
/// The prepared event. Note: this is optional temporarily until we can
/// handle all events.
event: Option<PreparedEvent>,
/// The status of the event (if the event belongs to a successful or
/// rejected transaction).
success: bool,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This data structure seems very strange to me.

Why not use Result<PreparedEvent, E> with some appropriate E instead of this separate success field? Can you have event: Some(e) at the same time as success: false? What about event: None and success: true? Maybe the success field should be a field on the prepared event instead of in this struct?

Comment on lines +1193 to +1196
PreparedEvent::ModuleDeployed(event) =>
// Only save the module into the `modules` table if the transaction was
// successful.
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PreparedEvent::ModuleDeployed(event) =>
// Only save the module into the `modules` table if the transaction was
// successful.
{
PreparedEvent::ModuleDeployed(event) => {
// Only save the module into the `modules` table if the transaction was
// successful.

Comment on lines +1203 to +1206
PreparedEvent::ContractInitialized(event) =>
// Only save the contract into the `contracts` table if the transaction was
// successful.
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PreparedEvent::ContractInitialized(event) =>
// Only save the contract into the `contracts` table if the transaction was
// successful.
{
PreparedEvent::ContractInitialized(event) => {
// Only save the contract into the `contracts` table if the transaction was
// successful.

Comment on lines +172 to 174
-- TODO: It would be nice to have every event in a separate row in a table to easily query a specific event from a specific transaction.
events
JSONB,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment: I am not sure that I agree to the TODO comment above. Depends a bit on our needs, and the comment here does not provide enough information to convince me 😄

There are drawbacks to having events in a separate table and for the queries that I have seen so far, this approach seems best.
PostgreSQL have pretty good support for JSON and since each transaction will have a very limited number of events, searching through all of one transaction should be fast.
But searching through all events of all transactions would probably not work out, but I don't see a need for that.

@@ -309,11 +310,47 @@ CREATE TABLE contracts(
init_transaction_index
BIGINT
NOT NULL,
-- The version of the smart contract.
version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: I think this version belongs on the module and not the contract.

event: Option<PreparedEvent>,
/// The status of the event (if the event belongs to a successful or
/// rejected transaction).
success: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request change: I don't think having this boolean is the best representation of this, since a rejected transaction would not have the same information as a successful one. Instead, we should expand the PreparedEvent enum with variants representing only the rejected cases that we care about.

PreparedEvent::AccountCreation(event) => event.save(tx).await,
// TODO: need to handle `rejected` baker events properly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment: I don't think we do.

This event represents the changes we need to do for bakers, a rejected transaction does not change anything on the state of the baker and will not result in this event

PreparedEvent::BakerEvents(events) => {
for event in events {
event.save(tx).await?;
}
Ok(())
}
PreparedEvent::ModuleDeployed(event) => event.save(tx).await,
PreparedEvent::ContractInitialized(event) => event.save(tx).await,
PreparedEvent::ModuleDeployed(event) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, I don't think we should have the event represent both a successful and rejected case.
We only need to update state for the successful case, and this event is only constructed in the successful case at the moment, since AccountTransactionEffects::None above represents all the rejected transactions

trace_element_index,
contract_events.block_height AS event_block_height,
transactions.hash as transaction_hash,
transactions.events,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: You should be able to extract the only relevant event like this:

Suggested change
transactions.events,
transactions.events[trace_element_index::INTEGER],

fn decode_value_with_schema(
opt_schema: &Option<Type>,
schema_name: &str,
value: &Vec<u8>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
value: &Vec<u8>,
value: &[u8],

amount: i64::try_from(data.amount.micro_ccd)?,
init_name: data.init_name.to_string(),
version: data.contract_version.into(),
// TODO: the send message/input parameter is missing and not exposed by the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Since this is not part of the current API, it would be a new feature and involve frontend work, so could you make it a feature request in an issue instead of this comment. The information is exposed by the SDK, just not very conveniently.

I think the smart contract page will need some work in general after the backend is ready, so it would be good to have a collection of ideas.

-- Every successful event associated to a contract.
CREATE TABLE contract_events (
-- An index/id for this event (row number).
index
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Do we ever use this index?

Comment on lines +1393 to +1394
LIMIT $3
OFFSET $4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, we will probably need to do this differently, ideally we would check this with some data and ensure that we actually are improving.

An alternative could be adding a column i, which is an index of the event for this contract, meaning skip x would result in WHERE x > i instead of the offset.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants