Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parse data field for provider errors #513

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading