Skip to content

Commit

Permalink
Gj/update checkpoint structure (#934)
Browse files Browse the repository at this point in the history
## Describe your changes
Adds LMP storage states to ObCheckpoint.

## Checklist before requesting a review
- [x] I have performed a self-review of my code.
- [ ] If it is a core feature, I have added thorough tests.
- [x] I removed all Clippy and Formatting Warnings. 
- [x] I added required Copyrights.
  • Loading branch information
Gauthamastro authored Mar 21, 2024
2 parents f70e573 + f27cd6a commit 154fdd7
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 67 deletions.
73 changes: 68 additions & 5 deletions pallets/ocex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1889,32 +1889,95 @@ pub mod pallet {
/// Fetch checkpoint for recovery
pub fn fetch_checkpoint() -> Result<ObCheckpointRaw, DispatchError> {
log::debug!(target:"ocex", "fetch_checkpoint called");
let account_id =
let account_ids =
<Accounts<T>>::iter().fold(vec![], |mut ids_accum, (acc, acc_info)| {
ids_accum.push((acc.clone(), acc_info.proxies));
ids_accum
});

let mut balances: BTreeMap<AccountAsset, Decimal> = BTreeMap::new();
let mut q_scores_uptime_map = BTreeMap::new();
let mut maker_volume_map = BTreeMap::new();
let mut taker_volume_map = BTreeMap::new();
let mut fees_paid_map = BTreeMap::new();
let mut total_maker_volume_map = BTreeMap::new();
// all offchain balances for main accounts
for account in account_id {
let main = Self::transform_account(account.0)?;
for (account, _) in &account_ids {
let main = Self::transform_account(account.clone())?;
let b = Self::get_offchain_balance(&main)?;
for (asset, balance) in b.into_iter() {
balances.insert(AccountAsset { main: main.clone(), asset }, balance);
}
}

let state_info = Self::get_state_info().map_err(|_err| DispatchError::Corruption)?;
let last_processed_block_number = state_info.last_block;
let snapshot_id = state_info.snapshot_id;
let state_change_id = state_info.stid;

let mut root = crate::storage::load_trie_root();
let mut storage = crate::storage::State;
let mut state = OffchainState::load(&mut storage, &mut root);

let registered_tradingpairs = <TradingPairs<T>>::iter()
.map(|(base, quote, _)| (base, quote))
.collect::<Vec<(AssetId, AssetId)>>();

let current_epoch = <LMPEpoch<T>>::get();

for epoch in 0..=current_epoch {
for (base, quote) in &registered_tradingpairs {
let pair = TradingPair::from(*quote, *base);
for (account, _) in &account_ids {
let main = Self::transform_account(account.clone())?;
// Get Q scores
let q_scores_map = crate::lmp::get_q_score_and_uptime_for_checkpoint(
&mut state, epoch, &pair, &main,
)?;

if !q_scores_map.is_empty() {
q_scores_uptime_map.insert((epoch, pair, main.clone()), q_scores_map);
}

let fees_paid = crate::lmp::get_fees_paid_by_main_account_in_quote(
&mut state, epoch, &pair, &main,
)?;

fees_paid_map.insert((epoch, pair, main.clone()), fees_paid);

let maker_volume = crate::lmp::get_maker_volume_by_main_account(
&mut state, epoch, &pair, &main,
)?;

maker_volume_map.insert((epoch, pair, main.clone()), maker_volume);

let trade_volume = crate::lmp::get_trade_volume_by_main_account(
&mut state, epoch, &pair, &main,
)?;

taker_volume_map.insert((epoch, pair, main.clone()), trade_volume);
}
let total_maker_volume =
crate::lmp::get_total_maker_volume(&mut state, epoch, &pair)?;
total_maker_volume_map.insert((epoch, pair), total_maker_volume);
}
}

let config = crate::lmp::get_lmp_config(&mut state, current_epoch)?;

log::debug!(target:"ocex", "fetch_checkpoint returning");
Ok(ObCheckpointRaw::new(
Ok(ObCheckpointRaw {
snapshot_id,
balances,
last_processed_block_number,
state_change_id,
))
config,
q_scores_uptime_map,
maker_volume_map,
taker_volume_map,
fees_paid_map,
total_maker_volume_map,
})
}

/// Fetches balance of given `AssetId` for given `AccountId` from offchain storage
Expand Down
143 changes: 99 additions & 44 deletions pallets/ocex/src/lmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::lmp::keys::{
get_fees_paid_by_main_account, get_maker_volume_by_main_account_key,
get_q_score_uptime_by_main_account, get_total_maker_volume_key,
get_trade_volume_by_main_account_key,
};
use crate::{
pallet::{IngressMessages, PriceOracle, TraderMetrics, TradingPairs},
storage::OffchainState,
Expand All @@ -42,16 +47,64 @@ use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

pub const LMP_CONFIG_KEY: [u8; 14] = *b"LMP_CONFIG_KEY";

pub mod keys {
use crate::lmp::LMP_CONFIG_KEY;
use orderbook_primitives::types::TradingPair;
use parity_scale_codec::Encode;
use polkadex_primitives::AccountId;
use sp_std::vec::Vec;

pub fn get_trade_volume_by_main_account_key(
epoch: u16,
pair: TradingPair,
main: &AccountId,
) -> Vec<u8> {
(epoch, pair, "trading_volume", main).encode()
}

pub fn get_maker_volume_by_main_account_key(
epoch: u16,
pair: TradingPair,
main: &AccountId,
) -> Vec<u8> {
(epoch, pair, "maker_volume", main).encode()
}

pub fn get_total_maker_volume_key(epoch: u16, pair: TradingPair) -> Vec<u8> {
(epoch, pair, "maker_volume").encode()
}

pub fn get_fees_paid_by_main_account(
epoch: u16,
pair: TradingPair,
main: &AccountId,
) -> Vec<u8> {
(epoch, pair, "fees_paid", main).encode()
}

#[allow(dead_code)]
pub fn get_lmp_config_key() -> Vec<u8> {
LMP_CONFIG_KEY.encode()
}

pub fn get_q_score_uptime_by_main_account(
epoch: u16,
pair: TradingPair,
main: &AccountId,
) -> Vec<u8> {
(epoch, pair, "q_score&uptime", main).encode()
}
}

/// Updates the trade volume generated by main account in offchain work state trie
pub fn update_trade_volume_by_main_account(
state: &mut OffchainState,
epoch: u16,
market: &TradingPairConfig,
trading_pair: TradingPair,
volume: Decimal,
main: &AccountId,
) -> Result<Decimal, &'static str> {
let trading_pair = TradingPair::from(market.quote_asset, market.base_asset);
let key = (epoch, trading_pair, "trading_volume", main).encode();
let key = get_trade_volume_by_main_account_key(epoch, trading_pair, main);
Ok(match state.get(&key)? {
None => {
state.insert(key, volume.encode());
Expand All @@ -74,7 +127,7 @@ pub fn get_trade_volume_by_main_account(
trading_pair: &TradingPair,
main: &AccountId,
) -> Result<Decimal, &'static str> {
let key = (epoch, trading_pair, "trading_volume", main).encode();
let key = get_trade_volume_by_main_account_key(epoch, *trading_pair, main);
Ok(match state.get(&key)? {
None => Decimal::zero(),
Some(encoded_volume) => {
Expand All @@ -90,7 +143,7 @@ pub fn get_maker_volume_by_main_account(
trading_pair: &TradingPair,
main: &AccountId,
) -> Result<Decimal, &'static str> {
let key = (epoch, trading_pair, "maker_volume", main).encode();
let key = get_maker_volume_by_main_account_key(epoch, *trading_pair, main);
Ok(match state.get(&key)? {
None => Decimal::zero(),
Some(encoded_volume) => {
Expand All @@ -103,12 +156,11 @@ pub fn get_maker_volume_by_main_account(
pub fn update_maker_volume_by_main_account(
state: &mut OffchainState,
epoch: u16,
market: &TradingPairConfig,
trading_pair: TradingPair,
volume: Decimal,
main: &AccountId,
) -> Result<Decimal, &'static str> {
let trading_pair = TradingPair::from(market.quote_asset, market.base_asset);
let key = (epoch, trading_pair, "maker_volume", main).encode();
let key = get_maker_volume_by_main_account_key(epoch, trading_pair, main);
Ok(match state.get(&key)? {
None => {
state.insert(key, volume.encode());
Expand All @@ -134,7 +186,7 @@ pub fn get_total_maker_volume(
return Ok(Decimal::zero());
}

let key = (epoch, trading_pair, "maker_volume").encode();
let key = get_total_maker_volume_key(epoch, *trading_pair);
Ok(match state.get(&key)? {
None => Decimal::zero(),
Some(encoded_volume) => {
Expand All @@ -147,11 +199,10 @@ pub fn get_total_maker_volume(
pub fn update_total_maker_volume(
state: &mut OffchainState,
epoch: u16,
market: &TradingPairConfig,
trading_pair: TradingPair,
volume: Decimal,
) -> Result<Decimal, &'static str> {
let trading_pair = TradingPair::from(market.quote_asset, market.base_asset);
let key = (epoch, trading_pair, "maker_volume").encode();
let key = get_total_maker_volume_key(epoch, trading_pair);
Ok(match state.get(&key)? {
None => {
state.insert(key, volume.encode());
Expand All @@ -171,12 +222,11 @@ pub fn update_total_maker_volume(
pub fn store_fees_paid_by_main_account_in_quote(
state: &mut OffchainState,
epoch: u16,
market: &TradingPairConfig,
trading_pair: TradingPair,
fees_in_quote_terms: Decimal,
main: &AccountId,
) -> Result<Decimal, &'static str> {
let trading_pair = TradingPair::from(market.quote_asset, market.base_asset);
let key = (epoch, trading_pair, "fees_paid", main).encode();
let key = get_fees_paid_by_main_account(epoch, trading_pair, main);
Ok(match state.get(&key)? {
None => {
state.insert(key, fees_in_quote_terms.encode());
Expand All @@ -199,7 +249,7 @@ pub fn get_fees_paid_by_main_account_in_quote(
trading_pair: &TradingPair,
main: &AccountId,
) -> Result<Decimal, &'static str> {
let key = (epoch, trading_pair, "fees_paid", main).encode();
let key = get_fees_paid_by_main_account(epoch, *trading_pair, main);
Ok(match state.get(&key)? {
None => Decimal::zero(),
Some(encoded_fees_paid) => {
Expand Down Expand Up @@ -243,7 +293,7 @@ pub fn store_q_score_and_uptime(
trading_pair: &TradingPair,
main: &AccountId,
) -> Result<(), &'static str> {
let key = (epoch, trading_pair, "q_score&uptime", main).encode();
let key = get_q_score_uptime_by_main_account(epoch, *trading_pair, main);
match state.get(&key)? {
None => state.insert(key, BTreeMap::from([(index, score)]).encode()),
Some(encoded_q_scores_map) => {
Expand All @@ -267,7 +317,7 @@ pub fn get_q_score_and_uptime(
trading_pair: &TradingPair,
main: &AccountId,
) -> Result<(Decimal, u16), &'static str> {
let key = (epoch, trading_pair, "q_score&uptime", main).encode();
let key = get_q_score_uptime_by_main_account(epoch, *trading_pair, main);
match state.get(&key)? {
None => {
log::warn!(target:"ocex","q_score&uptime not found for: main: {:?}, market: {:?}",main.to_ss58check_with_version(Ss58AddressFormat::from(POLKADEX_MAINNET_SS58)), trading_pair.to_string());
Expand All @@ -287,6 +337,28 @@ pub fn get_q_score_and_uptime(
}
}

/// Returns the individial Q score and uptime indexe
pub fn get_q_score_and_uptime_for_checkpoint(
state: &mut OffchainState,
epoch: u16,
trading_pair: &TradingPair,
main: &AccountId,
) -> Result<BTreeMap<u16, Decimal>, &'static str> {
let key = get_q_score_uptime_by_main_account(epoch, *trading_pair, main);
match state.get(&key)? {
None => {
log::warn!(target:"ocex","q_score&uptime not found for: main: {:?}, market: {:?}",main.to_ss58check_with_version(Ss58AddressFormat::from(POLKADEX_MAINNET_SS58)), trading_pair.to_string());
// If the q_score is not found, zero will be returned.
Ok(Default::default())
},
Some(encoded_q_scores_map) => {
let map = BTreeMap::<u16, Decimal>::decode(&mut &encoded_q_scores_map[..])
.map_err(|_| "Unable to decode decimal")?;
Ok(map)
},
}
}

impl<T: Config> Pallet<T> {
/// Updates the respective offchain DB trie keys for LMP metrics from given trade
pub fn update_lmp_storage_from_trade(
Expand All @@ -297,35 +369,18 @@ impl<T: Config> Pallet<T> {
taker_fees: Decimal,
) -> Result<(), &'static str> {
let epoch: u16 = <LMPEpoch<T>>::get();
let pair = TradingPair::from(config.quote_asset, config.base_asset);

// Store trade.price * trade.volume as maker volume for this epoch
let volume = trade.price.saturating_mul(trade.amount);
// Update the trade volume generated to maker account
update_trade_volume_by_main_account(
state,
epoch,
&config,
volume,
&trade.maker.main_account,
)?;
update_trade_volume_by_main_account(state, epoch, pair, volume, &trade.maker.main_account)?;
// Update the trade volume generated to taker account
update_trade_volume_by_main_account(
state,
epoch,
&config,
volume,
&trade.taker.main_account,
)?;
update_trade_volume_by_main_account(state, epoch, pair, volume, &trade.taker.main_account)?;
// Update the maker volume generated to account
update_maker_volume_by_main_account(
state,
epoch,
&config,
volume,
&trade.maker.main_account,
)?;
update_maker_volume_by_main_account(state, epoch, pair, volume, &trade.maker.main_account)?;
// Update the total maker volume generated
update_total_maker_volume(state, epoch, &config, volume)?;
update_total_maker_volume(state, epoch, pair, volume)?;

// Store maker_fees and taker_fees for the corresponding main account for this epoch
match trade.maker.side {
Expand All @@ -334,7 +389,7 @@ impl<T: Config> Pallet<T> {
store_fees_paid_by_main_account_in_quote(
state,
epoch,
&config,
pair,
fees,
&trade.maker.main_account,
)?;
Expand All @@ -344,7 +399,7 @@ impl<T: Config> Pallet<T> {
store_fees_paid_by_main_account_in_quote(
state,
epoch,
&config,
pair,
fees,
&trade.taker.main_account,
)?;
Expand All @@ -355,7 +410,7 @@ impl<T: Config> Pallet<T> {
store_fees_paid_by_main_account_in_quote(
state,
epoch,
&config,
pair,
fees,
&trade.maker.main_account,
)?;
Expand All @@ -365,7 +420,7 @@ impl<T: Config> Pallet<T> {
store_fees_paid_by_main_account_in_quote(
state,
epoch,
&config,
pair,
fees,
&trade.taker.main_account,
)?;
Expand Down
Loading

0 comments on commit 154fdd7

Please sign in to comment.