provider batch get transactioninfo
* provider batch get transactioninfo
provider batch get transactioninfo
* provider batch get transactioninfo
provider batch get transactioninfo
* get batch transaction infos
get batch transaction infos
* provider get transaction infos
fmt code
MODIFY
chain/api/src/chain.rs
chain/api/src/chain.rs
@@ -68,6 +68,13 @@ pub trait ChainReader {
fn verify(&self, block: Block) -> Result<VerifiedBlock>;
/// Execute block and verify it execute state, and save result base current chain, but do not change current chain.
fn execute(&self, block: VerifiedBlock) -> Result<ExecutedBlock>;
+ /// Get chain transaction infos
+ fn get_txn_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> Result<Vec<BlockTransactionInfo>>;
}
pub trait ChainWriter {

MODIFY
chain/api/src/message.rs
chain/api/src/message.rs
@@ -47,6 +47,11 @@ pub enum ChainRequest {
},
GetBlocks(Vec<HashValue>),
GetHeaders(Vec<HashValue>),
+ GetTransactionInfos {
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ },
}
impl ServiceRequest for ChainRequest {

MODIFY
chain/api/src/service.rs
chain/api/src/service.rs
@@ -48,6 +48,13 @@ pub trait ReadableChainService {
reverse: bool,
max_size: u64,
) -> Result<Vec<HashValue>>;
+
+ fn get_txn_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> Result<Vec<BlockTransactionInfo>>;
}
/// Writeable block chain service trait
@@ -99,6 +106,12 @@ pub trait ChainAsyncService:
reverse: bool,
max_size: u64,
) -> Result<Vec<HashValue>>;
+ async fn get_txn_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> Result<Vec<BlockTransactionInfo>>;
}
#[async_trait::async_trait]
@@ -347,4 +360,24 @@ where
bail!("get_block_ids invalid response")
}
}
+
+ async fn get_txn_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> Result<Vec<BlockTransactionInfo>> {
+ let response = self
+ .send(ChainRequest::GetTransactionInfos {
+ start_index,
+ reverse,
+ max_size,
+ })
+ .await??;
+ if let ChainResponse::TransactionInfos(tx_infos) = response {
+ Ok(tx_infos)
+ } else {
+ bail!("get txn infos error")
+ }
+ }
}

MODIFY
chain/service/src/chain_service.rs
chain/service/src/chain_service.rs
@@ -214,6 +214,15 @@ impl ServiceHandler<Self, ChainRequest> for ChainReaderService {
ChainRequest::GetHeaders(ids) => {
Ok(ChainResponse::BlockHeaderVec(self.inner.get_headers(ids)?))
}
+ ChainRequest::GetTransactionInfos {
+ start_index,
+ reverse,
+ max_size,
+ } => Ok(ChainResponse::TransactionInfos(self.inner.get_txn_infos(
+ start_index,
+ reverse,
+ max_size,
+ )?)),
}
}
}
@@ -353,6 +362,15 @@ impl ReadableChainService for ChainReaderServiceInner {
) -> Result<Vec<HashValue>> {
self.main.get_block_ids(start_number, reverse, max_size)
}
+
+ fn get_txn_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> Result<Vec<BlockTransactionInfo>> {
+ self.main.get_txn_infos(start_index, reverse, max_size)
+ }
}
#[cfg(test)]

