@@ -181,6 +181,7 @@ mod transaction_account_state_info;
181
181
pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
182
182
183
183
pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
184
+ pub const ACCUMULATOR_RING_SIZE: u32 = 10_000;
184
185
185
186
#[derive(Clone, Debug, PartialEq)]
186
187
pub struct RentDebit {
@@ -1519,13 +1520,17 @@ impl Bank {
1519
1520
}
1520
1521
bank.update_stake_history(None);
1521
1522
}
1522
- bank.update_accumulator();
1523
1523
bank.update_clock(None);
1524
1524
1525
1525
bank.update_rent();
1526
1526
bank.update_epoch_schedule();
1527
1527
bank.update_recent_blockhashes();
1528
1528
bank.fill_missing_sysvar_cache_entries();
1529
+
1530
+ // Update the accumulator last to make sure that the solana bank is in a
1531
+ // fully updated state before the accumulator is used.
1532
+ bank.update_accumulator();
1533
+
1529
1534
bank
1530
1535
}
1531
1536
@@ -1878,9 +1883,12 @@ impl Bank {
1878
1883
|_| {
1879
1884
new.update_slot_hashes();
1880
1885
new.update_stake_history(Some(parent_epoch));
1881
- new.update_accumulator();
1882
1886
new.update_clock(Some(parent_epoch));
1883
1887
new.update_fees();
1888
+
1889
+ // Update the accumulator last to make sure that all sysvars are in a
1890
+ // fully updated state before the accumulator sysvar updates.
1891
+ new.update_accumulator();
1884
1892
},
1885
1893
(),
1886
1894
"update_sysvars",
@@ -2596,6 +2604,8 @@ impl Bank {
2596
2604
let acc_state_magic = &mut b"PAS1".to_vec();
2597
2605
let accounts_data = &mut accounts.clone().collect::<Vec<_>>().try_to_vec()?;
2598
2606
data.append(acc_state_magic);
2607
+ data.append(&mut self.clock().slot.try_to_vec()?);
2608
+ data.append(&mut ACCUMULATOR_RING_SIZE.try_to_vec()?);
2599
2609
data.append(accounts_data);
2600
2610
let owner = solana_sdk::system_program::id();
2601
2611
let balance = self.get_minimum_balance_for_rent_exemption(data.len());
@@ -2666,7 +2676,7 @@ impl Bank {
2666
2676
sequence: sequence.sequence,
2667
2677
emitter_chain: 26,
2668
2678
emitter_address: ACCUMULATOR_EMITTER_ADDRESS,
2669
- payload: acc.serialize(ring_index ),
2679
+ payload: acc.serialize(self.clock().slot, ACCUMULATOR_RING_SIZE ),
2670
2680
},
2671
2681
};
2672
2682
@@ -15142,18 +15152,13 @@ pub(crate) mod tests {
15142
15152
true
15143
15153
);
15144
15154
15145
- // get the timestamp & slot for the message
15146
- let message_time = bank.clock().unix_timestamp;
15147
- let message_slot = bank.clock().slot;
15148
- let ring_index = (message_slot % 10_000) as u32;
15149
-
15150
- let mut sequence_tracker = get_acc_sequence_tracker(&bank);
15151
- let message_sequence = sequence_tracker.sequence;
15152
-
15153
- // Run accumulator again, the feature is now enabled so account data should contain a
15154
- // wormhole message.
15155
+ // The current sequence value will be used in the message when the bank advances, so we snapshot
15156
+ // it here before advancing the slot so we can assert the correct sequence is present in the message.
15157
+ let sequence_tracker_before_bank_advance = get_acc_sequence_tracker(&bank);
15155
15158
bank = new_from_parent(&Arc::new(bank));
15156
15159
15160
+ // get the timestamp & slot for the message
15161
+ let ring_index = (bank.clock().slot % ACCUMULATOR_RING_SIZE as u64) as u32;
15157
15162
let wormhole_message_account = get_wormhole_message_account(&bank, ring_index);
15158
15163
15159
15164
assert_ne!(wormhole_message_account.data().len(), 0);
@@ -15165,7 +15170,8 @@ pub(crate) mod tests {
15165
15170
let accumulator_elements = messages.clone().into_iter().sorted_unstable().dedup();
15166
15171
let expected_accumulator =
15167
15172
MerkleAccumulator::<Keccak160>::from_set(accumulator_elements).unwrap();
15168
- let expected_wormhole_message_payload = expected_accumulator.serialize(ring_index);
15173
+ let expected_wormhole_message_payload =
15174
+ expected_accumulator.serialize(bank.clock().slot, ACCUMULATOR_RING_SIZE);
15169
15175
assert_eq!(
15170
15176
wormhole_message.message.payload,
15171
15177
expected_wormhole_message_payload
@@ -15177,79 +15183,90 @@ pub(crate) mod tests {
15177
15183
consistency_level: 1,
15178
15184
vaa_time: 1u32,
15179
15185
vaa_signature_account: Pubkey::default().to_bytes(),
15180
- submission_time: message_time as u32,
15186
+ submission_time: bank.clock().unix_timestamp as u32,
15181
15187
nonce: 0,
15182
- sequence: message_sequence,
15188
+ sequence: sequence_tracker_before_bank_advance.sequence, // sequence is incremented after the message is processed
15183
15189
emitter_chain: 26,
15184
15190
emitter_address: ACCUMULATOR_EMITTER_ADDRESS,
15185
- payload: expected_accumulator.serialize(ring_index) ,
15191
+ payload: expected_wormhole_message_payload ,
15186
15192
},
15187
15193
};
15188
15194
15189
- let expected_wormhole_message_data = expected_wormhole_message.try_to_vec().unwrap();
15190
-
15191
15195
assert_eq!(
15192
15196
wormhole_message_account.data().to_vec(),
15193
- expected_wormhole_message_data
15197
+ expected_wormhole_message.try_to_vec().unwrap()
15194
15198
);
15195
15199
15196
15200
// verify hashes verify in accumulator
15197
15201
for msg in messages {
15198
15202
let msg_hash = Keccak160::hashv(&[[0u8].as_ref(), msg]);
15203
+ let msg_proof = expected_accumulator.prove(msg).unwrap();
15204
+
15199
15205
assert!(expected_accumulator.nodes.contains(&msg_hash));
15200
- let msg_proof = expected_accumulator.prove(msg);
15201
- assert!(msg_proof.is_some());
15202
- let msg_proof = msg_proof.unwrap();
15203
15206
assert!(expected_accumulator.check(msg_proof, msg));
15204
15207
}
15205
15208
15206
15209
// verify accumulator state account
15207
15210
let accumulator_state = get_accumulator_state(&bank, ring_index);
15208
15211
let acc_state_magic = &accumulator_state[..4];
15212
+ let acc_state_slot = LittleEndian::read_u64(&accumulator_state[4..12]);
15213
+ let acc_state_ring_size = LittleEndian::read_u32(&accumulator_state[12..16]);
15214
+
15209
15215
assert_eq!(acc_state_magic, b"PAS1");
15210
- let mut cursor = std::io::Cursor::new(&accumulator_state[4..]);
15216
+ assert_eq!(acc_state_slot, bank.clock().slot);
15217
+ assert_eq!(acc_state_ring_size, ACCUMULATOR_RING_SIZE);
15218
+
15219
+ let mut cursor = std::io::Cursor::new(&accumulator_state[16..]);
15211
15220
let num_elems = cursor.read_u32::<LittleEndian>().unwrap();
15212
15221
for _ in 0..(num_elems as usize) {
15213
15222
let element_len = cursor.read_u32::<LittleEndian>().unwrap();
15214
15223
let mut element_data = vec![0u8; element_len as usize];
15215
15224
cursor.read_exact(&mut element_data).unwrap();
15216
15225
15217
15226
let elem_hash = Keccak160::hashv(&[[0u8].as_ref(), element_data.as_slice()]);
15218
- assert!(expected_accumulator.nodes.contains(&elem_hash));
15219
- let elem_proof = expected_accumulator.prove(element_data.as_slice());
15220
- assert!(elem_proof.is_some());
15227
+ let elem_proof = expected_accumulator.prove(element_data.as_slice()).unwrap();
15221
15228
15222
- let elem_proof = elem_proof.unwrap( );
15229
+ assert!(expected_accumulator.nodes.contains(&elem_hash) );
15223
15230
assert!(expected_accumulator.check(elem_proof, element_data.as_slice()));
15224
15231
}
15225
15232
15226
15233
// verify sequence_tracker increments
15227
- sequence_tracker = get_acc_sequence_tracker(&bank);
15228
- assert_eq!(sequence_tracker.sequence, message_sequence + 1);
15234
+ assert_eq!(
15235
+ get_acc_sequence_tracker(&bank).sequence,
15236
+ sequence_tracker_before_bank_advance.sequence + 1
15237
+ );
15229
15238
15230
15239
// verify ring buffer cycles
15231
- let target_slot = bank.slot() + 9998;
15232
- // advance 9998 slots using warp_from_parent since doing large loops
15233
- // with new_from_parent takes a long time
15234
- let warped_bank = Bank::warp_from_parent(&Arc::new(bank), &Pubkey::default(), target_slot);
15240
+ let ring_index_before_buffer_cycle =
15241
+ (bank.clock().slot % ACCUMULATOR_RING_SIZE as u64) as u32;
15242
+ let target_slot = bank.slot() + ACCUMULATOR_RING_SIZE as u64;
15243
+ // advance ACCUMULATOR_RING_SIZE slots using warp_from_parent since doing large loops
15244
+ // with new_from_parent takes a long time. warp_from_parent results in a bank that is frozen.
15245
+ bank = Bank::warp_from_parent(&Arc::new(bank), &Pubkey::default(), target_slot);
15246
+
15247
+ // accumulator messages should still be the same before looping around
15248
+ let ring_index_after_buffer_cycle =
15249
+ (bank.clock().slot % ACCUMULATOR_RING_SIZE as u64) as u32;
15250
+ assert_eq!(
15251
+ ring_index_before_buffer_cycle,
15252
+ ring_index_after_buffer_cycle
15253
+ );
15235
15254
15236
- // advance one more slot
15237
- bank = new_from_parent(&Arc::new(warped_bank));
15255
+ let accumulator_state_after_skip =
15256
+ get_accumulator_state(&bank, ring_index_after_buffer_cycle);
15257
+ assert_eq!(
15258
+ &accumulator_state[16..],
15259
+ &accumulator_state_after_skip[16..]
15260
+ );
15238
15261
15239
- // accumulator state should still be the same before looping around
15240
- let accumulator_state_after_skip = get_accumulator_state(&bank, ring_index);
15241
- assert_eq!(&accumulator_state[4..], &accumulator_state_after_skip[4..]);
15262
+ // insert new message to make sure the update is written in the right position
15263
+ // in the ring buffer and overwrites the existing message
15242
15264
15243
- let message_time_1 = bank.clock().unix_timestamp;
15244
- let message_slot_1 = bank.clock().slot;
15245
- let ring_index_1 = (message_slot_1 % 10_000) as u32;
15246
- assert_eq!(ring_index, ring_index_1);
15265
+ // advance the bank to unfreeze it (to be able to store accounts). see the comment on warp_from_parent above.
15266
+ bank = new_from_parent(&Arc::new(bank));
15247
15267
15248
- sequence_tracker = get_acc_sequence_tracker(&bank);
15249
- let message_sequence_1 = sequence_tracker.sequence;
15268
+ let wh_sequence_before_acc_update = get_acc_sequence_tracker(&bank).sequence;
15250
15269
15251
- // insert new message to verify ring buffer cycles and overwrites old message
15252
- // at ring index
15253
15270
let message_0 = vec![1u8; 127];
15254
15271
let message_1 = vec![2u8; 127];
15255
15272
let message_2 = vec![3u8; 254];
@@ -15265,7 +15282,8 @@ pub(crate) mod tests {
15265
15282
// Run accumulator, update clock & other sysvars etc
15266
15283
bank = new_from_parent(&Arc::new(bank));
15267
15284
15268
- let updated_wormhole_message_account = get_wormhole_message_account(&bank, ring_index_1);
15285
+ let ring_index = (bank.clock().slot % ACCUMULATOR_RING_SIZE as u64) as u32;
15286
+ let updated_wormhole_message_account = get_wormhole_message_account(&bank, ring_index);
15269
15287
15270
15288
let updated_wormhole_message =
15271
15289
PostedMessageUnreliableData::deserialize(&mut updated_wormhole_message_account.data())
@@ -15283,10 +15301,9 @@ pub(crate) mod tests {
15283
15301
15284
15302
let expected_accumulator =
15285
15303
MerkleAccumulator::<Keccak160>::from_set(updated_accumulator_elements).unwrap();
15286
- let expected_wormhole_message_payload = expected_accumulator.serialize(ring_index);
15287
15304
assert_eq!(
15288
15305
updated_wormhole_message.message.payload,
15289
- expected_wormhole_message_payload
15306
+ expected_accumulator.serialize(bank.clock().slot, ACCUMULATOR_RING_SIZE)
15290
15307
);
15291
15308
15292
15309
let expected_wormhole_message = PostedMessageUnreliableData {
@@ -15295,20 +15312,18 @@ pub(crate) mod tests {
15295
15312
consistency_level: 1,
15296
15313
vaa_time: 1u32,
15297
15314
vaa_signature_account: Pubkey::default().to_bytes(),
15298
- submission_time: message_time_1 as u32,
15315
+ submission_time: bank.clock().unix_timestamp as u32,
15299
15316
nonce: 0,
15300
- sequence: message_sequence_1 ,
15317
+ sequence: wh_sequence_before_acc_update ,
15301
15318
emitter_chain: 26,
15302
15319
emitter_address: ACCUMULATOR_EMITTER_ADDRESS,
15303
- payload: expected_accumulator.serialize(ring_index_1 ),
15320
+ payload: expected_accumulator.serialize(bank.clock().slot, ACCUMULATOR_RING_SIZE ),
15304
15321
},
15305
15322
};
15306
15323
15307
- let expected_wormhole_message_data = expected_wormhole_message.try_to_vec().unwrap();
15308
-
15309
15324
assert_eq!(
15310
15325
updated_wormhole_message_account.data(),
15311
- expected_wormhole_message_data
15326
+ expected_wormhole_message.try_to_vec().unwrap()
15312
15327
);
15313
15328
15314
15329
// TODO: Should be done as additional tests.
0 commit comments