Skip to content

Commit 01bd5f9

Browse files
committed
Use bincode's new API, add utility functions for safer use
This resolves the deprecation warnings for the old `bincode::config()`, and adds wrapper utility functions that explicitly spells out whether serialization should use little or big endianness. Switching from `bincode::config()` to `bincode::options()` changed the default settings, which requires explicitly enabling `with_fixint_encoding` and `allow_trailing_bytes` to restore the old behaviour. Thanks @junderw for the investigative work and writing the code this is based on (mempool/electrs#34).
1 parent 6dafa6d commit 01bd5f9

File tree

6 files changed

+104
-44
lines changed

6 files changed

+104
-44
lines changed

src/bin/popular-scripts.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
extern crate electrs;
22

3-
use bincode::Options;
43
use electrs::{
54
config::Config,
65
new_index::{Store, TxHistoryKey},
6+
util::bincode,
77
};
88
use hex::DisplayHex;
99

@@ -24,10 +24,8 @@ fn main() {
2424
break;
2525
}
2626

27-
let entry: TxHistoryKey = bincode::options()
28-
.with_big_endian()
29-
.deserialize(&key)
30-
.expect("failed to deserialize TxHistoryKey");
27+
let entry: TxHistoryKey =
28+
bincode::deserialize_big(&key).expect("failed to deserialize TxHistoryKey");
3129

3230
if curr_scripthash != entry.hash {
3331
if total_entries > 100 {

src/elements/asset.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::elements::registry::{AssetMeta, AssetRegistry};
1313
use crate::errors::*;
1414
use crate::new_index::schema::{TxHistoryInfo, TxHistoryKey, TxHistoryRow};
1515
use crate::new_index::{db::DBFlush, ChainQuery, DBRow, Mempool, Query};
16-
use crate::util::{full_hash, Bytes, FullHash, TransactionStatus, TxInput};
16+
use crate::util::{bincode, full_hash, Bytes, FullHash, TransactionStatus, TxInput};
1717

1818
lazy_static! {
1919
pub static ref NATIVE_ASSET_ID: AssetId =
@@ -192,7 +192,7 @@ pub fn index_confirmed_tx_assets(
192192
// reissuances are only kept under the history index.
193193
rows.extend(issuances.into_iter().map(|(asset_id, asset_row)| DBRow {
194194
key: [b"i", &asset_id.into_inner()[..]].concat(),
195-
value: bincode::serialize(&asset_row).unwrap(),
195+
value: bincode::serialize_little(&asset_row).unwrap(),
196196
}));
197197
}
198198

@@ -371,7 +371,7 @@ pub fn lookup_asset(
371371

372372
let chain_row = history_db
373373
.get(&[b"i", &asset_id.into_inner()[..]].concat())
374-
.map(|row| bincode::deserialize::<AssetRow>(&row).expect("failed parsing AssetRow"));
374+
.map(|row| bincode::deserialize_little::<AssetRow>(&row).expect("failed parsing AssetRow"));
375375

376376
let row = chain_row
377377
.as_ref()
@@ -449,7 +449,7 @@ where
449449
{
450450
DBRow {
451451
key: asset_cache_key(asset_id),
452-
value: bincode::serialize(&(stats, blockhash)).unwrap(),
452+
value: bincode::serialize_little(&(stats, blockhash)).unwrap(),
453453
}
454454
}
455455

@@ -492,7 +492,7 @@ where
492492
.store()
493493
.cache_db()
494494
.get(&asset_cache_key(asset_id))
495-
.map(|c| bincode::deserialize(&c).unwrap())
495+
.map(|c| bincode::deserialize_little(&c).unwrap())
496496
.and_then(|(stats, blockhash)| {
497497
chain
498498
.height_by_hash(&blockhash)

src/new_index/db.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rocksdb;
33
use std::path::Path;
44

55
use crate::config::Config;
6-
use crate::util::Bytes;
6+
use crate::util::{bincode, Bytes};
77

88
static DB_VERSION: u32 = 1;
99

@@ -197,7 +197,7 @@ impl DB {
197197
}
198198

199199
fn verify_compatibility(&self, config: &Config) {
200-
let mut compatibility_bytes = bincode::serialize(&DB_VERSION).unwrap();
200+
let mut compatibility_bytes = bincode::serialize_little(&DB_VERSION).unwrap();
201201

202202
if config.light_mode {
203203
// append a byte to indicate light_mode is enabled.

src/new_index/schema.rs

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ use crate::daemon::Daemon;
2929
use crate::errors::*;
3030
use crate::metrics::{Gauge, HistogramOpts, HistogramTimer, HistogramVec, MetricOpts, Metrics};
3131
use crate::util::{
32-
full_hash, has_prevout, is_spendable, BlockHeaderMeta, BlockId, BlockMeta, BlockStatus, Bytes,
33-
HeaderEntry, HeaderList, ScriptToAddr,
32+
bincode, full_hash, has_prevout, is_spendable, BlockHeaderMeta, BlockId, BlockMeta,
33+
BlockStatus, Bytes, HeaderEntry, HeaderList, ScriptToAddr,
3434
};
3535

3636
use crate::new_index::db::{DBFlush, DBRow, ReverseScanIterator, ScanIterator, DB};
@@ -386,7 +386,7 @@ impl ChainQuery {
386386
self.store
387387
.txstore_db
388388
.get(&BlockRow::txids_key(full_hash(&hash[..])))
389-
.map(|val| bincode::deserialize(&val).expect("failed to parse block txids"))
389+
.map(|val| bincode::deserialize_little(&val).expect("failed to parse block txids"))
390390
}
391391
}
392392

@@ -400,7 +400,7 @@ impl ChainQuery {
400400
self.store
401401
.txstore_db
402402
.get(&BlockRow::meta_key(full_hash(&hash[..])))
403-
.map(|val| bincode::deserialize(&val).expect("failed to parse BlockMeta"))
403+
.map(|val| bincode::deserialize_little(&val).expect("failed to parse BlockMeta"))
404404
}
405405
}
406406

@@ -534,7 +534,7 @@ impl ChainQuery {
534534
.store
535535
.cache_db
536536
.get(&UtxoCacheRow::key(scripthash))
537-
.map(|c| bincode::deserialize(&c).unwrap())
537+
.map(|c| bincode::deserialize_little(&c).unwrap())
538538
.and_then(|(utxos_cache, blockhash)| {
539539
self.height_by_hash(&blockhash)
540540
.map(|height| (utxos_cache, height))
@@ -639,7 +639,7 @@ impl ChainQuery {
639639
.store
640640
.cache_db
641641
.get(&StatsCacheRow::key(scripthash))
642-
.map(|c| bincode::deserialize(&c).unwrap())
642+
.map(|c| bincode::deserialize_little(&c).unwrap())
643643
.and_then(|(stats, blockhash)| {
644644
self.height_by_hash(&blockhash)
645645
.map(|height| (stats, height))
@@ -1214,7 +1214,7 @@ impl TxRow {
12141214
fn into_row(self) -> DBRow {
12151215
let TxRow { key, value } = self;
12161216
DBRow {
1217-
key: bincode::serialize(&key).unwrap(),
1217+
key: bincode::serialize_little(&key).unwrap(),
12181218
value,
12191219
}
12201220
}
@@ -1249,14 +1249,14 @@ impl TxConfRow {
12491249

12501250
fn into_row(self) -> DBRow {
12511251
DBRow {
1252-
key: bincode::serialize(&self.key).unwrap(),
1252+
key: bincode::serialize_little(&self.key).unwrap(),
12531253
value: vec![],
12541254
}
12551255
}
12561256

12571257
fn from_row(row: DBRow) -> Self {
12581258
TxConfRow {
1259-
key: bincode::deserialize(&row.key).expect("failed to parse TxConfKey"),
1259+
key: bincode::deserialize_little(&row.key).expect("failed to parse TxConfKey"),
12601260
}
12611261
}
12621262
}
@@ -1285,7 +1285,7 @@ impl TxOutRow {
12851285
}
12861286
}
12871287
fn key(outpoint: &OutPoint) -> Bytes {
1288-
bincode::serialize(&TxOutKey {
1288+
bincode::serialize_little(&TxOutKey {
12891289
code: b'O',
12901290
txid: full_hash(&outpoint.txid[..]),
12911291
vout: outpoint.vout as u16,
@@ -1295,7 +1295,7 @@ impl TxOutRow {
12951295

12961296
fn into_row(self) -> DBRow {
12971297
DBRow {
1298-
key: bincode::serialize(&self.key).unwrap(),
1298+
key: bincode::serialize_little(&self.key).unwrap(),
12991299
value: self.value,
13001300
}
13011301
}
@@ -1326,14 +1326,14 @@ impl BlockRow {
13261326
fn new_txids(hash: FullHash, txids: &[Txid]) -> BlockRow {
13271327
BlockRow {
13281328
key: BlockKey { code: b'X', hash },
1329-
value: bincode::serialize(txids).unwrap(),
1329+
value: bincode::serialize_little(txids).unwrap(),
13301330
}
13311331
}
13321332

13331333
fn new_meta(hash: FullHash, meta: &BlockMeta) -> BlockRow {
13341334
BlockRow {
13351335
key: BlockKey { code: b'M', hash },
1336-
value: bincode::serialize(meta).unwrap(),
1336+
value: bincode::serialize_little(meta).unwrap(),
13371337
}
13381338
}
13391339

@@ -1362,14 +1362,14 @@ impl BlockRow {
13621362

13631363
fn into_row(self) -> DBRow {
13641364
DBRow {
1365-
key: bincode::serialize(&self.key).unwrap(),
1365+
key: bincode::serialize_little(&self.key).unwrap(),
13661366
value: self.value,
13671367
}
13681368
}
13691369

13701370
fn from_row(row: DBRow) -> Self {
13711371
BlockRow {
1372-
key: bincode::deserialize(&row.key).unwrap(),
1372+
key: bincode::deserialize_little(&row.key).unwrap(),
13731373
value: row.value,
13741374
}
13751375
}
@@ -1450,28 +1450,22 @@ impl TxHistoryRow {
14501450
}
14511451

14521452
fn prefix_end(code: u8, hash: &[u8]) -> Bytes {
1453-
bincode::serialize(&(code, full_hash(&hash[..]), std::u32::MAX)).unwrap()
1453+
bincode::serialize_big(&(code, full_hash(&hash[..]), std::u32::MAX)).unwrap()
14541454
}
14551455

14561456
fn prefix_height(code: u8, hash: &[u8], height: u32) -> Bytes {
1457-
bincode::config()
1458-
.big_endian()
1459-
.serialize(&(code, full_hash(&hash[..]), height))
1460-
.unwrap()
1457+
bincode::serialize_big(&(code, full_hash(&hash[..]), height)).unwrap()
14611458
}
14621459

14631460
pub fn into_row(self) -> DBRow {
14641461
DBRow {
1465-
key: bincode::config().big_endian().serialize(&self.key).unwrap(),
1462+
key: bincode::serialize_big(&self.key).unwrap(),
14661463
value: vec![],
14671464
}
14681465
}
14691466

14701467
pub fn from_row(row: DBRow) -> Self {
1471-
let key = bincode::config()
1472-
.big_endian()
1473-
.deserialize(&row.key)
1474-
.expect("failed to deserialize TxHistoryKey");
1468+
let key = bincode::deserialize_big(&row.key).expect("failed to deserialize TxHistoryKey");
14751469
TxHistoryRow { key }
14761470
}
14771471

@@ -1537,19 +1531,20 @@ impl TxEdgeRow {
15371531

15381532
fn filter(outpoint: &OutPoint) -> Bytes {
15391533
// TODO build key without using bincode? [ b"S", &outpoint.txid[..], outpoint.vout?? ].concat()
1540-
bincode::serialize(&(b'S', full_hash(&outpoint.txid[..]), outpoint.vout as u16)).unwrap()
1534+
bincode::serialize_little(&(b'S', full_hash(&outpoint.txid[..]), outpoint.vout as u16))
1535+
.unwrap()
15411536
}
15421537

15431538
fn into_row(self) -> DBRow {
15441539
DBRow {
1545-
key: bincode::serialize(&self.key).unwrap(),
1540+
key: bincode::serialize_little(&self.key).unwrap(),
15461541
value: vec![],
15471542
}
15481543
}
15491544

15501545
fn from_row(row: DBRow) -> Self {
15511546
TxEdgeRow {
1552-
key: bincode::deserialize(&row.key).expect("failed to deserialize TxEdgeKey"),
1547+
key: bincode::deserialize_little(&row.key).expect("failed to deserialize TxEdgeKey"),
15531548
}
15541549
}
15551550
}
@@ -1572,7 +1567,7 @@ impl StatsCacheRow {
15721567
code: b'A',
15731568
scripthash: full_hash(scripthash),
15741569
},
1575-
value: bincode::serialize(&(stats, blockhash)).unwrap(),
1570+
value: bincode::serialize_little(&(stats, blockhash)).unwrap(),
15761571
}
15771572
}
15781573

@@ -1582,7 +1577,7 @@ impl StatsCacheRow {
15821577

15831578
fn into_row(self) -> DBRow {
15841579
DBRow {
1585-
key: bincode::serialize(&self.key).unwrap(),
1580+
key: bincode::serialize_little(&self.key).unwrap(),
15861581
value: self.value,
15871582
}
15881583
}
@@ -1604,7 +1599,7 @@ impl UtxoCacheRow {
16041599
code: b'U',
16051600
scripthash: full_hash(scripthash),
16061601
},
1607-
value: bincode::serialize(&(utxos_cache, blockhash)).unwrap(),
1602+
value: bincode::serialize_little(&(utxos_cache, blockhash)).unwrap(),
16081603
}
16091604
}
16101605

@@ -1614,7 +1609,7 @@ impl UtxoCacheRow {
16141609

16151610
fn into_row(self) -> DBRow {
16161611
DBRow {
1617-
key: bincode::serialize(&self.key).unwrap(),
1612+
key: bincode::serialize_little(&self.key).unwrap(),
16181613
value: self.value,
16191614
}
16201615
}

src/util/bincode.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! This module creates two sets of serialize and deserialize for bincode.
2+
//! They explicitly spell out the bincode settings so that switching to
3+
//! new versions in the future is less error prone.
4+
//!
5+
//! This is a list of all the row types and their settings for bincode.
6+
//! +--------------+--------+------------+----------------+------------+
7+
//! | | Endian | Int Length | Allow Trailing | Byte Limit |
8+
//! +--------------+--------+------------+----------------+------------+
9+
//! | TxHistoryRow | big | fixed | allow | unlimited |
10+
//! | All others | little | fixed | allow | unlimited |
11+
//! +--------------+--------+------------+----------------+------------+
12+
//!
13+
//! Based on @junderw's https://github.com/mempool/electrs/pull/34. Thanks!
14+
15+
use bincode::Options;
16+
17+
pub fn serialize_big<T>(value: &T) -> Result<Vec<u8>, bincode::Error>
18+
where
19+
T: ?Sized + serde::Serialize,
20+
{
21+
big_endian().serialize(value)
22+
}
23+
24+
pub fn deserialize_big<'a, T>(bytes: &'a [u8]) -> Result<T, bincode::Error>
25+
where
26+
T: serde::Deserialize<'a>,
27+
{
28+
big_endian().deserialize(bytes)
29+
}
30+
31+
pub fn serialize_little<T>(value: &T) -> Result<Vec<u8>, bincode::Error>
32+
where
33+
T: ?Sized + serde::Serialize,
34+
{
35+
little_endian().serialize(value)
36+
}
37+
38+
pub fn deserialize_little<'a, T>(bytes: &'a [u8]) -> Result<T, bincode::Error>
39+
where
40+
T: serde::Deserialize<'a>,
41+
{
42+
little_endian().deserialize(bytes)
43+
}
44+
45+
/// This is the default settings for Options,
46+
/// but all explicitly spelled out, except for endianness.
47+
/// The following functions will add endianness.
48+
#[inline]
49+
fn options() -> impl Options {
50+
bincode::options()
51+
.with_fixint_encoding()
52+
.with_no_limit()
53+
.allow_trailing_bytes()
54+
}
55+
56+
/// Adding the endian flag for big endian
57+
#[inline]
58+
fn big_endian() -> impl Options {
59+
options().with_big_endian()
60+
}
61+
62+
/// Adding the endian flag for little endian
63+
#[inline]
64+
fn little_endian() -> impl Options {
65+
options().with_little_endian()
66+
}

src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod block;
22
mod script;
33
mod transaction;
44

5+
pub mod bincode;
56
pub mod electrum_merkle;
67
pub mod fees;
78

0 commit comments

Comments
 (0)