-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add Solana Runtime API to handle state_call requests (#115)
* feat: Add solana runtime apis * feat: Implement scale feature for np-solana * fix: Rename RpcKeyedAccount to KeyedAccount * feat: Add api_version to ResponseContext and OptionalContext type * feat: Derive PartialEq and Eq for solana types * feat: Make api_version optional in ResponseContext * refactor: Consolidate runtime APIs into a single call method * feat: Expose error module in solana-runtime-api * feat: Remove SCALE codec derivation from Solana types * feat: Add error definitions for SolanaRuntimeApi * feat: Add get_balance method * feat: Add get_account_info to pallet-solana * feat: Add get_multiple_accounts to pallet-solana * feat: Integrate solana-runtime to handle RPC method calls * feat: Add handler for getProgramAccounts method * feat: Add handler for getTransactionCount method * feat: Add cfg_attr for no_std support in solana-inline-spl * refactor: Replace alloc with nostd crate for no_std environment * feat: Add handler for getFeeForMessage method * feat: Add handler for simulateTransaction method * feat: Include account_keys in simulate_transaction response * feat: Add ScanResultsLimitBytes * feat: Implement byte limit check for account scan * fix: Resolve compilation errors after rebasing onto main * refactor: Enhance readability of verify_transaction function * chore: Update sources for multiple dependencies in Cargo.toml * refactor: update transaction count mutation to use saturating_add * refactor: Merge solana-runtime and solana-runtime-api packages * refactor: Remove solana-account-decoder package
- Loading branch information
Showing
18 changed files
with
1,241 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
[package] | ||
name = "solana-runtime-api" | ||
license = "Apache-2.0" | ||
authors = { workspace = true } | ||
version = { workspace = true } | ||
edition = { workspace = true } | ||
repository = { workspace = true } | ||
publish = false | ||
|
||
[dependencies] | ||
frame-support = { workspace = true, default-features = false } | ||
nostd = { workspace = true, features = ["alloc"] } | ||
pallet-solana = { workspace = true, default-features = false } | ||
parity-scale-codec = { workspace = true, default-features = false, features = [ | ||
"derive", | ||
] } | ||
scale-info = { workspace = true, default-features = false, features = [ | ||
"derive", | ||
] } | ||
serde = { workspace = true, default-features = false } | ||
serde_json = { workspace = true, default-features = false } | ||
solana-compute-budget = { workspace = true, default-features = false } | ||
solana-inline-spl = { workspace = true, default-features = false } | ||
solana-rpc-client-api = { workspace = true, default-features = false } | ||
solana-sdk = { workspace = true, default-features = false } | ||
sp-api = { workspace = true, default-features = false } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"frame-support/std", | ||
"pallet-solana/std", | ||
"parity-scale-codec/std", | ||
"scale-info/std", | ||
"serde/std", | ||
"serde_json/std", | ||
"solana-compute-budget/std", | ||
"solana-inline-spl/std", | ||
"solana-rpc-client-api/std", | ||
"solana-sdk/std", | ||
"sp-api/std", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// This file is part of Noir. | ||
|
||
// Copyright (c) Haderech Pte. Ltd. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use crate::{error::Error, SolanaRuntimeCall}; | ||
use frame_support::traits::Get; | ||
use nostd::marker::PhantomData; | ||
use pallet_solana::Pubkey; | ||
use solana_inline_spl::token::GenericTokenAccount; | ||
use solana_rpc_client_api::filter::RpcFilterType; | ||
use solana_sdk::account::{Account, ReadableAccount}; | ||
|
||
pub struct AccountInfo<T>(PhantomData<T>); | ||
impl<T> SolanaRuntimeCall<Pubkey, Option<Account>> for AccountInfo<T> | ||
where | ||
T: pallet_solana::Config, | ||
{ | ||
fn call(pubkey: Pubkey) -> Result<Option<Account>, Error> { | ||
Ok(pallet_solana::Pallet::<T>::get_account_info(pubkey)) | ||
} | ||
} | ||
|
||
pub struct MultipleAccounts<T>(PhantomData<T>); | ||
impl<T> SolanaRuntimeCall<Vec<Pubkey>, Vec<Option<Account>>> for MultipleAccounts<T> | ||
where | ||
T: pallet_solana::Config, | ||
{ | ||
fn call(pubkeys: Vec<Pubkey>) -> Result<Vec<Option<Account>>, Error> { | ||
Ok(pubkeys | ||
.into_iter() | ||
.map(|pubkey| pallet_solana::Pallet::<T>::get_account_info(pubkey)) | ||
.collect()) | ||
} | ||
} | ||
|
||
pub struct ProgramAccounts<T>(PhantomData<T>); | ||
impl<T> SolanaRuntimeCall<(Pubkey, Vec<Pubkey>, Vec<RpcFilterType>), Vec<(Pubkey, Account)>> | ||
for ProgramAccounts<T> | ||
where | ||
T: pallet_solana::Config, | ||
{ | ||
fn call( | ||
(program_id, pubkeys, filters): (Pubkey, Vec<Pubkey>, Vec<RpcFilterType>), | ||
) -> Result<Vec<(Pubkey, Account)>, Error> { | ||
let filter_closure = |account: &Account| { | ||
filters.iter().all(|filter_type| filter_allows(filter_type, account)) | ||
}; | ||
|
||
let byte_limit_for_scan = | ||
T::ScanResultsLimitBytes::get().map(|byte_limit| byte_limit as usize); | ||
let mut sum: usize = 0; | ||
let mut accounts = Vec::new(); | ||
|
||
for pubkey in pubkeys.iter() { | ||
if let Some(account) = pallet_solana::Pallet::<T>::get_account_info(*pubkey) { | ||
if account.owner == program_id && filter_closure(&account) { | ||
if Self::accumulate_and_check_scan_result_size( | ||
&mut sum, | ||
&account, | ||
byte_limit_for_scan, | ||
) { | ||
break; | ||
} | ||
accounts.push((*pubkey, account)); | ||
} | ||
} | ||
} | ||
|
||
Ok(accounts) | ||
} | ||
} | ||
|
||
impl<T> ProgramAccounts<T> { | ||
/// Accumulate size of (pubkey + account) into sum. | ||
/// Return true if sum > 'byte_limit_for_scan' | ||
fn accumulate_and_check_scan_result_size( | ||
sum: &mut usize, | ||
account: &Account, | ||
byte_limit_for_scan: Option<usize>, | ||
) -> bool { | ||
if let Some(byte_limit) = byte_limit_for_scan { | ||
let added = Self::calc_scan_result_size(account); | ||
*sum = sum.saturating_add(added); | ||
*sum > byte_limit | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
fn calc_scan_result_size(account: &Account) -> usize { | ||
account.data().len() + std::mem::size_of::<Account>() + std::mem::size_of::<Pubkey>() | ||
} | ||
} | ||
|
||
pub fn filter_allows(filter: &RpcFilterType, account: &Account) -> bool { | ||
match filter { | ||
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size, | ||
RpcFilterType::Memcmp(compare) => compare.bytes_match(account.data()), | ||
RpcFilterType::TokenAccountState => | ||
solana_inline_spl::token_2022::Account::valid_account_data(account.data()), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// This file is part of Noir. | ||
|
||
// Copyright (c) Haderech Pte. Ltd. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use crate::{error::Error, SolanaRuntimeCall}; | ||
use nostd::marker::PhantomData; | ||
use pallet_solana::Pubkey; | ||
|
||
pub struct Balance<T>(PhantomData<T>); | ||
impl<T> SolanaRuntimeCall<Pubkey, u64> for Balance<T> | ||
where | ||
T: pallet_solana::Config, | ||
{ | ||
fn call(pubkey: Pubkey) -> Result<u64, Error> { | ||
Ok(pallet_solana::Pallet::<T>::get_balance(pubkey)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// This file is part of Noir. | ||
|
||
// Copyright (c) Haderech Pte. Ltd. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use parity_scale_codec::{Decode, Encode}; | ||
use scale_info::TypeInfo; | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] | ||
pub enum Error { | ||
ParseError, | ||
UnsupportedMethod, | ||
InvalidParams, | ||
TransactionSignatureVerificationFailure, | ||
TransactionPrecompileVerificationFailure, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// This file is part of Noir. | ||
|
||
// Copyright (c) Haderech Pte. Ltd. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use crate::{error::Error, SolanaRuntimeCall}; | ||
use nostd::marker::PhantomData; | ||
use solana_compute_budget::compute_budget_processor::process_compute_budget_instructions; | ||
use solana_sdk::{ | ||
feature_set::{ | ||
include_loaded_accounts_data_size_in_fee_calculation, remove_rounding_in_fee_calculation, | ||
FeatureSet, | ||
}, | ||
fee::FeeStructure, | ||
message::{SanitizedMessage, SanitizedVersionedMessage, SimpleAddressLoader, VersionedMessage}, | ||
reserved_account_keys::ReservedAccountKeys, | ||
}; | ||
|
||
pub struct FeeForMessage<T>(PhantomData<T>); | ||
impl<T> SolanaRuntimeCall<VersionedMessage, u64> for FeeForMessage<T> | ||
where | ||
T: pallet_solana::Config, | ||
{ | ||
fn call(message: VersionedMessage) -> Result<u64, Error> { | ||
let sanitized_versioned_message = | ||
SanitizedVersionedMessage::try_from(message).map_err(|_| Error::InvalidParams)?; | ||
// TODO: Get address_loader and reserved_account_keys | ||
let sanitized_message = SanitizedMessage::try_new( | ||
sanitized_versioned_message, | ||
SimpleAddressLoader::Disabled, | ||
&ReservedAccountKeys::empty_key_set(), | ||
) | ||
.map_err(|_| Error::InvalidParams)?; | ||
|
||
// TODO: Get fee_structure, lamports_per_signature and feature_set | ||
let fee_structure = FeeStructure::default(); | ||
let lamports_per_signature = Default::default(); | ||
let feature_set = FeatureSet::default(); | ||
|
||
Ok(fee_structure.calculate_fee( | ||
&sanitized_message, | ||
lamports_per_signature, | ||
&process_compute_budget_instructions(sanitized_message.program_instructions_iter()) | ||
.unwrap_or_default() | ||
.into(), | ||
feature_set.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()), | ||
feature_set.is_active(&remove_rounding_in_fee_calculation::id()), | ||
)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// This file is part of Noir. | ||
|
||
// Copyright (c) Haderech Pte. Ltd. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
pub mod account; | ||
pub mod balance; | ||
pub mod error; | ||
pub mod fee; | ||
pub mod transaction; | ||
|
||
use error::Error; | ||
use nostd::{string::String, vec::Vec}; | ||
use sp_api::decl_runtime_apis; | ||
|
||
decl_runtime_apis! { | ||
pub trait SolanaRuntimeApi { | ||
fn call(method: String, params: Vec<u8>) -> Result<Vec<u8>, Error>; | ||
} | ||
} | ||
|
||
pub trait SolanaRuntimeCall<I = (), O = ()> | ||
where | ||
I: for<'de> serde::Deserialize<'de> + Send + Sync, | ||
O: serde::Serialize + Send + Sync, | ||
{ | ||
fn call_raw(params: Vec<u8>) -> Result<Vec<u8>, Error> { | ||
let input: I = serde_json::from_slice(¶ms).map_err(|_| Error::ParseError)?; | ||
let output = Self::call(input)?; | ||
serde_json::to_vec(&output).map_err(|_| Error::ParseError) | ||
} | ||
|
||
fn call(input: I) -> Result<O, Error>; | ||
} |
Oops, something went wrong.