diff --git a/pallets/passkey/src/tests.rs b/pallets/passkey/src/tests.rs index 6eda343f11..10dad35384 100644 --- a/pallets/passkey/src/tests.rs +++ b/pallets/passkey/src/tests.rs @@ -1,50 +1,134 @@ //! Unit tests for the passkey module. use super::*; use crate::mock::Passkey; -use common_primitives::utils::wrap_binary_data; -use frame_support::{assert_err, assert_noop, assert_ok}; -use frame_system::{limits::BlockLength, Call as SystemCall, RawOrigin}; +use frame_support::{assert_err, assert_noop, assert_ok, dispatch::RawOrigin}; +use frame_system::{limits::BlockLength, Call as SystemCall}; use mock::*; -use crate::test_common::{constants::*, utilities::*}; +use crate::test_common::{ + constants::{AUTHENTICATOR_DATA, REPLACED_CLIENT_DATA_JSON}, + utilities::*, +}; use pallet_balances::Call as BalancesCall; -use sp_core::{sr25519, Pair}; -use sp_runtime::{traits::One, DispatchError::BadOrigin, MultiSignature}; +use sp_core::{sr25519, sr25519::Public, Pair}; +use sp_runtime::{traits::One, DispatchError::BadOrigin}; + +struct TestPasskeyPayloadBuilder { + secret: p256::SecretKey, + key_pair: sr25519::Pair, + passkey_public_key: PasskeyPublicKey, + payload_to_sign: Vec, + nonce: u32, + call: ::RuntimeCall, + invalid_passkey_signature: bool, +} -#[test] -fn proxy_call_with_signed_origin_should_fail() { - new_test_ext().execute_with(|| { - // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - let passkey_public_key = PasskeyPublicKey([0u8; 33]); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); +impl TestPasskeyPayloadBuilder { + pub fn new() -> Self { + let (key_pair, _) = sr25519::Pair::generate(); + Self { + secret: p256::SecretKey::from_slice(&[ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, + ]) + .unwrap(), + key_pair, + passkey_public_key: PasskeyPublicKey([0u8; 33]), + payload_to_sign: vec![], + nonce: 0u32.into(), + call: RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] }).into(), + invalid_passkey_signature: false, + } + } + + pub fn with_a_valid_passkey(mut self) -> Self { + self.passkey_public_key = get_p256_public_key(&self.secret).unwrap(); + self + } + + pub fn with_custom_payload(mut self, payload: Vec) -> Self { + self.payload_to_sign = payload; + self + } + + pub fn with_passkey_as_payload(mut self) -> Self { + self.payload_to_sign = self.passkey_public_key.inner().to_vec(); + self + } + + pub fn with_account_nonce(mut self, nonce: u32) -> Self { + self.nonce = nonce; + self + } + + pub fn with_call(mut self, call: ::RuntimeCall) -> Self { + self.call = call; + self + } + + pub fn with_invalid_passkey_signature(mut self) -> Self { + self.invalid_passkey_signature = true; + self + } + + pub fn with_funded_account(self, amount: u64) -> Self { + assert_ok!(Balances::force_set_balance( + RawOrigin::Root.into(), + self.key_pair.public().into(), + amount.into() + )); + self + } + + pub fn build(&self) -> (PasskeyPayload, Public) { + let wrapped_binary = wrap_binary_data(self.payload_to_sign.clone()); + let signature: MultiSignature = self.key_pair.sign(wrapped_binary.as_slice()).into(); + let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); + let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); + let bad_authenticator = b"bad_auth".to_vec(); let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, + account_id: self.key_pair.public().into(), + account_nonce: self.nonce.into(), account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: test_account_2_key_pair.public().into(), - value: 100, - })), - }; + call: Box::new(self.call.clone()), + }; + let passkey_signature = passkey_sign( + &self.secret, + &call.encode(), + &client_data, + match self.invalid_passkey_signature { + true => &bad_authenticator, + false => &authenticator, + }, + ) + .unwrap(); let payload = PasskeyPayload { - passkey_public_key, + passkey_public_key: self.passkey_public_key.clone(), verifiable_passkey_signature: VerifiablePasskeySignature { - signature: PasskeySignature::default(), - client_data_json: PasskeyClientDataJson::default(), - authenticator_data: PasskeyAuthenticatorData::default(), + signature: passkey_signature, + client_data_json: client_data.try_into().unwrap(), + authenticator_data: authenticator.try_into().unwrap(), }, passkey_call: call, }; + (payload, self.key_pair.public()) + } +} + +#[test] +fn proxy_call_with_signed_origin_should_fail() { + new_test_ext().execute_with(|| { + // arrange + let (test_account_2_key_pair, _) = sr25519::Pair::generate(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: test_account_2_key_pair.public().into(), + value: 100, + })) + .build(); // assert - assert_noop!( - Passkey::proxy(RuntimeOrigin::signed(test_account_1_key_pair.public().into()), payload), - BadOrigin - ); + assert_noop!(Passkey::proxy(RuntimeOrigin::signed(account_pk.into()), payload), BadOrigin); }); } @@ -52,26 +136,10 @@ fn proxy_call_with_signed_origin_should_fail() { fn proxy_call_with_unsigned_origin_should_work() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let passkey_public_key = PasskeyPublicKey([0u8; 33]); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: PasskeySignature::default(), - client_data_json: PasskeyClientDataJson::default(), - authenticator_data: PasskeyAuthenticatorData::default(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .build(); // assert assert_ok!(Passkey::proxy(RuntimeOrigin::none(), payload)); @@ -82,43 +150,12 @@ fn proxy_call_with_unsigned_origin_should_work() { fn validate_unsigned_with_bad_account_signature_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - // fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let balance_after = Balances::free_balance(&test_account_1_key_pair.public().into()); - assert_eq!(balance_after, 10000000000); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data("bad data".as_bytes().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_custom_payload("bad data".as_bytes().to_vec()) + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .with_funded_account(10000000000) + .build(); let res = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); // assert @@ -130,48 +167,20 @@ fn validate_unsigned_with_bad_account_signature_should_fail() { fn validate_unsigned_with_bad_passkey_signature_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - // fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - let bad_authenticator = b"bad_auth".to_vec(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &bad_authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let amount = 10000000000; + let (payload, account_public) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .with_funded_account(amount) + .with_invalid_passkey_signature() + .build(); let res = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); // assert assert_eq!(res, InvalidTransaction::BadSigner.into()); - let balance_after = Balances::free_balance(&test_account_1_key_pair.public().into()); - assert_eq!(balance_after, 10000000000); + let balance_after = Balances::free_balance(&account_public.into()); + assert_eq!(balance_after, amount); }); } @@ -179,34 +188,13 @@ fn validate_unsigned_with_bad_passkey_signature_should_fail() { fn validate_unsigned_with_low_funds_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .build(); + + // act let res = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); // assert assert_eq!(res, InvalidTransaction::Payment.into()); @@ -217,43 +205,16 @@ fn validate_unsigned_with_low_funds_should_fail() { fn validate_unsigned_with_funds_should_pass() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - // fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let balance_after = Balances::free_balance(&test_account_1_key_pair.public().into()); - assert_eq!(balance_after, 10000000000); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .with_funded_account(10000000000) + .build(); + + // act let res = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); + // assert assert!(res.is_ok()); }); @@ -263,43 +224,16 @@ fn validate_unsigned_with_funds_should_pass() { fn pre_dispatch_with_funds_should_pass() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - // fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let balance_after = Balances::free_balance(&test_account_1_key_pair.public().into()); - assert_eq!(balance_after, 10000000000); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .with_funded_account(10000000000) + .build(); + + // act let res = Passkey::pre_dispatch(&Call::proxy { payload }); + // assert assert!(res.is_ok()); }); @@ -309,38 +243,17 @@ fn pre_dispatch_with_funds_should_pass() { fn pre_dispatch_with_low_funds_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; - let res = Passkey::pre_dispatch(&Call::proxy { payload }).unwrap_err(); + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .build(); + + // act + let res = Passkey::pre_dispatch(&Call::proxy { payload }); // assert - assert_eq!(res, InvalidTransaction::Payment.into()); + assert_err!(res, InvalidTransaction::Payment); }); } @@ -348,49 +261,19 @@ fn pre_dispatch_with_low_funds_should_fail() { fn validate_unsigned_should_fee_removed_on_successful_validation() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - let account_id: ::AccountId = - test_account_1_key_pair.public().into(); - let destination_id = test_account_2_key_pair.public().into(); - // Fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - account_id.clone(), - 10000000000 - )); - let initial_balance = Balances::free_balance(&account_id); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: test_account_2_key_pair.public().into(), + value: 100, + })) + .with_funded_account(10000000000) + .build(); - let call: PasskeyCall = PasskeyCall { - account_id: account_id.clone(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: destination_id, - value: 10000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let account_id: ::AccountId = account_pk.into(); + let initial_balance = Balances::free_balance(&account_id); // act let res = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); @@ -406,48 +289,20 @@ fn validate_unsigned_should_fee_removed_on_successful_validation() { fn fee_withdrawn_for_failed_call() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let account_id: ::AccountId = - test_account_1_key_pair.public().into(); - // Fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - account_id.clone(), - 10000000000 - )); - let initial_balance = Balances::free_balance(&account_id); - - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); + let amount = 10000000000; + let (test_account_2_key_pair, _) = sr25519::Pair::generate(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: test_account_2_key_pair.public().into(), + value: amount, + })) + .with_funded_account(amount) + .build(); - let call: PasskeyCall = PasskeyCall { - account_id: account_id.clone(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: account_id.clone(), - value: 10000000000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let account_id: ::AccountId = account_pk.into(); + let initial_balance = Balances::free_balance(&account_id); // act let validate_result = Passkey::validate_unsigned( @@ -468,44 +323,16 @@ fn fee_withdrawn_for_failed_call() { fn fee_not_removed_on_failed_validation() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let account_id: ::AccountId = - test_account_1_key_pair.public().into(); - // Fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - account_id.clone(), - 10000000000 - )); + let amount = 10000000000; + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_custom_payload(b"invalid data".to_vec()) + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })) + .with_funded_account(amount) + .build(); + + let account_id: ::AccountId = account_pk.into(); let initial_balance = Balances::free_balance(&account_id); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data("invalid data".as_bytes().to_vec()); - let signature: MultiSignature = - test_account_1_key_pair.sign(wrapped_binary.as_slice()).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - - let call: PasskeyCall = PasskeyCall { - account_id: account_id.clone(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { remark: vec![1, 2, 3u8] })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; // act let res = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); @@ -521,34 +348,20 @@ fn fee_not_removed_on_failed_validation() { fn validate_unsigned_with_unsupported_call_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let wrapped_binary = wrap_binary_data("data".as_bytes().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 3, - account_ownership_proof: signature, - // remark is an unsupported call - call: Box::new(RuntimeCall::System(SystemCall::remark_with_event { + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + // remark_with_event is an unsupported call + .with_call(RuntimeCall::System(SystemCall::remark_with_event { remark: vec![1, 2, 3u8], - })), - }; - let payload = PasskeyPayload { - passkey_public_key: PasskeyPublicKey([0u8; 33]), - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: PasskeySignature::default(), - client_data_json: PasskeyClientDataJson::default(), - authenticator_data: PasskeyAuthenticatorData::default(), - }, - passkey_call: call, - }; + })) + .build(); // act let v = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); // assert - let err: TransactionValidityError = InvalidTransaction::Call.into(); - assert_err!(v, err); + assert_err!(v, InvalidTransaction::Call); }); } @@ -556,57 +369,28 @@ fn validate_unsigned_with_unsupported_call_should_fail() { fn validate_unsigned_with_used_nonce_should_fail_with_stale() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - // Fund - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let who: ::AccountId = - test_account_1_key_pair.public().into(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: test_account_2_key_pair.public().into(), + value: 10000, + })) + .with_funded_account(10000000000) + .with_account_nonce(0) + .build(); + + let who: ::AccountId = account_pk.into(); let mut account = frame_system::Account::::get(&who); account.nonce += 1; frame_system::Account::::insert(who, account); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: test_account_2_key_pair.public().into(), - value: 10000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; - // act let v = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); // assert - let err: TransactionValidityError = InvalidTransaction::Stale.into(); - assert_err!(v, err); + assert_err!(v, InvalidTransaction::Stale); }); } @@ -614,51 +398,23 @@ fn validate_unsigned_with_used_nonce_should_fail_with_stale() { fn validate_unsigned_with_correct_nonce_should_work() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - // Fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let who: ::AccountId = - test_account_1_key_pair.public().into(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: test_account_2_key_pair.public().into(), + value: 10000, + })) + .with_funded_account(10000000000) + .with_account_nonce(2) + .build(); + + let who: ::AccountId = account_pk.into(); let mut account = frame_system::Account::::get(&who); account.nonce += 1; frame_system::Account::::insert(who.clone(), account); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 2, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: test_account_2_key_pair.public().into(), - value: 10000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; - // act let v = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); @@ -674,57 +430,20 @@ fn validate_unsigned_with_correct_nonce_should_work() { fn validate_unsigned_with_exceeding_weights_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - // Fund the account - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let who: ::AccountId = - test_account_1_key_pair.public().into(); - let mut account = frame_system::Account::::get(&who); - account.nonce += 1; - frame_system::Account::::insert(who.clone(), account); - - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); let block_length = BlockLength::default(); let max = block_length.max.get(DispatchClass::Normal); - - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 2, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { - remark: vec![1u8; *max as usize], - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1u8; *max as usize] })) + .with_funded_account(10000000000) + .build(); // act let v = Passkey::validate_unsigned(TransactionSource::InBlock, &Call::proxy { payload }); // assert - let err: TransactionValidityError = InvalidTransaction::ExhaustsResources.into(); - assert_err!(v, err); + assert_err!(v, InvalidTransaction::ExhaustsResources); }); } @@ -732,57 +451,27 @@ fn validate_unsigned_with_exceeding_weights_should_fail() { fn pre_dispatch_unsigned_with_used_nonce_should_fail_with_stale() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - // Fund - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let who: ::AccountId = - test_account_1_key_pair.public().into(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: test_account_2_key_pair.public().into(), + value: 10000, + })) + .with_funded_account(10000000000) + .with_account_nonce(0) + .build(); + let who: ::AccountId = account_pk.into(); let mut account = frame_system::Account::::get(&who); account.nonce += 1; frame_system::Account::::insert(who, account); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: test_account_2_key_pair.public().into(), - value: 10000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; - // act let v = Passkey::pre_dispatch(&Call::proxy { payload }); // assert - let err: TransactionValidityError = InvalidTransaction::Stale.into(); - assert_err!(v, err); + assert_err!(v, InvalidTransaction::Stale); }); } @@ -790,51 +479,24 @@ fn pre_dispatch_unsigned_with_used_nonce_should_fail_with_stale() { fn pre_dispatch_unsigned_with_future_nonce_should_fail_with_future() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - // Fund - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - test_account_1_key_pair.public().into(), - 10000000000 - )); - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); - - let call: PasskeyCall = PasskeyCall { - account_id: test_account_1_key_pair.public().into(), - account_nonce: 2, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: test_account_2_key_pair.public().into(), value: 10000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + })) + .with_funded_account(10000000000) + // setting a future nonce + .with_account_nonce(2) + .build(); // act let v = Passkey::pre_dispatch(&Call::proxy { payload }); // assert - let err: TransactionValidityError = InvalidTransaction::Future.into(); - assert_err!(v, err); + assert_err!(v, InvalidTransaction::Future); }); } @@ -842,51 +504,18 @@ fn pre_dispatch_unsigned_with_future_nonce_should_fail_with_future() { fn pre_dispatch_unsigned_should_increment_nonce_on_success() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let account_1_pk: ::AccountId = - test_account_1_key_pair.public().into(); - // Fund - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - account_1_pk.clone(), - 10000000000 - )); - let (test_account_2_key_pair, _) = sr25519::Pair::generate(); - - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); + let (payload, account_pk) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1u8; 3usize] })) + .with_funded_account(10000000000) + .build(); + let account_1_pk: ::AccountId = account_pk.into(); - let call: PasskeyCall = PasskeyCall { - account_id: account_1_pk.clone(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: test_account_2_key_pair.public().into(), - value: 10000, - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; - - // act assert + // act assert_ok!(Passkey::pre_dispatch(&Call::proxy { payload })); + // assert let account = frame_system::Account::::get(&account_1_pk); assert_eq!(account.nonce, ::Nonce::one()); }); @@ -896,53 +525,19 @@ fn pre_dispatch_unsigned_should_increment_nonce_on_success() { fn pre_dispatch_with_exceeding_weight_should_fail() { new_test_ext().execute_with(|| { // arrange - let (test_account_1_key_pair, _) = sr25519::Pair::generate(); - let account_1_pk: ::AccountId = - test_account_1_key_pair.public().into(); - // Fund - assert_ok!(Balances::force_set_balance( - RawOrigin::Root.into(), - account_1_pk.clone(), - 10000000000 - )); - - let secret = p256::SecretKey::from_slice(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, - ]) - .unwrap(); - let passkey_public_key = get_p256_public_key(&secret).unwrap(); - let wrapped_binary = wrap_binary_data(passkey_public_key.inner().to_vec()); - let signature: MultiSignature = test_account_1_key_pair.sign(&wrapped_binary).into(); - let client_data = base64_url::decode(REPLACED_CLIENT_DATA_JSON).unwrap(); - let authenticator = base64_url::decode(AUTHENTICATOR_DATA).unwrap(); let block_length = BlockLength::default(); let max = block_length.max.get(DispatchClass::Normal); - - let call: PasskeyCall = PasskeyCall { - account_id: account_1_pk.clone(), - account_nonce: 0, - account_ownership_proof: signature, - call: Box::new(RuntimeCall::System(SystemCall::remark { - remark: vec![1u8; *max as usize], - })), - }; - let passkey_signature = - passkey_sign(&secret, &call.encode(), &client_data, &authenticator).unwrap(); - let payload = PasskeyPayload { - passkey_public_key, - verifiable_passkey_signature: VerifiablePasskeySignature { - signature: passkey_signature, - client_data_json: client_data.try_into().unwrap(), - authenticator_data: authenticator.try_into().unwrap(), - }, - passkey_call: call, - }; + let (payload, _) = TestPasskeyPayloadBuilder::new() + .with_a_valid_passkey() + .with_passkey_as_payload() + .with_call(RuntimeCall::System(SystemCall::remark { remark: vec![1u8; *max as usize] })) + .with_funded_account(10000000000) + .build(); // act let v = Passkey::pre_dispatch(&Call::proxy { payload }); // assert - let err: TransactionValidityError = InvalidTransaction::ExhaustsResources.into(); - assert_err!(v, err); + assert_err!(v, InvalidTransaction::ExhaustsResources); }); }