diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 0113973af..6ae96dfeb 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -69,7 +69,14 @@ jobs: "python3 integration_test/scripts/runner.py integration_test/chain_operation/snapshot_operation.yaml", "python3 integration_test/scripts/runner.py integration_test/chain_operation/statesync_operation.yaml" ] - } + + }, + { + name: "Accesscontrol Module", + scripts: [ + "python3 integration_test/scripts/runner.py integration_test/acl_module/accesscontrol_register_test.yaml", + ] + }, ] steps: - uses: actions/checkout@v3 diff --git a/integration_test/acl_module/accesscontrol_register_test.yaml b/integration_test/acl_module/accesscontrol_register_test.yaml new file mode 100644 index 000000000..062524c2a --- /dev/null +++ b/integration_test/acl_module/accesscontrol_register_test.yaml @@ -0,0 +1,43 @@ +- name: Test registering accesscontrol dependencies + inputs: + # Get admin + - cmd: printf "12345678\n" | seid keys list --output json | jq ".[] | select (.name==\"admin\")" | jq -r .address + env: ADMIN_ADDR + # store code - get code ID + - cmd: printf "12345678\n" | seid tx wasm store integration_test/contracts/counter_parallel.wasm --from admin -b block -y --gas 5000000 --fees 5sei --output json | jq -r ".logs[].events[].attributes[] | select(.key == \"code_id\").value" + env: COUNTER_CODE_ID + # instantiate contract - get contract address + - cmd: "printf \"12345678\\n\" | seid tx wasm instantiate $COUNTER_CODE_ID \"{\\\"count\\\": 0}\" --label counter --admin $ADMIN_ADDR --from admin -b block -y --gas 5000000 --fees 5sei | grep -A 1 -m 1 \"key: _contract_address\" | sed -n \"s/.*value: //p\" | xargs" + env: COUNTER_ADDRESS + # assign filepath to env + - cmd: echo "integration_test/contracts/good_deps.json" + env: GOOD_DEPS_FILEPATH + # set up parallel dependencies + - cmd: python3 integration_test/contracts/contract_dep_generator.py build_counter_deps --base-filepath integration_test/contracts/parallelism_template.json --output-filepath $GOOD_DEPS_FILEPATH --code-id $COUNTER_CODE_ID --contract-address $COUNTER_ADDRESS + # assign filepath to env + - cmd: echo "integration_test/contracts/bad_deps.json" + env: BAD_DEPS_FILEPATH + # set up bad parallel dependencies + - cmd: python3 integration_test/contracts/contract_dep_generator.py build_counter_deps --base-filepath integration_test/contracts/bad_parallelism_template.json --output-filepath $BAD_DEPS_FILEPATH --code-id $COUNTER_CODE_ID --contract-address $COUNTER_ADDRESS + # register bad deps with chain + - cmd: printf "12345678\n" | seid tx accesscontrol register-wasm-dependency-mapping $BAD_DEPS_FILEPATH --from admin -b block -y --fees 2000usei + # make a counter contract tx to reset the mapping + - cmd: "printf \"12345678\\n\" | seid tx wasm execute $COUNTER_ADDRESS \"{\\\"increment\\\":{}}\" --from admin -b block -y --gas 1000000 --fees 1sei" + # query dep mapping after reset to ensure it was reset + - cmd: seid q accesscontrol wasm-dependency-mapping $COUNTER_ADDRESS --output json | jq -r ".wasm_dependency_mapping.reset_reason" + env: RESET_REASON + # register good deps with chain + - cmd: printf "12345678\n" | seid tx accesscontrol register-wasm-dependency-mapping $GOOD_DEPS_FILEPATH --from admin -b block -y --fees 2000usei + # make a counter contract tx to ensure it won't reset + - cmd: "printf \"12345678\\n\" | seid tx wasm execute $COUNTER_ADDRESS \"{\\\"increment\\\":{}}\" --from admin -b block -y --gas 1000000 --fees 1sei" + # query reset reason with good deps - should be empty + - cmd: seid q accesscontrol wasm-dependency-mapping $COUNTER_ADDRESS --output json | jq -r ".wasm_dependency_mapping.reset_reason" + env: RESET_REASON_2 + verifiers: + # reset reason should have a value after resetting the bad one + - type: eval + expr: RESET_REASON == "incorrectly specified dependency access list" + # second reset reason should be empty + - type: eval + expr: RESET_REASON_2 == "" + diff --git a/integration_test/contracts/bad_parallelism_template.json b/integration_test/contracts/bad_parallelism_template.json new file mode 100644 index 000000000..ba0cfacf2 --- /dev/null +++ b/integration_test/contracts/bad_parallelism_template.json @@ -0,0 +1,41 @@ +{ + "wasm_dependency_mapping": { + "contract_address": "{contract_address}", + "base_access_ops": [ + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_CONTRACT_STORE", + "identifier_template": "03%s" + }, + "selector_type": "CONTRACT_ADDRESS", + "selector": "{contract_address}" + }, + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_CODE", + "identifier_template": "{contract_code_id}" + }, + "selector_type": "NONE" + }, + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_CONTRACT_ADDRESS", + "identifier_template": "02%s" + }, + "selector_type": "CONTRACT_ADDRESS", + "selector": "{contract_address}" + }, + { + "operation": { + "access_type": "COMMIT", + "resource_type": "ANY", + "identifier_template": "*" + }, + "selector_type": "NONE" + } + ] + } +} \ No newline at end of file diff --git a/integration_test/contracts/contract_dep_generator.py b/integration_test/contracts/contract_dep_generator.py new file mode 100644 index 000000000..e26414a3e --- /dev/null +++ b/integration_test/contracts/contract_dep_generator.py @@ -0,0 +1,44 @@ +import json +import sys +import argparse +from functools import partial + +def build_counter_deps(base_filepath, output_filepath, code_id, contract_address): + with open(base_filepath, 'r') as file: + proposal = json.load(file) + proposal["wasm_dependency_mapping"]["contract_address"] = contract_address + for access_op in proposal["wasm_dependency_mapping"]["base_access_ops"]: + selector_type = access_op["selector_type"] + resource_type = access_op["operation"]["resource_type"] + id_template = access_op["operation"]["identifier_template"] + selector = access_op.get("selector") + if selector_type == "CONTRACT_ADDRESS": + if "contract_address" in selector: + access_op["selector"] = contract_address + elif resource_type == "KV_WASM_CODE": + if "contract_code_id" in id_template: + access_op["operation"]["identifier_template"] = f"01{int(code_id):016x}" + elif resource_type == "KV_WASM_PINNED_CODE_INDEX": + if "contract_code_id" in id_template: + access_op["operation"]["identifier_template"] = f"07{int(code_id):016x}" + with open(output_filepath, 'w') as output_file: + json.dump(proposal, output_file, indent=4) + +def main(): + parser = argparse.ArgumentParser(description="This is a parser to generate a parallel dependency json file from a template") + parser.add_argument('Action', type=str, help="The action to perform (eg. build_counter_deps)") + parser.add_argument('--base-filepath', dest="base_filepath", type=str, help="The json template filepath") + parser.add_argument('--output-filepath', dest="output_filepath", type=str, help="The json dependency output filepath") + parser.add_argument('--code-id', type=int, dest="code_id", help="The code id for which to generate dependencies") + parser.add_argument('--contract-address', dest="contract_address", type=str, help="The contract address for which to generate dependencies") + args = parser.parse_args() + actions = { + "build_counter_deps": partial(build_counter_deps, args.base_filepath, args.output_filepath, args.code_id, args.contract_address), + } + if args.Action not in actions: + print("Invalid Action") + actions[args.Action]() + + +if __name__ == "__main__": + main() diff --git a/integration_test/contracts/counter_parallel.wasm b/integration_test/contracts/counter_parallel.wasm new file mode 100644 index 000000000..7160fb3f8 Binary files /dev/null and b/integration_test/contracts/counter_parallel.wasm differ diff --git a/integration_test/contracts/parallelism_template.json b/integration_test/contracts/parallelism_template.json new file mode 100644 index 000000000..f12bfb778 --- /dev/null +++ b/integration_test/contracts/parallelism_template.json @@ -0,0 +1,58 @@ +{ + "wasm_dependency_mapping": { + "contract_address": "{contract_address}", + "base_access_ops": [ + { + "operation": { + "access_type": "WRITE", + "resource_type": "KV_WASM_CONTRACT_STORE", + "identifier_template": "03%s" + }, + "selector_type": "CONTRACT_ADDRESS", + "selector": "{contract_address}" + }, + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_CONTRACT_STORE", + "identifier_template": "03%s" + }, + "selector_type": "CONTRACT_ADDRESS", + "selector": "{contract_address}" + }, + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_CODE", + "identifier_template": "{contract_code_id}" + }, + "selector_type": "NONE" + }, + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_PINNED_CODE_INDEX", + "identifier_template": "{contract_code_id}" + }, + "selector_type": "NONE" + }, + { + "operation": { + "access_type": "READ", + "resource_type": "KV_WASM_CONTRACT_ADDRESS", + "identifier_template": "02%s" + }, + "selector_type": "CONTRACT_ADDRESS", + "selector": "{contract_address}" + }, + { + "operation": { + "access_type": "COMMIT", + "resource_type": "ANY", + "identifier_template": "*" + }, + "selector_type": "NONE" + } + ] + } +} \ No newline at end of file diff --git a/integration_test/scripts/runner.py b/integration_test/scripts/runner.py index 3607a83fc..1e1acc8ff 100644 --- a/integration_test/scripts/runner.py +++ b/integration_test/scripts/runner.py @@ -47,7 +47,7 @@ def verify_result(self, env_map, verifier): elems = verifier["expr"].strip().split() expr = "" for i in range(len(elems)): - if env_map.get(elems[i]): + if elems[i] in env_map: variable = env_map[elems[i]] if str(variable).isnumeric(): expr = expr + f' {variable}' diff --git a/integration_test/tokenfactory_module/create_tokenfactory_test.yaml b/integration_test/tokenfactory_module/create_tokenfactory_test.yaml index f91d0fbf1..3b042e4ee 100644 --- a/integration_test/tokenfactory_module/create_tokenfactory_test.yaml +++ b/integration_test/tokenfactory_module/create_tokenfactory_test.yaml @@ -3,18 +3,49 @@ # Get admin - cmd: printf "12345678\n" | seid keys list --output json | jq ".[] | select (.name==\"admin\")" | jq -r .address env: ADMIN_ADDR + # create new admin addr + - cmd: printf "12345678\ny\n" | seid keys add new_admin_addr --output json | jq -r ".address" + env: NEW_ADMIN_ADDR + # create uuid for tokenfactory denom + - cmd: uuidgen + env: TKF_UUID # Create denom - - cmd: printf "12345678\n" | seid tx tokenfactory create-denom test --from admin --fees 2000usei -y + - cmd: printf "12345678\n" | seid tx tokenfactory create-denom $TKF_UUID --from admin --fees 2000usei -y -b block # Query various fields about denom - - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/test\")" | jq -r .base + - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/${TKF_UUID}\")" | jq -r .base env: BASE - - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/test\")" | jq -r .name + - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/${TKF_UUID}\")" | jq -r .name env: NAME - - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/test\")" | jq -r .symbol + - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/${TKF_UUID}\")" | jq -r .symbol env: SYMBOL - - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/test\")" | jq -r .display + - cmd: seid q bank denom-metadata --output json | jq .metadatas | jq ".[] | select (.base==\"factory/${ADMIN_ADDR}/${TKF_UUID}\")" | jq -r .display env: DISPLAY + # mint some token + - cmd: printf "12345678\n" | seid tx tokenfactory mint 100$NAME --from admin -b block -y --fees 2000usei + # query balance + - cmd: seid q bank balances $ADMIN_ADDR --denom $NAME --output json | jq -r ".amount" + env: MINTED_BALANCE + # burn some token + - cmd: printf "12345678\n" | seid tx tokenfactory burn 60$NAME --from admin -b block -y --fees 2000usei + # query balance after burn + - cmd: seid q bank balances $ADMIN_ADDR --denom $NAME --output json | jq -r ".amount" + env: BALANCE_AFTER_BURN + # change admin + - cmd: printf "12345678\n" | seid tx tokenfactory change-admin $NAME $NEW_ADMIN_ADDR --from admin -b block -y --fees 2000usei + # query balance after burn + - cmd: seid q tokenfactory denom-authority-metadata $NAME --output json | jq -r ".authority_metadata.admin" + env: NEW_ADMIN verifiers: # All fields should be populated and match the base name - type: eval expr: NAME == BASE and SYMBOL == BASE and DISPLAY == BASE + # verify minted balance + - type: eval + expr: MINTED_BALANCE == 100 + # verify balance after burn + - type: eval + expr: BALANCE_AFTER_BURN == 40 + # verify new admin addr + - type: eval + expr: NEW_ADMIN_ADDR == NEW_ADMIN +