MODIFY
chain/src/chain.rs
chain/src/chain.rs
@@ -721,6 +721,30 @@ impl ChainReader for BlockChain {
verified_block.0,
)
}
+
+ fn get_txn_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> Result<Vec<BlockTransactionInfo>> {
+ let chain_header = self.current_header();
+ let hash_list = self
+ .txn_accumulator
+ .get_leaves(start_index, reverse, max_size)?;
+ let mut infos = vec![];
+ for hash in hash_list {
+ let info = self.storage.get_transaction_info(hash)?.ok_or_else(|| {
+ anyhow::anyhow!(format!(
+ "cannot find hash({}) on main chain(head: {})",
+ hash,
+ chain_header.id()
+ ))
+ })?;
+ infos.push(info);
+ }
+ Ok(infos)
+ }
}
impl BlockChain {

ADD
cmd/starcoin/src/chain/get_txn_info_list_cmd.rs
+// Copyright (c) The Starcoin Core Contributors
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::cli_state::CliState;
+use crate::StarcoinOpt;
+use anyhow::Result;
+use scmd::{CommandAction, ExecContext};
+use starcoin_rpc_api::types::TransactionInfoView;
+use structopt::StructOpt;
+
+/// Get transaction infos list
+#[derive(Debug, StructOpt)]
+#[structopt(name = "get-txn-info-list", alias = "get_txn_info_list")]
+pub struct GetTransactionInfoListOpt {
+ /// start_index
+ #[structopt(name = "start_index", long, short = "s")]
+ start_index: u64,
+
+ #[structopt(name = "reverse", long, short = "r")]
+ reverse: Option<bool>,
+
+ #[structopt(name = "count", long, short = "c")]
+ count: u64,
+}
+
+pub struct GetTransactionInfoListCommand;
+
+impl CommandAction for GetTransactionInfoListCommand {
+ type State = CliState;
+ type GlobalOpt = StarcoinOpt;
+ type Opt = GetTransactionInfoListOpt;
+ type ReturnItem = Vec<TransactionInfoView>;
+
+ fn run(
+ &self,
+ ctx: &ExecContext<Self::State, Self::GlobalOpt, Self::Opt>,
+ ) -> Result<Self::ReturnItem> {
+ let client = ctx.state().client();
+ let opt = ctx.opt();
+ let txn_infos = client.chain_get_transaction_infos(
+ opt.start_index,
+ opt.reverse.unwrap_or(false),
+ opt.count,
+ )?;
+ Ok(txn_infos)
+ }
+}

MODIFY
cmd/starcoin/src/chain/mod.rs
cmd/starcoin/src/chain/mod.rs
@@ -6,6 +6,7 @@ mod get_block_cmd;
mod get_events_cmd;
mod get_txn_cmd;
mod get_txn_info_cmd;
+mod get_txn_info_list_cmd;
mod get_txn_infos_cmd;
mod info_cmd;
mod list_block_cmd;
@@ -15,6 +16,7 @@ pub use get_block_cmd::*;
pub use get_events_cmd::*;
pub use get_txn_cmd::*;
pub use get_txn_info_cmd::*;
+pub use get_txn_info_list_cmd::*;
pub use get_txn_infos_cmd::*;
pub use info_cmd::*;
pub use list_block_cmd::*;

MODIFY
cmd/starcoin/src/lib.rs
cmd/starcoin/src/lib.rs
@@ -100,7 +100,8 @@ pub fn add_command(
.subcommand(chain::GetTxnInfosCommand)
.subcommand(chain::GetTransactionInfoCommand)
.subcommand(chain::GetEventsCommand)
- .subcommand(chain::EpochInfoCommand),
+ .subcommand(chain::EpochInfoCommand)
+ .subcommand(chain::GetTransactionInfoListCommand),
)
.command(
Command::with_name("txpool")

MODIFY
rpc/api/src/chain/mod.rs
rpc/api/src/chain/mod.rs
@@ -54,7 +54,7 @@ pub trait ChainApi {
transaction_hash: HashValue,
option: Option<GetTransactionOption>,
) -> FutureResult<Option<TransactionView>>;
- /// Get chain transactions
+ /// Get chain transaction info
#[rpc(name = "chain.get_transaction_info")]
fn get_transaction_info(
&self,
@@ -88,6 +88,13 @@ pub trait ChainApi {
/// Get headers by ids.
#[rpc(name = "chain.get_headers")]
fn get_headers(&self, ids: Vec<HashValue>) -> FutureResult<Vec<BlockHeaderView>>;
+ #[rpc(name = "chain.get_transaction_infos")]
+ fn get_transaction_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> FutureResult<Vec<TransactionInfoView>>;
}
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)]

MODIFY
rpc/client/src/lib.rs
rpc/client/src/lib.rs
@@ -753,6 +753,20 @@ impl RpcClient {
.map_err(map_err)
}
+ pub fn chain_get_transaction_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> anyhow::Result<Vec<TransactionInfoView>> {
+ self.call_rpc_blocking(|inner| {
+ inner
+ .chain_client
+ .get_transaction_infos(start_index, reverse, max_size)
+ })
+ .map_err(map_err)
+ }
+
pub fn dry_run(&self, txn: DryRunTransactionRequest) -> anyhow::Result<DryRunOutputView> {
self.call_rpc_blocking(|inner| inner.contract_client.dry_run(txn))
.map_err(map_err)

MODIFY
rpc/generated_rpc_schema/chain.json
rpc/generated_rpc_schema/chain.json
}
}
}
+ },
+ {
+ "name": "chain.get_transaction_infos",
+ "params": [
+ {
+ "name": "start_index",
+ "schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "uint64",
+ "type": "integer",
+ "format": "uint64",
+ "minimum": 0.0
+ }
+ },
+ {
+ "name": "reverse",
+ "schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Boolean",
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "max_size",
+ "schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "uint64",
+ "type": "integer",
+ "format": "uint64",
+ "minimum": 0.0
+ }
+ }
+ ],
+ "result": {
+ "name": "Vec < TransactionInfoView >",
+ "schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Array_of_TransactionInfoView",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "block_hash",
+ "block_number",
+ "event_root_hash",
+ "gas_used",
+ "state_root_hash",
+ "status",
+ "transaction_hash",
+ "transaction_index"
+ ],
+ "properties": {
+ "block_hash": {
+ "type": "string",
+ "format": "HashValue"
+ },
+ "block_number": {
+ "type": "string"
+ },
+ "event_root_hash": {
+ "description": "The root hash of Merkle Accumulator storing all events emitted during this transaction.",
+ "type": "string",
+ "format": "HashValue"
+ },
+ "gas_used": {
+ "description": "The amount of gas used.",
+ "type": "string"
+ },
+ "state_root_hash": {
+ "description": "The root hash of Sparse Merkle Tree describing the world state at the end of this transaction.",
+ "type": "string",
+ "format": "HashValue"
+ },
+ "status": {
+ "description": "The vm status. If it is not `Executed`, this will provide the general error class. Execution failures and Move abort's receive more detailed information. But other errors are generally categorized with no status code or other information",
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": [
+ "Executed",
+ "OutOfGas",
+ "MiscellaneousError"
+ ]
+ },
+ {
+ "type": "object",
+ "required": [
+ "MoveAbort"
+ ],
+ "properties": {
+ "MoveAbort": {
+ "type": "object",
+ "required": [
+ "abort_code",
+ "location"
+ ],
+ "properties": {
+ "abort_code": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "required": [
+ "ExecutionFailure"
+ ],
+ "properties": {
+ "ExecutionFailure": {
+ "type": "object",
+ "required": [
+ "code_offset",
+ "function",
+ "location"
+ ],
+ "properties": {
+ "code_offset": {
+ "type": "integer",
+ "format": "uint16",
+ "minimum": 0.0
+ },
+ "function": {
+ "type": "integer",
+ "format": "uint16",
+ "minimum": 0.0
+ },
+ "location": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "required": [
+ "Discard"
+ ],
+ "properties": {
+ "Discard": {
+ "type": "object",
+ "required": [
+ "status_code",
+ "status_code_name"
+ ],
+ "properties": {
+ "status_code": {
+ "type": "string"
+ },
+ "status_code_name": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "transaction_hash": {
+ "description": "The hash of this transaction.",
+ "type": "string",
+ "format": "HashValue"
+ },
+ "transaction_index": {
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ }
+ }
+ }
+ }
+ }
}
]
}
\ No newline at end of file

MODIFY
rpc/server/src/module/chain_rpc.rs
rpc/server/src/module/chain_rpc.rs
@@ -23,6 +23,7 @@ use starcoin_types::block::{BlockInfo, BlockNumber};
use starcoin_types::filter::Filter;
use starcoin_types::startup_info::ChainInfo;
use starcoin_types::transaction::TransactionInfo;
+use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::sync::Arc;
pub struct ChainRpcImpl<S>
@@ -412,6 +413,54 @@ where
Box::pin(fut.boxed())
}
+
+ fn get_transaction_infos(
+ &self,
+ start_index: u64,
+ reverse: bool,
+ max_size: u64,
+ ) -> FutureResult<Vec<TransactionInfoView>> {
+ let service = self.service.clone();
+ let fut = async move {
+ let txn_infos = service
+ .get_txn_infos(start_index, reverse, max_size)
+ .await?;
+ // remove duplicate block_id
+ let id_sets = txn_infos
+ .iter()
+ .map(|info| info.block_id())
+ .collect::<HashSet<HashValue>>();
+ let block_ids = id_sets.into_iter().collect();
+ let blocks = service.get_blocks(block_ids).await?;
+ let mut block_cache = HashMap::new();
+ for block in blocks {
+ let block = block.ok_or_else(|| {
+ anyhow::anyhow!(
+ "cannot find block which start_index {}, reverse {}, max_size {}",
+ start_index,
+ reverse,
+ max_size
+ )
+ })?;
+
+ block_cache.insert(block.header.id(), block);
+ }
+
+ txn_infos
+ .into_iter()
+ .map(|info| {
+ let block_id = info.block_id();
+ TransactionInfoView::new(
+ Into::<(_, TransactionInfo)>::into(info).1,
+ block_cache.get(&block_id).unwrap(),
+ )
+ })
+ .collect::<Result<Vec<_>, _>>()
+ }
+ .map_err(map_err);
+
+ Box::pin(fut.boxed())
+ }
}
fn try_decode_block_txns(state: &dyn StateView, block: &mut BlockView) -> anyhow::Result<()> {

MODIFY
testsuite/features/cmd.feature
testsuite/features/cmd.feature
@@ -14,6 +14,7 @@ Feature: cmd integration test
Then cmd: "chain get-txn-infos @$.header.block_hash@"
Then cmd: "chain get-txn @$[0].transaction_hash@"
Then cmd: "chain get-events @$.transaction_hash@"
+ Then cmd: "chain get-txn-info-list -s 0 -c 5"
Then stop
Examples:

provider batch get transactioninfo (#2966)

* provider batch get transactioninfo

provider batch get transactioninfo

* provider batch get transactioninfo

provider batch get transactioninfo

* get batch transaction infos

get batch transaction infos

* provider get transaction infos

fmt code