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

refactor(transaction): Validations for transaction requests #447

Merged
merged 26 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3612c10
refactor(transactions): add transaction validation before execution
SantiagoPittella Jul 24, 2024
712c98d
move validate_transaction function call
SantiagoPittella Jul 29, 2024
a101b2b
rename function, add maybe_await
SantiagoPittella Jul 29, 2024
f13eaa1
WIP: own notes and vec for non fungibles
SantiagoPittella Jul 30, 2024
207f95f
handle script template None option
SantiagoPittella Jul 30, 2024
1830957
reorder imports
SantiagoPittella Jul 30, 2024
426385e
add missing maybe_await
SantiagoPittella Jul 30, 2024
3de71ee
add integration test for not enough balance tx, add helper for failin…
SantiagoPittella Jul 30, 2024
9336ce4
lint & format
SantiagoPittella Jul 30, 2024
b47dabb
update CHANGELOG
SantiagoPittella Jul 30, 2024
b2bd788
use matches
SantiagoPittella Jul 31, 2024
d50eca2
wip
SantiagoPittella Jul 31, 2024
850aae7
Use BTreeSet instead of Vec, functional approach
SantiagoPittella Aug 1, 2024
6d41693
remove lifetimes, refactor assets check
SantiagoPittella Aug 1, 2024
29b7bce
rollback to .to_string in test
SantiagoPittella Aug 1, 2024
65679d5
avoid vec, use getters for assets
SantiagoPittella Aug 1, 2024
1e9ea15
add faucet account validations
SantiagoPittella Aug 1, 2024
e418886
fix format
SantiagoPittella Aug 1, 2024
238e0b4
move get_{outgoing,incoming}_assets methods to tx request
SantiagoPittella Aug 2, 2024
7d53c2b
move get_{outgoing,incoming}_assets methods to transaction module
SantiagoPittella Aug 5, 2024
02c956a
fix: include unauthenticated notes in validation
SantiagoPittella Aug 5, 2024
bae3f47
remove unused error
SantiagoPittella Aug 6, 2024
303bfac
change validation methods visibility, remove validate_faucet method, …
SantiagoPittella Aug 6, 2024
f63c612
abstract asset collection in function, add comments
SantiagoPittella Aug 6, 2024
0537f21
Set build script to use miden-node's next
igamigo Aug 6, 2024
88ecd56
use unwrap_or instead of match
SantiagoPittella Aug 6, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v0.5.0 (TBD)

