Skip to content

Commit

Permalink
impl Add/RemoveCurrencyPairs
Browse files Browse the repository at this point in the history
  • Loading branch information
noot committed Dec 13, 2024
1 parent 408a010 commit ebe0340
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
use astria_core::protocol::transaction::v1::action::AddCurrencyPairs;
use astria_core::{
connect::{
oracle::v2::{
CurrencyPairState,
QuotePrice,
},
types::v2::{
CurrencyPairId,
CurrencyPairNonce,
Price,
},
},
protocol::transaction::v1::action::AddCurrencyPairs,
Timestamp,
};
use astria_eyre::eyre::{
ensure,
OptionExt as _,
Expand All @@ -8,7 +22,18 @@ use astria_eyre::eyre::{
use async_trait::async_trait;
use cnidarium::StateWrite;

use crate::action_handler::ActionHandler;
use crate::{
action_handler::ActionHandler,
app::StateReadExt as _,
connect::{
market_map::state_ext::StateReadExt as _,
oracle::state_ext::{
StateReadExt as _,
StateWriteExt,
},
},
transaction::StateReadExt as _,
};

#[async_trait]
impl ActionHandler for AddCurrencyPairs {
Expand All @@ -17,7 +42,69 @@ impl ActionHandler for AddCurrencyPairs {
}

async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
todo!();
// TODO: should we use the market map admin here, or a different admin?
let admin = state
.get_params()
.await?
.ok_or_eyre("market map params not set")?
.admin;
let from = state
.get_transaction_context()
.expect("transaction source must be present in state when executing an action")
.address_bytes();
ensure!(
from == admin.bytes(),
"only the market map admin can add currency pairs"
);

let next_currency_pair_id = state
.get_next_currency_pair_id()
.await
.wrap_err("failed to get next currency pair id")?;
let num_currency_pairs = state
.get_num_currency_pairs()
.await
.wrap_err("failed to get number of currency pairs")?;
let timestamp: tendermint_proto::google::protobuf::Timestamp = state
.get_block_timestamp()
.await
.wrap_err("failed to get block timestamp")?
.into();

for pair in &self.pairs {
let currency_pair_state = CurrencyPairState {
price: QuotePrice {
price: Price::new(0),
block_timestamp: Timestamp {
seconds: timestamp.seconds,
nanos: timestamp.nanos,
},
block_height: state.get_block_height().await?,
},
nonce: CurrencyPairNonce::new(0),
id: next_currency_pair_id,
};
state
.put_currency_pair_state(pair.clone(), currency_pair_state)
.wrap_err("failed to put currency pair state")?;
num_currency_pairs
.checked_add(1)
.ok_or_eyre("overflow when incrementing number of currency pairs")?;
}

state
.put_next_currency_pair_id(CurrencyPairId::new(num_currency_pairs))
.wrap_err("failed to put next currency pair id")?;
state
.put_num_currency_pairs(
num_currency_pairs.saturating_add(
self.pairs
.len()
.try_into()
.expect("number of pairs cannot exceed u64::MAX"),
),
)
.wrap_err("failed to put number of currency pairs")?;
Ok(())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ use astria_eyre::eyre::{
use async_trait::async_trait;
use cnidarium::StateWrite;

use crate::action_handler::ActionHandler;
use crate::{
action_handler::ActionHandler,
connect::{
market_map::state_ext::StateReadExt as _,
oracle::state_ext::{
StateReadExt as _,
StateWriteExt,
},
},
transaction::StateReadExt as _,
};

#[async_trait]
impl ActionHandler for RemoveCurrencyPairs {
Expand All @@ -17,7 +27,44 @@ impl ActionHandler for RemoveCurrencyPairs {
}

async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
todo!();
// TODO: should we use the market map admin here, or a different admin?
let admin = state
.get_params()
.await?
.ok_or_eyre("market map params not set")?
.admin;
let from = state
.get_transaction_context()
.expect("transaction source must be present in state when executing an action")
.address_bytes();
ensure!(
from == admin.bytes(),
"only the market map admin can add currency pairs"
);

let num_currency_pairs = state
.get_num_currency_pairs()
.await
.wrap_err("failed to get number of currency pairs")?;
ensure!(
num_currency_pairs >= self.pairs.len() as u64,
"cannot remove more currency pairs than exist",
);

for pair in &self.pairs {
state
.delete_currency_pair(pair)
.await
.wrap_err("failed to delete currency pair")?;
num_currency_pairs
.checked_sub(1)
.ok_or_eyre("failed to decrement number of currency pairs")?;
}

state
.put_num_currency_pairs(num_currency_pairs)
.wrap_err("failed to put number of currency pairs")?;

Ok(())
}
}
21 changes: 9 additions & 12 deletions crates/astria-sequencer/src/app/vote_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,9 @@ impl Handler {
return Ok(abci::response::VerifyVoteExtension::Accept);
}

let max_num_currency_pairs =
DefaultCurrencyPairStrategy::get_max_num_currency_pairs(state, false)
.await
.wrap_err("failed to get max number of currency pairs")?;
let max_num_currency_pairs = DefaultCurrencyPairStrategy::get_max_num_currency_pairs(state)
.await
.wrap_err("failed to get max number of currency pairs")?;

let response = match verify_vote_extension(vote.vote_extension, max_num_currency_pairs) {
Ok(_) => abci::response::VerifyVoteExtension::Accept,
Expand Down Expand Up @@ -225,10 +224,9 @@ impl ProposalHandler {
));
}

let max_num_currency_pairs =
DefaultCurrencyPairStrategy::get_max_num_currency_pairs(state, true)
.await
.wrap_err("failed to get max number of currency pairs")?;
let max_num_currency_pairs = DefaultCurrencyPairStrategy::get_max_num_currency_pairs(state)
.await
.wrap_err("failed to get max number of currency pairs")?;

let mut all_currency_pair_ids = HashSet::new();
for vote in &mut extended_commit_info.votes {
Expand Down Expand Up @@ -310,10 +308,9 @@ impl ProposalHandler {
.await
.wrap_err("failed to validate vote extensions in validate_extended_commit_info")?;

let max_num_currency_pairs =
DefaultCurrencyPairStrategy::get_max_num_currency_pairs(state, true)
.await
.wrap_err("failed to get max number of currency pairs")?;
let max_num_currency_pairs = DefaultCurrencyPairStrategy::get_max_num_currency_pairs(state)
.await
.wrap_err("failed to get max number of currency pairs")?;

let mut all_currency_pair_ids = HashSet::new();
for vote in &extended_commit_info.votes {
Expand Down
3 changes: 0 additions & 3 deletions crates/astria-sequencer/src/connect/oracle/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ impl Component for OracleComponent {
state
.put_num_currency_pairs(connect.oracle().currency_pair_genesis.len() as u64)
.wrap_err("failed to put number of currency pairs")?;
state
.put_num_removed_currency_pairs(0)
.wrap_err("failed to put number of removed currency pairs")?;
}
Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,14 @@ impl DefaultCurrencyPairStrategy {
state.get_currency_pair(id).await
}

pub(crate) async fn get_max_num_currency_pairs<S: StateReadExt>(
state: &S,
is_proposal_phase: bool,
) -> Result<u64> {
let current = state
pub(crate) async fn get_max_num_currency_pairs<S: StateReadExt>(state: &S) -> Result<u64> {
// unlike the skip implementation, we don't need to track removed currency pairs
// from the previous block as we execute our transactions during the proposal phase,
// before vote extensions are broadcast. thus by the time we're making our VE, we
// already have the updated state for that block.
state
.get_num_currency_pairs()
.await
.wrap_err("failed to get number of currency pairs")?;

if is_proposal_phase {
let removed = state
.get_num_removed_currency_pairs()
.await
.wrap_err("failed to get number of removed currency pairs")?;
Ok(current.saturating_add(removed))
} else {
Ok(current)
}
.wrap_err("failed to get number of currency pairs")
}
}
Loading

0 comments on commit ebe0340

Please sign in to comment.