Skip to content

Commit

Permalink
feat: add publisher stake caps to validator (#1778)
Browse files Browse the repository at this point in the history
* go

* go

* arbitrary implementation

* add lenght as u16

* go

* go

* fix: hermes

* fix: make match statement explicit

* fix: make feed_id return an option

* fix: revert, add commment

* fix: solana tests

* fix: other tests

* fix: change from [0;32]

* add version

* Revert "add version"

This reverts commit 48af94f.

* bump
  • Loading branch information
guibescos authored Jul 31, 2024
1 parent f41782f commit ff2d6a0
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 47 deletions.
2 changes: 1 addition & 1 deletion apps/hermes/server/src/state/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl MessageState {
pub fn key(&self) -> MessageStateKey {
MessageStateKey {
feed_id: self.message.feed_id(),
type_: self.message.into(),
type_: self.message.clone().into(),
}
}

Expand Down
2 changes: 1 addition & 1 deletion pythnet/pythnet_sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pythnet-sdk"
version = "2.1.0"
version = "2.2.0"
description = "Pyth Runtime for Solana"
authors = ["Pyth Data Association"]
repository = "https://github.com/pyth-network/pythnet"
Expand Down
65 changes: 58 additions & 7 deletions pythnet/pythnet_sdk/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use borsh::{
#[cfg(feature = "quickcheck")]
use quickcheck::Arbitrary;
use {
crate::wire::PrefixedVec,
borsh::BorshSchema,
serde::{
Deserialize,
Expand All @@ -30,7 +31,7 @@ use {
/// some of the methods for PriceFeedMessage and TwapMessage are not used by the oracle
/// for the same reason. Rust compiler doesn't include the unused methods in the contract.
/// Once we start using the unused structs and methods, the contract size will increase.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(
feature = "strum",
derive(strum::EnumDiscriminants),
Expand All @@ -50,20 +51,28 @@ use {
pub enum Message {
PriceFeedMessage(PriceFeedMessage),
TwapMessage(TwapMessage),
PublisherStakeCapsMessage(PublisherStakeCapsMessage),
}

/// PublisherStakeCapsMessage is a global message that aggregates data from all price feeds
/// we can't associate it with a specific feed, so we use a feed id that is not used by any price feed
pub const PUBLISHER_STAKE_CAPS_MESSAGE_FEED_ID: FeedId = [1u8; 32];

impl Message {
pub fn publish_time(&self) -> i64 {
match self {
Self::PriceFeedMessage(msg) => msg.publish_time,
Self::TwapMessage(msg) => msg.publish_time,
Self::PublisherStakeCapsMessage(msg) => msg.publish_time,
}
}

/// TO DO : This API doesn't work with PublisherStakeCapsMessage since it doesn't have a feed_id, consider refactoring
pub fn feed_id(&self) -> FeedId {
match self {
Self::PriceFeedMessage(msg) => msg.feed_id,
Self::TwapMessage(msg) => msg.feed_id,
Self::PublisherStakeCapsMessage(_) => PUBLISHER_STAKE_CAPS_MESSAGE_FEED_ID,
}
}
}
Expand All @@ -80,6 +89,7 @@ impl Arbitrary for Message {

/// Id of a feed producing the message. One feed produces one or more messages.
pub type FeedId = [u8; 32];
pub type Pubkey = [u8; 32];

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, BorshSchema)]
Expand Down Expand Up @@ -116,15 +126,15 @@ pub struct PriceFeedMessage {
#[cfg(feature = "quickcheck")]
impl Arbitrary for PriceFeedMessage {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut id = [0u8; 32];
for item in &mut id {
let mut feed_id = [0u8; 32];
for item in &mut feed_id {
*item = u8::arbitrary(g);
}

let publish_time = i64::arbitrary(g);

PriceFeedMessage {
id,
feed_id,
price: i64::arbitrary(g),
conf: u64::arbitrary(g),
exponent: i32::arbitrary(g),
Expand Down Expand Up @@ -153,15 +163,15 @@ pub struct TwapMessage {
#[cfg(feature = "quickcheck")]
impl Arbitrary for TwapMessage {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut id = [0u8; 32];
for item in &mut id {
let mut feed_id = [0u8; 32];
for item in &mut feed_id {
*item = u8::arbitrary(g);
}

let publish_time = i64::arbitrary(g);

TwapMessage {
id,
feed_id,
cumulative_price: i128::arbitrary(g),
cumulative_conf: u128::arbitrary(g),
num_down_slots: u64::arbitrary(g),
Expand All @@ -173,6 +183,47 @@ impl Arbitrary for TwapMessage {
}
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PublisherStakeCapsMessage {
pub publish_time: i64,
pub caps: PrefixedVec<u16, PublisherStakeCap>, // PrefixedVec because we might have more than 256 publishers
}

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct PublisherStakeCap {
pub publisher: Pubkey,
pub cap: u64,
}

#[cfg(feature = "quickcheck")]
impl Arbitrary for PublisherStakeCapsMessage {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let caps = Vec::arbitrary(g);
PublisherStakeCapsMessage {
publish_time: i64::arbitrary(g),
caps: caps.into(),
}
}
}

#[cfg(feature = "quickcheck")]
impl Arbitrary for PublisherStakeCap {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
PublisherStakeCap {
publisher: {
let mut publisher = [0u8; 32];
for item in &mut publisher {
*item = u8::arbitrary(g);
}
publisher
},
cap: u64::arbitrary(g),
}
}
}

#[cfg(test)]
mod tests {

Expand Down
4 changes: 2 additions & 2 deletions pythnet/pythnet_sdk/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ pub fn create_dummy_twap_message() -> Message {
}

pub fn create_accumulator_message(
all_feeds: &[Message],
updates: &[Message],
all_feeds: &[&Message],
updates: &[&Message],
corrupt_wormhole_message: bool,
corrupt_messages: bool,
) -> Vec<u8> {
Expand Down
43 changes: 23 additions & 20 deletions target_chains/cosmwasm/contracts/pyth/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ mod test {
let feed1 = create_dummy_price_feed_message(100);
let feed2 = create_dummy_price_feed_message(200);
let feed3 = create_dummy_price_feed_message(300);
let data = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
let data = create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1], false, false);
check_sufficient_fee(&deps.as_ref(), &[data.into()])
}

Expand Down Expand Up @@ -1246,21 +1246,22 @@ mod test {
let feed2 = create_dummy_price_feed_message(200);
let feed3 = create_dummy_price_feed_message(300);

let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false, false);
let msg =
create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1, &feed3], false, false);
assert_eq!(
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
200
);

let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
let msg = create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1], false, false);
assert_eq!(
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
100
);

let msg = create_accumulator_message(
&[feed1, feed2, feed3],
&[feed1, feed2, feed3, feed1, feed3],
&[&feed1, &feed2, &feed3],
&[&feed1, &feed2, &feed3, &feed1, &feed3],
false,
false,
);
Expand All @@ -1272,8 +1273,8 @@ mod test {
let batch_msg =
create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]);
let msg = create_accumulator_message(
&[feed1, feed2, feed3],
&[feed1, feed2, feed3],
&[&feed1, &feed2, &feed3],
&[&feed1, &feed2, &feed3],
false,
false,
);
Expand All @@ -1293,7 +1294,7 @@ mod test {

let feed1 = create_dummy_price_feed_message(100);
let feed2 = create_dummy_price_feed_message(200);
let msg = create_accumulator_message(&[feed1, feed2], &[feed1], false, false);
let msg = create_accumulator_message(&[&feed1, &feed2], &[&feed1], false, false);
let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_ok());
Expand All @@ -1310,12 +1311,13 @@ mod test {
for i in 0..10000 {
all_feeds.push(create_dummy_price_feed_message(i));
}
let all_feeds: Vec<&Message> = all_feeds.iter().collect();
let msg = create_accumulator_message(&all_feeds, &all_feeds[100..110], false, false);
let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_ok());
for i in 100..110 {
check_price_match(&deps, &all_feeds[i]);
check_price_match(&deps, all_feeds[i]);
}
}

Expand All @@ -1338,8 +1340,8 @@ mod test {
let mut feed2 = create_dummy_price_feed_message(200);
let mut feed3 = create_dummy_price_feed_message(300);
let msg = create_accumulator_message(
&[feed1, feed2, feed3],
&[feed1, feed2, feed3],
&[&feed1, &feed2, &feed3],
&[&feed1, &feed2, &feed3],
false,
false,
);
Expand All @@ -1350,8 +1352,8 @@ mod test {
as_mut_price_feed(&mut feed2).price *= 2;
as_mut_price_feed(&mut feed3).price *= 2;
let msg2 = create_accumulator_message(
&[feed1, feed2, feed3],
&[feed1, feed2, feed3],
&[&feed1, &feed2, &feed3],
&[&feed1, &feed2, &feed3],
false,
false,
);
Expand All @@ -1376,8 +1378,8 @@ mod test {
as_mut_price_feed(&mut feed2).publish_time -= 1;
as_mut_price_feed(&mut feed2).price *= 2;
let msg = create_accumulator_message(
&[feed1, feed2, feed3],
&[feed1, feed2, feed3],
&[&feed1, &feed2, &feed3],
&[&feed1, &feed2, &feed3],
false,
false,
);
Expand All @@ -1400,10 +1402,11 @@ mod test {
let feed3 = create_dummy_price_feed_message(300);
as_mut_price_feed(&mut feed2).publish_time -= 1;
as_mut_price_feed(&mut feed2).price *= 2;
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false, false);
let msg =
create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1, &feed3], false, false);

let msg2 =
create_accumulator_message(&[feed1, feed2, feed3], &[feed2, feed3], false, false);
create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed2, &feed3], false, false);
let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);

Expand All @@ -1420,7 +1423,7 @@ mod test {
.unwrap();

let feed1 = create_dummy_price_feed_message(100);
let mut msg = create_accumulator_message(&[feed1], &[feed1], false, false);
let mut msg = create_accumulator_message(&[&feed1], &[&feed1], false, false);
msg[4] = 3; // major version
let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
Expand All @@ -1439,7 +1442,7 @@ mod test {
.unwrap();

let feed1 = create_dummy_price_feed_message(100);
let msg = create_accumulator_message(&[feed1], &[feed1], true, false);
let msg = create_accumulator_message(&[&feed1], &[&feed1], true, false);
let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err());
Expand Down Expand Up @@ -1467,7 +1470,7 @@ mod test {
prev_publish_time: 0,
publish_slot: 0,
});
let msg = create_accumulator_message(&[feed1], &[feed1], false, false);
let msg = create_accumulator_message(&[&feed1], &[&feed1], false, false);
let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err());
Expand Down
2 changes: 1 addition & 1 deletion target_chains/near/receiver/tests/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ async fn test_accumulator_updates() {
// Create a couple of test feeds.
let feed_1 = create_dummy_price_feed_message(100);
let feed_2 = create_dummy_price_feed_message(200);
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1], false, false);
let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1], false, false);
let message = hex::encode(message);

