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

Transaction writeset store #3903

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions chain/api/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use starcoin_types::{
transaction::Transaction,
};
use starcoin_vm_types::access_path::AccessPath;
use starcoin_vm_types::write_set::WriteSet;

#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -60,6 +61,7 @@ pub enum ChainRequest {
access_path: Option<AccessPath>,
},
GetBlockInfos(Vec<HashValue>),
GetTransactionWriteSet(HashValue),
}

impl ServiceRequest for ChainRequest {
Expand Down Expand Up @@ -88,4 +90,5 @@ pub enum ChainResponse {
HashVec(Vec<HashValue>),
TransactionProof(Box<Option<TransactionInfoWithProof>>),
BlockInfoVec(Box<Vec<Option<BlockInfo>>>),
TransactionWriteSet(Option<WriteSet>),
}
16 changes: 16 additions & 0 deletions chain/api/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use starcoin_types::{
startup_info::StartupInfo,
};
use starcoin_vm_types::access_path::AccessPath;
use starcoin_vm_types::write_set::WriteSet;

/// Readable block chain service trait
pub trait ReadableChainService {
Expand Down Expand Up @@ -72,6 +73,8 @@ pub trait ReadableChainService {
) -> Result<Option<TransactionInfoWithProof>>;

fn get_block_infos(&self, ids: Vec<HashValue>) -> Result<Vec<Option<BlockInfo>>>;

fn get_transaction_write_set(&self, hash: HashValue) -> Result<Option<WriteSet>>;
}

/// Writeable block chain service trait
Expand Down Expand Up @@ -139,6 +142,8 @@ pub trait ChainAsyncService:
) -> Result<Option<TransactionInfoWithProof>>;

async fn get_block_infos(&self, hashes: Vec<HashValue>) -> Result<Vec<Option<BlockInfo>>>;

async fn get_transaction_write_set(&self, hash: HashValue) -> Result<Option<WriteSet>>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -436,4 +441,15 @@ where
bail!("get block_infos error")
}
}

async fn get_transaction_write_set(&self, hash: HashValue) -> Result<Option<WriteSet>> {
let response = self
.send(ChainRequest::GetTransactionWriteSet(hash))
.await??;
if let ChainResponse::TransactionWriteSet(write_set) = response {
Ok(write_set)
} else {
bail!("get get_write_set error")
}
}
}
8 changes: 8 additions & 0 deletions chain/service/src/chain_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use starcoin_types::{
};
use starcoin_vm_runtime::metrics::VMMetrics;
use starcoin_vm_types::access_path::AccessPath;
use starcoin_vm_types::write_set::WriteSet;
use std::sync::Arc;

/// A Chain reader service to provider Reader API.
Expand Down Expand Up @@ -232,6 +233,9 @@ impl ServiceHandler<Self, ChainRequest> for ChainReaderService {
ChainRequest::GetBlockInfos(ids) => Ok(ChainResponse::BlockInfoVec(Box::new(
self.inner.get_block_infos(ids)?,
))),
ChainRequest::GetTransactionWriteSet(hash) => Ok(ChainResponse::TransactionWriteSet(
self.inner.get_transaction_write_set(hash)?,
)),
}
}
}
Expand Down Expand Up @@ -416,6 +420,10 @@ impl ReadableChainService for ChainReaderServiceInner {
fn get_block_infos(&self, ids: Vec<HashValue>) -> Result<Vec<Option<BlockInfo>>> {
self.storage.get_block_infos(ids)
}

fn get_transaction_write_set(&self, hash: HashValue) -> Result<Option<WriteSet>> {
self.storage.get_write_set(hash)
}
}

