Skip to content

Commit

Permalink
Merge branch 'murisi/move-init-proposal-content' (#1611)
Browse files Browse the repository at this point in the history
* origin/murisi/move-init-proposal-content:
  Added changelog entry.
  Fixed processing of code inside init-proposal transactions.
  Added CLI subcommand for validator change commission. Cleared up the MASP source and target in test vector expert view.
  Now moving proposal code into extra section.
  Increased the number of init-proposal and vote-proposal test vectors. Moved init-proposal content into extra data.
  • Loading branch information
Fraccaman committed Jul 6, 2023
2 parents 7936f71 + 8ef2d92 commit 1179811
Show file tree
Hide file tree
Showing 24 changed files with 511 additions and 183 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Move the content and code of init proposal transactions
into separare section to reduce tx size for hardware wallets
([\#1611](https://github.com/anoma/namada/pull/1611))
11 changes: 11 additions & 0 deletions apps/src/bin/namada-client/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ pub async fn main() -> Result<()> {
tx::submit_withdraw::<HttpClient>(&client, ctx, args)
.await?;
}
Sub::TxCommissionRateChange(TxCommissionRateChange(args)) => {
wait_until_node_is_synched(&args.tx.ledger_address).await;
let client =
HttpClient::new(args.tx.ledger_address.clone())
.unwrap();
let args = args.to_sdk(&mut ctx);
tx::submit_validator_commission_change::<HttpClient>(
&client, ctx, args,
)
.await?;
}
// Ledger queries
Sub::QueryEpoch(QueryEpoch(args)) => {
wait_until_node_is_synched(&args.ledger_address).await;
Expand Down
41 changes: 36 additions & 5 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ pub mod cmds {
.subcommand(Bond::def().display_order(2))
.subcommand(Unbond::def().display_order(2))
.subcommand(Withdraw::def().display_order(2))
.subcommand(TxCommissionRateChange::def().display_order(2))
// Queries
.subcommand(QueryEpoch::def().display_order(3))
.subcommand(QueryTransfers::def().display_order(3))
Expand Down Expand Up @@ -198,6 +199,8 @@ pub mod cmds {
Self::parse_with_ctx(matches, TxInitProposal);
let tx_vote_proposal =
Self::parse_with_ctx(matches, TxVoteProposal);
let tx_commission_rate_change =
Self::parse_with_ctx(matches, TxCommissionRateChange);
let bond = Self::parse_with_ctx(matches, Bond);
let unbond = Self::parse_with_ctx(matches, Unbond);
let withdraw = Self::parse_with_ctx(matches, Withdraw);
Expand Down Expand Up @@ -232,6 +235,7 @@ pub mod cmds {
.or(tx_init_proposal)
.or(tx_vote_proposal)
.or(tx_init_validator)
.or(tx_commission_rate_change)
.or(bond)
.or(unbond)
.or(withdraw)
Expand Down Expand Up @@ -294,6 +298,7 @@ pub mod cmds {
TxUpdateVp(TxUpdateVp),
TxInitAccount(TxInitAccount),
TxInitValidator(TxInitValidator),
TxCommissionRateChange(TxCommissionRateChange),
TxInitProposal(TxInitProposal),
TxVoteProposal(TxVoteProposal),
TxRevealPk(TxRevealPk),
Expand Down Expand Up @@ -1534,6 +1539,32 @@ pub mod cmds {
}
}

#[derive(Clone, Debug)]
pub struct TxCommissionRateChange(
pub args::CommissionRateChange<args::CliTypes>,
);

impl SubCmd for TxCommissionRateChange {
const CMD: &'static str = "change-commission-rate";

fn parse(matches: &ArgMatches) -> Option<Self>
where
Self: Sized,
{
matches.subcommand_matches(Self::CMD).map(|matches| {
TxCommissionRateChange(args::CommissionRateChange::parse(
matches,
))
})
}

fn def() -> App {
App::new(Self::CMD)
.about("Change commission raate.")
.add_args::<args::CommissionRateChange<args::CliTypes>>()
}
}

#[derive(Clone, Debug)]
pub struct TxVoteProposal(pub args::VoteProposal<args::CliTypes>);

Expand Down Expand Up @@ -3101,11 +3132,11 @@ pub mod args {
}
}

impl CliToSdk<TxCommissionRateChange<SdkTypes>>
for TxCommissionRateChange<CliTypes>
impl CliToSdk<CommissionRateChange<SdkTypes>>
for CommissionRateChange<CliTypes>
{
fn to_sdk(self, ctx: &mut Context) -> TxCommissionRateChange<SdkTypes> {
TxCommissionRateChange::<SdkTypes> {
fn to_sdk(self, ctx: &mut Context) -> CommissionRateChange<SdkTypes> {
CommissionRateChange::<SdkTypes> {
tx: self.tx.to_sdk(ctx),
validator: ctx.get(&self.validator),
rate: self.rate,
Expand All @@ -3114,7 +3145,7 @@ pub mod args {
}
}

impl Args for TxCommissionRateChange<CliTypes> {
impl Args for CommissionRateChange<CliTypes> {
fn parse(matches: &ArgMatches) -> Self {
let tx = Tx::parse(matches);
let validator = VALIDATOR.parse(matches);
Expand Down
48 changes: 33 additions & 15 deletions apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ use namada::types::hash::Hash;
use namada::types::key::*;
use namada::types::storage::{Epoch, Key};
use namada::types::token;
use namada::types::transaction::governance::{
InitProposalData, ProposalType, VoteProposalData,
};
use namada::types::transaction::governance::{ProposalType, VoteProposalData};
use namada::types::transaction::{InitValidator, TxType};
use sha2::{Digest as Sha2Digest, Sha256};

Expand Down Expand Up @@ -566,13 +564,14 @@ pub async fn submit_init_proposal<C: namada::ledger::queries::Client + Sync>(
Ok(())
} else {
let signer = ctx.get(&signer);
let tx_data: Result<InitProposalData, _> = proposal.clone().try_into();
let init_proposal_data = if let Ok(data) = tx_data {
data
} else {
eprintln!("Invalid data for init proposal transaction.");
safe_exit(1)
};
let tx_data = proposal.clone().try_into();
let (mut init_proposal_data, init_proposal_content, init_proposal_code) =
if let Ok(data) = tx_data {
data
} else {
eprintln!("Invalid data for init proposal transaction.");
safe_exit(1)
};

let balance =
rpc::get_token_balance(client, &ctx.native_token, &proposal.author)
Expand All @@ -592,22 +591,41 @@ pub async fn submit_init_proposal<C: namada::ledger::queries::Client + Sync>(
safe_exit(1);
}

if init_proposal_data.content.len()
if init_proposal_content.len()
> governance_parameters.max_proposal_content_size as usize
{
eprintln!("Proposal content size too big.",);
safe_exit(1);
}

let mut tx = Tx::new(TxType::Raw);
let data = init_proposal_data
.try_to_vec()
.expect("Encoding proposal data shouldn't fail");
let tx_code_hash = query_wasm_code_hash(client, args::TX_INIT_PROPOSAL)
.await
.unwrap();
tx.header.chain_id = ctx.config.ledger.chain_id.clone();
tx.header.expiration = args.tx.expiration;
// Put the content of this proposal into an extra section
{
let content_sec = tx.add_section(Section::ExtraData(Code::new(
init_proposal_content,
)));
let content_sec_hash = Hash(
content_sec.hash(&mut Sha256::new()).finalize_reset().into(),
);
init_proposal_data.content = content_sec_hash;
}
// Put any proposal code into an extra section
if let Some(init_proposal_code) = init_proposal_code {
let code_sec = tx
.add_section(Section::ExtraData(Code::new(init_proposal_code)));
let code_sec_hash =
Hash(code_sec.hash(&mut Sha256::new()).finalize_reset().into());
init_proposal_data.r#type =
ProposalType::Default(Some(code_sec_hash));
}
let data = init_proposal_data
.try_to_vec()
.expect("Encoding proposal data shouldn't fail");
tx.set_data(Data::new(data));
tx.set_code(Code::from_hash(tx_code_hash));

Expand Down Expand Up @@ -1036,7 +1054,7 @@ pub async fn submit_validator_commission_change<
>(
client: &C,
mut ctx: Context,
mut args: args::TxCommissionRateChange,
mut args: args::CommissionRateChange,
) -> Result<(), tx::Error> {
args.tx.chain_id = args
.tx
Expand Down
5 changes: 4 additions & 1 deletion apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ mod test_finalize_block {
use namada::proto::{Code, Data, Section, Signature};
use namada::types::dec::POS_DECIMAL_PRECISION;
use namada::types::governance::ProposalVote;
use namada::types::hash::Hash;
use namada::types::key::tm_consensus_key_raw_hash;
use namada::types::storage::Epoch;
use namada::types::time::DurationSecs;
Expand Down Expand Up @@ -1316,7 +1317,7 @@ mod test_finalize_block {

let proposal = InitProposalData {
id: Some(proposal_id),
content: vec![],
content: Hash::default(),
author: validator.clone(),
voting_start_epoch: Epoch::default(),
voting_end_epoch: Epoch::default().next(),
Expand All @@ -1327,6 +1328,8 @@ mod test_finalize_block {
storage_api::governance::init_proposal(
&mut shell.wl_storage,
proposal,
vec![],
None,
)
.unwrap();

Expand Down
15 changes: 11 additions & 4 deletions core/src/ledger/storage_api/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::types::transaction::governance::{
pub fn init_proposal<S>(
storage: &mut S,
data: InitProposalData,
content: Vec<u8>,
code: Option<Vec<u8>>,
) -> storage_api::Result<()>
where
S: StorageRead + StorageWrite,
Expand All @@ -23,18 +25,21 @@ where
};

let content_key = storage::get_content_key(proposal_id);
storage.write_bytes(&content_key, data.content)?;
storage.write_bytes(&content_key, content)?;

let author_key = storage::get_author_key(proposal_id);
storage.write(&author_key, data.author.clone())?;

let proposal_type_key = storage::get_proposal_type_key(proposal_id);
match data.r#type {
ProposalType::Default(Some(ref code)) => {
ProposalType::Default(Some(_)) => {
// Remove wasm code and write it under a different subkey
storage.write(&proposal_type_key, ProposalType::Default(None))?;
let proposal_code_key = storage::get_proposal_code_key(proposal_id);
storage.write_bytes(&proposal_code_key, code)?
let proposal_code = code.clone().ok_or(
storage_api::Error::new_const("Missing proposal code"),
)?;
storage.write_bytes(&proposal_code_key, proposal_code)?
}
_ => storage.write(&proposal_type_key, data.r#type.clone())?,
}
Expand All @@ -49,8 +54,10 @@ where
let grace_epoch_key = storage::get_grace_epoch_key(proposal_id);
storage.write(&grace_epoch_key, data.grace_epoch)?;

if let ProposalType::Default(Some(proposal_code)) = data.r#type {
if let ProposalType::Default(Some(_)) = data.r#type {
let proposal_code_key = storage::get_proposal_code_key(proposal_id);
let proposal_code =
code.ok_or(storage_api::Error::new_const("Missing proposal code"))?;
storage.write_bytes(&proposal_code_key, proposal_code)?;
}

Expand Down
47 changes: 30 additions & 17 deletions core/src/types/transaction/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::types::address::Address;
use crate::types::governance::{
self, Proposal, ProposalError, ProposalVote, VoteType,
};
use crate::types::hash::Hash;
use crate::types::storage::Epoch;

/// The type of a Proposal
Expand All @@ -21,7 +22,7 @@ use crate::types::storage::Epoch;
)]
pub enum ProposalType {
/// Default governance proposal with the optional wasm code
Default(Option<Vec<u8>>),
Default(Option<Hash>),
/// PGF council proposal
PGFCouncil,
/// ETH proposal
Expand Down Expand Up @@ -54,23 +55,30 @@ impl PartialEq<VoteType> for ProposalType {
}
}

impl TryFrom<governance::ProposalType> for ProposalType {
impl TryFrom<governance::ProposalType> for (ProposalType, Option<Vec<u8>>) {
type Error = ProposalError;

fn try_from(value: governance::ProposalType) -> Result<Self, Self::Error> {
match value {
governance::ProposalType::Default(path) => {
if let Some(p) = path {
match std::fs::read(p) {
Ok(code) => Ok(Self::Default(Some(code))),
Ok(code) => Ok((
ProposalType::Default(Some(Hash::default())),
Some(code),
)),
Err(_) => Err(Self::Error::InvalidProposalData),
}
} else {
Ok(Self::Default(None))
Ok((ProposalType::Default(None), None))
}
}
governance::ProposalType::PGFCouncil => Ok(Self::PGFCouncil),
governance::ProposalType::ETHBridge => Ok(Self::ETHBridge),
governance::ProposalType::PGFCouncil => {
Ok((ProposalType::PGFCouncil, None))
}
governance::ProposalType::ETHBridge => {
Ok((ProposalType::ETHBridge, None))
}
}
}
}
Expand All @@ -89,7 +97,7 @@ pub struct InitProposalData {
/// The proposal id
pub id: Option<u64>,
/// The proposal content
pub content: Vec<u8>,
pub content: Hash,
/// The proposal author address
pub author: Address,
/// The proposal type
Expand Down Expand Up @@ -123,18 +131,23 @@ pub struct VoteProposalData {
pub delegations: Vec<Address>,
}

impl TryFrom<Proposal> for InitProposalData {
impl TryFrom<Proposal> for (InitProposalData, Vec<u8>, Option<Vec<u8>>) {
type Error = ProposalError;

fn try_from(proposal: Proposal) -> Result<Self, Self::Error> {
Ok(InitProposalData {
id: proposal.id,
content: proposal.content.try_to_vec().unwrap(),
author: proposal.author,
r#type: proposal.r#type.try_into()?,
voting_start_epoch: proposal.voting_start_epoch,
voting_end_epoch: proposal.voting_end_epoch,
grace_epoch: proposal.grace_epoch,
})
let (r#type, code) = proposal.r#type.try_into()?;
Ok((
InitProposalData {
id: proposal.id,
content: Hash::default(),
author: proposal.author,
r#type,
voting_start_epoch: proposal.voting_start_epoch,
voting_end_epoch: proposal.voting_end_epoch,
grace_epoch: proposal.grace_epoch,
},
proposal.content.try_to_vec().unwrap(),
code,
))
}
}
Loading

0 comments on commit 1179811

Please sign in to comment.