Skip to content

Commit 29ac4c7

Browse files
Merge pull request #1155 from mintlayer/feat/json_blocks
Enable retrieving both transactions and blocks in json format
2 parents ca399d9 + 8443f25 commit 29ac4c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+346
-70
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chainstate/src/detail/chainstateref/mod.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use common::{
3434
tokens::TokenAuxiliaryData,
3535
tokens::{get_tokens_issuance_count, TokenId},
3636
AccountNonce, AccountType, Block, ChainConfig, GenBlock, GenBlockId, OutPointSourceId,
37-
Transaction, TxOutput, UtxoOutPoint,
37+
SignedTransaction, Transaction, TxMainChainIndex, TxOutput, UtxoOutPoint,
3838
},
3939
primitives::{id::WithId, BlockDistance, BlockHeight, Id, Idable},
4040
time_getter::TimeGetter,
@@ -162,6 +162,14 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
162162
self.time_getter.get_time()
163163
}
164164

165+
pub fn get_is_transaction_index_enabled(&self) -> Result<bool, PropertyQueryError> {
166+
Ok(self
167+
.db_tx
168+
.get_is_mainchain_tx_index_enabled()
169+
.map_err(PropertyQueryError::from)?
170+
.expect("Must be set on node initialization"))
171+
}
172+
165173
pub fn get_best_block_id(&self) -> Result<Id<GenBlock>, PropertyQueryError> {
166174
self.db_tx
167175
.get_best_block_id()
@@ -188,11 +196,36 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
188196
pub fn get_mainchain_tx_index(
189197
&self,
190198
tx_id: &OutPointSourceId,
191-
) -> Result<Option<common::chain::TxMainChainIndex>, PropertyQueryError> {
199+
) -> Result<Option<TxMainChainIndex>, PropertyQueryError> {
192200
log::trace!("Loading transaction index of id: {:?}", tx_id);
193201
self.db_tx.get_mainchain_tx_index(tx_id).map_err(PropertyQueryError::from)
194202
}
195203

204+
pub fn get_transaction_in_block(
205+
&self,
206+
id: Id<Transaction>,
207+
) -> Result<Option<SignedTransaction>, PropertyQueryError> {
208+
log::trace!("Loading whether tx index is enabled: {}", id);
209+
let is_tx_index_enabled = self.get_is_transaction_index_enabled()?;
210+
if !is_tx_index_enabled {
211+
return Err(PropertyQueryError::TransactionIndexDisabled);
212+
}
213+
log::trace!("Loading transaction index with id: {}", id);
214+
let tx_index = self.db_tx.get_mainchain_tx_index(&OutPointSourceId::Transaction(id))?;
215+
let tx_index = match tx_index {
216+
Some(tx_index) => tx_index,
217+
None => return Ok(None),
218+
};
219+
log::trace!("Loading transaction with id: {}", id);
220+
let position = match tx_index.position() {
221+
common::chain::SpendablePosition::Transaction(pos) => pos,
222+
common::chain::SpendablePosition::BlockReward(_) => {
223+
panic!("In get_transaction(), a tx id led to a block reward")
224+
}
225+
};
226+
Ok(self.db_tx.get_mainchain_tx_by_position(position)?)
227+
}
228+
196229
pub fn get_block_id_by_height(
197230
&self,
198231
height: &BlockHeight,

chainstate/src/detail/query.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ use common::{
2222
RPCFungibleTokenInfo, RPCNonFungibleTokenInfo, RPCTokenInfo, TokenAuxiliaryData,
2323
TokenData, TokenId,
2424
},
25-
Block, GenBlock, OutPointSourceId, Transaction, TxMainChainIndex, TxOutput,
25+
Block, GenBlock, OutPointSourceId, SignedTransaction, Transaction, TxMainChainIndex,
26+
TxOutput,
2627
},
2728
primitives::{BlockDistance, BlockHeight, Id, Idable},
2829
};
@@ -145,6 +146,17 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
145146
}
146147
}
147148

