mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-03 22:03:06 +00:00
Merge pull request #89 from vacp2p/schouhy/remove-precomputed-hash-from-transaction
Remove precomputed hash from Transaction
This commit is contained in:
commit
4580812b64
@ -8,7 +8,7 @@ pub trait TreeLeavItem {
|
||||
|
||||
impl TreeLeavItem for Transaction {
|
||||
fn hash(&self) -> TreeHashType {
|
||||
self.hash
|
||||
self.hash()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@ pub enum TxKind {
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
///General transaction object
|
||||
pub struct Transaction {
|
||||
pub hash: TreeHashType,
|
||||
pub tx_kind: TxKind,
|
||||
///Tx input data (public part)
|
||||
pub execution_input: Vec<u8>,
|
||||
@ -58,70 +57,6 @@ pub struct Transaction {
|
||||
pub state_changes: (serde_json::Value, usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
///General transaction object
|
||||
pub struct TransactionPayload {
|
||||
pub tx_kind: TxKind,
|
||||
///Tx input data (public part)
|
||||
pub execution_input: Vec<u8>,
|
||||
///Tx output data (public_part)
|
||||
pub execution_output: Vec<u8>,
|
||||
///Tx input utxo commitments
|
||||
pub utxo_commitments_spent_hashes: Vec<TreeHashType>,
|
||||
///Tx output utxo commitments
|
||||
pub utxo_commitments_created_hashes: Vec<TreeHashType>,
|
||||
///Tx output nullifiers
|
||||
pub nullifier_created_hashes: Vec<TreeHashType>,
|
||||
///Execution proof (private part)
|
||||
pub execution_proof_private: String,
|
||||
///Encoded blobs of data
|
||||
pub encoded_data: Vec<(CipherText, Vec<u8>, Tag)>,
|
||||
///Transaction senders ephemeral pub key
|
||||
pub ephemeral_pub_key: Vec<u8>,
|
||||
///Public (Pedersen) commitment
|
||||
pub commitment: Vec<PedersenCommitment>,
|
||||
///tweak
|
||||
pub tweak: Tweak,
|
||||
///secret_r
|
||||
pub secret_r: [u8; 32],
|
||||
///Hex-encoded address of a smart contract account called
|
||||
pub sc_addr: String,
|
||||
///Recorded changes in state of smart contract
|
||||
///
|
||||
/// First value represents vector of changes, second is new length of a state
|
||||
pub state_changes: (serde_json::Value, usize),
|
||||
}
|
||||
|
||||
impl From<TransactionPayload> for Transaction {
|
||||
fn from(value: TransactionPayload) -> Self {
|
||||
let raw_data = serde_json::to_vec(&value).unwrap();
|
||||
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
|
||||
hasher.update(&raw_data);
|
||||
|
||||
let hash = <TreeHashType>::from(hasher.finalize_fixed());
|
||||
|
||||
Self {
|
||||
hash,
|
||||
tx_kind: value.tx_kind,
|
||||
execution_input: value.execution_input,
|
||||
execution_output: value.execution_output,
|
||||
utxo_commitments_spent_hashes: value.utxo_commitments_spent_hashes,
|
||||
utxo_commitments_created_hashes: value.utxo_commitments_created_hashes,
|
||||
nullifier_created_hashes: value.nullifier_created_hashes,
|
||||
execution_proof_private: value.execution_proof_private,
|
||||
encoded_data: value.encoded_data,
|
||||
ephemeral_pub_key: value.ephemeral_pub_key,
|
||||
commitment: value.commitment,
|
||||
tweak: value.tweak,
|
||||
secret_r: value.secret_r,
|
||||
sc_addr: value.sc_addr,
|
||||
state_changes: value.state_changes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct MintMoneyPublicTx {
|
||||
pub acc: [u8; 32],
|
||||
@ -216,8 +151,19 @@ impl ActionData {
|
||||
}
|
||||
|
||||
impl Transaction {
|
||||
/// Computes and returns the SHA-256 hash of the JSON-serialized representation of `self`.
|
||||
pub fn hash(&self) -> TreeHashType {
|
||||
// TODO: Remove `unwrap` by implementing a `to_bytes` method
|
||||
// that deterministically encodes all transaction fields to bytes
|
||||
// and guarantees serialization will succeed.
|
||||
let raw_data = serde_json::to_vec(&self).unwrap();
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(&raw_data);
|
||||
TreeHashType::from(hasher.finalize_fixed())
|
||||
}
|
||||
|
||||
pub fn log(&self) {
|
||||
info!("Transaction hash is {:?}", hex::encode(self.hash));
|
||||
info!("Transaction hash is {:?}", hex::encode(self.hash()));
|
||||
info!("Transaction tx_kind is {:?}", self.tx_kind);
|
||||
info!("Transaction execution_input is {:?}", {
|
||||
if let Ok(action) = serde_json::from_slice::<ActionData>(&self.execution_input) {
|
||||
@ -267,3 +213,44 @@ impl Transaction {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use secp256k1_zkp::{constants::SECRET_KEY_SIZE, Tweak};
|
||||
use sha2::{digest::FixedOutput, Digest};
|
||||
|
||||
use crate::{
|
||||
merkle_tree_public::TreeHashType,
|
||||
transaction::{Transaction, TxKind},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_transaction_hash_is_sha256_of_json_bytes() {
|
||||
let tx = Transaction {
|
||||
tx_kind: TxKind::Public,
|
||||
execution_input: vec![1, 2, 3, 4],
|
||||
execution_output: vec![5, 6, 7, 8],
|
||||
utxo_commitments_spent_hashes: vec![[9; 32], [10; 32], [11; 32], [12; 32]],
|
||||
utxo_commitments_created_hashes: vec![[13; 32]],
|
||||
nullifier_created_hashes: vec![[0; 32], [1; 32], [2; 32], [3; 32]],
|
||||
execution_proof_private: "loremipsum".to_string(),
|
||||
encoded_data: vec![(vec![255, 255, 255], vec![254, 254, 254], 1)],
|
||||
ephemeral_pub_key: vec![5; 32],
|
||||
commitment: vec![],
|
||||
tweak: Tweak::from_slice(&[7; SECRET_KEY_SIZE]).unwrap(),
|
||||
secret_r: [8; 32],
|
||||
sc_addr: "someAddress".to_string(),
|
||||
state_changes: (serde_json::Value::Null, 10),
|
||||
};
|
||||
let expected_hash = {
|
||||
let data = serde_json::to_vec(&tx).unwrap();
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(&data);
|
||||
TreeHashType::from(hasher.finalize_fixed())
|
||||
};
|
||||
|
||||
let hash = tx.hash();
|
||||
|
||||
assert_eq!(expected_hash, hash);
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,7 +309,6 @@ mod tests {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
Transaction {
|
||||
hash,
|
||||
tx_kind: TxKind::Private,
|
||||
execution_input: vec![],
|
||||
execution_output: vec![],
|
||||
|
||||
@ -11,7 +11,7 @@ use accounts::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use chain_storage::NodeChainStore;
|
||||
use common::transaction::{Transaction, TransactionPayload, TxKind};
|
||||
use common::transaction::{Transaction, TxKind};
|
||||
use config::NodeConfig;
|
||||
use log::info;
|
||||
use sc_core::proofs_circuits::{
|
||||
@ -249,7 +249,7 @@ impl NodeCore {
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok((
|
||||
TransactionPayload {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Private,
|
||||
execution_input: vec![],
|
||||
execution_output: vec![],
|
||||
@ -346,7 +346,7 @@ impl NodeCore {
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok((
|
||||
TransactionPayload {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Private,
|
||||
execution_input: vec![],
|
||||
execution_output: vec![],
|
||||
@ -462,7 +462,7 @@ impl NodeCore {
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok((
|
||||
TransactionPayload {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Private,
|
||||
execution_input: vec![],
|
||||
execution_output: vec![],
|
||||
@ -607,7 +607,7 @@ impl NodeCore {
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok((
|
||||
TransactionPayload {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Private,
|
||||
execution_input: vec![],
|
||||
execution_output: vec![],
|
||||
@ -730,7 +730,7 @@ impl NodeCore {
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok((
|
||||
TransactionPayload {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Shielded,
|
||||
execution_input: serde_json::to_vec(&ActionData::SendMoneyShieldedTx(
|
||||
SendMoneyShieldedTx {
|
||||
@ -823,7 +823,7 @@ impl NodeCore {
|
||||
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok(TransactionPayload {
|
||||
Ok(Transaction {
|
||||
tx_kind: TxKind::Deshielded,
|
||||
execution_input: serde_json::to_vec(&ActionData::SendMoneyDeshieldedTx(
|
||||
SendMoneyDeshieldedTx {
|
||||
@ -1462,7 +1462,7 @@ impl NodeCore {
|
||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info);
|
||||
|
||||
Ok((
|
||||
TransactionPayload {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Shielded,
|
||||
execution_input: vec![],
|
||||
execution_output: serde_json::to_vec(&publication).unwrap(),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use accounts::{account_core::Account, key_management::ephemeral_key_holder::EphemeralKeyHolder};
|
||||
use anyhow::Result;
|
||||
use common::transaction::{TransactionPayload, TxKind};
|
||||
use common::transaction::{Transaction, TxKind};
|
||||
use rand::thread_rng;
|
||||
use risc0_zkvm::Receipt;
|
||||
use secp256k1_zkp::{CommitmentSecrets, PedersenCommitment, Tweak};
|
||||
@ -15,8 +15,8 @@ pub fn create_public_transaction_payload(
|
||||
secret_r: [u8; 32],
|
||||
sc_addr: String,
|
||||
state_changes: (serde_json::Value, usize),
|
||||
) -> TransactionPayload {
|
||||
TransactionPayload {
|
||||
) -> Transaction {
|
||||
Transaction {
|
||||
tx_kind: TxKind::Public,
|
||||
execution_input,
|
||||
execution_output: vec![],
|
||||
|
||||
@ -77,7 +77,6 @@ impl SequencerCore {
|
||||
tx_roots: [[u8; 32]; 2],
|
||||
) -> Result<(), TransactionMalformationErrorKind> {
|
||||
let Transaction {
|
||||
hash,
|
||||
tx_kind,
|
||||
ref execution_input,
|
||||
ref execution_output,
|
||||
@ -85,11 +84,12 @@ impl SequencerCore {
|
||||
ref nullifier_created_hashes,
|
||||
..
|
||||
} = tx;
|
||||
let tx_hash = tx.hash();
|
||||
|
||||
let mempool_size = self.mempool.len();
|
||||
|
||||
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
|
||||
return Err(TransactionMalformationErrorKind::MempoolFullForRound { tx: *hash });
|
||||
return Err(TransactionMalformationErrorKind::MempoolFullForRound { tx: tx_hash });
|
||||
}
|
||||
|
||||
let curr_sequencer_roots = self.get_tree_roots();
|
||||
@ -97,7 +97,7 @@ impl SequencerCore {
|
||||
if tx_roots != curr_sequencer_roots {
|
||||
return Err(
|
||||
TransactionMalformationErrorKind::ChainStateFurtherThanTransactionState {
|
||||
tx: *hash,
|
||||
tx: tx_hash,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -111,7 +111,7 @@ impl SequencerCore {
|
||||
//Public transactions can not make private operations.
|
||||
return Err(
|
||||
TransactionMalformationErrorKind::PublicTransactionChangedPrivateData {
|
||||
tx: *hash,
|
||||
tx: tx_hash,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -123,7 +123,7 @@ impl SequencerCore {
|
||||
//between public and private state.
|
||||
return Err(
|
||||
TransactionMalformationErrorKind::PrivateTransactionChangedPublicData {
|
||||
tx: *hash,
|
||||
tx: tx_hash,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -132,7 +132,7 @@ impl SequencerCore {
|
||||
};
|
||||
|
||||
//Tree checks
|
||||
let tx_tree_check = self.store.pub_tx_store.get_tx(*hash).is_some();
|
||||
let tx_tree_check = self.store.pub_tx_store.get_tx(tx_hash).is_some();
|
||||
let nullifier_tree_check = nullifier_created_hashes
|
||||
.iter()
|
||||
.map(|nullifier_hash| {
|
||||
@ -152,18 +152,22 @@ impl SequencerCore {
|
||||
.any(|check| check);
|
||||
|
||||
if tx_tree_check {
|
||||
return Err(TransactionMalformationErrorKind::TxHashAlreadyPresentInTree { tx: *hash });
|
||||
return Err(
|
||||
TransactionMalformationErrorKind::TxHashAlreadyPresentInTree { tx: tx.hash() },
|
||||
);
|
||||
}
|
||||
|
||||
if nullifier_tree_check {
|
||||
return Err(
|
||||
TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: *hash },
|
||||
TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: tx.hash() },
|
||||
);
|
||||
}
|
||||
|
||||
if utxo_commitments_check {
|
||||
return Err(
|
||||
TransactionMalformationErrorKind::UTXOCommitmentAlreadyPresentInTree { tx: *hash },
|
||||
TransactionMalformationErrorKind::UTXOCommitmentAlreadyPresentInTree {
|
||||
tx: tx.hash(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -187,8 +191,6 @@ impl SequencerCore {
|
||||
tx: TransactionMempool,
|
||||
) -> Result<(), TransactionMalformationErrorKind> {
|
||||
let Transaction {
|
||||
// ToDo: remove hashing of transactions on node side [Issue #66]
|
||||
hash: _,
|
||||
ref utxo_commitments_created_hashes,
|
||||
ref nullifier_created_hashes,
|
||||
..
|
||||
@ -301,7 +303,6 @@ mod tests {
|
||||
}
|
||||
|
||||
fn create_dummy_transaction(
|
||||
hash: TreeHashType,
|
||||
nullifier_created_hashes: Vec<[u8; 32]>,
|
||||
utxo_commitments_spent_hashes: Vec<[u8; 32]>,
|
||||
utxo_commitments_created_hashes: Vec<[u8; 32]>,
|
||||
@ -309,7 +310,6 @@ mod tests {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
Transaction {
|
||||
hash,
|
||||
tx_kind: TxKind::Private,
|
||||
execution_input: vec![],
|
||||
execution_output: vec![],
|
||||
@ -328,7 +328,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn common_setup(sequencer: &mut SequencerCore) {
|
||||
let tx = create_dummy_transaction([12; 32], vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]);
|
||||
let tx = create_dummy_transaction(vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]);
|
||||
let tx_mempool = TransactionMempool { tx };
|
||||
sequencer.mempool.push_item(tx_mempool);
|
||||
|
||||
@ -454,7 +454,7 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let tx = create_dummy_transaction([1; 32], vec![[91; 32]], vec![[71; 32]], vec![[81; 32]]);
|
||||
let tx = create_dummy_transaction(vec![[91; 32]], vec![[71; 32]], vec![[81; 32]]);
|
||||
let tx_roots = sequencer.get_tree_roots();
|
||||
let result = sequencer.transaction_pre_check(&tx, tx_roots);
|
||||
|
||||
@ -471,7 +471,7 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let tx = create_dummy_transaction([2; 32], vec![[92; 32]], vec![[72; 32]], vec![[82; 32]]);
|
||||
let tx = create_dummy_transaction(vec![[92; 32]], vec![[72; 32]], vec![[82; 32]]);
|
||||
let tx_roots = sequencer.get_tree_roots();
|
||||
|
||||
// Fill the mempool
|
||||
@ -493,7 +493,7 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let tx = create_dummy_transaction([3; 32], vec![[93; 32]], vec![[73; 32]], vec![[83; 32]]);
|
||||
let tx = create_dummy_transaction(vec![[93; 32]], vec![[73; 32]], vec![[83; 32]]);
|
||||
let tx_roots = sequencer.get_tree_roots();
|
||||
let tx_mempool = TransactionMempool { tx };
|
||||
|
||||
@ -507,7 +507,7 @@ mod tests {
|
||||
let config = setup_sequencer_config();
|
||||
let mut sequencer = SequencerCore::start_from_config(config);
|
||||
|
||||
let tx = create_dummy_transaction([4; 32], vec![[94; 32]], vec![[7; 32]], vec![[8; 32]]);
|
||||
let tx = create_dummy_transaction(vec![[94; 32]], vec![[7; 32]], vec![[8; 32]]);
|
||||
let tx_mempool = TransactionMempool { tx };
|
||||
sequencer.mempool.push_item(tx_mempool);
|
||||
|
||||
|
||||
@ -38,6 +38,6 @@ impl MemPoolItem for TransactionMempool {
|
||||
type Identifier = TreeHashType;
|
||||
|
||||
fn identifier(&self) -> Self::Identifier {
|
||||
self.tx.hash
|
||||
self.tx.hash()
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user