Ich versuche, einen intelligenten Vertrag für den Anwendungsfall des Identitätsmanagements zu implementieren.
Ich kann alle Testfälle, die ich geschrieben habe, in Mokka mit Trüffel bestehen.
Ich kompiliere diesen Smart Contract mit Truffle und rufe ihn von web3.py auf.
Aber wenn ich einen Eintrag in der Zuordnung ( sicontracts
) mit Schlüssel als bytes32
(Ipfs-Hash konvertiert in Bytes32) und Wert wie struct SIContract
in der function submitContract
. Es scheint nicht im Mapping gespeichert zu werden. Wenn ich das verifiziere, gibt function approveContract
es immer false zurück. Bei der Überprüfung konnte ich feststellen, dass meine Zuordnung nicht gespeichert wird. Bitte helfen Sie.
Soliditätscode :
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 zum Aufrufen der Submit-Funktion
self.smartIdContract.call({"from": sender_account}).submitContract(hex_hash,decode_hex(id_public_key))
Code zum Verifizieren des oben eingereichten Eintrags
self.smartIdContract.call({"from": wrong_addr}).approveContract(id_hash)
Was mache ich falsch ? Warum funktionieren meine Mocha-Testfälle einwandfrei und web3.py-Aufrufe schlagen fehl? Als Netzwerk verwende ich testrpc.
Meine Mokka-Testfälle für den obigen Vertrag sind:
/**
* 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');
});
});
});
});
Statt eines Anrufs wollen Sie eine Transaktion. Siehe: Was ist der Unterschied zwischen einer Transaktion und einem Anruf?
Also statt:
self.smartIdContract.call({"from": sender_account}).submitContract(...)
Versuchen:
self.smartIdContract.transact({"from": sender_account}).submitContract(...)
Oder die neuere Syntax von Web3.py v4:
bound_submission = self.smartIdContract.functions.submitContract(...)
txn_hash = bound_submission.transact({"from": sender_account})
Bill Goldberg
Bill Goldberg
Schnitzer
isValidContract
. Aber ja, ein Event wäre hier vielleicht noch besser.Bill Goldberg
Schnitzer