Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

feat: Declare V0 RPC call #1617

Merged
merged 30 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
aa8745c
feat : added declare v0
May 26, 2024
ecf3596
feat : added declare common function
May 27, 2024
8a05ffd
feat : fixed mismatch types
May 28, 2024
d77d90a
feat : added declare v0 deps and testing done
May 31, 2024
9342f36
removed setup dir
May 31, 2024
69f2ee0
feat : removed uneccessary logs
May 31, 2024
2a7f977
added pr title in changelog
May 31, 2024
a6c9126
fix : fixed prettier issues
May 31, 2024
0d1185f
feat : added requested changes
May 31, 2024
205151f
feat : added requested changes 2
Jun 1, 2024
73a0f05
feat : added requested changes 2
Jun 1, 2024
e848d97
Merge branch 'main' into main
ocdbytes Jun 1, 2024
3c2f7ef
lint test fix
Jun 1, 2024
d8df267
lint test fix
Jun 1, 2024
3767dbb
feat : added new requested changes : formatting and redundant code re…
Jun 3, 2024
6b9615f
Merge pull request #1 from ocdbytes/declareV0/feat
ocdbytes Jun 3, 2024
840f38b
lint issue fixed
Jun 3, 2024
62b6cd9
feat : rpc test fix & declare v0 rpc test added
Jun 3, 2024
bd5dec7
feat : fixed lint issues
Jun 3, 2024
90951ee
fix declare V0 test
Jun 3, 2024
e73623e
feat : fix lint issues
Jun 3, 2024
90c7620
feat : fix lint issues
Jun 3, 2024
f7d0f59
fix : added rpc test fixes
Jun 3, 2024
96c529c
feat : refactoring and comments added
Jun 17, 2024
f68fd03
Merge branch 'main' into main
ocdbytes Jun 17, 2024
0fb2574
refactor : changed program_vec to program_bytes
Jun 19, 2024
c0e504a
add_declare_transaction_v0 e2e
tdelabro Jun 19, 2024
ee50d2d
Merge pull request #2 from tdelabro/add-declare-transaction-v0
ocdbytes Jun 19, 2024
ea34185
fix : lint
Jun 19, 2024
54033cf
feat : refactor and removed unused deps
Jun 20, 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 @@ -8,6 +8,7 @@

## v0.8.0

- feat: Declare V0 RPC call
- feat: add `TransactionFilter<TxType>` to pallet-starknet `Config`
- chore: remove `ignore` from
`storage_changes_should_revert_on_transaction_revert` test
Expand Down
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions crates/client/rpc-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod tests;

use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;
use mp_transactions::BroadcastedDeclareTransactionV0;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;

Expand Down Expand Up @@ -41,6 +42,12 @@ pub struct PredeployedAccountWithBalance {
pub trait MadaraRpcApi: StarknetReadRpcApi {
#[method(name = "predeployedAccounts")]
fn predeployed_accounts(&self) -> RpcResult<Vec<PredeployedAccountWithBalance>>;

#[method(name = "addDeclareTransactionV0")]
tdelabro marked this conversation as resolved.
Show resolved Hide resolved
async fn add_declare_transaction_v0(
&self,
params: BroadcastedDeclareTransactionV0,
) -> RpcResult<DeclareTransactionResult>;
}

/// Starknet write rpc interface.
Expand Down
1 change: 1 addition & 0 deletions crates/client/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ sc-network-sync = { workspace = true }
# Starknet
blockifier = { workspace = true }
cairo-vm = { workspace = true }
indexmap = { workspace = true }
tdelabro marked this conversation as resolved.
Show resolved Hide resolved
jsonrpsee = { workspace = true, features = ["server", "macros"] }
log = { workspace = true }
mp-block = { workspace = true }
Expand Down
85 changes: 34 additions & 51 deletions crates/client/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod constants;
mod errors;
mod events;
mod madara_backend_client;
mod madara_routes;
mod runtime_api;
pub mod starknetrpcwrapper;
mod trace_api;
Expand All @@ -17,7 +18,7 @@ use std::sync::Arc;

use blockifier::transaction::account_transaction::AccountTransaction;
use blockifier::transaction::objects::{ResourcesMapping, TransactionExecutionInfo};
use blockifier::transaction::transactions::L1HandlerTransaction;
use blockifier::transaction::transactions::{DeclareTransaction, L1HandlerTransaction};
use errors::StarknetRpcApiError;
use jsonrpsee::core::{async_trait, RpcResult};
use log::error;
Expand Down Expand Up @@ -52,7 +53,7 @@ use sp_blockchain::HeaderBackend;
use sp_core::H256;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::transaction_validity::InvalidTransaction;
use starknet_api::core::Nonce;
use starknet_api::core::{ClassHash, Nonce};
use starknet_api::hash::StarkFelt;
use starknet_api::transaction::{Calldata, Fee, TransactionHash, TransactionVersion};
use starknet_core::types::{
Expand All @@ -68,7 +69,6 @@ use starknet_core::types::{
SimulationFlagForEstimateFee, StateDiff, StateUpdate, SyncStatus, SyncStatusType, Transaction,
TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceipt,
};
use starknet_core::utils::get_selector_from_name;
use trace_api::get_previous_block_substrate_hash;

use crate::constants::{MAX_EVENTS_CHUNK_SIZE, MAX_EVENTS_KEYS};
Expand Down Expand Up @@ -220,50 +220,49 @@ where
}
}

