Skip to content

Commit

Permalink
make map light client upgradeable
Browse files Browse the repository at this point in the history
  • Loading branch information
PandaRR007 committed Nov 29, 2022
1 parent 3175c62 commit 20548ff
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 10 deletions.
19 changes: 19 additions & 0 deletions mapclients/near/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@ EPOCH_ID=300 # get the information of this epoch id to initialize the MAP light
./scripts/deploy.sh
```

## Upgrade the contract

**NOTE**: currently the script works on MacOS only. Below `scripts` is in directory `../../mcs/near/map-cross-chain-service/`.
```shell
MAP_CLIENT_WASM_FILE=/path/to/map/client/contract # new MAP light client contract wasm file

# request to upgrade MAP light client contract by multisig member
./scripts/manage_multisig.sh request_and_confirm upgrade_map_client $MAP_CLIENT_WASM_FILE ${MEMBERS[1]}

# the request ID can be obtained from the last line of last command's output
REQUEST_ID=

# confirm the request by another member
./scripts/manage_multisig.sh confirm $REQUEST_ID ${MEMBERS[2]}

# if the request is not executed because of the time lock, anyone can execute it after REQUEST_LOCK time
# ./scripts/manage_multisig.sh execute $REQUEST_ID $MASTER_ACCOUNT
```


## Testing

Expand Down
37 changes: 34 additions & 3 deletions mapclients/near/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ pub mod traits;
mod hash;

use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::{env, log, near_bindgen, PanicOnDefault, serde_json};
use near_sdk::{AccountId, env, log, near_bindgen, PanicOnDefault, serde_json, Gas};
use near_sdk::collections::UnorderedMap;
use near_sdk::env::keccak256;
use near_sdk::json_types::U64;
use near_sdk::json_types::{Base64VecU8, U64};
use near_sdk::serde::{Serialize, Deserialize};
pub use crypto::{G1, G2, REGISTER_EXPECTED_ERR};
use crate::types::{istanbul::IstanbulExtra, istanbul::get_epoch_number, header::Header};
Expand All @@ -27,13 +27,15 @@ use crate::types::proof::{ReceiptProof, verify_trie_proof};
const ECDSA_SIG_LENGTH: usize = 65;
const ECDSA_REGISTER: u64 = 2;
const MAX_RECORD: u64 = 20;
const GAS_FOR_UPGRADE_SELF_DEPLOY: Gas = Gas(15_000_000_000_000);

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct MapLightClient {
epoch_records: UnorderedMap<u64, EpochRecord>,
epoch_size: u64,
header_height: u64,
owner: AccountId,
}

#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone, Debug)]
Expand All @@ -59,7 +61,8 @@ impl MapLightClient {
pub fn new(threshold: U64,
validators: Vec<Validator>,
epoch: U64,
epoch_size: U64) -> Self {
epoch_size: U64,
owner: AccountId) -> Self {
assert!(!Self::initialized(), "already initialized");
assert_ne!(0, validators.len(), "empty validators!");
assert_ne!(0, threshold.0, "threashold should not be 0");
Expand All @@ -85,9 +88,17 @@ impl MapLightClient {
epoch_records: val_records,
epoch_size: epoch_size.into(),
header_height: (epoch.0 - 1) * epoch_size.0,
owner,
}
}

#[private]
#[init(ignore_state)]
pub fn migrate_client() -> Self {
let client: MapLightClient = env::state_read().expect("ERR_CONTRACT_IS_NOT_INITIALIZED");
client
}

pub fn initialized() -> bool {
env::state_read::<MapLightClient>().is_some()
}
Expand Down Expand Up @@ -264,4 +275,24 @@ impl MapLightClient {
self.epoch_records.remove(&epoch_to_remove);
}
}

pub fn update_owner(&mut self, new_owner: AccountId) {
assert_eq!(self.owner, env::predecessor_account_id(), "unexpected caller {}", env::predecessor_account_id());
self.owner = new_owner;
}

pub fn upgrade_client(&mut self, code: Base64VecU8) {
assert_eq!(self.owner, env::predecessor_account_id(), "unexpected caller {}", env::predecessor_account_id());

let current_id = env::current_account_id();
let promise_id = env::promise_batch_create(&current_id);
env::promise_batch_action_deploy_contract(promise_id, &code.0);
env::promise_batch_action_function_call(
promise_id,
"migrate_client",
&[],
0,
env::prepaid_gas() - env::used_gas() - GAS_FOR_UPGRADE_SELF_DEPLOY,
);
}
}
8 changes: 5 additions & 3 deletions mapclients/near/map-client-factory/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::serde_json::json;
use near_sdk::{env, near_bindgen, Promise, Gas};
use near_sdk::{env, near_bindgen, Promise, Gas, AccountId};
use near_sdk::json_types::U64;
use map_light_client::Validator;

Expand All @@ -22,7 +22,8 @@ impl Factory {
threshold: U64,
validators: Vec<Validator>,
epoch: U64,
epoch_size: U64
epoch_size: U64,
owner: AccountId
) -> Promise {
let account_id = format!("{}.{}", name, env::current_account_id());
Promise::new(account_id.parse().unwrap())
Expand All @@ -35,7 +36,8 @@ impl Factory {
"threshold": threshold,
"validators": validators,
"epoch": epoch,
"epoch_size": epoch_size })
"epoch_size": epoch_size,
"owner": owner})
.to_string()
.as_bytes()
.to_vec(),
Expand Down
3 changes: 2 additions & 1 deletion mapclients/near/scripts/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ MASTER_ACCOUNT=maplabs.testnet # make sure the account is already created on NEA
FACTORY_NAME=cfac2 # the name of map client factory contract to be created, the account ID will be $FACTORY_NAME.$MASTER_ACCOUNT
CLIENT_NAME=client # the name of MAP light client contract to be created, the account ID will be $CLIENT_NAME.$FACTORY_NAME
MAP_RPC_URL=https://testnet-rpc.maplabs.io # the RPC url of MAP blockchain
EPOCH_ID=6 # get the information of this epoch id to initialize the MAP light client contract
EPOCH_ID=6 # get the information of this epoch id to initialize the MAP light client contract
OWNER=multisig.mfac.maplabs.testnet # the owner of the MAP light client, which is a multisig-timelock contract
1 change: 1 addition & 0 deletions mapclients/near/scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ source $SCRIPT_DIR/config.sh

RESPONSE=`curl -X POST $MAP_RPC_URL -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"istanbul_getEpochInfo","params":['$EPOCH_ID'],"id":1}'`
INIT_ARGS_CLIENT=`echo $RESPONSE | jq .result | jq --arg name $CLIENT_NAME '.name=$name'`
INIT_ARGS_CLIENT=`echo $INIT_ARGS_CLIENT | jq --args '.owner = "'$OWNER'"'`

