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

Murisi/fix tx malleability #1607

Merged
merged 10 commits into from
Jul 6, 2023
6 changes: 1 addition & 5 deletions apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use namada::types::address::Address;
use namada::types::governance::{
OfflineProposal, OfflineVote, Proposal, ProposalVote, VoteType,
};
use namada::types::hash::Hash;
use namada::types::key::*;
use namada::types::storage::{Epoch, Key};
use namada::types::token;
Expand All @@ -31,7 +30,6 @@ use namada::types::transaction::governance::{
};
use namada::types::transaction::{InitValidator, TxType};
use rust_decimal::Decimal;
use sha2::{Digest as Sha2Digest, Sha256};

use super::rpc;
use crate::cli::context::WalletAddress;
Expand Down Expand Up @@ -213,16 +211,14 @@ pub async fn submit_init_validator<
let extra = tx.add_section(Section::ExtraData(Code::from_hash(
validator_vp_code_hash,
)));
let extra_hash =
Hash(extra.hash(&mut Sha256::new()).finalize_reset().into());
let data = InitValidator {
account_key,
consensus_key: consensus_key.ref_to(),
protocol_key,
dkg_key,
commission_rate,
max_commission_rate_change,
validator_vp_code_hash: extra_hash,
validator_vp_code_hash: extra.get_hash(),
};
let data = data.try_to_vec().expect("Encoding tx data shouldn't fail");
tx.header.chain_id = tx_args.chain_id.clone().unwrap();
Expand Down
15 changes: 9 additions & 6 deletions apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ where
continue;
}