/// Taken from https://github.com/paritytech/substrate/blob/master/client/rpc/src/author/mod.rs#L78
const TX_SOURCE: TransactionSource = TransactionSource::External;

impl<A, B, BE, G, C, P, H> MadaraRpcApiServer for Starknet<A, B, BE, G, C, P, H>
impl<A, B, BE, G, C, P, H> Starknet<A, B, BE, G, C, P, H>
where
A: ChainApi<Block = B> + 'static,
B: BlockT,
P: TransactionPool<Block = B> + 'static,
BE: Backend<B> + 'static,
C: HeaderBackend<B> + BlockBackend<B> + StorageProvider<B, BE> + 'static,
C: ProvideRuntimeApi<B>,
G: GenesisProvider + Send + Sync + 'static,
C::Api: StarknetRuntimeApi<B> + ConvertTransactionRuntimeApi<B>,
P: TransactionPool<Block = B> + 'static,
G: GenesisProvider + Send + Sync + 'static,
H: HasherT + Send + Sync + 'static,
{
fn predeployed_accounts(&self) -> RpcResult<Vec<PredeployedAccountWithBalance>> {
let genesis_data = self.genesis_provider.load_genesis_data()?;
let block_id = BlockId::Tag(BlockTag::Latest);
let fee_token_address: FieldElement = genesis_data.eth_fee_token_address.0;
async fn declare_tx_common(
&self,
txn: DeclareTransaction,
) -> Result<(TransactionHash, ClassHash), StarknetRpcApiError> {
let best_block_hash = self.get_best_block_hash();
let current_block_hash = self.get_best_block_hash();
let contract_class = self
.overrides
.for_block_hash(self.client.as_ref(), current_block_hash)
.contract_class_by_class_hash(current_block_hash, txn.class_hash());

Ok(genesis_data
.predeployed_accounts
.into_iter()
.map(|account| {
let contract_address: FieldElement = account.contract_address.into();
let balance_string = &self
.call(
FunctionCall {
contract_address: fee_token_address,
entry_point_selector: get_selector_from_name("balanceOf")
.expect("the provided method name should be a valid ASCII string."),
calldata: vec![contract_address],
},
block_id,
)
.expect("FunctionCall attributes should be correct.")[0];
let balance =
Felt252Wrapper::from_hex_be(balance_string).expect("`balanceOf` should return a Felt").into();
PredeployedAccountWithBalance { account, balance }
})
.collect::<Vec<_>>())
if let Some(contract_class) = contract_class {
log::debug!("Contract class already exists: {:?}", contract_class);
return Err(StarknetRpcApiError::ClassAlreadyDeclared);
}

let extrinsic =
self.convert_tx_to_extrinsic(best_block_hash, AccountTransaction::Declare(txn.clone())).unwrap();

let res = submit_extrinsic(self.pool.clone(), best_block_hash, extrinsic).await;

match res {
Ok(_val) => Ok((txn.tx_hash, txn.class_hash())),
Err(e) => Err(e),
}
}
}

/// Taken from https://github.com/paritytech/substrate/blob/master/client/rpc/src/author/mod.rs#L78
const TX_SOURCE: TransactionSource = TransactionSource::External;

#[async_trait]
impl<A, B, BE, G, C, P, H> StarknetWriteRpcApiServer for Starknet<A, B, BE, G, C, P, H>
where
Expand All @@ -290,8 +289,6 @@ where
&self,
declare_transaction: BroadcastedDeclareTransaction,
) -> RpcResult<DeclareTransactionResult> {
let best_block_hash = self.get_best_block_hash();

let opt_sierra_contract_class = if let BroadcastedDeclareTransaction::V2(ref tx) = declare_transaction {
Some(flattened_sierra_to_sierra_contract_class(tx.contract_class.clone()))
} else {
Expand All @@ -304,22 +301,8 @@ where
error!("Failed to convert BroadcastedDeclareTransaction to DeclareTransaction, error: {e}");
StarknetRpcApiError::InternalServerError
})?;
let (class_hash, tx_hash) = (transaction.class_hash(), transaction.tx_hash());

