Skip to content
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
35 changes: 31 additions & 4 deletions src/new_index/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,45 @@ impl Mempool {
.any(|txin| self.txstore.contains_key(&txin.previous_output.txid))
}

pub fn history(&self, scripthash: &[u8], limit: usize) -> Vec<Transaction> {
pub fn history(
&self,
scripthash: &[u8],
last_seen_txid: Option<&Txid>,
limit: usize,
) -> Vec<Transaction> {
let _timer = self.latency.with_label_values(&["history"]).start_timer();
self.history.get(scripthash).map_or_else(
|| vec![],
|entries| self._history(entries, last_seen_txid, limit),
)
}

pub fn history_txids_iter<'a>(&'a self, scripthash: &[u8]) -> impl Iterator<Item = Txid> + 'a {
self.history
.get(scripthash)
.map_or_else(|| vec![], |entries| self._history(entries, limit))
.into_iter()
.flat_map(|v| v.iter().map(|e| e.get_txid()).unique())
}

fn _history(&self, entries: &[TxHistoryInfo], limit: usize) -> Vec<Transaction> {
fn _history(
&self,
entries: &[TxHistoryInfo],
last_seen_txid: Option<&Txid>,
limit: usize,
) -> Vec<Transaction> {
entries
.iter()
.map(|e| e.get_txid())
.unique()
// TODO seek directly to last seen tx without reading earlier rows
.skip_while(|txid| {
// skip until we reach the last_seen_txid
last_seen_txid.map_or(false, |last_seen_txid| last_seen_txid != txid)
})
.skip(match last_seen_txid {
Some(_) => 1, // skip the last_seen_txid itself
None => 0,
})
.take(limit)
.map(|txid| self.txstore.get(&txid).expect("missing mempool tx"))
.cloned()
Expand Down Expand Up @@ -515,7 +542,7 @@ impl Mempool {
.start_timer();
self.asset_history
.get(asset_id)
.map_or_else(|| vec![], |entries| self._history(entries, limit))
.map_or_else(|| vec![], |entries| self._history(entries, None, limit))
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/new_index/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,12 @@ impl ChainQuery {
self._history(b'H', scripthash, last_seen_txid, limit)
}

pub fn history_txids_iter<'a>(&'a self, scripthash: &[u8]) -> impl Iterator<Item = Txid> + 'a {
self.history_iter_scan_reverse(b'H', scripthash)
.map(|row| TxHistoryRow::from_row(row).get_txid())
.unique()
}

fn _history(
&self,
code: u8,
Expand Down
69 changes: 55 additions & 14 deletions src/rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,24 +793,61 @@ fn handle_request(
None,
) => {
let script_hash = to_scripthash(script_type, script_str, config.network_type)?;
let max_txs = query_params
.get("max_txs")
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(CHAIN_TXS_PER_PAGE);
let after_txid = query_params
.get("after_txid")
.and_then(|s| s.parse::<Txid>().ok());

let mut txs = vec![];

if let Some(given_txid) = &after_txid {
let is_mempool = query
.mempool()
.history_txids_iter(&script_hash[..])
.any(|txid| given_txid == &txid);
let is_confirmed = if is_mempool {
false
} else {
query
.chain()
.history_txids_iter(&script_hash[..])
.any(|txid| given_txid == &txid)
};
if !is_mempool && !is_confirmed {
return Err(HttpError(
StatusCode::UNPROCESSABLE_ENTITY,
String::from("after_txid not found"),
));
}
}

txs.extend(
query
.mempool()
.history(&script_hash[..], MAX_MEMPOOL_TXS)
.history(&script_hash[..], after_txid.as_ref(), max_txs)
.into_iter()
.map(|tx| (tx, None)),
);

txs.extend(
query
.chain()
.history(&script_hash[..], None, CHAIN_TXS_PER_PAGE)
.into_iter()
.map(|(tx, blockid)| (tx, Some(blockid))),
);
if txs.len() < max_txs {
let after_txid_ref = if !txs.is_empty() {
// If there are any txs, we know mempool found the
// after_txid IF it exists... so always return None.
None
} else {
after_txid.as_ref()
};
txs.extend(
query
.chain()
.history(&script_hash[..], after_txid_ref, max_txs - txs.len())
.into_iter()
.map(|(tx, blockid)| (tx, Some(blockid))),
);
}

json_maybe_error_response(prepare_txs(txs, query, config), TTL_SHORT)
}
Expand All @@ -833,14 +870,14 @@ fn handle_request(
) => {
let script_hash = to_scripthash(script_type, script_str, config.network_type)?;
let last_seen_txid = last_seen_txid.and_then(|txid| Txid::from_hex(txid).ok());
let max_txs = query_params
.get("max_txs")
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(CHAIN_TXS_PER_PAGE);

let txs = query
.chain()
.history(
&script_hash[..],
last_seen_txid.as_ref(),
CHAIN_TXS_PER_PAGE,
)
.history(&script_hash[..], last_seen_txid.as_ref(), max_txs)
.into_iter()
.map(|(tx, blockid)| (tx, Some(blockid)))
.collect();
Expand All @@ -864,10 +901,14 @@ fn handle_request(
None,
) => {
let script_hash = to_scripthash(script_type, script_str, config.network_type)?;
let max_txs = query_params
.get("max_txs")
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(MAX_MEMPOOL_TXS);

let txs = query
.mempool()
.history(&script_hash[..], MAX_MEMPOOL_TXS)
.history(&script_hash[..], None, max_txs)
.into_iter()
.map(|tx| (tx, None))
.collect();
Expand Down