Skip to content

Commit f946a6f

Browse files
committed
Fix output indexes to be represented as a u32
Bitcoin's consensus rules allows for output indexes larger than u16, which would result in an overflow prior to this fix. This recently happened with a transaction on testnet: https://blockstream.info/testnet/tx/ca3b75556430e1adf9e9790bce9c73a3d9afdb42305588e64c65b258c06c05c9 Based on @junderw's mempool/electrs#75. Thanks! This change requires a full database reindex.
1 parent 255fb17 commit f946a6f

File tree

5 files changed

+35
-35
lines changed

5 files changed

+35
-35
lines changed

src/elements/asset.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ pub struct IssuedAsset {
7474
#[derive(Serialize, Deserialize, Debug)]
7575
pub struct AssetRow {
7676
pub issuance_txid: FullHash,
77-
pub issuance_vin: u16,
77+
pub issuance_vin: u32,
7878
pub prev_txid: FullHash,
79-
pub prev_vout: u16,
79+
pub prev_vout: u32,
8080
pub issuance: Bytes, // bincode does not like dealing with AssetIssuance, deserialization fails with "invalid type: sequence, expected a struct"
8181
pub reissuance_token: FullHash,
8282
}
@@ -108,7 +108,7 @@ impl IssuedAsset {
108108
},
109109
issuance_prevout: OutPoint {
110110
txid: deserialize(&asset.prev_txid).unwrap(),
111-
vout: asset.prev_vout as u32,
111+
vout: asset.prev_vout,
112112
},
113113
contract_hash,
114114
reissuance_token,
@@ -157,7 +157,7 @@ impl LiquidAsset {
157157
#[derive(Serialize, Deserialize, Debug)]
158158
pub struct IssuingInfo {
159159
pub txid: FullHash,
160-
pub vin: u16,
160+
pub vin: u32,
161161
pub is_reissuance: bool,
162162
// None for blinded issuances
163163
pub issued_amount: Option<u64>,
@@ -167,7 +167,7 @@ pub struct IssuingInfo {
167167
#[derive(Serialize, Deserialize, Debug)]
168168
pub struct BurningInfo {
169169
pub txid: FullHash,
170-
pub vout: u16,
170+
pub vout: u32,
171171
pub value: u64,
172172
}
173173

@@ -251,7 +251,7 @@ fn index_tx_assets(
251251
pegout.asset.explicit().unwrap(),
252252
TxHistoryInfo::Pegout(PegoutInfo {
253253
txid,
254-
vout: txo_index as u16,
254+
vout: txo_index as u32,
255255
value: pegout.value,
256256
}),
257257
));
@@ -262,7 +262,7 @@ fn index_tx_assets(
262262
asset_id,
263263
TxHistoryInfo::Burning(BurningInfo {
264264
txid,
265-
vout: txo_index as u16,
265+
vout: txo_index as u32,
266266
value: value,
267267
}),
268268
));
@@ -277,7 +277,7 @@ fn index_tx_assets(
277277
pegin.asset,
278278
TxHistoryInfo::Pegin(PeginInfo {
279279
txid,
280-
vin: txi_index as u16,
280+
vin: txi_index as u32,
281281
value: pegin.value,
282282
}),
283283
));
@@ -302,7 +302,7 @@ fn index_tx_assets(
302302
asset_id,
303303
TxHistoryInfo::Issuing(IssuingInfo {
304304
txid,
305-
vin: txi_index as u16,
305+
vin: txi_index as u32,
306306
is_reissuance,
307307
issued_amount,
308308
token_amount,
@@ -321,9 +321,9 @@ fn index_tx_assets(
321321
asset_id,
322322
AssetRow {
323323
issuance_txid: txid,
324-
issuance_vin: txi_index as u16,
324+
issuance_vin: txi_index as u32,
325325
prev_txid: full_hash(&txi.previous_output.txid[..]),
326-
prev_vout: txi.previous_output.vout as u16,
326+
prev_vout: txi.previous_output.vout as u32,
327327
issuance: serialize(&txi.asset_issuance),
328328
reissuance_token: full_hash(&reissuance_token.into_inner()[..]),
329329
},

src/elements/peg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ impl PegoutValue {
5252
#[derive(Serialize, Deserialize, Debug)]
5353
pub struct PeginInfo {
5454
pub txid: FullHash,
55-
pub vin: u16,
55+
pub vin: u32,
5656
pub value: u64,
5757
}
5858

5959
// Inner type for the indexer TxHistoryInfo::Pegout variant
6060
#[derive(Serialize, Deserialize, Debug)]
6161
pub struct PegoutInfo {
6262
pub txid: FullHash,
63-
pub vout: u16,
63+
pub vout: u32,
6464
pub value: u64,
6565
}

src/new_index/mempool.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl Mempool {
186186

187187
Some(Utxo {
188188
txid: deserialize(&info.txid).expect("invalid txid"),
189-
vout: info.vout as u32,
189+
vout: info.vout,
190190
value: info.value,
191191
confirmed: None,
192192

@@ -377,9 +377,9 @@ impl Mempool {
377377
compute_script_hash(&prevout.script_pubkey),
378378
TxHistoryInfo::Spending(SpendingInfo {
379379
txid: txid_bytes,
380-
vin: input_index as u16,
380+
vin: input_index,
381381
prev_txid: full_hash(&txi.previous_output.txid[..]),
382-
prev_vout: txi.previous_output.vout as u16,
382+
prev_vout: txi.previous_output.vout,
383383
value: prevout.value.amount_value(),
384384
}),
385385
)
@@ -398,7 +398,7 @@ impl Mempool {
398398
compute_script_hash(&txo.script_pubkey),
399399
TxHistoryInfo::Funding(FundingInfo {
400400
txid: txid_bytes,
401-
vout: index as u16,
401+
vout: index as u32,
402402
value: txo.value.amount_value(),
403403
}),
404404
)

src/new_index/schema.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ impl ChainQuery {
876876
let txid: Txid = deserialize(&edge.key.spending_txid).unwrap();
877877
self.tx_confirming_block(&txid).map(|b| SpendingInput {
878878
txid,
879-
vin: edge.key.spending_vin as u32,
879+
vin: edge.key.spending_vin,
880880
confirmed: Some(b),
881881
})
882882
})
@@ -1104,7 +1104,7 @@ fn index_transaction(
11041104
confirmed_height,
11051105
TxHistoryInfo::Funding(FundingInfo {
11061106
txid,
1107-
vout: txo_index as u16,
1107+
vout: txo_index as u32,
11081108
value: txo.value.amount_value(),
11091109
}),
11101110
);
@@ -1130,19 +1130,19 @@ fn index_transaction(
11301130
confirmed_height,
11311131
TxHistoryInfo::Spending(SpendingInfo {
11321132
txid,
1133-
vin: txi_index as u16,
1133+
vin: txi_index as u32,
11341134
prev_txid: full_hash(&txi.previous_output.txid[..]),
1135-
prev_vout: txi.previous_output.vout as u16,
1135+
prev_vout: txi.previous_output.vout,
11361136
value: prev_txo.value.amount_value(),
11371137
}),
11381138
);
11391139
rows.push(history.into_row());
11401140

11411141
let edge = TxEdgeRow::new(
11421142
full_hash(&txi.previous_output.txid[..]),
1143-
txi.previous_output.vout as u16,
1143+
txi.previous_output.vout,
11441144
txid,
1145-
txi_index as u16,
1145+
txi_index as u32,
11461146
);
11471147
rows.push(edge.into_row());
11481148
}
@@ -1262,7 +1262,7 @@ impl TxConfRow {
12621262
struct TxOutKey {
12631263
code: u8,
12641264
txid: FullHash,
1265-
vout: u16,
1265+
vout: u32,
12661266
}
12671267

12681268
struct TxOutRow {
@@ -1276,7 +1276,7 @@ impl TxOutRow {
12761276
key: TxOutKey {
12771277
code: b'O',
12781278
txid: *txid,
1279-
vout: vout as u16,
1279+
vout: vout as u32,
12801280
},
12811281
value: serialize(txout),
12821282
}
@@ -1285,7 +1285,7 @@ impl TxOutRow {
12851285
bincode::serialize(&TxOutKey {
12861286
code: b'O',
12871287
txid: full_hash(&outpoint.txid[..]),
1288-
vout: outpoint.vout as u16,
1288+
vout: outpoint.vout as u32,
12891289
})
12901290
.unwrap()
12911291
}
@@ -1375,16 +1375,16 @@ impl BlockRow {
13751375
#[derive(Serialize, Deserialize, Debug)]
13761376
pub struct FundingInfo {
13771377
pub txid: FullHash,
1378-
pub vout: u16,
1378+
pub vout: u32,
13791379
pub value: Value,
13801380
}
13811381

13821382
#[derive(Serialize, Deserialize, Debug)]
13831383
pub struct SpendingInfo {
13841384
pub txid: FullHash, // spending transaction
1385-
pub vin: u16,
1385+
pub vin: u32,
13861386
pub prev_txid: FullHash, // funding transaction
1387-
pub prev_vout: u16,
1387+
pub prev_vout: u32,
13881388
pub value: Value,
13891389
}
13901390

@@ -1506,9 +1506,9 @@ impl TxHistoryInfo {
15061506
struct TxEdgeKey {
15071507
code: u8,
15081508
funding_txid: FullHash,
1509-
funding_vout: u16,
1509+
funding_vout: u32,
15101510
spending_txid: FullHash,
1511-
spending_vin: u16,
1511+
spending_vin: u32,
15121512
}
15131513

15141514
struct TxEdgeRow {
@@ -1518,9 +1518,9 @@ struct TxEdgeRow {
15181518
impl TxEdgeRow {
15191519
fn new(
15201520
funding_txid: FullHash,
1521-
funding_vout: u16,
1521+
funding_vout: u32,
15221522
spending_txid: FullHash,
1523-
spending_vin: u16,
1523+
spending_vin: u32,
15241524
) -> Self {
15251525
let key = TxEdgeKey {
15261526
code: b'S',
@@ -1534,7 +1534,7 @@ impl TxEdgeRow {
15341534

15351535
fn filter(outpoint: &OutPoint) -> Bytes {
15361536
// TODO build key without using bincode? [ b"S", &outpoint.txid[..], outpoint.vout?? ].concat()
1537-
bincode::serialize(&(b'S', full_hash(&outpoint.txid[..]), outpoint.vout as u16)).unwrap()
1537+
bincode::serialize(&(b'S', full_hash(&outpoint.txid[..]), outpoint.vout)).unwrap()
15381538
}
15391539

15401540
fn into_row(self) -> DBRow {

src/util/transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl From<Option<BlockId>> for TransactionStatus {
4848
#[derive(Serialize, Deserialize)]
4949
pub struct TxInput {
5050
pub txid: Txid,
51-
pub vin: u16,
51+
pub vin: u32,
5252
}
5353

5454
pub fn is_coinbase(txin: &TxIn) -> bool {

0 commit comments

Comments
 (0)