Skip to content

Commit 03f03af

Browse files
nagarajm22Jouzo
authored andcommitted
WIP: Implementation for ocean-API transaction module (#2781)
* added transaction index * added transaction api implementation * fixed .cpp file formats * fixed id to Txid * added transction list method by block_hash * added transaction indexing * removed transaction by block_hash from trx module * update txid strong type * removed method list_trasnction_txid * added vin and vout index in transaction with query * updated vin and vout table as Txid * fixed conflicts in transaction branch * fixed fmt * Restore cpp fmt --------- Co-authored-by: jouzo <jdesclercs@gmail.com>
1 parent 4ad383c commit 03f03af

12 files changed

Lines changed: 300 additions & 21 deletions

File tree

lib/ain-ocean/src/api/response.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ mod tests {
128128
fn should_next_with_value() {
129129
let items: Vec<Item> = vec![Item::new("0", "a"), Item::new("1", "b")];
130130

131-
let next = ApiPagedResponse::next(items, Some("b")).page.next;
131+
let next = ApiPagedResponse::next(items, Some("b".to_string()))
132+
.page
133+
.next;
132134
assert_eq!(next, Some("b".into()));
133135
}
134136

lib/ain-ocean/src/api/transactions.rs

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,85 @@
1-
use std::sync::Arc;
2-
3-
use axum::{extract::Path, routing::get, Router};
4-
use defichain_rpc::{Client, RpcApi};
1+
use axum::{
2+
extract::{Path, Query},
3+
routing::get,
4+
Json, Router,
5+
};
6+
use bitcoin::Txid;
57
use serde::Deserialize;
68

9+
use crate::{
10+
api_paged_response::ApiPagedResponse,
11+
api_query::PaginationQuery,
12+
model::{Transaction, TransactionVin, TransactionVout},
13+
repository::RepositoryOps,
14+
Result, SERVICES,
15+
};
16+
717
#[derive(Deserialize)]
818
struct TransactionId {
9-
id: String,
19+
id: Txid,
1020
}
1121

12-
async fn get_transaction(Path(TransactionId { id }): Path<TransactionId>) -> String {
13-
format!("Details of transaction with id {}", id)
22+
async fn get_transaction(
23+
Path(TransactionId { id }): Path<TransactionId>,
24+
) -> Result<Json<Option<Transaction>>> {
25+
format!("Details of transaction with id {}", id);
26+
let transactions = SERVICES.transaction.by_id.get(&id)?;
27+
Ok(Json(transactions))
1428
}
1529

16-
async fn get_vins(Path(TransactionId { id }): Path<TransactionId>) -> String {
17-
format!("Vins for transaction with id {}", id)
30+
async fn get_vins(
31+
Query(query): Query<PaginationQuery>,
32+
) -> Result<Json<ApiPagedResponse<TransactionVin>>> {
33+
let transaction_list = SERVICES
34+
.transaction
35+
.vin_by_id
36+
.list(None)?
37+
.take(query.size)
38+
.map(|item| {
39+
let (txid, id) = item?;
40+
let b = SERVICES
41+
.transaction
42+
.vin_by_id
43+
.get(&txid)?
44+
.ok_or("Missing block index")?;
45+
46+
Ok(b)
47+
})
48+
.collect::<Result<Vec<_>>>()?;
49+
50+
Ok(Json(ApiPagedResponse::of(
51+
transaction_list,
52+
query.size,
53+
|transaction_list| transaction_list.id.clone(),
54+
)))
1855
}
1956

20-
async fn get_vouts(Path(TransactionId { id }): Path<TransactionId>) -> String {
21-
format!("Vouts for transaction with id {}", id)
57+
//get list of vout transaction, by passing id which contains txhash + vout_idx
58+
async fn get_vouts(
59+
Query(query): Query<PaginationQuery>,
60+
) -> Result<Json<ApiPagedResponse<TransactionVout>>> {
61+
let transaction_list = SERVICES
62+
.transaction
63+
.vout_by_id
64+
.list(None)?
65+
.take(query.size)
66+
.map(|item| {
67+
let (txid, id) = item?;
68+
let b = SERVICES
69+
.transaction
70+
.vout_by_id
71+
.get(&txid)?
72+
.ok_or("Missing block index")?;
73+
74+
Ok(b)
75+
})
76+
.collect::<Result<Vec<_>>>()?;
77+
78+
Ok(Json(ApiPagedResponse::of(
79+
transaction_list,
80+
query.size,
81+
|transaction_list| transaction_list.id.clone(),
82+
)))
2283
}
2384

2485
pub fn router(state: Arc<Client>) -> Router {

lib/ain-ocean/src/indexer/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod auction;
22
mod masternode;
33
mod oracle;
44
mod pool;
5+
pub mod transaction;
56
pub mod tx_result;
67

78
use defichain_rpc::RpcApi;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use bitcoin::{blockdata::locktime::absolute::LockTime, Txid};
2+
use dftx_rs::{Block, Transaction};
3+
use log::debug;
4+
5+
use super::BlockContext;
6+
use crate::{
7+
indexer::Result,
8+
model::{
9+
Transaction as TrasnactionMapper, TransactionVin, TransactionVinScript, TransactionVinVout,
10+
TransactionVinVoutScript, TransactionVout, TransactionVoutScript,
11+
},
12+
repository::RepositoryOps,
13+
SERVICES,
14+
};
15+
16+
pub fn index_transactions(ctx: &BlockContext, tx: Transaction) -> Result<()> {
17+
debug!("[CreateTransaction] Indexing...");
18+
let tx_id = tx.txid();
19+
20+
let lock_time_as_i32 = match tx.lock_time {
21+
LockTime::Blocks(value) => value.to_consensus_u32(),
22+
LockTime::Seconds(value) => value.to_consensus_u32(),
23+
};
24+
let total_vout_value: u64 = tx.output.iter().map(|output| output.value.to_sat()).sum();
25+
let weight = tx.weight();
26+
let weight_i32 = weight.to_vbytes_ceil() as i32;
27+
28+
let trx = TrasnactionMapper {
29+
id: tx_id,
30+
order: 0,
31+
block: ctx.clone(),
32+
txid: tx_id.to_string(),
33+
hash: ctx.hash.to_string(),
34+
version: tx.version.0,
35+
size: tx.total_size() as i32,
36+
v_size: tx.vsize() as i32,
37+
weight: weight_i32,
38+
total_vout_value: total_vout_value.to_string(),
39+
lock_time: lock_time_as_i32 as i32,
40+
vin_count: tx.input.len() as i32,
41+
vout_count: tx.output.len() as i32,
42+
};
43+
// Index transaction
44+
SERVICES.transaction.by_id.put(&tx_id, &trx)?;
45+
// Indexing transaction vin
46+
for (vin_idx, vin) in tx.input.iter().enumerate() {
47+
let trx_vin = TransactionVin {
48+
id: format!("{}-{}", tx_id, vin_idx),
49+
txid: tx_id.to_string(),
50+
coinbase: vin.script_sig.to_string(),
51+
vout: TransactionVinVout {
52+
id: format!("{}-{}-vout", tx_id, vin_idx),
53+
txid: tx_id.to_string(),
54+
n: vin.previous_output.vout as i32,
55+
value: "0".to_string(),
56+
token_id: 0,
57+
script: TransactionVinVoutScript {
58+
hex: vin.script_sig.to_string(),
59+
},
60+
},
61+
script: TransactionVinScript {
62+
hex: vin.script_sig.to_string(),
63+
},
64+
tx_in_witness: vec![],
65+
sequence: vin.sequence.to_string(),
66+
};
67+
68+
SERVICES.transaction.vin_by_id.put(&tx_id, &trx_vin)?;
69+
}
70+
// Index transaction vout
71+
for (vout_idx, vout) in tx.output.iter().enumerate() {
72+
let trx_vout = TransactionVout {
73+
id: format!("{}-{}", tx_id, vout_idx),
74+
txid: tx_id.to_string(),
75+
n: vout_idx as i32,
76+
value: vout.value.to_string(),
77+
token_id: 0,
78+
script: TransactionVoutScript {
79+
hex: vout.script_pubkey.to_string(),
80+
r#type: "pubkey".to_string(),
81+
},
82+
};
83+
SERVICES.transaction.vout_by_id.put(&tx_id, &trx_vout)?;
84+
// .put(&format!("{}-{}", tx_id, vout_idx), &trx_vout)?; //need
85+
}
86+
87+
Ok(())
88+
}
89+
90+
pub fn invalidate_transaction(ctx: &BlockContext, tx: Txid, idx: usize) -> Result<()> {
91+
debug!("[CreateMasternode] Invalidating...");
92+
SERVICES.transaction.by_id.delete(&tx)?;
93+
Ok(())
94+
}

lib/ain-ocean/src/lib.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@ use std::{path::PathBuf, sync::Arc};
66

77
pub use api::ocean_router;
88
use error::OceanError;
9-
pub use indexer::{index_block, invalidate_block, tx_result, BlockV2Info};
9+
pub use indexer::{
10+
index_block, invalidate_block,
11+
transaction::{index_transactions, invalidate_transaction},
12+
tx_result, BlockV2Info,
13+
};
14+
use model::TransactionVin;
1015
use repository::{
1116
AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository,
1217
BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository,
13-
PoolSwapRepository, RawBlockRepository, TxResultRepository,
18+
PoolSwapRepository, RawBlockRepository, TransactionRepository, TransactionVinRepository,
19+
TransactionVoutRepository, TxResultRepository,
1420
};
1521
pub mod api;
1622
mod model;
@@ -50,13 +56,20 @@ pub struct PoolService {
5056
by_id: PoolSwapRepository,
5157
}
5258

59+
pub struct TransactionService {
60+
by_id: TransactionRepository,
61+
vin_by_id: TransactionVinRepository,
62+
vout_by_id: TransactionVoutRepository,
63+
}
64+
5365
pub struct Services {
5466
masternode: MasternodeService,
5567
block: BlockService,
5668
auction: AuctionService,
5769
result: TxResultRepository,
5870
pool: PoolService,
5971
client: Arc<Client>,
72+
transaction: TransactionService,
6073
}
6174

6275
impl Services {
@@ -89,6 +102,11 @@ impl Services {
89102
pool: PoolService {
90103
by_id: PoolSwapRepository::new(Arc::clone(&store)),
91104
},
105+
transaction: TransactionService {
106+
by_id: TransactionRepository::new(Arc::clone(&store)),
107+
vin_by_id: TransactionVinRepository::new(Arc::clone(&store)),
108+
vout_by_id: TransactionVoutRepository::new(Arc::clone(&store)),
109+
},
92110
client,
93111
})
94112
}

lib/ain-ocean/src/model/transaction.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use bitcoin::Txid;
12
use serde::{Deserialize, Serialize};
23

34
use super::BlockContext;
45

56
#[derive(Serialize, Deserialize, Debug)]
67
#[serde(rename_all = "camelCase")]
78
pub struct Transaction {
8-
pub id: String,
9+
pub id: Txid,
910
pub order: i32,
1011
pub block: BlockContext,
1112
pub txid: String,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,27 @@
1+
use std::sync::Arc;
12

3+
use ain_db::LedgerColumn;
4+
use ain_macros::Repository;
5+
use bitcoin::{BlockHash, Txid};
6+
7+
use super::RepositoryOps;
8+
use crate::{
9+
model::Transaction,
10+
storage::{columns, ocean_store::OceanStore},
11+
Result,
12+
};
13+
#[derive(Repository)]
14+
#[repository(K = "Txid", V = "Transaction")]
15+
pub struct TransactionRepository {
16+
pub store: Arc<OceanStore>,
17+
col: LedgerColumn<columns::Transaction>,
18+
}
19+
20+
impl TransactionRepository {
21+
pub fn new(store: Arc<OceanStore>) -> Self {
22+
Self {
23+
col: store.column(),
24+
store,
25+
}
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
1+
use std::sync::Arc;
12

3+
use ain_db::LedgerColumn;
4+
use ain_macros::Repository;
5+
use bitcoin::Txid;
6+
7+
use super::RepositoryOps;
8+
use crate::{
9+
model::TransactionVin,
10+
storage::{columns, ocean_store::OceanStore},
11+
Result,
12+
};
13+
14+
#[derive(Repository)]
15+
#[repository(K = "Txid", V = "TransactionVin")]
16+
pub struct TransactionVinRepository {
17+
pub store: Arc<OceanStore>,
18+
col: LedgerColumn<columns::TransactionVin>,
19+
}
20+
21+
impl TransactionVinRepository {
22+
pub fn new(store: Arc<OceanStore>) -> Self {
23+
Self {
24+
col: store.column(),
25+
store,
26+
}
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
1+
use std::sync::Arc;
12

3+
use ain_db::LedgerColumn;
4+
use ain_macros::Repository;
5+
use bitcoin::Txid;
6+
7+
use super::RepositoryOps;
8+
use crate::{
9+
model::TransactionVout,
10+
storage::{columns, ocean_store::OceanStore},
11+
Result,
12+
};
13+
14+
#[derive(Repository)]
15+
#[repository(K = "Txid", V = "TransactionVout")]
16+
pub struct TransactionVoutRepository {
17+
pub store: Arc<OceanStore>,
18+
col: LedgerColumn<columns::TransactionVout>,
19+
}
20+
21+
impl TransactionVoutRepository {
22+
pub fn new(store: Arc<OceanStore>) -> Self {
23+
Self {
24+
col: store.column(),
25+
store,
26+
}
27+
}
28+
}
Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use ain_db::{Column, ColumnName, TypedColumn};
2+
use bitcoin::{BlockHash, Txid};
23

4+
use crate::model;
35
#[derive(Debug)]
46
pub struct Transaction;
57

@@ -8,9 +10,23 @@ impl ColumnName for Transaction {
810
}
911

1012
impl Column for Transaction {
11-
type Index = String;
13+
type Index = Txid;
1214
}
1315

1416
impl TypedColumn for Transaction {
15-
type Type = String;
17+
type Type = model::Transaction;
18+
}
19+
20+
pub struct TransactionByBlockHash;
21+
22+
impl ColumnName for TransactionByBlockHash {
23+
const NAME: &'static str = "transaction_by_block_hash";
24+
}
25+
26+
impl Column for TransactionByBlockHash {
27+
type Index = BlockHash;
28+
}
29+
30+
impl TypedColumn for TransactionByBlockHash {
31+
type Type = model::Transaction;
1632
}

0 commit comments

Comments
 (0)