Skip to content

Commit

Permalink
feat(transaction): implement rpc transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammadNassar1 committed May 29, 2024
1 parent 0f49f20 commit 37a169f
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 68 deletions.
131 changes: 74 additions & 57 deletions src/external_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@
#[path = "external_transaction_test.rs"]
mod external_transaction_test;

use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use crate::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce};
use crate::data_availability::DataAvailabilityMode;
use crate::state::{EntryPoint, EntryPointType};
use crate::hash::StarkFelt;
use crate::state::EntryPoint;
use crate::transaction::{
AccountDeploymentData, Calldata, ContractAddressSalt, PaymasterData, ResourceBoundsMapping,
Tip, TransactionSignature,
AccountDeploymentData, Calldata, ContractAddressSalt, PaymasterData, ResourceBounds, Tip,
TransactionSignature,
};

/// An external transaction.
/// Transactions that are ready to be broadcasted to the network through RPC and are not included in
/// a block.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type")]
#[serde(deny_unknown_fields)]
pub enum ExternalTransaction {
/// A declare transaction.
#[serde(rename = "DECLARE")]
Declare(ExternalDeclareTransaction),
/// A deploy account transaction.
#[serde(rename = "DEPLOY_ACCOUNT")]
DeployAccount(ExternalDeployAccountTransaction),
/// An invoke transaction.
#[serde(rename = "INVOKE_FUNCTION")]
#[serde(rename = "INVOKE")]
Invoke(ExternalInvokeTransaction),
}

Expand Down Expand Up @@ -54,98 +52,117 @@ impl ExternalTransaction {
);
}

/// A declare transaction that can be added to Starknet through the Starknet gateway.
/// It has a serialization format that the Starknet gateway accepts in the `add_transaction`
/// HTTP method.
/// A RPC declare transaction.
///
/// This transaction is equivalent to the component DECLARE_TXN in the
/// [`Starknet specs`] with a contract class (DECLARE_TXN allows having
/// either a contract class or a class hash).
///
/// [`Starknet specs`]: https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "version")]
pub enum ExternalDeclareTransaction {
#[serde(rename = "0x3")]
V3(ExternalDeclareTransactionV3),
}

/// A deploy account transaction that can be added to Starknet through the Starknet gateway.
/// It has a serialization format that the Starknet gateway accepts in the `add_transaction`
/// HTTP method.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
/// A RPC deploy account transaction.
///
/// This transaction is equivalent to the component DEPLOY_ACCOUNT_TXN in the
/// [`Starknet specs`].
///
/// [`Starknet specs`]: https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(tag = "version")]
pub enum ExternalDeployAccountTransaction {
#[serde(rename = "0x3")]
V3(ExternalDeployAccountTransactionV3),
}

/// An invoke transaction that can be added to Starknet through the Starknet gateway.
/// It has a serialization format that the Starknet gateway accepts in the `add_transaction`
/// HTTP method.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
/// A RPC invoke transaction.
///
/// This transaction is equivalent to the component INVOKE_TXN in the
/// [`Starknet specs`].
///
/// [`Starknet specs`]: https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(tag = "version")]
pub enum ExternalInvokeTransaction {
#[serde(rename = "0x3")]
V3(ExternalInvokeTransactionV3),
}

/// A declare transaction of a Cairo-v1 contract class that can be added to Starknet through the
/// Starknet gateway.
/// It has a serialization format that the Starknet gateway accepts in the `add_transaction`
/// HTTP method.
/// RPC.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ExternalDeclareTransactionV3 {
// TODO: Check with Shahak why we need to keep the DeclareType.
// pub r#type: DeclareType,
pub sender_address: ContractAddress,
pub compiled_class_hash: CompiledClassHash,
pub signature: TransactionSignature,
pub nonce: Nonce,
pub contract_class: ContractClass,
pub resource_bounds: ResourceBoundsMapping,
pub tip: Tip,
pub signature: TransactionSignature,
pub nonce: Nonce,
pub compiled_class_hash: CompiledClassHash,
pub sender_address: ContractAddress,
pub nonce_data_availability_mode: DataAvailabilityMode,
pub fee_data_availability_mode: DataAvailabilityMode,
pub paymaster_data: PaymasterData,
pub account_deployment_data: AccountDeploymentData,
pub nonce_data_availability_mode: DataAvailabilityMode,
pub fee_data_availability_mode: DataAvailabilityMode,
}

/// A deploy account transaction that can be added to Starknet through the Starknet gateway.
/// It has a serialization format that the Starknet gateway accepts in the `add_transaction`
/// HTTP method.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
/// A deploy account transaction that can be added to Starknet through the RPC.
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct ExternalDeployAccountTransactionV3 {
pub resource_bounds: ResourceBoundsMapping,
pub tip: Tip,
pub contract_address_salt: ContractAddressSalt,
pub signature: TransactionSignature,
pub nonce: Nonce,
pub class_hash: ClassHash,
pub contract_address_salt: ContractAddressSalt,
pub constructor_calldata: Calldata,
pub nonce: Nonce,
pub signature: TransactionSignature,
pub resource_bounds: ResourceBoundsMapping,
pub tip: Tip,
pub paymaster_data: PaymasterData,
pub nonce_data_availability_mode: DataAvailabilityMode,
pub fee_data_availability_mode: DataAvailabilityMode,
pub paymaster_data: PaymasterData,
}

