Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ethereum::transact call allows to be executed by different origins with the same transaction signature #1066

Open
dmitrylavrenov opened this issue May 29, 2023 · 3 comments
Labels

Comments

@dmitrylavrenov
Copy link
Contributor

dmitrylavrenov commented May 29, 2023

Question

What is the reason that Ethereum::transact call allows to be executed by different origins with the same transaction signature?

Input info

During the pallet-ethereum code research the following implementation has been discovered - https://github.com/paritytech/frontier/blob/4b1b16846aeca5856e33dc38fa5bf12e5e64ebb5/frame/ethereum/src/lib.rs#L282.

At the beginning, it's checked that the transaction is ethereum transaction by let source = ensure_ethereum_transaction(origin)?;. Then, Self::apply_validated_transaction(source, transaction) is applied without verifying that the real signature of the transaction corresponds to source trx sender.

Proof

There is the following test in frontier code base that checks nonce incrementation for origin that executes transaction - https://github.com/paritytech/frontier/blob/4b1b16846aeca5856e33dc38fa5bf12e5e64ebb5/frame/ethereum/src/tests/legacy.rs#L45

I've added the following test with the Alice transaction signature that is executed by Bob to check our thoughts.

#[test]
fn check_source_origin() {
	let (pairs, mut ext) = new_test_ext(2);
	let alice = &pairs[0];
	let bob = &pairs[1];

	ext.execute_with(|| {
		let t = legacy_erc20_creation_transaction(alice);
		assert_ok!(Ethereum::execute(bob.address, &t, None,));
		assert_eq!(EVM::account_basic(&bob.address).0.nonce, U256::from(1));
                assert_eq!(EVM::account_basic(&alice.address).0.nonce, U256::from(0));
	});
}

The test is passed successfully. So, Alice transaction is executed by Bob and nonce is increased for Bob.

I would like to understand the correct behaviour here to prevent any vulnerabilities in frontier logic usage at our https://github.com/humanode-network/humanode repo.

CC @MOZGIII

@sorpaas
Copy link
Member

sorpaas commented May 29, 2023

The signature verification does not happen in pallets. Instead, it happens in a lower layer of runtime, as a special type of extrinsic. See https://github.com/paritytech/frontier/tree/4b1b16846aeca5856e33dc38fa5bf12e5e64ebb5/primitives/self-contained

@dmitrylavrenov
Copy link
Contributor Author

The signature verification does not happen in pallets. Instead, it happens in a lower layer of runtime, as a special type of extrinsic. See https://github.com/paritytech/frontier/tree/4b1b16846aeca5856e33dc38fa5bf12e5e64ebb5/primitives/self-contained

I've walked through the code and looks like I got your idea. Let me clarify it.

  • pallet_ethereum::transact call can be submitted only via extrinsic call as signed extrinsic.
  • there are CheckedExtrinsic and UncheckedExtrinsic at self-contained logic that implement traits::Applyable with validate and verify methods including signatures verification logic.

To sum up, the pallet relies on checks before that applies during extrinsic submission?

@dmitrylavrenov
Copy link
Contributor Author

@sorpaas any news?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants