Skip to content

Commit 097f600

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 01bd5f9 commit 097f600

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
@@ -879,7 +879,7 @@ impl ChainQuery {
879879
let txid: Txid = deserialize(&edge.key.spending_txid).unwrap();
880880
self.tx_confirming_block(&txid).map(|b| SpendingInput {
881881
txid,
882-
vin: edge.key.spending_vin as u32,
882+
vin: edge.key.spending_vin,
883883
confirmed: Some(b),
884884
})
885885
})
@@ -1107,7 +1107,7 @@ fn index_transaction(
11071107
confirmed_height,
11081108
TxHistoryInfo::Funding(FundingInfo {
11091109
txid,
1110-
vout: txo_index as u16,
1110+
vout: txo_index as u32,
11111111
value: txo.value.amount_value(),
11121112
}),
11131113
);
@@ -1133,19 +1133,19 @@ fn index_transaction(
11331133
confirmed_height,
11341134
TxHistoryInfo::Spending(SpendingInfo {
11351135
txid,
1136-
vin: txi_index as u16,
1136+
vin: txi_index as u32,
11371137
prev_txid: full_hash(&txi.previous_output.txid[..]),
1138-
prev_vout: txi.previous_output.vout as u16,
1138+
prev_vout: txi.previous_output.vout,
11391139
value: prev_txo.value.amount_value(),
11401140
}),
11411141
);
11421142
rows.push(history.into_row());
11431143

11441144
let edge = TxEdgeRow::new(
11451145
full_hash(&txi.previous_output.txid[..]),
1146-
txi.previous_output.vout as u16,
1146+
txi.previous_output.vout,
11471147
txid,
1148-
txi_index as u16,
1148+
txi_index as u32,
11491149
);
11501150
rows.push(edge.into_row());
11511151
}
@@ -1265,7 +1265,7 @@ impl TxConfRow {
12651265
struct TxOutKey {
12661266
code: u8,
12671267
txid: FullHash,
1268-
vout: u16,
1268+
vout: u32,
12691269
}
12701270

12711271
struct TxOutRow {
@@ -1279,7 +1279,7 @@ impl TxOutRow {
12791279
key: TxOutKey {
12801280
code: b'O',
12811281
txid: *txid,
1282-
vout: vout as u16,
1282+
vout: vout as u32,
12831283
},
12841284
value: serialize(txout),
12851285
}
@@ -1288,7 +1288,7 @@ impl TxOutRow {
12881288
bincode::serialize_little(&TxOutKey {
12891289
code: b'O',
12901290
txid: full_hash(&outpoint.txid[..]),
1291-
vout: outpoint.vout as u16,
1291+
vout: outpoint.vout as u32,
12921292
})
12931293
.unwrap()
12941294
}
@@ -1378,16 +1378,16 @@ impl BlockRow {
13781378
#[derive(Serialize, Deserialize, Debug)]
13791379
pub struct FundingInfo {
13801380
pub txid: FullHash,
1381-
pub vout: u16,
1381+
pub vout: u32,
13821382
pub value: Value,
13831383
}
13841384

13851385
#[derive(Serialize, Deserialize, Debug)]
13861386
pub struct SpendingInfo {
13871387
pub txid: FullHash, // spending transaction
1388-
pub vin: u16,
1388+
pub vin: u32,
13891389
pub prev_txid: FullHash, // funding transaction
1390-
pub prev_vout: u16,
1390+
pub prev_vout: u32,
13911391
pub value: Value,
13921392
}
13931393

@@ -1503,9 +1503,9 @@ impl TxHistoryInfo {
15031503
struct TxEdgeKey {
15041504
code: u8,
15051505
funding_txid: FullHash,
1506-
funding_vout: u16,
1506+
funding_vout: u32,
15071507
spending_txid: FullHash,
1508-
spending_vin: u16,
1508+
spending_vin: u32,
15091509
}
15101510

15111511
struct TxEdgeRow {
@@ -1515,9 +1515,9 @@ struct TxEdgeRow {
15151515
impl TxEdgeRow {
15161516
fn new(
15171517
funding_txid: FullHash,
1518-
funding_vout: u16,
1518+
funding_vout: u32,
15191519
spending_txid: FullHash,
1520-
spending_vin: u16,
1520+
spending_vin: u32,
15211521
) -> Self {
15221522
let key = TxEdgeKey {
15231523
code: b'S',
@@ -1531,7 +1531,7 @@ impl TxEdgeRow {
15311531

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

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)