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

Add tx sechashes as entropy src for established acct addr gen #2781

Merged
merged 5 commits into from
Apr 12, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Adds a transaction's code and data section hashes as additional
sources of entropy, to compute an established account's address.
([\#2781](https://github.com/anoma/namada/pull/2781))
34 changes: 15 additions & 19 deletions crates/core/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::hash::Hash;
use std::str::FromStr;

use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use borsh_ext::BorshSerializeExt;
use data_encoding::HEXUPPER;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -460,14 +459,14 @@ impl EstablishedAddressGen {
&mut self,
rng_source: impl AsRef<[u8]>,
) -> Address {
let gen_bytes = self.serialize_to_vec();
let bytes = [&gen_bytes, rng_source.as_ref()].concat();
let full_hash = Sha256::digest(&bytes);
// take first 20 bytes of the hash
let mut hash: [u8; HASH_LEN] = Default::default();
hash.copy_from_slice(&full_hash[..HASH_LEN]);
self.last_hash = full_hash.into();
Address::Established(EstablishedAddress { hash })
self.last_hash = {
let mut hasher_state = Sha256::new();
hasher_state.update(self.last_hash);
hasher_state.update(rng_source);
hasher_state.finalize()
}
.into();
Address::Established(self.last_hash.into())
}
}

Expand Down Expand Up @@ -586,6 +585,7 @@ impl InternalAddress {

#[cfg(test)]
pub mod tests {
use borsh_ext::BorshSerializeExt;
use proptest::prelude::*;

use super::*;
Expand Down Expand Up @@ -652,17 +652,13 @@ pub fn gen_established_address(seed: impl AsRef<str>) -> Address {
use rand::prelude::ThreadRng;
use rand::{thread_rng, RngCore};

let mut key_gen = EstablishedAddressGen::new(seed);
EstablishedAddressGen::new(seed).generate_address({
let mut thread_local_rng: ThreadRng = thread_rng();
let mut buffer = [0u8; 32];

let mut rng: ThreadRng = thread_rng();
let mut rng_bytes = [0u8; 32];
rng.fill_bytes(&mut rng_bytes[..]);
let rng_source = rng_bytes
.iter()
.map(|b| format!("{:02X}", b))
.collect::<Vec<String>>()
.join("");
key_gen.generate_address(rng_source)
thread_local_rng.fill_bytes(&mut buffer[..]);
buffer
})
}

/// Generate a new established address. Unlike `gen_established_address`, this
Expand Down
11 changes: 10 additions & 1 deletion crates/namada/src/vm/host_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1481,12 +1481,15 @@ where
}

/// Initialize a new account established address.
#[allow(clippy::too_many_arguments)]
pub fn tx_init_account<MEM, D, H, CA>(
env: &TxVmEnv<MEM, D, H, CA>,
code_hash_ptr: u64,
code_hash_len: u64,
code_tag_ptr: u64,
code_tag_len: u64,
entropy_source_ptr: u64,
entropy_source_len: u64,
result_ptr: u64,
) -> TxResult<()>
where
Expand All @@ -1511,14 +1514,20 @@ where

tx_validate_vp_code_hash::<MEM, D, H, CA>(env, &code_hash, &code_tag)?;

let (entropy_source, gas) = env
.memory
.read_bytes(entropy_source_ptr, entropy_source_len as _)
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?;
tx_charge_gas::<MEM, D, H, CA>(env, gas)?;

tracing::debug!("tx_init_account");

let code_hash = Hash::try_from(&code_hash[..])
.map_err(|e| TxRuntimeError::InvalidVpCodeHash(e.to_string()))?;
let mut state = env.state();
let (write_log, in_mem, _db) = state.split_borrow();
let gen = &in_mem.address_gen;
let (addr, gas) = write_log.init_account(gen, code_hash);
let (addr, gas) = write_log.init_account(gen, code_hash, &entropy_source);
let addr_bytes = addr.serialize_to_vec();
tx_charge_gas::<MEM, D, H, CA>(env, gas)?;
let gas = env
Expand Down
17 changes: 9 additions & 8 deletions crates/state/src/write_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,14 @@ impl WriteLog {
&mut self,
storage_address_gen: &EstablishedAddressGen,
vp_code_hash: Hash,
entropy_source: &[u8],
) -> (Address, u64) {
// If we've previously generated a new account, we use the local copy of
// the generator. Otherwise, we create a new copy from the storage
let address_gen =
self.address_gen.get_or_insert(storage_address_gen.clone());
let addr =
address_gen.generate_address("TODO more randomness".as_bytes());
let address_gen = self
.address_gen
.get_or_insert_with(|| storage_address_gen.clone());
let addr = address_gen.generate_address(entropy_source);
let key = storage::Key::validity_predicate(&addr);
let gas = (key.len() + vp_code_hash.len()) as u64
* STORAGE_WRITE_GAS_PER_BYTE;
Expand Down Expand Up @@ -743,7 +744,7 @@ mod tests {
// init
let init_vp = "initialized".as_bytes().to_vec();
let vp_hash = Hash::sha256(init_vp);
let (addr, gas) = write_log.init_account(&address_gen, vp_hash);
let (addr, gas) = write_log.init_account(&address_gen, vp_hash, &[]);
let vp_key = storage::Key::validity_predicate(&addr);
assert_eq!(
gas,
Expand Down Expand Up @@ -776,7 +777,7 @@ mod tests {

let init_vp = "initialized".as_bytes().to_vec();
let vp_hash = Hash::sha256(init_vp);
let (addr, _) = write_log.init_account(&address_gen, vp_hash);
let (addr, _) = write_log.init_account(&address_gen, vp_hash, &[]);
let vp_key = storage::Key::validity_predicate(&addr);

// update should fail
Expand All @@ -795,7 +796,7 @@ mod tests {

let init_vp = "initialized".as_bytes().to_vec();
let vp_hash = Hash::sha256(init_vp);
let (addr, _) = write_log.init_account(&address_gen, vp_hash);
let (addr, _) = write_log.init_account(&address_gen, vp_hash, &[]);
let vp_key = storage::Key::validity_predicate(&addr);

// delete should fail
Expand Down Expand Up @@ -830,7 +831,7 @@ mod tests {

// initialize an account
let vp1 = Hash::sha256("vp1".as_bytes());
let (addr1, _) = state.write_log.init_account(&address_gen, vp1);
let (addr1, _) = state.write_log.init_account(&address_gen, vp1, &[]);
state.write_log.commit_tx();

// write values
Expand Down
8 changes: 6 additions & 2 deletions crates/tests/src/vm_host_env/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,15 @@ pub fn init_storage() -> (Address, Address) {
});

// initialize a token
let token = tx_host_env::ctx().init_account(code_hash, &None).unwrap();
let token = tx_host_env::ctx()
.init_account(code_hash, &None, &[])
.unwrap();
let denom_key = token::storage_key::denom_key(&token);
let token_denom = token::Denomination(ANY_DENOMINATION);
// initialize an account
let account = tx_host_env::ctx().init_account(code_hash, &None).unwrap();
let account = tx_host_env::ctx()
.init_account(code_hash, &None, &[])
.unwrap();
let key = token::storage_key::balance_key(&token, &account);
let init_bal = Amount::from_uint(100, token_denom).unwrap();
tx_host_env::with(|env| {
Expand Down
6 changes: 3 additions & 3 deletions crates/tests/src/vm_host_env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ mod tests {
tx_host_env::init();

let code = vec![];
tx::ctx().init_account(code, &None).unwrap();
tx::ctx().init_account(code, &None, &[]).unwrap();
}

#[test]
Expand All @@ -229,7 +229,7 @@ mod tests {
let key = Key::wasm_code(&code_hash);
env.state.write_bytes(&key, &code).unwrap();
});
tx::ctx().init_account(code_hash, &None).unwrap();
tx::ctx().init_account(code_hash, &None, &[]).unwrap();
}

/// Test that a tx updating validity predicate that is not in the allowlist
Expand Down Expand Up @@ -329,7 +329,7 @@ mod tests {
});

// Initializing a new account with the VP should fail
tx::ctx().init_account(vp_hash, &None).unwrap();
tx::ctx().init_account(vp_hash, &None, &[]).unwrap();
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions crates/tests/src/vm_host_env/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,8 @@ mod native_tx_host_env {
code_hash_len: u64,
code_tag_ptr: u64,
code_tag_len: u64,
entropy_source_ptr: u64,
entropy_source_len: u64,
result_ptr: u64
));
native_host_fn!(tx_emit_ibc_event(event_ptr: u64, event_len: u64));
Expand Down
1 change: 1 addition & 0 deletions crates/tx_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub trait TxEnv: StorageRead + StorageWrite {
&mut self,
code_hash: impl AsRef<[u8]>,
code_tag: &Option<String>,
entropy_source: &[u8],
) -> Result<Address>;

/// Update a validity predicate
Expand Down
3 changes: 3 additions & 0 deletions crates/tx_prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ impl TxEnv for Ctx {
&mut self,
code_hash: impl AsRef<[u8]>,
code_tag: &Option<String>,
entropy_source: &[u8],
) -> Result<Address, Error> {
let code_hash = code_hash.as_ref();
let code_tag = code_tag.serialize_to_vec();
Expand All @@ -300,6 +301,8 @@ impl TxEnv for Ctx {
code_hash.len() as _,
code_tag.as_ptr() as _,
code_tag.len() as _,
entropy_source.as_ptr() as _,
entropy_source.len() as _,
result.as_ptr() as _,
)
};
Expand Down
2 changes: 2 additions & 0 deletions crates/vm_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub mod tx {
code_hash_len: u64,
code_tag_ptr: u64,
code_tag_len: u64,
entropy_source_ptr: u64,
entropy_source_len: u64,
result_ptr: u64,
);

Expand Down
16 changes: 15 additions & 1 deletion wasm/wasm_source/src/tx_init_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use namada_tx_prelude::*;

const HASH_LEN: usize = hash::HASH_LENGTH;

#[transaction(gas = 885069)]
fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult {
let signed = tx_data;
Expand All @@ -28,8 +30,20 @@ fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult {
err
})?;

let entropy = {
let mut buffer = [0u8; HASH_LEN * 2];

// Add code hash as entropy
buffer[..HASH_LEN].copy_from_slice(&signed.code_sechash().0);

// Add data hash as entropy
buffer[HASH_LEN..].copy_from_slice(&signed.data_sechash().0);

buffer
};

let address =
ctx.init_account(vp_code_sec.code.hash(), &vp_code_sec.tag)?;
ctx.init_account(vp_code_sec.code.hash(), &vp_code_sec.tag, &entropy)?;

match account::init_account(ctx, &address, tx_data) {
Ok(address) => {
Expand Down
Loading