let current_block_hash = self.get_best_block_hash();
let contract_class = self
.overrides
.for_block_hash(self.client.as_ref(), current_block_hash)
.contract_class_by_class_hash(current_block_hash, class_hash);

if let Some(contract_class) = contract_class {
error!("Contract class already exists: {:?}", contract_class);
return Err(StarknetRpcApiError::ClassAlreadyDeclared.into());
}

let extrinsic = self.convert_tx_to_extrinsic(best_block_hash, AccountTransaction::Declare(transaction))?;

submit_extrinsic(self.pool.clone(), best_block_hash, extrinsic).await?;
let (tx_hash, class_hash) = self.declare_tx_common(transaction).await?;

if let Some(sierra_contract_class) = opt_sierra_contract_class {
if let Some(e) = self.backend.sierra_classes().store_sierra_class(class_hash, sierra_contract_class).err() {
Expand Down
86 changes: 86 additions & 0 deletions crates/client/rpc/src/madara_routes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use jsonrpsee::core::{async_trait, RpcResult};
use log::error;
use mc_genesis_data_provider::GenesisProvider;
pub use mc_rpc_core::{
Felt, MadaraRpcApiServer, PredeployedAccountWithBalance, StarknetReadRpcApiServer, StarknetTraceRpcApiServer,
StarknetWriteRpcApiServer,
};
use mp_felt::Felt252Wrapper;
use mp_hashers::HasherT;
use mp_transactions::from_broadcasted_transactions::try_declare_tx_from_broadcasted_declare_tx_v0;
use mp_transactions::BroadcastedDeclareTransactionV0;
use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi};
use sc_client_api::backend::Backend;
use sc_client_api::{BlockBackend, StorageProvider};
use sc_transaction_pool::ChainApi;
use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use starknet_core::types::{BlockId, BlockTag, DeclareTransactionResult, FieldElement, FunctionCall};
use starknet_core::utils::get_selector_from_name;

use crate::errors::StarknetRpcApiError;
use crate::Starknet;

#[async_trait]
impl<A, B, BE, G, C, P, H> MadaraRpcApiServer for Starknet<A, B, BE, G, C, P, H>
where
A: ChainApi<Block = B> + 'static,
B: BlockT,
BE: Backend<B> + 'static,
C: HeaderBackend<B> + BlockBackend<B> + StorageProvider<B, BE> + 'static,
C: ProvideRuntimeApi<B>,
G: GenesisProvider + Send + Sync + 'static,
C::Api: StarknetRuntimeApi<B> + ConvertTransactionRuntimeApi<B>,
P: TransactionPool<Block = B> + 'static,
H: HasherT + Send + Sync + 'static,
{
fn predeployed_accounts(&self) -> RpcResult<Vec<PredeployedAccountWithBalance>> {
let genesis_data = self.genesis_provider.load_genesis_data()?;
let block_id = BlockId::Tag(BlockTag::Latest);
let fee_token_address: FieldElement = genesis_data.eth_fee_token_address.0;

Ok(genesis_data
.predeployed_accounts
.into_iter()
.map(|account| {
let contract_address: FieldElement = account.contract_address.into();
let balance_string = &self
.call(
FunctionCall {
contract_address: fee_token_address,
entry_point_selector: get_selector_from_name("balanceOf")
.expect("the provided method name should be a valid ASCII string."),
calldata: vec![contract_address],
},
block_id,
)
.expect("FunctionCall attributes should be correct.")[0];
let balance =
Felt252Wrapper::from_hex_be(balance_string).expect("`balanceOf` should return a Felt").into();
PredeployedAccountWithBalance { account, balance }
})
.collect::<Vec<_>>())
}

async fn add_declare_transaction_v0(
&self,
declare_transaction: BroadcastedDeclareTransactionV0,
) -> RpcResult<DeclareTransactionResult> {
let chain_id = Felt252Wrapper(self.chain_id()?.0);

let transaction =
try_declare_tx_from_broadcasted_declare_tx_v0(declare_transaction, chain_id).map_err(|e| {
error!("Failed to convert BroadcastedDeclareTransactionV0 to DeclareTransaction, error: {e}");
StarknetRpcApiError::InternalServerError
})?;

let (tx_hash, class_hash) = self.declare_tx_common(transaction).await?;

Ok(DeclareTransactionResult {
transaction_hash: Felt252Wrapper::from(tx_hash).into(),
class_hash: Felt252Wrapper::from(class_hash).into(),
})
}
}
10 changes: 9 additions & 1 deletion crates/client/rpc/src/starknetrpcwrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub use mc_rpc_core::{
StarknetWriteRpcApiServer,
};
use mp_hashers::HasherT;
use mp_transactions::TransactionStatus;
use mp_transactions::{BroadcastedDeclareTransactionV0, TransactionStatus};
use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi};
use sc_client_api::backend::{Backend, StorageProvider};
use sc_client_api::BlockBackend;
Expand Down Expand Up @@ -36,6 +36,7 @@ impl<A: ChainApi, B: BlockT, BE, G, C, P, H> Clone for StarknetRpcWrapper<A, B,
}
}

