-
Notifications
You must be signed in to change notification settings - Fork 46
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 support for on-chain notes
to the database
#300
Conversation
+ add dabase to gitignore
@@ -12,6 +12,7 @@ message Note { | |||
account.AccountId sender = 4; | |||
fixed64 tag = 5; | |||
merkle.MerklePath merkle_path = 7; | |||
optional bytes details = 8; |
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.
Can we document somewhere what details
is meant to contain and when the endpoint will return it?
I might be missing something but it seems this PR includes some changes that are also on the PR for |
We had a misunderstanding, you were right indeed. I re-based the PR on |
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.
Thank you! Looks good! I left a few comments inline. The man one is about potentially making the details
column nullable.
note_hash, | ||
sender, | ||
tag, | ||
merkle_path | ||
merkle_path, | ||
details |
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 is probably OK for now, but in the future we should refactor this. The main reason is that select_notes_since_block_by_tag_and_sender()
is used to build a sync_state
response and for this response we don't need not details. With this approach, we'd be doing a lot of unnecessary work (e.g., reading the details form the database, parsing them etc.).
Let's create an issue to address this in the future.
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.
Should I just remove the details
field from this query ?
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.
@phklive in public accounts we had the same issue and I removed this field from query and structure. I also added structure for specific endpoint for public accounts where this field is useful.
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.
To the extent of my understanding as of now I do not think that it would be wise to simply remove the details field and set all note details to None
this would be misleading. Hence I prefer to open a separate issue to refactor this flow.
Before opening the issue @bobbinth could you please clarify the reason why we would not need note details when syncing the state? I thought that we would also want to collect some new notes from the network using sync_state and that some of these notes could happen to be on-chain.
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.
To the extent of my understanding as of now I do not think that it would be wise to simply remove the details field and set all note details to
None
this would be misleading. Hence I prefer to open a separate issue to refactor this flow.
Agreed. We should have a separate struct which is like note but without details (that's how it works for accounts, I believe). And yes, we can do it in a separate PR.
Before opening the issue @bobbinth could you please clarify the reason why we would not need note details when syncing the state? I thought that we would also want to collect some new notes from the network using sync_state and that some of these notes could happen to be on-chain.
State sync could return many irrelevant notes (because we do a kind of "fuzzy" matching based on tags) and sending details for such notes could be expensive. So, the process is that with state sync we get minimal note info (Id + metadata + inclusion proofs) and if some of the notes happen to be on-chain, we can request details for them separately via the GetNotesById
endpoint (this is actually one of the main reasons why we add this endpoint).
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.
Opened issue here: #309
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.
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.
Does it not come with note metadata? If it is not there yet, we should make sure the protobuf messages include note_type
.
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.
Does it not come with note metadata? If it is not there yet, we should make sure the protobuf messages include
note_type
.
It comes with note metadata, but response of this endpoint doesn't contain note metadata.
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.
Correct, the sync endpoint specifically does not include the note type in any form.
store/src/db/sql.rs
Outdated
let details_data = row.get_ref(7)?.as_blob()?; | ||
let details = deserialize(details_data)?; |
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.
Related to the above comment: if we make column nullable and store NULL
on None
, we might need to handle this slightly differently.
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.
Does that only apply to notes or does it also apply to accounts? I have the understanding that we are not following this pattern when inserting accounts:
miden-node/store/src/db/sql.rs
Lines 159 to 214 in f5a7bd9
pub fn upsert_accounts( | |
transaction: &Transaction, | |
accounts: &[AccountUpdateDetails], | |
block_num: BlockNumber, | |
) -> Result<usize> { | |
let mut upsert_stmt = transaction.prepare( | |
"INSERT OR REPLACE INTO accounts (account_id, account_hash, block_num, details) VALUES (?1, ?2, ?3, ?4);", | |
)?; | |
let mut select_details_stmt = | |
transaction.prepare("SELECT details FROM accounts WHERE account_id = ?1;")?; | |
let mut count = 0; | |
for update in accounts.iter() { | |
let account_id = update.account_id.into(); | |
let full_account = match &update.details { | |
None => None, | |
Some(AccountDetails::Full(account)) => { | |
debug_assert!(account.is_new()); | |
debug_assert_eq!(account_id, u64::from(account.id())); | |
if account.hash() != update.final_state_hash { | |
return Err(DatabaseError::ApplyBlockFailedAccountHashesMismatch { | |
calculated: account.hash(), | |
expected: update.final_state_hash, | |
}); | |
} | |
Some(Cow::Borrowed(account)) | |
}, | |
Some(AccountDetails::Delta(delta)) => { | |
let mut rows = select_details_stmt.query(params![u64_to_value(account_id)])?; | |
let Some(row) = rows.next()? else { | |
return Err(DatabaseError::AccountNotFoundInDb(account_id)); | |
}; | |
let account = | |
apply_delta(account_id, &row.get_ref(0)?, delta, &update.final_state_hash)?; | |
Some(Cow::Owned(account)) | |
}, | |
}; | |
let inserted = upsert_stmt.execute(params![ | |
u64_to_value(account_id), | |
update.final_state_hash.to_bytes(), | |
block_num, | |
full_account.as_ref().map(|account| account.to_bytes()), | |
])?; | |
debug_assert_eq!(inserted, 1); | |
count += inserted; | |
} | |
Ok(count) | |
} |
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.
@phklive if I understood you correctly, in line 205 I process None
details as NULL
.
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.
@phklive if I understood you correctly, in line 205 I process
None
details asNULL
.
Could you clarify, how do you convert the full_account
to Null
in case there are no details? It is not fully clear to me in line 205.
Could you also please clarify why you are using Cow::Borrowed
and Cow::Owned
?
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.
how do you convert the
full_account
toNull
in case there are no details?
full_account
is actually an Option
here. Line 205 only translates account details in Some(...)
container to binary, so it becomes Some(Vec<u8>)
or None
if details is None
.
Could you also please clarify why you are using
Cow::Borrowed
andCow::Owned
?
It helps to provide owned value, as well, as borrowed. You can see that this match
in line 173 can return borrowed account in a case it was provided by transaction or load account from the database, then apply delta and return new owned account.
@phklive - how close are we to getting this reviewed/merged? |
Should be ready for review, finalized in the plane. Just arrived safely in Athens 🇬🇷 |
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.
Looks good! Thank you!
Let's make sure to create an issue to remove note details from state sync responses.
Can we merge? |
Yes we can. Opening the issue now. |
* Getting notes by id works * lint and test * Improved comments + Added conversion from digest::Digest to NoteId * Added rpc validation for NoteId's * Added documentation to Readmes * Lint * Added details field to database * Fixed ci problems * Added details to Note type * Added test for endpoint + refactored sql query + improved documentation * Fixed lint * Fixed ci with test problem * lint * Fix nit in migration + add dabase to gitignore * Order rpc and store endpoints alphabitically * Change name to database to prevent gitignore problems * generated * Changed serialized None to Null + added test * Added documentation * chore: force refresh of readme files * chore: remove duplicate GetNoteById descriptions from readme files --------- Co-authored-by: Bobbin Threadbare <bobbinth@protonmail.com>
In this PR I propose an update to the database to provide support for on-chain notes.
Closes: #288