Skip to content

Commit 9434e29

Browse files
committed
Merge remote-tracking branch 'origin/develop' into perf/2.0-syncing
2 parents e979816 + 7d7e414 commit 9434e29

File tree

8 files changed

+774
-87
lines changed

8 files changed

+774
-87
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
99

1010
### Added
1111

12+
- Added field `vm_error` to EventObserver transaction outputs
1213
- Added new `ValidateRejectCode` values to the `/v3/block_proposal` endpoint
1314
- Added `StateMachineUpdateContent::V1` to support a vector of `StacksTransaction` expected to be replayed in subsequent Stacks blocks
1415

@@ -18,6 +19,10 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1819
- Added index for `next_ready_nakamoto_block()` which improves block processing performance.
1920
- Added a new field, `parent_burn_block_hash`, to the payload that is included in the `/new_burn_block` event observer payload.
2021

22+
### Fixed
23+
24+
- Fix regression in mock-mining, allowing the mock miner to continue mining blocks throughout a tenure instead of failing after mining the tenure change block.
25+
2126
## [3.1.0.0.8]
2227

2328
### Added

stacks-signer/src/v0/signer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ use stacks_common::util::get_epoch_time_secs;
4343
use stacks_common::util::secp256k1::MessageSignature;
4444
use stacks_common::{debug, error, info, warn};
4545

46+
#[cfg(not(any(test, feature = "testing")))]
47+
use super::signer_state::SUPPORTED_SIGNER_PROTOCOL_VERSION;
4648
use super::signer_state::{GlobalStateEvaluator, LocalStateMachine};
4749
use crate::chainstate::{ProposalEvalConfig, SortitionMinerStatus, SortitionsView};
4850
use crate::client::{ClientError, SignerSlotID, StackerDB, StacksClient};

stackslib/src/chainstate/burn/operations/mod.rs

Lines changed: 236 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
use std::{error, fmt, fs, io};
1818

1919
use clarity::vm::types::PrincipalData;
20-
use serde::Deserialize;
20+
use serde::de::Error as DeError;
21+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
2122
use serde_json::json;
2223
use stacks_common::types::chainstate::{
2324
BlockHeaderHash, BurnchainHeaderHash, StacksAddress, StacksBlockId, TrieHash, VRFSeed,
@@ -374,6 +375,132 @@ pub fn stacks_addr_serialize(addr: &StacksAddress) -> serde_json::Value {
374375
})
375376
}
376377

