0

I'm struggling with this modifier as well as one I'd like to use for some other contracts. I figure if I understand why this is a problem I can probably get the rest right.

enter image description here

I can compile, migrate (which inserts a record, also), and test, but if I use the onlyOwner modifier, it works for the migration record but fails on the testing record insert. Why? doesn't the truffle testing use the same account as deploying? and if so shouldn't that work?

enter image description here

The modifier I want for the other contracts is something like this:
modifier (not quite working):

// modifiers  
/**
* @dev Modifer onlyBy for Access Control
*/
modifier onlyBy(address _credentialOrgAddress){
    uint32 foundAccount = 0;
    CredentialOrgFactory cof = CredentialOrgFactory(credentialOrgContractAddress);
    if (cof.isCredentialOrg(_credentialOrgAddress)){
        foundAccount = 1;
    }
    require(foundAccount == 1, "Not Credentialing Org");
    _;
}

solidity code:

pragma solidity ^0.4.21;  

/**
 * @title CredentialOrgFactory
 * @dev The CredentialOrgFactory allows the contract owner to add new credentialing orgs  */  
import "./Pausable.sol";  
import "./SafeMath32.sol";  

contract CredentialOrgFactory is Pausable {

/**
*  @dev Library useage for safemath for uint32
*/
using SafeMath32 for uint32;

/**
* @dev mappings
*/
mapping(address => CredentialOrg) addressToCredentialOrg;

/**
* @dev events for contract
* One for the create CredentialOrg and one for the basic 'logging'.
*/
event CredentialOrgCreateEvent(string shortName, address schoolAddress, string detail);
event CredentialOrgEvent(address schoolAddress, string detail);

/**
* @dev CredentialOrg Count
*/
uint32 private credentialOrgCount;

/**
* @dev Primary CredentialOrg structure, and following array.
*/
struct CredentialOrg {
    string shortName;          // School shortName (len 30)
    string officialSchoolName; // official school shortName (70 or less)
    address schoolAddress;
}

CredentialOrg[] private credentialOrgs; // array to hold Credentialing Orgs

/**
* @dev class constructor
*/
constructor() public {
    credentialOrgCount = 0;
}

// functions
function getOwner()
public view
returns (address returnedOwner)
{
    returnedOwner = owner;
}

/**
* @dev allows owner to create new credentialing orgs
* @param _shortName shortName of Credentialing orgs
* @param _officialSchoolName official School Name
* @param _schoolAddress address of credential org.
* @return createStatus bool noting creation status success or failure
*/
function createCredentialOrg(string _shortName, string _officialSchoolName, address _schoolAddress) //onlyOwner
public 
returns (bool createStatus)
{
    emit CredentialOrgCreateEvent(_shortName, _schoolAddress, "New Org Add (PRE)");
    require(bytes(_shortName).length > 0 && bytes(_shortName).length < 31, "createCredentialOrg shortName problem");
    require(bytes(_officialSchoolName).length > 0 && bytes(_officialSchoolName).length < 70, "createCredentialOrg officalSchoolName length problem");
    require(_schoolAddress != 0, "createCredentialOrg (FAIL) school Address can not be 0");
    createStatus = false;
    uint32 position = uint32(credentialOrgs.push(CredentialOrg(_shortName, _officialSchoolName, _schoolAddress)));
    if (position > 0){
        addressToCredentialOrg[_schoolAddress] = credentialOrgs[position.sub(1)];
        credentialOrgCount = credentialOrgCount.add(1);
        createStatus = true;
        emit CredentialOrgCreateEvent(_shortName, _schoolAddress, "createCredentialOrg (SUCCESS)");
    } else {
        emit CredentialOrgCreateEvent(_shortName, _schoolAddress, "createCredentialOrg (FAIL)");
    }
    return (createStatus);
}

/**
* @dev allows selection of a credentialingOrg by position
* @param _credentialOrgPosition allows selection of credentialing orgs details.
* @return shortName - shortName of Credential Org
* @return officialSchooName - official school name
* @return school -the schools ethereum address 
*/
function selectCredentialOrgByPosition(uint32 _credentialOrgPosition) 
public view 
returns (string shortName, string officialSchoolName, address schoolAddress)
{
    shortName = "";
    officialSchoolName = "";
    schoolAddress = 0;
    require(_credentialOrgPosition >= 0, "selectCredentialOrg - position had to be greater or equal to 0.");
    if (_credentialOrgPosition < credentialOrgCount){
        emit CredentialOrgEvent(msg.sender, "selectCredentialOrg~position - (SUCCESS)");
        return (credentialOrgs[_credentialOrgPosition].shortName, credentialOrgs[_credentialOrgPosition].officialSchoolName, credentialOrgs[_credentialOrgPosition].schoolAddress);
    } else {
        emit CredentialOrgEvent(msg.sender, "selectCredentialOrg~position - (FAIL) top boundry exceeded.");
        return (shortName, officialSchoolName, schoolAddress);
    }
}

/**
* @dev allows selection of a credentialingOrg by address
* @param _credentialOrgAddress allows selection of credentialing orgs details.
* @return shortName - shortName of Credential Org
* @return officialSchooName - official school name
* @return school -the schools ethereum address 
*/
function selectCredentialOrgByAddress(address _credentialOrgAddress) 
public view 
returns (string shortName, string officialSchoolName, address schoolAddress)
{
    require(_credentialOrgAddress != 0, "selectCredentialOrg - Address 0 not valid");
    CredentialOrg memory testCred = addressToCredentialOrg[_credentialOrgAddress];
    if (testCred.schoolAddress != 0){
        emit CredentialOrgEvent(msg.sender, "selectCredentialOrg~address - (SUCCESS)");
        return (testCred.shortName, testCred.officialSchoolName, testCred.schoolAddress);
    } else {
        emit CredentialOrgEvent(msg.sender, "selectCredentialOrg~address - (FAIL)");
        return ("", "", 0);
    }
}

/**
* @dev allows checking if credentialOrg exists
* @param _credentialOrgAddress function returns bool if an address is a credentialingOrg
* @return isAddress returns true if address is Credentialing Org, false if not.
*/
function isCredentialOrg(address _credentialOrgAddress) 
public view
returns (bool isOrgAddress)
{
    isOrgAddress = false;
    CredentialOrg memory testCredentialOrg = addressToCredentialOrg[_credentialOrgAddress];
    if (testCredentialOrg.schoolAddress != 0){
        isOrgAddress = true;
        emit CredentialOrgEvent(msg.sender, "isCredentialOrg - (SUCCESS)");
    } else {
        emit CredentialOrgEvent(msg.sender, "isCredentialOrg - (FAIL)");
    }
    return (isOrgAddress);
}

/**
* @dev returns the credentialOrgCount
* @return returnOrgCount - returns the total credential orgs count
*/
function selectOrgCount()
public view
returns (uint32 returnOrgCount)
{
    returnOrgCount = credentialOrgCount;
    emit CredentialOrgEvent(msg.sender, "selectOrgCount - (SUCCESS)");
    return (returnOrgCount);
}

}
1

