Skip to content

Commit

Permalink
feat: burn op definition and storage for vote-for-agg-key
Browse files Browse the repository at this point in the history
  • Loading branch information
hstove committed Feb 14, 2024
1 parent 60f0e07 commit 3d5adf5
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 13 deletions.
3 changes: 3 additions & 0 deletions stackslib/src/burnchains/burnchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ impl BurnchainStateTransition {
// the burn distribution, so just account for them for now.
all_user_burns.insert(op.txid.clone(), op.clone());
}
BlockstackOperationType::VoteForAggregateKey(_) => {
accepted_ops.push(block_ops[i].clone());
}
};
}

Expand Down
7 changes: 7 additions & 0 deletions stackslib/src/chainstate/burn/db/processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ impl<'a> SortitionHandleTx<'a> {
);
BurnchainError::OpError(e)
}),
BlockstackOperationType::VoteForAggregateKey(ref op) => op.check().map_err(|e| {
warn!(
"REJECTED({}) vote for aggregate key op {} at {},{}: {:?}",
op.block_height, &op.txid, op.block_height, op.vtxindex, &e
);
BurnchainError::OpError(e)
}),
}
}

Expand Down
116 changes: 114 additions & 2 deletions stackslib/src/chainstate/burn/db/sortdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use stacks_common::types::chainstate::{
BlockHeaderHash, BurnchainHeaderHash, PoxId, SortitionId, StacksAddress, StacksBlockId,
TrieHash, VRFSeed,
};
use stacks_common::types::StacksPublicKeyBuffer;
use stacks_common::util::hash::{hex_bytes, to_hex, Hash160, Sha512Trunc256Sum};
use stacks_common::util::secp256k1::{MessageSignature, Secp256k1PublicKey};
use stacks_common::util::vrf::*;
Expand All @@ -59,7 +60,7 @@ use crate::chainstate::burn::operations::leader_block_commit::{
};
use crate::chainstate::burn::operations::{
BlockstackOperationType, DelegateStxOp, LeaderBlockCommitOp, LeaderKeyRegisterOp, PreStxOp,
StackStxOp, TransferStxOp, UserBurnSupportOp,
StackStxOp, TransferStxOp, UserBurnSupportOp, VoteForAggregateKeyOp,
};
use crate::chainstate::burn::{
BlockSnapshot, ConsensusHash, ConsensusHashExtensions, Opcodes, OpsHash, SortitionHash,
Expand Down Expand Up @@ -431,6 +432,39 @@ impl FromRow<TransferStxOp> for TransferStxOp {
}
}

impl FromRow<VoteForAggregateKeyOp> for VoteForAggregateKeyOp {
fn from_row<'a>(row: &'a Row) -> Result<VoteForAggregateKeyOp, db_error> {
let txid = Txid::from_column(row, "txid")?;
let vtxindex: u32 = row.get_unwrap("vtxindex");
let block_height = u64::from_column(row, "block_height")?;
let burn_header_hash = BurnchainHeaderHash::from_column(row, "burn_header_hash")?;

let sender = StacksAddress::from_column(row, "sender_addr")?;
let aggregate_key_str: String = row.get_unwrap("aggregate_key");
let aggregate_key: StacksPublicKeyBuffer = serde_json::from_str(&aggregate_key_str)
.expect("CORRUPTION: DB stored bad transition ops");
let round: u32 = row.get_unwrap("round");
let reward_cycle = u64::from_column(row, "reward_cycle")?;
let signer_index: u16 = row.get_unwrap("signer_index");
let signer_key_str: String = row.get_unwrap("signer_key");
let signer_key: StacksPublicKeyBuffer = serde_json::from_str(&signer_key_str)
.expect("CORRUPTION: DB stored bad transition ops");

Ok(VoteForAggregateKeyOp {
txid,
vtxindex,
block_height,
burn_header_hash,
sender,
aggregate_key,
round,
reward_cycle,
signer_index,
signer_key,
})
}
}

impl FromColumn<ASTRules> for ASTRules {
fn from_column<'a>(row: &'a Row, column_name: &str) -> Result<ASTRules, db_error> {
let x: u8 = row.get_unwrap(column_name);
Expand Down Expand Up @@ -497,7 +531,7 @@ impl FromRow<StacksEpoch> for StacksEpoch {
}
}

