From b2fce98765b6e469d2b5a686f82e53e67703122f Mon Sep 17 00:00:00 2001 From: moana Date: Mon, 9 Sep 2024 11:16:11 +0200 Subject: [PATCH] execution-core: Support unsigned moonlight transactions Resolves: #2304 --- execution-core/src/transfer/moonlight.rs | 61 +++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/execution-core/src/transfer/moonlight.rs b/execution-core/src/transfer/moonlight.rs index c12ffa481c..f39ebdea73 100644 --- a/execution-core/src/transfer/moonlight.rs +++ b/execution-core/src/transfer/moonlight.rs @@ -87,6 +87,23 @@ impl Transaction { Ok(Self { payload, signature }) } + /// Create a transaction by signing a previously generated payload with a + /// given secret-key. + /// + /// Note that this transaction will be invalid if the secret-key used for + /// signing doesn't form a valid key-pair with the public-key of the + /// `from_account`. + #[must_use] + pub fn new_from_payload( + from_sk: &AccountSecretKey, + payload: Payload, + ) -> Self { + let digest = payload.signature_message(); + let signature = from_sk.sign(&digest); + + Self { payload, signature } + } + /// The proof of the transaction. #[must_use] pub fn signature(&self) -> &AccountSignature { @@ -267,7 +284,7 @@ impl Transaction { /// The payload for a moonlight transaction. #[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)] #[archive_attr(derive(CheckBytes))] -struct Payload { +pub struct Payload { /// ID of the chain for this transaction to execute on. pub chain_id: u8, /// Key of the sender of this transaction. @@ -293,6 +310,48 @@ struct Payload { } impl Payload { + /// Create a new unsigned transaction-payload. + /// This can be used to generate a transaction payload without the + /// secret-key of the sender. + /// + /// To generate a valid transaction, the sender will need to sign the + /// transaction at a later point, using [`Transaction::new_from_payload`] + /// with the secret-key that forms a valid key-pair with the public-key + /// of the `from_account`. + /// + /// # Errors + /// The creation of a transaction is not possible and will error if: + /// - the memo, if given, is too large + pub fn new_unsigned( + from_account: AccountPublicKey, + deposit: u64, + gas_limit: u64, + gas_price: u64, + nonce: u64, + chain_id: u8, + data: Option>, + ) -> Result { + let data = data.map(Into::into); + + if let Some(TransactionData::Memo(memo)) = data.as_ref() { + if memo.len() > MAX_MEMO_SIZE { + return Err(Error::MemoTooLarge(memo.len())); + } + } + + Ok(Self { + chain_id, + from_account, + to_account: None, + value: 0, + deposit, + gas_limit, + gas_price, + nonce, + data, + }) + } + /// Serialize the payload into a byte buffer. #[must_use] pub fn to_var_bytes(&self) -> Vec {