-
Notifications
You must be signed in to change notification settings - Fork 78
Derive P2TR input weight from witness data #1200
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
Conversation
Pull Request Test Coverage Report for Build 20275523512Details
💛 - Coveralls |
arminsabouri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approach looks correct. Had a suggestion and question for breaking up p2tr key spend and script spend input pair constructors. Did not review the tests. Will circle back once this is out of draft. Thanks
payjoin/src/core/psbt/mod.rs
Outdated
| match witness.len() { | ||
| 0 => Err(InputWeightError::NotSupported), | ||
| 1 => { | ||
| let signature = | ||
| witness.iter().next().ok_or(InputWeightError::NotSupported)?; | ||
| if !(signature.len() == SCHNORR_SIGNATURE_SIZE | ||
| || signature.len() == SCHNORR_SIGNATURE_SIZE + 1) | ||
| { | ||
| return Err(InputWeightError::NotSupported); | ||
| } | ||
| Ok(InputWeightPrediction::new(0, vec![signature.len()])) | ||
| } | ||
| _ => Ok(InputWeightPrediction::new( | ||
| 0, | ||
| witness.iter().map(|el| el.len()).collect::<Vec<_>>(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this match on length necessary? Once we have a non-empty witness can we not just calculate expected satisfaction weight?
InputWeightPrediction::new(0, witness.iter().map(|el| el.len()).collect::<Vec<_>>())7b85692 to
81eb642
Compare
|
@Mshehu5 I'll do another review once this is out of draft |
81eb642 to
0d49a8e
Compare
arminsabouri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some trivial nits in the tests and suggested clean up of duplicated code. The main issue remaining is a possible regression in psbt/mod.rs
| Ok(iwp) | ||
| }, | ||
| P2tr => Ok(InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH), | ||
| P2tr => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe there is a regression here. For key spends we know the weight prediction even though we do not have the witness. We may need to internally distinguish between keyspends and scriptpath using the new ctors introduced by this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review and for sharing the links to help clarify the necessary changes.
I’ve pushed updates that set the weight to key spend when the witness is not available.
Script path weights can still be set explicitly using the constructor or derived from witness
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this will have the same issue as the original issue. I.e if the witness is not known and its a taproot output we assume the key spend path is being used -- even though that may not be the case; which is what prompted the new ctors and user provided weight.
Perphaps the best way to solve this is to set expected weight to the key spend weight in the key spend ctor. And return a error here as we cannot accurately determine the input weight prediction for a taproot output that has no witness. What do you think?
payjoin/tests/integration.rs
Outdated
| let expect_weight = psbtin | ||
| .witness_utxo | ||
| .as_ref() | ||
| .filter(|txo| txo.script_pubkey.is_p2tr()) | ||
| .map(|_| Weight::from_wu(P2TR_INPUT_WEIGHT)); | ||
| InputPair::new(txin, psbtin, expect_weight).expect("Input pair should be valid") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is no longer needed as key spend is now automatically derived when no witness is present unlike before
0d49a8e to
017feb4
Compare
| Ok(iwp) | ||
| }, | ||
| P2tr => Ok(InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH), | ||
| P2tr => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this will have the same issue as the original issue. I.e if the witness is not known and its a taproot output we assume the key spend path is being used -- even though that may not be the case; which is what prompted the new ctors and user provided weight.
Perphaps the best way to solve this is to set expected weight to the key spend weight in the key spend ctor. And return a error here as we cannot accurately determine the input weight prediction for a taproot output that has no witness. What do you think?
a4c1812 to
ce2be55
Compare
arminsabouri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cack
I had a few nits. Otherwise looks good 👍
Thanks
payjoin/src/core/receive/mod.rs
Outdated
| let key_spend_weight = | ||
| InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH.weight() + NON_WITNESS_INPUT_WEIGHT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this could be a const.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when trying to do this I get an error from rust analyzer:
const P2TR_KEY_SPEND_WEIGHT: Weight = InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH.weight() + NON_WITNESS_INPUT_WEIGHT;
cannot call non-const operator in constants
calls in constants are limited to constant functions, tuple structs and tuple variants
weight( ) is a non constant function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant the whole expressions can be evaluated and expressed as a const
const DEAFULT_SIGHASH_KEY_SPEND_INPUT_WEIGHT: Weight = ...,
Previously, P2TR weight estimation assumed key-path spends only, which was incorrect for script-path spends and non-default sighash. This change derives weight from actual witness data when available, matching P2WSH handling. When witness data is unavailable, applications must provide expected_weight manually, ensuring accurate fee calculation.
6368515 to
ab2f027
Compare
Use the new helpers so key-spend inputs get the default weight and script-path inputs take caller-supplied weight.
ab2f027 to
a7dbe56
Compare
arminsabouri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-AcK a7dbe56
Replaces: #880 as contibutor is currently busy
I aslo followed comments from previous PR: #880 (comment)
closes: #788
Previously, P2TR weight estimation assumed key-path spends only, which was incorrect for script-path spends and non-default sighash.
This change derives weight from actual witness data when available, matching P2WSH handling.
When witness data is unavailable, applications must provide expected_weight manually, ensuring accurate fee calculation.
Also Adding new helpers for P2tr so key-spend inputs get the default weight and script-path inputs take caller-supplied weight.
Pull Request Checklist
Please confirm the following before requesting review:
AI
in the body of this PR.