I am trying to implement a smart contract for identity management use case.
I am able to pass all the test cases which I have written in mocha with truffle.
I am compiling this smart contract using truffle and calling it from web3.py.
But when I add an entry in the mapping ( sicontracts
) with key as bytes32
( Ipfs hash converted to bytes32 ) and value as struct SIContract
in the function submitContract
. It seems to be not getting saved in the mapping. When I verify this in function approveContract
it always returns false. When I checked I could find that my mapping is not getting saved. Please help.
Solidity Code :
pragma solidity ^0.4.0;
/**
* The purpose of this contract is to provide a mechanism to verify idntity
*/
contract SmartIdentityRegistry {
address private owner;
uint constant PENDING = 0;
uint constant ACTIVE = 1;
uint constant REJECTED = 2;
/**
* Constructor of the registry.
*/
function SmartIdentityRegistry() {
owner = msg.sender;
}
/**
* The SIContract structure: every SIContract is composed of:
* - Hash of contract bytecode
* - Account that submitted the address
* - Status - 0 = pending, 1 = active, 2 = rejected.
*/
struct SIContract {
bytes32 hash;
address submitter;
uint status;
}
/**
* Mapping for contract registry.
*/
mapping(bytes32 => SIContract) public sicontracts;
/**
* The only permission worth setting; doing the reverse is pointless as a contract
* owner can interact with the contract as an anonymous third party simply by using
* another public key address.
*/
modifier onlyBy(address _account) {
if (msg.sender != _account) {
revert();
}
_;
}
/**
* Anyone can submit a contract for acceptance into a registry.
*/
function submitContract(bytes32 _contractHash, address idOwner) returns(bool) {
var sicontract = sicontracts[_contractHash];
sicontract.hash = _contractHash;
sicontract.submitter = idOwner;
sicontract.status = PENDING;
return true;
}
/**
* Only the registry owner (ideally multi-sig) can approve a contract.
*/
function approveContract(bytes32 _contractHash) returns(bool) {
var sicontract = sicontracts[_contractHash];
if(sicontract.submitter != msg.sender){
return false;
}
sicontract.status = ACTIVE;
return true;
}
/**
* Only the registry owner (ideally multi-sig) can reject a contract.
*/
function rejectContract(bytes32 _contractHash) onlyBy(owner) returns(bool) {
var sicontract = sicontracts[_contractHash];
sicontract.status = REJECTED;
return true;
}
/**
* Only the registry owner and original submitter can delete a contract.
* A contract in the rejected list cannot be removed.
*/
function deleteContract(bytes32 _contractHash) returns(bool) {
var sicontract = sicontracts[_contractHash];
if (sicontract.status != REJECTED) {
if (sicontract.submitter == msg.sender) {
if (msg.sender == owner) {
delete sicontracts[_contractHash];
return true;
}
}
} else {
revert();
}
}
/**
* This is the public registry function that contracts should use to check
* whether a contract is valid. It's defined as a function, rather than .call
* so that the registry owner can choose to charge based on their reputation
* of managing good contracts in a registry.
*
* Using a function rather than a call also allows for better management of
* dependencies when a chain forks, as the registry owner can choose to kill
* the registry on the wrong fork to stop this function executing.
*/
function isValidContract(bytes32 _contractHash) returns(bool) {
if (sicontracts[_contractHash].status == ACTIVE) {
return true;
}
if (sicontracts[_contractHash].status == REJECTED) {
revert();
} else {
return false;
}
}
}
Python code of calling submit function
self.smartIdContract.call({"from": sender_account}).submitContract(hex_hash,decode_hex(id_public_key))
Code for verifying above submitted entry
self.smartIdContract.call({"from": wrong_addr}).approveContract(id_hash)
What am I doing wrong ? Why my mocha test cases work fine and web3.py calls fails ? I am using testrpc as network.
My mocha test cases for the above contract is :
/**
* The purpose of this test contract is to test the functions in SmartIdentityRegistry.sol.
*/
var SmartIdentityRegistry = artifacts.require("SmartIdentityRegistry");
contract('SmartIdentityRegistry', function(accounts) {
var registry,
contractRegistry1,
contractRegistry2,
contracthash1,
contracthash2;
contracthash1 = '0xca02b2202ffaacbd499438ef6d594a48f7a7631b60405ec8f30a0d7c096d54d5';
contracthash2 = '0xca02b2202ffaacbd499438ef6d594a48f7a7631b60405ec8f30a0d7c096dc3ff';
before("Setup the Smart Identity registry and hydrate the required variables", function(done) {
contractRegistry1 = accounts[0];
contractRegistry2 = accounts[1];
SmartIdentityRegistry.new({from: contractRegistry1})
.then(function(response) {
registry = response;
done();
});
return registry,
contractRegistry1,
contractRegistry2;
});
describe("SmartIdentityRegistry tests", function() {
it("will submit a contract into the registry", function() {
return registry.submitContract(contracthash1,contractRegistry2, {from: contractRegistry1})
.then(function(response) {
assert.isOk(response, 'Contract submitting failed');
});
});
it("will prove that the submitter can only approve a contract", function() {
return registry.approveContract(contracthash1, {from: contractRegistry2})
.then(function(response) {
assert.isOk(response, 'Contract approval failed');
});
});
it("will prove that a non-id owner cannot approve a contract", function() {
return registry.approveContract(contracthash1, {from: contractRegistry1})
.catch(function(error) {
assert.isOk(error, "Expected error has not been caught");
});
});
it("will prove that the registry owner can reject a contract", function() {
return registry.rejectContract(contracthash1, {from: contractRegistry1})
.then(function(response) {
assert.isOk(response, 'Contract rejection failed');
});
});
it("will prove that a non-owner cannot reject a contract", function() {
return registry.rejectContract(contracthash1, {from: contractRegistry2})
.catch(function(error) {
assert.isOk(error, "Expected error has not been caught");
});
});
it("will delete a contract from the registry", function() {
registry.submitContract(contracthash2,contractRegistry2, {from: contractRegistry1})
.then(function(response) {
assert.isOk(response, 'Contract submitting failed');
});
return registry.deleteContract(contracthash2).then(function(response) {
assert.isOk(response, 'Contract failed to be deleted');
});
});
it("will verify a contract is not valid", function() {
registry.submitContract(contracthash2,contractRegistry2, {from: contractRegistry1})
.then(function(response) {
assert.isOk(response, 'Contract submitting failed');
});
return registry.isValidContract(contracthash2).then(function(response) {
assert.isOk(response, 'Failed to verify contract');
});
});
it("will verify a contract is not valid and will throw an error", function() {
registry.submitContract(contracthash2,contractRegistry2, {from: contractRegistry1})
.then(function(response) {
assert.isOk(response, 'Contract submitting failed');
});
registry.rejectContract(contracthash2, {from: contractRegistry1});
return registry.isValidContract(contracthash2)
.catch(function(error) {
assert.isOk(error, "Expected error has not been caught");
});
});
it("will verify a contract is valid", function() {
registry.submitContract(contracthash2, contractRegistry2,{from: contractRegistry1})
.then(function(response) {
assert.isOk(response, 'Contract submitting failed');
});
registry.approveContract(contracthash2, {from: contractRegistry2});
return registry.isValidContract(contracthash2)
.then(function(response) {
assert.isOk(response, 'Failed to verify contract');
});
});
});
});