NEAR-DevHub / neardevhub-contract

DevHub Portal Product Contract (Hosted on NEAR Blockchain) – Includes other instances (e.g. Infrastructure, Events)
https://neardevhub.org
19 stars 15 forks source link

Filter by authors #14

Closed ailisp closed 1 year ago

ailisp commented 1 year ago

This PR implements filter post by author in smart contract side in an efficient way. The migration is designed to be scalable.

This is tested by:

There are alternative ways to implement this feature, and overall this smart contract side filter is better:

ailisp commented 1 year ago

@frol all comments addressed and tested again. I don't have permission to production deploy, may you share the key?

ailisp commented 1 year ago

Max asked me to add self upgrade and generic migrate method to this contract. With these, we can migrate the contract with a function call access key, and on CD

ailisp commented 1 year ago

So i've tested self upgrade and generic migration works:

  1. Deploy the old contract (from master) except adding the self_upgrade method:

    // in an impl Contract {
    pub fn unsafe_self_upgrade() {
        near_sdk::assert_self();
    
        let contract = env::input().expect("No contract code is attached in input");
        Promise::new(env::current_account_id()).deploy_contract(contract);
    }

    and change this:

        let mut siblings = self
            .post_to_children
            .get(&parent_id)
            .unwrap_or_else(|| panic!("Parent id {} not found", parent_id));

    to

        let mut siblings = self
            .post_to_children
            .get(&parent_id)
            .unwrap_or_else(|| if id == 0 { Vec::new() } else { panic!("Parent id {} not found", parent_id)});
  2. add a few posts with different authors, e.g.

    near call c.zxcvn.testnet add_post --accountId zxcvn.testnet --deposit 0.01 --args '{"parent_id":null,"body":{"post_type": "Idea","idea_version":"V1","name":"e","description":"ee"},"labels":[]}'
  3. go to this branch, call self upgrade with this branch's wasm. e.g.:

    near call c.zxcvn.testnet unsafe_self_upgrade --accountId c.zxcvn.testnet --args $(base64 < res/devgovgigs.wasm ) --base64 --gas 300000000000000
  4. migrate step 1. e.g.:

    near call c.zxcvn.testnet unsafe_migrate --accountId c.zxcvn.testnet --args '{"V3":"AddPostAuthorsField"}'
  5. migrate step 2. e.g.:

    near call c.zxcvn.testnet migrate --accountId c.zxcvn.testnet --args '{"to":{"V3":{"InsertPostAuthors":{"start":0,"end":100}}}}'  --gas 300000000000000
    # a couple of times in production until all posts are added.
  6. Add some posts with new contract. You will see posts by authors result is expected. e.g.:

    near view c.zxcvn.testnet get_posts_by_author '{"author":"a.zxcvn.testnet"}'
ailisp commented 1 year ago

@frol Please take another look and let's figure out a plan to run ^ steps in the CD. My thought:

  1. have a PR to just add

    pub fn unsafe_self_upgrade() {
        near_sdk::assert_self();
    
        let contract = env::input().expect("No contract code is attached in input");
        Promise::new(env::current_account_id()).deploy_contract(contract);
    }
  2. manually deploy contract with unsafe_self_upgrade

  3. add an account A in the github secret. add function call access key to enable account A to call unsafe_self_upgrade, unsafe_migrate and migrate.

  4. In CD, call unsafe_self_upgrade for every PR.

  5. create this PR specific script, commit, which calls above unsafe_migrate and migrate with this PR specific args. In CD runs this script.

frol commented 1 year ago

@ailisp I suggest we completely eliminate human interactions and implement a migration method that does not need any parameters and return whether we need to call it once again or all the migrations are already applied. Thus, CI will just do the following:

  1. Call a deploy function to deploy the code
  2. Call a migrate function until it returns that all the migrations are applied (the deploy function may even call the migrate function as a callback once if we have enough gas)
ailisp commented 1 year ago

Sounds good! Will try

ailisp commented 1 year ago

@frol Now your suggested mechanism works! Please take another look

ailisp commented 1 year ago

Comments are addressed. I'll coordinate with @nearmax to do the last manual deploy (to add self_upgrade method to production contract, and add access keys), then setup the CD to deploy this into production.

ailisp commented 1 year ago

Steps to deploy:

  1. Deploy the new contract in the main branch to mainnet. With near-cli-js, it is:
    git checkout main && git pull
    export NEAR_ENV=mainnet
    near deploy devgovgigs.near res/devgovgigs.wasm
  2. Call unsafe_migrate a few times until all posts are migrated. It will print done if so. Otherwise, it prints needs-migration and just repeating run this command. It migrates 100 posts a time.
    near call devgovgigs.near unsafe_migrate --accountId devgovgigs.near --gas 300000000000000
  3. Add function call access keys to devgovgigs.near. So I can setup CD with this key.
    near add-key devgovgigs.near 5qNj2Kzef8U19ysEFuFgKeTRKSmGrrY8WDYcjd6DB4r9 --contract-id devgovgigs.near --method-names unsafe_self_upgrade --method-names unsafe_migrate --allowance 10000
MaksymZavershynskyi commented 1 year ago

@ailisp @frol I have executed the above commands.