-
Notifications
You must be signed in to change notification settings - Fork 315
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
funding: implement execute ActionLiquidityTournamentVote
#5033
Changes from all commits
551c987
6097a52
8599115
69987f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pub mod nullifier; | ||
pub mod votes; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use async_trait::async_trait; | ||
use cnidarium::StateWrite; | ||
use penumbra_sdk_asset::asset; | ||
use penumbra_sdk_keys::Address; | ||
|
||
use crate::component::state_key; | ||
|
||
#[async_trait] | ||
pub trait StateWriteExt: StateWrite { | ||
// Keeping this as returning a result to not have to touch other code if it changes to return an error. | ||
async fn tally( | ||
&mut self, | ||
epoch: u64, | ||
asset: asset::Id, | ||
power: u64, | ||
voter: &Address, | ||
) -> anyhow::Result<()> { | ||
self.nonverifiable_put_raw( | ||
state_key::lqt::v1::votes::receipt(epoch, asset, power, voter).to_vec(), | ||
Vec::default(), | ||
); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<T: StateWrite + ?Sized> StateWriteExt for T {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,5 +12,59 @@ pub mod lqt { | |
format!("funding/lqt/v1/nullifier/{epoch_index:020}/lookup/{nullifier}") | ||
} | ||
} | ||
|
||
pub mod votes { | ||
use penumbra_sdk_asset::asset; | ||
use penumbra_sdk_keys::{address::ADDRESS_LEN_BYTES, Address}; | ||
|
||
const PART0: &'static str = "funding/lqt/v1/votes/"; | ||
const EPOCH_LEN: usize = 20; | ||
const PART1: &'static str = "/by_asset/"; | ||
const PREFIX_LEN: usize = PART0.len() + EPOCH_LEN + PART1.len(); | ||
|
||
/// A prefix for accessing the votes in a given epoch, c.f. [`power_asset_address`]; | ||
pub(crate) fn prefix(epoch_index: u64) -> [u8; PREFIX_LEN] { | ||
let mut bytes = [0u8; PREFIX_LEN]; | ||
|
||
let rest = &mut bytes; | ||
let (bytes_part0, rest) = rest.split_at_mut(PART0.len()); | ||
let (bytes_epoch_index, bytes_part1) = rest.split_at_mut(EPOCH_LEN); | ||
|
||
bytes_part0.copy_from_slice(PART0.as_bytes()); | ||
bytes_epoch_index | ||
.copy_from_slice(format!("{epoch_index:0w$}", w = EPOCH_LEN).as_bytes()); | ||
bytes_part1.copy_from_slice(PART1.as_bytes()); | ||
|
||
bytes | ||
} | ||
|
||
const ASSET_LEN: usize = 32; | ||
const POWER_LEN: usize = 8; | ||
const RECEIPT_LEN: usize = PREFIX_LEN + ASSET_LEN + POWER_LEN + ADDRESS_LEN_BYTES; | ||
|
||
/// When present, indicates that an address voted for a particular asset, with a given power. | ||
/// | ||
/// To get the values ordered by descending voting power, use [`prefix`]; | ||
pub(crate) fn receipt( | ||
epoch_index: u64, | ||
asset: asset::Id, | ||
power: u64, | ||
voter: &Address, | ||
) -> [u8; RECEIPT_LEN] { | ||
let mut bytes = [0u8; RECEIPT_LEN]; | ||
|
||
let rest = &mut bytes; | ||
let (bytes_prefix, rest) = rest.split_at_mut(PREFIX_LEN); | ||
let (bytes_asset, rest) = rest.split_at_mut(ASSET_LEN); | ||
let (bytes_power, bytes_voter) = rest.split_at_mut(POWER_LEN); | ||
|
||
bytes_prefix.copy_from_slice(&prefix(epoch_index)); | ||
bytes_asset.copy_from_slice(&asset.to_bytes()); | ||
bytes_power.copy_from_slice(&((!power).to_be_bytes())); | ||
bytes_voter.copy_from_slice(&voter.to_vec()); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
bytes | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
use anyhow::{anyhow, Context}; | ||
use decaf377_rdsa::{Signature, SpendAuth, VerificationKey}; | ||
use penumbra_sdk_asset::{asset::Denom, balance, Value}; | ||
use penumbra_sdk_asset::{ | ||
asset::{self, Denom, REGISTRY}, | ||
balance, Value, | ||
}; | ||
use penumbra_sdk_keys::Address; | ||
use penumbra_sdk_proto::{core::component::funding::v1 as pb, DomainType}; | ||
use penumbra_sdk_sct::Nullifier; | ||
|
@@ -34,6 +37,17 @@ pub struct LiquidityTournamentVoteBody { | |
pub rk: VerificationKey<SpendAuth>, | ||
} | ||
|
||
impl LiquidityTournamentVoteBody { | ||
/// Get the asset id that should be incentivized. | ||
/// | ||
/// This will return None if the denom is not a base denom. | ||
pub fn incentivized_id(&self) -> Option<asset::Id> { | ||
REGISTRY | ||
.parse_denom(&self.incentivized.denom) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I presume this still work for unknown denoms right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://rustdoc.penumbra.zone/main/src/penumbra_sdk_asset/asset/registry.rs.html#70 Yeah, the case in which it returns None is only when it's a known non-base denom. |
||
.map(|x| x.id()) | ||
} | ||
} | ||
|
||
impl DomainType for LiquidityTournamentVoteBody { | ||
type Proto = pb::LiquidityTournamentVoteBody; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think we can revisit in a follow-up PR.