#[cfg(test)]
Expand Down
5 changes: 5 additions & 0 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ impl BlockChain {
let block_id = block.id();
let txn_infos = executed_data.txn_infos;
let txn_events = executed_data.txn_events;
let txn_write_set = executed_data.txn_write_sets;

debug_assert!(
txn_events.len() == txn_infos.len(),
Expand Down Expand Up @@ -505,6 +506,10 @@ impl BlockChain {

storage.save_block_info(block_info.clone())?;

for (hash_value, write_set) in txn_write_set.iter() {
Copy link
Collaborator

@simonjiao simonjiao Jun 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can consume the txn_write_set, becase it will not be used any more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passed it into batch save function

storage.save_write_set(*hash_value, write_set.clone())?;
}

watch(CHAIN_WATCH_NAME, "n26");
Ok(ExecutedBlock { block, block_info })
}
Expand Down
11 changes: 10 additions & 1 deletion executor/src/block_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ use starcoin_types::transaction::TransactionStatus;
use starcoin_types::transaction::{Transaction, TransactionInfo};
use starcoin_vm_runtime::metrics::VMMetrics;
use starcoin_vm_types::contract_event::ContractEvent;
use starcoin_vm_types::write_set::WriteSet;
use std::collections::HashMap;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BlockExecutedData {
pub state_root: HashValue,
pub txn_infos: Vec<TransactionInfo>,
pub txn_events: Vec<Vec<ContractEvent>>,
pub txn_write_sets: HashMap<HashValue, WriteSet>,
}

impl Default for BlockExecutedData {
Expand All @@ -23,6 +26,7 @@ impl Default for BlockExecutedData {
state_root: HashValue::zero(),
txn_events: vec![],
txn_infos: vec![],
txn_write_sets: HashMap::default(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里为什么用HashMap,之前都是vec!, 这里有快速查找和插入需求吗?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里因为一个block涉及到多个transaction,map实现起来比较方便

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是L80还是哪里?方便给我说下

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里改成了vec,没改之前的考虑是方便说外面一对一的去取;改了之后的考虑是1. 如果有重复hashvalue则不会覆盖造成数据丢失,2. 存数据库时也是用的顺序存储

}
}
}
Expand Down Expand Up @@ -53,12 +57,13 @@ pub fn block_execute<S: ChainStateReader + ChainStateWriter>(
}
TransactionStatus::Keep(status) => {
chain_state
.apply_write_set(write_set)
.apply_write_set(write_set.clone())
.map_err(BlockExecutorError::BlockChainStateErr)?;

let txn_state_root = chain_state
.commit()
.map_err(BlockExecutorError::BlockChainStateErr)?;

#[cfg(testing)]
info!("txn_hash {} gas_used {}", txn_hash, gas_used);
executed_data.txn_infos.push(TransactionInfo::new(
Expand All @@ -68,7 +73,11 @@ pub fn block_execute<S: ChainStateReader + ChainStateWriter>(
gas_used,
status,
));

executed_data.txn_events.push(events);

// Put write set into result
executed_data.txn_write_sets.insert(txn_hash, write_set);
}
};
}
Expand Down
7 changes: 7 additions & 0 deletions rpc/api/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::types::pubsub::EventFilter;
use crate::types::{
BlockHeaderView, BlockInfoView, BlockView, ChainId, ChainInfoView, StrView,
TransactionEventResponse, TransactionInfoView, TransactionInfoWithProofView, TransactionView,
TransactionWriteSetView,
};
use crate::FutureResult;
use jsonrpc_core::Result;
Expand Down Expand Up @@ -122,6 +123,12 @@ pub trait ChainApi {
event_index: Option<u64>,
access_path: Option<StrView<AccessPath>>,
) -> FutureResult<Option<StrView<Vec<u8>>>>;

#[rpc(name = "chain.get_transaction_write_set")]
fn get_transaction_write_set(
&self,
block_hash: HashValue,
) -> FutureResult<Option<TransactionWriteSetView>>;
}

#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)]
Expand Down
79 changes: 59 additions & 20 deletions rpc/api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ use starcoin_vm_types::transaction::{
};
use starcoin_vm_types::transaction_argument::convert_txn_args;
use starcoin_vm_types::vm_status::{DiscardedVMStatus, KeptVMStatus, StatusCode};
use starcoin_vm_types::write_set::WriteOp;
use starcoin_vm_types::write_set::{WriteOp, WriteSet};
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;

pub type ByteCode = Vec<u8>;

mod node_api_types;
pub mod pubsub;