149+
pub fn is_transaction_index_enabled(&self) -> Result<bool, PropertyQueryError> {
150+
self.chainstate_ref.get_is_transaction_index_enabled()
151+
}
152+
153+
pub fn get_transaction_in_block(
154+
&self,
155+
id: Id<Transaction>,
156+
) -> Result<Option<SignedTransaction>, PropertyQueryError> {
157+
self.chainstate_ref.get_transaction_in_block(id)
158+
}
159+
148160
pub fn get_locator(&self) -> Result<Locator, PropertyQueryError> {
149161
let best_block_index = self
150162
.chainstate_ref

chainstate/src/interface/chainstate_interface.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{ChainInfo, ChainstateConfig, ChainstateError, ChainstateEvent};
2222
use chainstate_types::{BlockIndex, EpochData, GenBlockIndex, Locator};
2323

2424
use common::chain::block::signed_block_header::SignedBlockHeader;
25-
use common::chain::{AccountNonce, AccountType};
25+
use common::chain::{AccountNonce, AccountType, SignedTransaction};
2626
use common::{
2727
chain::{
2828
block::{timestamp::BlockTimestamp, Block, BlockReward, GenBlock},
@@ -115,6 +115,11 @@ pub trait ChainstateInterface: Send {
115115
&self,
116116
starting_block: &Id<GenBlock>,
117117
) -> Result<BlockTimestamp, ChainstateError>;
118+
fn is_transaction_index_enabled(&self) -> Result<bool, ChainstateError>;
119+
fn get_transaction(
120+
&self,
121+
tx_id: &Id<Transaction>,
122+
) -> Result<Option<SignedTransaction>, ChainstateError>;
118123
fn is_already_an_orphan(&self, block_id: &Id<Block>) -> bool;
119124
fn orphans_count(&self) -> usize;
120125
fn get_ancestor(

chainstate/src/interface/chainstate_interface_impl.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use common::{
3232
block::{signed_block_header::SignedBlockHeader, Block, BlockReward, GenBlock},
3333
config::ChainConfig,
3434
tokens::{RPCTokenInfo, TokenAuxiliaryData, TokenId},
35-
AccountNonce, AccountType, DelegationId, OutPointSourceId, PoolId, Transaction, TxInput,
36-
TxMainChainIndex, TxOutput, UtxoOutPoint,
35+
AccountNonce, AccountType, DelegationId, OutPointSourceId, PoolId, SignedTransaction,
36+
Transaction, TxInput, TxMainChainIndex, TxOutput, UtxoOutPoint,
3737
},
3838
primitives::{id::WithId, Amount, BlockHeight, Id},
3939
};
@@ -579,6 +579,25 @@ impl<S: BlockchainStorage, V: TransactionVerificationStrategy> ChainstateInterfa
579579
.get_account_nonce_count(account)
580580
.map_err(ChainstateError::FailedToReadProperty)
581581
}
582+
583+
fn is_transaction_index_enabled(&self) -> Result<bool, ChainstateError> {
584+
self.chainstate
585+
.query()
586+
.map_err(ChainstateError::from)?
587+
.is_transaction_index_enabled()
588+
.map_err(ChainstateError::FailedToReadProperty)
589+
}
590+
591+
fn get_transaction(
592+
&self,
593+
tx_id: &Id<Transaction>,
594+
) -> Result<Option<SignedTransaction>, ChainstateError> {
595+
self.chainstate
596+
.query()
597+
.map_err(ChainstateError::from)?
598+
.get_transaction_in_block(*tx_id)
599+
.map_err(ChainstateError::from)
600+
}
582601
}
583602

584603
// TODO: remove this function. The value of an output cannot be generalized and exposed from ChainstateInterface in such way

chainstate/src/interface/chainstate_interface_impl_delegation.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use common::chain::{
2525
block::{signed_block_header::SignedBlockHeader, timestamp::BlockTimestamp, BlockReward},
2626
config::ChainConfig,
2727
tokens::TokenAuxiliaryData,
28-
AccountNonce, AccountType, OutPointSourceId, TxMainChainIndex,
28+
AccountNonce, AccountType, OutPointSourceId, SignedTransaction, TxMainChainIndex,
2929
};
3030
use common::chain::{Transaction, UtxoOutPoint};
3131
use common::{
@@ -342,6 +342,17 @@ where
342342
) -> Result<Option<AccountNonce>, ChainstateError> {
343343
self.deref().get_account_nonce_count(account)
344344
}
345+
346+
fn is_transaction_index_enabled(&self) -> Result<bool, ChainstateError> {
347+
self.deref().is_transaction_index_enabled()
348+
}
349+
350+
fn get_transaction(
351+
&self,
352+
tx_id: &Id<Transaction>,
353+
) -> Result<Option<SignedTransaction>, ChainstateError> {
354+
self.deref().get_transaction(tx_id)
355+
}
345356
}
346357

