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

Add authorized voter #3162

Merged
merged 2 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions programs/vote/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ fn entrypoint(
VoteInstruction::DelegateStake(delegate_id) => {
vote_state::delegate_stake(keyed_accounts, delegate_id)
}
VoteInstruction::AuthorizeVoter(voter_id) => {
vote_state::authorize_voter(keyed_accounts, voter_id)
}
VoteInstruction::Vote(vote) => {
debug!("{:?} by {}", vote, keyed_accounts[0].signer_key().unwrap());
solana_metrics::submit(
Expand Down
9 changes: 9 additions & 0 deletions programs/vote_api/src/vote_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub enum VoteInstruction {
InitializeAccount,
/// `Delegate` or `Assign` a vote account to a particular node
DelegateStake(Pubkey),
/// Authorize a voter to send signed votes.
AuthorizeVoter(Pubkey),
Vote(Vote),
/// Clear the credits in the vote account
/// * Transaction::keys[0] - the "vote account"
Expand All @@ -40,6 +42,13 @@ impl VoteInstruction {
vec![(vote_id, true)],
)
}
pub fn new_authorize_voter(vote_id: Pubkey, authorized_voter_id: Pubkey) -> BuilderInstruction {
BuilderInstruction::new(
id(),
&VoteInstruction::AuthorizeVoter(authorized_voter_id),
vec![(vote_id, true)],
)
}
pub fn new_initialize_account(vote_id: Pubkey) -> BuilderInstruction {
BuilderInstruction::new(
id(),
Expand Down
58 changes: 50 additions & 8 deletions programs/vote_api/src/vote_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,20 @@ impl Lockout {
pub struct VoteState {
pub votes: VecDeque<Lockout>,
pub delegate_id: Pubkey,
pub authorized_voter_id: Pubkey,
pub root_slot: Option<u64>,
credits: u64,
}

impl VoteState {
pub fn new(delegate_id: Pubkey) -> Self {
pub fn new(staker_id: Pubkey) -> Self {
let votes = VecDeque::new();
let credits = 0;
let root_slot = None;
Self {
votes,
delegate_id,
delegate_id: staker_id,
authorized_voter_id: staker_id,
credits,
root_slot,
}
Expand Down Expand Up @@ -173,6 +175,35 @@ pub fn delegate_stake(
Ok(())
}

/// Authorize the given pubkey to sign votes. This may be called multiple times,
/// but will implicitly withdraw authorization from the previously authorized
/// voter. The default voter is the owner of the vote account's pubkey.
pub fn authorize_voter(
keyed_accounts: &mut [KeyedAccount],
voter_id: Pubkey,
) -> Result<(), ProgramError> {
if !check_id(&keyed_accounts[0].account.owner) {
error!("account[0] is not assigned to the VOTE_PROGRAM");
Err(ProgramError::InvalidArgument)?;
}

if keyed_accounts[0].signer_key().is_none() {
error!("account[0] should sign the transaction");
Err(ProgramError::InvalidArgument)?;
}

let vote_state = VoteState::deserialize(&keyed_accounts[0].account.userdata);
if let Ok(mut vote_state) = vote_state {
vote_state.authorized_voter_id = voter_id;
vote_state.serialize(&mut keyed_accounts[0].account.userdata)?;
} else {
error!("account[0] does not valid userdata");
Err(ProgramError::InvalidUserdata)?;
}

Ok(())
}

/// Initialize the vote_state for a vote account
/// Assumes that the account is being init as part of a account creation or balance transfer and
/// that the transaction must be signed by the staker's keys
Expand Down Expand Up @@ -206,12 +237,24 @@ pub fn process_vote(keyed_accounts: &mut [KeyedAccount], vote: Vote) -> Result<(
Err(ProgramError::InvalidArgument)?;
}

if keyed_accounts[0].signer_key().is_none() {
error!("account[0] should sign the transaction");
let mut vote_state = VoteState::deserialize(&keyed_accounts[0].account.userdata)?;

// If no voter was authorized, expect account[0] to be the signer, otherwise account[1].
let signer_index = if vote_state.authorized_voter_id == *keyed_accounts[0].unsigned_key() {
0
} else {
1
};

if keyed_accounts.get(signer_index).is_none() {
error!("account[{}] not provided", signer_index);
Err(ProgramError::InvalidArgument)?;
}
if keyed_accounts[signer_index].signer_key().is_none() {
error!("account[{}] should sign the transaction", signer_index);
Err(ProgramError::InvalidArgument)?;
}

let mut vote_state = VoteState::deserialize(&keyed_accounts[0].account.userdata)?;
vote_state.process_vote(vote);
vote_state.serialize(&mut keyed_accounts[0].account.userdata)?;
Ok(())
Expand Down Expand Up @@ -335,9 +378,8 @@ mod tests {
let mut vote_account = create_vote_account(100);

let vote = Vote::new(1);
let vote_state = vote_and_deserialize(&vote_id, &mut vote_account, vote.clone()).unwrap();
assert_eq!(vote_state.delegate_id, Pubkey::default());
assert_eq!(vote_state.votes, vec![Lockout::new(&vote)]);
let res = vote_and_deserialize(&vote_id, &mut vote_account, vote.clone());
assert_eq!(res, Err(ProgramError::InvalidArgument));
}

#[test]
Expand Down
15 changes: 15 additions & 0 deletions programs/vote_api/src/vote_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ impl VoteTransaction {
.sign(&[from_keypair, voter_keypair], recent_blockhash)
}

/// Choose a voter id to accept signed votes from
pub fn new_authorize_voter(
vote_keypair: &Keypair,
recent_blockhash: Hash,
authorized_voter_id: Pubkey,
fee: u64,
) -> Transaction {
TransactionBuilder::new(fee)
.push(VoteInstruction::new_authorize_voter(
vote_keypair.pubkey(),
authorized_voter_id,
))
.sign(&[vote_keypair], recent_blockhash)
}

/// Choose a node id to `delegate` or `assign` this vote account to
pub fn delegate_vote_account<T: KeypairUtil>(
vote_keypair: &T,
Expand Down