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 support for on-chain notes to the database #300

Merged
merged 31 commits into from
Apr 10, 2024
Merged

Conversation

phklive
Copy link
Contributor

@phklive phklive commented Apr 5, 2024

In this PR I propose an update to the database to provide support for on-chain notes.

Closes: #288

@phklive phklive marked this pull request as ready for review April 5, 2024 20:02
@phklive phklive requested review from bobbinth and hackaugusto and removed request for bobbinth and hackaugusto April 5, 2024 20:02
@phklive phklive requested review from hackaugusto, igamigo, bobbinth and polydez and removed request for hackaugusto and igamigo April 6, 2024 00:18
@@ -12,6 +12,7 @@ message Note {
account.AccountId sender = 4;
fixed64 tag = 5;
merkle.MerklePath merkle_path = 7;
optional bytes details = 8;
Copy link
Collaborator

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?

rpc/README.md Outdated Show resolved Hide resolved
@igamigo
Copy link
Collaborator

igamigo commented Apr 6, 2024

Do we want to base this PR off of phklive-get-notes-by-id?

Does that bring any issues?

These PR's are very linked. And the first PR is needed to correctly test this one.

I might be missing something but it seems this PR includes some changes that are also on the PR for phklive-get-notes-by-id, which makes it a a bit harder to tell which changes belong to this PR as opposed to the other.

@phklive phklive changed the base branch from next to phklive-get-notes-by-id April 6, 2024 21:18
@phklive
Copy link
Contributor Author

phklive commented Apr 6, 2024

Do we want to base this PR off of phklive-get-notes-by-id?

Does that bring any issues?
These PR's are very linked. And the first PR is needed to correctly test this one.

I might be missing something but it seems this PR includes some changes that are also on the PR for phklive-get-notes-by-id, which makes it a a bit harder to tell which changes belong to this PR as opposed to the other.

We had a misunderstanding, you were right indeed.

I re-based the PR on phklive-get-notes-by-id and did the same for this PR: #303

Copy link
Contributor

@bobbinth bobbinth left a 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.

node/miden-node.toml Outdated Show resolved Hide resolved
store/src/db/migrations.rs Outdated Show resolved Hide resolved
Comment on lines 376 to +380
note_hash,
sender,
tag,
merkle_path
merkle_path,
details
Copy link
Contributor

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.

Copy link
Contributor Author

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 ?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Opened issue here: #309

Copy link
Collaborator

@igamigo igamigo Apr 10, 2024

Choose a reason for hiding this comment

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

Regarding this, with the current information we get from the sync, there is no way to tell whether the note is on chain or not, so we should add that information to the response. @phklive @bobbinth @polydez

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Collaborator

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.

proto/src/domain/notes.rs Show resolved Hide resolved
store/src/db/sql.rs Outdated Show resolved Hide resolved
Comment on lines 279 to 280
let details_data = row.get_ref(7)?.as_blob()?;
let details = deserialize(details_data)?;
Copy link
Contributor

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.

Copy link
Contributor Author

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:

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)
}

Copy link
Contributor

@polydez polydez Apr 9, 2024

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.

Copy link
Contributor Author

@phklive phklive Apr 9, 2024

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.

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?

@polydez

Copy link
Contributor

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 to Null 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 and Cow::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.

Base automatically changed from phklive-get-notes-by-id to next April 8, 2024 19:51
@bobbinth
Copy link
Contributor

bobbinth commented Apr 9, 2024

@phklive - how close are we to getting this reviewed/merged?

@phklive
Copy link
Contributor Author

phklive commented Apr 9, 2024

@phklive - how close are we to getting this reviewed/merged?

Should be ready for review, finalized in the plane. Just arrived safely in Athens 🇬🇷

@phklive phklive requested review from bobbinth and igamigo April 9, 2024 22:15
Copy link
Contributor

@bobbinth bobbinth left a 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.

@Dominik1999
Copy link
Contributor

Can we merge?

@phklive
Copy link
Contributor Author

phklive commented Apr 10, 2024

Can we merge?

Yes we can. Opening the issue now.

@phklive phklive merged commit bae6864 into next Apr 10, 2024
5 checks passed
@phklive phklive deleted the phklive-db-onchain-note branch April 10, 2024 07:39
bobbinth added a commit that referenced this pull request Apr 12, 2024
* 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>
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.

5 participants