Skip to content

Implement pallet view function queries#4722

Merged
re-gius merged 144 commits intoparitytech:masterfrom
ascjones:aj/view-functions
Jan 28, 2025
Merged

Implement pallet view function queries#4722
re-gius merged 144 commits intoparitytech:masterfrom
ascjones:aj/view-functions

Conversation

@ascjones
Copy link
Copy Markdown
Contributor

@ascjones ascjones commented Jun 6, 2024

Closes #216.

This PR allows pallets to define a view_functions impl like so:

#[pallet::view_functions]
impl<T: Config> Pallet<T>
where
	T::AccountId: From<SomeType1> + SomeAssociation1,
{
	/// Query value no args.
	pub fn get_value() -> Option<u32> {
		SomeValue::<T>::get()
	}

	/// Query value with args.
	pub fn get_value_with_arg(key: u32) -> Option<u32> {
		SomeMap::<T>::get(key)
	}
}

QueryId

Each view function is uniquely identified by a QueryId, which for this implementation is generated by:

twox_128(pallet_name) ++ twox_128("fn_name(fnarg_types) -> return_ty")

The prefix twox_128(pallet_name) is the same as the storage prefix for pallets and take into account multiple instances of the same pallet.

The suffix is generated from the fn type signature so is guaranteed to be unique for that pallet impl. For one of the view fns in the example above it would be twox_128("get_value_with_arg(u32) -> Option<u32>"). It is a known limitation that only the type names themselves are taken into account: in the case of type aliases the signature may have the same underlying types but a different id; for generics the concrete types may be different but the signatures will remain the same.

The existing Runtime Call dispatchables are addressed by their concatenated indices pallet_index ++ call_index, and the dispatching is handled by the SCALE decoding of the RuntimeCallEnum::PalletVariant(PalletCallEnum::dispatchable_variant(payload)). For view_functions the runtime/pallet generated enum structure is replaced by implementing the DispatchQuery trait on the outer (runtime) scope, dispatching to a pallet based on the id prefix, and the inner (pallet) scope dispatching to the specific function based on the id suffix.

Future implementations could also modify/extend this scheme and routing to pallet agnostic queries.

Executing externally

These view functions can be executed externally via the system runtime api:

pub trait ViewFunctionsApi<QueryId, Query, QueryResult, Error> where
	QueryId: codec::Codec,
	Query: codec::Codec,
	QueryResult: codec::Codec,
	Error: codec::Codec,
{
	/// Execute a view function query.
	fn execute_query(query_id: QueryId, query: Query) -> Result<QueryResult, Error>;
}

XCQ

Currently there is work going on by @xlc to implement XCQ which may eventually supersede this work.

It may be that we still need the fixed function local query dispatching in addition to XCQ, in the same way that we have chain specific runtime dispatchables and XCM.

I have kept this in mind and the high level query API is agnostic to the underlying query dispatch and execution. I am just providing the implementation for the view_function definition.

Metadata

Currently I am utilizing the custom section of the frame metadata, to avoid modifying the official metadata format until this is standardized.

vs runtime_api

There are similarities with runtime_apis, some differences being:

  • queries can be defined directly on pallets, so no need for boilerplate declarations and implementations
  • no versioning, the QueryId will change if the signature changes.
  • possibility for queries to be executed from smart contracts (see below)

Calling from contracts

Future work would be to add weight annotations to the view function queries, and a host function to pallet_contracts to allow executing these queries from contracts.

TODO

  • Consistent naming (view functions pallet impl, queries, high level api?)
  • End to end tests via runtime_api
  • UI tests
  • Mertadata tests
  • Docs

@ascjones ascjones deleted the aj/view-functions branch January 28, 2025 13:09
ordian added a commit that referenced this pull request Feb 3, 2025
* master:
  Remove warnings by cleaning up the `Cargo.toml` (#7416)
  [Backport] Version bumps from stable2412-1 + prdocs reorg (#7401)
  fix pre-dispatch PoV underweight for ParasInherent (#7378)
  malus-collator: implement malicious collator submitting same collation to all backing groups (#6924)
  `fatxpool`: use tracing for logging (#6897)
  Improvements for Weekly bench (#7390)
  Replace derivative dependency with derive-where (#7324)
  Add support for feature `pallet_balances/insecure_zero_ed` in benchmarks and testing (#7379)
  Fix Snowbridge benchmark tests (#7296)
  Bridges small nits/improvements (#7383)
  Migrating cumulus-pallet-session-benchmarking to Benchmarking V2  (#6564)
  [pallet-revive] implement the block author API  (#7198)
  Use checked math in frame-balances named_reserve (#7365)
  move installation of frame-omni-bencher into a cmd.py itself (#7372)
  remove old bench & revert the frame-weight-template (#7362)
  ci: fix workflow permissions (#7366)
  [net/libp2p] Use raw `Identify` observed addresses to discover external addresses (#7338)
  Improve `set_validation_data` error message. (#7359)
  Implement pallet view function queries (#4722)
@jsdw jsdw mentioned this pull request Apr 2, 2025
@Polkadot-Forum
Copy link
Copy Markdown

This pull request has been mentioned on Polkadot Forum. There might be relevant details there:

https://forum.polkadot.network/t/stabilizing-v16-metadata/12352/1

github-merge-queue bot pushed a commit that referenced this pull request Apr 17, 2025
Pallet view functions are no longer marked as experimental, and their
use is suggested starting from this PR.

Your feedback is more than welcome.

See
[docs](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.view_functions_experimental.html)
for a quick introduction. For more context, you can look at:

- #4722 
- #7412 
- #7830 : discussion on possible changes to pallet view functions

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Krayt78 pushed a commit to Krayt78/polkadot-sdk that referenced this pull request Apr 18, 2025
Pallet view functions are no longer marked as experimental, and their
use is suggested starting from this PR.

Your feedback is more than welcome.

See
[docs](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.view_functions_experimental.html)
for a quick introduction. For more context, you can look at:

- paritytech#4722 
- paritytech#7412 
- paritytech#7830 : discussion on possible changes to pallet view functions

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
castillax pushed a commit that referenced this pull request May 12, 2025
Pallet view functions are no longer marked as experimental, and their
use is suggested starting from this PR.

Your feedback is more than welcome.

See
[docs](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.view_functions_experimental.html)
for a quick introduction. For more context, you can look at:

- #4722 
- #7412 
- #7830 : discussion on possible changes to pallet view functions

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
fellowship-merge-bot bot pushed a commit to polkadot-fellows/runtimes that referenced this pull request Oct 22, 2025
FRAME "View Functions"
(paritytech/polkadot-sdk#216) support was
implemented and released in Polkadot SDK with
paritytech/polkadot-sdk#4722, but it was never
exposed on the System Chains' runtimes.

This PR adds the missing `execute_view_function()` to all System Chains'
Runtime APIs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T1-FRAME This PR/Issue is related to core FRAME, the framework. T4-runtime_API This PR/Issue is related to runtime APIs.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FRAME Core] Add support for view_functions