347358
#[cfg(test)]

chainstate/src/rpc.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ use crate::{Block, BlockSource, ChainInfo, GenBlock};
2121
use common::{
2222
chain::{
2323
tokens::{RPCTokenInfo, TokenId},
24-
PoolId,
24+
PoolId, SignedTransaction, Transaction,
2525
},
2626
primitives::{Amount, BlockHeight, Id},
2727
};
2828
use rpc::Result as RpcResult;
29-
use serialization::hex_encoded::HexEncoded;
29+
use serialization::{hex_encoded::HexEncoded, json_encoded::JsonEncoded};
3030

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

45+
/// Returns a json-encoded serialized block with the given id.
46+
#[method(name = "get_block_json")]
47+
async fn get_block_json(&self, id: Id<Block>) -> RpcResult<Option<String>>;
48+
49+
/// returns a hex-encoded transaction, assuming it's in the mainchain.
50+
/// Note: The transaction index must be enabled in the node.
51+
#[method(name = "get_transaction")]
52+
async fn get_transaction(
53+
&self,
54+
id: Id<Transaction>,
55+
) -> RpcResult<Option<HexEncoded<SignedTransaction>>>;
56+
57+
/// returns a json-encoded transaction, assuming it's in the mainchain.
58+
/// Note: The transaction index must be enabled in the node.
59+
#[method(name = "get_transaction_json")]
60+
async fn get_transaction_json(&self, id: Id<Transaction>) -> RpcResult<Option<String>>;
61+
4562
/// Returns a hex-encoded serialized blocks from the mainchain starting from a given block height.
4663
#[method(name = "get_mainchain_blocks")]
4764
async fn get_mainchain_blocks(
@@ -117,6 +134,27 @@ impl ChainstateRpcServer for super::ChainstateHandle {
117134
Ok(block.map(HexEncoded::new))
118135
}
119136

137+
async fn get_block_json(&self, id: Id<Block>) -> RpcResult<Option<String>> {
138+
let block: Option<Block> =
139+
rpc::handle_result(self.call(move |this| this.get_block(id)).await)?;
140+
Ok(block.map(JsonEncoded::new).map(|blk| blk.to_string()))
141+
}
142+
143+
async fn get_transaction(
144+
&self,
145+
id: Id<Transaction>,
146+
) -> RpcResult<Option<HexEncoded<SignedTransaction>>> {
147+
let tx: Option<SignedTransaction> =
148+
rpc::handle_result(self.call(move |this| this.get_transaction(&id)).await)?;
149+
Ok(tx.map(HexEncoded::new))
150+
}
151+
152+
async fn get_transaction_json(&self, id: Id<Transaction>) -> RpcResult<Option<String>> {
153+
let tx: Option<SignedTransaction> =
154+
rpc::handle_result(self.call(move |this| this.get_transaction(&id)).await)?;
155+
Ok(tx.map(JsonEncoded::new).map(|tx| tx.to_string()))
156+
}
157+
120158
async fn get_mainchain_blocks(
121159
&self,
122160
from: BlockHeight,

chainstate/storage/src/internal/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use common::{
2323
tokens::{TokenAuxiliaryData, TokenId},
2424
transaction::{Transaction, TxMainChainIndex, TxMainChainPosition},
2525
AccountNonce, AccountType, Block, ChainConfig, DelegationId, GenBlock, OutPointSourceId,
26-
PoolId, UtxoOutPoint,
26+
PoolId, SignedTransaction, UtxoOutPoint,
2727
},
2828
primitives::{Amount, BlockHeight, Id},
2929
};
@@ -245,7 +245,7 @@ impl<B: storage::Backend> BlockchainStorageRead for Store<B> {
245245
fn get_mainchain_tx_by_position(
246246
&self,
247247
tx_index: &TxMainChainPosition,
248-
) -> crate::Result<Option<Transaction>>;
248+
) -> crate::Result<Option<SignedTransaction>>;
249249

250250
fn get_block_id_by_height(
251251
&self,

chainstate/storage/src/internal/store_tx.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use common::{
2222
tokens::{TokenAuxiliaryData, TokenId},
2323
transaction::{Transaction, TxMainChainIndex, TxMainChainPosition},
2424
AccountNonce, AccountType, Block, DelegationId, GenBlock, OutPointSourceId, PoolId,
25-
UtxoOutPoint,
25+
SignedTransaction, UtxoOutPoint,
2626
},
2727
primitives::{Amount, BlockHeight, Id, Idable, H256},
2828
};
@@ -143,7 +143,7 @@ macro_rules! impl_read_ops {
143143
fn get_mainchain_tx_by_position(
144144
&self,
145145
tx_index: &TxMainChainPosition,
146-
) -> crate::Result<Option<Transaction>> {
146+
) -> crate::Result<Option<SignedTransaction>> {
147147
let block_id = tx_index.block_id();
148148
match self.0.get::<db::DBBlock, _>().get(block_id) {
149149
Err(e) => Err(e.into()),
@@ -153,7 +153,7 @@ macro_rules! impl_read_ops {
153153
let begin = tx_index.byte_offset_in_block() as usize;
154154
let encoded_tx =
155155
block.get(begin..).expect("Transaction outside of block range");
156-
let tx = Transaction::decode(&mut &*encoded_tx)
156+
let tx = SignedTransaction::decode(&mut &*encoded_tx)
157157
.expect("Invalid tx encoding in DB");
158158
Ok(Some(tx))
159159
}

chainstate/storage/src/internal/test.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,18 @@ fn test_storage_manipulation() {
5252
// Prepare some test data
5353
let tx0 = Transaction::new(0xaabbccdd, vec![], vec![]).unwrap();
5454
let tx1 = Transaction::new(0xbbccddee, vec![], vec![]).unwrap();
55+
let signed_tx0 = SignedTransaction::new(tx0.clone(), vec![]).expect("invalid witness count");
56+
let signed_tx1 = SignedTransaction::new(tx1.clone(), vec![]).expect("invalid witness count");
5557
let block0 = Block::new(
56-
vec![SignedTransaction::new(tx0.clone(), vec![]).expect("invalid witness count")],
58+
vec![signed_tx0.clone()],
5759
Id::new(H256::default()),
5860
BlockTimestamp::from_int_seconds(12),
5961
ConsensusData::None,
6062
BlockReward::new(Vec::new()),
6163
)
6264
.unwrap();
6365
let block1 = Block::new(
64-
vec![SignedTransaction::new(tx1.clone(), vec![]).expect("invalid witness count")],
66+
vec![signed_tx1],
6567
Id::new(block0.get_id().get()),
6668
BlockTimestamp::from_int_seconds(34),
6769
ConsensusData::None,
@@ -114,7 +116,7 @@ fn test_storage_manipulation() {
114116
let pos_tx0 = TxMainChainPosition::new(block0.get_id(), offset_tx0 as u32);
115117
assert_eq!(
116118
&store.get_mainchain_tx_by_position(&pos_tx0).unwrap().unwrap(),
117-
&tx0
119+
&signed_tx0
118120
);
119121

120122
// Test setting and retrieving best chain id
@@ -144,7 +146,7 @@ fn test_storage_manipulation() {
144146
);
145147
if let Ok(Some(index)) = store.get_mainchain_tx_index(&out_id_tx0) {
146148
if let SpendablePosition::Transaction(ref p) = index.position() {
147-
assert_eq!(store.get_mainchain_tx_by_position(p), Ok(Some(tx0)));
149+
assert_eq!(store.get_mainchain_tx_by_position(p), Ok(Some(signed_tx0)));
148150
} else {
149151
unreachable!();
150152
};

chainstate/storage/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ use common::chain::block::BlockReward;
3131
use common::chain::config::EpochIndex;
3232
use common::chain::tokens::{TokenAuxiliaryData, TokenId};
3333
use common::chain::transaction::{Transaction, TxMainChainIndex, TxMainChainPosition};
34-
use common::chain::{AccountNonce, AccountType, Block, GenBlock, OutPointSourceId};
34+
use common::chain::{
35+
AccountNonce, AccountType, Block, GenBlock, OutPointSourceId, SignedTransaction,
36+
};
3537
use common::primitives::{BlockHeight, Id};
3638
use pos_accounting::{
3739
AccountingBlockUndo, DeltaMergeUndo, PoSAccountingDeltaData, PoSAccountingStorageRead,
@@ -93,7 +95,7 @@ pub trait BlockchainStorageRead:
9395
fn get_mainchain_tx_by_position(
9496
&self,
9597
tx_index: &TxMainChainPosition,
96-
) -> crate::Result<Option<Transaction>>;
98+
) -> crate::Result<Option<SignedTransaction>>;
9799

98100
/// Get mainchain block by its height
99101
fn get_block_id_by_height(&self, height: &BlockHeight) -> crate::Result<Option<Id<GenBlock>>>;

chainstate/storage/src/mock/mock_impl.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use common::{
2525
block::BlockReward,
2626
config::EpochIndex,
2727
transaction::{OutPointSourceId, Transaction, TxMainChainIndex, TxMainChainPosition},
28-
AccountNonce, AccountType, Block, DelegationId, GenBlock, PoolId, UtxoOutPoint,
28+
AccountNonce, AccountType, Block, DelegationId, GenBlock, PoolId, SignedTransaction,
29+
UtxoOutPoint,
2930
},
3031
primitives::{Amount, BlockHeight, Id},
3132
};
@@ -64,7 +65,7 @@ mockall::mock! {
6465
fn get_mainchain_tx_by_position(
6566
&self,
6667
tx_index: &TxMainChainPosition,
67-
) -> crate::Result<Option<Transaction>>;
68+
) -> crate::Result<Option<SignedTransaction>>;
6869

6970
fn get_block_id_by_height(
7071
&self,
@@ -320,7 +321,7 @@ mockall::mock! {
320321
fn get_mainchain_tx_by_position(
321322
&self,
322323
tx_index: &TxMainChainPosition,
323-
) -> crate::Result<Option<Transaction>>;
324+
) -> crate::Result<Option<SignedTransaction>>;
324325

325326
fn get_block_id_by_height(
326327
&self,
@@ -435,7 +436,7 @@ mockall::mock! {
435436
fn get_mainchain_tx_by_position(
436437
&self,
437438
tx_index: &TxMainChainPosition,
438-
) -> crate::Result<Option<Transaction>>;
439+
) -> crate::Result<Option<SignedTransaction>>;
439440

440441
fn get_block_id_by_height(
441442
&self,

0 commit comments

Comments
 (0)