Skip to content

Commit dfc2df7

Browse files
authored
[hermes] Use raw_message for future-compatibility (#913)
1 parent 742c37e commit dfc2df7

File tree

6 files changed

+62
-88
lines changed

6 files changed

+62
-88
lines changed

hermes/src/network/pythnet.rs

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ use {
2020
Result,
2121
},
2222
borsh::BorshDeserialize,
23-
byteorder::BE,
2423
futures::stream::StreamExt,
25-
pythnet_sdk::messages::Message,
2624
solana_account_decoder::UiAccountEncoding,
2725
solana_client::{
2826
nonblocking::{
@@ -157,44 +155,9 @@ pub async fn run(store: Arc<Store>, pythnet_ws_endpoint: String) -> Result<!> {
157155
}
158156
};
159157

160-
// The validators writes the accumulator messages using Borsh with
161-
// the following struct. We cannot directly have messages as Vec<Messages>
162-
// because they are serialized using big-endian byte order and Borsh
163-
// uses little-endian byte order.
164-
#[derive(BorshDeserialize)]
165-
struct RawAccumulatorMessages {
166-
pub magic: [u8; 4],
167-
pub slot: u64,
168-
pub ring_size: u32,
169-
pub raw_messages: Vec<Vec<u8>>,
170-
}
171-
172-
let accumulator_messages = RawAccumulatorMessages::try_from_slice(&account.data);
158+
let accumulator_messages = AccumulatorMessages::try_from_slice(&account.data);
173159
match accumulator_messages {
174160
Ok(accumulator_messages) => {
175-
let messages = accumulator_messages
176-
.raw_messages
177-
.iter()
178-
.map(|message| {
179-
pythnet_sdk::wire::from_slice::<BE, Message>(message.as_slice())
180-
})
181-
.collect::<Result<Vec<Message>, _>>();
182-
183-
let messages = match messages {
184-
Ok(messages) => messages,
185-
Err(err) => {
186-
log::error!("Failed to parse messages: {:?}", err);
187-
continue;
188-
}
189-
};
190-
191-
let accumulator_messages = AccumulatorMessages {
192-
magic: accumulator_messages.magic,
193-
slot: accumulator_messages.slot,
194-
ring_size: accumulator_messages.ring_size,
195-
messages,
196-
};
197-
198161
let (candidate, _) = Pubkey::find_program_address(
199162
&[
200163
b"AccumulatorState",

hermes/src/store.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,19 @@ use {
3333
anyhow,
3434
Result,
3535
},
36+
byteorder::BigEndian,
3637
pyth_sdk::PriceIdentifier,
3738
pythnet_sdk::{
3839
messages::{
3940
Message,
4041
MessageType,
4142
},
42-
wire::v1::{
43-
WormholeMessage,
44-
WormholePayload,
43+
wire::{
44+
from_slice,
45+
v1::{
46+
WormholeMessage,
47+
WormholePayload,
48+
},
4549
},
4650
},
4751
std::{
@@ -199,12 +203,14 @@ impl Store {
199203

200204
let message_states = completed_state
201205
.accumulator_messages
202-
.messages
203-
.iter()
206+
.raw_messages
207+
.into_iter()
204208
.enumerate()
205-
.map(|(idx, message)| {
209+
.map(|(idx, raw_message)| {
206210
Ok(MessageState::new(
207-
*message,
211+
from_slice::<BigEndian, _>(raw_message.as_ref())
212+
.map_err(|e| anyhow!("Failed to deserialize message: {:?}", e))?,
213+
raw_message,
208214
ProofSet {
209215
wormhole_merkle_proof: wormhole_merkle_message_states_proofs
210216
.get(idx)

hermes/src/store/proof/wormhole_merkle.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,26 +76,20 @@ pub fn construct_message_states_proofs(
7676
let accumulator_messages = &completed_accumulator_state.accumulator_messages;
7777
let wormhole_merkle_state = &completed_accumulator_state.wormhole_merkle_state;
7878

79-
let raw_messages = accumulator_messages
80-
.messages
81-
.iter()
82-
.map(|m| {
83-
to_vec::<_, byteorder::BE>(m).map_err(|e| anyhow!("Failed to serialize message: {}", e))
84-
})
85-
.collect::<Result<Vec<Vec<u8>>>>()?;
86-
8779
// Check whether the state is valid
88-
let merkle_acc =
89-
match MerkleTree::<Keccak160>::from_set(raw_messages.iter().map(|m| m.as_ref())) {
90-
Some(merkle_acc) => merkle_acc,
91-
None => return Ok(vec![]), // It only happens when the message set is empty
92-
};
80+
let merkle_acc = match MerkleTree::<Keccak160>::from_set(
81+
accumulator_messages.raw_messages.iter().map(|m| m.as_ref()),
82+
) {
83+
Some(merkle_acc) => merkle_acc,
84+
None => return Ok(vec![]), // It only happens when the message set is empty
85+
};
9386

9487
if merkle_acc.root.as_bytes() != wormhole_merkle_state.root.root {
9588
return Err(anyhow!("Invalid merkle root"));
9689
}
9790

98-
raw_messages
91+
accumulator_messages
92+
.raw_messages
9993
.iter()
10094
.map(|m| {
10195
Ok(WormholeMerkleMessageProof {

hermes/src/store/storage.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use {
44
types::{
55
AccumulatorMessages,
66
ProofSet,
7+
RawMessage,
78
RequestTime,
89
Slot,
910
UnixTimestamp,
@@ -71,6 +72,7 @@ pub struct MessageStateTime {
7172
pub struct MessageState {
7273
pub slot: Slot,
7374
pub message: Message,
75+
pub raw_message: RawMessage,
7476
pub proof_set: ProofSet,
7577
pub received_at: UnixTimestamp,
7678
}
@@ -92,13 +94,15 @@ impl MessageState {
9294

9395
pub fn new(
9496
message: Message,
97+
raw_message: RawMessage,
9598
proof_set: ProofSet,
9699
slot: Slot,
97100
received_at: UnixTimestamp,
98101
) -> Self {
99102
Self {
100103
slot,
101104
message,
105+
raw_message,
102106
proof_set,
103107
received_at,
104108
}
@@ -151,20 +155,20 @@ mod test {
151155
wormhole_merkle_state: None,
152156
};
153157

154-
assert!(CompletedAccumulatorState::try_from(accumulator_state.clone()).is_err());
158+
assert!(CompletedAccumulatorState::try_from(accumulator_state).is_err());
155159

156160
let accumulator_state = AccumulatorState {
157161
slot: 1,
158162
accumulator_messages: Some(AccumulatorMessages {
159-
slot: 1,
160-
magic: [0; 4],
161-
ring_size: 10,
162-
messages: vec![],
163+
slot: 1,
164+
magic: [0; 4],
165+
ring_size: 10,
166+
raw_messages: vec![],
163167
}),
164168
wormhole_merkle_state: None,
165169
};
166170

167-
assert!(CompletedAccumulatorState::try_from(accumulator_state.clone()).is_err());
171+
assert!(CompletedAccumulatorState::try_from(accumulator_state).is_err());
168172

169173
let accumulator_state = AccumulatorState {
170174
slot: 1,
@@ -179,15 +183,15 @@ mod test {
179183
}),
180184
};
181185

182-
assert!(CompletedAccumulatorState::try_from(accumulator_state.clone()).is_err());
186+
assert!(CompletedAccumulatorState::try_from(accumulator_state).is_err());
183187

184188
let accumulator_state = AccumulatorState {
185189
slot: 1,
186190
accumulator_messages: Some(AccumulatorMessages {
187-
slot: 1,
188-
magic: [0; 4],
189-
ring_size: 10,
190-
messages: vec![],
191+
slot: 1,
192+
magic: [0; 4],
193+
ring_size: 10,
194+
raw_messages: vec![],
191195
}),
192196
wormhole_merkle_state: Some(WormholeMerkleState {
193197
vaa: vec![],
@@ -200,14 +204,14 @@ mod test {
200204
};
201205

202206
assert_eq!(
203-
CompletedAccumulatorState::try_from(accumulator_state.clone()).unwrap(),
207+
CompletedAccumulatorState::try_from(accumulator_state).unwrap(),
204208
CompletedAccumulatorState {
205209
slot: 1,
206210
accumulator_messages: AccumulatorMessages {
207-
slot: 1,
208-
magic: [0; 4],
209-
ring_size: 10,
210-
messages: vec![],
211+
slot: 1,
212+
magic: [0; 4],
213+
ring_size: 10,
214+
raw_messages: vec![],
211215
},
212216
wormhole_merkle_state: WormholeMerkleState {
213217
vaa: vec![],

hermes/src/store/storage/local_storage.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ mod test {
211211
) -> MessageState {
212212
MessageState {
213213
slot,
214+
raw_message: vec![],
214215
message: Message::PriceFeedMessage(PriceFeedMessage {
215216
feed_id,
216217
publish_time,
@@ -574,10 +575,10 @@ mod test {
574575
// Change the state to have accumulator messages
575576
// We mutate the existing state because the normal flow is like this.
576577
accumulator_state.accumulator_messages = Some(AccumulatorMessages {
577-
magic: [0; 4],
578-
slot: 10,
579-
ring_size: 3,
580-
messages: vec![],
578+
magic: [0; 4],
579+
slot: 10,
580+
ring_size: 3,
581+
raw_messages: vec![],
581582
});
582583

583584
// Store the accumulator state again.

hermes/src/store/types.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
use {
22
super::proof::wormhole_merkle::WormholeMerkleMessageProof,
3-
pythnet_sdk::messages::{
4-
Message,
5-
PriceFeedMessage,
6-
},
3+
borsh::BorshDeserialize,
4+
pythnet_sdk::messages::PriceFeedMessage,
75
};
86

97
#[derive(Clone, PartialEq, Debug)]
@@ -20,12 +18,20 @@ pub enum RequestTime {
2018
FirstAfter(UnixTimestamp),
2119
}
2220

23-
#[derive(Clone, PartialEq, Debug)]
21+
pub type RawMessage = Vec<u8>;
22+
23+
/// Accumulator messages coming from Pythnet validators.
24+
///
25+
/// The validators writes the accumulator messages using Borsh with
26+
/// the following struct. We cannot directly have messages as Vec<Messages>
27+
/// because they are serialized using big-endian byte order and Borsh
28+
/// uses little-endian byte order.
29+
#[derive(Clone, PartialEq, Debug, BorshDeserialize)]
2430
pub struct AccumulatorMessages {
25-
pub magic: [u8; 4],
26-
pub slot: Slot,
27-
pub ring_size: u32,
28-
pub messages: Vec<Message>,
31+
pub magic: [u8; 4],
32+
pub slot: u64,
33+
pub ring_size: u32,
34+
pub raw_messages: Vec<RawMessage>,
2935
}
3036

3137
impl AccumulatorMessages {

0 commit comments

Comments
 (0)