Mapeo de estructura con clave como bytes32 que no se guarda

Estoy tratando de implementar un contrato inteligente para el caso de uso de gestión de identidad.

Soy capaz de pasar todos los casos de prueba que he escrito en moca con trufa.

Estoy compilando este contrato inteligente usando truffle y llamándolo desde web3.py.

Pero cuando agrego una entrada en el mapeo ( sicontracts) con clave como bytes32(Ipfs hash convertida a bytes32) y valor como struct SIContracten el archivo function submitContract. Parece que no se guarda en el mapeo. Cuando verifico esto function approveContract, siempre devuelve falso. Cuando revisé, pude encontrar que mi mapeo no se está guardando. Por favor ayuda.

Código de solidez:

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;
    }
}
}

Código de Python para llamar a la función de envío

 self.smartIdContract.call({"from": sender_account}).submitContract(hex_hash,decode_hex(id_public_key))

Código para verificar la entrada enviada anteriormente

self.smartIdContract.call({"from": wrong_addr}).approveContract(id_hash)

Qué estoy haciendo mal ? ¿Por qué mis casos de prueba de mocha funcionan bien y las llamadas web3.py fallan? Estoy usando testrpc como red.

Mis casos de prueba de mocha para el contrato anterior son:

/**
 * 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');
        });
    });
});

 });

Respuestas (1)

En lugar de una llamada, desea una transacción. Ver: ¿Cuál es la diferencia entre una transacción y una llamada?

Así que en lugar de:

self.smartIdContract.call({"from": sender_account}).submitContract(...)

Intentar:

self.smartIdContract.transact({"from": sender_account}).submitContract(...)

O la sintaxis más nueva de Web3.py v4:

bound_submission = self.smartIdContract.functions.submitContract(...)
txn_hash = bound_submission.transact({"from": sender_account})
Gracias Carber. ¿Cómo obtendré el resultado en la segunda verificación? ¿Debo usar event o puedo tener esto sin cambiar el contrato anterior?
¿O puedo llamar y decir que está verificado?
Después de su segunda transacción, puede esperar a que se extraiga y luego llamar isValidContract. Pero sí, un evento podría ser aún mejor aquí.
Este es un usuario de la aplicación web que primero envía el hash de identificación y verifica con la aprobación después de eso. 2 pasos consecutivos. ¿Cómo puedo esperar hasta que se extraiga? ¿Hay bloqueo de llamadas? mi plan es De la siguiente manera, primero realice la transacción al enviar el contrato y llame a la segunda función.
Esperar el evento suena como tu mejor opción.