Skip to content

Commit

Permalink
Merge branch 'tomas/implicit-vps' (#592)
Browse files Browse the repository at this point in the history
- fix imports in `shared/src/ledger/storage/mod.rs`
- update token XAN -> NAM in
  - `tests/src/e2e/ledger_tests.rs`
  - `wasm/wasm_source/src/vp_implicit.rs`
- remove NFT from `wasm/wasm_source/src/vp_implicit.rs`
- added shielded token transfer params in test in
  - `wasm/wasm_source/src/vp_implicit.rs`

* tomas/implicit-vps:
  changelog: add #592
  [ci] wasm checksums update
  test/e2e: add test for implicit account's PK revealing
  add manual "reveal-pk" command and automatically reveal when needed
  vp_prelude: refactor `key::get` to re-use new `storage_api::key::get`
  wasm/vp_implicit: add support and tests for revealing PK
  wasm: add tx_reveal_pk
  test/wasm/vp_implicit: use implicit addresses as vp_owner
  wasm/vp_implicit: rm change handling from implicit VP
  test/e2e: add test for transfer from implicit account
  protocol: allow to use implicit accounts in inner txs
  storage: load implicit VP from parameters
  add implicit_vp to protocol parameters and genesis
  wasm: add vp_implicit from a copy of vp_user
  • Loading branch information
tzemanovic committed Nov 16, 2022
2 parents 4381caa + 484c0e7 commit 7cab394
Show file tree
Hide file tree
Showing 25 changed files with 1,380 additions and 91 deletions.
6 changes: 6 additions & 0 deletions .changelog/unreleased/features/592-implicit-vp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- Added a validity predicate for implicit accounts. This is set in
protocol parameters and may be changed via governance. Additionally,
added automatic public key reveal in the client that use an implicit
account that hasn't revealed its PK yet as a source. It's also
possible to manually submit reveal transaction with client command
([#592](https://github.com/anoma/namada/pull/592))
3 changes: 3 additions & 0 deletions apps/src/bin/anoma-client/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pub async fn main() -> Result<()> {
Sub::TxVoteProposal(TxVoteProposal(args)) => {
tx::submit_vote_proposal(ctx, args).await;
}
Sub::TxRevealPk(TxRevealPk(args)) => {
tx::submit_reveal_pk(ctx, args).await;
}
Sub::Bond(Bond(args)) => {
tx::submit_bond(ctx, args).await;
}
Expand Down
1 change: 1 addition & 0 deletions apps/src/bin/anoma/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fn handle_command(cmd: cli::cmds::Anoma, raw_sub_cmd: String) -> Result<()> {
| cli::cmds::Anoma::TxTransfer(_)
| cli::cmds::Anoma::TxIbcTransfer(_)
| cli::cmds::Anoma::TxUpdateVp(_)
| cli::cmds::Anoma::TxRevealPk(_)
| cli::cmds::Anoma::TxInitProposal(_)
| cli::cmds::Anoma::TxVoteProposal(_) => {
handle_subcommand("namadac", sub_args)
Expand Down
64 changes: 62 additions & 2 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub mod cmds {
TxUpdateVp(TxUpdateVp),
TxInitProposal(TxInitProposal),
TxVoteProposal(TxVoteProposal),
TxRevealPk(TxRevealPk),
}

impl Cmd for Anoma {
Expand All @@ -64,6 +65,7 @@ pub mod cmds {
.subcommand(TxUpdateVp::def())
.subcommand(TxInitProposal::def())
.subcommand(TxVoteProposal::def())
.subcommand(TxRevealPk::def())
}

fn parse(matches: &ArgMatches) -> Option<Self> {
Expand All @@ -80,6 +82,7 @@ pub mod cmds {
SubCmd::parse(matches).map(Self::TxInitProposal);
let tx_vote_proposal =
SubCmd::parse(matches).map(Self::TxVoteProposal);
let tx_reveal_pk = SubCmd::parse(matches).map(Self::TxRevealPk);
node.or(client)
.or(wallet)
.or(ledger)
Expand All @@ -89,6 +92,7 @@ pub mod cmds {
.or(tx_update_vp)
.or(tx_init_proposal)
.or(tx_vote_proposal)
.or(tx_reveal_pk)
}
}

Expand Down Expand Up @@ -152,11 +156,12 @@ pub mod cmds {
.subcommand(TxIbcTransfer::def().display_order(1))
.subcommand(TxUpdateVp::def().display_order(1))
.subcommand(TxInitAccount::def().display_order(1))
.subcommand(TxInitValidator::def().display_order(1))
.subcommand(TxRevealPk::def().display_order(1))
// Proposal transactions
.subcommand(TxInitProposal::def().display_order(1))
.subcommand(TxVoteProposal::def().display_order(1))
// PoS transactions
.subcommand(TxInitValidator::def().display_order(2))
.subcommand(Bond::def().display_order(2))
.subcommand(Unbond::def().display_order(2))
.subcommand(Withdraw::def().display_order(2))
Expand Down Expand Up @@ -187,6 +192,7 @@ pub mod cmds {
let tx_init_account = Self::parse_with_ctx(matches, TxInitAccount);
let tx_init_validator =
Self::parse_with_ctx(matches, TxInitValidator);
let tx_reveal_pk = Self::parse_with_ctx(matches, TxRevealPk);
let tx_init_proposal =
Self::parse_with_ctx(matches, TxInitProposal);
let tx_vote_proposal =
Expand Down Expand Up @@ -217,9 +223,10 @@ pub mod cmds {
.or(tx_ibc_transfer)
.or(tx_update_vp)
.or(tx_init_account)
.or(tx_init_validator)
.or(tx_reveal_pk)
.or(tx_init_proposal)
.or(tx_vote_proposal)
.or(tx_init_validator)
.or(bond)
.or(unbond)
.or(withdraw)
Expand Down Expand Up @@ -281,6 +288,7 @@ pub mod cmds {
TxInitValidator(TxInitValidator),
TxInitProposal(TxInitProposal),
TxVoteProposal(TxVoteProposal),
TxRevealPk(TxRevealPk),
Bond(Bond),
Unbond(Unbond),
Withdraw(Withdraw),
Expand Down Expand Up @@ -1328,6 +1336,36 @@ pub mod cmds {
}
}

#[derive(Clone, Debug)]
pub struct TxRevealPk(pub args::RevealPk);

impl SubCmd for TxRevealPk {
const CMD: &'static str = "reveal-pk";

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

fn def() -> App {
App::new(Self::CMD)
.about(
"Submit a tx to reveal the public key an implicit \
account. Typically, you don't have to do this manually \
and the client will detect when a tx to reveal PK is \
needed and submit it automatically. This will write the \
PK into the account's storage so that it can be used for \
signature verification on transactions authorized by \
this account.",
)
.add_args::<args::RevealPk>()
}
}

#[derive(Clone, Debug)]
pub enum Utils {
JoinNetwork(JoinNetwork),
Expand Down Expand Up @@ -2160,6 +2198,28 @@ pub mod args {
}
}

#[derive(Clone, Debug)]
pub struct RevealPk {
/// Common tx arguments
pub tx: Tx,
/// A public key to be revealed on-chain
pub public_key: WalletPublicKey,
}

impl Args for RevealPk {
fn parse(matches: &ArgMatches) -> Self {
let tx = Tx::parse(matches);
let public_key = PUBLIC_KEY.parse(matches);

Self { tx, public_key }
}

fn def(app: App) -> App {
app.add_args::<Tx>()
.arg(PUBLIC_KEY.def().about("A public key to reveal."))
}
}

#[derive(Clone, Debug)]
pub struct QueryProposal {
/// Common query args
Expand Down
13 changes: 12 additions & 1 deletion apps/src/lib/client/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,20 @@ pub async fn tx_signer(
args.ledger_address.clone(),
)
.await;
// Check if the signer is implicit account that needs to reveal its
// PK first
if matches!(signer, Address::Implicit(_)) {
let pk: common::PublicKey = signing_key.ref_to();
super::tx::reveal_pk_if_needed(ctx, &pk, args).await;
}
signing_key
}
TxSigningKey::SecretKey(signing_key) => {
// Check if the signing key needs to reveal its PK first
let pk: common::PublicKey = signing_key.ref_to();
super::tx::reveal_pk_if_needed(ctx, &pk, args).await;
signing_key
}
TxSigningKey::SecretKey(signing_key) => signing_key,
TxSigningKey::None => {
panic!(
"All transactions must be signed; please either specify the \
Expand Down
109 changes: 109 additions & 0 deletions apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const TX_INIT_ACCOUNT_WASM: &str = "tx_init_account.wasm";
const TX_INIT_VALIDATOR_WASM: &str = "tx_init_validator.wasm";
const TX_INIT_PROPOSAL: &str = "tx_init_proposal.wasm";
const TX_VOTE_PROPOSAL: &str = "tx_vote_proposal.wasm";
const TX_REVEAL_PK: &str = "tx_reveal_pk.wasm";
const TX_UPDATE_VP_WASM: &str = "tx_update_vp.wasm";
const TX_TRANSFER_WASM: &str = "tx_transfer.wasm";
const TX_IBC_WASM: &str = "tx_ibc.wasm";
Expand Down Expand Up @@ -2024,6 +2025,114 @@ pub async fn submit_vote_proposal(mut ctx: Context, args: args::VoteProposal) {
}
}

pub async fn submit_reveal_pk(mut ctx: Context, args: args::RevealPk) {
let args::RevealPk {
tx: args,
public_key,
} = args;
let public_key = ctx.get_cached(&public_key);
if !reveal_pk_if_needed(&mut ctx, &public_key, &args).await {
let addr: Address = (&public_key).into();
println!("PK for {addr} is already revealed, nothing to do.");
}
}

pub async fn reveal_pk_if_needed(
ctx: &mut Context,
public_key: &common::PublicKey,
args: &args::Tx,
) -> bool {
let addr: Address = public_key.into();
// Check if PK revealed
if args.force || !has_revealed_pk(&addr, args.ledger_address.clone()).await
{
// If not, submit it
submit_reveal_pk_aux(ctx, public_key, args).await;
true
} else {
false
}
}

pub async fn has_revealed_pk(
addr: &Address,
ledger_address: TendermintAddress,
) -> bool {
rpc::get_public_key(addr, ledger_address).await.is_some()
}

pub async fn submit_reveal_pk_aux(
ctx: &mut Context,
public_key: &common::PublicKey,
args: &args::Tx,
) {
let addr: Address = public_key.into();
println!("Submitting a tx to reveal the public key for address {addr}...");
let tx_data = public_key
.try_to_vec()
.expect("Encoding a public key shouldn't fail");
let tx_code = ctx.read_wasm(TX_REVEAL_PK);
let tx = Tx::new(tx_code, Some(tx_data));

// submit_tx without signing the inner tx
let keypair = if let Some(signing_key) = &args.signing_key {
ctx.get_cached(signing_key)
} else if let Some(signer) = args.signer.as_ref() {
let signer = ctx.get(signer);
find_keypair(&mut ctx.wallet, &signer, args.ledger_address.clone())
.await
} else {
find_keypair(&mut ctx.wallet, &addr, args.ledger_address.clone()).await
};
let epoch = rpc::query_epoch(args::Query {
ledger_address: args.ledger_address.clone(),
})
.await;
let to_broadcast = if args.dry_run {
TxBroadcastData::DryRun(tx)
} else {
super::signing::sign_wrapper(ctx, args, epoch, tx, &keypair).await
};

if args.dry_run {
if let TxBroadcastData::DryRun(tx) = to_broadcast {
rpc::dry_run_tx(&args.ledger_address, tx.to_bytes()).await;
} else {
panic!(
"Expected a dry-run transaction, received a wrapper \
transaction instead"
);
}
} else {
// Either broadcast or submit transaction and collect result into
// sum type
let result = if args.broadcast_only {
Left(broadcast_tx(args.ledger_address.clone(), &to_broadcast).await)
} else {
Right(submit_tx(args.ledger_address.clone(), to_broadcast).await)
};
// Return result based on executed operation, otherwise deal with
// the encountered errors uniformly
match result {
Right(Err(err)) => {
eprintln!(
"Encountered error while broadcasting transaction: {}",
err
);
safe_exit(1)
}
Left(Err(err)) => {
eprintln!(
"Encountered error while broadcasting transaction: {}",
err
);
safe_exit(1)
}
_ => {}
}
}
}

/// Check if current epoch is in the last third of the voting period of the
/// proposal. This ensures that it is safe to optimize the vote writing to
/// storage.
Expand Down
Loading

0 comments on commit 7cab394

Please sign in to comment.