Expand Down Expand Up @@ -266,8 +267,8 @@ impl ArgumentsView {
/// Because we cannot distinguish whether `0x12341235` is an human readable address or just some bcs bytes in hex string.
impl<'de> Deserialize<'de> for ArgumentsView {
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
let args = <Vec<TransactionArgumentView>>::deserialize(deserializer)?;
Ok(ArgumentsView::HumanReadable(args))
Expand All @@ -277,8 +278,8 @@ impl<'de> Deserialize<'de> for ArgumentsView {
/// Only return BCS hex string when returning arguments out of jsonrpc.
impl Serialize for ArgumentsView {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
where
S: Serializer,
{
match self {
Self::HumanReadable(_vs) => {
Expand Down Expand Up @@ -477,7 +478,7 @@ impl From<BlockHeaderView> for BlockHeader {
}

impl FromIterator<BlockHeaderView> for Vec<BlockHeader> {
fn from_iter<T: IntoIterator<Item = BlockHeaderView>>(views: T) -> Self {
fn from_iter<T: IntoIterator<Item=BlockHeaderView>>(views: T) -> Self {
let mut blocks = vec![];
for view in views {
blocks.push(view.into())
Expand Down Expand Up @@ -1221,6 +1222,7 @@ impl From<TransactionOutput> for TransactionOutputView {
}
}
}

impl From<(AccessPath, WriteOp)> for TransactionOutputAction {
fn from((access_path, op): (AccessPath, WriteOp)) -> Self {
let (action, value) = match op {
Expand All @@ -1242,6 +1244,7 @@ impl From<(AccessPath, WriteOp)> for TransactionOutputAction {
}
}
}

#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct TransactionOutputAction {
pub access_path: AccessPath,
Expand Down Expand Up @@ -1546,7 +1549,7 @@ impl<T> JsonSchema for StrView<T> {
instance_type: Some(InstanceType::String.into()),
..Default::default()
}
.into()
.into()
}
}

Expand All @@ -1557,25 +1560,25 @@ impl<T> From<T> for StrView<T> {
}

impl<T> Serialize for StrView<T>
where
Self: ToString,
where
Self: ToString,
{
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

impl<'de, T> Deserialize<'de> for StrView<T>
where
Self: FromStr,
<Self as FromStr>::Err: std::fmt::Display,
where
Self: FromStr,
<Self as FromStr>::Err: std::fmt::Display,
{
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;

Expand Down Expand Up @@ -1790,8 +1793,8 @@ impl From<Vec<u8>> for BytesView {

impl<'de> Deserialize<'de> for BytesView {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
<Vec<u8>>::from_hex(s)
Expand All @@ -1802,8 +1805,8 @@ impl<'de> Deserialize<'de> for BytesView {

impl Serialize for BytesView {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
where
S: Serializer,
{
hex::encode(self).serialize(serializer)
}
Expand All @@ -1822,6 +1825,7 @@ pub struct ConnectLocal;
impl ServiceRequest for ConnectLocal {
type Response = RpcChannel;
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct AccumulatorInfoView {
/// Accumulator root hash
Expand Down Expand Up @@ -1928,6 +1932,41 @@ impl From<StateKey> for StateKeyView {
}
}

#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct TransactionWriteSetView {
hash_value: HashValue,
access_write_set: Vec<TransactionOutputAction>,
table_write_set: Vec<TransactionOutputTableItemAction>,
}

impl TransactionWriteSetView {
pub fn new(hash_value: HashValue, write_set: WriteSet) -> anyhow::Result<Self> {
let mut access_write_set = vec![];
let mut table_item_write_set = vec![];
for (state_key, op) in write_set {
match state_key {
StateKey::AccessPath(access_path) => {
access_write_set.push((access_path, op));
}
StateKey::TableItem(table_item) => {
table_item_write_set.push((table_item, op));
}
}
}
Ok(Self {
hash_value,
access_write_set: access_write_set
.into_iter()
.map(TransactionOutputAction::from)
.collect(),
table_write_set: table_item_write_set
.into_iter()
.map(TransactionOutputTableItemAction::from)
.collect(),
})
}
}

#[cfg(test)]
mod tests {
use crate::types::{ByteCodeOrScriptFunction, FunctionId, StrView};
Expand Down
18 changes: 17 additions & 1 deletion rpc/server/src/module/chain_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use starcoin_rpc_api::types::pubsub::EventFilter;
use starcoin_rpc_api::types::{
BlockHeaderView, BlockInfoView, BlockTransactionsView, BlockView, ChainId, ChainInfoView,
SignedUserTransactionView, StrView, TransactionEventResponse, TransactionInfoView,
TransactionInfoWithProofView, TransactionView,
TransactionInfoWithProofView, TransactionView, TransactionWriteSetView,
};
use starcoin_rpc_api::FutureResult;
use starcoin_state_api::StateView;
Expand Down Expand Up @@ -469,6 +469,22 @@ where

Box::pin(fut.boxed())
}

fn get_transaction_write_set(
&self,
txn_hash: HashValue,
) -> FutureResult<Option<TransactionWriteSetView>> {
let service = self.service.clone();
let fut = async move {
let write_set = service.get_transaction_write_set(txn_hash).await?;
match write_set {
None => Ok(None),
Some(w) => Ok(Some(TransactionWriteSetView::new(txn_hash, w)?)),
}
}
.map_err(map_err);
Box::pin(fut.boxed())
}
}

fn try_decode_block_txns(state: &dyn StateView, block: &mut BlockView) -> anyhow::Result<()> {
Expand Down
Loading