Skip to content
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

calculate sig ops on fly #597

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

biryukovmaxim
Copy link
Collaborator

@biryukovmaxim biryukovmaxim commented Nov 14, 2024

Migrate to runtime signature operation counting

Changes signature operation counting from static analysis to runtime counting during script execution for improved accuracy.

Key changes

  • Add sig_op tracking fields to TxScriptEngine
  • Remove static sig_op counting functions
  • Count sig_ops during script execution
  • Add runtime checks for sig_op limits
  • Add new error type for sig_op limit violations
  • Update transaction validation to use runtime counting

Breaking changes

  • Changes sig_op validation timing from pre-execution to during execution
  • May affect transaction fee estimation

Todo

  • Add tests for sig_op calculation
  • Add documentation for new sig_op runtime counting behavior
  • Consider adding sig_op estimation helper for fee calculation

Requires manual testing and careful review of sig_op counting logic.

@biryukovmaxim biryukovmaxim force-pushed the sig-op-calculation branch 2 times, most recently from 75e6d58 to 6e1efd2 Compare January 23, 2025 09:44
crypto/txscript/errors/src/lib.rs Outdated Show resolved Hide resolved
crypto/txscript/errors/src/lib.rs Outdated Show resolved Hide resolved
@@ -94,6 +112,36 @@ fn parse_script<T: VerifiableTransaction, Reused: SigHashReusedValues>(
script.iter().batching(|it| deserialize_next_opcode(it))
}

pub fn get_sig_op_count_via_simulation<T: VerifiableTransaction, Reused: SigHashReusedValues>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this function? It's never used

Copy link
Collaborator Author

@biryukovmaxim biryukovmaxim Feb 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was aiming to use it in test, but made them without the function.
the idea is adding some helper function that can derive sig op count that is needed for execution by executing it with TxEngine help

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the function is only for tests, delete it since it's not used.

If you think it's somehow good for users, add documentation that explains what it does

crypto/txscript/src/lib.rs Outdated Show resolved Hide resolved
crypto/txscript/src/lib.rs Outdated Show resolved Hide resolved
crypto/txscript/src/lib.rs Outdated Show resolved Hide resolved
crypto/txscript/src/lib.rs Outdated Show resolved Hide resolved
crypto/txscript/src/lib.rs Outdated Show resolved Hide resolved
crypto/txscript/src/opcodes/mod.rs Outdated Show resolved Hide resolved
crypto/txscript/src/opcodes/mod.rs Outdated Show resolved Hide resolved
Comment on lines 87 to 89
pub sig_op_limit: u8,
/// Remaining signature operations that can be executed
pub sig_op_remaining: u8,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it shouldn't be pub anymore?

sig_op_remaining.checked_sub(num_sigs).ok_or(TxScriptError::ExceededSigOpLimit(num_sigs as u16, *sig_op_limit))?;
}
let num_sigs =
num_sigs.try_into().map_err(|_| TxScriptError::NumberTooBig("Signatures count mustn't exceed 255".to_string()))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a suspicion that this can create a netsplit, since num_sigs arrived from the stack as i32 so it can theoretically be bigger than 255. But after some reading of the context it seems that this error is actually unreachable, since num_sigs is bounded by num_keys which is bounded by MAX_PUB_KEYS_PER_MUTLTISIG=20.

But just to be sure, can you make a multisig test where the hardfork is inactive and num_sigs=256? I expect to see it fails with Err(TxScriptError::InvalidPubKeyCount(format!("too many pubkeys {num_keys} > {MAX_PUB_KEYS_PER_MUTLTISIG}"))) or Err(TxScriptError::InvalidSignatureCount(format!("more signatures than pubkeys {num_sigs} > {num_keys}")))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually it will face first MAX_SCRIPT_ELEMENT_SIZE then MAX_STACK_SIZE and only after that, it will fail with error related to MAX_PUB_KEYS_PER_MUTLTISIG.

Make the fields of RuntimeSigOpCounter private and add:
- A constructor (new) that ensures consistency between limit and remaining
- Getter methods for accessing the private fields
- Updated example code to use the new API

This change improves encapsulation by ensuring the counter's internal state
can only be modified through the consume_sig_ops method, preventing
potential inconsistencies between sig_op_limit and sig_op_remaining that
could occur with direct field access.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants