Skip to content

Commit ff2d6a0

Browse files
authored
feat: add publisher stake caps to validator (#1778)
* 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
1 parent f41782f commit ff2d6a0

File tree

12 files changed

+107
-47
lines changed

12 files changed

+107
-47
lines changed

apps/hermes/server/src/state/cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl MessageState {
6969
pub fn key(&self) -> MessageStateKey {
7070
MessageStateKey {
7171
feed_id: self.message.feed_id(),
72-
type_: self.message.into(),
72+
type_: self.message.clone().into(),
7373
}
7474
}
7575

pythnet/pythnet_sdk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pythnet-sdk"
3-
version = "2.1.0"
3+
version = "2.2.0"
44
description = "Pyth Runtime for Solana"
55
authors = ["Pyth Data Association"]
66
repository = "https://github.com/pyth-network/pythnet"

pythnet/pythnet_sdk/src/messages.rs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use borsh::{
1111
#[cfg(feature = "quickcheck")]
1212
use quickcheck::Arbitrary;
1313
use {
14+
crate::wire::PrefixedVec,
1415
borsh::BorshSchema,
1516
serde::{
1617
Deserialize,
@@ -30,7 +31,7 @@ use {
3031
/// some of the methods for PriceFeedMessage and TwapMessage are not used by the oracle
3132
/// for the same reason. Rust compiler doesn't include the unused methods in the contract.
3233
/// Once we start using the unused structs and methods, the contract size will increase.
33-
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
34+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3435
#[cfg_attr(
3536
feature = "strum",
3637
derive(strum::EnumDiscriminants),
@@ -50,20 +51,28 @@ use {
5051
pub enum Message {
5152
PriceFeedMessage(PriceFeedMessage),
5253
TwapMessage(TwapMessage),
54+
PublisherStakeCapsMessage(PublisherStakeCapsMessage),
5355
}
5456

57+
/// PublisherStakeCapsMessage is a global message that aggregates data from all price feeds
58+
/// we can't associate it with a specific feed, so we use a feed id that is not used by any price feed
59+
pub const PUBLISHER_STAKE_CAPS_MESSAGE_FEED_ID: FeedId = [1u8; 32];
60+
5561
impl Message {
5662
pub fn publish_time(&self) -> i64 {
5763
match self {
5864
Self::PriceFeedMessage(msg) => msg.publish_time,
5965
Self::TwapMessage(msg) => msg.publish_time,
66+
Self::PublisherStakeCapsMessage(msg) => msg.publish_time,
6067
}
6168
}
6269

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

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

8494
#[repr(C)]
8595
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, BorshSchema)]
@@ -116,15 +126,15 @@ pub struct PriceFeedMessage {
116126
#[cfg(feature = "quickcheck")]
117127
impl Arbitrary for PriceFeedMessage {
118128
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
119-
let mut id = [0u8; 32];
120-
for item in &mut id {
129+
let mut feed_id = [0u8; 32];
130+
for item in &mut feed_id {
121131
*item = u8::arbitrary(g);
122132
}
123133

124134
let publish_time = i64::arbitrary(g);
125135

126136
PriceFeedMessage {
127-
id,
137+
feed_id,
128138
price: i64::arbitrary(g),
129139
conf: u64::arbitrary(g),
130140
exponent: i32::arbitrary(g),
@@ -153,15 +163,15 @@ pub struct TwapMessage {
153163
#[cfg(feature = "quickcheck")]
154164
impl Arbitrary for TwapMessage {
155165
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
156-
let mut id = [0u8; 32];
157-
for item in &mut id {
166+
let mut feed_id = [0u8; 32];
167+
for item in &mut feed_id {
158168
*item = u8::arbitrary(g);
159169
}
160170

161171
let publish_time = i64::arbitrary(g);
162172

163173
TwapMessage {
164-
id,
174+
feed_id,
165175
cumulative_price: i128::arbitrary(g),
166176
cumulative_conf: u128::arbitrary(g),
167177
num_down_slots: u64::arbitrary(g),
@@ -173,6 +183,47 @@ impl Arbitrary for TwapMessage {
173183
}
174184
}
175185

186+
#[repr(C)]
187+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
188+
pub struct PublisherStakeCapsMessage {
189+
pub publish_time: i64,
190+
pub caps: PrefixedVec<u16, PublisherStakeCap>, // PrefixedVec because we might have more than 256 publishers
191+
}
192+
193+
#[repr(C)]
194+
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
195+
pub struct PublisherStakeCap {
196+
pub publisher: Pubkey,
197+
pub cap: u64,
198+
}
199+
200+
#[cfg(feature = "quickcheck")]
201+
impl Arbitrary for PublisherStakeCapsMessage {
202+
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
203+
let caps = Vec::arbitrary(g);
204+
PublisherStakeCapsMessage {
205+
publish_time: i64::arbitrary(g),
206+
caps: caps.into(),
207+
}
208+
}
209+
}
210+
211+
#[cfg(feature = "quickcheck")]
212+
impl Arbitrary for PublisherStakeCap {
213+
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
214+
PublisherStakeCap {
215+
publisher: {
216+
let mut publisher = [0u8; 32];
217+
for item in &mut publisher {
218+
*item = u8::arbitrary(g);
219+
}
220+
publisher
221+
},
222+
cap: u64::arbitrary(g),
223+
}
224+
}
225+
}
226+
176227
#[cfg(test)]
177228
mod tests {
178229

pythnet/pythnet_sdk/src/test_utils/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ pub fn create_dummy_twap_message() -> Message {
153153
}
154154

155155
pub fn create_accumulator_message(
156-
all_feeds: &[Message],
157-
updates: &[Message],
156+
all_feeds: &[&Message],
157+
updates: &[&Message],
158158
corrupt_wormhole_message: bool,
159159
corrupt_messages: bool,
160160
) -> Vec<u8> {

target_chains/cosmwasm/contracts/pyth/src/contract.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,7 @@ mod test {
11551155
let feed1 = create_dummy_price_feed_message(100);
11561156
let feed2 = create_dummy_price_feed_message(200);
11571157
let feed3 = create_dummy_price_feed_message(300);
1158-
let data = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
1158+
let data = create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1], false, false);
11591159
check_sufficient_fee(&deps.as_ref(), &[data.into()])
11601160
}
11611161

@@ -1246,21 +1246,22 @@ mod test {
12461246
let feed2 = create_dummy_price_feed_message(200);
12471247
let feed3 = create_dummy_price_feed_message(300);
12481248

1249-
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false, false);
1249+
let msg =
1250+
create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1, &feed3], false, false);
12501251
assert_eq!(
12511252
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
12521253
200
12531254
);
12541255

1255-
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
1256+
let msg = create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1], false, false);
12561257
assert_eq!(
12571258
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
12581259
100
12591260
);
12601261

12611262
let msg = create_accumulator_message(
1262-
&[feed1, feed2, feed3],
1263-
&[feed1, feed2, feed3, feed1, feed3],
1263+
&[&feed1, &feed2, &feed3],
1264+
&[&feed1, &feed2, &feed3, &feed1, &feed3],
12641265
false,
12651266
false,
12661267
);
@@ -1272,8 +1273,8 @@ mod test {
12721273
let batch_msg =
12731274
create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]);
12741275
let msg = create_accumulator_message(
1275-
&[feed1, feed2, feed3],
1276-
&[feed1, feed2, feed3],
1276+
&[&feed1, &feed2, &feed3],
1277+
&[&feed1, &feed2, &feed3],
12771278
false,
12781279
false,
12791280
);
@@ -1293,7 +1294,7 @@ mod test {
12931294

12941295
let feed1 = create_dummy_price_feed_message(100);
12951296
let feed2 = create_dummy_price_feed_message(200);
1296-
let msg = create_accumulator_message(&[feed1, feed2], &[feed1], false, false);
1297+
let msg = create_accumulator_message(&[&feed1, &feed2], &[&feed1], false, false);
12971298
let info = mock_info("123", &[]);
12981299
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
12991300
assert!(result.is_ok());
@@ -1310,12 +1311,13 @@ mod test {
13101311
for i in 0..10000 {
13111312
all_feeds.push(create_dummy_price_feed_message(i));
13121313
}
1314+
let all_feeds: Vec<&Message> = all_feeds.iter().collect();
13131315
let msg = create_accumulator_message(&all_feeds, &all_feeds[100..110], false, false);
13141316
let info = mock_info("123", &[]);
13151317
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
13161318
assert!(result.is_ok());
13171319
for i in 100..110 {
1318-
check_price_match(&deps, &all_feeds[i]);
1320+
check_price_match(&deps, all_feeds[i]);
13191321
}
13201322
}
13211323

@@ -1338,8 +1340,8 @@ mod test {
13381340
let mut feed2 = create_dummy_price_feed_message(200);
13391341
let mut feed3 = create_dummy_price_feed_message(300);
13401342
let msg = create_accumulator_message(
1341-
&[feed1, feed2, feed3],
1342-
&[feed1, feed2, feed3],
1343+
&[&feed1, &feed2, &feed3],
1344+
&[&feed1, &feed2, &feed3],
13431345
false,
13441346
false,
13451347
);
@@ -1350,8 +1352,8 @@ mod test {
13501352
as_mut_price_feed(&mut feed2).price *= 2;
13511353
as_mut_price_feed(&mut feed3).price *= 2;
13521354
let msg2 = create_accumulator_message(
1353-
&[feed1, feed2, feed3],
1354-
&[feed1, feed2, feed3],
1355+
&[&feed1, &feed2, &feed3],
1356+
&[&feed1, &feed2, &feed3],
13551357
false,
13561358
false,
13571359
);
@@ -1376,8 +1378,8 @@ mod test {
13761378
as_mut_price_feed(&mut feed2).publish_time -= 1;
13771379
as_mut_price_feed(&mut feed2).price *= 2;
13781380
let msg = create_accumulator_message(
1379-
&[feed1, feed2, feed3],
1380-
&[feed1, feed2, feed3],
1381+
&[&feed1, &feed2, &feed3],
1382+
&[&feed1, &feed2, &feed3],
13811383
false,
13821384
false,
13831385
);
@@ -1400,10 +1402,11 @@ mod test {
14001402
let feed3 = create_dummy_price_feed_message(300);
14011403
as_mut_price_feed(&mut feed2).publish_time -= 1;
14021404
as_mut_price_feed(&mut feed2).price *= 2;
1403-
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false, false);
1405+
let msg =
1406+
create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed1, &feed3], false, false);
14041407

14051408
let msg2 =
1406-
create_accumulator_message(&[feed1, feed2, feed3], &[feed2, feed3], false, false);
1409+
create_accumulator_message(&[&feed1, &feed2, &feed3], &[&feed2, &feed3], false, false);
14071410
let info = mock_info("123", &[]);
14081411
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
14091412

@@ -1420,7 +1423,7 @@ mod test {
14201423
.unwrap();
14211424

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

14411444
let feed1 = create_dummy_price_feed_message(100);
1442-
let msg = create_accumulator_message(&[feed1], &[feed1], true, false);
1445+
let msg = create_accumulator_message(&[&feed1], &[&feed1], true, false);
14431446
let info = mock_info("123", &[]);
14441447
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
14451448
assert!(result.is_err());
@@ -1467,7 +1470,7 @@ mod test {
14671470
prev_publish_time: 0,
14681471
publish_slot: 0,
14691472
});
1470-
let msg = create_accumulator_message(&[feed1], &[feed1], false, false);
1473+
let msg = create_accumulator_message(&[&feed1], &[&feed1], false, false);
14711474
let info = mock_info("123", &[]);
14721475
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
14731476
assert!(result.is_err());

target_chains/near/receiver/tests/workspaces.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ async fn test_accumulator_updates() {
910910
// Create a couple of test feeds.
911911
let feed_1 = create_dummy_price_feed_message(100);
912912
let feed_2 = create_dummy_price_feed_message(200);
913-
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1], false, false);
913+
let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1], false, false);
914914
let message = hex::encode(message);
915915

916916
// Call the usual UpdatePriceFeed function.

target_chains/solana/programs/pyth-push-oracle/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub mod pyth_push_oracle {
8383
.map_err(|_| PushOracleError::DeserializeMessageFailed)?;
8484
let next_timestamp = match message {
8585
Message::PriceFeedMessage(price_feed_message) => price_feed_message.publish_time,
86-
Message::TwapMessage(_) => {
86+
Message::TwapMessage(_) | Message::PublisherStakeCapsMessage(_) => {
8787
return err!(PushOracleError::UnsupportedMessageType);
8888
}
8989
};

target_chains/solana/programs/pyth-push-oracle/tests/test_update_price_feed.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ async fn test_update_price_feed() {
4747
let feed_2 = create_dummy_price_feed_message_with_feed_id(300, feed_id_2);
4848

4949
let message = create_accumulator_message(
50-
&[feed_1_old, feed_1_recent, feed_2],
51-
&[feed_1_old, feed_1_recent, feed_2],
50+
&[&feed_1_old, &feed_1_recent, &feed_2],
51+
&[&feed_1_old, &feed_1_recent, &feed_2],
5252
false,
5353
false,
5454
);

target_chains/solana/programs/pyth-solana-receiver/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ fn post_price_update_from_vaa<'info>(
437437
price_update_account.price_message = price_feed_message;
438438
price_update_account.posted_slot = Clock::get()?.slot;
439439
}
440-
Message::TwapMessage(_) => {
440+
Message::TwapMessage(_) | Message::PublisherStakeCapsMessage(_) => {
441441
return err!(ReceiverError::UnsupportedMessageType);
442442
}
443443
}

target_chains/solana/programs/pyth-solana-receiver/tests/test_post_price_update_from_vaa.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async fn test_invalid_wormhole_message() {
5555
let feed_1 = create_dummy_price_feed_message(100);
5656
let feed_2 = create_dummy_price_feed_message(200);
5757

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

6161
let ProgramTestFixtures {
@@ -100,7 +100,7 @@ async fn test_invalid_update_message() {
100100
let feed_1 = create_dummy_price_feed_message(100);
101101
let feed_2 = create_dummy_price_feed_message(200);
102102

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

106106

@@ -150,15 +150,15 @@ async fn test_post_price_update_from_vaa() {
150150
let twap_1 = create_dummy_twap_message();
151151

152152
let message = create_accumulator_message(
153-
&[feed_1, feed_2, twap_1],
154-
&[feed_1, feed_2, twap_1],
153+
&[&feed_1, &feed_2, &twap_1],
154+
&[&feed_1, &feed_2, &twap_1],
155155
false,
156156
false,
157157
);
158158

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

161-
let message2 = create_accumulator_message(&[feed_2, feed_3], &[feed_3], false, false);
161+
let message2 = create_accumulator_message(&[&feed_2, &feed_3], &[&feed_3], false, false);
162162
let (_, merkle_price_updates2) = deserialize_accumulator_update_data(message2).unwrap();
163163

164164
let ProgramTestFixtures {

0 commit comments

Comments
 (0)