pub const SORTITION_DB_VERSION: &'static str = "8";
pub const SORTITION_DB_VERSION: &'static str = "9";

const SORTITION_DB_INITIAL_SCHEMA: &'static [&'static str] = &[
r#"
Expand Down Expand Up @@ -729,6 +763,23 @@ const SORTITION_DB_SCHEMA_8: &'static [&'static str] = &[
);"#,
];

const SORTITION_DB_SCHEMA_9: &'static [&'static str] = &[r#"
CREATE TABLE vote_for_aggregate_key (
txid TEXT NOT NULL,
vtxindex INTEGER NOT NULL,
block_height INTEGER NOT NULL,
burn_header_hash TEXT NOT NULL,
sender_addr TEXT NOT NULL,
aggregate_key TEXT NOT NULL,
round INTEGER NOT NULL,
reward_cycle INTEGER NOT NULL,
signer_index INTEGER NOT NULL,
signer_key TEXT NOT NULL,
PRIMARY KEY(txid,burn_header_Hash)
);"#];

const SORTITION_DB_INDEXES: &'static [&'static str] = &[
"CREATE INDEX IF NOT EXISTS snapshots_block_hashes ON snapshots(block_height,index_root,winning_stacks_block_hash);",
"CREATE INDEX IF NOT EXISTS snapshots_block_stacks_hashes ON snapshots(num_sortitions,index_root,winning_stacks_block_hash);",
Expand Down Expand Up @@ -2905,6 +2956,7 @@ impl SortitionDB {
SortitionDB::apply_schema_6(&db_tx, epochs_ref)?;
SortitionDB::apply_schema_7(&db_tx, epochs_ref)?;
SortitionDB::apply_schema_8(&db_tx)?;
SortitionDB::apply_schema_9(&db_tx)?;

db_tx.instantiate_index()?;

Expand Down Expand Up @@ -3323,6 +3375,18 @@ impl SortitionDB {
Ok(())
}

fn apply_schema_9(tx: &DBTx) -> Result<(), db_error> {
for sql_exec in SORTITION_DB_SCHEMA_9 {
tx.execute_batch(sql_exec)?;
}

tx.execute(
"INSERT OR REPLACE INTO db_config (version) VALUES (?1)",
&["9"],
)?;
Ok(())
}

fn check_schema_version_or_error(&mut self) -> Result<(), db_error> {
match SortitionDB::get_schema_version(self.conn()) {
Ok(Some(version)) => {
Expand Down Expand Up @@ -3377,6 +3441,10 @@ impl SortitionDB {
let tx = self.tx_begin()?;
SortitionDB::apply_schema_8(&tx.deref())?;
tx.commit()?;
} else if version == "8" {
let tx = self.tx_begin()?;
SortitionDB::apply_schema_9(&tx.deref())?;
tx.commit()?;
} else if version == expected_version {
return Ok(());
} else {
Expand Down Expand Up @@ -4354,6 +4422,20 @@ impl SortitionDB {
)
}

/// Get the list of `vote-for-aggregate-key` operations processed in a given burnchain block.
/// This will be the same list in each PoX fork; it's up to the Stacks block-processing logic
/// to reject them.
pub fn get_vote_for_aggregate_key_ops(
conn: &Connection,
burn_header_hash: &BurnchainHeaderHash,
) -> Result<Vec<VoteForAggregateKeyOp>, db_error> {
query_rows(
conn,
"SELECT * FROM vote_for_aggregate_key WHERE burn_header_hash = ? ORDER BY vtxindex",
&[burn_header_hash],
)
}

/// Get the list of Transfer-STX operations processed in a given burnchain block.
/// This will be the same list in each PoX fork; it's up to the Stacks block-processing logic
/// to reject them.
Expand Down Expand Up @@ -5321,6 +5403,13 @@ impl<'a> SortitionHandleTx<'a> {
);
self.insert_delegate_stx(op)
}
BlockstackOperationType::VoteForAggregateKey(ref op) => {
info!(
"ACCEPTED({}) vote for aggregate key {} at {},{}",
op.block_height, &op.txid, op.block_height, op.vtxindex
);
self.insert_vote_for_aggregate_key(op)
}
}
}

Expand Down Expand Up @@ -5388,6 +5477,29 @@ impl<'a> SortitionHandleTx<'a> {
Ok(())
}

/// Insert a vote-for-aggregate-key op
fn insert_vote_for_aggregate_key(
&mut self,
op: &VoteForAggregateKeyOp,
) -> Result<(), db_error> {
let args: &[&dyn ToSql] = &[
&op.txid,
&op.vtxindex,
&u64_to_sql(op.block_height)?,
&op.burn_header_hash,
&op.sender.to_string(),
&serde_json::to_string(&op.aggregate_key).unwrap(),
&op.round,
&u64_to_sql(op.reward_cycle)?,
&op.signer_index,
&serde_json::to_string(&op.signer_key).unwrap(),
];

self.execute("REPLACE INTO vote_for_aggregate_key (txid, vtxindex, block_height, burn_header_hash, sender_addr, aggregate_key, round, reward_cycle, signer_index, signer_key) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", args)?;

Ok(())
}

/// Insert a transfer-stx op
fn insert_transfer_stx(&mut self, op: &TransferStxOp) -> Result<(), db_error> {
let args: &[&dyn ToSql] = &[
Expand Down
4 changes: 4 additions & 0 deletions stackslib/src/chainstate/burn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub enum Opcodes {
PreStx = 'p' as u8,
TransferStx = '$' as u8,
DelegateStx = '#' as u8,
VoteForAggregateKey = 'v' as u8,
}

// a burnchain block snapshot
Expand Down Expand Up @@ -192,6 +193,7 @@ impl Opcodes {
const HTTP_PEG_IN: &'static str = "peg_in";
const HTTP_PEG_OUT_REQUEST: &'static str = "peg_out_request";
const HTTP_PEG_OUT_FULFILL: &'static str = "peg_out_fulfill";
const HTTP_VOTE_FOR_AGGREGATE_KEY: &'static str = "vote_for_aggregate_key";

pub fn to_http_str(&self) -> &'static str {
match self {
Expand All @@ -202,6 +204,7 @@ impl Opcodes {
Opcodes::PreStx => Self::HTTP_PRE_STX,
Opcodes::TransferStx => Self::HTTP_TRANSFER_STX,
Opcodes::DelegateStx => Self::HTTP_DELEGATE_STX,
Opcodes::VoteForAggregateKey => Self::HTTP_VOTE_FOR_AGGREGATE_KEY,
}
}

Expand All @@ -214,6 +217,7 @@ impl Opcodes {
Self::HTTP_PRE_STX => Opcodes::PreStx,
Self::HTTP_TRANSFER_STX => Opcodes::TransferStx,
Self::HTTP_DELEGATE_STX => Opcodes::DelegateStx,
Self::HTTP_VOTE_FOR_AGGREGATE_KEY => Opcodes::VoteForAggregateKey,
_ => return None,
};

Expand Down
31 changes: 31 additions & 0 deletions stackslib/src/chainstate/burn/operations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use serde_json::json;
use stacks_common::types::chainstate::{
BlockHeaderHash, BurnchainHeaderHash, StacksAddress, StacksBlockId, TrieHash, VRFSeed,
};
use stacks_common::types::StacksPublicKeyBuffer;
use stacks_common::util::hash::{hex_bytes, to_hex, Hash160, Sha512Trunc256Sum};
use stacks_common::util::secp256k1::MessageSignature;
use stacks_common::util::vrf::VRFPublicKey;
Expand All @@ -46,6 +47,7 @@ pub mod leader_key_register;
pub mod stack_stx;
pub mod transfer_stx;
pub mod user_burn_support;
pub mod vote_for_aggregate_key;

#[cfg(test)]
mod test;
Expand Down Expand Up @@ -305,6 +307,22 @@ pub struct DelegateStxOp {
pub burn_header_hash: BurnchainHeaderHash, // hash of the burn chain block header
}

#[derive(Debug, PartialEq, Clone, Eq, Serialize, Deserialize)]
pub struct VoteForAggregateKeyOp {
pub sender: StacksAddress,
pub aggregate_key: StacksPublicKeyBuffer,
pub round: u32,
pub reward_cycle: u64,
pub signer_index: u16,
pub signer_key: StacksPublicKeyBuffer,

// common to all transactions
pub txid: Txid, // transaction ID
pub vtxindex: u32, // index in the block where this tx occurs
pub block_height: u64, // block height at which this tx occurs
pub burn_header_hash: BurnchainHeaderHash, // hash of the burn chain block header
}

fn hex_ser_memo<S: serde::Serializer>(bytes: &[u8], s: S) -> Result<S::Ok, S::Error> {
let inst = to_hex(bytes);
s.serialize_str(inst.as_str())
Expand Down Expand Up @@ -348,6 +366,7 @@ pub enum BlockstackOperationType {
StackStx(StackStxOp),
TransferStx(TransferStxOp),
DelegateStx(DelegateStxOp),
VoteForAggregateKey(VoteForAggregateKeyOp),
}

// serialization helpers for blockstack_op_to_json function
Expand Down Expand Up @@ -375,6 +394,7 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(_) => Opcodes::PreStx,
BlockstackOperationType::TransferStx(_) => Opcodes::TransferStx,
BlockstackOperationType::DelegateStx(_) => Opcodes::DelegateStx,
BlockstackOperationType::VoteForAggregateKey(_) => Opcodes::VoteForAggregateKey,
}
}

Expand All @@ -391,6 +411,7 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(ref data) => &data.txid,
BlockstackOperationType::TransferStx(ref data) => &data.txid,
BlockstackOperationType::DelegateStx(ref data) => &data.txid,
BlockstackOperationType::VoteForAggregateKey(ref data) => &data.txid,
}
}

Expand All @@ -403,6 +424,7 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(ref data) => data.vtxindex,
BlockstackOperationType::TransferStx(ref data) => data.vtxindex,
BlockstackOperationType::DelegateStx(ref data) => data.vtxindex,
BlockstackOperationType::VoteForAggregateKey(ref data) => data.vtxindex,
}
}

