-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hybrid pre load slots and accounts (#384)
* chore: create structures for hybrid pre-load * chore: add queries to load history into memory * lint * lint * chore: load slot and account onto memory * chore: make queries leaner * lint
- Loading branch information
1 parent
0b79850
commit 97fbfd8
Showing
7 changed files
with
292 additions
and
38 deletions.
There are no files selected for viewing
32 changes: 32 additions & 0 deletions
32
.sqlx/query-3aa3f853d45b3fadcc9eb1a80cc45233482a14c82ac8a6630922bdcefae3cfd8.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
4 changes: 2 additions & 2 deletions
4
...85c0333dc2de6412fe5cff8594e5dc4b183f.json → ...6c24f91dccea326df850e48b0f53d3c6437f.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
38 changes: 38 additions & 0 deletions
38
.sqlx/query-edae8a7534d957fb6f727f9222299b258a4c96059ab55cd6af5477502acd2265.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
use std::collections::HashMap; | ||
use std::sync::Arc; | ||
|
||
use sqlx::types::BigDecimal; | ||
use sqlx::FromRow; | ||
use sqlx::Pool; | ||
use sqlx::Postgres; | ||
|
||
use crate::eth::primitives::Account; | ||
use crate::eth::primitives::Address; | ||
use crate::eth::primitives::Bytes; | ||
use crate::eth::primitives::Nonce; | ||
use crate::eth::primitives::Slot; | ||
use crate::eth::primitives::SlotIndex; | ||
use crate::eth::primitives::SlotValue; | ||
use crate::eth::primitives::StoragePointInTime; | ||
use crate::eth::primitives::Wei; | ||
|
||
#[derive(Debug)] | ||
struct SlotInfo { | ||
value: SlotValue, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct AccountInfo { | ||
balance: Wei, | ||
nonce: Nonce, | ||
bytecode: Option<Bytes>, | ||
slots: HashMap<SlotIndex, SlotInfo>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct HybridHistory { | ||
pub hybrid_accounts_slots: HashMap<Address, AccountInfo>, | ||
pool: Arc<Pool<Postgres>>, | ||
} | ||
|
||
#[derive(FromRow)] | ||
struct AccountRow { | ||
address: Vec<u8>, | ||
nonce: Option<BigDecimal>, | ||
balance: Option<BigDecimal>, | ||
bytecode: Option<Vec<u8>>, | ||
} | ||
|
||
#[derive(FromRow)] | ||
struct SlotRow { | ||
account_address: Vec<u8>, | ||
slot_index: SlotIndex, | ||
value: Option<Vec<u8>>, | ||
} | ||
|
||
impl HybridHistory { | ||
pub async fn new(pool: Arc<Pool<Postgres>>) -> Result<Self, sqlx::Error> { | ||
// Initialize the structure | ||
let mut history = HybridHistory { | ||
hybrid_accounts_slots: HashMap::new(), | ||
pool, | ||
}; | ||
|
||
history.load_latest_data().await?; | ||
|
||
Ok(history) | ||
} | ||
|
||
//XXX TODO use a fixed block_number during load, in order to avoid sync problem | ||
// e.g other instance moving forward and this query getting incongruous data | ||
async fn load_latest_data(&mut self) -> Result<(), sqlx::Error> { | ||
let account_rows = sqlx::query_as!( | ||
AccountRow, | ||
" | ||
SELECT DISTINCT ON (address) | ||
address, | ||
nonce, | ||
balance, | ||
bytecode | ||
FROM | ||
neo_accounts | ||
ORDER BY | ||
address, | ||
block_number DESC | ||
" | ||
) | ||
.fetch_all(&*self.pool) | ||
.await?; | ||
|
||
let mut accounts: HashMap<Address, AccountInfo> = HashMap::new(); | ||
|
||
for account_row in account_rows { | ||
let addr: Address = account_row.address.try_into().unwrap_or_default(); //XXX add alert | ||
accounts.insert( | ||
addr, | ||
AccountInfo { | ||
balance: account_row.balance.map(|b| b.try_into().unwrap_or_default()).unwrap_or_default(), | ||
nonce: account_row.nonce.map(|n| n.try_into().unwrap_or_default()).unwrap_or_default(), | ||
bytecode: account_row.bytecode.map(Bytes::from), | ||
slots: HashMap::new(), | ||
}, | ||
); | ||
} | ||
|
||
// Load slots | ||
let slot_rows = sqlx::query_as!( | ||
SlotRow, | ||
" | ||
SELECT DISTINCT ON (account_address, slot_index) | ||
account_address, | ||
slot_index, | ||
value | ||
FROM | ||
neo_account_slots | ||
ORDER BY | ||
account_address, | ||
slot_index, | ||
block_number DESC | ||
" | ||
) | ||
.fetch_all(&*self.pool) | ||
.await?; | ||
|
||
for slot_row in slot_rows { | ||
let addr = &slot_row.account_address.try_into().unwrap_or_default(); //XXX add alert | ||
if let Some(account_info) = accounts.get_mut(addr) { | ||
account_info.slots.insert( | ||
slot_row.slot_index, | ||
SlotInfo { | ||
value: slot_row.value.unwrap_or_default().into(), | ||
}, | ||
); | ||
} | ||
} | ||
|
||
self.hybrid_accounts_slots = accounts; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub async fn get_slot_at_point(&self, address: &Address, slot_index: &SlotIndex, point_in_time: &StoragePointInTime) -> Option<Slot> { | ||
match point_in_time { | ||
StoragePointInTime::Present => self.hybrid_accounts_slots.get(address).map(|account_info| { | ||
let value = account_info.slots.get(slot_index).map(|slot_info| slot_info.value.clone()).unwrap_or_default(); | ||
Slot { | ||
index: slot_index.clone(), | ||
value, | ||
} | ||
}), | ||
StoragePointInTime::Past(_number) => { | ||
None //XXX TODO use postgres query | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl AccountInfo { | ||
pub async fn to_account(&self, point_in_time: &StoragePointInTime, address: &Address) -> Account { | ||
match point_in_time { | ||
StoragePointInTime::Present => Account { | ||
address: address.clone(), | ||
nonce: self.nonce.clone(), | ||
balance: self.balance.clone(), | ||
bytecode: self.bytecode.clone(), | ||
}, | ||
StoragePointInTime::Past(_number) => Account::default(), | ||
} | ||
} | ||
} |
Oops, something went wrong.