Skip to content

Commit

Permalink
[move] migrate PoF bid ux to fixed values instead of percent (#323)
Browse files Browse the repository at this point in the history
Co-authored-by: 0o-de-lally <[email protected]>
  • Loading branch information
sirouk and 0o-de-lally authored Jan 9, 2025
1 parent ecb415d commit 8c7fc88
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 10 deletions.
49 changes: 49 additions & 0 deletions framework/cached-packages/src/libra_framework_sdk_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ pub enum EntryFunctionCall {
epoch_expiry: u64,
},

/// update the bid using estimated net reward instead of the internal bid variables
ProofOfFeePofUpdateBidNetReward {
net_reward: u64,
epoch_expiry: u64,
},

/// This function initiates governance for the multisig. It is called by the sponsor address, and is only callable once.
/// init_gov fails gracefully if the governance is already initialized.
/// init_type will throw errors if the type is already initialized.
Expand Down Expand Up @@ -808,6 +814,10 @@ impl EntryFunctionCall {
ProofOfFeePofUpdateBid { bid, epoch_expiry } => {
proof_of_fee_pof_update_bid(bid, epoch_expiry)
}
ProofOfFeePofUpdateBidNetReward {
net_reward,
epoch_expiry,
} => proof_of_fee_pof_update_bid_net_reward(net_reward, epoch_expiry),
SafeInitPaymentMultisig { authorities } => safe_init_payment_multisig(authorities),
SlowWalletSmokeTestVmUnlock {
user_addr,
Expand Down Expand Up @@ -2147,6 +2157,28 @@ pub fn proof_of_fee_pof_update_bid(bid: u64, epoch_expiry: u64) -> TransactionPa
))
}

/// update the bid using estimated net reward instead of the internal bid variables
pub fn proof_of_fee_pof_update_bid_net_reward(
net_reward: u64,
epoch_expiry: u64,
) -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
AccountAddress::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1,
]),
ident_str!("proof_of_fee").to_owned(),
),
ident_str!("pof_update_bid_net_reward").to_owned(),
vec![],
vec![
bcs::to_bytes(&net_reward).unwrap(),
bcs::to_bytes(&epoch_expiry).unwrap(),
],
))
}

/// This function initiates governance for the multisig. It is called by the sponsor address, and is only callable once.
/// init_gov fails gracefully if the governance is already initialized.
/// init_type will throw errors if the type is already initialized.
Expand Down Expand Up @@ -3105,6 +3137,19 @@ mod decoder {
}
}

pub fn proof_of_fee_pof_update_bid_net_reward(
payload: &TransactionPayload,
) -> Option<EntryFunctionCall> {
if let TransactionPayload::EntryFunction(script) = payload {
Some(EntryFunctionCall::ProofOfFeePofUpdateBidNetReward {
net_reward: bcs::from_bytes(script.args().first()?).ok()?,
epoch_expiry: bcs::from_bytes(script.args().get(1)?).ok()?,
})
} else {
None
}
}