Expand All @@ -415,6 +437,7 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(ref data) => data.block_height,
BlockstackOperationType::TransferStx(ref data) => data.block_height,
BlockstackOperationType::DelegateStx(ref data) => data.block_height,
BlockstackOperationType::VoteForAggregateKey(ref data) => data.block_height,
}
}

Expand All @@ -427,6 +450,7 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(ref data) => data.burn_header_hash.clone(),
BlockstackOperationType::TransferStx(ref data) => data.burn_header_hash.clone(),
BlockstackOperationType::DelegateStx(ref data) => data.burn_header_hash.clone(),
BlockstackOperationType::VoteForAggregateKey(ref data) => data.burn_header_hash.clone(),
}
}

Expand All @@ -442,6 +466,9 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(ref mut data) => data.block_height = height,
BlockstackOperationType::TransferStx(ref mut data) => data.block_height = height,
BlockstackOperationType::DelegateStx(ref mut data) => data.block_height = height,
BlockstackOperationType::VoteForAggregateKey(ref mut data) => {
data.block_height = height
}
};
}

Expand All @@ -459,6 +486,9 @@ impl BlockstackOperationType {
BlockstackOperationType::PreStx(ref mut data) => data.burn_header_hash = hash,
BlockstackOperationType::TransferStx(ref mut data) => data.burn_header_hash = hash,
BlockstackOperationType::DelegateStx(ref mut data) => data.burn_header_hash = hash,
BlockstackOperationType::VoteForAggregateKey(ref mut data) => {
data.burn_header_hash = hash
}
};
}

Expand Down Expand Up @@ -550,6 +580,7 @@ impl fmt::Display for BlockstackOperationType {
BlockstackOperationType::UserBurnSupport(ref op) => write!(f, "{:?}", op),
BlockstackOperationType::TransferStx(ref op) => write!(f, "{:?}", op),
BlockstackOperationType::DelegateStx(ref op) => write!(f, "{:?}", op),
BlockstackOperationType::VoteForAggregateKey(ref op) => write!(f, "{:?}", op),
}
}
}
Expand Down

0 comments on commit 3d5adf5

Please sign in to comment.