-
Notifications
You must be signed in to change notification settings - Fork 117
fix(p2pk): allow listing and spending p2pk utxos created with uncompressed pubkeys #2410
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 9 commits
38a1be2
1477355
7b180f2
a125a0a
296b904
7366240
4d5523c
d3d4ab2
f866969
4645f9b
2d055ec
e65a9f0
4a1188e
1eaf3e8
c5c62d2
93d0376
5e69799
c2ec918
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,11 +55,6 @@ pub enum UtxoSignTxError { | |
| script: Script, | ||
| prev_script: Script, | ||
| }, | ||
| #[display( | ||
| fmt = "Can't spend the UTXO with script = '{}'. This script format isn't supported", | ||
| script | ||
| )] | ||
| UnspendableUTXO { script: Script }, | ||
| #[display(fmt = "Transport error: {}", _0)] | ||
| Transport(String), | ||
| #[display(fmt = "Internal error: {}", _0)] | ||
|
|
@@ -87,8 +82,8 @@ impl From<UtxoSignWithKeyPairError> for UtxoSignTxError { | |
| // that are expected to be checked by [`sign_common::UtxoSignTxParamsBuilder::build`] already. | ||
| // So if this error happens, it's our internal error. | ||
| UtxoSignWithKeyPairError::InputIndexOutOfBound { .. } => UtxoSignTxError::Internal(error), | ||
| UtxoSignWithKeyPairError::UnspendableUTXO { script } => UtxoSignTxError::UnspendableUTXO { script }, | ||
| UtxoSignWithKeyPairError::ErrorSigning(sign) => UtxoSignTxError::ErrorSigning(sign), | ||
| UtxoSignWithKeyPairError::InternalError(internal) => UtxoSignTxError::Internal(internal), | ||
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,13 +30,10 @@ pub enum UtxoSignWithKeyPairError { | |
| }, | ||
| #[display(fmt = "Input index '{}' is out of bound. Total length = {}", index, len)] | ||
| InputIndexOutOfBound { len: usize, index: usize }, | ||
| #[display( | ||
| fmt = "Can't spend the UTXO with script = '{}'. This script format isn't supported", | ||
| script | ||
| )] | ||
| UnspendableUTXO { script: Script }, | ||
| #[display(fmt = "Error signing using a private key")] | ||
| ErrorSigning(keys::Error), | ||
| #[display(fmt = "{}", _0)] | ||
| InternalError(String), | ||
| } | ||
|
|
||
| impl From<keys::Error> for UtxoSignWithKeyPairError { | ||
|
|
@@ -59,9 +56,10 @@ pub fn sign_tx( | |
| ScriptType::PubKeyHash => p2pkh_spend(&unsigned, i, key_pair, signature_version, fork_id), | ||
| // Allow spending legacy P2PK utxos. | ||
| ScriptType::PubKey => p2pk_spend(&unsigned, i, key_pair, signature_version, fork_id), | ||
| _ => MmError::err(UtxoSignWithKeyPairError::UnspendableUTXO { | ||
| script: input.prev_script.clone(), | ||
| }), | ||
| _ => MmError::err(UtxoSignWithKeyPairError::InternalError(format!( | ||
| "Can't spend the UTXO with script = '{}'. This script format isn't supported", | ||
| input.prev_script | ||
| ))), | ||
|
||
| } | ||
| }) | ||
| .collect::<UtxoSignWithKeyPairResult<_>>()?; | ||
|
|
@@ -77,20 +75,30 @@ pub fn p2pk_spend( | |
| fork_id: u32, | ||
| ) -> UtxoSignWithKeyPairResult<TransactionInput> { | ||
| let unsigned_input = get_input(signer, input_index)?; | ||
|
|
||
| let script = Builder::build_p2pk(key_pair.public()); | ||
| if script != unsigned_input.prev_script { | ||
| // P2PK UTXOs can have either compressed or uncompressed public keys in the scriptPubkey. | ||
| // We need to check that one of them matches the prev_script of the input being spent. | ||
| let pubkey = key_pair.public().to_secp256k1_pubkey().map_err(|e| { | ||
| UtxoSignWithKeyPairError::InternalError(format!("Couldn't get secp256k1 pubkey from keypair: {}", e)) | ||
| })?; | ||
| // Build the scriptPubKey for both compressed and uncompressed public keys. | ||
| let possible_script_pubkeys = vec![ | ||
| Builder::build_p2pk(&keys::Public::Compressed(pubkey.serialize().into())), | ||
| Builder::build_p2pk(&keys::Public::Normal(pubkey.serialize_uncompressed().into())), | ||
| ]; | ||
|
||
| // Check that one of the scriptPubkeys matches the prev_script of the input being spent. | ||
| if !possible_script_pubkeys.contains(&unsigned_input.prev_script) { | ||
| return MmError::err(UtxoSignWithKeyPairError::MismatchScript { | ||
| script_type: "P2PK".to_owned(), | ||
| script, | ||
| // Safe indexing since the array has exactly 2 elements. | ||
| script: possible_script_pubkeys[0].clone(), | ||
| prev_script: unsigned_input.prev_script.clone(), | ||
| }); | ||
| } | ||
|
|
||
| let signature = calc_and_sign_sighash( | ||
| signer, | ||
| input_index, | ||
| &script, | ||
| &unsigned_input.prev_script, | ||
| key_pair, | ||
| signature_version, | ||
| SIGHASH_ALL, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,7 +3,7 @@ use crypto::dhash160; | |||||||||||||||
| use hash::{H160, H264, H520}; | ||||||||||||||||
| use hex::ToHex; | ||||||||||||||||
| use secp256k1::{recovery::{RecoverableSignature, RecoveryId}, | ||||||||||||||||
| Message as SecpMessage, PublicKey, Signature as SecpSignature}; | ||||||||||||||||
| Error as SecpError, Message as SecpMessage, PublicKey, Signature as SecpSignature}; | ||||||||||||||||
| use std::{fmt, ops}; | ||||||||||||||||
| use {CompactSignature, Error, Message, Signature}; | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -80,6 +80,13 @@ impl Public { | |||||||||||||||
| Public::Normal(_) => None, | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| pub fn to_secp256k1_pubkey(&self) -> Result<PublicKey, SecpError> { | ||||||||||||||||
| match self { | ||||||||||||||||
| Public::Compressed(public) => PublicKey::from_slice(&**public), | ||||||||||||||||
| Public::Normal(public) => PublicKey::from_slice(&**public), | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+96
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pretty sure new rustc will complain and suggest similar code
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can let this throw for now and the other PR will fix it. but i can fix it here if u want too. |
||||||||||||||||
| } | ||||||||||||||||
borngraced marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
|
|
||||||||||||||||
| impl ops::Deref for Public { | ||||||||||||||||
|
|
||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.