Skip to content

Commit

Permalink
Merge branch 'tiago/addr-generator-randomness' (#2781)
Browse files Browse the repository at this point in the history
* origin/tiago/addr-generator-randomness:
  Changelog for #2781
  Add entropy source to `tx_init_account`
  More addr gen refactoring
  Refactor `EstablishedAddressGen::generate_address`
  Lazily clone storage addr gen
  • Loading branch information
tzemanovic committed Apr 1, 2024
2 parents 2612fae + eb3e05d commit 82aee6e
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 34 deletions.
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 namada_macros::BorshDeserializer;
#[cfg(feature = "migrations")]
Expand Down Expand Up @@ -472,14 +471,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 @@ -600,6 +599,7 @@ impl InternalAddress {

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

use super::*;
Expand Down Expand Up @@ -666,17 +666,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 @@ -1463,12 +1463,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 @@ -1493,14 +1496,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 @@ -462,13 +462,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 @@ -839,7 +840,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 @@ -872,7 +873,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 @@ -891,7 +892,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 @@ -926,7 +927,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 @@ -246,11 +246,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 @@ -215,7 +215,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 @@ -230,7 +230,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 @@ -330,7 +330,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]
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

0 comments on commit 82aee6e

Please sign in to comment.