Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

current time impl for VM #545

Merged
merged 8 commits into from
Aug 10, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions fuel-core/src/database.rs
Original file line number Diff line number Diff line change
@@ -262,8 +262,15 @@ impl InterpreterStorage for Database {
Ok(height.into())
}

fn timestamp(&self, _height: u32) -> Result<Word, Self::DataError> {
todo!()
fn timestamp(&self, height: u32) -> Result<Word, Self::DataError> {
let id = self.block_hash(height)?;
let block = Storage::<Bytes32, FuelBlockDb>::get(self, &id)?.unwrap_or_default();
block
.headers
.time
.timestamp()
.try_into()
.map_err(|e| Self::DataError::DatabaseError(Box::new(e)))
}

fn block_hash(&self, block_height: u32) -> Result<Bytes32, Error> {
153 changes: 153 additions & 0 deletions fuel-core/src/executor.rs
Original file line number Diff line number Diff line change
@@ -89,6 +89,13 @@ impl Executor {
};

let mut block_db_transaction = self.database.transaction();
// Insert the current headers (including time, block height, producer into the db tx)
Storage::<Bytes32, FuelBlockDb>::insert(
block_db_transaction.deref_mut(),
&Bytes32::zeroed(), // use id of zero as current block
&block.to_db_block(),
)?;

let mut txs_merkle = MerkleTree::new();
let mut tx_status = vec![];
let mut coinbase = 0u64;
@@ -285,6 +292,12 @@ impl Executor {
block_db_transaction.deref_mut(),
)?;

// cleanup unfinalized headers (block height + time + producer)
Storage::<Bytes32, FuelBlockDb>::remove(
block_db_transaction.deref_mut(),
&Bytes32::zeroed(),
)?;

// insert block into database
Storage::<Bytes32, FuelBlockDb>::insert(
block_db_transaction.deref_mut(),
@@ -817,6 +830,7 @@ impl From<crate::state::Error> for Error {
mod tests {
use super::*;
use crate::model::FuelBlockHeader;
use chrono::TimeZone;
use fuel_core_interfaces::model::{CheckedMessage, Message};
use fuel_core_interfaces::{
common::{
@@ -1875,4 +1889,143 @@ mod tests {
))
));
}

#[tokio::test]
async fn get_block_height_returns_current_executing_block() {
let mut rng = StdRng::seed_from_u64(1234);

// return current block height
let script = vec![Opcode::BHEI(0x10), Opcode::RET(0x10)];
let tx = TransactionBuilder::script(script.into_iter().collect(), vec![])
.gas_limit(10000)
.add_unsigned_coin_input(
rng.gen(),
rng.gen(),
1000,
AssetId::zeroed(),
Default::default(),
0,
)
.finalize();

// setup block
let block_height = rng.gen_range(5u32..1000u32);

let mut block = FuelBlock {
header: FuelBlockHeader {
height: block_height.into(),
..Default::default()
},
transactions: vec![tx.clone()],
};

// setup db with coin to spend
let mut database = Database::default();
let coin_input = &tx.inputs()[0];
Storage::<UtxoId, Coin>::insert(
&mut database,
coin_input.utxo_id().unwrap(),
&Coin {
owner: *coin_input.input_owner().unwrap(),
amount: coin_input.amount().unwrap(),
asset_id: *coin_input.asset_id().unwrap(),
maturity: (coin_input.maturity().unwrap()).into(),
block_created: 0u64.into(),
status: CoinStatus::Unspent,
},
)
.unwrap();

// make executor with db
let executor = Executor {
database: database.clone(),
config: Config {
utxo_validation: true,
..Config::local_node()
},
};

executor
.execute(&mut block, ExecutionMode::Production)
.await
.unwrap();

let receipts = Storage::<Bytes32, Vec<Receipt>>::get(&database, &tx.id())
.unwrap()
.unwrap();
assert_eq!(block_height as u64, receipts[0].val().unwrap());
}

#[tokio::test]
async fn get_time_returns_current_executing_block_time() {
let mut rng = StdRng::seed_from_u64(1234);

// return current block height
let script = vec![
Opcode::BHEI(0x10),
Opcode::TIME(0x11, 0x10),
Opcode::RET(0x11),
];
let tx = TransactionBuilder::script(script.into_iter().collect(), vec![])
.gas_limit(10000)
.add_unsigned_coin_input(
rng.gen(),
rng.gen(),
1000,
AssetId::zeroed(),
Default::default(),
0,
)
.finalize();

// setup block
let block_height = rng.gen_range(5u32..1000u32);
let time = rng.gen_range(1u32..u32::MAX);

let mut block = FuelBlock {
header: FuelBlockHeader {
height: block_height.into(),
time: Utc.timestamp(time as i64, 0),
..Default::default()
},
transactions: vec![tx.clone()],
};

// setup db with coin to spend
let mut database = Database::default();
let coin_input = &tx.inputs()[0];
Storage::<UtxoId, Coin>::insert(
&mut database,
coin_input.utxo_id().unwrap(),
&Coin {
owner: *coin_input.input_owner().unwrap(),
amount: coin_input.amount().unwrap(),
asset_id: *coin_input.asset_id().unwrap(),
maturity: (coin_input.maturity().unwrap()).into(),
block_created: 0u64.into(),
status: CoinStatus::Unspent,
},
)
.unwrap();

// make executor with db
let executor = Executor {
database: database.clone(),
config: Config {
utxo_validation: true,
..Config::local_node()
},
};

executor
.execute(&mut block, ExecutionMode::Production)
.await
.unwrap();

let receipts = Storage::<Bytes32, Vec<Receipt>>::get(&database, &tx.id())
.unwrap()
.unwrap();

assert_eq!(time as u64, receipts[0].val().unwrap());
}
}