Skip to content

Commit 5dfe714

Browse files
authored
Merge branch 'mempool' into docker_build
2 parents aca3509 + 682b10b commit 5dfe714

File tree

10 files changed

+7284
-8979
lines changed

10 files changed

+7284
-8979
lines changed

contrib/popular-scripts.txt

Lines changed: 7167 additions & 8952 deletions
Large diffs are not rendered by default.

electrs-start-liquid

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
#source "${HOME}/.cargo/env"
33
#export PATH="${HOME}/.cargo/bin:${PATH}"
44

5+
# don't bother making electrs.core files
6+
ulimit -c
7+
8+
# get credentials from elements.conf directly
59
ELEMENTS_RPC_USER=$(grep 'rpcuser=' ${HOME}/elements.conf|cut -d = -f2|head -1)
610
ELEMENTS_RPC_PASS=$(grep 'rpcpassword=' ${HOME}/elements.conf|cut -d = -f2|head -1)
711

12+
# run in loop in case of crash
813
until false
914
do
1015
cd "${HOME}/electrs"

electrs-start-liquidtestnet

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
#source "${HOME}/.cargo/env"
33
#export PATH="${HOME}/.cargo/bin:${PATH}"
44

5+
# don't bother making electrs.core files
6+
ulimit -c
7+
8+
# get credentials from elements.conf directly
59
ELEMENTS_RPC_USER=$(grep 'rpcuser=' "${HOME}/elements.conf"|cut -d = -f2|head -1)
610
ELEMENTS_RPC_PASS=$(grep 'rpcpassword=' "${HOME}/elements.conf"|cut -d = -f2|head -1)
711

12+
# run in loop in case of crash
813
until false
914
do
1015
cd "${HOME}/electrs"

electrs-start-mainnet

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
#source "${HOME}/.cargo/env"
33
#export PATH="${HOME}/.cargo/bin:${PATH}"
44

5+
# don't bother making electrs.core files
6+
ulimit -c
7+
8+
# get credentials from bitcoin.conf directly
59
BITCOIN_RPC_USER=$(grep 'rpcuser=' ${HOME}/bitcoin.conf|cut -d = -f2|head -1)
610
BITCOIN_RPC_PASS=$(grep 'rpcpassword=' ${HOME}/bitcoin.conf|cut -d = -f2|head -1)
711

12+
# run in loop in case of crash
813
until false
914
do
1015
cd "${HOME}/electrs"

electrs-start-signet

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
#source "${HOME}/.cargo/env"
33
#export PATH="${HOME}/.cargo/bin:${PATH}"
44

5+
# don't bother making electrs.core files
6+
ulimit -c
7+
8+
# get credentials from bitcoin.conf directly
59
BITCOIN_RPC_USER=$(grep 'rpcuser=' "${HOME}/bitcoin.conf"|cut -d = -f2|head -1)
610
BITCOIN_RPC_PASS=$(grep 'rpcpassword=' "${HOME}/bitcoin.conf"|cut -d = -f2|head -1)
711

12+
# run in loop in case of crash
813
until false
914
do
1015
cd "${HOME}/electrs"

electrs-start-testnet

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
#source "${HOME}/.cargo/env"
33
#export PATH="${HOME}/.cargo/bin:${PATH}"
44

5+
# don't bother making electrs.core files
6+
ulimit -c
7+
8+
# get credentials from bitcoin.conf directly
59
BITCOIN_RPC_USER=$(grep 'rpcuser=' ${HOME}/bitcoin.conf|cut -d = -f2|head -1)
610
BITCOIN_RPC_PASS=$(grep 'rpcpassword=' ${HOME}/bitcoin.conf|cut -d = -f2|head -1)
711

12+
# run in loop in case of crash
813
until false
914
do
1015
cd "${HOME}/electrs"

src/elements/asset.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::collections::{HashMap, HashSet};
2-
use std::sync::{Arc, RwLock};
2+
use std::sync::{Arc, RwLock, RwLockReadGuard};
33

44
use bitcoin::hashes::{hex::FromHex, sha256, Hash};
55
use elements::confidential::{Asset, Value};
@@ -345,9 +345,14 @@ fn asset_history_row(
345345
TxHistoryRow { key }
346346
}
347347

