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

Enable retrieving both transactions and blocks in json format #1155

Merged
merged 12 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 35 additions & 2 deletions chainstate/src/detail/chainstateref/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use common::{
tokens::TokenAuxiliaryData,
tokens::{get_tokens_issuance_count, TokenId},
AccountNonce, AccountType, Block, ChainConfig, GenBlock, GenBlockId, OutPointSourceId,
Transaction, TxOutput, UtxoOutPoint,
SignedTransaction, Transaction, TxMainChainIndex, TxOutput, UtxoOutPoint,
},
primitives::{id::WithId, BlockDistance, BlockHeight, Id, Idable},
time_getter::TimeGetter,
Expand Down Expand Up @@ -162,6 +162,14 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
self.time_getter.get_time()
}

pub fn get_is_transaction_index_enabled(&self) -> Result<bool, PropertyQueryError> {
Ok(self
.db_tx
.get_is_mainchain_tx_index_enabled()
.map_err(PropertyQueryError::from)?
.expect("Must be set on node initialization"))
}

pub fn get_best_block_id(&self) -> Result<Id<GenBlock>, PropertyQueryError> {
self.db_tx
.get_best_block_id()
Expand All @@ -188,11 +196,36 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
pub fn get_mainchain_tx_index(
&self,
tx_id: &OutPointSourceId,
) -> Result<Option<common::chain::TxMainChainIndex>, PropertyQueryError> {
) -> Result<Option<TxMainChainIndex>, PropertyQueryError> {
log::trace!("Loading transaction index of id: {:?}", tx_id);
self.db_tx.get_mainchain_tx_index(tx_id).map_err(PropertyQueryError::from)
}

pub fn get_transaction_in_block(
&self,
id: Id<Transaction>,
) -> Result<Option<SignedTransaction>, PropertyQueryError> {
log::trace!("Loading whether tx index is enabled: {}", id);
let is_tx_index_enabled = self.get_is_transaction_index_enabled()?;
if !is_tx_index_enabled {
return Err(PropertyQueryError::TransactionIndexDisabled);
}
log::trace!("Loading transaction index with id: {}", id);
let tx_index = self.db_tx.get_mainchain_tx_index(&OutPointSourceId::Transaction(id))?;
let tx_index = match tx_index {
Some(tx_index) => tx_index,
None => return Ok(None),
};
log::trace!("Loading transaction with id: {}", id);
let position = match tx_index.position() {
common::chain::SpendablePosition::Transaction(pos) => pos,
common::chain::SpendablePosition::BlockReward(_) => {
panic!("In get_transaction(), a tx id led to a block reward")
}
};
Ok(self.db_tx.get_mainchain_tx_by_position(position)?)
}

pub fn get_block_id_by_height(
&self,
height: &BlockHeight,
Expand Down
14 changes: 13 additions & 1 deletion chainstate/src/detail/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use common::{
RPCFungibleTokenInfo, RPCNonFungibleTokenInfo, RPCTokenInfo, TokenAuxiliaryData,
TokenData, TokenId,
},
Block, GenBlock, OutPointSourceId, Transaction, TxMainChainIndex, TxOutput,
Block, GenBlock, OutPointSourceId, SignedTransaction, Transaction, TxMainChainIndex,
TxOutput,
},
primitives::{BlockDistance, BlockHeight, Id, Idable},
};
Expand Down Expand Up @@ -145,6 +146,17 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
}
}

pub fn is_transaction_index_enabled(&self) -> Result<bool, PropertyQueryError> {
self.chainstate_ref.get_is_transaction_index_enabled()
}

pub fn get_transaction_in_block(
&self,
id: Id<Transaction>,
) -> Result<Option<SignedTransaction>, PropertyQueryError> {
self.chainstate_ref.get_transaction_in_block(id)
}

