Skip to content

Commit

Permalink
fix(tari-script): use tari script encoding for execution stack serde …
Browse files Browse the repository at this point in the history
…de/serialization
  • Loading branch information
sdbondi committed Oct 10, 2022
1 parent e59be99 commit 9ab4274
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ impl TryFrom<TransactionInput> for grpc::TransactionInput {
script: input
.script()
.map_err(|_| "Non-compact Transaction input should contain script".to_string())?
.as_bytes(),
input_data: input.input_data.as_bytes(),
.to_bytes(),
input_data: input.input_data.to_bytes(),
script_signature,
sender_offset_public_key: input
.sender_offset_public_key()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl From<TransactionOutput> for grpc::TransactionOutput {
features: Some(output.features.into()),
commitment: Vec::from(output.commitment.as_bytes()),
range_proof: Vec::from(output.proof.as_bytes()),
script: output.script.as_bytes(),
script: output.script.to_bytes(),
sender_offset_public_key: output.sender_offset_public_key.as_bytes().to_vec(),
metadata_signature: Some(grpc::ComSignature {
public_nonce_commitment: Vec::from(output.metadata_signature.public_nonce().as_bytes()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ impl From<UnblindedOutput> for grpc::UnblindedOutput {
value: u64::from(output.value),
spending_key: output.spending_key.as_bytes().to_vec(),
features: Some(output.features.into()),
script: output.script.as_bytes(),
input_data: output.input_data.as_bytes(),
script: output.script.to_bytes(),
input_data: output.input_data.to_bytes(),
script_private_key: output.script_private_key.as_bytes().to_vec(),
sender_offset_public_key: output.sender_offset_public_key.as_bytes().to_vec(),
metadata_signature: Some(grpc::ComSignature {
Expand Down
4 changes: 2 additions & 2 deletions base_layer/core/src/consensus/consensus_encoding/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSi

impl ConsensusEncoding for TariScript {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
self.as_bytes().consensus_encode(writer)
self.to_bytes().consensus_encode(writer)
}
}

Expand All @@ -54,7 +54,7 @@ impl ConsensusDecoding for TariScript {

impl ConsensusEncoding for ExecutionStack {
fn consensus_encode<W: io::Write>(&self, writer: &mut W) -> Result<(), io::Error> {
self.as_bytes().consensus_encode(writer)
self.to_bytes().consensus_encode(writer)
}
}

Expand Down
8 changes: 4 additions & 4 deletions base_layer/core/src/proto/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl TryFrom<TransactionInput> for proto::types::TransactionInput {
if input.is_compact() {
let output_hash = input.output_hash();
Ok(Self {
input_data: input.input_data.as_bytes(),
input_data: input.input_data.to_bytes(),
script_signature: Some(input.script_signature.into()),
output_hash: output_hash.to_vec(),
..Default::default()
Expand All @@ -192,8 +192,8 @@ impl TryFrom<TransactionInput> for proto::types::TransactionInput {
script: input
.script()
.map_err(|_| "Non-compact Transaction input should contain script".to_string())?
.as_bytes(),
input_data: input.input_data.as_bytes(),
.to_bytes(),
input_data: input.input_data.to_bytes(),
script_signature: Some(input.script_signature.clone().into()),
sender_offset_public_key: input
.sender_offset_public_key()
Expand Down Expand Up @@ -277,7 +277,7 @@ impl From<TransactionOutput> for proto::types::TransactionOutput {
features: Some(output.features.into()),
commitment: Some(output.commitment.into()),
range_proof: output.proof.to_vec(),
script: output.script.as_bytes(),
script: output.script.to_bytes(),
sender_offset_public_key: output.sender_offset_public_key.as_bytes().to_vec(),
metadata_signature: Some(output.metadata_signature.into()),
covenant: output.covenant.to_bytes(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,11 @@ impl TransactionInput {
SpentOutput::OutputData { ref script, .. } => {
match script.execute_with_context(&self.input_data, &context)? {
StackItem::PublicKey(pubkey) => Ok(pubkey),
_ => Err(TransactionError::ScriptExecutionError(
"The script executed successfully but it did not leave a public key on the stack".to_string(),
)),
item => Err(TransactionError::ScriptExecutionError(format!(
"The script executed successfully but it did not leave a public key on the stack. Remaining \
stack item was {:?}",
item
))),
}
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl From<SingleRoundSenderData> for proto::SingleRoundSenderData {
metadata: Some(sender_data.metadata.into()),
message: sender_data.message,
features: Some(sender_data.features.into()),
script: sender_data.script.as_bytes(),
script: sender_data.script.to_bytes(),
sender_offset_public_key: sender_data.sender_offset_public_key.to_vec(),
public_commitment_nonce: sender_data.public_commitment_nonce.to_vec(),
covenant: sender_data.covenant.to_consensus_bytes(),
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/tests/chain_storage_tests/chain_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,7 @@ mod malleability {
fn script() {
check_output_malleability(|block: &mut Block| {
let output = &mut block.body.outputs_mut()[0];
let mut script_bytes = output.script.as_bytes();
let mut script_bytes = output.script.to_bytes();
Opcode::PushZero.to_bytes(&mut script_bytes);
let mod_script = TariScript::from_bytes(&script_bytes).unwrap();
output.script = mod_script;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1417,8 +1417,8 @@ impl From<KnownOneSidedPaymentScript> for KnownOneSidedPaymentScriptSql {
let script_lock_height = known_script.script_lock_height as i64;
let script_hash = known_script.script_hash;
let private_key = known_script.private_key.as_bytes().to_vec();
let script = known_script.script.as_bytes().to_vec();
let input = known_script.input.as_bytes().to_vec();
let script = known_script.script.to_bytes().to_vec();
let input = known_script.input.to_bytes().to_vec();
KnownOneSidedPaymentScriptSql {
script_hash,
private_key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ impl NewOutputSql {
status: status as i32,
received_in_tx_id: received_in_tx_id.map(|i| i.as_u64() as i64),
hash: Some(output.hash.to_vec()),
script: output.unblinded_output.script.as_bytes(),
input_data: output.unblinded_output.input_data.as_bytes(),
script: output.unblinded_output.script.to_bytes(),
input_data: output.unblinded_output.input_data.to_bytes(),
script_private_key: output.unblinded_output.script_private_key.to_vec(),
metadata: Some(output.unblinded_output.features.metadata.clone()),
sender_offset_public_key: output.unblinded_output.sender_offset_public_key.to_vec(),
Expand Down
10 changes: 5 additions & 5 deletions infrastructure/tari_script/src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl TariScript {
}
}

pub fn as_bytes(&self) -> Vec<u8> {
pub fn to_bytes(&self) -> Vec<u8> {
self.script.iter().fold(Vec::new(), |mut bytes, op| {
op.to_bytes(&mut bytes);
bytes
Expand All @@ -137,7 +137,7 @@ impl TariScript {
if D::output_size() < 32 {
return Err(ScriptError::InvalidDigest);
}
let h = D::digest(&self.as_bytes());
let h = D::digest(&self.to_bytes());
Ok(slice_to_hash(&h.as_slice()[..32]))
}

Expand Down Expand Up @@ -178,7 +178,7 @@ impl TariScript {
pub fn script_message(&self, pub_key: &RistrettoPublicKey) -> Result<RistrettoSecretKey, ScriptError> {
let b = Blake256::new()
.chain(pub_key.as_bytes())
.chain(&self.as_bytes())
.chain(&self.to_bytes())
.finalize();
RistrettoSecretKey::from_bytes(b.as_slice()).map_err(|_| ScriptError::InvalidSignature)
}
Expand Down Expand Up @@ -562,7 +562,7 @@ impl Hex for TariScript {
}

fn to_hex(&self) -> String {
to_hex(&self.as_bytes())
to_hex(&self.to_bytes())
}
}

Expand Down Expand Up @@ -948,7 +948,7 @@ mod test {
#[test]
fn serialisation() {
let script = script!(Add Sub Add);
assert_eq!(&script.as_bytes(), &[0x93, 0x94, 0x93]);
assert_eq!(&script.to_bytes(), &[0x93, 0x94, 0x93]);
assert_eq!(TariScript::from_bytes(&[0x93, 0x94, 0x93]).unwrap(), script);
assert_eq!(script.to_hex(), "939493");
assert_eq!(TariScript::from_hex("939493").unwrap(), script);
Expand Down
107 changes: 81 additions & 26 deletions infrastructure/tari_script/src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ use serde::{
};
use tari_utilities::hex::{from_hex, Hex};

use crate::TariScript;
use crate::{ExecutionStack, TariScript};

impl Serialize for TariScript {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let script_bin = self.as_bytes();
let script_bin = self.to_bytes();
if ser.is_human_readable() {
ser.serialize_str(&script_bin.to_hex())
} else {
Expand All @@ -40,44 +40,99 @@ impl Serialize for TariScript {
}
}

struct ScriptVisitor;
impl<'de> Deserialize<'de> for TariScript {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
struct ScriptVisitor;

impl<'de> Visitor<'de> for ScriptVisitor {
type Value = TariScript;
impl<'de> Visitor<'de> for ScriptVisitor {
type Value = TariScript;

fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("Expecting a binary array or hex string")
}
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("Expecting a binary array or hex string")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: Error {
let bytes = from_hex(v).map_err(|e| E::custom(e.to_string()))?;
self.visit_bytes(&bytes)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: Error {
let bytes = from_hex(v).map_err(|e| E::custom(e.to_string()))?;
self.visit_bytes(&bytes)
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where E: Error {
self.visit_str(&v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where E: Error {
self.visit_str(&v)
}

fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: Error {
TariScript::from_bytes(v).map_err(|e| E::custom(e.to_string()))
}

fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where E: Error {
self.visit_bytes(v)
}
}

fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: Error {
TariScript::from_bytes(v).map_err(|e| E::custom(e.to_string()))
if de.is_human_readable() {
de.deserialize_string(ScriptVisitor)
} else {
de.deserialize_bytes(ScriptVisitor)
}
}
}

fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where E: Error {
self.visit_bytes(v)
// -------------------------------- ExecutionStack -------------------------------- //
impl Serialize for ExecutionStack {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let stack_bin = self.to_bytes();
if ser.is_human_readable() {
ser.serialize_str(&stack_bin.to_hex())
} else {
ser.serialize_bytes(&stack_bin)
}
}
}

impl<'de> Deserialize<'de> for TariScript {
impl<'de> Deserialize<'de> for ExecutionStack {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
struct ExecutionStackVisitor;

impl<'de> Visitor<'de> for ExecutionStackVisitor {
type Value = ExecutionStack;

fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("Expecting a binary array or hex string")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: Error {
let bytes = from_hex(v).map_err(|e| E::custom(e.to_string()))?;
self.visit_bytes(&bytes)
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where E: Error {
self.visit_str(&v)
}

fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: Error {
ExecutionStack::from_bytes(v).map_err(|e| E::custom(e.to_string()))
}

fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where E: Error {
self.visit_bytes(v)
}
}

if de.is_human_readable() {
de.deserialize_string(ScriptVisitor)
de.deserialize_string(ExecutionStackVisitor)
} else {
de.deserialize_bytes(ScriptVisitor)
de.deserialize_bytes(ExecutionStackVisitor)
}
}
}
Loading

0 comments on commit 9ab4274

Please sign in to comment.