From 097f60077d911f32d14e74152b679825a9aff34d Mon Sep 17 00:00:00 2001 From: Nadav Ivgi Date: Thu, 15 Feb 2024 12:47:55 +0200 Subject: [PATCH] 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 https://github.com/mempool/electrs/pull/75. Thanks! This change requires a full database reindex. --- src/elements/asset.rs | 22 +++++++++++----------- src/elements/peg.rs | 4 ++-- src/new_index/mempool.rs | 8 ++++---- src/new_index/schema.rs | 34 +++++++++++++++++----------------- src/util/transaction.rs | 2 +- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/elements/asset.rs b/src/elements/asset.rs index 726431b54..67e1b7e03 100644 --- a/src/elements/asset.rs +++ b/src/elements/asset.rs @@ -74,9 +74,9 @@ pub struct IssuedAsset { #[derive(Serialize, Deserialize, Debug)] pub struct AssetRow { pub issuance_txid: FullHash, - pub issuance_vin: u16, + pub issuance_vin: u32, pub prev_txid: FullHash, - pub prev_vout: u16, + pub prev_vout: u32, pub issuance: Bytes, // bincode does not like dealing with AssetIssuance, deserialization fails with "invalid type: sequence, expected a struct" pub reissuance_token: FullHash, } @@ -108,7 +108,7 @@ impl IssuedAsset { }, issuance_prevout: OutPoint { txid: deserialize(&asset.prev_txid).unwrap(), - vout: asset.prev_vout as u32, + vout: asset.prev_vout, }, contract_hash, reissuance_token, @@ -157,7 +157,7 @@ impl LiquidAsset { #[derive(Serialize, Deserialize, Debug)] pub struct IssuingInfo { pub txid: FullHash, - pub vin: u16, + pub vin: u32, pub is_reissuance: bool, // None for blinded issuances pub issued_amount: Option, @@ -167,7 +167,7 @@ pub struct IssuingInfo { #[derive(Serialize, Deserialize, Debug)] pub struct BurningInfo { pub txid: FullHash, - pub vout: u16, + pub vout: u32, pub value: u64, } @@ -251,7 +251,7 @@ fn index_tx_assets( pegout.asset.explicit().unwrap(), TxHistoryInfo::Pegout(PegoutInfo { txid, - vout: txo_index as u16, + vout: txo_index as u32, value: pegout.value, }), )); @@ -262,7 +262,7 @@ fn index_tx_assets( asset_id, TxHistoryInfo::Burning(BurningInfo { txid, - vout: txo_index as u16, + vout: txo_index as u32, value: value, }), )); @@ -277,7 +277,7 @@ fn index_tx_assets( pegin.asset, TxHistoryInfo::Pegin(PeginInfo { txid, - vin: txi_index as u16, + vin: txi_index as u32, value: pegin.value, }), )); @@ -302,7 +302,7 @@ fn index_tx_assets( asset_id, TxHistoryInfo::Issuing(IssuingInfo { txid, - vin: txi_index as u16, + vin: txi_index as u32, is_reissuance, issued_amount, token_amount, @@ -321,9 +321,9 @@ fn index_tx_assets( asset_id, AssetRow { issuance_txid: txid, - issuance_vin: txi_index as u16, + issuance_vin: txi_index as u32, prev_txid: full_hash(&txi.previous_output.txid[..]), - prev_vout: txi.previous_output.vout as u16, + prev_vout: txi.previous_output.vout as u32, issuance: serialize(&txi.asset_issuance), reissuance_token: full_hash(&reissuance_token.into_inner()[..]), }, diff --git a/src/elements/peg.rs b/src/elements/peg.rs index 4c093f5bd..d053b64a5 100644 --- a/src/elements/peg.rs +++ b/src/elements/peg.rs @@ -52,7 +52,7 @@ impl PegoutValue { #[derive(Serialize, Deserialize, Debug)] pub struct PeginInfo { pub txid: FullHash, - pub vin: u16, + pub vin: u32, pub value: u64, } @@ -60,6 +60,6 @@ pub struct PeginInfo { #[derive(Serialize, Deserialize, Debug)] pub struct PegoutInfo { pub txid: FullHash, - pub vout: u16, + pub vout: u32, pub value: u64, } diff --git a/src/new_index/mempool.rs b/src/new_index/mempool.rs index cfd395de9..797af7339 100644 --- a/src/new_index/mempool.rs +++ b/src/new_index/mempool.rs @@ -186,7 +186,7 @@ impl Mempool { Some(Utxo { txid: deserialize(&info.txid).expect("invalid txid"), - vout: info.vout as u32, + vout: info.vout, value: info.value, confirmed: None, @@ -377,9 +377,9 @@ impl Mempool { compute_script_hash(&prevout.script_pubkey), TxHistoryInfo::Spending(SpendingInfo { txid: txid_bytes, - vin: input_index as u16, + vin: input_index, prev_txid: full_hash(&txi.previous_output.txid[..]), - prev_vout: txi.previous_output.vout as u16, + prev_vout: txi.previous_output.vout, value: prevout.value.amount_value(), }), ) @@ -398,7 +398,7 @@ impl Mempool { compute_script_hash(&txo.script_pubkey), TxHistoryInfo::Funding(FundingInfo { txid: txid_bytes, - vout: index as u16, + vout: index as u32, value: txo.value.amount_value(), }), ) diff --git a/src/new_index/schema.rs b/src/new_index/schema.rs index d5eba9a51..b2393b0ea 100644 --- a/src/new_index/schema.rs +++ b/src/new_index/schema.rs @@ -879,7 +879,7 @@ impl ChainQuery { let txid: Txid = deserialize(&edge.key.spending_txid).unwrap(); self.tx_confirming_block(&txid).map(|b| SpendingInput { txid, - vin: edge.key.spending_vin as u32, + vin: edge.key.spending_vin, confirmed: Some(b), }) }) @@ -1107,7 +1107,7 @@ fn index_transaction( confirmed_height, TxHistoryInfo::Funding(FundingInfo { txid, - vout: txo_index as u16, + vout: txo_index as u32, value: txo.value.amount_value(), }), ); @@ -1133,9 +1133,9 @@ fn index_transaction( confirmed_height, TxHistoryInfo::Spending(SpendingInfo { txid, - vin: txi_index as u16, + vin: txi_index as u32, prev_txid: full_hash(&txi.previous_output.txid[..]), - prev_vout: txi.previous_output.vout as u16, + prev_vout: txi.previous_output.vout, value: prev_txo.value.amount_value(), }), ); @@ -1143,9 +1143,9 @@ fn index_transaction( let edge = TxEdgeRow::new( full_hash(&txi.previous_output.txid[..]), - txi.previous_output.vout as u16, + txi.previous_output.vout, txid, - txi_index as u16, + txi_index as u32, ); rows.push(edge.into_row()); } @@ -1265,7 +1265,7 @@ impl TxConfRow { struct TxOutKey { code: u8, txid: FullHash, - vout: u16, + vout: u32, } struct TxOutRow { @@ -1279,7 +1279,7 @@ impl TxOutRow { key: TxOutKey { code: b'O', txid: *txid, - vout: vout as u16, + vout: vout as u32, }, value: serialize(txout), } @@ -1288,7 +1288,7 @@ impl TxOutRow { bincode::serialize_little(&TxOutKey { code: b'O', txid: full_hash(&outpoint.txid[..]), - vout: outpoint.vout as u16, + vout: outpoint.vout as u32, }) .unwrap() } @@ -1378,16 +1378,16 @@ impl BlockRow { #[derive(Serialize, Deserialize, Debug)] pub struct FundingInfo { pub txid: FullHash, - pub vout: u16, + pub vout: u32, pub value: Value, } #[derive(Serialize, Deserialize, Debug)] pub struct SpendingInfo { pub txid: FullHash, // spending transaction - pub vin: u16, + pub vin: u32, pub prev_txid: FullHash, // funding transaction - pub prev_vout: u16, + pub prev_vout: u32, pub value: Value, } @@ -1503,9 +1503,9 @@ impl TxHistoryInfo { struct TxEdgeKey { code: u8, funding_txid: FullHash, - funding_vout: u16, + funding_vout: u32, spending_txid: FullHash, - spending_vin: u16, + spending_vin: u32, } struct TxEdgeRow { @@ -1515,9 +1515,9 @@ struct TxEdgeRow { impl TxEdgeRow { fn new( funding_txid: FullHash, - funding_vout: u16, + funding_vout: u32, spending_txid: FullHash, - spending_vin: u16, + spending_vin: u32, ) -> Self { let key = TxEdgeKey { code: b'S', @@ -1531,7 +1531,7 @@ impl TxEdgeRow { fn filter(outpoint: &OutPoint) -> Bytes { // TODO build key without using bincode? [ b"S", &outpoint.txid[..], outpoint.vout?? ].concat() - bincode::serialize_little(&(b'S', full_hash(&outpoint.txid[..]), outpoint.vout as u16)) + bincode::serialize_little(&(b'S', full_hash(&outpoint.txid[..]), outpoint.vout)) .unwrap() } diff --git a/src/util/transaction.rs b/src/util/transaction.rs index dda5e4f7c..d5a72754a 100644 --- a/src/util/transaction.rs +++ b/src/util/transaction.rs @@ -48,7 +48,7 @@ impl From> for TransactionStatus { #[derive(Serialize, Deserialize)] pub struct TxInput { pub txid: Txid, - pub vin: u16, + pub vin: u32, } pub fn is_coinbase(txin: &TxIn) -> bool {