pub fn get_locator(&self) -> Result<Locator, PropertyQueryError> {
let best_block_index = self
.chainstate_ref
Expand Down
7 changes: 6 additions & 1 deletion chainstate/src/interface/chainstate_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{ChainInfo, ChainstateConfig, ChainstateError, ChainstateEvent};
use chainstate_types::{BlockIndex, EpochData, GenBlockIndex, Locator};

use common::chain::block::signed_block_header::SignedBlockHeader;
use common::chain::{AccountNonce, AccountType};
use common::chain::{AccountNonce, AccountType, SignedTransaction};
use common::{
chain::{
block::{timestamp::BlockTimestamp, Block, BlockReward, GenBlock},
Expand Down Expand Up @@ -115,6 +115,11 @@ pub trait ChainstateInterface: Send {
&self,
starting_block: &Id<GenBlock>,
) -> Result<BlockTimestamp, ChainstateError>;
fn is_transaction_index_enabled(&self) -> Result<bool, ChainstateError>;
fn get_transaction(
&self,
tx_id: &Id<Transaction>,
) -> Result<Option<SignedTransaction>, ChainstateError>;
fn is_already_an_orphan(&self, block_id: &Id<Block>) -> bool;
fn orphans_count(&self) -> usize;
fn get_ancestor(
Expand Down
23 changes: 21 additions & 2 deletions chainstate/src/interface/chainstate_interface_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use common::{
block::{signed_block_header::SignedBlockHeader, Block, BlockReward, GenBlock},
config::ChainConfig,
tokens::{RPCTokenInfo, TokenAuxiliaryData, TokenId},
AccountNonce, AccountType, DelegationId, OutPointSourceId, PoolId, Transaction, TxInput,
TxMainChainIndex, TxOutput, UtxoOutPoint,
AccountNonce, AccountType, DelegationId, OutPointSourceId, PoolId, SignedTransaction,
Transaction, TxInput, TxMainChainIndex, TxOutput, UtxoOutPoint,
},
primitives::{id::WithId, Amount, BlockHeight, Id},
};
Expand Down Expand Up @@ -579,6 +579,25 @@ impl<S: BlockchainStorage, V: TransactionVerificationStrategy> ChainstateInterfa
.get_account_nonce_count(account)
.map_err(ChainstateError::FailedToReadProperty)
}

fn is_transaction_index_enabled(&self) -> Result<bool, ChainstateError> {
self.chainstate
.query()
.map_err(ChainstateError::from)?
.is_transaction_index_enabled()
.map_err(ChainstateError::FailedToReadProperty)
}

fn get_transaction(
&self,
tx_id: &Id<Transaction>,
) -> Result<Option<SignedTransaction>, ChainstateError> {
self.chainstate
.query()
.map_err(ChainstateError::from)?
.get_transaction_in_block(*tx_id)
.map_err(ChainstateError::from)
}
}

// TODO: remove this function. The value of an output cannot be generalized and exposed from ChainstateInterface in such way
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use common::chain::{
block::{signed_block_header::SignedBlockHeader, timestamp::BlockTimestamp, BlockReward},
config::ChainConfig,
tokens::TokenAuxiliaryData,
AccountNonce, AccountType, OutPointSourceId, TxMainChainIndex,
AccountNonce, AccountType, OutPointSourceId, SignedTransaction, TxMainChainIndex,
};
use common::chain::{Transaction, UtxoOutPoint};
use common::{
Expand Down Expand Up @@ -342,6 +342,17 @@ where
) -> Result<Option<AccountNonce>, ChainstateError> {
self.deref().get_account_nonce_count(account)
}

fn is_transaction_index_enabled(&self) -> Result<bool, ChainstateError> {
self.deref().is_transaction_index_enabled()
}

fn get_transaction(
&self,
tx_id: &Id<Transaction>,
) -> Result<Option<SignedTransaction>, ChainstateError> {
self.deref().get_transaction(tx_id)
}
}

#[cfg(test)]
Expand Down
42 changes: 40 additions & 2 deletions chainstate/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ use crate::{Block, BlockSource, ChainInfo, GenBlock};
use common::{
chain::{
tokens::{RPCTokenInfo, TokenId},
PoolId,
PoolId, SignedTransaction, Transaction,
},
primitives::{Amount, BlockHeight, Id},
};
use rpc::Result as RpcResult;
use serialization::hex_encoded::HexEncoded;
use serialization::{hex_encoded::HexEncoded, json_encoded::JsonEncoded};