#[async_trait]
impl<A, B, BE, G, C, P, H> MadaraRpcApiServer for StarknetRpcWrapper<A, B, BE, G, C, P, H>
where
A: ChainApi<Block = B> + 'static,
Expand All @@ -51,6 +52,13 @@ where
fn predeployed_accounts(&self) -> RpcResult<Vec<PredeployedAccountWithBalance>> {
self.0.predeployed_accounts()
}

async fn add_declare_transaction_v0(
&self,
params: BroadcastedDeclareTransactionV0,
) -> RpcResult<DeclareTransactionResult> {
self.0.add_declare_transaction_v0(params).await
}
}

#[async_trait]
Expand Down
17 changes: 17 additions & 0 deletions crates/pallets/starknet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,23 @@ pub mod pallet {

let transaction = Self::convert_runtime_calls_to_starknet_transaction(call.clone())
.map_err(|_| InvalidTransaction::Call)?;

tdelabro marked this conversation as resolved.
Show resolved Hide resolved
match transaction {
Transaction::AccountTransaction(AccountTransaction::Declare(DeclareTransaction { tx, .. }))
if tx.version() == TransactionVersion::ZERO =>
{
let sender_address: ContractAddress = Felt252Wrapper::from(tx.sender_address()).into();
let nonce: Nonce = Felt252Wrapper::from(tx.nonce()).into();

return ValidTransaction::with_tag_prefix("starknet")
.priority(u64::MAX)
.longevity(T::TransactionLongevity::get())
.propagate(true)
.and_provides((sender_address, nonce))
.build();
}
_ => {}
}
// Important to store the nonce before the call to prevalidate, because the `handle_nonce`
// function will increment it
let transaction_nonce = get_transaction_nonce(&transaction);
Expand Down
1 change: 1 addition & 0 deletions crates/pallets/starknet/src/transaction_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ impl<T: Config> Pallet<T> {
AccountTransaction::DeployAccount(tx) => tx.contract_address,
AccountTransaction::Invoke(tx) => tx.tx.sender_address(),
};

if address == sender_address
&& account_nonce == Nonce(StarkFelt::ZERO)
&& incoming_tx_nonce == Nonce(StarkFelt::ONE)
Expand Down
Loading
Loading