Skip to content

Commit

Permalink
feat: parse data field for provider errors (#513)
Browse files Browse the repository at this point in the history
  • Loading branch information
xJonathanLEI authored Dec 5, 2023
1 parent 4107312 commit 7b23df2
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 76 deletions.
65 changes: 62 additions & 3 deletions starknet-accounts/tests/single_owner_account.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
use rand::RngCore;
use starknet_accounts::{Account, Call, ConnectedAccount, ExecutionEncoding, SingleOwnerAccount};
use starknet_accounts::{
Account, AccountError, Call, ConnectedAccount, ExecutionEncoding, SingleOwnerAccount,
};
use starknet_core::{
chain_id,
types::{
contract::{
legacy::{LegacyContractClass, RawLegacyAbiEntry, RawLegacyFunction},
SierraClass,
},
BlockId, BlockTag, FieldElement,
BlockId, BlockTag, FieldElement, StarknetError,
},
utils::get_selector_from_name,
};
use starknet_providers::{
jsonrpc::{HttpTransport, JsonRpcClient},
Provider, SequencerGatewayProvider,
Provider, ProviderError, SequencerGatewayProvider,
};
use starknet_signers::{LocalWallet, SigningKey};
use std::sync::Arc;
Expand Down Expand Up @@ -66,6 +68,15 @@ async fn can_estimate_fee_with_jsonrpc() {
.await
}

#[tokio::test]
async fn can_parse_fee_estimation_error_with_jsonrpc() {
can_parse_fee_estimation_error_inner(
create_jsonrpc_client(),
"0x44c3c30803ea9c4e063ae052e6b7ef537284fca6b93849dae9a093e42aa1574",
)
.await
}

// The `simulate`-related test cases are temporarily removed until it's supported in [Provider]
// TODO: add `simulate` test cases back once transaction simulation in supported

Expand Down Expand Up @@ -197,6 +208,54 @@ async fn can_estimate_fee_inner<P: Provider + Send + Sync>(provider: P, address:
assert!(fee_estimate.overall_fee > 0);
}

async fn can_parse_fee_estimation_error_inner<P: Provider + Send + Sync>(
provider: P,
address: &str,
) {
let signer = LocalWallet::from(SigningKey::from_secret_scalar(
FieldElement::from_hex_be(
"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
)
.unwrap(),
));
let address = FieldElement::from_hex_be(address).unwrap();
let eth_token_address = FieldElement::from_hex_be(
"049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
)
.unwrap();

let mut account = SingleOwnerAccount::new(
provider,
signer,
address,
chain_id::TESTNET,
ExecutionEncoding::Legacy,
);
account.set_block_id(BlockId::Tag(BlockTag::Pending));

match account
.execute(vec![Call {
to: eth_token_address,
selector: get_selector_from_name("transfer").unwrap(),
calldata: vec![
address,
FieldElement::from_dec_str("1000000000000000000000").unwrap(),
FieldElement::ZERO,
],
}])
.estimate_fee()
.await
{
Ok(_) => panic!("unexpected successful fee estimation"),
Err(AccountError::Provider(ProviderError::StarknetError(
StarknetError::ContractError(err_data),
))) => {
assert!(!err_data.revert_error.is_empty());
}
_ => panic!("unexpected error type"),
}
}

async fn can_execute_tst_mint_inner<P: Provider + Send + Sync>(provider: P, address: &str) {
// This test case is not very useful as the sequencer will always respond with
// `TransactionReceived` even if the transaction will eventually fail, just like how
Expand Down
38 changes: 27 additions & 11 deletions starknet-core/src/types/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen

// Code generated with version:
// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#51260963a0723fdbc715598efb7198ce5a1d49b9
// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#bddc1b829c33b14440d22a85bc937e3d16e32ed1

// Code generation requested but not implemented for these types:
// - `BLOCK_ID`
Expand Down Expand Up @@ -241,6 +241,14 @@ pub struct CompressedLegacyContractClass {
pub abi: Option<Vec<LegacyContractAbiEntry>>,
}

/// More data about the execution failure.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
pub struct ContractErrorData {
/// A string encoding the execution trace up to the point of failure
pub revert_error: String,
}

/// Contract storage diff item.
#[serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -1007,6 +1015,14 @@ pub struct MsgToL1 {
pub payload: Vec<FieldElement>,
}

/// Extra information on why trace is not available. Either it wasn't executed yet (received), or
/// the transaction failed (rejected).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
pub struct NoTraceAvailableErrorData {
pub status: SequencerTransactionStatus,
}

/// Nonce update.
///
/// The updated nonce per contract address.
Expand Down Expand Up @@ -1305,7 +1321,7 @@ pub enum SimulationFlag {
}

/// JSON-RPC error codes
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum StarknetError {
/// Failed to write transaction
FailedToReceiveTransaction,
Expand All @@ -1328,7 +1344,7 @@ pub enum StarknetError {
/// Too many keys provided in a filter
TooManyKeysInFilter,
/// Contract error
ContractError,
ContractError(ContractErrorData),
/// Class already declared
ClassAlreadyDeclared,
/// Invalid transaction nonce
Expand All @@ -1354,9 +1370,9 @@ pub enum StarknetError {
/// the contract class version is not supported
UnsupportedContractClassVersion,
/// An unexpected error occurred
UnexpectedError,
UnexpectedError(String),
/// No trace available for transaction
NoTraceAvailable,
NoTraceAvailable(NoTraceAvailableErrorData),
/// Invalid transaction hash
InvalidTransactionHash,
}
Expand All @@ -1377,7 +1393,7 @@ impl core::fmt::Display for StarknetError {
Self::NoBlocks => write!(f, "NoBlocks"),
Self::InvalidContinuationToken => write!(f, "InvalidContinuationToken"),
Self::TooManyKeysInFilter => write!(f, "TooManyKeysInFilter"),
Self::ContractError => write!(f, "ContractError"),
Self::ContractError(_) => write!(f, "ContractError"),
Self::ClassAlreadyDeclared => write!(f, "ClassAlreadyDeclared"),
Self::InvalidTransactionNonce => write!(f, "InvalidTransactionNonce"),
Self::InsufficientMaxFee => write!(f, "InsufficientMaxFee"),
Expand All @@ -1390,8 +1406,8 @@ impl core::fmt::Display for StarknetError {
Self::CompiledClassHashMismatch => write!(f, "CompiledClassHashMismatch"),
Self::UnsupportedTxVersion => write!(f, "UnsupportedTxVersion"),
Self::UnsupportedContractClassVersion => write!(f, "UnsupportedContractClassVersion"),
Self::UnexpectedError => write!(f, "UnexpectedError"),
Self::NoTraceAvailable => write!(f, "NoTraceAvailable"),
Self::UnexpectedError(_) => write!(f, "UnexpectedError"),
Self::NoTraceAvailable(_) => write!(f, "NoTraceAvailable"),
Self::InvalidTransactionHash => write!(f, "InvalidTransactionHash"),
}
}
Expand All @@ -1410,7 +1426,7 @@ impl StarknetError {
Self::NoBlocks => "There are no blocks",
Self::InvalidContinuationToken => "The supplied continuation token is invalid or unknown",
Self::TooManyKeysInFilter => "Too many keys provided in a filter",
Self::ContractError => "Contract error",
Self::ContractError(_) => "Contract error",
Self::ClassAlreadyDeclared => "Class already declared",
Self::InvalidTransactionNonce => "Invalid transaction nonce",
Self::InsufficientMaxFee => "Max fee is smaller than the minimal transaction cost (validation plus fee transfer)",
Expand All @@ -1423,8 +1439,8 @@ impl StarknetError {
Self::CompiledClassHashMismatch => "the compiled class hash did not match the one supplied in the transaction",
Self::UnsupportedTxVersion => "the transaction version is not supported",
Self::UnsupportedContractClassVersion => "the contract class version is not supported",
Self::UnexpectedError => "An unexpected error occurred",
Self::NoTraceAvailable => "No trace available for transaction",
Self::UnexpectedError(_) => "An unexpected error occurred",
Self::NoTraceAvailable(_) => "No trace available for transaction",
Self::InvalidTransactionHash => "Invalid transaction hash",
}
}
Expand Down
61 changes: 13 additions & 48 deletions starknet-core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@ mod codegen;
pub use codegen::{
BlockStatus, BlockTag, BlockWithTxHashes, BlockWithTxs, BroadcastedDeclareTransactionV1,
BroadcastedDeclareTransactionV2, BroadcastedDeployAccountTransaction,
BroadcastedInvokeTransaction, CallType, CompressedLegacyContractClass, ContractStorageDiffItem,
DataAvailabilityMode, DeclareTransactionReceipt, DeclareTransactionTrace, DeclareTransactionV0,
DeclareTransactionV1, DeclareTransactionV2, DeclaredClassItem, DeployAccountTransaction,
DeployAccountTransactionReceipt, DeployAccountTransactionTrace, DeployTransaction,
DeployTransactionReceipt, DeployedContractItem, EmittedEvent, EntryPointType,
EntryPointsByType, Event, EventFilter, EventFilterWithPage, EventsChunk, ExecutionResources,
FeeEstimate, FlattenedSierraClass, FunctionCall, FunctionInvocation, FunctionStateMutability,
InvokeTransactionReceipt, InvokeTransactionTrace, InvokeTransactionV0, InvokeTransactionV1,
L1HandlerTransaction, L1HandlerTransactionReceipt, L1HandlerTransactionTrace,
LegacyContractEntryPoint, LegacyEntryPointsByType, LegacyEventAbiEntry, LegacyEventAbiType,
LegacyFunctionAbiEntry, LegacyFunctionAbiType, LegacyStructAbiEntry, LegacyStructAbiType,
LegacyStructMember, LegacyTypedParameter, MsgFromL1, MsgToL1, NonceUpdate, OrderedEvent,
BroadcastedInvokeTransaction, CallType, CompressedLegacyContractClass, ContractErrorData,
ContractStorageDiffItem, DataAvailabilityMode, DeclareTransactionReceipt,
DeclareTransactionTrace, DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2,
DeclaredClassItem, DeployAccountTransaction, DeployAccountTransactionReceipt,
DeployAccountTransactionTrace, DeployTransaction, DeployTransactionReceipt,
DeployedContractItem, EmittedEvent, EntryPointType, EntryPointsByType, Event, EventFilter,
EventFilterWithPage, EventsChunk, ExecutionResources, FeeEstimate, FlattenedSierraClass,
FunctionCall, FunctionInvocation, FunctionStateMutability, InvokeTransactionReceipt,
InvokeTransactionTrace, InvokeTransactionV0, InvokeTransactionV1, L1HandlerTransaction,
L1HandlerTransactionReceipt, L1HandlerTransactionTrace, LegacyContractEntryPoint,
LegacyEntryPointsByType, LegacyEventAbiEntry, LegacyEventAbiType, LegacyFunctionAbiEntry,
LegacyFunctionAbiType, LegacyStructAbiEntry, LegacyStructAbiType, LegacyStructMember,
LegacyTypedParameter, MsgFromL1, MsgToL1, NoTraceAvailableErrorData, NonceUpdate, OrderedEvent,
OrderedMessage, PendingBlockWithTxHashes, PendingBlockWithTxs,
PendingDeclareTransactionReceipt, PendingDeployAccountTransactionReceipt,
PendingInvokeTransactionReceipt, PendingL1HandlerTransactionReceipt, PendingStateUpdate,
Expand Down Expand Up @@ -516,42 +517,6 @@ impl TryFrom<&L1HandlerTransaction> for MsgToL2 {
}
}

impl TryFrom<i64> for StarknetError {
type Error = ();

fn try_from(value: i64) -> Result<Self, Self::Error> {
Ok(match value {
1 => StarknetError::FailedToReceiveTransaction,
20 => StarknetError::ContractNotFound,
24 => StarknetError::BlockNotFound,
27 => StarknetError::InvalidTransactionIndex,
28 => StarknetError::ClassHashNotFound,
29 => StarknetError::TransactionHashNotFound,
31 => StarknetError::PageSizeTooBig,
32 => StarknetError::NoBlocks,
33 => StarknetError::InvalidContinuationToken,
34 => StarknetError::TooManyKeysInFilter,
40 => StarknetError::ContractError,
51 => StarknetError::ClassAlreadyDeclared,
52 => StarknetError::InvalidTransactionNonce,
53 => StarknetError::InsufficientMaxFee,
54 => StarknetError::InsufficientAccountBalance,
55 => StarknetError::ValidationFailure,
56 => StarknetError::CompilationFailed,
57 => StarknetError::ContractClassSizeIsTooLarge,
58 => StarknetError::NonAccount,
59 => StarknetError::DuplicateTx,
60 => StarknetError::CompiledClassHashMismatch,
61 => StarknetError::UnsupportedTxVersion,
62 => StarknetError::UnsupportedContractClassVersion,
63 => StarknetError::UnexpectedError,
10 => StarknetError::NoTraceAvailable,
25 => StarknetError::InvalidTransactionHash,
_ => return Err(()),
})
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading

0 comments on commit 7b23df2

Please sign in to comment.