#[rpc::rpc(server, client, namespace = "chainstate")]
trait ChainstateRpc {
Expand All @@ -42,6 +42,23 @@ trait ChainstateRpc {
#[method(name = "get_block")]
async fn get_block(&self, id: Id<Block>) -> RpcResult<Option<HexEncoded<Block>>>;

/// Returns a json-encoded serialized block with the given id.
#[method(name = "get_block_json")]
async fn get_block_json(&self, id: Id<Block>) -> RpcResult<Option<String>>;

/// returns a hex-encoded transaction, assuming it's in the mainchain.
/// Note: The transaction index must be enabled in the node.
#[method(name = "get_transaction")]
async fn get_transaction(
&self,
id: Id<Transaction>,
) -> RpcResult<Option<HexEncoded<SignedTransaction>>>;

/// returns a json-encoded transaction, assuming it's in the mainchain.
/// Note: The transaction index must be enabled in the node.
#[method(name = "get_transaction_json")]
async fn get_transaction_json(&self, id: Id<Transaction>) -> RpcResult<Option<String>>;

/// Returns a hex-encoded serialized blocks from the mainchain starting from a given block height.
#[method(name = "get_mainchain_blocks")]
async fn get_mainchain_blocks(
Expand Down Expand Up @@ -117,6 +134,27 @@ impl ChainstateRpcServer for super::ChainstateHandle {
Ok(block.map(HexEncoded::new))
}

async fn get_block_json(&self, id: Id<Block>) -> RpcResult<Option<String>> {
let block: Option<Block> =
rpc::handle_result(self.call(move |this| this.get_block(id)).await)?;
Ok(block.map(JsonEncoded::new).map(|blk| blk.to_string()))
}

async fn get_transaction(
&self,
id: Id<Transaction>,
) -> RpcResult<Option<HexEncoded<SignedTransaction>>> {
let tx: Option<SignedTransaction> =
rpc::handle_result(self.call(move |this| this.get_transaction(&id)).await)?;
Ok(tx.map(HexEncoded::new))
}

async fn get_transaction_json(&self, id: Id<Transaction>) -> RpcResult<Option<String>> {
let tx: Option<SignedTransaction> =
rpc::handle_result(self.call(move |this| this.get_transaction(&id)).await)?;
Ok(tx.map(JsonEncoded::new).map(|tx| tx.to_string()))
}

async fn get_mainchain_blocks(
&self,
from: BlockHeight,
Expand Down
4 changes: 2 additions & 2 deletions chainstate/storage/src/internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use common::{
tokens::{TokenAuxiliaryData, TokenId},
transaction::{Transaction, TxMainChainIndex, TxMainChainPosition},
AccountNonce, AccountType, Block, ChainConfig, DelegationId, GenBlock, OutPointSourceId,
PoolId, UtxoOutPoint,
PoolId, SignedTransaction, UtxoOutPoint,
},
primitives::{Amount, BlockHeight, Id},
};
Expand Down Expand Up @@ -245,7 +245,7 @@ impl<B: storage::Backend> BlockchainStorageRead for Store<B> {
fn get_mainchain_tx_by_position(
&self,
tx_index: &TxMainChainPosition,
) -> crate::Result<Option<Transaction>>;
) -> crate::Result<Option<SignedTransaction>>;

fn get_block_id_by_height(
&self,
Expand Down
6 changes: 3 additions & 3 deletions chainstate/storage/src/internal/store_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use common::{
tokens::{TokenAuxiliaryData, TokenId},
transaction::{Transaction, TxMainChainIndex, TxMainChainPosition},
AccountNonce, AccountType, Block, DelegationId, GenBlock, OutPointSourceId, PoolId,
UtxoOutPoint,
SignedTransaction, UtxoOutPoint,
},
primitives::{Amount, BlockHeight, Id, Idable, H256},
};
Expand Down Expand Up @@ -143,7 +143,7 @@ macro_rules! impl_read_ops {
fn get_mainchain_tx_by_position(
&self,
tx_index: &TxMainChainPosition,
) -> crate::Result<Option<Transaction>> {
) -> crate::Result<Option<SignedTransaction>> {
let block_id = tx_index.block_id();
match self.0.get::<db::DBBlock, _>().get(block_id) {
Err(e) => Err(e.into()),
Expand All @@ -153,7 +153,7 @@ macro_rules! impl_read_ops {
let begin = tx_index.byte_offset_in_block() as usize;
let encoded_tx =
block.get(begin..).expect("Transaction outside of block range");
let tx = Transaction::decode(&mut &*encoded_tx)
let tx = SignedTransaction::decode(&mut &*encoded_tx)
.expect("Invalid tx encoding in DB");
Ok(Some(tx))
}
Expand Down
10 changes: 6 additions & 4 deletions chainstate/storage/src/internal/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,18 @@ fn test_storage_manipulation() {
// Prepare some test data
let tx0 = Transaction::new(0xaabbccdd, vec![], vec![]).unwrap();
let tx1 = Transaction::new(0xbbccddee, vec![], vec![]).unwrap();
let signed_tx0 = SignedTransaction::new(tx0.clone(), vec![]).expect("invalid witness count");
let signed_tx1 = SignedTransaction::new(tx1.clone(), vec![]).expect("invalid witness count");
let block0 = Block::new(
vec![SignedTransaction::new(tx0.clone(), vec![]).expect("invalid witness count")],
vec![signed_tx0.clone()],
Id::new(H256::default()),
BlockTimestamp::from_int_seconds(12),
ConsensusData::None,
BlockReward::new(Vec::new()),
)
.unwrap();
let block1 = Block::new(
vec![SignedTransaction::new(tx1.clone(), vec![]).expect("invalid witness count")],
vec![signed_tx1],
Id::new(block0.get_id().get()),
BlockTimestamp::from_int_seconds(34),
ConsensusData::None,
Expand Down Expand Up @@ -114,7 +116,7 @@ fn test_storage_manipulation() {
let pos_tx0 = TxMainChainPosition::new(block0.get_id(), offset_tx0 as u32);
assert_eq!(
&store.get_mainchain_tx_by_position(&pos_tx0).unwrap().unwrap(),
&tx0
&signed_tx0
);

// Test setting and retrieving best chain id
Expand Down Expand Up @@ -144,7 +146,7 @@ fn test_storage_manipulation() {
);
if let Ok(Some(index)) = store.get_mainchain_tx_index(&out_id_tx0) {
if let SpendablePosition::Transaction(ref p) = index.position() {
assert_eq!(store.get_mainchain_tx_by_position(p), Ok(Some(tx0)));
assert_eq!(store.get_mainchain_tx_by_position(p), Ok(Some(signed_tx0)));
} else {
unreachable!();
};
Expand Down
6 changes: 4 additions & 2 deletions chainstate/storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ use common::chain::block::BlockReward;
use common::chain::config::EpochIndex;
use common::chain::tokens::{TokenAuxiliaryData, TokenId};
use common::chain::transaction::{Transaction, TxMainChainIndex, TxMainChainPosition};
use common::chain::{AccountNonce, AccountType, Block, GenBlock, OutPointSourceId};
use common::chain::{
AccountNonce, AccountType, Block, GenBlock, OutPointSourceId, SignedTransaction,
};
use common::primitives::{BlockHeight, Id};
use pos_accounting::{
AccountingBlockUndo, DeltaMergeUndo, PoSAccountingDeltaData, PoSAccountingStorageRead,
Expand Down Expand Up @@ -93,7 +95,7 @@ pub trait BlockchainStorageRead:
fn get_mainchain_tx_by_position(
&self,
tx_index: &TxMainChainPosition,
) -> crate::Result<Option<Transaction>>;
) -> crate::Result<Option<SignedTransaction>>;

/// Get mainchain block by its height
fn get_block_id_by_height(&self, height: &BlockHeight) -> crate::Result<Option<Id<GenBlock>>>;
Expand Down
9 changes: 5 additions & 4 deletions chainstate/storage/src/mock/mock_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ use common::{
block::BlockReward,
config::EpochIndex,
transaction::{OutPointSourceId, Transaction, TxMainChainIndex, TxMainChainPosition},
AccountNonce, AccountType, Block, DelegationId, GenBlock, PoolId, UtxoOutPoint,
AccountNonce, AccountType, Block, DelegationId, GenBlock, PoolId, SignedTransaction,
UtxoOutPoint,
},
primitives::{Amount, BlockHeight, Id},
};
Expand Down Expand Up @@ -64,7 +65,7 @@ mockall::mock! {
fn get_mainchain_tx_by_position(
&self,
tx_index: &TxMainChainPosition,
) -> crate::Result<Option<Transaction>>;
) -> crate::Result<Option<SignedTransaction>>;

fn get_block_id_by_height(
&self,
Expand Down Expand Up @@ -320,7 +321,7 @@ mockall::mock! {
fn get_mainchain_tx_by_position(
&self,
tx_index: &TxMainChainPosition,
) -> crate::Result<Option<Transaction>>;
) -> crate::Result<Option<SignedTransaction>>;

fn get_block_id_by_height(
&self,
Expand Down Expand Up @@ -435,7 +436,7 @@ mockall::mock! {
fn get_mainchain_tx_by_position(
&self,
tx_index: &TxMainChainPosition,
) -> crate::Result<Option<Transaction>>;
) -> crate::Result<Option<SignedTransaction>>;

fn get_block_id_by_height(
&self,
Expand Down
Loading