Skip to content

Commit

Permalink
feat: support for TenureChange transaction types
Browse files Browse the repository at this point in the history
  • Loading branch information
zone117x committed Oct 26, 2023
1 parent 4e3cdb5 commit 30363ed
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 6 deletions.
81 changes: 76 additions & 5 deletions src/stacks_tx/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,18 @@ impl TransactionPayload {
}
x if x == TransactionPayloadID::VersionedSmartContract as u8 => {
let clarity_version_u8 = fd.read_u8()?;
let clarity_version = ClarityVersion::from_u8(clarity_version_u8).ok_or(format!(
"Failed to parse smart contract Clarity version: unknown value {}",
clarity_version_u8
))?;
let clarity_version =
ClarityVersion::from_u8(clarity_version_u8).ok_or(format!(
"Failed to parse smart contract Clarity version: unknown value {}",
clarity_version_u8
))?;
let payload = TransactionSmartContract::deserialize(fd)?;
TransactionPayload::VersionedSmartContract(payload, clarity_version)
}
x if x == TransactionPayloadID::TenureChange as u8 => {
let payload = TransactionTenureChange::deserialize(fd)?;
TransactionPayload::TenureChange(payload)
}
_ => {
return Err(format!(
"Failed to parse transaction -- unknown payload ID {}",
Expand Down Expand Up @@ -428,6 +433,40 @@ impl TransactionSmartContract {
}
}

impl TransactionTenureChange {
pub fn deserialize(fd: &mut Cursor<&[u8]>) -> Result<Self, DeserializeError> {
let mut previous_tenure_end = [0u8; 32];
fd.read_exact(&mut previous_tenure_end)?;

let previous_tenure_blocks = fd.read_u16::<BigEndian>()?;

let cause_u8: u8 = fd.read_u8()?;
let cause = TenureChangeCause::from_u8(cause_u8).ok_or(format!(
"Failed to parse transaction: invalid tenure change cause {}",
cause_u8
))?;

let mut pubkey_hash = [0u8; 20];
fd.read_exact(&mut pubkey_hash)?;

let mut signature = [0u8; 65];
fd.read_exact(&mut signature)?;

let signers_len: u32 = fd.read_u32::<BigEndian>()?;
let mut signers: Vec<u8> = vec![0u8; signers_len as usize];
fd.read_exact(&mut signers)?;

Ok(TransactionTenureChange {
previous_tenure_end,
previous_tenure_blocks,
cause,
pubkey_hash,
signature,
signers,
})
}
}

impl StacksMicroblockHeader {
pub fn deserialize(fd: &mut Cursor<&[u8]>) -> Result<Self, DeserializeError> {
let cursor_pos = fd.position() as usize;
Expand Down Expand Up @@ -622,6 +661,7 @@ pub enum TransactionPayloadID {
Coinbase = 4,
CoinbaseToAltRecipient = 5,
VersionedSmartContract = 6,
TenureChange = 7,
}

pub enum TransactionPayload {
Expand All @@ -631,11 +671,42 @@ pub enum TransactionPayload {
PoisonMicroblock(StacksMicroblockHeader, StacksMicroblockHeader),
Coinbase(CoinbasePayload),
CoinbaseToAltRecipient(CoinbasePayload, PrincipalData),
VersionedSmartContract(TransactionSmartContract, ClarityVersion)
VersionedSmartContract(TransactionSmartContract, ClarityVersion),
TenureChange(TransactionTenureChange),
}

pub struct CoinbasePayload(pub [u8; 32]);

pub struct TransactionTenureChange {
pub previous_tenure_end: [u8; 32],
pub previous_tenure_blocks: u16,
pub cause: TenureChangeCause,
pub pubkey_hash: [u8; 20],
pub signature: [u8; 65],
pub signers: Vec<u8>,
}

#[repr(u8)]
#[derive(PartialEq, Copy, Clone)]
pub enum TenureChangeCause {
BlockFound = 0,
NoBlockFound = 1,
NullMiner = 2,
}

impl TenureChangeCause {
pub fn from_u8(n: u8) -> Option<TenureChangeCause> {
match n {
x if x == TenureChangeCause::BlockFound as u8 => Some(TenureChangeCause::BlockFound),
x if x == TenureChangeCause::NoBlockFound as u8 => {
Some(TenureChangeCause::NoBlockFound)
}
x if x == TenureChangeCause::NullMiner as u8 => Some(TenureChangeCause::NullMiner),
_ => None,
}
}
}

pub struct TransactionSmartContract {
pub name: ClarityName,
pub code_body: StacksString,
Expand Down
37 changes: 36 additions & 1 deletion src/stacks_tx/neon_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use super::deserialize::{
StacksTransaction, StandardPrincipalData, TransactionAuth, TransactionAuthField,
TransactionAuthFieldID, TransactionAuthFlags, TransactionContractCall, TransactionPayload,
TransactionPayloadID, TransactionPublicKeyEncoding, TransactionSmartContract,
TransactionSpendingCondition, TransactionVersion,
TransactionSpendingCondition, TransactionTenureChange, TransactionVersion,
};

struct TxSerializationContext {
Expand Down Expand Up @@ -516,6 +516,12 @@ impl NeonJsSerialize for TransactionPayload {

smart_contract.neon_js_serialize(cx, obj, extra_ctx)?;
}
TransactionPayload::TenureChange(ref tenure_change) => {
let type_id = cx.number(TransactionPayloadID::TenureChange as u8);
obj.set(cx, "type_id", type_id)?;

tenure_change.neon_js_serialize(cx, obj, extra_ctx)?;
}
}
Ok(())
}
Expand Down Expand Up @@ -629,6 +635,35 @@ impl NeonJsSerialize for TransactionSmartContract {
}
}

impl NeonJsSerialize for TransactionTenureChange {
fn neon_js_serialize(
&self,
cx: &mut FunctionContext,
obj: &Handle<JsObject>,
_extra_ctx: &(),
) -> NeonResult<()> {
let previous_tenure_end = cx.string(encode_hex(&self.previous_tenure_end));
obj.set(cx, "previous_tenure_end", previous_tenure_end)?;

let previous_tenure_blocks = cx.number(self.previous_tenure_blocks);
obj.set(cx, "previous_tenure_blocks", previous_tenure_blocks)?;

let cause = cx.number(self.cause as u8);
obj.set(cx, "cause", cause)?;

let pubkey_hash = cx.string(encode_hex(&self.pubkey_hash));
obj.set(cx, "pubkey_hash", pubkey_hash)?;

let signature = cx.string(encode_hex(&self.signature));
obj.set(cx, "signature", signature)?;

let signers = cx.string(encode_hex(&self.signers));
obj.set(cx, "signers", signers)?;

Ok(())
}
}

impl NeonJsSerialize for StacksMicroblockHeader {
fn neon_js_serialize(
&self,
Expand Down

0 comments on commit 30363ed

Please sign in to comment.