Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/7484-remove-high-s-special-casing.removed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed the special-casing of transactions with high-S signatures from mempool admittance and block validation. Now that we've transitioned into Epoch 4.0, those signatures are forbidden by consensus and no longer need to be special-cased.
25 changes: 0 additions & 25 deletions stacks-node/src/tests/nakamoto_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3590,31 +3590,6 @@ fn block_proposal_api_endpoint() {
HTTP_UNPROCESSABLE,
None,
),
(
"High-S signature",
{
let mut p = proposal.clone();
p.block.executed_and_skipped_txs_mut()[0] =
p.block.executed_and_skipped_txs()[0].with_negated_s_in_signature();
// tweaking the signature changes the transaction id (which is
// the main problem with high-S signatures), so we need to update
// the transaction merkle root
let txid_vecs: Vec<_> = p
.block
.txs()
.map(|tx| tx.txid().as_bytes().to_vec())
.collect();

let merkle_tree = MerkleTree::<Sha512Trunc256Sum>::new(&txid_vecs);
let tx_merkle_root = merkle_tree.root();

p.block.header.tx_merkle_root = tx_merkle_root;

sign(&p)
},
HTTP_ACCEPTED,
Some(Err(ValidateRejectCode::BadTransaction)),
),
];

// Build HTTP client
Expand Down
9 changes: 2 additions & 7 deletions stackslib/src/chainstate/stacks/db/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6620,13 +6620,8 @@ impl StacksChainState {
// makes transaction ids malleable. That's why we don't admit them to the mempol,
// and signers reject blocks with them. Once Epoch 4.0 begins, they will also
// not be allowed by consensus anymore.
Comment thread
brice-stacks marked this conversation as resolved.
Outdated
StacksChainState::process_transaction_precheck(
chainstate_config,
tx,
epoch,
Some(TransactionAuthVerificationMode::EnforceLowS),
)
.map_err(MemPoolRejection::FailedToValidate)?;
StacksChainState::process_transaction_precheck(chainstate_config, tx, epoch)
.map_err(MemPoolRejection::FailedToValidate)?;

// 3: it must pay a tx fee
let fee = tx.get_tx_fee();
Expand Down
17 changes: 7 additions & 10 deletions stackslib/src/chainstate/stacks/db/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,6 @@ impl StacksChainState {
config: &DBConfig,
tx: &StacksTransaction,
epoch_id: StacksEpochId,
auth_verification_mode_override: Option<TransactionAuthVerificationMode>,
) -> Result<(), Error> {
// valid auth?
if !tx.auth.is_supported_in_epoch(epoch_id) {
Expand All @@ -677,13 +676,11 @@ impl StacksChainState {

return Err(Error::InvalidStacksTransaction(msg, false));
}
let verification_mode = auth_verification_mode_override.unwrap_or_else(|| {
if epoch_id.allows_tx_signatures_with_high_s() {
TransactionAuthVerificationMode::AllowHighS
} else {
TransactionAuthVerificationMode::EnforceLowS
}
});
let verification_mode = if epoch_id.allows_tx_signatures_with_high_s() {
TransactionAuthVerificationMode::AllowHighS
} else {
TransactionAuthVerificationMode::EnforceLowS
};

tx.verify(verification_mode)?;

Expand Down Expand Up @@ -1910,7 +1907,7 @@ impl StacksChainState {
// Static precheck (size, version, anchor mode, multisig encoding,
// Clarity version...). A problematic marker only skips payload
// execution; the transaction must still be otherwise valid.
StacksChainState::process_transaction_precheck(&clarity_block.config, tx, epoch, None)?;
StacksChainState::process_transaction_precheck(&clarity_block.config, tx, epoch)?;

let mut transaction = clarity_block.connection().start_transaction_processing();

Expand Down Expand Up @@ -1956,7 +1953,7 @@ impl StacksChainState {
debug!("Process transaction {} ({})", tx.txid(), tx.payload.name());
let epoch = clarity_block.get_epoch();

StacksChainState::process_transaction_precheck(&clarity_block.config, tx, epoch, None)?;
StacksChainState::process_transaction_precheck(&clarity_block.config, tx, epoch)?;

let mut transaction = clarity_block.connection().start_transaction_processing();

Expand Down
42 changes: 8 additions & 34 deletions stackslib/src/net/api/postblock_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,12 +728,6 @@ impl NakamotoBlockProposal {
let burn_chain_height = miner_tenure_info.burn_tip_height;
let mut tenure_tx = builder.tenure_begin(&burn_dbconn, &mut miner_tenure_info)?;

// Even if consensus allows high-S signatures, we want to refuse to sign blocks that
// contain them. If they're allowed in the current epoch, we therefore have to check
// for them ourselves.
let consensus_allow_high_s_tx_sig =
tenure_tx.get_epoch().allows_tx_signatures_with_high_s();

let block_deadline = Instant::now() + Duration::from_secs(timeout_secs);
let per_tx_max_execution_time = Duration::from_secs(max_tx_execution_time_secs);
// Bound the analysis phase during proposal validation by the
Expand Down Expand Up @@ -778,34 +772,14 @@ impl NakamotoBlockProposal {

let tx_len = tx.tx_len();

let tx_result = {
// If consensus allows high-S transaction signatures, then `try_mine_tx_with_len`
// would allow such a transaction, so we perform the stricter verification first,
// and only call `try_mine_tx_with_len` if successful. If consensus forbids it,
// we don't have to do this, because `try_mine_tx_with_len` will do it itself.
let high_s_check_result = if consensus_allow_high_s_tx_sig {
match tx.verify(
stacks_codec::transaction::TransactionAuthVerificationMode::EnforceLowS,
) {
Ok(()) => Ok(()),
Err(error) => Err(TransactionResult::error(tx, error.into())),
}
} else {
Ok(())
};

match high_s_check_result {
Ok(()) => builder.try_mine_tx_with_len(
&mut tenure_tx,
tx,
tx_len,
&BlockLimitFunction::NO_LIMIT_HIT,
&resource_budgets,
&mut receipts_total,
),
Err(e) => e,
}
};
let tx_result = builder.try_mine_tx_with_len(
&mut tenure_tx,
tx,
tx_len,
&BlockLimitFunction::NO_LIMIT_HIT,
&resource_budgets,
&mut receipts_total,
);

let reason = match tx_result {
TransactionResult::Success(success_result) => {
Expand Down
Loading