Skip to content

Commit

Permalink
chore: verify the state after wrong migration (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
karim-en authored Mar 5, 2025
1 parent ad57fd8 commit f75e376
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
12 changes: 7 additions & 5 deletions near-plugins-derive/src/upgradable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,17 +218,19 @@ pub fn derive_upgradable(input: TokenStream) -> TokenStream {
)
}

let promise = ::near_sdk::Promise::new(::near_sdk::env::current_account_id())
let deploy_promise = ::near_sdk::Promise::new(::near_sdk::env::current_account_id())
.deploy_contract(code);
match function_call_args {
None => promise.function_call("up_verify_state".to_owned(), vec![], near_sdk::NearToken::from_yoctonear(0), near_sdk::Gas::from_tgas(2)),
let promise = match function_call_args {
None => deploy_promise,
Some(args) => {
// Execute the `DeployContract` and `FunctionCall` actions in a batch
// transaction to make a failure of the function call roll back the code
// deployment.
promise.function_call(args.function_name, args.arguments, args.amount, args.gas)
deploy_promise.function_call(args.function_name, args.arguments, args.amount, args.gas)
},
}
};

promise.function_call("up_verify_state".to_owned(), vec![], near_sdk::NearToken::from_yoctonear(0), near_sdk::Gas::from_tgas(2))
}

fn up_verify_state(&self) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ impl Contract {
pub fn is_migrated(&self) -> bool {
self.is_migrated
}

pub fn migrate_empty() -> bool {
// This method is used to test the rollback mechanism of `Upgradable::up_deploy_code` when
// the migration method is empty.
true
}
}

/// Corresponds to the state defined in the initial `../upgradable` contract.
Expand Down
47 changes: 47 additions & 0 deletions near-plugins-derive/tests/upgradable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,53 @@ async fn test_deploy_code_with_missed_migration() -> anyhow::Result<()> {
Ok(())
}

/// Deploys a new version of the contract with wrong migration
/// Verifies the failure rolls back the deployment, i.e. the initial
/// code remains active.
#[tokio::test]
async fn test_deploy_code_with_wrong_migration() -> anyhow::Result<()> {
let worker = near_workspaces::sandbox().await?;
let dao = worker.dev_create_account().await?;
let setup = Setup::new(worker.clone(), Some(dao.id().clone()), None).await?;

// Compile the other version of the contract and stage its code.
let code = common::repo::compile_project(
Path::new(PROJECT_PATH_STATE_MIGRATION),
"upgradable_state_migration",
)
.await?;
let res = setup
.upgradable_contract
.up_stage_code(&dao, code.clone())
.await?;
assert_success_with_unit_return(res);
setup.assert_staged_code(Some(&code)).await;

// Deploy staged code with wrong migration function
let function_call_args: FunctionCallArgs = FunctionCallArgs {
function_name: "migrate_empty".to_string(),
arguments: Vec::new(),
amount: NearToken::from_yoctonear(0),
gas: Gas::from_tgas(3),
};

let res = setup
.upgradable_contract
.up_deploy_code(
&dao,
convert_code_to_deploy_hash(&code),
Some(function_call_args),
)
.await?;
assert_failure_with(res, "Cannot deserialize the contract state");

// Verify `code` wasn't deployed by calling a function that is defined only in the initial
// contract but not in the contract corresponding to the `code`.
setup.assert_is_set_up(&setup.unauth_account).await;

Ok(())
}

/// Deploys staged code in a batch transaction with two function call actions:
///
/// 1. `up_deploy_code` with a function call to a migration method that fails
Expand Down

0 comments on commit f75e376

Please sign in to comment.