Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support versioned contract transactions #257

Merged
merged 2 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
95 changes: 91 additions & 4 deletions src/chainstate/stacks/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,30 @@ 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),
}
}

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 +150,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 +192,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 +1629,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 +1678,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 +1733,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