Skip to content

Commit

Permalink
Feat(standalone): Persist transaction data (#481)
Browse files Browse the repository at this point in the history
  • Loading branch information
birchmd committed Apr 7, 2022
1 parent d0e9e82 commit 2ffa94e
Show file tree
Hide file tree
Showing 15 changed files with 727 additions and 441 deletions.
7 changes: 7 additions & 0 deletions engine-standalone-storage/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::TransactionIncluded;
#[derive(Debug, PartialEq, Clone)]
pub enum Error {
BlockNotFound(H256),
Borsh(String),
NoBlockAtHeight(u64),
TransactionNotFound(TransactionIncluded),
TransactionHashNotFound(H256),
Expand All @@ -16,3 +17,9 @@ impl From<rocksdb::Error> for Error {
Self::Rocksdb(e)
}
}

impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self::Borsh(e.to_string())
}
}
83 changes: 65 additions & 18 deletions engine-standalone-storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use rocksdb::DB;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::path::Path;
use sync::types::TransactionMessage;

const VERSION: u8 = 0;

Expand All @@ -28,7 +29,7 @@ const ENGINE_KEY_SUFFIX_LEN: usize = (64 / 8) + (16 / 8);
pub enum StoragePrefix {
BlockHash = 0x00,
BlockHeight = 0x01,
TransactionPosition = 0x02,
TransactionData = 0x02,
TransactionHash = 0x03,
Diff = 0x04,
Engine = 0x05,
Expand Down Expand Up @@ -108,20 +109,17 @@ impl Storage {
self.db.write(batch)
}

pub fn get_transaction_by_hash(
pub fn get_transaction_data(
&self,
tx_hash: H256,
) -> Result<TransactionIncluded, error::Error> {
let storage_key =
construct_storage_key(StoragePrefix::TransactionPosition, tx_hash.as_ref());
self.db
) -> Result<sync::types::TransactionMessage, error::Error> {
let storage_key = construct_storage_key(StoragePrefix::TransactionData, tx_hash.as_ref());
let bytes = self
.db
.get_pinned(storage_key)?
.map(|slice| {
let mut buf = [0u8; 34];
buf.copy_from_slice(slice.as_ref());
TransactionIncluded::from_bytes(buf)
})
.ok_or(error::Error::TransactionHashNotFound(tx_hash))
.ok_or(error::Error::TransactionHashNotFound(tx_hash))?;
let message = TransactionMessage::try_from_slice(bytes.as_ref())?;
Ok(message)
}

pub fn get_transaction_by_position(
Expand Down Expand Up @@ -150,7 +148,7 @@ impl Storage {
pub fn set_transaction_included(
&mut self,
tx_hash: H256,
tx_included: &TransactionIncluded,
tx_included: &TransactionMessage,
diff: &Diff,
) -> Result<(), error::Error> {
let batch = rocksdb::WriteBatch::default();
Expand All @@ -162,7 +160,7 @@ impl Storage {
pub fn revert_transaction_included(
&mut self,
tx_hash: H256,
tx_included: &TransactionIncluded,
tx_included: &TransactionMessage,
diff: &Diff,
) -> Result<(), error::Error> {
let batch = rocksdb::WriteBatch::default();
Expand All @@ -174,20 +172,24 @@ impl Storage {
fn process_transaction<F: Fn(&mut rocksdb::WriteBatch, &[u8], &[u8])>(
&mut self,
tx_hash: H256,
tx_included: &TransactionIncluded,
tx_msg: &TransactionMessage,
diff: &Diff,
mut batch: rocksdb::WriteBatch,
action: F,
) -> Result<(), error::Error> {
let tx_included = TransactionIncluded {
block_hash: tx_msg.block_hash,
position: tx_msg.position,
};
let tx_included_bytes = tx_included.to_bytes();
let block_height = self.get_block_height_by_hash(tx_included.block_hash)?;

let storage_key = construct_storage_key(StoragePrefix::TransactionHash, &tx_included_bytes);
action(&mut batch, &storage_key, tx_hash.as_ref());

let storage_key =
construct_storage_key(StoragePrefix::TransactionPosition, tx_hash.as_ref());
action(&mut batch, &storage_key, &tx_included_bytes);
let storage_key = construct_storage_key(StoragePrefix::TransactionData, tx_hash.as_ref());
let msg_bytes = tx_msg.to_bytes();
action(&mut batch, &storage_key, &msg_bytes);

let storage_key = construct_storage_key(StoragePrefix::Diff, &tx_included_bytes);
let diff_bytes = diff.try_to_bytes().unwrap();
Expand Down Expand Up @@ -333,6 +335,51 @@ impl Storage {
&self.db,
)
}

/// Same as `access_engine_storage_at_position`, but does not modify `self`, hence the immutable
/// borrow instead of the mutable one. The use case for this function is to execute a transaction
/// with the engine, but not to make any immediate changes to storage; only return the diff and outcome.
/// Note the closure is allowed to mutate the `EngineStateAccess` object, but this does not impact the `Storage`
/// because all changes are held in the diff in memory.
pub fn with_engine_access<'db, 'input, R, F>(
&'db self,
block_height: u64,
transaction_position: u16,
input: &'input [u8],
f: F,
) -> EngineAccessResult<R>
where
F: for<'output> FnOnce(engine_state::EngineStateAccess<'db, 'input, 'output>) -> R,
{
let diff = RefCell::new(Diff::default());
let engine_output = Cell::new(Vec::new());

let engine_state = engine_state::EngineStateAccess::new(
input,
block_height,
transaction_position,
&diff,
&engine_output,
&self.db,
);

let result = f(engine_state);
let diff = engine_state.get_transaction_diff();
let engine_output = engine_output.into_inner();

EngineAccessResult {
result,
engine_output,
diff,
}
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct EngineAccessResult<R> {
pub result: R,
pub engine_output: Vec<u8>,
pub diff: Diff,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
Expand Down
19 changes: 16 additions & 3 deletions engine-standalone-storage/src/relayer_db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,17 @@ where
}

let diff = io.get_transaction_diff();
let tx_included = crate::TransactionIncluded {
let tx_msg = crate::TransactionMessage {
block_hash,
near_receipt_id: near_tx_hash,
position: transaction_position,
succeeded: true,
signer: env.signer_account_id(),
caller: env.predecessor_account_id(),
attached_near: 0,
transaction: crate::sync::types::TransactionKind::Submit(tx),
};
storage.set_transaction_included(tx_hash, &tx_included, &diff)?;
storage.set_transaction_included(tx_hash, &tx_msg, &diff)?;
}
Ok(())
}
Expand Down Expand Up @@ -189,6 +195,7 @@ pub mod error {
#[cfg(test)]
mod test {
use super::FallibleIterator;
use crate::sync::types::{TransactionKind, TransactionMessage};
use aurora_engine::{connector, engine, parameters};
use aurora_engine_types::H256;

Expand Down Expand Up @@ -237,9 +244,15 @@ mod test {
storage
.set_transaction_included(
H256::zero(),
&crate::TransactionIncluded {
&TransactionMessage {
block_hash,
position: 0,
near_receipt_id: H256::zero(),
succeeded: true,
signer: "aurora".parse().unwrap(),
caller: "aurora".parse().unwrap(),
attached_near: 0,
transaction: TransactionKind::Unknown,
},
&diff,
)
Expand Down

0 comments on commit 2ffa94e

Please sign in to comment.