FACTORY_ACCOUNT=$FACTORY_NAME.$MASTER_ACCOUNT
echo $MASTER_ACCOUNT
Expand Down
3 changes: 2 additions & 1 deletion mapclients/near/tests/data/init_value.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@
"_BLSG1PublicKey": "0x28681fcac6825e2a6711b2ef0d3a22eae527c41ecccdeb4e69dfff4002219d8b131f98eaf9323bf171e947401f0e6b1951f4c8f8aa525b677f1c811c88358e37",
"_UncompressedBLSPublicKey": "Gsq81OIpjJHhdSYgqemenElRPq694arTgb8pRqQCFPAHHHKgLpEM8DGPlU49CViK9NDqX+xloMZRGwy2Qj3HbQbg14f6wraD+m8Z9zTfvdi94cuSkkaVZ52B4mXN7TfNB6Or5T6C+VfbkqTcJ5o7elWRx3X8H7eagYXZW7uTsrs="
}
]
],
"owner": "multisig.test.near"
}
53 changes: 52 additions & 1 deletion mapclients/near/tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ const INIT_VALUE: &str = r#"{
}
],
"epoch":"1",
"epoch_size":"1000"
"epoch_size":"1000",
"owner": "multisig.test.near"
}"#;

const HEADER_0_012: &str = r#"{
Expand Down Expand Up @@ -143,6 +144,56 @@ async fn test_initialize() -> anyhow::Result<()> {
Ok(())
}

#[tokio::test]
async fn test_manage_owner() -> anyhow::Result<()> {
let (worker, contract) = deploy_contract().await?;
let account = worker.dev_create_account().await?;

let mut init_args: serde_json::Value = serde_json::from_str(INIT_VALUE).unwrap();
init_args["owner"] = json!(contract.id());

let res = contract
.call(&worker, "new")
.args_json(json!(init_args))?
.gas(300_000_000_000_000)
.transact()
.await?;

assert!(res.is_success(), "new contract failed");

let res = contract
.call(&worker, "update_owner")
.args_json(json!({
"new_owner": account.id()
}))?
.gas(300_000_000_000_000)
.transact()
.await?;
assert!(res.is_success(), "update_owner failed");

let res = contract
.call(&worker, "update_owner")
.args_json(json!({
"new_owner": account.id()
}))?
.gas(300_000_000_000_000)
.transact()
.await;
assert!(res.is_err(), "update_owner should fail");

let res = account
.call(&worker, contract.id(), "update_owner")
.args_json(json!({
"new_owner": contract.id()
}))?
.gas(300_000_000_000_000)
.transact()
.await?;
assert!(res.is_success(), "update_owner should succeed");

Ok(())
}

#[tokio::test]
async fn test_update_block_header() -> anyhow::Result<()> {
let (worker, contract) = deploy_contract().await?;
Expand Down
3 changes: 2 additions & 1 deletion mcs/near/scripts/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ export MCS_FACTORY_ACCOUNT=$MCS_FACTORY_NAME.$MASTER_ACCOUNT
export MCS_ACCOUNT=$MCS_NAME.$MCS_FACTORY_ACCOUNT
export MULTISIG_ACCOUNT=$MULTISIG_NAME.$MCS_FACTORY_ACCOUNT
export MEMBERS
export MASTER_ACCOUNT
export MASTER_ACCOUNT
export CLIENT_ACCOUNT
14 changes: 14 additions & 0 deletions mcs/near/scripts/manage_multisig.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function printHelp() {
echo " remove_mcs <token> <chain id> remove mcs token to_chain"
echo " remove_ft <token> <chain id> remove fungible token to_chain"
echo " upgrade_multisig <wasm file> upgrade multisig contract"
echo " upgrade_map_client <wasm file> upgrade map light client contract"
echo " upgrade_mcs <wasm file> upgrade mcs contract"
echo " upgrade_mcs_token <token> <wasm file> upgrade mcs token contract"
echo " set_client <map client account> set new map light client account to mcs contract"
Expand Down Expand Up @@ -186,6 +187,19 @@ function prepare_request() {
exit 1
fi
;;
upgrade_map_client)
if [[ $# == 3 ]]; then
echo "upgrade map light client contract to $2"
RECEIVER=$CLIENT_ACCOUNT
METHOD="upgrade_client"
CODE=`base64 -i $2`
ARGS=`echo '{"code": "'$CODE'"}'| base64`
MEMBER=$3
else
printHelp
exit 1
fi
;;
upgrade_mcs)
if [[ $# == 3 ]]; then
echo "upgrade mcs contract to $2"
Expand Down

0 comments on commit 20548ff

Please sign in to comment.