Skip to content

Commit cbcf170

Browse files
Dentosalxgreenx
andauthored
Store old blocks and txs after regenesis (#1811)
Work towards #1790 This PR adds `OldFuelBlocks`, `OldFuelBlockConsensus` and `OldTransactions` tables to the off-chain database. If the requested block is lower than genesis block height, we go to `off_chain::OldFuelBlocks` , otherwise to `on_chain::FuelBlocks`. For transactions, we try `on_chain::Transactions` and fallback to `off_chain::OldTransactions`. Also exposes `fuel_core_bin` as a library to help with e2e testing. ## Checklist - [x] Breaking changes are clearly marked as such in the PR description and changelog (no breaking changes) - [x] New behavior is reflected in tests - [x] [The specification](https://github.com/FuelLabs/fuel-specs/) matches the implemented behavior (link update PR if changes are needed) ### Before requesting review - [x] I have reviewed the code myself ### Before merge - [x] Retarget to master branch --------- Co-authored-by: Green Baneling <[email protected]>
1 parent bdabd84 commit cbcf170

File tree

30 files changed

+881
-90
lines changed

30 files changed

+881
-90
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Description of the upcoming release here.
1919
- [#1821](https://github.com/FuelLabs/fuel-core/pull/1821): Propagate shutdown signal to (re)genesis. Also add progress bar for (re)genesis.
2020
- [#1813](https://github.com/FuelLabs/fuel-core/pull/1813): Added back support for `/health` endpoint.
2121
- [#1799](https://github.com/FuelLabs/fuel-core/pull/1799): Snapshot creation is now concurrent.
22+
- [#1811](https://github.com/FuelLabs/fuel-core/pull/1811): Regenesis now preserves old blocks and transactions for GraphQL API.
2223

2324
### Changed
2425

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.
Binary file not shown.

bin/fuel-core/src/cli.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ pub async fn run_cli() -> anyhow::Result<()> {
141141
pub fn local_testnet_chain_config() -> ChainConfig {
142142
const TESTNET_CHAIN_CONFIG: &[u8] =
143143
include_bytes!("../chainspec/testnet/chain_config.json");
144+
const TESTNET_CHAIN_CONFIG_STATE_BYTECODE: &[u8] =
145+
include_bytes!("../chainspec/testnet/state_transition_bytecode.wasm");
144146

145-
let config: ChainConfig = serde_json::from_slice(TESTNET_CHAIN_CONFIG).unwrap();
147+
let mut config: ChainConfig = serde_json::from_slice(TESTNET_CHAIN_CONFIG).unwrap();
148+
config.state_transition_bytecode = TESTNET_CHAIN_CONFIG_STATE_BYTECODE.to_vec();
146149
config
147150
}
148151

bin/fuel-core/src/cli/run.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl Command {
371371
}
372372
}
373373

374-
pub async fn exec(command: Command) -> anyhow::Result<()> {
374+
pub fn get_service(command: Command) -> anyhow::Result<FuelService> {
375375
#[cfg(any(feature = "rocks-db", feature = "rocksdb-production"))]
376376
if command.db_prune && command.database_path.exists() {
377377
fuel_core::combined_database::CombinedDatabase::prune(&command.database_path)?;
@@ -389,7 +389,11 @@ pub async fn exec(command: Command) -> anyhow::Result<()> {
389389
// initialize the server
390390
let combined_database = CombinedDatabase::from_config(&config.combined_db_config)?;
391391

392-
let service = FuelService::new(combined_database, config)?;
392+
FuelService::new(combined_database, config)
393+
}
394+
395+
pub async fn exec(command: Command) -> anyhow::Result<()> {
396+
let service = get_service(command)?;
393397

394398
// Genesis could take a long time depending on the snapshot size. Start needs to be
395399
// interruptible by the shutdown_signal

bin/fuel-core/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![deny(clippy::arithmetic_side_effects)]
2+
#![deny(clippy::cast_possible_truncation)]
3+
#![deny(unused_crate_dependencies)]
4+
#![deny(warnings)]
5+
6+
pub mod cli;
7+
pub use fuel_core::service::FuelService;
8+
9+
use tikv_jemallocator as _; // Used only by the binary

bin/fuel-core/src/main.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
1-
#![deny(clippy::arithmetic_side_effects)]
2-
#![deny(clippy::cast_possible_truncation)]
3-
#![deny(unused_crate_dependencies)]
4-
#![deny(warnings)]
5-
61
// Use Jemalloc for main binary
72
#[global_allocator]
83
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
94

10-
use fuel_core::service::FuelService;
11-
12-
mod cli;
5+
use fuel_core_bin::cli;
136

147
#[tokio::main]
158
async fn main() -> anyhow::Result<()> {

crates/chain-config/src/config/randomize.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@ use fuel_core_storage::{
1616
ContractsStateKey,
1717
};
1818
use fuel_core_types::{
19-
blockchain::primitives::DaBlockHeight,
19+
blockchain::{
20+
block::CompressedBlock,
21+
consensus::{
22+
poa::PoAConsensus,
23+
Consensus,
24+
},
25+
header::PartialBlockHeader,
26+
primitives::DaBlockHeight,
27+
},
2028
entities::{
2129
coins::coin::{
2230
CompressedCoin,
@@ -29,18 +37,29 @@ use fuel_core_types::{
2937
relayer::message::MessageV1,
3038
Message,
3139
},
40+
fuel_asm::{
41+
op,
42+
RegId,
43+
},
3244
fuel_tx::{
3345
ContractId,
46+
Transaction,
47+
TransactionBuilder,
48+
UniqueIdentifier,
3449
UtxoId,
3550
},
3651
fuel_types::{
3752
Address,
3853
AssetId,
3954
BlockHeight,
4055
Bytes32,
56+
ChainId,
4157
Nonce,
4258
},
43-
fuel_vm::Salt,
59+
fuel_vm::{
60+
Salt,
61+
Signature,
62+
},
4463
};
4564

4665
use crate::TableEntry;
@@ -171,3 +190,39 @@ impl Randomize for ContractsStateKey {
171190
Self::new(&contract_id, &state_key)
172191
}
173192
}
193+
194+
impl Randomize for CompressedBlock {
195+
fn randomize(mut rng: impl rand::Rng) -> Self {
196+
let tx1: Transaction = Randomize::randomize(&mut rng);
197+
let tx2: Transaction = Randomize::randomize(&mut rng);
198+
199+
let tx_ids = vec![tx1.id(&ChainId::default()), tx2.id(&ChainId::default())];
200+
201+
Self::test(
202+
PartialBlockHeader::default().generate(&[tx1, tx2], &[], rng.gen()),
203+
tx_ids,
204+
)
205+
}
206+
}
207+
208+
impl Randomize for (BlockHeight, Consensus) {
209+
fn randomize(mut rng: impl rand::Rng) -> Self {
210+
(
211+
rng.gen::<u32>().into(),
212+
Consensus::PoA(PoAConsensus::new(Signature::from_bytes([rng.gen(); 64]))),
213+
)
214+
}
215+
}
216+
217+
impl Randomize for Transaction {
218+
fn randomize(mut rng: impl rand::Rng) -> Self {
219+
let program: Vec<u8> = [op::ret(RegId::ONE)].into_iter().collect();
220+
match rng.gen_range(0..2) {
221+
0 => TransactionBuilder::create(program.into(), rng.gen(), vec![rng.gen()])
222+
.finalize_as_transaction(),
223+
1 => TransactionBuilder::script(program, vec![rng.gen(), rng.gen()])
224+
.finalize_as_transaction(),
225+
_ => unreachable!(),
226+
}
227+
}
228+
}

crates/chain-config/src/config/state.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ use fuel_core_storage::{
1616
ContractsLatestUtxo,
1717
ContractsRawCode,
1818
ContractsState,
19+
FuelBlocks,
1920
Messages,
21+
SealedBlockConsensus,
2022
Transactions,
2123
},
2224
ContractsAssetKey,
@@ -408,11 +410,29 @@ impl AsTable<Transactions> for StateConfig {
408410
}
409411

410412
impl AddTable<Transactions> for StateConfigBuilder {
411-
fn add(&mut self, _entries: Vec<TableEntry<Transactions>>) {
412-
// Do not include these for now
413+
fn add(&mut self, _entries: Vec<TableEntry<Transactions>>) {}
414+
}
415+
416+
impl AsTable<FuelBlocks> for StateConfig {
417+
fn as_table(&self) -> Vec<TableEntry<FuelBlocks>> {
418+
Vec::new() // Do not include these for now
419+
}
420+
}
421+
422+
impl AddTable<FuelBlocks> for StateConfigBuilder {
423+
fn add(&mut self, _entries: Vec<TableEntry<FuelBlocks>>) {}
424+
}
425+
426+
impl AsTable<SealedBlockConsensus> for StateConfig {
427+
fn as_table(&self) -> Vec<TableEntry<SealedBlockConsensus>> {
428+
Vec::new() // Do not include these for now
413429
}
414430
}
415431

432+
impl AddTable<SealedBlockConsensus> for StateConfigBuilder {
433+
fn add(&mut self, _entries: Vec<TableEntry<SealedBlockConsensus>>) {}
434+
}
435+
416436
impl StateConfig {
417437
pub fn sorted(mut self) -> Self {
418438
self.coins = self
@@ -677,6 +697,8 @@ mod tests {
677697
let mut rng = StdRng::seed_from_u64(0);
678698
let state_config = StateConfig::randomize(&mut rng);
679699

700+
let chain_config = ChainConfig::local_testnet();
701+
680702
macro_rules! write_in_fragments {
681703
($($fragment_ty: ty,)*) => {
682704
[
@@ -692,7 +714,6 @@ mod tests {
692714
}
693715
}
694716

695-
let chain_config = ChainConfig::local_testnet();
696717
let fragments = write_in_fragments!(
697718
Coins,
698719
Messages,

crates/fuel-core/src/graphql_api/database.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::fuel_core_graphql_api::{
1414
use fuel_core_storage::{
1515
iter::{
1616
BoxedIter,
17+
IntoBoxedIter,
1718
IterDirection,
1819
},
1920
transactional::AtomicView,
@@ -29,6 +30,7 @@ use fuel_core_txpool::types::{
2930
use fuel_core_types::{
3031
blockchain::{
3132
block::CompressedBlock,
33+
consensus::Consensus,
3234
primitives::{
3335
BlockId,
3436
DaBlockHeight,
@@ -117,12 +119,56 @@ impl DatabaseBlocks for ReadView {
117119
height: Option<BlockHeight>,
118120
direction: IterDirection,
119121
) -> BoxedIter<'_, StorageResult<CompressedBlock>> {
120-
self.on_chain.blocks(height, direction)
122+
// Chain together blocks from the off-chain db and the on-chain db
123+
// The blocks in off-chain db, if any, are from time before regenesis
124+
125+
if let Some(height) = height {
126+
match self.on_chain.latest_genesis_height() {
127+
Ok(onchain_start_height) => {
128+
match (height >= onchain_start_height, direction) {
129+
(true, IterDirection::Forward) => {
130+
self.on_chain.blocks(Some(height), direction)
131+
}
132+
(true, IterDirection::Reverse) => self
133+
.on_chain
134+
.blocks(Some(height), direction)
135+
.chain(self.off_chain.old_blocks(None, direction))
136+
.into_boxed(),
137+
(false, IterDirection::Forward) => self
138+
.off_chain
139+
.old_blocks(Some(height), direction)
140+
.chain(self.on_chain.blocks(None, direction))
141+
.into_boxed(),
142+
(false, IterDirection::Reverse) => {
143+
self.off_chain.old_blocks(Some(height), direction)
144+
}
145+
}
146+
}
147+
Err(err) => core::iter::once(Err(err)).into_boxed(),
148+
}
149+
} else {
150+
match direction {
151+
IterDirection::Forward => self
152+
.off_chain
153+
.old_blocks(None, direction)
154+
.chain(self.on_chain.blocks(None, direction))
155+
.into_boxed(),
156+
IterDirection::Reverse => self
157+
.on_chain
158+
.blocks(None, direction)
159+
.chain(self.off_chain.old_blocks(None, direction))
160+
.into_boxed(),
161+
}
162+
}
121163
}
122164

123165
fn latest_height(&self) -> StorageResult<BlockHeight> {
124166
self.on_chain.latest_height()
125167
}
168+
169+
fn latest_genesis_height(&self) -> StorageResult<BlockHeight> {
170+
self.on_chain.latest_genesis_height()
171+
}
126172
}
127173

128174
impl<M> StorageInspect<M> for ReadView
@@ -242,6 +288,25 @@ impl OffChainDatabase for ReadView {
242288
self.off_chain.contract_salt(contract_id)
243289
}
244290

291+
fn old_blocks(
292+
&self,
293+
height: Option<BlockHeight>,
294+
direction: IterDirection,
295+
) -> BoxedIter<'_, StorageResult<CompressedBlock>> {
296+
self.off_chain.old_blocks(height, direction)
297+
}
298+
299+
fn old_block_consensus(&self, height: BlockHeight) -> StorageResult<Consensus> {
300+
self.off_chain.old_block_consensus(height)
301+
}
302+
303+
fn old_transaction(
304+
&self,
305+
id: &TxId,
306+
) -> StorageResult<Option<fuel_core_types::fuel_tx::Transaction>> {
307+
self.off_chain.old_transaction(id)
308+
}
309+
245310
fn relayed_tx_status(
246311
&self,
247312
id: Bytes32,

crates/fuel-core/src/graphql_api/ports.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use fuel_core_txpool::service::TxStatusMessage;
2222
use fuel_core_types::{
2323
blockchain::{
2424
block::CompressedBlock,
25+
consensus::Consensus,
2526
primitives::{
2627
BlockId,
2728
DaBlockHeight,
@@ -91,6 +92,16 @@ pub trait OffChainDatabase: Send + Sync {
9192

9293
fn contract_salt(&self, contract_id: &ContractId) -> StorageResult<Salt>;
9394

95+
fn old_blocks(
96+
&self,
97+
height: Option<BlockHeight>,
98+
direction: IterDirection,
99+
) -> BoxedIter<'_, StorageResult<CompressedBlock>>;
100+
101+
fn old_block_consensus(&self, height: BlockHeight) -> StorageResult<Consensus>;
102+
103+
fn old_transaction(&self, id: &TxId) -> StorageResult<Option<Transaction>>;
104+
94105
fn relayed_tx_status(
95106
&self,
96107
id: Bytes32,
@@ -123,6 +134,9 @@ pub trait DatabaseBlocks:
123134
) -> BoxedIter<'_, StorageResult<CompressedBlock>>;
124135

125136
fn latest_height(&self) -> StorageResult<BlockHeight>;
137+
138+
/// First (i.e. lowest) height stored in this db.
139+
fn latest_genesis_height(&self) -> StorageResult<BlockHeight>;
126140
}
127141

128142
/// Trait that specifies all the getters required for messages.
@@ -230,7 +244,14 @@ pub mod worker {
230244
contracts::ContractsInfo,
231245
messages::OwnedMessageIds,
232246
},
233-
graphql_api::storage::relayed_transactions::RelayedTransactionStatuses,
247+
graphql_api::storage::{
248+
old::{
249+
OldFuelBlockConsensus,
250+
OldFuelBlocks,
251+
OldTransactions,
252+
},
253+
relayed_transactions::RelayedTransactionStatuses,
254+
},
234255
};
235256
use fuel_core_services::stream::BoxStream;
236257
use fuel_core_storage::{
@@ -264,6 +285,9 @@ pub mod worker {
264285
+ StorageMutate<OwnedCoins, Error = StorageError>
265286
+ StorageMutate<FuelBlockIdsToHeights, Error = StorageError>
266287
+ StorageMutate<ContractsInfo, Error = StorageError>
288+
+ StorageMutate<OldFuelBlocks, Error = StorageError>
289+
+ StorageMutate<OldFuelBlockConsensus, Error = StorageError>
290+
+ StorageMutate<OldTransactions, Error = StorageError>
267291
+ StorageMutate<RelayedTransactionStatuses, Error = StorageError>
268292
{
269293
fn record_tx_id_owner(

0 commit comments

Comments
 (0)