From 56ba91793ac3f83393a157fde8205b64a082fa8c Mon Sep 17 00:00:00 2001 From: firatNEAR Date: Wed, 1 Mar 2023 18:45:36 +0100 Subject: [PATCH 01/13] Broken --- .../validated_operations/delegate_action.rs | 59 ++++++++++++++++++ .../src/adapters/validated_operations/mod.rs | 1 + chain/rosetta-rpc/src/models.rs | 60 ++++++++++++++++++- 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs new file mode 100644 index 00000000000..fe2a8502dfb --- /dev/null +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -0,0 +1,59 @@ +use super::ValidatedOperation; + +pub(crate) struct DelegateActionOperation { + pub(crate) account: crate::models::AccountIdentifier, + pub(crate) operations: Vec, + pub(crate) max_block_height: near_primitives::types::BlockHeight, + pub(crate) public_key: crate::models::PublicKey, +} + +impl ValidatedOperation for DelegateActionOperation { + const OPERATION_TYPE: crate::models::OperationType = + crate::models::OperationType::DelegateAction; + + fn into_operation( + self, + operation_identifier: crate::models::OperationIdentifier, + ) -> crate::models::Operation { + crate::models::Operation { + operation_identifier, + + account: self.account, + amount: None, + metadata: Some(crate::models::OperationMetadata { + public_key: Some(self.public_key), + max_block_height: Some(self.max_block_height), + ..Default::default() + }), + + related_operations: None, + type_: Self::OPERATION_TYPE, + status: None, + } + } +} +fn required_fields_error() -> crate::errors::ErrorKind { + crate::errors::ErrorKind::InvalidInput( + "DELEGATE_ACTION operation requires `public_key`, 'max_block_height' being passed in the metadata".into(), + ) +} +impl TryFrom for DelegateActionOperation { + type Error = crate::errors::ErrorKind; + + fn try_from(operation: crate::models::Operation) -> Result { + Self::validate_operation_type(operation.type_)?; + let metadata = operation.metadata.ok_or_else(required_fields_error)?; + let public_key = metadata.public_key.ok_or_else(required_fields_error)?; + let max_block_height = metadata.max_block_height.ok_or_else(required_fields_error)?; + + Ok(Self { account: operation.account, public_key, max_block_height }) + } +} + +pub struct NonDelegateActionOperation(crate::models::Operation); + +impl From for crate::models::Operation { + fn from(action: NonDelegateActionOperation) -> Self { + action.0 + } +} diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs b/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs index 1d1d7214bf1..f4a44ce49ec 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs @@ -29,6 +29,7 @@ mod initiate_function_call; mod refund_delete_account; mod stake; mod transfer; +pub mod delegate_action; pub(crate) trait ValidatedOperation: TryFrom diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index e14cc10c286..5d7a7bf54fd 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -709,6 +709,7 @@ pub(crate) enum OperationType { CreateAccount, InitiateDeleteAccount, DeleteAccount, + DelegateAction, RefundDeleteAccount, InitiateAddKey, AddKey, @@ -763,7 +764,7 @@ pub(crate) struct OperationMetadata { /// Has to be specified for TRANSFER operations which represent gas prepayments or gas refunds #[serde(skip_serializing_if = "Option::is_none")] pub transfer_fee_type: Option, - /// Has to be specified for ADD_KEY, REMOVE_KEY, and STAKE operations + /// Has to be specified for ADD_KEY, REMOVE_KEY, DELEGATE_ACTION and STAKE operations #[serde(skip_serializing_if = "Option::is_none")] pub public_key: Option, // /// Has to be specified for ADD_KEY @@ -785,6 +786,12 @@ pub(crate) struct OperationMetadata { pub attached_gas: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub predecessor_id: Option, + /// Has to be specified for DELEGATE_ACTION operation + #[serde(skip_serializing_if = "Option::is_none")] + pub max_block_height: Option, + /// Has to be specified for DELEGATE_ACTION operation + #[serde(skip_serializing_if = "Option::is_none")] + pub operations: Option, } impl OperationMetadata { @@ -843,6 +850,57 @@ pub(crate) struct Operation { #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option, } +/// A small private module to protect the private fields inside `NonDelegateAction`. +mod private_non_delegate_action { + use super::*; + + /// This is Action which mustn't contain DelegateAction. + /// + /// This struct is needed to avoid the recursion when Action/DelegateAction is deserialized. + /// + /// Important: Don't make the inner Action public, this must only be constructed + /// through the correct interface that ensures the inner Action is actually not + /// a delegate action. That would break an assumption of this type, which we use + /// in several places. For example, borsh de-/serialization relies on it. If the + /// invariant is broken, we may end up with a `Transaction` or `Receipt` that we + /// can serialize but deserializing it back causes a parsing error. + #[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Debug)] + pub struct NonDelegateActionOperation(Operation); + + impl From for Operation { + fn from(action: NonDelegateActionOperation) -> Self { + action.0 + } + } + + #[derive(Debug, thiserror::Error)] + #[error("attempted to construct NonDelegateAction from Action::Delegate")] + pub struct IsDelegateOperation; + + impl TryFrom for NonDelegateActionOperation { + type Error = IsDelegateOperation; + + fn try_from(action: Operation) -> Result { + if matches!(action.type_, DelegateAction) { + Err(IsDelegateOperation) + } else { + Ok(Self(action)) + } + } + } + + // fn deserialize_reader( + // rd: &mut R, + // ) -> ::core::result::Result { + // match u8::deserialize_reader(rd)? { + // ACTION_DELEGATE_NUMBER => Err(Error::new( + // ErrorKind::InvalidInput, + // "DelegateAction mustn't contain a nested one", + // )), + // n => borsh::de::EnumExt::deserialize_variant(rd, n).map(Self), + // } + // } +} /// The operation_identifier uniquely identifies an operation within a /// transaction. From 22e12ef4b87b1c0c0ade90d9ce5eb03aaa0daf9a Mon Sep 17 00:00:00 2001 From: firatNEAR Date: Wed, 8 Mar 2023 11:33:27 +0100 Subject: [PATCH 02/13] Broken commit for rosetta runtime mapping --- chain/rosetta-rpc/src/adapters/mod.rs | 116 +++++++++++++++- .../validated_operations/delegate_action.rs | 41 ++++-- .../initiate_delegate_action.rs | 36 +++++ .../intitiate_signed_delegate_action.rs | 36 +++++ .../src/adapters/validated_operations/mod.rs | 7 +- .../signed_delegate_action.rs | 47 +++++++ chain/rosetta-rpc/src/models.rs | 124 +++++++++++------- 7 files changed, 348 insertions(+), 59 deletions(-) create mode 100644 chain/rosetta-rpc/src/adapters/validated_operations/initiate_delegate_action.rs create mode 100644 chain/rosetta-rpc/src/adapters/validated_operations/intitiate_signed_delegate_action.rs create mode 100644 chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 6ce148bc197..207442608f0 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -2,8 +2,15 @@ use actix::Addr; use near_chain_configs::Genesis; use near_client::ViewClientActor; use near_o11y::WithSpanContextExt; +use near_primitives::borsh::BorshSerialize; use validated_operations::ValidatedOperation; +use crate::utils::BlobInHexString; + +use self::validated_operations::{ + initiate_delegate_action, intitiate_signed_delegate_action, signed_delegate_action, +}; + mod transactions; mod validated_operations; @@ -419,8 +426,55 @@ impl From for Vec { ); operations.push(deploy_contract_operation); } - // TODO(#8469): Implement delegate action support, for now they are ignored. - near_primitives::transaction::Action::Delegate(_) => (), + near_primitives::transaction::Action::Delegate(action) => { + let intitiate_signed_delegate_action_operation_id = + crate::models::OperationIdentifier::new(&operations); + operations.push( + validated_operations::InitiateSignedDelegateActionOperation { + sender_account: sender_account_identifier.clone(), + } + .into_operation(intitiate_signed_delegate_action_operation_id.clone()), + ); + + let hex_bytes: BlobInHexString> = action + .delegate_action + .clone() + .try_to_vec() + .expect("Failed to deseralize") + .into(); + let singing_payload = crate::models::SigningPayload { + account_identifier: action.delegate_action.clone().sender_id.into(), + signature_type: Some(action.signature.key_type().into()), + hex_bytes: hex_bytes.clone(), + }; + let signed_delegate_action_operation_id = + crate::models::OperationIdentifier::new(&operations); + + operations.push(validated_operations::signed_delegate_action::SignedDelegateActionOperation { + receiver_id: receiver_account_identifier.clone(), + signature : crate::models::Signature::from_signature(action.signature, (&action.delegate_action.public_key.clone()).into(), singing_payload, hex_bytes) + }.into_related_operation( + signed_delegate_action_operation_id.clone(), + vec![intitiate_signed_delegate_action_operation_id], + )); + + let initiate_delegate_action_operation_id = + crate::models::OperationIdentifier::new(&operations); + + operations.push(validated_operations::initiate_delegate_action::InitiateDelegateActionOperation{ + sender_account: action.delegate_action.clone().sender_id.into() + }.into_related_operation(initiate_delegate_action_operation_id.clone(), vec![signed_delegate_action_operation_id])); + + let delegate_action_operation_id = + crate::models::OperationIdentifier::new(&operations); + let delegate_action_operation: validated_operations::DelegateActionOperation = + action.delegate_action.clone().into(); + + operations.push(delegate_action_operation.into_related_operation( + delegate_action_operation_id, + vec![initiate_delegate_action_operation_id], + )) + } // TODO(#8469): Implement delegate action support, for now they are ignored. } } operations @@ -639,7 +693,6 @@ impl TryFrom> for NearActions { } sender_account_id.try_set(&transfer_operation.account)?; } - actions.push( near_primitives::transaction::FunctionCallAction { method_name: function_call_operation.method_name, @@ -650,13 +703,53 @@ impl TryFrom> for NearActions { .into(), ) } + crate::models::OperationType::SignedDelegateAction => { + let delegate_action_operation = + validated_operations::delegate_action::DelegateActionOperation::try_from( + tail_operation, + )?; + let initiate_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from(tail_operation)?; + + let signed_delegate_action_operation = validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from(tail_operation)?; + receiver_account_id.try_set(&signed_delegate_action_operation.receiver_id)?; + + let intitiate_signed_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from_option(operations.next())?; + sender_account_id + .try_set(&intitiate_signed_delegate_action_operation.sender_account)?; + actions.push( + near_primitives::delegate_action::SignedDelegateAction { + delegate_action: near_primitives::delegate_action::DelegateAction { + sender_id: initiate_delegate_action_operation + .sender_account + .address + .parse() + .unwrap(), + receiver_id: delegate_action_operation + .receiver_id + .address + .parse() + .unwrap(), + actions: delegate_action_operation.operations, + nonce: delegate_action_operation.nonce, + max_block_height: delegate_action_operation.max_block_height, + public_key: delegate_action_operation.public_key.into(), + }, + signature: signed_delegate_action_operation.signature.into(), + } + .into(), + ) + } + // crate::models::OperationType::SignedDelegateAction crate::models::OperationType::InitiateCreateAccount | crate::models::OperationType::InitiateDeleteAccount | crate::models::OperationType::InitiateAddKey | crate::models::OperationType::InitiateDeleteKey | crate::models::OperationType::InitiateDeployContract | crate::models::OperationType::InitiateFunctionCall + | crate::models::OperationType::DelegateAction + | crate::models::OperationType::InitiateSignedDelegateAction + | crate::models::OperationType::InitiateDelegateAction | crate::models::OperationType::DeleteAccount => { return Err(crate::errors::ErrorKind::InvalidInput(format!( "Unexpected operation `{:?}`", @@ -956,6 +1049,23 @@ mod tests { } } + #[test] + fn test_near_actions_invalid_signed_delegate_function() { + let operations = vec![crate::models::Operation { + type_: crate::models::OperationType::SignedDelegateAction, + account: "sender.near".parse().unwrap(), + amount: None, + operation_identifier: crate::models::OperationIdentifier::new(&[]), + related_operations: None, + status: None, + metadata: None, + }]; + assert!(matches!( + NearActions::try_from(operations), + Err(crate::errors::ErrorKind::InvalidInput(_)) + )); + } + #[test] fn test_near_actions_invalid_transfer_no_amount() { let operations = vec![crate::models::Operation { diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs index fe2a8502dfb..c7dbc63a9b6 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -1,10 +1,11 @@ use super::ValidatedOperation; pub(crate) struct DelegateActionOperation { - pub(crate) account: crate::models::AccountIdentifier, - pub(crate) operations: Vec, + pub(crate) receiver_id: crate::models::AccountIdentifier, + pub(crate) operations: Vec, pub(crate) max_block_height: near_primitives::types::BlockHeight, pub(crate) public_key: crate::models::PublicKey, + pub(crate) nonce: near_primitives::types::Nonce, } impl ValidatedOperation for DelegateActionOperation { @@ -18,11 +19,13 @@ impl ValidatedOperation for DelegateActionOperation { crate::models::Operation { operation_identifier, - account: self.account, + account: self.receiver_id, amount: None, metadata: Some(crate::models::OperationMetadata { public_key: Some(self.public_key), max_block_height: Some(self.max_block_height), + operations: Some(self.operations), + nonce: Some(self.nonce), ..Default::default() }), @@ -34,7 +37,7 @@ impl ValidatedOperation for DelegateActionOperation { } fn required_fields_error() -> crate::errors::ErrorKind { crate::errors::ErrorKind::InvalidInput( - "DELEGATE_ACTION operation requires `public_key`, 'max_block_height' being passed in the metadata".into(), + "DELEGATE_ACTION operation requires `public_key`, 'max_block_height' and 'operations' being passed in the metadata".into(), ) } impl TryFrom for DelegateActionOperation { @@ -45,15 +48,33 @@ impl TryFrom for DelegateActionOperation { let metadata = operation.metadata.ok_or_else(required_fields_error)?; let public_key = metadata.public_key.ok_or_else(required_fields_error)?; let max_block_height = metadata.max_block_height.ok_or_else(required_fields_error)?; + let nonce = metadata.nonce.ok_or_else(required_fields_error)?; + let operations = metadata.operations.ok_or_else(required_fields_error)?; - Ok(Self { account: operation.account, public_key, max_block_height }) + Ok(Self { receiver_id: operation.account, public_key, max_block_height, operations, nonce }) } } -pub struct NonDelegateActionOperation(crate::models::Operation); - -impl From for crate::models::Operation { - fn from(action: NonDelegateActionOperation) -> Self { - action.0 +impl From for DelegateActionOperation { + fn from(delegate_action: near_primitives::delegate_action::DelegateAction) -> Self { + let mut non_delegate_action_operations: Vec = + vec![]; + for action in delegate_action.actions { + non_delegate_action_operations.push(action.into()); + } + DelegateActionOperation { + receiver_id: delegate_action.receiver_id.into(), + max_block_height: delegate_action.max_block_height, + public_key: (&delegate_action.public_key).into(), + operations: non_delegate_action_operations, + nonce: delegate_action.nonce, + } + } +} +impl From + for crate::models::NonDelegateActionOperation +{ + fn from(delegate_action: near_primitives::delegate_action::NonDelegateAction) -> Self { + delegate_action.into() } } diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/initiate_delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/initiate_delegate_action.rs new file mode 100644 index 00000000000..f074cbd9f17 --- /dev/null +++ b/chain/rosetta-rpc/src/adapters/validated_operations/initiate_delegate_action.rs @@ -0,0 +1,36 @@ +use super::ValidatedOperation; + +pub(crate) struct InitiateDelegateActionOperation { + pub(crate) sender_account: crate::models::AccountIdentifier, +} + +impl ValidatedOperation for InitiateDelegateActionOperation { + const OPERATION_TYPE: crate::models::OperationType = + crate::models::OperationType::InitiateDelegateAction; + + fn into_operation( + self, + operation_identifier: crate::models::OperationIdentifier, + ) -> crate::models::Operation { + crate::models::Operation { + operation_identifier, + + account: self.sender_account, + amount: None, + metadata: None, + + related_operations: None, + type_: Self::OPERATION_TYPE, + status: None, + } + } +} + +impl TryFrom for InitiateDelegateActionOperation { + type Error = crate::errors::ErrorKind; + + fn try_from(operation: crate::models::Operation) -> Result { + Self::validate_operation_type(operation.type_)?; + Ok(Self { sender_account: operation.account }) + } +} diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/intitiate_signed_delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/intitiate_signed_delegate_action.rs new file mode 100644 index 00000000000..3459e4abacb --- /dev/null +++ b/chain/rosetta-rpc/src/adapters/validated_operations/intitiate_signed_delegate_action.rs @@ -0,0 +1,36 @@ +use super::ValidatedOperation; + +pub(crate) struct InitiateSignedDelegateActionOperation { + pub(crate) sender_account: crate::models::AccountIdentifier, +} + +impl ValidatedOperation for InitiateSignedDelegateActionOperation { + const OPERATION_TYPE: crate::models::OperationType = + crate::models::OperationType::InitiateSignedDelegateAction; + + fn into_operation( + self, + operation_identifier: crate::models::OperationIdentifier, + ) -> crate::models::Operation { + crate::models::Operation { + operation_identifier, + + account: self.sender_account, + amount: None, + metadata: None, + + related_operations: None, + type_: Self::OPERATION_TYPE, + status: None, + } + } +} + +impl TryFrom for InitiateSignedDelegateActionOperation { + type Error = crate::errors::ErrorKind; + + fn try_from(operation: crate::models::Operation) -> Result { + Self::validate_operation_type(operation.type_)?; + Ok(Self { sender_account: operation.account }) + } +} diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs b/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs index f4a44ce49ec..80e7bbc6f55 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs @@ -1,5 +1,6 @@ pub(crate) use self::add_key::AddKeyOperation; pub(crate) use self::create_account::CreateAccountOperation; +pub(crate) use self::delegate_action::DelegateActionOperation; pub(crate) use self::delete_account::DeleteAccountOperation; pub(crate) use self::delete_key::DeleteKeyOperation; pub(crate) use self::deploy_contract::DeployContractOperation; @@ -10,12 +11,14 @@ pub(crate) use self::initiate_delete_account::InitiateDeleteAccountOperation; pub(crate) use self::initiate_delete_key::InitiateDeleteKeyOperation; pub(crate) use self::initiate_deploy_contract::InitiateDeployContractOperation; pub(crate) use self::initiate_function_call::InitiateFunctionCallOperation; +pub(crate) use self::intitiate_signed_delegate_action::InitiateSignedDelegateActionOperation; pub(crate) use self::refund_delete_account::RefundDeleteAccountOperation; pub(crate) use self::stake::StakeOperation; pub(crate) use self::transfer::TransferOperation; mod add_key; mod create_account; +pub mod delegate_action; mod delete_account; mod delete_key; mod deploy_contract; @@ -26,10 +29,12 @@ mod initiate_delete_account; mod initiate_delete_key; mod initiate_deploy_contract; mod initiate_function_call; +pub mod intitiate_signed_delegate_action; mod refund_delete_account; +pub mod signed_delegate_action; mod stake; mod transfer; -pub mod delegate_action; +pub mod initiate_delegate_action; pub(crate) trait ValidatedOperation: TryFrom diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs new file mode 100644 index 00000000000..fd7313a1258 --- /dev/null +++ b/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs @@ -0,0 +1,47 @@ +use super::ValidatedOperation; + +pub(crate) struct SignedDelegateActionOperation { + pub(crate) receiver_id: crate::models::AccountIdentifier, + pub(crate) signature: crate::models::Signature, +} + +impl ValidatedOperation for SignedDelegateActionOperation { + const OPERATION_TYPE: crate::models::OperationType = + crate::models::OperationType::SignedDelegateAction; + + fn into_operation( + self, + operation_identifier: crate::models::OperationIdentifier, + ) -> crate::models::Operation { + crate::models::Operation { + operation_identifier, + + account: self.receiver_id, + amount: None, + metadata: Some(crate::models::OperationMetadata { + signature: Some(self.signature), + ..Default::default() + }), + + related_operations: None, + type_: Self::OPERATION_TYPE, + status: None, + } + } +} +fn required_fields_error() -> crate::errors::ErrorKind { + crate::errors::ErrorKind::InvalidInput( + "DELEGATE_ACTION operation requires `signature` being passed in the metadata".into(), + ) +} +impl TryFrom for SignedDelegateActionOperation { + type Error = crate::errors::ErrorKind; + + fn try_from(operation: crate::models::Operation) -> Result { + Self::validate_operation_type(operation.type_)?; + let metadata = operation.metadata.ok_or_else(required_fields_error)?; + let signature = metadata.signature.ok_or_else(required_fields_error)?; + + Ok(Self { receiver_id: operation.account, signature }) + } +} diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index 5d7a7bf54fd..bb64a6a601e 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -712,6 +712,7 @@ pub(crate) enum OperationType { DelegateAction, RefundDeleteAccount, InitiateAddKey, + SignedDelegateAction, AddKey, InitiateDeleteKey, DeleteKey, @@ -720,6 +721,8 @@ pub(crate) enum OperationType { InitiateDeployContract, DeployContract, InitiateFunctionCall, + InitiateSignedDelegateAction, + InitiateDelegateAction, FunctionCall, } @@ -791,7 +794,13 @@ pub(crate) struct OperationMetadata { pub max_block_height: Option, /// Has to be specified for DELEGATE_ACTION operation #[serde(skip_serializing_if = "Option::is_none")] - pub operations: Option, + pub nonce: Option, + /// Has to be specified for DELEGATE_ACTION operation + #[serde(skip_serializing_if = "Option::is_none")] + pub operations: Option>, + /// Has to be specified for SIGNED_DELEGATE_ACTION operation + #[serde(skip_serializing_if = "Option::is_none")] + pub signature: Option, } impl OperationMetadata { @@ -850,56 +859,60 @@ pub(crate) struct Operation { #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option, } -/// A small private module to protect the private fields inside `NonDelegateAction`. -mod private_non_delegate_action { - use super::*; - /// This is Action which mustn't contain DelegateAction. - /// - /// This struct is needed to avoid the recursion when Action/DelegateAction is deserialized. - /// - /// Important: Don't make the inner Action public, this must only be constructed - /// through the correct interface that ensures the inner Action is actually not - /// a delegate action. That would break an assumption of this type, which we use - /// in several places. For example, borsh de-/serialization relies on it. If the - /// invariant is broken, we may end up with a `Transaction` or `Receipt` that we - /// can serialize but deserializing it back causes a parsing error. - #[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Debug)] - pub struct NonDelegateActionOperation(Operation); - - impl From for Operation { - fn from(action: NonDelegateActionOperation) -> Self { - action.0 - } - } +/// This is Operation which mustn't contain DelegateActionOperation. +/// +/// This struct is needed to avoid the recursion when Action/DelegateAction is deserialized. +/// +/// Important: Don't make the inner Action public, this must only be constructed +/// through the correct interface that ensures the inner Action is actually not +/// a delegate action. That would break an assumption of this type, which we use +/// in several places. For example, borsh de-/serialization relies on it. If the +/// invariant is broken, we may end up with a `Transaction` or `Receipt` that we +/// can serialize but deserializing it back causes a parsing error. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Apiv2Schema)] +pub(crate) struct NonDelegateActionOperation(crate::models::Operation); - #[derive(Debug, thiserror::Error)] - #[error("attempted to construct NonDelegateAction from Action::Delegate")] - pub struct IsDelegateOperation; +impl From for crate::models::Operation { + fn from(action: NonDelegateActionOperation) -> Self { + action.0 + } +} - impl TryFrom for NonDelegateActionOperation { - type Error = IsDelegateOperation; +impl TryFrom for near_primitives::delegate_action::NonDelegateAction { + type Error = crate::errors::ErrorKind; - fn try_from(action: Operation) -> Result { - if matches!(action.type_, DelegateAction) { - Err(IsDelegateOperation) - } else { - Ok(Self(action)) - } + fn try_from(value: NonDelegateActionOperation) -> Result { + let near_action = crate::adapters::NearActions::try_from(value.0); + Ok(near_primitives::delegate_action::NonDelegateAction { 0: }) + } +} +// impl Into> +// for Vec +// { +// fn into(self) -> Vec { +// let non_delegate_actions: Vec = vec![]; +// let near_actions :self.try_into(); +// // for non_delegate_action_operation in self { +// // let near_actions = non_delegate_action_operationtry_into(); +// // non_delegate_actions.push(non_delegate_action_operation.0.try_into()) +// // } +// } +// } + +#[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Debug)] +pub struct IsDelegateOperation; + +impl TryFrom for NonDelegateActionOperation { + type Error = IsDelegateOperation; + + fn try_from(operation: crate::models::Operation) -> Result { + if matches!(operation.type_, crate::models::OperationType::DelegateAction) { + Err(IsDelegateOperation) + } else { + Ok(Self(operation)) } } - - // fn deserialize_reader( - // rd: &mut R, - // ) -> ::core::result::Result { - // match u8::deserialize_reader(rd)? { - // ACTION_DELEGATE_NUMBER => Err(Error::new( - // ErrorKind::InvalidInput, - // "DelegateAction mustn't contain a nested one", - // )), - // n => borsh::de::EnumExt::deserialize_variant(rd, n).map(Self), - // } - // } } /// The operation_identifier uniquely identifies an operation within a @@ -1267,6 +1280,27 @@ impl TryFrom<&Signature> for near_crypto::Signature { } } +impl Signature { + pub fn from_signature( + signature: near_crypto::Signature, + public_key: PublicKey, + signing_payload: SigningPayload, + hex_bytes: BlobInHexString>, + ) -> Self { + match signature { + near_crypto::Signature::ED25519(_) => Signature { + signature_type: signature.key_type().into(), + public_key, + signing_payload, + hex_bytes, + }, + near_crypto::Signature::SECP256K1(_) => { + unimplemented!("SEC256K1 keys are not implemented in Rosetta yet") + } + } + } +} + /// SignatureType is the type of a cryptographic signature. #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize, Apiv2Schema)] #[serde(rename_all = "lowercase")] From acbd543ce153252203fd28c570c82b42ac4c1176 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Fri, 10 Mar 2023 10:48:05 +0900 Subject: [PATCH 03/13] WIP delegate action operation mapping + typecheck ok --- chain/rosetta-rpc/src/adapters/mod.rs | 101 ++++++++++++++---- .../src/adapters/validated_operations/mod.rs | 2 +- chain/rosetta-rpc/src/models.rs | 17 +-- chain/rosetta-rpc/src/utils.rs | 9 ++ 4 files changed, 97 insertions(+), 32 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 207442608f0..c7fd9294123 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -7,10 +7,6 @@ use validated_operations::ValidatedOperation; use crate::utils::BlobInHexString; -use self::validated_operations::{ - initiate_delegate_action, intitiate_signed_delegate_action, signed_delegate_action, -}; - mod transactions; mod validated_operations; @@ -442,7 +438,7 @@ impl From for Vec { .try_to_vec() .expect("Failed to deseralize") .into(); - let singing_payload = crate::models::SigningPayload { + let signing_payload = crate::models::SigningPayload { account_identifier: action.delegate_action.clone().sender_id.into(), signature_type: Some(action.signature.key_type().into()), hex_bytes: hex_bytes.clone(), @@ -451,8 +447,13 @@ impl From for Vec { crate::models::OperationIdentifier::new(&operations); operations.push(validated_operations::signed_delegate_action::SignedDelegateActionOperation { - receiver_id: receiver_account_identifier.clone(), - signature : crate::models::Signature::from_signature(action.signature, (&action.delegate_action.public_key.clone()).into(), singing_payload, hex_bytes) + receiver_id: receiver_account_identifier.clone(), + signature: crate::models::Signature::from_signature( + action.signature, + (&action.delegate_action.public_key.clone()).into(), + signing_payload, + hex_bytes, + ) }.into_related_operation( signed_delegate_action_operation_id.clone(), vec![intitiate_signed_delegate_action_operation_id], @@ -462,7 +463,7 @@ impl From for Vec { crate::models::OperationIdentifier::new(&operations); operations.push(validated_operations::initiate_delegate_action::InitiateDelegateActionOperation{ - sender_account: action.delegate_action.clone().sender_id.into() + sender_account: action.delegate_action.sender_id.clone().into() }.into_related_operation(initiate_delegate_action_operation_id.clone(), vec![signed_delegate_action_operation_id])); let delegate_action_operation_id = @@ -473,7 +474,23 @@ impl From for Vec { operations.push(delegate_action_operation.into_related_operation( delegate_action_operation_id, vec![initiate_delegate_action_operation_id], - )) + )); + + // We know that there are no delegate actions inside so this is guaranteed to + // be a single-level recursion. + let delegated_operations: Vec = NearActions { + sender_account_id: action.delegate_action.sender_id.clone(), + receiver_account_id: action.delegate_action.receiver_id.clone(), + actions: action + .delegate_action + .actions + .into_iter() + .map(|a| a.into()) + .collect::>(), + } + .into(); + + operations.extend(delegated_operations); } // TODO(#8469): Implement delegate action support, for now they are ignored. } } @@ -704,13 +721,13 @@ impl TryFrom> for NearActions { ) } crate::models::OperationType::SignedDelegateAction => { - let delegate_action_operation = - validated_operations::delegate_action::DelegateActionOperation::try_from( - tail_operation, - )?; - let initiate_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from(tail_operation)?; + let delegate_action_operation: validated_operations::delegate_action::DelegateActionOperation = todo!(); + // validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from( + // tail_operation, + // )?; + let initiate_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from_option(operations.next())?; - let signed_delegate_action_operation = validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from(tail_operation)?; + let signed_delegate_action_operation = validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from_option(operations.next())?; receiver_account_id.try_set(&signed_delegate_action_operation.receiver_id)?; let intitiate_signed_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from_option(operations.next())?; @@ -730,17 +747,56 @@ impl TryFrom> for NearActions { .address .parse() .unwrap(), - actions: delegate_action_operation.operations, + actions: { + let sub_near_actions_wrapper: NearActions = delegate_action_operation + .operations + .into_iter() + .map(|o| crate::models::Operation::from(o)) + .collect::>() + .try_into()?; + + // make sure that the delegated actions are consistent with the + // containing DelegateAction + if Some(sub_near_actions_wrapper.sender_account_id.clone().into()) + != *sender_account_id.as_ref() + { + return Err(crate::errors::ErrorKind::InvalidInput(format!( + "Delegated action sender `{}` does not equal the receiver of the delegate action `{:?}`", + sub_near_actions_wrapper.sender_account_id, sender_account_id.into_inner(), + ))); + } + + // Rewrite when .try_collect() is stable + let sub_actions_results = sub_near_actions_wrapper.actions.into_iter().map(|a| a.try_into()).collect::>(); + let sub_actions = { + let mut actions = vec![]; + for r in sub_actions_results.into_iter() { + if let Ok(r) = r { + actions.push(r); + } else { + return Err(crate::errors::ErrorKind::InvalidInput("Delegate action contains nested delegate action".to_string())); + } + } + actions + }; + + sub_actions + }, nonce: delegate_action_operation.nonce, max_block_height: delegate_action_operation.max_block_height, - public_key: delegate_action_operation.public_key.into(), + public_key: match (&delegate_action_operation.public_key).try_into() { + Ok(o) => o, + Err(_) => return Err(crate::errors::ErrorKind::InvalidInput("Invalid public key on delegate action".to_string())), + }, + }, + signature: match (&signed_delegate_action_operation.signature).try_into() { + Ok(s) => s, + Err(_) => return Err(crate::errors::ErrorKind::InvalidInput("Failed to parse delegate action signature".to_string())), }, - signature: signed_delegate_action_operation.signature.into(), } .into(), ) } - // crate::models::OperationType::SignedDelegateAction crate::models::OperationType::InitiateCreateAccount | crate::models::OperationType::InitiateDeleteAccount | crate::models::OperationType::InitiateAddKey @@ -1060,10 +1116,9 @@ mod tests { status: None, metadata: None, }]; - assert!(matches!( - NearActions::try_from(operations), - Err(crate::errors::ErrorKind::InvalidInput(_)) - )); + let value = NearActions::try_from(operations); + dbg!(&value); + assert!(matches!(value, Err(crate::errors::ErrorKind::InvalidInput(_)))); } #[test] diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs b/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs index 80e7bbc6f55..8218def550a 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/mod.rs @@ -25,6 +25,7 @@ mod deploy_contract; mod function_call; mod initiate_add_key; mod initiate_create_account; +pub mod initiate_delegate_action; mod initiate_delete_account; mod initiate_delete_key; mod initiate_deploy_contract; @@ -34,7 +35,6 @@ mod refund_delete_account; pub mod signed_delegate_action; mod stake; mod transfer; -pub mod initiate_delegate_action; pub(crate) trait ValidatedOperation: TryFrom diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index bb64a6a601e..47129f8c17b 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -879,14 +879,15 @@ impl From for crate::models::Operation { } } -impl TryFrom for near_primitives::delegate_action::NonDelegateAction { - type Error = crate::errors::ErrorKind; - - fn try_from(value: NonDelegateActionOperation) -> Result { - let near_action = crate::adapters::NearActions::try_from(value.0); - Ok(near_primitives::delegate_action::NonDelegateAction { 0: }) - } -} +// impl TryFrom for near_primitives::delegate_action::NonDelegateAction { +// type Error = crate::errors::ErrorKind; +// +// fn try_from(value: NonDelegateActionOperation) -> Result { +// todo!() +// // let near_action = crate::adapters::NearActions::try_from(value.0); +// // Ok(near_primitives::delegate_action::NonDelegateAction { 0: }) +// } +// } // impl Into> // for Vec // { diff --git a/chain/rosetta-rpc/src/utils.rs b/chain/rosetta-rpc/src/utils.rs index 2ebffe84d2e..348a0b7d2e2 100644 --- a/chain/rosetta-rpc/src/utils.rs +++ b/chain/rosetta-rpc/src/utils.rs @@ -469,6 +469,15 @@ where } } +impl<'a, T> AsRef> for InitializeOnce<'a, T> +where + T: std::fmt::Debug + std::clone::Clone + std::cmp::Eq, +{ + fn as_ref(&self) -> &Option { + &self.known_value + } +} + /// Get a block with `block_id`. /// Returns `Ok(Some(_))` if the block exists and is final. /// Returns `Ok(None)` if the block does not exist or is not final. From 1c36b948b900c802fdec016b479f3681c9297f56 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Mon, 13 Mar 2023 22:27:14 +0900 Subject: [PATCH 04/13] chore: compiles w/o todo!() but operation ordering is inconsistent, so still broken --- Cargo.lock | 1 + chain/rosetta-rpc/Cargo.toml | 3 +- chain/rosetta-rpc/src/adapters/mod.rs | 57 ++++++++++++------- .../validated_operations/delegate_action.rs | 29 ++++++---- chain/rosetta-rpc/src/errors.rs | 8 ++- chain/rosetta-rpc/src/models.rs | 31 +++------- 6 files changed, 71 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df9591a2271..a9068c88ab6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3781,6 +3781,7 @@ dependencies = [ "serde", "serde_json", "strum", + "thiserror", "tokio", "validator", ] diff --git a/chain/rosetta-rpc/Cargo.toml b/chain/rosetta-rpc/Cargo.toml index b2e0bb02572..2270858895f 100644 --- a/chain/rosetta-rpc/Cargo.toml +++ b/chain/rosetta-rpc/Cargo.toml @@ -20,6 +20,7 @@ paperclip.workspace = true serde.workspace = true serde_json.workspace = true strum.workspace = true +thiserror.workspace = true tokio.workspace = true validator.workspace = true @@ -38,4 +39,4 @@ insta = "1" near-actix-test-utils = { path = "../../test-utils/actix-test-utils" } [features] -nightly = [] \ No newline at end of file +nightly = [] diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index c7fd9294123..8adfb06c5a6 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -205,7 +205,7 @@ pub(crate) async fn collect_transactions( /// There are some helper Operation Types defined since a single operation /// has only a single "account" field, so to indicate "sender" and "receiver" /// we use two operations (e.g. InitiateAddKey and AddKey). -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct NearActions { pub sender_account_id: near_primitives::types::AccountId, pub receiver_account_id: near_primitives::types::AccountId, @@ -508,10 +508,10 @@ impl TryFrom> for NearActions { /// Operations. The implementations are bijective (there is a test below). fn try_from(operations: Vec) -> Result { let mut sender_account_id = crate::utils::InitializeOnce::new( - "A single transaction cannot be send from multiple senders", + "A single transaction cannot be sent from multiple senders", ); let mut receiver_account_id = crate::utils::InitializeOnce::new( - "A single transaction cannot be send to multiple recipients", + "A single transaction cannot be sent to multiple recipients", ); let mut actions = vec![]; @@ -720,11 +720,12 @@ impl TryFrom> for NearActions { .into(), ) } - crate::models::OperationType::SignedDelegateAction => { - let delegate_action_operation: validated_operations::delegate_action::DelegateActionOperation = todo!(); - // validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from( - // tail_operation, - // )?; + crate::models::OperationType::DelegateAction => { + let delegate_action_operation = + validated_operations::delegate_action::DelegateActionOperation::try_from( + tail_operation, + )?; + let initiate_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from_option(operations.next())?; let signed_delegate_action_operation = validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from_option(operations.next())?; @@ -803,7 +804,7 @@ impl TryFrom> for NearActions { | crate::models::OperationType::InitiateDeleteKey | crate::models::OperationType::InitiateDeployContract | crate::models::OperationType::InitiateFunctionCall - | crate::models::OperationType::DelegateAction + | crate::models::OperationType::SignedDelegateAction | crate::models::OperationType::InitiateSignedDelegateAction | crate::models::OperationType::InitiateDelegateAction | crate::models::OperationType::DeleteAccount => { @@ -845,7 +846,10 @@ mod tests { use actix::System; use near_actix_test_utils::run_actix; use near_client::test_utils::setup_no_network; + use near_crypto::{KeyType, PublicKey}; + use near_primitives::delegate_action::{DelegateAction, SignedDelegateAction}; use near_primitives::runtime::config::RuntimeConfig; + use near_primitives::transaction::{Action, TransferAction}; use near_primitives::views::RuntimeConfigView; #[test] @@ -1107,18 +1111,29 @@ mod tests { #[test] fn test_near_actions_invalid_signed_delegate_function() { - let operations = vec![crate::models::Operation { - type_: crate::models::OperationType::SignedDelegateAction, - account: "sender.near".parse().unwrap(), - amount: None, - operation_identifier: crate::models::OperationIdentifier::new(&[]), - related_operations: None, - status: None, - metadata: None, - }]; - let value = NearActions::try_from(operations); - dbg!(&value); - assert!(matches!(value, Err(crate::errors::ErrorKind::InvalidInput(_)))); + let near_actions = NearActions { + sender_account_id: "proxy.near".parse().unwrap(), + receiver_account_id: "account.near".parse().unwrap(), + actions: vec![Action::Delegate(SignedDelegateAction { + delegate_action: DelegateAction { + sender_id: "account.near".parse().unwrap(), + receiver_id: "receiver.near".parse().unwrap(), + actions: vec![Action::Transfer(TransferAction { deposit: 1 }) + .try_into() + .unwrap()], + nonce: 0, + max_block_height: 0, + public_key: PublicKey::empty(KeyType::ED25519), + }, + signature: Default::default(), + })], + }; + + let operations: Vec = near_actions.clone().try_into().unwrap(); + + let near_actions_from_operations = NearActions::try_from(dbg!(operations)).unwrap(); + + assert_eq!(near_actions, near_actions_from_operations); } #[test] diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs index c7dbc63a9b6..a977f032a08 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -1,3 +1,5 @@ +use crate::adapters::NearActions; + use super::ValidatedOperation; pub(crate) struct DelegateActionOperation { @@ -35,11 +37,13 @@ impl ValidatedOperation for DelegateActionOperation { } } } + fn required_fields_error() -> crate::errors::ErrorKind { crate::errors::ErrorKind::InvalidInput( "DELEGATE_ACTION operation requires `public_key`, 'max_block_height' and 'operations' being passed in the metadata".into(), ) } + impl TryFrom for DelegateActionOperation { type Error = crate::errors::ErrorKind; @@ -57,24 +61,25 @@ impl TryFrom for DelegateActionOperation { impl From for DelegateActionOperation { fn from(delegate_action: near_primitives::delegate_action::DelegateAction) -> Self { - let mut non_delegate_action_operations: Vec = - vec![]; - for action in delegate_action.actions { - non_delegate_action_operations.push(action.into()); + let near_action = NearActions { + sender_account_id: delegate_action.sender_id, + receiver_account_id: delegate_action.receiver_id.clone(), + actions: delegate_action.actions.into_iter().map(|a| a.into()).collect(), + }; + + let operations: Vec = near_action.into(); + let mut non_delegate_operations: Vec = vec![]; + for operation in operations { + // unwrap is safe because these actions were converted from `NonDelegateAction`s above + non_delegate_operations.push(operation.try_into().unwrap()); } + DelegateActionOperation { receiver_id: delegate_action.receiver_id.into(), max_block_height: delegate_action.max_block_height, public_key: (&delegate_action.public_key).into(), - operations: non_delegate_action_operations, + operations: non_delegate_operations, nonce: delegate_action.nonce, } } } -impl From - for crate::models::NonDelegateActionOperation -{ - fn from(delegate_action: near_primitives::delegate_action::NonDelegateAction) -> Self { - delegate_action.into() - } -} diff --git a/chain/rosetta-rpc/src/errors.rs b/chain/rosetta-rpc/src/errors.rs index c61ea89b2de..69311b9a167 100644 --- a/chain/rosetta-rpc/src/errors.rs +++ b/chain/rosetta-rpc/src/errors.rs @@ -1,10 +1,16 @@ -#[derive(Debug, strum::EnumIter)] +#[derive(Debug, strum::EnumIter, thiserror::Error)] pub(crate) enum ErrorKind { + #[error("Invalid input: {0}")] InvalidInput(String), + #[error("Not found: {0}")] NotFound(String), + #[error("Wrong network: {0}")] WrongNetwork(String), + #[error("Timeout: {0}")] Timeout(String), + #[error("Internal invariant violation: {0}")] InternalInvariantError(String), + #[error("Internal error: {0}")] InternalError(String), } diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index 47129f8c17b..8029d084a83 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -879,29 +879,8 @@ impl From for crate::models::Operation { } } -// impl TryFrom for near_primitives::delegate_action::NonDelegateAction { -// type Error = crate::errors::ErrorKind; -// -// fn try_from(value: NonDelegateActionOperation) -> Result { -// todo!() -// // let near_action = crate::adapters::NearActions::try_from(value.0); -// // Ok(near_primitives::delegate_action::NonDelegateAction { 0: }) -// } -// } -// impl Into> -// for Vec -// { -// fn into(self) -> Vec { -// let non_delegate_actions: Vec = vec![]; -// let near_actions :self.try_into(); -// // for non_delegate_action_operation in self { -// // let near_actions = non_delegate_action_operationtry_into(); -// // non_delegate_actions.push(non_delegate_action_operation.0.try_into()) -// // } -// } -// } - -#[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Debug)] +#[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Debug, thiserror::Error)] +#[error("Delegate operation cannot contain a delegate operation")] pub struct IsDelegateOperation; impl TryFrom for NonDelegateActionOperation { @@ -916,6 +895,12 @@ impl TryFrom for NonDelegateActionOperation { } } +impl From for crate::errors::ErrorKind { + fn from(value: IsDelegateOperation) -> Self { + crate::errors::ErrorKind::InvalidInput(value.to_string()) + } +} + /// The operation_identifier uniquely identifies an operation within a /// transaction. #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Apiv2Schema)] From 316881f1f4a3ea86185ac4c8c516f52340eeed70 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Fri, 17 Mar 2023 20:24:54 +0900 Subject: [PATCH 05/13] fix: delegate action should work --- chain/rosetta-rpc/src/adapters/mod.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 8adfb06c5a6..a204ae14b8e 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -513,6 +513,9 @@ impl TryFrom> for NearActions { let mut receiver_account_id = crate::utils::InitializeOnce::new( "A single transaction cannot be sent to multiple recipients", ); + let mut delegate_proxy_account_id = crate::utils::InitializeOnce::new( + "A single transaction cannot be sent by multiple proxies", + ); let mut actions = vec![]; // Iterate over operations backwards to handle the related operations @@ -729,10 +732,11 @@ impl TryFrom> for NearActions { let initiate_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from_option(operations.next())?; let signed_delegate_action_operation = validated_operations::signed_delegate_action::SignedDelegateActionOperation::try_from_option(operations.next())?; - receiver_account_id.try_set(&signed_delegate_action_operation.receiver_id)?; + // the "sender" of this group of operations is considered to be the delegating account, not the proxy + sender_account_id.try_set(&signed_delegate_action_operation.receiver_id)?; - let intitiate_signed_delegate_action_operation = validated_operations::initiate_delegate_action::InitiateDelegateActionOperation::try_from_option(operations.next())?; - sender_account_id + let intitiate_signed_delegate_action_operation = validated_operations::intitiate_signed_delegate_action::InitiateSignedDelegateActionOperation::try_from_option(operations.next())?; + delegate_proxy_account_id .try_set(&intitiate_signed_delegate_action_operation.sender_account)?; actions.push( @@ -1110,6 +1114,7 @@ mod tests { } #[test] + #[should_panic(expected = "Failed to parse delegate action signature")] fn test_near_actions_invalid_signed_delegate_function() { let near_actions = NearActions { sender_account_id: "proxy.near".parse().unwrap(), @@ -1125,15 +1130,13 @@ mod tests { max_block_height: 0, public_key: PublicKey::empty(KeyType::ED25519), }, - signature: Default::default(), + signature: Default::default(), // this is not a valid signature })], }; let operations: Vec = near_actions.clone().try_into().unwrap(); - let near_actions_from_operations = NearActions::try_from(dbg!(operations)).unwrap(); - - assert_eq!(near_actions, near_actions_from_operations); + NearActions::try_from(operations).unwrap(); } #[test] From 54b48380b4bc33dd4c7be228fedcbdca22259c7c Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Tue, 21 Mar 2023 22:55:07 +0900 Subject: [PATCH 06/13] fix: no nested metadata + incorrect use of crate::models::Signature in internal structure --- chain/rosetta-rpc/src/adapters/mod.rs | 94 ++++++++----------- .../validated_operations/delegate_action.rs | 8 +- .../signed_delegate_action.rs | 9 +- chain/rosetta-rpc/src/models.rs | 15 ++- 4 files changed, 58 insertions(+), 68 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index a204ae14b8e..b41f1a62325 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -448,13 +448,7 @@ impl From for Vec { operations.push(validated_operations::signed_delegate_action::SignedDelegateActionOperation { receiver_id: receiver_account_identifier.clone(), - signature: crate::models::Signature::from_signature( - action.signature, - (&action.delegate_action.public_key.clone()).into(), - signing_payload, - hex_bytes, - ) - }.into_related_operation( + signature: action.signature }.into_related_operation( signed_delegate_action_operation_id.clone(), vec![intitiate_signed_delegate_action_operation_id], )); @@ -516,7 +510,7 @@ impl TryFrom> for NearActions { let mut delegate_proxy_account_id = crate::utils::InitializeOnce::new( "A single transaction cannot be sent by multiple proxies", ); - let mut actions = vec![]; + let mut actions: Vec = vec![]; // Iterate over operations backwards to handle the related operations let mut operations = operations.into_iter().rev(); @@ -739,7 +733,7 @@ impl TryFrom> for NearActions { delegate_proxy_account_id .try_set(&intitiate_signed_delegate_action_operation.sender_account)?; - actions.push( + let delegate_action: near_primitives::transaction::Action = near_primitives::delegate_action::SignedDelegateAction { delegate_action: near_primitives::delegate_action::DelegateAction { sender_id: initiate_delegate_action_operation @@ -753,54 +747,37 @@ impl TryFrom> for NearActions { .parse() .unwrap(), actions: { - let sub_near_actions_wrapper: NearActions = delegate_action_operation - .operations - .into_iter() - .map(|o| crate::models::Operation::from(o)) - .collect::>() - .try_into()?; - - // make sure that the delegated actions are consistent with the - // containing DelegateAction - if Some(sub_near_actions_wrapper.sender_account_id.clone().into()) - != *sender_account_id.as_ref() - { - return Err(crate::errors::ErrorKind::InvalidInput(format!( - "Delegated action sender `{}` does not equal the receiver of the delegate action `{:?}`", - sub_near_actions_wrapper.sender_account_id, sender_account_id.into_inner(), - ))); - } - - // Rewrite when .try_collect() is stable - let sub_actions_results = sub_near_actions_wrapper.actions.into_iter().map(|a| a.try_into()).collect::>(); - let sub_actions = { - let mut actions = vec![]; - for r in sub_actions_results.into_iter() { - if let Ok(r) = r { - actions.push(r); - } else { - return Err(crate::errors::ErrorKind::InvalidInput("Delegate action contains nested delegate action".to_string())); + let mut nda = vec![]; + for a in actions.into_iter() { + nda.push(match a.try_into() { + Ok(a) => a, + Err(_) => { + return Err(crate::errors::ErrorKind::InvalidInput( + "Nested delegate actions not allowed" + .to_string(), + )) } - } - actions - }; - - sub_actions + }); + } + nda }, nonce: delegate_action_operation.nonce, max_block_height: delegate_action_operation.max_block_height, - public_key: match (&delegate_action_operation.public_key).try_into() { + public_key: match (&delegate_action_operation.public_key).try_into() + { Ok(o) => o, - Err(_) => return Err(crate::errors::ErrorKind::InvalidInput("Invalid public key on delegate action".to_string())), + Err(_) => { + return Err(crate::errors::ErrorKind::InvalidInput( + "Invalid public key on delegate action".to_string(), + )) + } }, }, - signature: match (&signed_delegate_action_operation.signature).try_into() { - Ok(s) => s, - Err(_) => return Err(crate::errors::ErrorKind::InvalidInput("Failed to parse delegate action signature".to_string())), - }, + signature: signed_delegate_action_operation.signature, } - .into(), - ) + .into(); + + actions = vec![delegate_action]; } crate::models::OperationType::InitiateCreateAccount | crate::models::OperationType::InitiateDeleteAccount @@ -850,7 +827,7 @@ mod tests { use actix::System; use near_actix_test_utils::run_actix; use near_client::test_utils::setup_no_network; - use near_crypto::{KeyType, PublicKey}; + use near_crypto::{KeyType, SecretKey}; use near_primitives::delegate_action::{DelegateAction, SignedDelegateAction}; use near_primitives::runtime::config::RuntimeConfig; use near_primitives::transaction::{Action, TransferAction}; @@ -1114,9 +1091,9 @@ mod tests { } #[test] - #[should_panic(expected = "Failed to parse delegate action signature")] fn test_near_actions_invalid_signed_delegate_function() { - let near_actions = NearActions { + let sk = SecretKey::from_seed(KeyType::ED25519, ""); + let original_near_actions = NearActions { sender_account_id: "proxy.near".parse().unwrap(), receiver_account_id: "account.near".parse().unwrap(), actions: vec![Action::Delegate(SignedDelegateAction { @@ -1128,15 +1105,20 @@ mod tests { .unwrap()], nonce: 0, max_block_height: 0, - public_key: PublicKey::empty(KeyType::ED25519), + public_key: sk.public_key(), }, - signature: Default::default(), // this is not a valid signature + signature: sk.sign(&[0]), })], }; - let operations: Vec = near_actions.clone().try_into().unwrap(); + let operations: Vec = + original_near_actions.clone().try_into().unwrap(); + + dbg!(&operations); + + let converted_near_actions = NearActions::try_from(operations).unwrap(); - NearActions::try_from(operations).unwrap(); + assert_eq!(converted_near_actions, original_near_actions); } #[test] diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs index a977f032a08..811328ab295 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -4,7 +4,7 @@ use super::ValidatedOperation; pub(crate) struct DelegateActionOperation { pub(crate) receiver_id: crate::models::AccountIdentifier, - pub(crate) operations: Vec, + // pub(crate) operations: Vec, pub(crate) max_block_height: near_primitives::types::BlockHeight, pub(crate) public_key: crate::models::PublicKey, pub(crate) nonce: near_primitives::types::Nonce, @@ -26,7 +26,6 @@ impl ValidatedOperation for DelegateActionOperation { metadata: Some(crate::models::OperationMetadata { public_key: Some(self.public_key), max_block_height: Some(self.max_block_height), - operations: Some(self.operations), nonce: Some(self.nonce), ..Default::default() }), @@ -53,9 +52,9 @@ impl TryFrom for DelegateActionOperation { let public_key = metadata.public_key.ok_or_else(required_fields_error)?; let max_block_height = metadata.max_block_height.ok_or_else(required_fields_error)?; let nonce = metadata.nonce.ok_or_else(required_fields_error)?; - let operations = metadata.operations.ok_or_else(required_fields_error)?; + // let operations = metadata.operations.ok_or_else(required_fields_error)?; - Ok(Self { receiver_id: operation.account, public_key, max_block_height, operations, nonce }) + Ok(Self { receiver_id: operation.account, public_key, max_block_height, nonce }) } } @@ -78,7 +77,6 @@ impl From for DelegateActionOp receiver_id: delegate_action.receiver_id.into(), max_block_height: delegate_action.max_block_height, public_key: (&delegate_action.public_key).into(), - operations: non_delegate_operations, nonce: delegate_action.nonce, } } diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs index fd7313a1258..f528b42b88b 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs @@ -2,7 +2,7 @@ use super::ValidatedOperation; pub(crate) struct SignedDelegateActionOperation { pub(crate) receiver_id: crate::models::AccountIdentifier, - pub(crate) signature: crate::models::Signature, + pub(crate) signature: near_crypto::Signature, } impl ValidatedOperation for SignedDelegateActionOperation { @@ -19,7 +19,7 @@ impl ValidatedOperation for SignedDelegateActionOperation { account: self.receiver_id, amount: None, metadata: Some(crate::models::OperationMetadata { - signature: Some(self.signature), + signature: Some(self.signature.to_string()), ..Default::default() }), @@ -40,7 +40,10 @@ impl TryFrom for SignedDelegateActionOperation { fn try_from(operation: crate::models::Operation) -> Result { Self::validate_operation_type(operation.type_)?; let metadata = operation.metadata.ok_or_else(required_fields_error)?; - let signature = metadata.signature.ok_or_else(required_fields_error)?; + let signature = + metadata.signature.ok_or_else(required_fields_error)?.parse().map_err(|e| { + crate::errors::ErrorKind::InvalidInput("Invalid key format".to_string()) + })?; Ok(Self { receiver_id: operation.account, signature }) } diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index 8029d084a83..5dc7248492d 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -795,12 +795,9 @@ pub(crate) struct OperationMetadata { /// Has to be specified for DELEGATE_ACTION operation #[serde(skip_serializing_if = "Option::is_none")] pub nonce: Option, - /// Has to be specified for DELEGATE_ACTION operation - #[serde(skip_serializing_if = "Option::is_none")] - pub operations: Option>, /// Has to be specified for SIGNED_DELEGATE_ACTION operation #[serde(skip_serializing_if = "Option::is_none")] - pub signature: Option, + pub signature: Option, } impl OperationMetadata { @@ -1287,6 +1284,16 @@ impl Signature { } } +// #[cfg(test)] +// mod tests { +// #[test] +// fn test_signature_from() { +// let native_key = near_crypto::SecretKey::from_random(near_crypto::KeyType::ED25519); +// let native_signature = native_key.sign(&[0]); +// let converted_signature = crate::models::Signature::from_signature(signature, public_key, signing_payload, hex_bytes); +// } +// } + /// SignatureType is the type of a cryptographic signature. #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize, Apiv2Schema)] #[serde(rename_all = "lowercase")] From 7a9b90ea1915ed555a52e1774354a6c6f29409af Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Tue, 21 Mar 2023 23:10:30 +0900 Subject: [PATCH 07/13] fix: correct sender & receiver when delegate action --- chain/rosetta-rpc/src/adapters/mod.rs | 45 ++++++++++--------- .../signed_delegate_action.rs | 2 +- chain/rosetta-rpc/src/models.rs | 31 ------------- 3 files changed, 24 insertions(+), 54 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index b41f1a62325..640066bfd52 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -2,11 +2,8 @@ use actix::Addr; use near_chain_configs::Genesis; use near_client::ViewClientActor; use near_o11y::WithSpanContextExt; -use near_primitives::borsh::BorshSerialize; use validated_operations::ValidatedOperation; -use crate::utils::BlobInHexString; - mod transactions; mod validated_operations; @@ -432,17 +429,6 @@ impl From for Vec { .into_operation(intitiate_signed_delegate_action_operation_id.clone()), ); - let hex_bytes: BlobInHexString> = action - .delegate_action - .clone() - .try_to_vec() - .expect("Failed to deseralize") - .into(); - let signing_payload = crate::models::SigningPayload { - account_identifier: action.delegate_action.clone().sender_id.into(), - signature_type: Some(action.signature.key_type().into()), - hex_bytes: hex_bytes.clone(), - }; let signed_delegate_action_operation_id = crate::models::OperationIdentifier::new(&operations); @@ -810,12 +796,27 @@ impl TryFrom> for NearActions { })? .address .into(); + + let delegate_proxy_account_id: Option = + delegate_proxy_account_id.into_inner().map(|a| a.address.into()); + let sender_account_id: Option = + sender_account_id.into_inner().map(|a| a.address.into()); + + let actual_receiver_account_id = if delegate_proxy_account_id.is_some() { + sender_account_id.clone().unwrap_or_else(|| receiver_account_id.clone()) + } else { + receiver_account_id.clone() + }; + let actual_sender_account_id = delegate_proxy_account_id + .clone() + .or_else(|| sender_account_id.clone()) + .unwrap_or_else(|| { + // in case of reflexive action + receiver_account_id.clone() + }); Ok(Self { - sender_account_id: sender_account_id - .into_inner() - .map(|account_identifier| account_identifier.address.into()) - .unwrap_or_else(|| receiver_account_id.clone()), - receiver_account_id, + sender_account_id: actual_sender_account_id, + receiver_account_id: actual_receiver_account_id, actions, }) } @@ -1091,8 +1092,10 @@ mod tests { } #[test] - fn test_near_actions_invalid_signed_delegate_function() { + fn test_delegate_actions_bijection() { + // dummy key let sk = SecretKey::from_seed(KeyType::ED25519, ""); + let original_near_actions = NearActions { sender_account_id: "proxy.near".parse().unwrap(), receiver_account_id: "account.near".parse().unwrap(), @@ -1114,8 +1117,6 @@ mod tests { let operations: Vec = original_near_actions.clone().try_into().unwrap(); - dbg!(&operations); - let converted_near_actions = NearActions::try_from(operations).unwrap(); assert_eq!(converted_near_actions, original_near_actions); diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs index f528b42b88b..d334b0a8b48 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/signed_delegate_action.rs @@ -41,7 +41,7 @@ impl TryFrom for SignedDelegateActionOperation { Self::validate_operation_type(operation.type_)?; let metadata = operation.metadata.ok_or_else(required_fields_error)?; let signature = - metadata.signature.ok_or_else(required_fields_error)?.parse().map_err(|e| { + metadata.signature.ok_or_else(required_fields_error)?.parse().map_err(|_| { crate::errors::ErrorKind::InvalidInput("Invalid key format".to_string()) })?; diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index 5dc7248492d..db95fb12d91 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -1263,37 +1263,6 @@ impl TryFrom<&Signature> for near_crypto::Signature { } } -impl Signature { - pub fn from_signature( - signature: near_crypto::Signature, - public_key: PublicKey, - signing_payload: SigningPayload, - hex_bytes: BlobInHexString>, - ) -> Self { - match signature { - near_crypto::Signature::ED25519(_) => Signature { - signature_type: signature.key_type().into(), - public_key, - signing_payload, - hex_bytes, - }, - near_crypto::Signature::SECP256K1(_) => { - unimplemented!("SEC256K1 keys are not implemented in Rosetta yet") - } - } - } -} - -// #[cfg(test)] -// mod tests { -// #[test] -// fn test_signature_from() { -// let native_key = near_crypto::SecretKey::from_random(near_crypto::KeyType::ED25519); -// let native_signature = native_key.sign(&[0]); -// let converted_signature = crate::models::Signature::from_signature(signature, public_key, signing_payload, hex_bytes); -// } -// } - /// SignatureType is the type of a cryptographic signature. #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize, Apiv2Schema)] #[serde(rename_all = "lowercase")] From df440ee74307e7f5629dece068a8a40d5c342611 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Tue, 21 Mar 2023 23:15:12 +0900 Subject: [PATCH 08/13] fix: formatting --- chain/rosetta-rpc/src/adapters/mod.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 640066bfd52..474fb536a63 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -420,24 +420,28 @@ impl From for Vec { operations.push(deploy_contract_operation); } near_primitives::transaction::Action::Delegate(action) => { - let intitiate_signed_delegate_action_operation_id = + let initiate_signed_delegate_action_operation_id = crate::models::OperationIdentifier::new(&operations); operations.push( validated_operations::InitiateSignedDelegateActionOperation { sender_account: sender_account_identifier.clone(), } - .into_operation(intitiate_signed_delegate_action_operation_id.clone()), + .into_operation(initiate_signed_delegate_action_operation_id.clone()), ); let signed_delegate_action_operation_id = crate::models::OperationIdentifier::new(&operations); - operations.push(validated_operations::signed_delegate_action::SignedDelegateActionOperation { - receiver_id: receiver_account_identifier.clone(), - signature: action.signature }.into_related_operation( - signed_delegate_action_operation_id.clone(), - vec![intitiate_signed_delegate_action_operation_id], - )); + operations.push( + validated_operations::signed_delegate_action::SignedDelegateActionOperation { + receiver_id: receiver_account_identifier.clone(), + signature: action.signature, + } + .into_related_operation( + signed_delegate_action_operation_id.clone(), + vec![initiate_signed_delegate_action_operation_id], + ) + ); let initiate_delegate_action_operation_id = crate::models::OperationIdentifier::new(&operations); From d86192029d867c8fdeb475d2bba7383999254c46 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Tue, 21 Mar 2023 23:34:35 +0900 Subject: [PATCH 09/13] fix: clippy --- chain/rosetta-rpc/src/adapters/mod.rs | 13 ++++++------- chain/rosetta-rpc/src/adapters/transactions.rs | 12 ++++++------ chain/rosetta-rpc/src/lib.rs | 8 ++------ chain/rosetta-rpc/src/utils.rs | 8 ++++---- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 474fb536a63..9fc62748410 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -34,10 +34,10 @@ async fn convert_genesis_records_to_transaction( let genesis_accounts: std::collections::BTreeMap<_, _> = crate::utils::query_accounts( &near_primitives::types::BlockId::Hash(block.header.hash).into(), genesis_account_ids.iter(), - &view_client_addr, + view_client_addr, ) .await?; - let runtime_config = crate::utils::query_protocol_config(block.header.hash, &view_client_addr) + let runtime_config = crate::utils::query_protocol_config(block.header.hash, view_client_addr) .await? .runtime_config; @@ -147,7 +147,7 @@ pub(crate) async fn convert_block_to_transactions( near_primitives::types::BlockId::Hash(block.header.prev_hash), ); let accounts_previous_state = - crate::utils::query_accounts(&prev_block_id, touched_account_ids.iter(), &view_client_addr) + crate::utils::query_accounts(&prev_block_id, touched_account_ids.iter(), view_client_addr) .await?; let accounts_changes = view_client_addr @@ -163,13 +163,13 @@ pub(crate) async fn convert_block_to_transactions( ) .await??; - let runtime_config = crate::utils::query_protocol_config(block.header.hash, &view_client_addr) + let runtime_config = crate::utils::query_protocol_config(block.header.hash, view_client_addr) .await? .runtime_config; let exec_to_rx = - transactions::ExecutionToReceipts::for_block(&view_client_addr, block.header.hash).await?; + transactions::ExecutionToReceipts::for_block(view_client_addr, block.header.hash).await?; transactions::convert_block_changes_to_transactions( - &view_client_addr, + view_client_addr, &runtime_config, &block.header.hash, accounts_changes, @@ -812,7 +812,6 @@ impl TryFrom> for NearActions { receiver_account_id.clone() }; let actual_sender_account_id = delegate_proxy_account_id - .clone() .or_else(|| sender_account_id.clone()) .unwrap_or_else(|| { // in case of reflexive action diff --git a/chain/rosetta-rpc/src/adapters/transactions.rs b/chain/rosetta-rpc/src/adapters/transactions.rs index 8281f1a897b..3589f870d0c 100644 --- a/chain/rosetta-rpc/src/adapters/transactions.rs +++ b/chain/rosetta-rpc/src/adapters/transactions.rs @@ -57,7 +57,7 @@ impl ExecutionToReceipts { .await? .map_err(crate::errors::ErrorKind::InternalInvariantError)? .into_values() - .flat_map(|outcomes| outcomes) + .flatten() .filter(|exec| !exec.outcome.receipt_ids.is_empty()) .map(|exec| (exec.id, exec.outcome.receipt_ids)) .collect(); @@ -110,13 +110,13 @@ fn convert_cause_to_transaction_id( match cause { StateChangeCauseView::TransactionProcessing { tx_hash } => { - Ok((TransactionIdentifier::transaction(&tx_hash), Some(*tx_hash))) + Ok((TransactionIdentifier::transaction(tx_hash), Some(*tx_hash))) } StateChangeCauseView::ActionReceiptProcessingStarted { receipt_hash } | StateChangeCauseView::ActionReceiptGasReward { receipt_hash } | StateChangeCauseView::ReceiptProcessing { receipt_hash } | StateChangeCauseView::PostponedReceipt { receipt_hash } => { - Ok((TransactionIdentifier::receipt(&receipt_hash), Some(*receipt_hash))) + Ok((TransactionIdentifier::receipt(receipt_hash), Some(*receipt_hash))) } StateChangeCauseView::InitialState => { Ok((TransactionIdentifier::block_event("block", block_hash), None)) @@ -214,7 +214,7 @@ impl<'a> RosettaTransactions<'a> { &mut self, cause: &near_primitives::views::StateChangeCauseView, ) -> crate::errors::Result<&mut crate::models::Transaction> { - let (id, exec_hash) = convert_cause_to_transaction_id(&self.block_hash, cause)?; + let (id, exec_hash) = convert_cause_to_transaction_id(self.block_hash, cause)?; let tx = self.map.entry(id.hash).or_insert_with_key(|hash| { let related_transactions = exec_hash .map(|exec_hash| self.exec_to_rx.get_related(exec_hash)) @@ -278,8 +278,8 @@ pub(crate) async fn convert_block_changes_to_transactions( let predecessor_id = get_predecessor_id_from_receipt_or_transaction( view_client_addr, &account_change.cause, - &transactions_in_block, - &receipts_in_block, + transactions_in_block, + receipts_in_block, ) .await; let previous_account_state = accounts_previous_state.get(&account_id); diff --git a/chain/rosetta-rpc/src/lib.rs b/chain/rosetta-rpc/src/lib.rs index f109ea3839f..be30b97a09e 100644 --- a/chain/rosetta-rpc/src/lib.rs +++ b/chain/rosetta-rpc/src/lib.rs @@ -566,9 +566,7 @@ async fn construction_payloads( check_network_identifier(&client_addr, network_identifier).await?; - let signer_public_access_key: near_crypto::PublicKey = public_keys - .iter() - .next() + let signer_public_access_key: near_crypto::PublicKey = public_keys.first() .ok_or_else(|| { errors::ErrorKind::InvalidInput("exactly one public key is expected".to_string()) })? @@ -631,9 +629,7 @@ async fn construction_combine( check_network_identifier(&client_addr, network_identifier).await?; - let signature = signatures - .iter() - .next() + let signature = signatures.first() .ok_or_else(|| { errors::ErrorKind::InvalidInput("exactly one signature is expected".to_string()) })? diff --git a/chain/rosetta-rpc/src/utils.rs b/chain/rosetta-rpc/src/utils.rs index 348a0b7d2e2..de0b5e6b42a 100644 --- a/chain/rosetta-rpc/src/utils.rs +++ b/chain/rosetta-rpc/src/utils.rs @@ -53,7 +53,7 @@ where where D: serde::Deserializer<'de>, { - let blob = hex::decode(&::deserialize(deserializer)?) + let blob = hex::decode(::deserialize(deserializer)?) .map_err(|err| { serde::de::Error::invalid_value( serde::de::Unexpected::Other(&format!( @@ -118,7 +118,7 @@ where D: serde::Deserializer<'de>, { Ok(Self(T::from( - hex::decode(&::deserialize(deserializer)?).map_err( + hex::decode(::deserialize(deserializer)?).map_err( |err| { serde::de::Error::invalid_value( serde::de::Unexpected::Other(&format!( @@ -203,7 +203,7 @@ where T: Copy + PartialEq + std::string::ToString, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "SignedDiff({})", self.to_string()) + write!(f, "SignedDiff({})", self) } } @@ -566,7 +566,7 @@ pub(crate) async fn get_nonces( err )) })?, - &view_client_addr, + view_client_addr, ) .await?; nonces.push(access_key.nonce); From 03f5267dbe1845273e2906a2a5d95baddc0a86ca Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Tue, 21 Mar 2023 23:52:43 +0900 Subject: [PATCH 10/13] fix: run scripts/formatting --fix --- chain/rosetta-rpc/src/adapters/mod.rs | 5 ++--- .../src/adapters/validated_operations/delegate_action.rs | 1 - chain/rosetta-rpc/src/lib.rs | 6 ++++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 9fc62748410..24a052b5b9e 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -811,9 +811,8 @@ impl TryFrom> for NearActions { } else { receiver_account_id.clone() }; - let actual_sender_account_id = delegate_proxy_account_id - .or_else(|| sender_account_id.clone()) - .unwrap_or_else(|| { + let actual_sender_account_id = + delegate_proxy_account_id.or_else(|| sender_account_id.clone()).unwrap_or_else(|| { // in case of reflexive action receiver_account_id.clone() }); diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs index 811328ab295..e48ba8529b9 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -4,7 +4,6 @@ use super::ValidatedOperation; pub(crate) struct DelegateActionOperation { pub(crate) receiver_id: crate::models::AccountIdentifier, - // pub(crate) operations: Vec, pub(crate) max_block_height: near_primitives::types::BlockHeight, pub(crate) public_key: crate::models::PublicKey, pub(crate) nonce: near_primitives::types::Nonce, diff --git a/chain/rosetta-rpc/src/lib.rs b/chain/rosetta-rpc/src/lib.rs index be30b97a09e..a018e5ea91e 100644 --- a/chain/rosetta-rpc/src/lib.rs +++ b/chain/rosetta-rpc/src/lib.rs @@ -566,7 +566,8 @@ async fn construction_payloads( check_network_identifier(&client_addr, network_identifier).await?; - let signer_public_access_key: near_crypto::PublicKey = public_keys.first() + let signer_public_access_key: near_crypto::PublicKey = public_keys + .first() .ok_or_else(|| { errors::ErrorKind::InvalidInput("exactly one public key is expected".to_string()) })? @@ -629,7 +630,8 @@ async fn construction_combine( check_network_identifier(&client_addr, network_identifier).await?; - let signature = signatures.first() + let signature = signatures + .first() .ok_or_else(|| { errors::ErrorKind::InvalidInput("exactly one signature is expected".to_string()) })? From ed3a153c52b4586ff1fdd12ca2171c378d5e940d Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Wed, 22 Mar 2023 21:51:16 +0900 Subject: [PATCH 11/13] fix: remove commented code --- .../src/adapters/validated_operations/delegate_action.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs index e48ba8529b9..b7ed13500ce 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -51,7 +51,6 @@ impl TryFrom for DelegateActionOperation { let public_key = metadata.public_key.ok_or_else(required_fields_error)?; let max_block_height = metadata.max_block_height.ok_or_else(required_fields_error)?; let nonce = metadata.nonce.ok_or_else(required_fields_error)?; - // let operations = metadata.operations.ok_or_else(required_fields_error)?; Ok(Self { receiver_id: operation.account, public_key, max_block_height, nonce }) } From 882a76ce445a27a3230beea2f889b3abd1d95107 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Thu, 23 Mar 2023 17:01:42 +0900 Subject: [PATCH 12/13] fix: remove dead code --- .../validated_operations/delegate_action.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs index b7ed13500ce..8cc02ad0b31 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/delegate_action.rs @@ -1,5 +1,3 @@ -use crate::adapters::NearActions; - use super::ValidatedOperation; pub(crate) struct DelegateActionOperation { @@ -58,19 +56,6 @@ impl TryFrom for DelegateActionOperation { impl From for DelegateActionOperation { fn from(delegate_action: near_primitives::delegate_action::DelegateAction) -> Self { - let near_action = NearActions { - sender_account_id: delegate_action.sender_id, - receiver_account_id: delegate_action.receiver_id.clone(), - actions: delegate_action.actions.into_iter().map(|a| a.into()).collect(), - }; - - let operations: Vec = near_action.into(); - let mut non_delegate_operations: Vec = vec![]; - for operation in operations { - // unwrap is safe because these actions were converted from `NonDelegateAction`s above - non_delegate_operations.push(operation.try_into().unwrap()); - } - DelegateActionOperation { receiver_id: delegate_action.receiver_id.into(), max_block_height: delegate_action.max_block_height, From 99a2ea6fbabdc8a78337c22227fbab7f1510b55b Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Thu, 23 Mar 2023 17:06:01 +0900 Subject: [PATCH 13/13] fix: better naming --- chain/rosetta-rpc/src/adapters/mod.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 24a052b5b9e..4f3ea2500ac 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -729,17 +729,12 @@ impl TryFrom> for NearActions { sender_id: initiate_delegate_action_operation .sender_account .address - .parse() - .unwrap(), - receiver_id: delegate_action_operation - .receiver_id - .address - .parse() - .unwrap(), + .into(), + receiver_id: delegate_action_operation.receiver_id.address.into(), actions: { - let mut nda = vec![]; - for a in actions.into_iter() { - nda.push(match a.try_into() { + let mut non_delegate_actions = vec![]; + for action in actions.into_iter() { + non_delegate_actions.push(match action.try_into() { Ok(a) => a, Err(_) => { return Err(crate::errors::ErrorKind::InvalidInput( @@ -749,7 +744,7 @@ impl TryFrom> for NearActions { } }); } - nda + non_delegate_actions }, nonce: delegate_action_operation.nonce, max_block_height: delegate_action_operation.max_block_height,