Merge pull request #257 from hirosystems/fix/versioned-contract

fix: support versioned contract transactions
This commit is contained in:
Brice Dobry
2023-04-18 12:46:29 -04:00
committed by GitHub
2 changed files with 93 additions and 4 deletions

View File

@@ -618,6 +618,8 @@ pub enum TransactionPayloadID {
ContractCall = 2,
PoisonMicroblock = 3,
Coinbase = 4,
CoinbaseToAltRecipient = 5,
VersionedSmartContract = 6,
}
/// Encoding of an asset type identifier

View File

@@ -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 {
@@ -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))?;
@@ -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)?;
@@ -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";
@@ -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,
@@ -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]