348+
pub enum AssetRegistryLock<'a> {
349+
RwLock(&'a Arc<RwLock<AssetRegistry>>),
350+
RwLockReadGuard(&'a RwLockReadGuard<'a, AssetRegistry>),
351+
}
352+
348353
pub fn lookup_asset(
349354
query: &Query,
350-
registry: Option<&Arc<RwLock<AssetRegistry>>>,
355+
registry: Option<AssetRegistryLock>,
351356
asset_id: &AssetId,
352357
meta: Option<&AssetMeta>, // may optionally be provided if already known
353358
) -> Result<Option<LiquidAsset>> {
@@ -362,7 +367,8 @@ pub fn lookup_asset(
362367
}
363368

364369
let history_db = query.chain().store().history_db();
365-
let mempool_issuances = &query.mempool().asset_issuance;
370+
let mempool = query.mempool();
371+
let mempool_issuances = &mempool.asset_issuance;
366372

367373
let chain_row = history_db
368374
.get(&[b"i", &asset_id.into_inner()[..]].concat())
@@ -375,11 +381,14 @@ pub fn lookup_asset(
375381
Ok(if let Some(row) = row {
376382
let reissuance_token = parse_asset_id(&row.reissuance_token);
377383

378-
let registry = registry.map(|r| r.read().unwrap());
379-
let meta = meta
380-
.or_else(|| registry.as_ref().and_then(|r| r.get(asset_id)))
381-
.cloned();
382-
let stats = issued_asset_stats(query, asset_id, &reissuance_token);
384+
let meta = meta.map(Clone::clone).or_else(|| match registry {
385+
Some(AssetRegistryLock::RwLock(rwlock)) => {
386+
rwlock.read().unwrap().get(asset_id).cloned()
387+
}
388+
Some(AssetRegistryLock::RwLockReadGuard(guard)) => guard.get(asset_id).cloned(),
389+
None => None,
390+
});
391+
let stats = issued_asset_stats(query.chain(), &mempool, asset_id, &reissuance_token);
383392
let status = query.get_tx_status(&deserialize(&row.issuance_txid).unwrap());
384393

385394
let asset = IssuedAsset::new(asset_id, row, stats, meta, status);
@@ -459,21 +468,20 @@ fn pegged_asset_stats(query: &Query, asset_id: &AssetId) -> (PeggedAssetStats, P
459468

460469
// Get stats for issued assets
461470
fn issued_asset_stats(
462-
query: &Query,
471+
chain: &ChainQuery,
472+
mempool: &Mempool,
463473
asset_id: &AssetId,
464474
reissuance_token: &AssetId,
465475
) -> (IssuedAssetStats, IssuedAssetStats) {
466476
let afn = apply_issued_asset_stats;
467477

468-
let chain = query.chain();
469478
let mut chain_stats = chain_asset_stats(chain, asset_id, afn);
470479
chain_stats.burned_reissuance_tokens =
471480
chain_asset_stats(chain, reissuance_token, afn).burned_amount;
472481

473-
let mempool = query.mempool();
474-
let mut mempool_stats = mempool_asset_stats(&mempool, asset_id, afn);
482+
let mut mempool_stats = mempool_asset_stats(mempool, asset_id, afn);
475483
mempool_stats.burned_reissuance_tokens =
476-
mempool_asset_stats(&mempool, reissuance_token, afn).burned_amount;
484+
mempool_asset_stats(mempool, reissuance_token, afn).burned_amount;
477485

478486
(chain_stats, mempool_stats)
479487
}

src/new_index/mempool.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use bitcoin::consensus::encode::serialize;
66
#[cfg(feature = "liquid")]
77
use elements::{encode::serialize, AssetId};
88

9-
use std::collections::{BTreeSet, HashMap, HashSet};
9+
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
1010
use std::iter::FromIterator;
11+
use std::ops::Bound::{Excluded, Unbounded};
1112
use std::sync::Arc;
1213
use std::time::{Duration, Instant};
1314

@@ -29,7 +30,7 @@ use crate::elements::asset;
2930
pub struct Mempool {
3031
chain: Arc<ChainQuery>,
3132
config: Arc<Config>,
32-
txstore: HashMap<Txid, Transaction>,
33+
txstore: BTreeMap<Txid, Transaction>,
3334
feeinfo: HashMap<Txid, TxFeeInfo>,
3435
history: HashMap<FullHash, Vec<TxHistoryInfo>>, // ScriptHash -> {history_entries}
3536
edges: HashMap<OutPoint, (Txid, u32)>, // OutPoint -> (spending_txid, spending_vin)
@@ -62,7 +63,7 @@ impl Mempool {
6263
pub fn new(chain: Arc<ChainQuery>, metrics: &Metrics, config: Arc<Config>) -> Self {
6364
Mempool {
6465
chain,
65-
txstore: HashMap::new(),
66+
txstore: BTreeMap::new(),
6667
feeinfo: HashMap::new(),
6768
history: HashMap::new(),
6869
edges: HashMap::new(),
@@ -289,6 +290,31 @@ impl Mempool {
289290
self.txstore.keys().collect()
290291
}
291292

293+
// Get all txs in the mempool
294+
pub fn txs(&self) -> Vec<Transaction> {
295+
let _timer = self.latency.with_label_values(&["txs"]).start_timer();
296+
self.txstore.values().cloned().collect()
297+
}
298+
299+
// Get n txs after the given txid in the mempool
300+
pub fn txs_page(&self, n: usize, start: Option<Txid>) -> Vec<Transaction> {
301+
let _timer = self.latency.with_label_values(&["txs"]).start_timer();
302+
let mut page = Vec::with_capacity(n);
303+
let start_bound = match start {
304+
Some(txid) => Excluded(txid),
305+
None => Unbounded,
306+
};
307+
308+
self.txstore
309+
.range((start_bound, Unbounded))
310+
.take(n)
311+
.for_each(|(_, value)| {
312+
page.push(value.clone());
313+
});
314+
315+
page
316+
}
317+
292318
// Get an overview of the most recent transactions
293319
pub fn recent_txs_overview(&self) -> Vec<&TxOverview> {
294320
// We don't bother ever deleting elements from the recent list.

src/new_index/query.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::util::{is_spendable, BlockId, Bytes, TransactionStatus};
1313

1414
#[cfg(feature = "liquid")]
1515
use crate::{
16-
chain::AssetId,
16+
chain::{asset::AssetRegistryLock, AssetId},
1717
elements::{lookup_asset, AssetRegistry, AssetSorting, LiquidAsset},
1818
};
1919

@@ -232,7 +232,12 @@ impl Query {
232232

233233
#[cfg(feature = "liquid")]
234234
pub fn lookup_asset(&self, asset_id: &AssetId) -> Result<Option<LiquidAsset>> {
235-
lookup_asset(self, self.asset_db.as_ref(), asset_id, None)
235+
lookup_asset(
236+
self,
237+
self.asset_db.as_ref().map(AssetRegistryLock::RwLock),
238+
asset_id,
239+
None,
240+
)
236241
}
237242

238243
#[cfg(feature = "liquid")]
@@ -251,8 +256,13 @@ impl Query {
251256
let results = results
252257
.into_iter()
253258
.map(|(asset_id, metadata)| {
254-
lookup_asset(self, None, asset_id, Some(metadata))?
255-
.chain_err(|| "missing registered asset")
259+
lookup_asset(
260+
self,
261+
Some(AssetRegistryLock::RwLockReadGuard(&asset_db)),
262+
asset_id,
263+
Some(metadata),
264+
)?
265+
.chain_err(|| "missing registered asset")
256266
})
257267
.collect::<Result<Vec<_>>>()?;
258268
Ok((total_num, results))

src/rest.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ async fn run_server(config: Arc<Config>, query: Arc<Query>, rx: oneshot::Receive
549549
Response::builder()
550550
.status(err.0)
551551
.header("Content-Type", "text/plain")
552-
.header("Server", &**VERSION_STRING)
552+
.header("X-Powered-By", &**VERSION_STRING)
553553
.body(Body::from(err.1))
554554
.unwrap()
555555
});
@@ -720,7 +720,7 @@ fn handle_request(
720720
.status(StatusCode::OK)
721721
.header("Content-Type", "application/octet-stream")
722722
.header("Cache-Control", format!("public, max-age={:}", TTL_LONG))
723-
.header("Server", &**VERSION_STRING)
723+
.header("X-Powered-By", &**VERSION_STRING)
724724
.body(Body::from(raw))
725725
.unwrap())
726726
}
@@ -991,7 +991,7 @@ fn handle_request(
991991
.status(StatusCode::OK)
992992
.header("Content-Type", content_type)
993993
.header("Cache-Control", format!("public, max-age={:}", ttl))
994-
.header("Server", &**VERSION_STRING)
994+
.header("X-Powered-By", &**VERSION_STRING)
995995
.body(body)
996996
.unwrap())
997997
}
@@ -1086,6 +1086,27 @@ fn handle_request(
10861086
(&Method::GET, Some(&"mempool"), Some(&"txids"), None, None, None) => {
10871087
json_response(query.mempool().txids(), TTL_SHORT)
10881088
}
1089+
(&Method::GET, Some(&"mempool"), Some(&"txs"), Some(&"all"), None, None) => {
1090+
let txs = query
1091+
.mempool()
1092+
.txs()
1093+
.into_iter()
1094+
.map(|tx| (tx, None))
1095+
.collect();
1096+
1097+
json_maybe_error_response(prepare_txs(txs, query, config), TTL_SHORT)
1098+
}
1099+
(&Method::GET, Some(&"mempool"), Some(&"txs"), last_seen_txid, None, None) => {
1100+
let last_seen_txid = last_seen_txid.and_then(|txid| Txid::from_hex(txid).ok());
1101+
let txs = query
1102+
.mempool()
1103+
.txs_page(10_000, last_seen_txid)
1104+
.into_iter()
1105+
.map(|tx| (tx, None))
1106+
.collect();
1107+
1108+
json_maybe_error_response(prepare_txs(txs, query, config), TTL_SHORT)
1109+
}
10891110
(&Method::GET, Some(&"mempool"), Some(&"recent"), None, None, None) => {
10901111
let mempool = query.mempool();
10911112
let recent = mempool.recent_txs_overview();
@@ -1117,7 +1138,7 @@ fn handle_request(
11171138
// Disable caching because we don't currently support caching with query string params
11181139
.header("Cache-Control", "no-store")
11191140
.header("Content-Type", "application/json")
1120-
.header("Server", &**VERSION_STRING)
1141+
.header("X-Powered-By", &**VERSION_STRING)
11211142
.header("X-Total-Results", total_num.to_string())
11221143
.body(Body::from(serde_json::to_string(&assets)?))
11231144
.unwrap())
@@ -1233,7 +1254,7 @@ where
12331254
.status(status)
12341255
.header("Content-Type", "text/plain")
12351256
.header("Cache-Control", format!("public, max-age={:}", ttl))
1236-
.header("Server", &**VERSION_STRING)
1257+
.header("X-Powered-By", &**VERSION_STRING)
12371258
.body(message.into())
12381259
.unwrap())
12391260
}
@@ -1243,7 +1264,7 @@ fn json_response<T: Serialize>(value: T, ttl: u32) -> Result<Response<Body>, Htt
12431264
Ok(Response::builder()
12441265
.header("Content-Type", "application/json")
12451266
.header("Cache-Control", format!("public, max-age={:}", ttl))
1246-
.header("Server", &**VERSION_STRING)
1267+
.header("X-Powered-By", &**VERSION_STRING)
12471268
.body(Body::from(value))
12481269
.unwrap())
12491270
}
@@ -1255,7 +1276,7 @@ fn json_maybe_error_response<T: Serialize>(
12551276
let response = Response::builder()
12561277
.header("Content-Type", "application/json")
12571278
.header("Cache-Control", format!("public, max-age={:}", ttl))
1258-
.header("Server", &**VERSION_STRING);
1279+
.header("X-Powered-By", &**VERSION_STRING);
12591280
Ok(match value {
12601281
Ok(v) => response
12611282
.body(Body::from(serde_json::to_string(&v)?))

0 commit comments

Comments
 (0)