pub fn safe_init_payment_multisig(payload: &TransactionPayload) -> Option<EntryFunctionCall> {
if let TransactionPayload::EntryFunction(script) = payload {
Some(EntryFunctionCall::SafeInitPaymentMultisig {
Expand Down Expand Up @@ -3480,6 +3525,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy<EntryFunctionDecoderMa
"proof_of_fee_pof_update_bid".to_string(),
Box::new(decoder::proof_of_fee_pof_update_bid),
);
map.insert(
"proof_of_fee_pof_update_bid_net_reward".to_string(),
Box::new(decoder::proof_of_fee_pof_update_bid_net_reward),
);
map.insert(
"safe_init_payment_multisig".to_string(),
Box::new(decoder::safe_init_payment_multisig),
Expand Down
82 changes: 81 additions & 1 deletion framework/libra-framework/sources/ol_sources/proof_of_fee.move
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ module ol_framework::proof_of_fee {
const LONG_WINDOW: u64 = 10; // 10 epochs
/// Margin for vouches
const VOUCH_MARGIN: u64 = 2;
/// Maximum days before a bid expires.
const MAXIMUM_BID_EXPIRATION_EPOCHS: u64 = 30;


//////// ERRORS /////////
/// Not an active validator
Expand All @@ -75,6 +78,10 @@ module ol_framework::proof_of_fee {
const EBID_EXPIRED: u64 = 16;
/// not enough coin balance
const ELOW_UNLOCKED_COIN_BALANCE: u64 = 17;
/// reward should never reach zero, very bad
const EWTF_WHY_IS_REWARD_ZERO: u64 = 18;
/// don't try to set a net reward greater than the max epoch reward
const ENET_REWARD_GREATER_THAN_REWARD: u64 = 19;

// A struct on the validators account which indicates their
// latest bid (and epoch)
Expand Down Expand Up @@ -645,7 +652,6 @@ module ol_framework::proof_of_fee {

// get the current bid for a validator
// CONSENSUS CRITICAL
// ALL EYES ON THIS
// Proof of Fee returns the current bid of the validator during the auction for upcoming epoch seats.
// returns (current bid, expiration epoch)
#[view]
Expand All @@ -665,6 +671,31 @@ module ol_framework::proof_of_fee {
return (0, 0)
}

#[view]
/// Convenience function to calculate the implied net reward
/// that the validator is seeking on a per-epoch basis.
/// @returns the unscaled coin value (not human readable) of the net reward
/// the user expects
public fun user_net_reward(node_addr: address): u64 acquires
ConsensusReward, ProofOfFeeAuction {
// get the user percentage rate

let (bid_pct, _) = current_bid(node_addr);
if (bid_pct == 0) return 0;
// get the current nominal reward
let (nominal_reward, _, _ , _) = get_consensus_reward();

let user_entry_fee = bid_pct * nominal_reward;
if (user_entry_fee == 0) return 0;
user_entry_fee = user_entry_fee / 10;

if (user_entry_fee < nominal_reward) {
return nominal_reward - user_entry_fee
};

return 0
}

#[view]
// which epoch did they last retract a bid?
public fun is_already_retracted(node_addr: address): (bool, u64) acquires ProofOfFeeAuction {
Expand Down Expand Up @@ -735,6 +766,47 @@ module ol_framework::proof_of_fee {
pof.bid = bid;
}

/// converts a current desired net_reward to the internal bid percentage
// Note: this uses the current epoch reward, which may not reflect the
// incoming epochs ajusted reward.
fun convert_net_reward_to_bid(net_reward: u64): u64 acquires ConsensusReward {
// if user wants zero, return 100% scaled
if (net_reward == 0) {
return 1000
};

let (nominal_reward, _, _ , _) = get_consensus_reward();
assert!(nominal_reward > 0, EWTF_WHY_IS_REWARD_ZERO);
assert!(net_reward < nominal_reward, ENET_REWARD_GREATER_THAN_REWARD);

let pct_with_decimal = (net_reward * 10) / nominal_reward;

return pct_with_decimal
}

/// Instead of setting a bid with the internal variables of pct bid, we
/// allow the user to set their expected net_reward in an epoch
fun set_net_reward(account_sig: &signer, net_reward: u64, expiry_epoch: u64) acquires
ConsensusReward, ProofOfFeeAuction {
// double check the epoch expiry
let epoch_checked = check_epoch_expiry(expiry_epoch);
// convert to bid
let scaled_pct = convert_net_reward_to_bid(net_reward);
set_bid(account_sig, scaled_pct, epoch_checked);
}

/// check if the expiry is too far in the future
/// and if so, return what the maximum allowed would be.
/// if within range returns the provided epoch without change
/// @returns checked epoch for bid expiration
fun check_epoch_expiry(expiry_epoch: u64): u64 {
let this_epoch = epoch_helper::get_current_epoch();
if (expiry_epoch > MAXIMUM_BID_EXPIRATION_EPOCHS) {
return this_epoch + MAXIMUM_BID_EXPIRATION_EPOCHS
};
expiry_epoch
}

/// Note that the validator will not be bidding on any future
/// epochs if they retract their bid. The must set a new bid.
fun retract_bid(account_sig: &signer) acquires ProofOfFeeAuction {
Expand Down Expand Up @@ -770,6 +842,14 @@ module ol_framework::proof_of_fee {
set_bid(sender, bid, epoch_expiry);
}

/// update the bid using estimated net reward instead of the internal bid variables
public entry fun pof_update_bid_net_reward(sender: &signer, net_reward: u64,
epoch_expiry: u64) acquires ProofOfFeeAuction, ConsensusReward {
let checked_epoch = check_epoch_expiry(epoch_expiry);
// update the bid, initializes if not already.
set_net_reward(sender, net_reward, checked_epoch);
}

/// retract bid
public entry fun pof_retract_bid(sender: signer) acquires ProofOfFeeAuction {
// retract a bid
Expand Down
Binary file modified framework/releases/head.mrb
Binary file not shown.
28 changes: 19 additions & 9 deletions tools/txs/src/txs_cli_vals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use diem_genesis::config::OperatorConfiguration;
use diem_types::account_address::AccountAddress;
use libra_cached_packages::libra_stdlib::EntryFunctionCall::{
self, JailUnjailByVoucher, ProofOfFeePofRetractBid, ProofOfFeePofUpdateBid,
StakeUpdateNetworkAndFullnodeAddresses, ValidatorUniverseRegisterValidator, VouchRevoke,
VouchVouchFor,
ProofOfFeePofUpdateBidNetReward, StakeUpdateNetworkAndFullnodeAddresses,
ValidatorUniverseRegisterValidator, VouchRevoke, VouchVouchFor,
};
use libra_config::validator_registration;
use libra_types::global_config_dir;
Expand All @@ -18,14 +18,17 @@ use std::{fs, path::PathBuf};
pub enum ValidatorTxs {
/// Proof-of-Fee auction bidding
Pof {
#[clap(short('r'), long)]
/// Estimated net reward you would like to receive each epoch
net_reward: u64,
#[clap(short, long)]
/// Percentage of the nominal reward you will bid to join the
/// validator set, with three decimal places: 1.234 is 123.4%
bid_pct: f64,
bid_pct: Option<f64>,
#[clap(short, long)]
/// Epoch until the bid is valid (will expire in `expiry` + 1)
/// Epoch until the bid is valid (will expire in `expiry` + 1). Max 30 epochs
expiry: u64,
#[clap(short, long)]
#[clap(long)]
/// Eliminates the bid. There are only a limited amount of retractions that can happen in an epoch
retract: bool,
},
Expand Down Expand Up @@ -69,23 +72,30 @@ impl ValidatorTxs {
pub fn make_payload(&self) -> anyhow::Result<EntryFunctionCall> {
let p = match self {
ValidatorTxs::Pof {
net_reward,
bid_pct,
expiry: epoch_expiry,
expiry,
retract,
} => {
if *retract {
ProofOfFeePofRetractBid {}
} else {
} else if let Some(b) = bid_pct {
// TODO: the u64 will truncate, but without rounding it will drop the last digit.
let scaled_bid = (bid_pct * 1000.0).round() as u64; // scale to 10ˆ3.
let scaled_bid = (b * 1000.0).round() as u64; // scale to 10ˆ3.
if scaled_bid > 1100 {
bail!(
"a bid amount at 110.0% or above the epoch's reward, will be rejected"
);
}
ProofOfFeePofUpdateBid {
bid: scaled_bid,
epoch_expiry: *epoch_expiry,
epoch_expiry: *expiry,
}
} else {
// Default path is to update based on the expected net reward
ProofOfFeePofUpdateBidNetReward {
net_reward: *net_reward,
epoch_expiry: *expiry,
}
}
}
Expand Down

0 comments on commit 8c7fc88

Please sign in to comment.