Skip to content

Commit

Permalink
feat: refactor error handling and introduce SignerConfig for transact…
Browse files Browse the repository at this point in the history
…ion signing
  • Loading branch information
incubator4 committed Nov 6, 2024
1 parent db9e6a5 commit 4eb731b
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 88 deletions.
11 changes: 4 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,9 @@ pub enum Error {
#[error(transparent)]
TransactionBuilderError(#[from] alloy::network::TransactionBuilderError<Ethereum>),

#[error("Build transaction error: {0}")]
BuildTransactionError(String),

#[error("Invalid signer type '{0}'")]
InvalidSignerType(String),

#[error("Invalid transaction type '{0}'")]
InvalidTransactionType(String),

#[error("Require config key '{0}' not found")]
RequireConfigKeyNotFound(&'static str),

Expand Down Expand Up @@ -73,13 +67,16 @@ impl IntoResponse for RPCError {
error: String,
}

let err_string = self.error.to_string();
tracing::info!(err_string);

{
(
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrResponse {
id: self.id,
jsonrpc: self.jsonrpc,
error: self.error.to_string(),
error: err_string,
}),
)
.into_response()
Expand Down
32 changes: 14 additions & 18 deletions src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::prelude::*;
use crate::signer::SignerConfig;
use alloy::{
network::TransactionBuilder,
primitives::{address, TxKind},
primitives::TxKind,
rlp::Encodable,
rpc::types::{TransactionInput, TransactionRequest},
};
Expand Down Expand Up @@ -74,37 +74,33 @@ async fn sign(

let gas_price = request.gas_price();

let tx = request
let wallet = config.wallet().await.map_err(rpc_err_map)?;
let tx_envelop = request
.with_gas_price(gas_price.unwrap_or(90000))
.build_typed_tx()
.map_err(|_| Error::BuildTransactionError(format!("tx_type is none")))
.build(&wallet)
.await
.map_err(Error::TransactionBuilderError)
.map_err(rpc_err_map)?;

let mut tx_hash = DefaultHasher::new();
tx.hash(&mut tx_hash);

let signature = config.sign_transaction(tx).await.map_err(rpc_err_map)?;

let mut sign_hash = DefaultHasher::new();
signature.hash(&mut sign_hash);
tx_envelop.tx_hash().hash(&mut tx_hash);

info!(
request = req_hash.finish(),
tx = tx_hash.finish(),
sign = sign_hash.finish(),
"check hash"
req_hash = req_hash.finish(),
tx_hash = tx_hash.finish(),
"sign tx"
);

let mut encoded_sign = Vec::<u8>::new();
let mut encoded_tx = Vec::<u8>::new();

signature.encode(&mut encoded_sign);
tx_envelop.encode(&mut encoded_tx);

let hex: String = encoded_sign.iter().map(|b| format!("{:02x}", b)).collect();
let hex_string: String = encoded_tx.iter().map(|b| format!("{:02x?}", b)).collect();

Ok(Json(SignReponse {
id,
jsonrpc,
result: format!("0x{}", hex),
result: format!("0x{}", hex_string),
}))
}

Expand Down
31 changes: 31 additions & 0 deletions src/signer/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum SignerConfig {
PrivateKey(String),
Mnemonic(String),
KeyStore {
path: String,
password: String,
},
AzureKeyVault {
key: String,
secret: String,
},
AwsKms {
key: String,
},
GoogleKms {
project_id: String,
location: String,
key_ring: String,
key: String,
version: u64,
},
AlicloudKms {
key: String,
secret: String,
},
}
81 changes: 18 additions & 63 deletions src/signer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod config;
pub use config::SignerConfig;

use crate::prelude::*;
use alloy::{
consensus::TypedTransaction,
network::TxSigner,
network::{EthereumWallet, TxSigner},
primitives::Address,
signers::{
aws::AwsSigner,
Expand All @@ -14,40 +16,9 @@ use alloy::{
use gcloud_sdk::{
google::cloud::kms::v1::key_management_service_client::KeyManagementServiceClient, GoogleApi,
};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum SignerConfig {
PrivateKey(String),
Mnemonic(String),
KeyStore {
path: String,
password: String,
},
AzureKeyVault {
key: String,
secret: String,
},
AwsKms {
key: String,
},
GoogleKms {
project_id: String,
location: String,
key_ring: String,
key: String,
version: u64,
},
AlicloudKms {
key: String,
secret: String,
},
}

impl SignerConfig {
pub async fn signer(&self) -> Result<Box<dyn TxSigner<Signature> + Send + Sync + 'static>> {
async fn signer(&self) -> Result<Box<dyn TxSigner<Signature> + Send + Sync + 'static>> {
let signer: Box<dyn TxSigner<Signature> + Send + Sync + 'static> = match self {
SignerConfig::PrivateKey(key) => Box::new(key.parse::<PrivateKeySigner>()?),
SignerConfig::Mnemonic(mnemonic) => Box::new(
Expand Down Expand Up @@ -87,40 +58,24 @@ impl SignerConfig {
Ok(signer)
}

pub async fn sign_transaction(&self, tx: TypedTransaction) -> Result<Signature> {
pub async fn wallet(&self) -> Result<EthereumWallet> {
let signer = self.signer().await?;

match tx {
TypedTransaction::Eip1559(tx) => {
let mut tx_1559 = tx.clone();

signer
.sign_transaction(&mut tx_1559)
.await
.map_err(Error::SignerError)
}
TypedTransaction::Eip2930(tx) => {
let mut tx_2930 = tx.clone();

signer
.sign_transaction(&mut tx_2930)
.await
.map_err(Error::SignerError)
}
TypedTransaction::Eip4844(tx) => {
let mut tx_4844 = tx.clone();

signer
.sign_transaction(&mut tx_4844)
.await
.map_err(Error::SignerError)
}
tx => Err(Error::InvalidTransactionType(tx.tx_type().to_string())),
}
Ok(EthereumWallet::new(signer))
}

pub async fn address(&self) -> Result<Address> {
let signer = self.signer().await?;
Ok(signer.address())
}
}

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

// #[test]
// fn test_rlp() {
// let rlp = "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b";
// let tx = TypedTransaction::
// }
}

0 comments on commit 4eb731b

Please sign in to comment.