Skip to content

Commit

Permalink
feat: test coverage part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Dean Amiel committed Mar 7, 2024
1 parent 1e1841b commit a885204
Show file tree
Hide file tree
Showing 3 changed files with 345 additions and 9 deletions.
2 changes: 1 addition & 1 deletion contracts/axelar-auth-verifier/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl AxelarAuthVerifierInterface for AxelarAuthVerifier {
.storage()
.persistent()
.get(&DataKey::EpochBySignerHash(signer_set_hash))
.unwrap();
.unwrap_or(0);

let epoch: u64 = env.storage().instance().get(&DataKey::Epoch).unwrap();

Expand Down
331 changes: 326 additions & 5 deletions contracts/axelar-auth-verifier/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#![cfg(test)]
extern crate std;

use soroban_sdk::{testutils::Address as _, xdr::ToXdr, Address, Bytes, Env};
use soroban_sdk::{testutils::Address as _, xdr::ToXdr, Address, Bytes, Env, Vec, U256};

use axelar_soroban_std::testutils::assert_invocation;

use crate::{
contract::{AxelarAuthVerifier, AxelarAuthVerifierClient},
testutils::{generate_proof, generate_signer_set, initialize, randint, transfer_operatorship},
testutils::{
generate_empty_signer_set, generate_proof, generate_signer_set, initialize, randint,
transfer_operatorship,
},
};

fn setup_env<'a>() -> (Env, Address, AxelarAuthVerifierClient<'a>) {
Expand All @@ -28,6 +31,65 @@ fn test_initialize() {
initialize(&env, &client, user, randint(0, 10), randint(1, 10));
}

#[test]
#[should_panic(expected = "Already initialized")]
fn test_fails_if_already_initialized() {
let (env, _, client) = setup_env();
let user_one = Address::generate(&env);
let user_two = Address::generate(&env);

initialize(&env, &client, user_one, randint(0, 10), randint(1, 10));

// second initialization should panic
initialize(&env, &client, user_two, randint(0, 10), randint(1, 10));
}

#[test]
fn test_fails_with_empty_signer_set() {
let (env, _, client) = setup_env();
let owner = Address::generate(&env);

// create an empty WeightedSigners vector
let empty_signer_set = generate_empty_signer_set(&env);

// serialize the empty signer set to Bytes
let empty_operator_set = empty_signer_set.to_xdr(&env);

// call should panic because signer set is empty
let res = client.try_initialize(&owner, &randint(0, 10), &empty_operator_set);
assert!(res.is_err());
}

#[test]
fn test_transfer_ownership() {
let (env, _, client) = setup_env();

let initial_owner = Address::generate(&env);
let new_owner = Address::generate(&env);

initialize(
&env,
&client,
initial_owner.clone(),
randint(1, 10),
randint(1, 10),
);

// transfer ownership to the new owner
client.transfer_ownership(&new_owner);

assert_invocation(
&env,
&initial_owner,
&client.address,
"transfer_ownership",
(new_owner.clone(),),
);

let retrieved_owner = client.owner();
assert_eq!(retrieved_owner, new_owner);
}

#[test]
fn test_validate_proof() {
let (env, _, client) = setup_env();
Expand All @@ -44,6 +106,116 @@ fn test_validate_proof() {
assert!(latest_signer_set);
}

#[test]
#[should_panic(expected = "invalid epoch")]
fn test_fail_validate_proof_invalid_epoch() {
let (env, _, client) = setup_env();
let user = Address::generate(&env);

initialize(&env, &client, user, randint(0, 10), randint(1, 10));

let different_signers = generate_signer_set(&env, randint(1, 10), false);

let msg = Bytes::from_array(&env, &[0x01, 0x02, 0x03]);
let msg_hash = env.crypto().keccak256(&msg);
let proof = generate_proof(&env, msg_hash.clone(), different_signers);

// should panic, epoch should return zero for invalid signer set
client.validate_proof(&msg_hash, &proof.to_xdr(&env));
}

#[test]
#[should_panic(expected = "invalid signatures")]
fn test_fail_validate_proof_invalid_signatures() {
let (env, _, client) = setup_env();
let user = Address::generate(&env);

let signers = initialize(&env, &client, user, randint(0, 10), randint(1, 10));

let msg = Bytes::from_array(&env, &[0x01, 0x02, 0x03]);
let msg_hash = env.crypto().keccak256(&msg);
let proof = generate_proof(&env, msg_hash.clone(), signers);

let different_msg = Bytes::from_array(&env, &[0x04, 0x05, 0x06]);
let different_msg_hash = env.crypto().keccak256(&different_msg);

// should panic, proof is for different message hash
client.validate_proof(&different_msg_hash, &proof.to_xdr(&env));
}

#[test]
#[should_panic(expected = "invalid signatures")]
fn test_fail_validate_proof_empty_signatures() {
let (env, _, client) = setup_env();
let user = Address::generate(&env);

let signers = initialize(&env, &client, user, randint(0, 10), randint(1, 10));

let msg = Bytes::from_array(&env, &[0x01, 0x02, 0x03]);
let msg_hash = env.crypto().keccak256(&msg);
let mut proof = generate_proof(&env, msg_hash.clone(), signers);

proof.signatures = Vec::new(&env);

// validate_proof should panic, empty signatures
client.validate_proof(&msg_hash, &proof.to_xdr(&env));
}

#[test]
#[should_panic(expected = "invalid signatures")]
fn test_fail_validate_proof_invalid_signer_set() {
let (env, _, client) = setup_env();
let user = Address::generate(&env);

let signers = initialize(&env, &client, user, randint(0, 10), randint(1, 10));

let msg = Bytes::from_array(&env, &[0x01, 0x02, 0x03]);
let msg_hash = env.crypto().keccak256(&msg);
let mut proof = generate_proof(&env, msg_hash.clone(), signers);

let new_signers = generate_signer_set(&env, randint(1, 10), false);
let new_proof = generate_proof(&env, msg_hash.clone(), new_signers);

proof.signatures = new_proof.signatures;

// validate_proof should panic, signatures do not match signers
client.validate_proof(&msg_hash, &proof.to_xdr(&env));
}

#[test]
#[should_panic(expected = "invalid signatures")]
fn test_fail_validate_proof_threshold_not_met() {
let (env, _, client) = setup_env();
let user = Address::generate(&env);

let signers = initialize(&env, &client, user, randint(0, 10), randint(1, 10));

let env = &env;
let zero = U256::from_u32(env, 0);
let mut total_weight = zero.clone();

let mut index_below_threshold = 0;

// find the index where the total weight is just below the threshold
for (i, weight) in signers.signer_set.signers.iter().map(|s| s.1).enumerate() {
total_weight = total_weight.add(&weight);
if total_weight >= signers.signer_set.threshold {
index_below_threshold = i;
break;
}
}

let msg = Bytes::from_array(&env, &[0x01, 0x02, 0x03]);
let msg_hash = env.crypto().keccak256(&msg);
let mut proof = generate_proof(&env, msg_hash.clone(), signers);

// remove signatures to just below the threshold
proof.signatures = proof.signatures.slice(0..index_below_threshold as u32);

// should panic, all signatures are valid but total weight is below threshold
client.validate_proof(&msg_hash, &proof.to_xdr(&env));
}

#[test]
fn test_transfer_operatorship() {
let (env, _, client) = setup_env();
Expand All @@ -62,7 +234,7 @@ fn test_transfer_operatorship() {
let msg = Bytes::from_array(&env, &[0x01, 0x02, 0x03]);
let msg_hash = env.crypto().keccak256(&msg);

let new_signers = generate_signer_set(&env, randint(1, 10));
let new_signers = generate_signer_set(&env, randint(1, 10), false);

let encoded_new_signer_set = transfer_operatorship(&env, &client, new_signers.clone());

Expand All @@ -79,6 +251,155 @@ fn test_transfer_operatorship() {
assert!(latest_signer_set);
}

#[test]
fn test_transfer_operatorship_fail_empty_signer_set() {
let (env, _, client) = setup_env();

let user = Address::generate(&env);
let previous_signer_retention = 1;

initialize(
&env,
&client,
user.clone(),
previous_signer_retention,
randint(1, 10),
);

let empty_signer_set = generate_empty_signer_set(&env);

let empty_operator_set = empty_signer_set.to_xdr(&env);

// should throw an error, empty signer set
let res = client.try_transfer_operatorship(&empty_operator_set);
assert!(res.is_err());
}

#[test]
fn test_transfer_operatorship_fail_zero_weight() {
let (env, _, client) = setup_env();

let user = Address::generate(&env);
let previous_signer_retention = 1;

initialize(
&env,
&client,
user.clone(),
previous_signer_retention,
randint(1, 10),
);

let new_signers = generate_signer_set(&env, randint(1, 10), true);

let encoded_new_signer_set = new_signers.signer_set.to_xdr(&env);

// should throw an error, last signer weight is zero
let res = client.try_transfer_operatorship(&encoded_new_signer_set);
assert!(res.is_err());
}

#[test]
fn test_transfer_operatorship_fail_zero_threshold() {
let (env, _, client) = setup_env();

let user = Address::generate(&env);
let previous_signer_retention = 1;

initialize(
&env,
&client,
user.clone(),
previous_signer_retention,
randint(1, 10),
);

let mut new_signers = generate_signer_set(&env, randint(1, 10), false);

// set the threshold to zero
new_signers.signer_set.threshold = U256::from_u32(&env, 0);

let encoded_new_signer_set = new_signers.signer_set.to_xdr(&env);

// should error because the threshold is set to zero
let res = client.try_transfer_operatorship(&encoded_new_signer_set);
assert!(res.is_err());
}

#[test]
fn test_transfer_operatorship_fail_low_total_weight() {
let (env, _, client) = setup_env();

let user = Address::generate(&env);
let previous_signer_retention = 1;

initialize(
&env,
&client,
user.clone(),
previous_signer_retention,
randint(1, 10),
);

let mut new_signers = generate_signer_set(&env, randint(1, 10), false);

let env = &env;
let zero = U256::from_u32(env, 0);
let one = U256::from_u32(env, 1);
let mut total_weight = zero.clone();

for weight in new_signers.signer_set.signers.iter().map(|s| s.1) {
total_weight = total_weight.add(&weight);
}

let new_threshold = total_weight.add(&one);

// set the threshold to zero
new_signers.signer_set.threshold = new_threshold;

let encoded_new_signer_set = new_signers.signer_set.to_xdr(&env);

// should error because the threshold is set to zero
let res = client.try_transfer_operatorship(&encoded_new_signer_set);
assert!(res.is_err());
}

#[test]
fn test_transfer_operatorship_fail_wrong_signer_order() {
let (env, _, client) = setup_env();

let user = Address::generate(&env);
let previous_signer_retention = 1;

initialize(
&env,
&client,
user.clone(),
previous_signer_retention,
randint(1, 10),
);

let mut new_signers = generate_signer_set(&env, randint(1, 10), false);

let len = new_signers.signer_set.signers.len();

// create a new vec and reverse signer order
let mut reversed_signers = Vec::new(&env);
for i in (0..len).rev() {
if let Some(item) = new_signers.signer_set.signers.get(i as u32) {
reversed_signers.push_back(item);
}
}

new_signers.signer_set.signers = reversed_signers;

let encoded_new_signer_set = new_signers.signer_set.to_xdr(&env);

// should error because signers are in wrong order
let res = client.try_transfer_operatorship(&encoded_new_signer_set);
assert!(res.is_err());
}

#[test]
fn test_multi_transfer_operatorship() {
let (env, _, client) = setup_env();
Expand All @@ -100,7 +421,7 @@ fn test_multi_transfer_operatorship() {
let mut previous_signers = original_signers.clone();

for _ in 0..previous_signer_retention {
let new_signers = generate_signer_set(&env, randint(1, 10));
let new_signers = generate_signer_set(&env, randint(1, 10), false);

transfer_operatorship(&env, &client, new_signers.clone());

Expand Down Expand Up @@ -140,7 +461,7 @@ fn test_transfer_operatorship_panics_on_outdated_signer_set() {
let msg_hash = env.crypto().keccak256(&msg);

for _ in 0..(previous_signer_retention + 1) {
let new_signers = generate_signer_set(&env, randint(1, 10));
let new_signers = generate_signer_set(&env, randint(1, 10), false);
transfer_operatorship(&env, &client, new_signers.clone());
}

Expand Down
Loading

0 comments on commit a885204

Please sign in to comment.