-
Notifications
You must be signed in to change notification settings - Fork 14
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
base: main
Are you sure you want to change the base?
Conversation
b758d16
to
32edfec
Compare
8f8eecc
to
7eaf605
Compare
686bcb2
to
9f4e397
Compare
de04c9f
to
8ea3d7e
Compare
There was a problem hiding this 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.
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, | ||
} |
There was a problem hiding this comment.
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?
PreparedEvent::ModuleDeployed(event) => | ||
// Only save the module into the `modules` table if the transaction was | ||
// successful. | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
PreparedEvent::ContractInitialized(event) => | ||
// Only save the contract into the `contracts` table if the transaction was | ||
// successful. | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
-- 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, |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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) => |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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:
transactions.events, | |
transactions.events[trace_element_index::INTEGER], |
fn decode_value_with_schema( | ||
opt_schema: &Option<Type>, | ||
schema_name: &str, | ||
value: &Vec<u8>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
LIMIT $3 | ||
OFFSET $4 |
There was a problem hiding this comment.
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.
Purpose
Addresses #253
Changes