// Call the usual UpdatePriceFeed function.
Expand Down
2 changes: 1 addition & 1 deletion target_chains/solana/programs/pyth-push-oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub mod pyth_push_oracle {
.map_err(|_| PushOracleError::DeserializeMessageFailed)?;
let next_timestamp = match message {
Message::PriceFeedMessage(price_feed_message) => price_feed_message.publish_time,
Message::TwapMessage(_) => {
Message::TwapMessage(_) | Message::PublisherStakeCapsMessage(_) => {
return err!(PushOracleError::UnsupportedMessageType);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ async fn test_update_price_feed() {
let feed_2 = create_dummy_price_feed_message_with_feed_id(300, feed_id_2);

let message = create_accumulator_message(
&[feed_1_old, feed_1_recent, feed_2],
&[feed_1_old, feed_1_recent, feed_2],
&[&feed_1_old, &feed_1_recent, &feed_2],
&[&feed_1_old, &feed_1_recent, &feed_2],
false,
false,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ fn post_price_update_from_vaa<'info>(
price_update_account.price_message = price_feed_message;
price_update_account.posted_slot = Clock::get()?.slot;
}
Message::TwapMessage(_) => {
Message::TwapMessage(_) | Message::PublisherStakeCapsMessage(_) => {
return err!(ReceiverError::UnsupportedMessageType);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async fn test_invalid_wormhole_message() {
let feed_1 = create_dummy_price_feed_message(100);
let feed_2 = create_dummy_price_feed_message(200);

let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], true, false);
let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1, &feed_2], true, false);
let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();

let ProgramTestFixtures {
Expand Down Expand Up @@ -100,7 +100,7 @@ async fn test_invalid_update_message() {
let feed_1 = create_dummy_price_feed_message(100);
let feed_2 = create_dummy_price_feed_message(200);

let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false, true);
let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1, &feed_2], false, true);
let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();


Expand Down Expand Up @@ -150,15 +150,15 @@ async fn test_post_price_update_from_vaa() {
let twap_1 = create_dummy_twap_message();

let message = create_accumulator_message(
&[feed_1, feed_2, twap_1],
&[feed_1, feed_2, twap_1],
&[&feed_1, &feed_2, &twap_1],
&[&feed_1, &feed_2, &twap_1],
false,
false,
);

let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();

let message2 = create_accumulator_message(&[feed_2, feed_3], &[feed_3], false, false);
let message2 = create_accumulator_message(&[&feed_2, &feed_3], &[&feed_3], false, false);
let (_, merkle_price_updates2) = deserialize_accumulator_update_data(message2).unwrap();

let ProgramTestFixtures {
Expand Down
Loading

0 comments on commit ff2d6a0

Please sign in to comment.