4
4
byteorder:: LittleEndian ,
5
5
itertools:: Itertools ,
6
6
log:: * ,
7
+ pyth_oracle:: validator:: AggregationError ,
7
8
solana_sdk:: {
8
9
account:: { AccountSharedData , ReadableAccount } ,
9
- clock:: Slot ,
10
10
feature_set,
11
11
hash:: hashv,
12
12
pubkey:: Pubkey ,
19
19
20
20
pub const ACCUMULATOR_RING_SIZE : u32 = 10_000 ;
21
21
22
- #[ derive( Debug , thiserror:: Error ) ]
23
- pub enum AccumulatorUpdateErrorV2 {
24
- #[ error( "no oracle pubkey" ) ]
25
- NoOraclePubkey ,
26
- #[ error( "get_program_accounts failed to return accounts: {0}" ) ]
27
- GetProgramAccounts ( #[ from] ScanError ) ,
28
- }
29
-
30
22
lazy_static ! {
31
23
static ref ORACLE_PUBKEY : Option <Pubkey > = match env:: var( "PYTH_ORACLE_PUBKEY" ) {
32
24
Ok ( value) => Some (
@@ -45,8 +37,8 @@ lazy_static! {
45
37
/// not include any `Custom` style variant we can leverage, so we introduce our own.
46
38
#[ derive( Debug , thiserror:: Error ) ]
47
39
pub enum AccumulatorUpdateErrorV1 {
48
- #[ error( "get_program_accounts failed to return accounts" ) ]
49
- GetProgramAccounts ,
40
+ #[ error( "get_program_accounts failed to return accounts: {0} " ) ]
41
+ GetProgramAccounts ( # [ from ] ScanError ) ,
50
42
51
43
#[ error( "failed to serialize sequence account" ) ]
52
44
FailedSequenceSerialization ,
@@ -59,6 +51,9 @@ pub enum AccumulatorUpdateErrorV1 {
59
51
60
52
#[ error( "could not parse Pubkey from environment" ) ]
61
53
InvalidEnvPubkey ( #[ from] solana_sdk:: pubkey:: ParsePubkeyError ) ,
54
+
55
+ #[ error( "no oracle pubkey" ) ]
56
+ NoOraclePubkey ,
62
57
}
63
58
64
59
/// Updates the Accumulator Sysvar at the start of a new slot. See `update_clock` to see a similar
@@ -82,31 +77,9 @@ pub fn update_accumulator(bank: &Bank) {
82
77
83
78
info ! ( "Accumulator: Updating accumulator. Slot: {}" , bank. slot( ) ) ;
84
79
85
- lazy_static ! {
86
- static ref ACCUMULATOR_V2_SLOT : Option <Slot > =
87
- match std:: env:: var( "PYTH_ACCUMULATOR_V2_FROM_SLOT" ) {
88
- Ok ( value) => Some (
89
- value
90
- . parse( )
91
- . expect( "invalid value of PYTH_ACCUMULATOR_V2_FROM_SLOT env var" )
92
- ) ,
93
- Err ( std:: env:: VarError :: NotPresent ) => None ,
94
- Err ( std:: env:: VarError :: NotUnicode ( err) ) => {
95
- panic!( "invalid value of PYTH_ACCUMULATOR_V2_FROM_SLOT env var: {err:?}" ) ;
96
- }
97
- } ;
80
+ if let Err ( e) = update_v2 ( bank) {
81
+ error ! ( "Error updating accumulator v2: {:?}" , e) ;
98
82
}
99
-
100
- // TODO: No longer a slot or feature flag, based on price account flag.
101
- if ( * ACCUMULATOR_V2_SLOT ) . map_or ( false , |v2_slot| bank. slot ( ) >= v2_slot) {
102
- if let Err ( e) = update_v2 ( bank) {
103
- error ! ( "Error updating accumulator: {:?}" , e) ;
104
- }
105
- } else {
106
- if let Err ( e) = update_v1 ( bank) {
107
- error ! ( "Error updating accumulator: {:?}" , e) ;
108
- }
109
- } ;
110
83
}
111
84
112
85
/// Read the pubkey from the environment variable `var` or return `default`
@@ -158,7 +131,11 @@ pub fn get_accumulator_keys() -> Vec<(
158
131
accumulator_pubkeys
159
132
}
160
133
161
- pub fn update_v1 ( bank : & Bank ) -> std:: result:: Result < ( ) , AccumulatorUpdateErrorV1 > {
134
+ pub fn update_v1 (
135
+ bank : & Bank ,
136
+ v2_messages : Vec < & [ u8 ] > ,
137
+ use_message_buffers : bool ,
138
+ ) -> std:: result:: Result < ( ) , AccumulatorUpdateErrorV1 > {
162
139
use {
163
140
byteorder:: ReadBytesExt ,
164
141
pythnet_sdk:: {
@@ -179,57 +156,66 @@ pub fn update_v1(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
179
156
Pubkey :: new_from_array ( MESSAGE_BUFFER_PID ) ,
180
157
) ?;
181
158
182
- let accounts = bank
183
- . get_program_accounts ( & message_buffer_pid, & ScanConfig :: new ( true ) )
184
- . map_err ( |_| AccumulatorUpdateErrorV1 :: GetProgramAccounts ) ?;
185
-
186
- let preimage = b"account:MessageBuffer" ;
187
- let mut expected_sighash = [ 0u8 ; 8 ] ;
188
- expected_sighash. copy_from_slice ( & hashv ( & [ preimage] ) . to_bytes ( ) [ ..8 ] ) ;
189
-
190
- // Filter accounts that don't match the Anchor sighash.
191
- let accounts = accounts. iter ( ) . filter ( |( _, account) | {
192
- // Remove accounts that do not start with the expected Anchor sighash.
193
- let mut sighash = [ 0u8 ; 8 ] ;
194
- sighash. copy_from_slice ( & account. data ( ) [ ..8 ] ) ;
195
- sighash == expected_sighash
196
- } ) ;
197
-
198
- // This code, using the offsets in each Account, extracts the various data versions from
199
- // the account. We deduplicate this result because the accumulator expects a set.
200
- let accounts = accounts
201
- . map ( |( _, account) | {
202
- let data = account. data ( ) ;
203
- let mut cursor = std:: io:: Cursor :: new ( & data) ;
204
- let _sighash = cursor. read_u64 :: < LittleEndian > ( ) ?;
205
- let _bump = cursor. read_u8 ( ) ?;
206
- let _version = cursor. read_u8 ( ) ?;
207
- let header_len = cursor. read_u16 :: < LittleEndian > ( ) ?;
208
- let mut header_begin = header_len;
209
- let mut inputs = Vec :: new ( ) ;
210
- let mut cur_end_offsets_idx: usize = 0 ;
211
- while let Some ( end) = cursor. read_u16 :: < LittleEndian > ( ) . ok ( ) {
212
- if end == 0 || cur_end_offsets_idx == ( u8:: MAX as usize ) {
213
- break ;
159
+ let message_buffer_accounts;
160
+ let v1_messages = if use_message_buffers {
161
+ message_buffer_accounts = bank
162
+ . get_program_accounts ( & message_buffer_pid, & ScanConfig :: new ( true ) )
163
+ . map_err ( AccumulatorUpdateErrorV1 :: GetProgramAccounts ) ?;
164
+
165
+ let preimage = b"account:MessageBuffer" ;
166
+ let mut expected_sighash = [ 0u8 ; 8 ] ;
167
+ expected_sighash. copy_from_slice ( & hashv ( & [ preimage] ) . to_bytes ( ) [ ..8 ] ) ;
168
+
169
+ // Filter accounts that don't match the Anchor sighash.
170
+ let message_buffer_accounts = message_buffer_accounts. iter ( ) . filter ( |( _, account) | {
171
+ // Remove accounts that do not start with the expected Anchor sighash.
172
+ let mut sighash = [ 0u8 ; 8 ] ;
173
+ sighash. copy_from_slice ( & account. data ( ) [ ..8 ] ) ;
174
+ sighash == expected_sighash
175
+ } ) ;
176
+
177
+ // This code, using the offsets in each Account, extracts the various data versions from
178
+ // the account. We deduplicate this result because the accumulator expects a set.
179
+ message_buffer_accounts
180
+ . map ( |( _, account) | {
181
+ let data = account. data ( ) ;
182
+ let mut cursor = std:: io:: Cursor :: new ( & data) ;
183
+ let _sighash = cursor. read_u64 :: < LittleEndian > ( ) ?;
184
+ let _bump = cursor. read_u8 ( ) ?;
185
+ let _version = cursor. read_u8 ( ) ?;
186
+ let header_len = cursor. read_u16 :: < LittleEndian > ( ) ?;
187
+ let mut header_begin = header_len;
188
+ let mut inputs = Vec :: new ( ) ;
189
+ let mut cur_end_offsets_idx: usize = 0 ;
190
+ while let Some ( end) = cursor. read_u16 :: < LittleEndian > ( ) . ok ( ) {
191
+ if end == 0 || cur_end_offsets_idx == ( u8:: MAX as usize ) {
192
+ break ;
193
+ }
194
+
195
+ let end_offset = header_len + end;
196
+ if end_offset as usize > data. len ( ) {
197
+ break ;
198
+ }
199
+ let accumulator_input_data = & data[ header_begin as usize ..end_offset as usize ] ;
200
+ inputs. push ( accumulator_input_data) ;
201
+ header_begin = end_offset;
202
+ cur_end_offsets_idx += 1 ;
214
203
}
215
204
216
- let end_offset = header_len + end;
217
- if end_offset as usize > data. len ( ) {
218
- break ;
219
- }
220
- let accumulator_input_data = & data[ header_begin as usize ..end_offset as usize ] ;
221
- inputs. push ( accumulator_input_data) ;
222
- header_begin = end_offset;
223
- cur_end_offsets_idx += 1 ;
224
- }
205
+ Ok ( inputs)
206
+ } )
207
+ . collect :: < std:: result:: Result < Vec < _ > , std:: io:: Error > > ( ) ?
208
+ . into_iter ( )
209
+ . flatten ( )
210
+ . sorted_unstable ( )
211
+ . dedup ( )
212
+ . collect ( )
213
+ } else {
214
+ Vec :: new ( )
215
+ } ;
225
216
226
- Ok ( inputs)
227
- } )
228
- . collect :: < std:: result:: Result < Vec < _ > , std:: io:: Error > > ( ) ?
229
- . into_iter ( )
230
- . flatten ( )
231
- . sorted_unstable ( )
232
- . dedup ( ) ;
217
+ let mut messages = v1_messages;
218
+ messages. extend ( v2_messages) ;
233
219
234
220
// We now generate a Proof PDA (Owned by the System Program) to store the resulting Proof
235
221
// Set. The derivation includes the ring buffer index to simulate a ring buffer in order
@@ -242,8 +228,7 @@ pub fn update_v1(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
242
228
let accumulator_data = {
243
229
let mut data = vec ! [ ] ;
244
230
let acc_state_magic = & mut b"PAS1" . to_vec ( ) ;
245
- let accounts_data =
246
- & mut borsh:: BorshSerialize :: try_to_vec ( & accounts. clone ( ) . collect :: < Vec < _ > > ( ) ) ?;
231
+ let accounts_data = & mut borsh:: BorshSerialize :: try_to_vec ( & messages) ?;
247
232
data. append ( acc_state_magic) ;
248
233
data. append ( & mut borsh:: BorshSerialize :: try_to_vec ( & bank. slot ( ) ) ?) ;
249
234
data. append ( & mut borsh:: BorshSerialize :: try_to_vec (
@@ -260,7 +245,7 @@ pub fn update_v1(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
260
245
// Generate a Message owned by Wormhole to be sent cross-chain. This short-circuits the
261
246
// Wormhole message generation code that would normally be called, but the Guardian
262
247
// set filters our messages so this does not pose a security risk.
263
- if let Some ( accumulator) = MerkleAccumulator :: < Keccak160 > :: from_set ( accounts ) {
248
+ if let Some ( accumulator) = MerkleAccumulator :: < Keccak160 > :: from_set ( messages . into_iter ( ) ) {
264
249
post_accumulator_attestation ( bank, accumulator, ring_index) ?;
265
250
}
266
251
@@ -390,14 +375,16 @@ fn post_accumulator_attestation(
390
375
Ok ( ( ) )
391
376
}
392
377
393
- pub fn update_v2 ( bank : & Bank ) -> std:: result:: Result < ( ) , AccumulatorUpdateErrorV2 > {
378
+ pub fn update_v2 ( bank : & Bank ) -> std:: result:: Result < ( ) , AccumulatorUpdateErrorV1 > {
394
379
// 1. Find Oracle
395
- let oracle_pubkey = ORACLE_PUBKEY . ok_or ( AccumulatorUpdateErrorV2 :: NoOraclePubkey ) ?;
380
+ let oracle_pubkey = ORACLE_PUBKEY . ok_or ( AccumulatorUpdateErrorV1 :: NoOraclePubkey ) ?;
396
381
397
382
// 2. Find Oracle Accounts
398
383
let accounts = bank
399
384
. get_program_accounts ( & oracle_pubkey, & ScanConfig :: new ( true ) )
400
- . map_err ( AccumulatorUpdateErrorV2 :: GetProgramAccounts ) ?;
385
+ . map_err ( AccumulatorUpdateErrorV1 :: GetProgramAccounts ) ?;
386
+
387
+ let mut any_legacy_mode = false ;
401
388
402
389
// 3. Call Aggregation on Price Accounts.
403
390
for ( pubkey, mut account) in accounts {
@@ -409,16 +396,25 @@ pub fn update_v2(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
409
396
bank. clock ( ) . unix_timestamp ,
410
397
& mut price_account_data,
411
398
) {
412
- Ok ( success) => {
413
- if success {
414
- account. set_data ( price_account_data) ;
415
- bank. store_account_and_update_capitalization ( & pubkey, & account) ;
416
- }
399
+ Ok ( ( ) ) => {
400
+ account. set_data ( price_account_data) ;
401
+ bank. store_account_and_update_capitalization ( & pubkey, & account) ;
417
402
}
418
- Err ( err) => trace ! ( "Aggregation: failed to update_price_cumulative, {:?}" , err) ,
403
+ Err ( err) => match err {
404
+ AggregationError :: NotPriceFeedAccount => { }
405
+ AggregationError :: LegacyAggregationMode => {
406
+ any_legacy_mode = true ;
407
+ }
408
+ AggregationError :: NotTradingStatus => {
409
+ trace ! ( "Aggregation: failed to update_price_cumulative, {:?}" , err) ;
410
+ }
411
+ } ,
419
412
}
420
413
}
421
414
415
+ // TODO: make new messages
416
+ update_v1 ( bank, Vec :: new ( ) , any_legacy_mode) ?;
417
+
422
418
// 5. Merkleize the results.
423
419
424
420
// 6. Create Wormhole Message Account
0 commit comments