diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f7fce479b..ac469d673b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE ### Added +- Add `vrf_seed` to the `/v3/sortitions` rpc endpoint + ### Changed ### Fixed diff --git a/docs/rpc/api/core-node/get_sortitions.example.json b/docs/rpc/api/core-node/get_sortitions.example.json index a56fd887b1..571a51beb6 100644 --- a/docs/rpc/api/core-node/get_sortitions.example.json +++ b/docs/rpc/api/core-node/get_sortitions.example.json @@ -10,6 +10,7 @@ "miner_pk_hash160": "0x6bc51b33e9f3626944eb879147e18111581f8f9b", "stacks_parent_ch": "0x697357c72da55b759b1d6b721676c92c69f0b490", "last_sortition_ch": "0x697357c72da55b759b1d6b721676c92c69f0b490", - "committed_block_hash": "0xeea47d6d639c565027110e192e308fb11656183d5c077bcd718d830652800183" + "committed_block_hash": "0xeea47d6d639c565027110e192e308fb11656183d5c077bcd718d830652800183", + "vrf_seed": "0x48b754acc291a5bfad1354ee19bbc471f14af2b21dc7eccc0f929bd16798defe" } ] diff --git a/stacks-signer/src/tests/chainstate.rs b/stacks-signer/src/tests/chainstate.rs index 19f0d843c8..85d8dfb805 100644 --- a/stacks-signer/src/tests/chainstate.rs +++ b/stacks-signer/src/tests/chainstate.rs @@ -556,6 +556,7 @@ fn check_proposal_refresh() { stacks_parent_ch: Some(view.cur_sortition.parent_tenure_id), last_sortition_ch: Some(view.cur_sortition.parent_tenure_id), committed_block_hash: None, + vrf_seed: None, }, SortitionInfo { burn_block_hash: BurnchainHeaderHash([128; 32]), @@ -569,6 +570,7 @@ fn check_proposal_refresh() { stacks_parent_ch: Some(view.cur_sortition.parent_tenure_id), last_sortition_ch: Some(view.cur_sortition.parent_tenure_id), committed_block_hash: None, + vrf_seed: None, }, ]; diff --git a/stackslib/src/net/api/getsortition.rs b/stackslib/src/net/api/getsortition.rs index b41e516cbf..63cd23303e 100644 --- a/stackslib/src/net/api/getsortition.rs +++ b/stackslib/src/net/api/getsortition.rs @@ -16,8 +16,10 @@ use std::io::{Read, Seek, SeekFrom, Write}; use std::{fs, io}; +use clarity::types::chainstate::VRFSeed; use regex::{Captures, Regex}; use serde::de::Error as de_Error; +use serde::Serialize; use stacks_common::codec::{StacksMessageCodec, MAX_MESSAGE_LEN}; use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, SortitionId, StacksBlockId, @@ -111,6 +113,9 @@ pub struct SortitionInfo { /// In Stacks 2.x, this is the winning block. /// In Stacks 3.x, this is the first block of the parent tenure. pub committed_block_hash: Option, + #[serde(with = "prefix_opt_hex")] + /// This is the VRF seed generated by this sortition + pub vrf_seed: Option, } impl TryFrom<(&str, &str)> for QuerySpecifier { @@ -163,12 +168,12 @@ impl GetSortitionHandler { let is_shadow = chainstate .nakamoto_blocks_db() .is_shadow_tenure(&sortition_sn.consensus_hash)?; - let (miner_pk_hash160, stacks_parent_ch, committed_block_hash, last_sortition_ch) = + let (miner_pk_hash160, stacks_parent_ch, committed_block_hash, last_sortition_ch, vrf_seed) = if !sortition_sn.sortition && !is_shadow { let handle = sortdb.index_handle(&sortition_sn.sortition_id); let last_sortition = handle.get_last_snapshot_with_sortition(sortition_sn.block_height)?; - (None, None, None, Some(last_sortition.consensus_hash)) + (None, None, None, Some(last_sortition.consensus_hash), None) } else if !sortition_sn.sortition && is_shadow { // this is a shadow tenure. let parent_tenure_ch = chainstate @@ -191,6 +196,7 @@ impl GetSortitionHandler { parent_tenure_start_header.index_block_hash().0, )), Some(parent_tenure_ch), + None, ) } else { let block_commit = SortitionDB::get_block_commit(sortdb.conn(), &sortition_sn.winning_block_txid, &sortition_sn.sortition_id)? @@ -236,6 +242,7 @@ impl GetSortitionHandler { Some(stacks_parent_sn.consensus_hash), Some(block_commit.block_header_hash), Some(last_sortition_ch), + Some(block_commit.new_seed), ) }; @@ -251,6 +258,7 @@ impl GetSortitionHandler { stacks_parent_ch, last_sortition_ch, committed_block_hash, + vrf_seed, }) } } diff --git a/stackslib/src/net/api/mod.rs b/stackslib/src/net/api/mod.rs index 9604b3eb69..cff12f2242 100644 --- a/stackslib/src/net/api/mod.rs +++ b/stackslib/src/net/api/mod.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use clarity::types::chainstate::VRFSeed; use clarity::vm::costs::ExecutionCost; use stacks_common::codec::read_next; use stacks_common::types::chainstate::{ @@ -239,6 +240,7 @@ macro_rules! impl_hex_deser { impl_hex_deser!(BurnchainHeaderHash); impl_hex_deser!(StacksBlockId); impl_hex_deser!(SortitionId); +impl_hex_deser!(VRFSeed); impl_hex_deser!(ConsensusHash); impl_hex_deser!(BlockHeaderHash); impl_hex_deser!(Hash160); diff --git a/stackslib/src/net/api/tests/getsortition.rs b/stackslib/src/net/api/tests/getsortition.rs index e112fde4a0..5a8e9ae034 100644 --- a/stackslib/src/net/api/tests/getsortition.rs +++ b/stackslib/src/net/api/tests/getsortition.rs @@ -16,6 +16,7 @@ use std::collections::BTreeMap; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use clarity::types::chainstate::VRFSeed; use stacks_common::types::chainstate::{BurnchainHeaderHash, ConsensusHash}; use stacks_common::types::net::PeerHost; @@ -159,6 +160,13 @@ fn response() { let second_entry: SortitionInfo = serde_json::from_value(info_array[1].clone()) .expect("Response array elements should parse to SortitionInfo"); assert!(first_entry.was_sortition); + assert_eq!( + first_entry.vrf_seed, + Some( + VRFSeed::from_hex("48b754acc291a5bfad1354ee19bbc471f14af2b21dc7eccc0f929bd16798defe") + .unwrap() + ) + ); assert!(second_entry.was_sortition); assert_eq!( first_entry.last_sortition_ch.as_ref().unwrap(),