Skip to content

Commit

Permalink
fix: support versioned contract transactions
Browse files Browse the repository at this point in the history
The upstream changes for 2.1 added support to pass the Clarity version
when deploying a contract. Using this new transaction type is the
default from stacks.js, so it makes sense to support this new type in
the subnet as well.
  • Loading branch information
obycode committed Apr 18, 2023
1 parent 7d373f0 commit f5ab5c5
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/chainstate/stacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,8 @@ pub enum TransactionPayloadID {
ContractCall = 2,
PoisonMicroblock = 3,
Coinbase = 4,
CoinbaseToAltRecipient = 5,
VersionedSmartContract = 6,
}

/// Encoding of an asset type identifier
Expand Down
96 changes: 92 additions & 4 deletions src/chainstate/stacks/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,31 @@ impl StacksMessageCodec for TransactionSmartContract {
}
}

fn ClarityVersion_consensus_serialize<W: Write>(
version: &ClarityVersion,
fd: &mut W,
) -> Result<(), codec_error> {
match *version {
ClarityVersion::Clarity1 => write_next(fd, &1u8)?,
ClarityVersion::Clarity2 => write_next(fd, &2u8)?,
}
Ok(())
}

fn ClarityVersion_consensus_deserialize<R: Read>(
fd: &mut R,
) -> Result<ClarityVersion, codec_error> {
let version_byte: u8 = read_next(fd)?;
match version_byte {
1u8 => Ok(ClarityVersion::Clarity1),
2u8 => Ok(ClarityVersion::Clarity2),
_ => Err(codec_error::DeserializeError(format!(
"Unrecognized ClarityVersion byte {}",
&version_byte
))),
}
}

impl StacksMessageCodec for TransactionPayload {
fn consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), codec_error> {
match *self {
Expand All @@ -126,9 +151,17 @@ impl StacksMessageCodec for TransactionPayload {
write_next(fd, &(TransactionPayloadID::ContractCall as u8))?;
cc.consensus_serialize(fd)?;
}
TransactionPayload::SmartContract(ref sc, _) => {
write_next(fd, &(TransactionPayloadID::SmartContract as u8))?;
sc.consensus_serialize(fd)?;
TransactionPayload::SmartContract(ref sc, ref version_opt) => {
if let Some(version) = version_opt {
// caller requests a specific Clarity version
write_next(fd, &(TransactionPayloadID::VersionedSmartContract as u8))?;
ClarityVersion_consensus_serialize(&version, fd)?;
sc.consensus_serialize(fd)?;
} else {
// caller requests to use whatever the current clarity version is
write_next(fd, &(TransactionPayloadID::SmartContract as u8))?;
sc.consensus_serialize(fd)?;
}
}
TransactionPayload::PoisonMicroblock(ref h1, ref h2) => {
write_next(fd, &(TransactionPayloadID::PoisonMicroblock as u8))?;
Expand Down Expand Up @@ -160,6 +193,11 @@ impl StacksMessageCodec for TransactionPayload {
let payload: TransactionSmartContract = read_next(fd)?;
TransactionPayload::SmartContract(payload, None)
}
x if x == TransactionPayloadID::VersionedSmartContract as u8 => {
let version = ClarityVersion_consensus_deserialize(fd)?;
let payload: TransactionSmartContract = read_next(fd)?;
TransactionPayload::SmartContract(payload, Some(version))
}
x if x == TransactionPayloadID::PoisonMicroblock as u8 => {
let h1: StacksMicroblockHeader = read_next(fd)?;
let h2: StacksMicroblockHeader = read_next(fd)?;
Expand Down Expand Up @@ -1592,7 +1630,7 @@ mod test {
}

#[test]
fn tx_stacks_transacton_payload_contracts() {
fn tx_stacks_transaction_payload_contracts() {
let hello_contract_call = "hello-contract-call";
let hello_contract_name = "hello-contract-name";
let hello_function_name = "hello-function-name";
Expand Down Expand Up @@ -1641,12 +1679,48 @@ mod test {
.consensus_serialize(&mut smart_contract_bytes)
.unwrap();

let mut version_1_smart_contract_bytes = vec![];
ClarityVersion_consensus_serialize(
&ClarityVersion::Clarity1,
&mut version_1_smart_contract_bytes,
)
.unwrap();
smart_contract
.name
.consensus_serialize(&mut version_1_smart_contract_bytes)
.unwrap();
smart_contract
.code_body
.consensus_serialize(&mut version_1_smart_contract_bytes)
.unwrap();

let mut version_2_smart_contract_bytes = vec![];
ClarityVersion_consensus_serialize(
&ClarityVersion::Clarity2,
&mut version_2_smart_contract_bytes,
)
.unwrap();
smart_contract
.name
.consensus_serialize(&mut version_2_smart_contract_bytes)
.unwrap();
smart_contract
.code_body
.consensus_serialize(&mut version_2_smart_contract_bytes)
.unwrap();

let mut transaction_contract_call = vec![TransactionPayloadID::ContractCall as u8];
transaction_contract_call.append(&mut contract_call_bytes.clone());

let mut transaction_smart_contract = vec![TransactionPayloadID::SmartContract as u8];
transaction_smart_contract.append(&mut smart_contract_bytes.clone());

let mut v1_smart_contract = vec![TransactionPayloadID::VersionedSmartContract as u8];
v1_smart_contract.append(&mut version_1_smart_contract_bytes.clone());

let mut v2_smart_contract = vec![TransactionPayloadID::VersionedSmartContract as u8];
v2_smart_contract.append(&mut version_2_smart_contract_bytes.clone());

check_codec_and_corruption::<TransactionContractCall>(&contract_call, &contract_call_bytes);
check_codec_and_corruption::<TransactionSmartContract>(
&smart_contract,
Expand All @@ -1660,6 +1734,20 @@ mod test {
&TransactionPayload::SmartContract(smart_contract.clone(), None),
&transaction_smart_contract,
);
check_codec_and_corruption::<TransactionPayload>(
&TransactionPayload::SmartContract(
smart_contract.clone(),
Some(ClarityVersion::Clarity1),
),
&v1_smart_contract,
);
check_codec_and_corruption::<TransactionPayload>(
&TransactionPayload::SmartContract(
smart_contract.clone(),
Some(ClarityVersion::Clarity2),
),
&v2_smart_contract,
);
}

#[test]
Expand Down

0 comments on commit f5ab5c5

Please sign in to comment.