The problem is your tests are in solidity and each test is a function in contract TestCredentialOrgFactory, and your test testInsertCredentialOrg is calling a function in CredentialOrgFactory

function testInsertCredentialOrg() public {
    // ... Here msg.sender is web3.eth.accounts[0]
    testVal = credentialOrgFactory.createCredentialOrg(...);

}

Inside testInsertCredentialOrg the sender is the default address of your node (usually the first account created), ie the owner or creator of CredentialOrgFactory.

You call credentialOrgFactory.createCredentialOrg() inside a contract, this changes the sender to the calling contract TestCredentialOrgFactory

function createCredentialOrg(string _shortName, ...) 
public onlyOwner
returns (bool createStatus)
{
    // ... Here msg.sender is TestCredentialOrgFactory
}

There are two possible solutions

  1. Rewrite your test in javascript, you will be able to switch who is sending the transaction.

    This is the more flexible solution unless you have lots of tests.

  2. Instantiate your contract inside your test

    function testInsertCredentialOrg() public {
        // The owner of credentialOrgFactory is TestCredentialOrgFactory
        CredentialOrgFactory credentialOrgFactory = new CredentialOrgFactory(...)
    
        // This call should succeed because the owner is TestCredentialOrgFactory
        testVal = credentialOrgFactory.createCredentialOrg(...);
    
    }
    

    If your contract needs lots of gas to deploy your test might not have enough left to run.

  • will work on that now. appreciate. I expected to have to eventually go the JS route for testing, but was hoping to keep the working set as small as possible at least till class completion. Hadn't considered instantiating inside the test, will try that first. I can get away with not having onlyOwner on the CredentialOrgFactory contract, but not the other contracts which it will use the isCredentialOrg for Access control. – shaddow Aug 16 '18 at 21:26
  • 1
    that worked! added: // regular tests CredentialOrgFactory credentialOrgFactoryA = CredentialOrgFactory(DeployedAddresses.CredentialOrgFactory()); // onlyOwner tests CredentialOrgFactory credentialOrgFactoryB = new CredentialOrgFactory(); – shaddow Aug 16 '18 at 22:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.