-
Notifications
You must be signed in to change notification settings - Fork 977
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
init validator tx - verify ownership of used keys #2163
Changes from 5 commits
a20bd2a
2a97981
03524aa
0a64056
a9771c2
7adadaa
88578bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- Require to verify ownership of all validator keys when initialized on-chain. | ||
([\#2163](https://github.com/anoma/namada/pull/2163)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2076,6 +2076,85 @@ where | |
sentinel.set_invalid_commitment(); | ||
} | ||
|
||
/// Verify a transaction signature | ||
#[allow(clippy::too_many_arguments)] | ||
pub fn tx_verify_tx_section_signature<MEM, DB, H, CA>( | ||
env: &TxVmEnv<MEM, DB, H, CA>, | ||
hash_list_ptr: u64, | ||
hash_list_len: u64, | ||
public_keys_map_ptr: u64, | ||
public_keys_map_len: u64, | ||
threshold: u8, | ||
max_signatures_ptr: u64, | ||
max_signatures_len: u64, | ||
) -> TxResult<i64> | ||
where | ||
MEM: VmMemory, | ||
DB: storage::DB + for<'iter> storage::DBIter<'iter>, | ||
H: StorageHasher, | ||
CA: WasmCacheAccess, | ||
{ | ||
let (hash_list, gas) = env | ||
.memory | ||
.read_bytes(hash_list_ptr, hash_list_len as _) | ||
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?; | ||
|
||
let sentinel = unsafe { env.ctx.sentinel.get() }; | ||
tx_charge_gas(env, gas)?; | ||
let hashes = <[Hash; 1]>::try_from_slice(&hash_list) | ||
.map_err(TxRuntimeError::EncodingError)?; | ||
|
||
let (public_keys_map, gas) = env | ||
.memory | ||
.read_bytes(public_keys_map_ptr, public_keys_map_len as _) | ||
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?; | ||
tx_charge_gas(env, gas)?; | ||
let public_keys_map = | ||
namada_core::types::account::AccountPublicKeysMap::try_from_slice( | ||
&public_keys_map, | ||
) | ||
.map_err(TxRuntimeError::EncodingError)?; | ||
|
||
tx_charge_gas(env, gas)?; | ||
|
||
let (max_signatures, gas) = env | ||
.memory | ||
.read_bytes(max_signatures_ptr, max_signatures_len as _) | ||
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?; | ||
tx_charge_gas(env, gas)?; | ||
let max_signatures = Option::<u8>::try_from_slice(&max_signatures) | ||
.map_err(TxRuntimeError::EncodingError)?; | ||
|
||
let tx = unsafe { env.ctx.tx.get() }; | ||
|
||
tx_charge_gas( | ||
env, | ||
gas::VERIFY_TX_SIG_GAS * public_keys_map.idx_to_pk.len() as u64, | ||
)?; | ||
match tx.verify_signatures( | ||
&hashes, | ||
public_keys_map, | ||
&None, | ||
threshold, | ||
max_signatures, | ||
// This uses VpGasMeter, so we're charging the gas here manually | ||
// instead | ||
&mut None, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor thing here, we can change the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've refactored it in 88578bf but without the dynamic dispatch using a lambda instead. It also moves the gas metering logic back into the relevant places in |
||
) { | ||
Ok(_) => Ok(HostEnvResult::Success.to_i64()), | ||
Err(err) => match err { | ||
namada_core::proto::Error::OutOfGas(inner) => { | ||
sentinel.set_out_of_gas(); | ||
Err(TxRuntimeError::OutOfGas(inner)) | ||
} | ||
namada_core::proto::Error::InvalidSectionSignature(_) => { | ||
Ok(HostEnvResult::Fail.to_i64()) | ||
} | ||
_ => Ok(HostEnvResult::Fail.to_i64()), | ||
}, | ||
} | ||
} | ||
|
||
/// Evaluate a validity predicate with the given input data. | ||
pub fn vp_eval<MEM, DB, H, EVAL, CA>( | ||
env: &VpVmEnv<'static, MEM, DB, H, EVAL, CA>, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,6 @@ use std::marker::PhantomData; | |
pub use borsh::{BorshDeserialize, BorshSerialize}; | ||
pub use borsh_ext; | ||
use borsh_ext::BorshSerializeExt; | ||
pub use namada_core::ledger::eth_bridge; | ||
pub use namada_core::ledger::governance::storage as gov_storage; | ||
pub use namada_core::ledger::parameters::storage as parameters_storage; | ||
pub use namada_core::ledger::storage::types::encode; | ||
|
@@ -28,11 +27,14 @@ pub use namada_core::ledger::storage_api::{ | |
ResultExt, StorageRead, StorageWrite, | ||
}; | ||
pub use namada_core::ledger::tx_env::TxEnv; | ||
pub use namada_core::ledger::{eth_bridge, parameters}; | ||
pub use namada_core::proto::{Section, Tx}; | ||
use namada_core::types::account::AccountPublicKeysMap; | ||
pub use namada_core::types::address::Address; | ||
use namada_core::types::chain::CHAIN_ID_LENGTH; | ||
pub use namada_core::types::ethereum_events::EthAddress; | ||
use namada_core::types::internal::HostEnvResult; | ||
use namada_core::types::key::common; | ||
use namada_core::types::storage::TxIndex; | ||
pub use namada_core::types::storage::{ | ||
self, BlockHash, BlockHeight, Epoch, Header, BLOCK_HASH_LENGTH, | ||
|
@@ -361,3 +363,36 @@ impl TxEnv for Ctx { | |
pub fn tx_ibc_execute() { | ||
unsafe { namada_tx_ibc_execute() } | ||
} | ||
|
||
/// Verify section signatures against the given list of keys | ||
pub fn verify_signatures_of_pks( | ||
ctx: &Ctx, | ||
tx: &Tx, | ||
pks: Vec<common::PublicKey>, | ||
) -> EnvResult<bool> { | ||
let max_signatures_per_transaction = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we don't have support for validator multisig, it would only be an issue if the source of the tx is a mutisig with threshold > There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, I was wrong on this - we do have multisig validator support, but with the default this would still allow up to 10 multisig participants which should be sufficient |
||
parameters::max_signatures_per_transaction(ctx)?; | ||
|
||
// Require signatures from all the given keys | ||
let threshold = u8::try_from(pks.len()).into_storage_result()?; | ||
let public_keys_index_map = AccountPublicKeysMap::from_iter(pks); | ||
|
||
// Serialize parameters | ||
let max_signatures = max_signatures_per_transaction.serialize_to_vec(); | ||
let public_keys_map = public_keys_index_map.serialize_to_vec(); | ||
let targets = [tx.raw_header_hash()].serialize_to_vec(); | ||
|
||
let valid = unsafe { | ||
namada_tx_verify_tx_section_signature( | ||
targets.as_ptr() as _, | ||
targets.len() as _, | ||
public_keys_map.as_ptr() as _, | ||
public_keys_map.len() as _, | ||
threshold, | ||
max_signatures.as_ptr() as _, | ||
max_signatures.len() as _, | ||
) | ||
}; | ||
|
||
Ok(HostEnvResult::is_success(valid)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does a threshold of 0 mean here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's unused for signing - this field is only used for offline proposal votes