Skip to content

Commit

Permalink
Recombined Tx and SigningTx.
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi committed Jan 27, 2023
1 parent 69deef8 commit 6809564
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 137 deletions.
3 changes: 2 additions & 1 deletion apps/src/lib/node/ledger/shell/process_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ mod test_process_proposal {
use namada::types::token::Amount;
use namada::types::transaction::encrypted::EncryptedTx;
use namada::types::transaction::{EncryptionKey, Fee, WrapperTx};
use namada::proto::TxCode;

use super::*;
use crate::facade::tendermint_proto::abci::RequestInitChain;
Expand Down Expand Up @@ -329,7 +330,7 @@ mod test_process_proposal {
.try_to_vec()
.expect("Test failed");
Tx {
code: vec![],
code: TxCode::Literal(vec![]),
data: Some(
SignedTxData {
sig,
Expand Down
3 changes: 2 additions & 1 deletion core/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pub mod generated;
mod types;

pub use types::{Dkg, Error, Signed, SignedTxData, Tx};
pub use types::{Dkg, Error, Signed, SignedTxData, Tx, TxCode};

#[cfg(test)]
mod tests {
Expand All @@ -17,6 +17,7 @@ mod tests {
fn encoding_round_trip() {
let tx = Tx {
code: "wasm code".as_bytes().to_owned(),
is_literal: true,
data: Some("arbitrary data".as_bytes().to_owned()),
timestamp: Some(std::time::SystemTime::now().into()),
inner_tx: None,
Expand Down
182 changes: 86 additions & 96 deletions core/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,97 +128,48 @@ where
}
}

/// A Tx with its code replaced by a hash salted with the Borsh
/// serialized timestamp of the transaction. This structure will almost
/// certainly be smaller than a Tx, yet in the usual cases it contains
/// enough information to confirm that the Tx is as intended and make a
/// non-malleable signature.
/// Represents either the literal code of a transaction or its hash.
#[derive(
Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema, Hash,
Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Hash, PartialEq, Eq,
)]
pub struct SigningTx {
pub code_hash: [u8; 32],
pub data: Option<Vec<u8>>,
pub timestamp: DateTimeUtc,
pub enum TxCode {
Hash([u8; 32]),
Literal(Vec<u8>),
}

impl SigningTx {
pub fn hash(&self) -> [u8; 32] {
let timestamp = Some(self.timestamp.into());
let mut bytes = vec![];
types::Tx {
code: self.code_hash.to_vec(),
data: self.data.clone(),
timestamp,
inner_tx: None,
inner_tx_code: None,
impl TxCode {
pub fn code(&self) -> Option<Vec<u8>> {
match self {
Self::Hash(_hash) => None,
Self::Literal(lit) => Some(lit.clone()),
}
.encode(&mut bytes)
.expect("encoding a transaction failed");
hash_tx(&bytes).0
}

/// Sign a transaction using [`SignedTxData`].
pub fn sign(self, keypair: &common::SecretKey) -> Self {
let to_sign = self.hash();
let sig = common::SigScheme::sign(keypair, to_sign);
let signed = SignedTxData {
data: self.data,
sig,
}
.try_to_vec()
.expect("Encoding transaction data shouldn't fail");
SigningTx {
code_hash: self.code_hash,
data: Some(signed),
timestamp: self.timestamp,
pub fn code_hash(&self) -> [u8; 32] {
match self {
Self::Hash(hash) => hash.clone(),
Self::Literal(lit) => hash_tx(lit).0,
}
}

/// Verify that the transaction has been signed by the secret key
/// counterpart of the given public key.
pub fn verify_sig(
&self,
pk: &common::PublicKey,
sig: &common::Signature,
) -> std::result::Result<(), VerifySigError> {
// Try to get the transaction data from decoded `SignedTxData`
let tx_data = self.data.clone().ok_or(VerifySigError::MissingData)?;
let signed_tx_data = SignedTxData::try_from_slice(&tx_data[..])
.expect("Decoding transaction data shouldn't fail");
let data = signed_tx_data.data;
let tx = SigningTx {
code_hash: self.code_hash,
data,
timestamp: self.timestamp,
};
let signed_data = tx.hash();
common::SigScheme::verify_signature_raw(pk, &signed_data, sig)
}

/// Expand this reduced Tx using the supplied code only if the the code
/// hashes to the stored code hash
pub fn expand(self, code: Vec<u8>) -> Option<Tx> {
if hash_tx(&code).0 == self.code_hash {
Some(Tx {
code,
data: self.data,
timestamp: self.timestamp,
inner_tx: None,
inner_tx_code: None,
})
} else {
None
pub fn expand(&mut self, code: Vec<u8>) {
if TxCode::Hash(hash_tx(&code).0) == *self {
*self = TxCode::Literal(code);
}
}
}

impl From<Tx> for SigningTx {
fn from(tx: Tx) -> SigningTx {
SigningTx {
code_hash: hash_tx(&tx.code).0,
data: tx.data,
timestamp: tx.timestamp,
pub fn contract(&mut self) {
*self = TxCode::Hash(self.code_hash());
}
pub fn is_literal(&self) -> bool {
match self {
Self::Literal(_) => true,
_ => false,
}
}
pub fn is_hash(&self) -> bool {
match self {
Self::Hash(_) => true,
_ => false,
}
}
}
Expand All @@ -230,7 +181,7 @@ impl From<Tx> for SigningTx {
Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema,
)]
pub struct Tx {
pub code: Vec<u8>,
pub code: TxCode,
pub data: Option<Vec<u8>>,
pub timestamp: DateTimeUtc,
/// the encrypted payload
Expand Down Expand Up @@ -284,8 +235,13 @@ impl TryFrom<&[u8]> for Tx {
),
None => None,
};
let code = if tx.is_literal {
TxCode::Literal(tx.code)
} else {
TxCode::Hash(tx.code.try_into().expect("Unable to deserialize code hash"))
};
Ok(Tx {
code: tx.code,
code,
data: tx.data,
timestamp,
inner_tx,
Expand All @@ -309,7 +265,8 @@ impl From<Tx> for types::Tx {
};

types::Tx {
code: tx.code,
code: tx.code.code().unwrap_or(tx.code.code_hash().to_vec()),
is_literal: tx.code.is_literal(),
data: tx.data,
timestamp,
inner_tx,
Expand Down Expand Up @@ -407,7 +364,7 @@ impl From<Tx> for ResponseDeliverTx {
impl Tx {
pub fn new(code: Vec<u8>, data: Option<Vec<u8>>) -> Self {
Tx {
code,
code: TxCode::Literal(code),
data,
timestamp: DateTimeUtc::now(),
inner_tx: None,
Expand All @@ -424,23 +381,42 @@ impl Tx {
}

pub fn hash(&self) -> [u8; 32] {
SigningTx::from(self.clone()).hash()
let timestamp = Some(self.timestamp.into());
let mut bytes = vec![];
types::Tx {
code: self.code.code().unwrap_or(self.code.code_hash().to_vec()),
is_literal: self.code.is_literal(),
data: self.data.clone(),
timestamp,
inner_tx: None,
inner_tx_code: None,
}
.encode(&mut bytes)
.expect("encoding a transaction failed");
hash_tx(&bytes).0
}

pub fn code_hash(&self) -> [u8; 32] {
SigningTx::from(self.clone()).code_hash
self.code.code_hash()
}

/// Sign a transaction using [`SignedTxData`].
pub fn sign(mut self, keypair: &common::SecretKey) -> Self {
let code = self.code.clone();
let inner_tx = std::mem::take(&mut self.inner_tx);
let inner_tx_code = std::mem::take(&mut self.inner_tx_code);
let tx = SigningTx::from(self)
.sign(keypair)
.expand(code)
.expect("code hashes to unexpected value");
Self { inner_tx, inner_tx_code, ..tx }
pub fn sign(self, keypair: &common::SecretKey) -> Self {
let to_sign = self.hash();
let sig = common::SigScheme::sign(keypair, to_sign);
let signed = SignedTxData {
data: self.data,
sig,
}
.try_to_vec()
.expect("Encoding transaction data shouldn't fail");
Tx {
code: self.code,
data: Some(signed),
timestamp: self.timestamp,
inner_tx: self.inner_tx,
inner_tx_code: self.inner_tx_code,
}
}

/// Verify that the transaction has been signed by the secret key
Expand All @@ -450,7 +426,20 @@ impl Tx {
pk: &common::PublicKey,
sig: &common::Signature,
) -> std::result::Result<(), VerifySigError> {
SigningTx::from(self.clone()).verify_sig(pk, sig)
// Try to get the transaction data from decoded `SignedTxData`
let tx_data = self.data.clone().ok_or(VerifySigError::MissingData)?;
let signed_tx_data = SignedTxData::try_from_slice(&tx_data[..])
.expect("Decoding transaction data shouldn't fail");
let data = signed_tx_data.data;
let tx = Tx {
code: self.code.clone(),
data,
timestamp: self.timestamp,
inner_tx: self.inner_tx.clone(),
inner_tx_code: self.inner_tx_code.clone(),
};
let signed_data = tx.hash();
common::SigScheme::verify_signature_raw(pk, &signed_data, sig)
}

#[cfg(feature = "ferveo-tpke")]
Expand Down Expand Up @@ -555,7 +544,8 @@ mod tests {
assert_eq!(tx_from_bytes, tx);

let types_tx = types::Tx {
code,
code: code.clone(),
is_literal: true,
data: Some(data),
timestamp: None,
inner_tx: None,
Expand Down
2 changes: 0 additions & 2 deletions core/src/types/transaction/encrypted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
#[cfg(feature = "ferveo-tpke")]
pub mod encrypted_tx {
use std::io::{Error, ErrorKind, Write};
use std::hash::Hasher;
use std::hash::Hash;

use ark_ec::PairingEngine;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
Expand Down
12 changes: 6 additions & 6 deletions core/src/types/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,19 @@ pub mod tx_types {
.map(|data| SignedTxData::try_from_slice(&data[..]))
{
let signed_hash = Tx {
code: tx.code,
code: tx.code.clone(),
data: Some(data.clone()),
timestamp: tx.timestamp,
inner_tx: None,
inner_tx_code: None,
inner_tx: tx.inner_tx.clone(),
inner_tx_code: tx.inner_tx_code.clone(),
}
.hash();
match TxType::try_from(Tx {
code: vec![],
code: tx.code,
data: Some(data),
timestamp: tx.timestamp,
inner_tx: None,
inner_tx_code: None,
inner_tx: tx.inner_tx,
inner_tx_code: tx.inner_tx_code,
})
.map_err(|err| TxError::Deserialization(err.to_string()))?
{
Expand Down
1 change: 1 addition & 0 deletions proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ message Tx {
google.protobuf.Timestamp timestamp = 3;
optional bytes inner_tx = 4;
optional bytes inner_tx_code = 5;
bool is_literal = 6;
}

message Dkg { string data = 1; }
Expand Down
4 changes: 2 additions & 2 deletions shared/src/ledger/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ where
CA: 'static + WasmCacheAccess + Sync,
{
gas_meter
.add_compiling_fee(tx.code.len())
.add_compiling_fee(tx.code.code().expect("tx code not present").len())
.map_err(Error::GasError)?;
let empty = vec![];
let tx_data = tx.data.as_ref().unwrap_or(&empty);
Expand All @@ -171,7 +171,7 @@ where
write_log,
gas_meter,
tx_index,
&tx.code,
&tx.code.code().expect("tx code not present"),
tx_data,
vp_wasm_cache,
tx_wasm_cache,
Expand Down
Loading

0 comments on commit 6809564

Please sign in to comment.