Skip to content

Commit

Permalink
Feat: Allow hashchain to be initialized with new directly (#846)
Browse files Browse the repository at this point in the history
## Description

For the mainnet Aurora Engine we must use the `pause_contract` +
`start_hashchain` migration procedure because it is already live.
However, for new silos it will be useful to have the hashchain enabled
from the start. This PR adds a new optional parameter to the `new`
function where an initial (genesis) hashchain value can be specified and
then hashchain will be enabled on all transactions going forward.

## Performance / NEAR gas cost considerations

N/A; impacts `new` only.

## Testing

Tests updated to use `new` for starting the hashchain by default. Some
tests still use the migration procedure to ensure that is also tested.
  • Loading branch information
birchmd authored Oct 5, 2023
1 parent 88cc4a2 commit 5e2ecbb
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 38 deletions.
14 changes: 7 additions & 7 deletions engine-tests/src/tests/hashchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ use aurora_engine_types::{
#[test]
fn test_hashchain() {
let (mut runner, mut signer, _) = crate::tests::sanity::initialize_transfer();
// Re-init the hashchain so we know the first tx is `start_hashchain`.
let account_id = runner.aurora_account_id.clone();
utils::init_hashchain(&mut runner, &account_id, None);

// The tests initialize the hashchain with the default value.
let hc = get_latest_hashchain(&runner);
// Hashchain starts 2 heights lower than the current context height because
// at `hc.block_height + 1` the `start_hashchain` is submitted and at
// `hc.block_height + 2` the signer address is created in the EVM state.
assert_eq!(hc.block_height, runner.context.block_height - 2);
// Hashchain starts 1 height lower than the current context height because
// at `hc.block_height + 1` the `start_hashchain` is submitted.
assert_eq!(hc.block_height, runner.context.block_height - 1);
assert_eq!(hc.hashchain, hex::encode(H256::default()));

// Execute a transaction and the hashchain changes
Expand Down Expand Up @@ -57,9 +59,7 @@ fn test_hashchain() {
&Bloom::default(),
)
.unwrap();
// Skip a block height because at block_height + 1 there is no "real" transaction
// (that height is skipped when the signer address is directly inserted into the EVM state)
block_height += 2;
block_height += 1;
hc.move_to_block(block_height).unwrap();
// Insert the `submit` transaction we care about
hc.add_block_tx(block_height, "submit", &input, &output, &Bloom::default())
Expand Down
2 changes: 1 addition & 1 deletion engine-tests/src/tests/sanity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ fn test_num_wasm_functions() {
let module = walrus::ModuleConfig::default()
.parse(runner.code.code())
.unwrap();
let expected_number = 1464;
let expected_number = 1465;
let actual_number = module.funcs.iter().count();

assert!(
Expand Down
23 changes: 6 additions & 17 deletions engine-tests/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use aurora_engine::engine::{EngineError, EngineErrorKind, GasPaymentError};
use aurora_engine::parameters::{SubmitArgs, ViewCallArgs};
use aurora_engine_types::account_id::AccountId;
use aurora_engine_types::borsh::{BorshDeserialize, BorshSerialize};
use aurora_engine_types::parameters::engine::{NewCallArgs, NewCallArgsV4};
use aurora_engine_types::types::{NEP141Wei, PromiseResult};
use evm::ExitFatal;
use libsecp256k1::{self, Message, PublicKey, SecretKey};
Expand All @@ -21,8 +22,7 @@ use std::borrow::Cow;

use crate::prelude::fungible_token::{FungibleToken, FungibleTokenMetadata};
use crate::prelude::parameters::{
InitCallArgs, LegacyNewCallArgs, RelayerKeyManagerArgs, StartHashchainArgs, SubmitResult,
TransactionStatus,
InitCallArgs, StartHashchainArgs, SubmitResult, TransactionStatus,
};
use crate::prelude::transactions::{
eip_1559::{self, SignedTransaction1559, Transaction1559},
Expand Down Expand Up @@ -621,12 +621,13 @@ impl ExecutionProfile {
pub fn deploy_runner() -> AuroraRunner {
let mut runner = AuroraRunner::default();
let aurora_account_id = str_to_account_id(runner.aurora_account_id.as_str());
let args = LegacyNewCallArgs {
let args = NewCallArgs::V4(NewCallArgsV4 {
chain_id: crate::prelude::u256_to_arr(&U256::from(runner.chain_id)),
owner_id: aurora_account_id.clone(),
bridge_prover_id: str_to_account_id("bridge_prover.near"),
upgrade_delay_blocks: 1,
};
key_manager: aurora_account_id,
initial_hashchain: Some([0u8; 32]),
});

let account_id = runner.aurora_account_id.clone();
let result = runner.call("new", &account_id, args.try_to_vec().unwrap());
Expand All @@ -641,18 +642,6 @@ pub fn deploy_runner() -> AuroraRunner {
let result = runner.call("new_eth_connector", &account_id, args.try_to_vec().unwrap());
assert!(result.is_ok());

// Need to set a key manager because that is the only account that can initialize the hashchain
let args = RelayerKeyManagerArgs {
key_manager: Some(aurora_account_id),
};
let result: Result<VMOutcome, EngineError> = runner.call(
"set_key_manager",
&account_id,
serde_json::to_vec(&args).unwrap(),
);
assert!(result.is_ok());
init_hashchain(&mut runner, &account_id, None);

runner
}

Expand Down
25 changes: 25 additions & 0 deletions engine-types/src/parameters/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum NewCallArgs {
V1(LegacyNewCallArgs),
V2(NewCallArgsV2),
V3(NewCallArgsV3),
V4(NewCallArgsV4),
}

impl NewCallArgs {
Expand All @@ -25,6 +26,14 @@ impl NewCallArgs {
Ok,
)
}

#[must_use]
pub const fn initial_hashchain(&self) -> Option<RawH256> {
match self {
Self::V4(args) => args.initial_hashchain,
Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
}
}
}

/// Old Borsh-encoded parameters for the `new` function.
Expand Down Expand Up @@ -66,6 +75,22 @@ pub struct NewCallArgsV3 {
pub key_manager: AccountId,
}

#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
pub struct NewCallArgsV4 {
/// Chain id, according to the EIP-115 / ethereum-lists spec.
pub chain_id: RawU256,
/// Account which can upgrade this contract.
/// Use empty to disable updatability.
pub owner_id: AccountId,
/// How many blocks after staging upgrade can deploy it.
pub upgrade_delay_blocks: u64,
/// Relayer keys manager.
pub key_manager: AccountId,
/// Initial value of the hashchain.
/// If none is provided then the hashchain will start disabled.
pub initial_hashchain: Option<RawH256>,
}

/// Borsh-encoded parameters for the `set_owner` function.
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down
43 changes: 32 additions & 11 deletions engine/src/contract_methods/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
Authorizer, EngineAuthorizer, EnginePrecompilesPauser, PausedPrecompilesChecker,
PausedPrecompilesManager, PrecompileFlags,
},
state,
state::{self, EngineState},
};
use aurora_engine_hashchain::{bloom::Bloom, hashchain::Hashchain};
use aurora_engine_modexp::AuroraModExp;
Expand Down Expand Up @@ -48,17 +48,38 @@ const CODE_KEY: &[u8; 4] = b"CODE";
const CODE_STAGE_KEY: &[u8; 10] = b"CODE_STAGE";

#[named]
pub fn new<I: IO + Copy, E: Env>(io: I, env: &E) -> Result<(), ContractError> {
with_hashchain(io, env, function_name!(), |mut io| {
if state::get_state(&io).is_ok() {
return Err(b"ERR_ALREADY_INITIALIZED".into());
}
pub fn new<I: IO + Copy, E: Env>(mut io: I, env: &E) -> Result<(), ContractError> {
if state::get_state(&io).is_ok() {
return Err(b"ERR_ALREADY_INITIALIZED".into());
}

let bytes = io.read_input().to_vec();
let args = NewCallArgs::deserialize(&bytes).map_err(|_| errors::ERR_BORSH_DESERIALIZE)?;
state::set_state(&mut io, &args.into())?;
Ok(())
})
let input = io.read_input().to_vec();
let args = NewCallArgs::deserialize(&input).map_err(|_| errors::ERR_BORSH_DESERIALIZE)?;

let initial_hashchain = args.initial_hashchain();
let state: EngineState = args.into();

if let Some(block_hashchain) = initial_hashchain {
let block_height = env.block_height();
let mut hashchain = Hashchain::new(
state.chain_id,
env.current_account_id(),
block_height,
block_hashchain,
);

hashchain.add_block_tx(
block_height,
function_name!(),
&input,
&[],
&Bloom::default(),
)?;
crate::hashchain::save_hashchain(&mut io, &hashchain)?;
}

state::set_state(&mut io, &state)?;
Ok(())
}

pub fn get_version<I: IO>(mut io: I) -> Result<(), ContractError> {
Expand Down
18 changes: 16 additions & 2 deletions engine/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::parameters::{LegacyNewCallArgs, NewCallArgs, NewCallArgsV2};
use crate::parameters::{
LegacyNewCallArgs, NewCallArgs, NewCallArgsV2, NewCallArgsV3, NewCallArgsV4,
};
use aurora_engine_sdk::io::{StorageIntermediate, IO};
use aurora_engine_types::account_id::AccountId;
use aurora_engine_types::borsh::{self, BorshDeserialize, BorshSerialize};
use aurora_engine_types::parameters::engine::NewCallArgsV3;
use aurora_engine_types::storage::{bytes_to_key, KeyPrefix};
use aurora_engine_types::{Cow, Vec};

Expand Down Expand Up @@ -177,12 +178,25 @@ impl From<NewCallArgsV3> for EngineState {
}
}

impl From<NewCallArgsV4> for EngineState {
fn from(args: NewCallArgsV4) -> Self {
Self {
chain_id: args.chain_id,
owner_id: args.owner_id,
upgrade_delay_blocks: args.upgrade_delay_blocks,
is_paused: false,
key_manager: Some(args.key_manager),
}
}
}

impl From<NewCallArgs> for EngineState {
fn from(args: NewCallArgs) -> Self {
match args {
NewCallArgs::V1(args) => args.into(),
NewCallArgs::V2(args) => args.into(),
NewCallArgs::V3(args) => args.into(),
NewCallArgs::V4(args) => args.into(),
}
}
}
Expand Down

0 comments on commit 5e2ecbb

Please sign in to comment.