/// An invoke account transaction that can be added to Starknet through the Starknet gateway.
/// The invoke is a V3 transaction.
/// It has a serialization format that the Starknet gateway accepts in the `add_transaction`
/// HTTP method.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
/// An invoke account transaction that can be added to Starknet through the RPC.
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct ExternalInvokeTransactionV3 {
pub resource_bounds: ResourceBoundsMapping,
pub tip: Tip,
pub calldata: Calldata,
pub sender_address: ContractAddress,
pub nonce: Nonce,
pub calldata: Calldata,
pub signature: TransactionSignature,
pub nonce_data_availability_mode: DataAvailabilityMode,
pub fee_data_availability_mode: DataAvailabilityMode,
pub nonce: Nonce,
pub resource_bounds: ResourceBoundsMapping,
pub tip: Tip,
pub paymaster_data: PaymasterData,
pub account_deployment_data: AccountDeploymentData,
pub nonce_data_availability_mode: DataAvailabilityMode,
pub fee_data_availability_mode: DataAvailabilityMode,
}

// The contract class in SN_API state doesn't have `contract_class_version`, not following the spec.
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ContractClass {
#[serde(rename = "sierra_program")]
pub compressed_sierra_program: String,
pub sierra_program: Vec<StarkFelt>,
pub contract_class_version: String,
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPoint>>,
pub entry_points_by_type: EntryPointByType,
pub abi: String,
}

#[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct EntryPointByType {
#[serde(rename = "CONSTRUCTOR")]
pub constructor: Vec<EntryPoint>,
#[serde(rename = "EXTERNAL")]
pub external: Vec<EntryPoint>,
#[serde(rename = "L1_HANDLER")]
pub l1handler: Vec<EntryPoint>,
}

// The serialization of the struct in transaction is in capital letters, not following the spec.
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct ResourceBoundsMapping {
pub l1_gas: ResourceBounds,
pub l2_gas: ResourceBounds,
}
23 changes: 12 additions & 11 deletions src/external_transaction_test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::collections::BTreeMap;
use std::sync::Arc;

use rstest::rstest;
Expand All @@ -8,25 +7,26 @@ use crate::external_transaction::{
ContractClass, DataAvailabilityMode, ExternalDeclareTransaction, ExternalDeclareTransactionV3,
ExternalDeployAccountTransaction, ExternalDeployAccountTransactionV3,
ExternalInvokeTransaction, ExternalInvokeTransactionV3, ExternalTransaction,
ResourceBoundsMapping,
};
use crate::hash::{StarkFelt, StarkHash};
use crate::transaction::{
AccountDeploymentData, Calldata, ContractAddressSalt, PaymasterData, Resource, ResourceBounds,
ResourceBoundsMapping, Tip, TransactionSignature,
AccountDeploymentData, Calldata, ContractAddressSalt, PaymasterData, ResourceBounds, Tip,
TransactionSignature,
};
use crate::{contract_address, patricia_key, stark_felt};

fn create_resource_bounds() -> ResourceBoundsMapping {
let mut map = BTreeMap::new();
map.insert(Resource::L1Gas, ResourceBounds { max_amount: 100, max_price_per_unit: 12 });
map.insert(Resource::L2Gas, ResourceBounds { max_amount: 58, max_price_per_unit: 31 });
ResourceBoundsMapping(map)
fn create_resource_bounds_for_testing() -> ResourceBoundsMapping {
ResourceBoundsMapping {
l1_gas: ResourceBounds { max_amount: 100, max_price_per_unit: 12 },
l2_gas: ResourceBounds { max_amount: 58, max_price_per_unit: 31 },
}
}

fn create_declare_v3() -> ExternalDeclareTransaction {
ExternalDeclareTransaction::V3(ExternalDeclareTransactionV3 {
contract_class: ContractClass::default(),
resource_bounds: create_resource_bounds(),
resource_bounds: create_resource_bounds_for_testing(),
tip: Tip(1),
signature: TransactionSignature(vec![StarkFelt::ONE, StarkFelt::TWO]),
nonce: Nonce(stark_felt!("0x1")),
Expand All @@ -41,7 +41,7 @@ fn create_declare_v3() -> ExternalDeclareTransaction {

fn create_deploy_account_v3() -> ExternalDeployAccountTransaction {
ExternalDeployAccountTransaction::V3(ExternalDeployAccountTransactionV3 {
resource_bounds: create_resource_bounds(),
resource_bounds: create_resource_bounds_for_testing(),
tip: Tip::default(),
contract_address_salt: ContractAddressSalt(stark_felt!("0x23")),
class_hash: ClassHash(stark_felt!("0x2")),
Expand All @@ -56,7 +56,7 @@ fn create_deploy_account_v3() -> ExternalDeployAccountTransaction {

fn create_invoke_v3() -> ExternalInvokeTransaction {
ExternalInvokeTransaction::V3(ExternalInvokeTransactionV3 {
resource_bounds: create_resource_bounds(),
resource_bounds: create_resource_bounds_for_testing(),
tip: Tip(50),
calldata: Calldata(Arc::new(vec![stark_felt!("0x2000"), stark_felt!("0x1000")])),
sender_address: contract_address!("0x53"),
Expand All @@ -69,6 +69,7 @@ fn create_invoke_v3() -> ExternalInvokeTransaction {
})
}

// We are testing the `ExternalTransaction` serialization. Passing non-default values.
#[rstest]
#[case(ExternalTransaction::Declare(create_declare_v3()))]
#[case(ExternalTransaction::DeployAccount(create_deploy_account_v3()))]
Expand Down

0 comments on commit 37a169f

Please sign in to comment.