* Added the Web Client Crate
* Added validations in transaction requests (#447).
* [BREAKING] Refactored `Client` to merge submit_transaction and prove_transaction (#445)
* Tracked token symbols with config file (#441).
* [BREAKING] Refactored `TransactionRequest` to represent a generalized transaction (#438).
Expand Down
2 changes: 1 addition & 1 deletion crates/rust-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ miden-objects = {default-features = false, features = ["serde", "testing"], git
uuid = { version = "1.9", features = ["serde", "v4"] }

[build-dependencies]
miden-rpc-proto = { version = "0.4" }
miden-rpc-proto = { git = "https://github.com/0xPolygonMiden/miden-node/", branch = "next" }
miette = { version = "7.2", features = ["fancy"] }
prost = { version = "0.12", default-features = false, features = ["derive"] }
prost-build = { version = "0.12", default-features = false }
Expand Down
56 changes: 46 additions & 10 deletions crates/rust-client/src/rpc/tonic_client/generated/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ pub struct ApplyBlockRequest {
#[prost(bytes = "vec", tag = "1")]
pub block: ::prost::alloc::vec::Vec<u8>,
}
/// Returns a list of nullifiers that match the specified prefixes and are recorded in the node.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CheckNullifiersByPrefixRequest {
/// Number of bits used for nullifier prefix. Currently the only supported value is 16.
#[prost(uint32, tag = "1")]
pub prefix_len: u32,
/// List of nullifiers to check. Each nullifier is specified by its prefix with length equal
/// to prefix_len
#[prost(uint32, repeated, tag = "2")]
pub nullifiers: ::prost::alloc::vec::Vec<u32>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CheckNullifiersRequest {
Expand Down Expand Up @@ -47,20 +59,29 @@ pub struct SyncStateRequest {
/// it won't be included in the response.
#[prost(message, repeated, tag = "2")]
pub account_ids: ::prost::alloc::vec::Vec<super::account::AccountId>,
/// Determines the tags which the client is interested in. These are only the 16high bits of the
/// note's complete tag.
///
/// The above means it is not possible to request an specific note, but only a "note family",
/// this is done to increase the privacy of the client, by hiding the note's the client is
/// intereted on.
#[prost(uint32, repeated, tag = "3")]
/// Specifies the tags which the client is interested in.
#[prost(fixed32, repeated, tag = "3")]
pub note_tags: ::prost::alloc::vec::Vec<u32>,
/// Determines the nullifiers the client is interested in.
///
/// Similarly to the note_tags, this determins only the 16high bits of the target nullifier.
/// Determines the nullifiers the client is interested in by specifying the 16high bits of the
/// target nullifier.
#[prost(uint32, repeated, tag = "4")]
pub nullifiers: ::prost::alloc::vec::Vec<u32>,
}
/// Note synchronization request.
///
/// Specifies note tags that client is intersted in. The server will return the first block which
/// contains a note matching `note_tags` or the chain tip.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SyncNoteRequest {
/// Last block known by the client. The response will contain data starting from the next block,
/// until the first block which contains a note of matching the requested tag.
#[prost(fixed32, tag = "1")]
pub block_num: u32,
/// Specifies the tags which the client is interested in.
#[prost(fixed32, repeated, tag = "2")]
pub note_tags: ::prost::alloc::vec::Vec<u32>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetBlockInputsRequest {
Expand Down Expand Up @@ -122,3 +143,18 @@ pub struct GetBlockByNumberRequest {
#[prost(fixed32, tag = "1")]
pub block_num: u32,
}
/// Returns delta of the account states in the range from `from_block_num` (exclusive) to
/// `to_block_num` (inclusive).
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountStateDeltaRequest {
/// ID of the account for which the delta is requested.
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<super::account::AccountId>,
/// Block number from which the delta is requested (exclusive).
#[prost(fixed32, tag = "2")]
pub from_block_num: u32,
/// Block number up to which the delta is requested (inclusive).
#[prost(fixed32, tag = "3")]
pub to_block_num: u32,
}
35 changes: 35 additions & 0 deletions crates/rust-client/src/rpc/tonic_client/generated/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ pub struct CheckNullifiersResponse {
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CheckNullifiersByPrefixResponse {
/// List of nullifiers matching the prefixes specified in the request.
#[prost(message, repeated, tag = "1")]
pub nullifiers: ::prost::alloc::vec::Vec<NullifierUpdate>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetBlockHeaderByNumberResponse {
/// The requested block header
#[prost(message, optional, tag = "1")]
Expand Down Expand Up @@ -56,6 +63,27 @@ pub struct SyncStateResponse {
#[prost(message, repeated, tag = "8")]
pub nullifiers: ::prost::alloc::vec::Vec<NullifierUpdate>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SyncNoteResponse {
/// Number of the latest block in the chain
#[prost(fixed32, tag = "1")]
pub chain_tip: u32,
/// Block header of the block with the first note matching the specified criteria
#[prost(message, optional, tag = "2")]
pub block_header: ::core::option::Option<super::block_header::BlockHeader>,
/// Proof for block header's MMR with respect to the chain tip.
///
/// More specifically, the full proof consists of `forest`, `position` and `path` components. This
/// value constitutes the `path`. The other two components can be obtained as follows:
/// - `position` is simply `resopnse.block_header.block_num`
/// - `forest` is the same as `response.chain_tip + 1`
#[prost(message, optional, tag = "3")]
pub mmr_path: ::core::option::Option<super::merkle::MerklePath>,
/// List of all notes together with the Merkle paths from `response.block_header.note_root`
#[prost(message, repeated, tag = "4")]
pub notes: ::prost::alloc::vec::Vec<super::note::NoteSyncRecord>,
}
/// An account returned as a response to the GetBlockInputs
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down Expand Up @@ -170,3 +198,10 @@ pub struct GetBlockByNumberResponse {
#[prost(bytes = "vec", optional, tag = "1")]
pub block: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountStateDeltaResponse {
/// The calculated `AccountStateDelta` encoded using miden native format
#[prost(bytes = "vec", optional, tag = "1")]
pub delta: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
76 changes: 76 additions & 0 deletions crates/rust-client/src/rpc/tonic_client/generated/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,33 @@ pub mod api_client {
req.extensions_mut().insert(GrpcMethod::new("rpc.Api", "CheckNullifiers"));
self.inner.unary(req, path, codec).await
}
pub async fn check_nullifiers_by_prefix(
&mut self,
request: impl tonic::IntoRequest<
super::super::requests::CheckNullifiersByPrefixRequest,
>,
) -> std::result::Result<
tonic::Response<super::super::responses::CheckNullifiersByPrefixResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/rpc.Api/CheckNullifiersByPrefix",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("rpc.Api", "CheckNullifiersByPrefix"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_details(
&mut self,
request: impl tonic::IntoRequest<
Expand All @@ -134,6 +161,33 @@ pub mod api_client {
req.extensions_mut().insert(GrpcMethod::new("rpc.Api", "GetAccountDetails"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_state_delta(
&mut self,
request: impl tonic::IntoRequest<
super::super::requests::GetAccountStateDeltaRequest,
>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountStateDeltaResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/rpc.Api/GetAccountStateDelta",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("rpc.Api", "GetAccountStateDelta"));
self.inner.unary(req, path, codec).await
}
pub async fn get_block_by_number(
&mut self,
request: impl tonic::IntoRequest<
Expand Down Expand Up @@ -234,6 +288,28 @@ pub mod api_client {
.insert(GrpcMethod::new("rpc.Api", "SubmitProvenTransaction"));
self.inner.unary(req, path, codec).await
}
pub async fn sync_notes(
&mut self,
request: impl tonic::IntoRequest<super::super::requests::SyncNoteRequest>,
) -> std::result::Result<
tonic::Response<super::super::responses::SyncNoteResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static("/rpc.Api/SyncNotes");
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new("rpc.Api", "SyncNotes"));
self.inner.unary(req, path, codec).await
}
pub async fn sync_state(
&mut self,
request: impl tonic::IntoRequest<super::super::requests::SyncStateRequest>,
Expand Down
56 changes: 46 additions & 10 deletions crates/rust-client/src/rpc/web_tonic_client/generated/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ pub struct ApplyBlockRequest {
#[prost(bytes = "vec", tag = "1")]
pub block: ::prost::alloc::vec::Vec<u8>,
}
/// Returns a list of nullifiers that match the specified prefixes and are recorded in the node.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CheckNullifiersByPrefixRequest {
/// Number of bits used for nullifier prefix. Currently the only supported value is 16.
#[prost(uint32, tag = "1")]
pub prefix_len: u32,
/// List of nullifiers to check. Each nullifier is specified by its prefix with length equal
/// to prefix_len
#[prost(uint32, repeated, tag = "2")]
pub nullifiers: ::prost::alloc::vec::Vec<u32>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CheckNullifiersRequest {
Expand Down Expand Up @@ -47,20 +59,29 @@ pub struct SyncStateRequest {
/// it won't be included in the response.
#[prost(message, repeated, tag = "2")]
pub account_ids: ::prost::alloc::vec::Vec<super::account::AccountId>,
/// Determines the tags which the client is interested in. These are only the 16high bits of the
/// note's complete tag.
///
/// The above means it is not possible to request an specific note, but only a "note family",
/// this is done to increase the privacy of the client, by hiding the note's the client is
/// intereted on.
#[prost(uint32, repeated, tag = "3")]
/// Specifies the tags which the client is interested in.
#[prost(fixed32, repeated, tag = "3")]
pub note_tags: ::prost::alloc::vec::Vec<u32>,
/// Determines the nullifiers the client is interested in.
///
/// Similarly to the note_tags, this determins only the 16high bits of the target nullifier.
/// Determines the nullifiers the client is interested in by specifying the 16high bits of the
/// target nullifier.
#[prost(uint32, repeated, tag = "4")]
pub nullifiers: ::prost::alloc::vec::Vec<u32>,
}
/// Note synchronization request.
///
/// Specifies note tags that client is intersted in. The server will return the first block which
/// contains a note matching `note_tags` or the chain tip.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SyncNoteRequest {
/// Last block known by the client. The response will contain data starting from the next block,
/// until the first block which contains a note of matching the requested tag.
#[prost(fixed32, tag = "1")]
pub block_num: u32,
/// Specifies the tags which the client is interested in.
#[prost(fixed32, repeated, tag = "2")]
pub note_tags: ::prost::alloc::vec::Vec<u32>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetBlockInputsRequest {
Expand Down Expand Up @@ -122,3 +143,18 @@ pub struct GetBlockByNumberRequest {
#[prost(fixed32, tag = "1")]
pub block_num: u32,
}
/// Returns delta of the account states in the range from `from_block_num` (exclusive) to
/// `to_block_num` (inclusive).
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountStateDeltaRequest {
/// ID of the account for which the delta is requested.
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<super::account::AccountId>,
/// Block number from which the delta is requested (exclusive).
#[prost(fixed32, tag = "2")]
pub from_block_num: u32,
/// Block number up to which the delta is requested (inclusive).
#[prost(fixed32, tag = "3")]
pub to_block_num: u32,
}
35 changes: 35 additions & 0 deletions crates/rust-client/src/rpc/web_tonic_client/generated/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ pub struct CheckNullifiersResponse {
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CheckNullifiersByPrefixResponse {
/// List of nullifiers matching the prefixes specified in the request.
#[prost(message, repeated, tag = "1")]
pub nullifiers: ::prost::alloc::vec::Vec<NullifierUpdate>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetBlockHeaderByNumberResponse {
/// The requested block header
#[prost(message, optional, tag = "1")]
Expand Down Expand Up @@ -56,6 +63,27 @@ pub struct SyncStateResponse {
#[prost(message, repeated, tag = "8")]
pub nullifiers: ::prost::alloc::vec::Vec<NullifierUpdate>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SyncNoteResponse {
/// Number of the latest block in the chain
#[prost(fixed32, tag = "1")]
pub chain_tip: u32,
/// Block header of the block with the first note matching the specified criteria
#[prost(message, optional, tag = "2")]
pub block_header: ::core::option::Option<super::block_header::BlockHeader>,
/// Proof for block header's MMR with respect to the chain tip.
///
/// More specifically, the full proof consists of `forest`, `position` and `path` components. This
/// value constitutes the `path`. The other two components can be obtained as follows:
/// - `position` is simply `resopnse.block_header.block_num`
/// - `forest` is the same as `response.chain_tip + 1`
#[prost(message, optional, tag = "3")]
pub mmr_path: ::core::option::Option<super::merkle::MerklePath>,
/// List of all notes together with the Merkle paths from `response.block_header.note_root`
#[prost(message, repeated, tag = "4")]
pub notes: ::prost::alloc::vec::Vec<super::note::NoteSyncRecord>,
}
/// An account returned as a response to the GetBlockInputs
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down Expand Up @@ -170,3 +198,10 @@ pub struct GetBlockByNumberResponse {
#[prost(bytes = "vec", optional, tag = "1")]
pub block: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountStateDeltaResponse {
/// The calculated `AccountStateDelta` encoded using miden native format
#[prost(bytes = "vec", optional, tag = "1")]
pub delta: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
Loading