Zuordnung von Struct mit Schlüssel als bytes32 wird nicht gespeichert

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 SIContractin der function submitContract. Es scheint nicht im Mapping gespeichert zu werden. Wenn ich das verifiziere, gibt function approveContractes 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');
        });
    });
});

 });

Antworten (1)

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})
Danke Carver. Wie bekomme ich dann das Ergebnis bei der zweiten Überprüfung? Soll ich event verwenden oder kann ich dies haben, ohne den oben genannten Vertrag zu ändern?
Oder kann ich anrufen und sagen, dass es verifiziert ist?
Nach Ihrer zweiten Transaktion könnten Sie warten, bis sie abgebaut wird, und dann anrufen isValidContract. Aber ja, ein Event wäre hier vielleicht noch besser.
Dies ist ein Web-App-Benutzer, der zuerst einen ID-Hash einreicht und danach mit Genehmigung verifiziert. 2 aufeinanderfolgende Schritte. Wie kann ich warten, bis es abgebaut wird? Gibt es einen blockierenden Anruf? Mein Plan ist. Führen Sie wie folgt zuerst eine Transaktion zum Senden des Vertrags durch und rufen Sie die zweite Funktion auf.
Das Warten auf das Ereignis klingt nach der besten Option.