let tx = if let Ok(()) = tx.validate_header() {
let tx = if tx.validate_tx().is_ok() {
tx
} else {
tracing::error!(
Expand Down Expand Up @@ -307,7 +307,7 @@ where
DecryptedTx::Decrypted { has_valid_pow: _ } => {
if let Some(code_sec) = tx
.get_section(tx.code_sechash())
.and_then(Section::code_sec)
.and_then(|x| Section::code_sec(x.as_ref()))
{
stats.increment_tx_type(
code_sec.code.hash().to_string(),
Expand Down Expand Up @@ -980,11 +980,11 @@ mod test_finalize_block {
wrapper.set_code(Code::new(
format!("transaction data: {}", i).as_bytes().to_owned(),
));
wrapper.encrypt(&Default::default());
wrapper.add_section(Section::Signature(Signature::new(
&wrapper.header_hash(),
vec![wrapper.header_hash(), wrapper.sections[0].get_hash()],
&keypair,
)));
wrapper.encrypt(&Default::default());
if i > 1 {
processed_txs.push(ProcessedTx {
tx: wrapper.to_bytes(),
Expand Down Expand Up @@ -1215,11 +1215,14 @@ mod test_finalize_block {
.as_bytes()
.to_owned(),
));
wrapper_tx.encrypt(&Default::default());
wrapper_tx.add_section(Section::Signature(Signature::new(
&wrapper_tx.header_hash(),
vec![
wrapper_tx.header_hash(),
wrapper_tx.sections[0].get_hash(),
],
&keypair,
)));
wrapper_tx.encrypt(&Default::default());
valid_txs.push(wrapper_tx.clone());
processed_txs.push(ProcessedTx {
tx: wrapper_tx.to_bytes(),
Expand Down
27 changes: 19 additions & 8 deletions apps/src/lib/node/ledger/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,8 +772,8 @@ where
}

// Tx signature check
let tx_type = match tx.validate_header() {
Ok(()) => tx.header(),
let tx_type = match tx.validate_tx() {
Ok(_) => tx.header(),
Err(msg) => {
response.code = ErrorCodes::InvalidSig.into();
response.log = msg.to_string();
Expand Down Expand Up @@ -1357,11 +1357,14 @@ mod test_mempool_validate {
invalid_wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
invalid_wrapper
.set_data(Data::new("transaction data".as_bytes().to_owned()));
invalid_wrapper.encrypt(&Default::default());
invalid_wrapper.add_section(Section::Signature(Signature::new(
&invalid_wrapper.header_hash(),
vec![
invalid_wrapper.header_hash(),
invalid_wrapper.sections[0].get_hash(),
],
&keypair,
)));
invalid_wrapper.encrypt(&Default::default());

// we mount a malleability attack to try and remove the fee
let mut new_wrapper =
Expand Down Expand Up @@ -1421,11 +1424,11 @@ mod test_mempool_validate {
wrapper.header.chain_id = shell.chain_id.clone();
wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
wrapper.encrypt(&Default::default());
wrapper.add_section(Section::Signature(Signature::new(
&wrapper.header_hash(),
vec![wrapper.header_hash(), wrapper.sections[0].get_hash()],
&keypair,
)));
wrapper.encrypt(&Default::default());

// Write wrapper hash to storage
let wrapper_hash = wrapper.header_hash();
Expand Down Expand Up @@ -1517,7 +1520,11 @@ mod test_mempool_validate {
tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
tx.add_section(Section::Signature(Signature::new(
&tx.header_hash(),
vec![
tx.header_hash(),
tx.sections[0].get_hash(),
tx.sections[1].get_hash(),
],
&keypair,
)));

Expand Down Expand Up @@ -1548,7 +1555,11 @@ mod test_mempool_validate {
tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
tx.add_section(Section::Signature(Signature::new(
&tx.header_hash(),
vec![
tx.header_hash(),
tx.sections[0].get_hash(),
tx.sections[1].get_hash(),
],
&keypair,
)));

Expand Down
33 changes: 18 additions & 15 deletions apps/src/lib/node/ledger/shell/prepare_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ where
if let (Some(block_time), Some(exp)) = (block_time.as_ref(), &tx.header.expiration) {
if block_time > exp { return None }
}
if tx.validate_header().is_ok() && tx.header().wrapper().is_some() && self.replay_protection_checks(&tx, tx_bytes.as_slice(), &mut temp_wl_storage).is_ok() {
if tx.validate_tx().is_ok() && tx.header().wrapper().is_some() && self.replay_protection_checks(&tx, tx_bytes.as_slice(), &mut temp_wl_storage).is_ok() {
return Some(tx_bytes.clone());
}
}
Expand Down Expand Up @@ -370,11 +370,11 @@ mod test_prepare_proposal {
tx.set_data(Data::new(
format!("transaction data: {}", i).as_bytes().to_owned(),
));
tx.encrypt(&Default::default());
tx.add_section(Section::Signature(Signature::new(
&tx.header_hash(),
vec![tx.header_hash(), tx.sections[0].get_hash()],
&keypair,
)));
tx.encrypt(&Default::default());

shell.enqueue_tx(tx.clone());
expected_wrapper.push(tx.clone());
Expand Down Expand Up @@ -437,11 +437,11 @@ mod test_prepare_proposal {
wrapper.header.chain_id = shell.chain_id.clone();
wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
wrapper.encrypt(&Default::default());
wrapper.add_section(Section::Signature(Signature::new(
&wrapper.header_hash(),
vec![wrapper.header_hash(), wrapper.sections[0].get_hash()],
&keypair,
)));
wrapper.encrypt(&Default::default());

// Write wrapper hash to storage
let wrapper_unsigned_hash = wrapper.header_hash();
Expand Down Expand Up @@ -489,11 +489,11 @@ mod test_prepare_proposal {
wrapper.header.chain_id = shell.chain_id.clone();
wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
wrapper.encrypt(&Default::default());
wrapper.add_section(Section::Signature(Signature::new(
&wrapper.header_hash(),
vec![wrapper.header_hash(), wrapper.sections[0].get_hash()],
&keypair,
)));
wrapper.encrypt(&Default::default());

let req = RequestPrepareProposal {
txs: vec![wrapper.to_bytes(); 2],
Expand Down Expand Up @@ -530,11 +530,11 @@ mod test_prepare_proposal {
wrapper.header.chain_id = shell.chain_id.clone();
wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
wrapper.encrypt(&Default::default());
wrapper.add_section(Section::Signature(Signature::new(
&wrapper.header_hash(),
vec![wrapper.header_hash(), wrapper.sections[0].get_hash()],
&keypair,
)));
wrapper.encrypt(&Default::default());
let inner_unsigned_hash =
wrapper.clone().update_header(TxType::Raw).header_hash();

Expand Down Expand Up @@ -585,11 +585,11 @@ mod test_prepare_proposal {
wrapper.set_code(tx_code.clone());
let tx_data = Data::new("transaction data".as_bytes().to_owned());
wrapper.set_data(tx_data.clone());
wrapper.encrypt(&Default::default());
wrapper.add_section(Section::Signature(Signature::new(
&wrapper.header_hash(),
vec![wrapper.header_hash(), wrapper.sections[0].get_hash()],
&keypair,
)));
wrapper.encrypt(&Default::default());

let mut new_wrapper =
Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Expand All @@ -607,11 +607,14 @@ mod test_prepare_proposal {
new_wrapper.header.timestamp = wrapper.header.timestamp;
new_wrapper.set_code(tx_code);
new_wrapper.set_data(tx_data);
new_wrapper.encrypt(&Default::default());
new_wrapper.add_section(Section::Signature(Signature::new(
&new_wrapper.header_hash(),
vec![
new_wrapper.header_hash(),
new_wrapper.sections[0].get_hash(),
],
&keypair,
)));
new_wrapper.encrypt(&Default::default());

let req = RequestPrepareProposal {
txs: vec![wrapper.to_bytes(), new_wrapper.to_bytes()],
Expand Down Expand Up @@ -650,11 +653,11 @@ mod test_prepare_proposal {
wrapper_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
wrapper_tx
.set_data(Data::new("transaction data".as_bytes().to_owned()));
wrapper_tx.encrypt(&Default::default());
wrapper_tx.add_section(Section::Signature(Signature::new(
&wrapper_tx.header_hash(),
vec![wrapper_tx.header_hash(), wrapper_tx.sections[0].get_hash()],
&keypair,
)));
wrapper_tx.encrypt(&Default::default());

let time = DateTimeUtc::now();
let block_time =
Expand Down
Loading