378+
fn normalize_stacks_addr_fields<'de, D>(
379+
inner: &mut serde_json::Map<String, serde_json::Value>,
380+
) -> Result<(), D::Error>
381+
where
382+
D: Deserializer<'de>,
383+
{
384+
// Rename `address_version` to `version`
385+
if let Some(address_version) = inner.remove("address_version") {
386+
inner.insert("version".to_string(), address_version);
387+
}
388+
389+
// Rename `address_hash_bytes` to `bytes` and convert to bytes
390+
if let Some(address_bytes) = inner
391+
.remove("address_hash_bytes")
392+
.and_then(|addr| serde_json::Value::as_str(&addr).map(|x| x.to_string()))
393+
{
394+
let address_hex: String = address_bytes.chars().skip(2).collect(); // Remove "0x" prefix
395+
inner.insert(
396+
"bytes".to_string(),
397+
serde_json::to_value(&address_hex).map_err(DeError::custom)?,
398+
);
399+
}
400+
401+
Ok(())
402+
}
403+
404+
/// Serialization function for serializing extended information within the BlockstackOperationType
405+
/// that is not printed via the standard serde implementation. Specifically, serializes additional
406+
/// StacksAddress information.
407+
pub fn blockstack_op_extended_serialize_opt<S: Serializer>(
408+
op: &Option<BlockstackOperationType>,
409+
s: S,
410+
) -> Result<S::Ok, S::Error> {
411+
match op {
412+
Some(op) => {
413+
let value = op.blockstack_op_to_json();
414+
value.serialize(s)
415+
}
416+
None => s.serialize_none(),
417+
}
418+
}
419+
420+
/// Deserialize the burnchain op that was serialized with blockstack_op_to_json
421+
pub fn blockstack_op_extended_deserialize<'de, D>(
422+
deserializer: D,
423+
) -> Result<Option<BlockstackOperationType>, D::Error>
424+
where
425+
D: Deserializer<'de>,
426+
{
427+
use serde::de::Error as DeError;
428+
use serde_json::{Map, Value};
429+
430+
let raw: Option<Value> = Option::deserialize(deserializer)?;
431+
let Some(Value::Object(mut obj)) = raw else {
432+
return Ok(None);
433+
};
434+
435+
let Some((key, value)) = obj.iter_mut().next() else {
436+
return Ok(None);
437+
};
438+
439+
let inner = value
440+
.as_object_mut()
441+
.ok_or_else(|| DeError::custom("Expected blockstack op to be an object"))?;
442+
443+
let normalized_key = match key.as_str() {
444+
"pre_stx" => {
445+
BlockstackOperationType::normalize_pre_stx_fields::<D>(inner)?;
446+
"PreStx"
447+
}
448+
"stack_stx" => {
449+
BlockstackOperationType::normalize_stack_stx_fields::<D>(inner)?;
450+
"StackStx"
451+
}
452+
"transfer_stx" => {
453+
BlockstackOperationType::normalize_transfer_stx_fields::<D>(inner)?;
454+
"TransferStx"
455+
}
456+
"delegate_stx" => {
457+
BlockstackOperationType::normalize_delegate_stx_fields::<D>(inner)?;
458+
"DelegateStx"
459+
}
460+
"vote_for_aggregate_key" => {
461+
BlockstackOperationType::normalize_vote_for_aggregate_key_fields::<D>(inner)?;
462+
"VoteForAggregateKey"
463+
}
464+
"leader_key_register" => "LeaderKeyRegister",
465+
"leader_block_commit" => "LeaderBlockCommit",
466+
other => other,
467+
};
468+
469+
let mut map = Map::new();
470+
map.insert(normalized_key.to_string(), value.clone());
471+
472+
let normalized = Value::Object(map);
473+
474+
serde_json::from_value(normalized)
475+
.map(Some)
476+
.map_err(serde::de::Error::custom)
477+
}
478+
479+
fn normalize_common_fields<'de, D>(
480+
map: &mut serde_json::Map<String, serde_json::Value>,
481+
) -> Result<(), D::Error>
482+
where
483+
D: Deserializer<'de>,
484+
{
485+
if let Some(hex_str) = map
486+
.get("burn_header_hash")
487+
.and_then(serde_json::Value::as_str)
488+
{
489+
let cleaned = hex_str.strip_prefix("0x").unwrap_or(hex_str);
490+
let val = BurnchainHeaderHash::from_hex(cleaned).map_err(DeError::custom)?;
491+
let ser_val = serde_json::to_value(val).map_err(DeError::custom)?;
492+
map.insert("burn_header_hash".to_string(), ser_val);
493+
}
494+
495+
if let Some(val) = map.remove("burn_txid") {
496+
map.insert("txid".to_string(), val);
497+
}
498+
if let Some(val) = map.remove("burn_block_height") {
499+
map.insert("block_height".to_string(), val);
500+
}
501+
Ok(())
502+
}
503+
377504
impl BlockstackOperationType {
378505
pub fn opcode(&self) -> Opcodes {
379506
match *self {
@@ -475,6 +602,114 @@ impl BlockstackOperationType {
475602
};
476603
}
477604

605+
// Replace all the normalize_* functions with minimal implementations
606+
fn normalize_pre_stx_fields<'de, D>(
607+
map: &mut serde_json::Map<String, serde_json::Value>,
608+
) -> Result<(), D::Error>
609+
where
610+
D: Deserializer<'de>,
611+
{
612+
normalize_common_fields::<D>(map)?;
613+
if let Some(serde_json::Value::Object(obj)) = map.get_mut("output") {
614+
normalize_stacks_addr_fields::<D>(obj)?;
615+
}
616+
Ok(())
617+
}
618+
619+
fn normalize_stack_stx_fields<'de, D>(
620+
map: &mut serde_json::Map<String, serde_json::Value>,
621+
) -> Result<(), D::Error>
622+
where
623+
D: Deserializer<'de>,
624+
{
625+
normalize_common_fields::<D>(map)?;
626+
if let Some(serde_json::Value::Object(obj)) = map.get_mut("sender") {
627+
normalize_stacks_addr_fields::<D>(obj)?;
628+
}
629+
if let Some(reward_val) = map.get("reward_addr") {
630+
let b58_str = reward_val
631+
.as_str()
632+
.ok_or_else(|| DeError::custom("Expected base58 string in reward_addr"))?;
633+
let addr = PoxAddress::from_b58(b58_str)
634+
.ok_or_else(|| DeError::custom("Invalid stacks address"))?;
635+
let val = serde_json::to_value(addr).map_err(DeError::custom)?;
636+
map.insert("reward_addr".into(), val);
637+
}
638+
Ok(())
639+
}
640+
641+
fn normalize_transfer_stx_fields<'de, D>(
642+
map: &mut serde_json::Map<String, serde_json::Value>,
643+
) -> Result<(), D::Error>
644+
where
645+
D: Deserializer<'de>,
646+
{
647+
normalize_common_fields::<D>(map)?;
648+
for field in ["recipient", "sender"] {
649+
if let Some(serde_json::Value::Object(obj)) = map.get_mut(field) {
650+
normalize_stacks_addr_fields::<D>(obj)?;
651+
}
652+
}
653+
if let Some(memo_str) = map.get("memo").and_then(serde_json::Value::as_str) {
654+
let memo_hex = memo_str.trim_start_matches("0x");
655+
let memo_bytes = hex_bytes(memo_hex).map_err(DeError::custom)?;
656+
let val = serde_json::to_value(memo_bytes).map_err(DeError::custom)?;
657+
map.insert("memo".into(), val);
658+
}
659+
Ok(())
660+
}
661+
662+
fn normalize_delegate_stx_fields<'de, D>(
663+
map: &mut serde_json::Map<String, serde_json::Value>,
664+
) -> Result<(), D::Error>
665+
where
666+
D: Deserializer<'de>,
667+
{
668+
normalize_common_fields::<D>(map)?;
669+
if let Some(serde_json::Value::Array(arr)) = map.get("reward_addr") {
670+
if arr.len() == 2 {
671+
let index = arr[0]
672+
.as_u64()
673+
.ok_or_else(|| DeError::custom("Expected u64 index"))?
674+
as u32;
675+
let b58_str = arr[1]
676+
.as_str()
677+
.ok_or_else(|| DeError::custom("Expected base58 string"))?;
678+
let addr = PoxAddress::from_b58(b58_str)
679+
.ok_or_else(|| DeError::custom("Invalid stacks address"))?;
680+
let val = serde_json::to_value((index, addr)).map_err(DeError::custom)?;
681+
map.insert("reward_addr".into(), val);
682+
}
683+
}
684+
for field in ["delegate_to", "sender"] {
685+
if let Some(serde_json::Value::Object(obj)) = map.get_mut(field) {
686+
normalize_stacks_addr_fields::<D>(obj)?;
687+
}
688+
}
689+
Ok(())
690+
}
691+
692+
fn normalize_vote_for_aggregate_key_fields<'de, D>(
693+
map: &mut serde_json::Map<String, serde_json::Value>,
694+
) -> Result<(), D::Error>
695+
where
696+
D: Deserializer<'de>,
697+
{
698+
normalize_common_fields::<D>(map)?;
699+
for field in ["aggregate_key", "signer_key"] {
700+
if let Some(hex_str) = map.get(field).and_then(serde_json::Value::as_str) {
701+
let cleaned = hex_str.strip_prefix("0x").unwrap_or(hex_str);
702+
let val = StacksPublicKeyBuffer::from_hex(cleaned).map_err(DeError::custom)?;
703+
let ser_val = serde_json::to_value(val).map_err(DeError::custom)?;
704+
map.insert(field.to_string(), ser_val);
705+
}
706+
}
707+
if let Some(serde_json::Value::Object(obj)) = map.get_mut("sender") {
708+
normalize_stacks_addr_fields::<D>(obj)?;
709+
}
710+
Ok(())
711+
}
712+
478713
pub fn pre_stx_to_json(op: &PreStxOp) -> serde_json::Value {
479714
json!({
480715
"pre_stx": {

0 commit comments

Comments
 (0)