Отображение структуры с ключом как bytes32 не сохраняется

Я пытаюсь реализовать смарт-контракт для случая использования управления идентификацией.

Я могу пройти все тестовые случаи, которые я написал мокко с трюфелем.

Я компилирую этот смарт-контракт с помощью трюфеля и вызываю его из web3.py.

Но когда я добавляю запись в сопоставление ( sicontracts) с ключом как bytes32(хэш Ipfs, преобразованный в bytes32) и значением, как struct SIContractв файле function submitContract. Кажется, он не сохраняется в сопоставлении. Когда я проверяю это, function approveContractон всегда возвращает false. Когда я проверил, я обнаружил, что мое сопоставление не сохраняется. Пожалуйста помоги.

Код прочности:

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 для вызова функции отправки

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

Код для проверки представленной выше записи

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

Что я делаю не так ? Почему мои тестовые примеры мокко работают нормально, а вызовы web3.py терпят неудачу? Я использую testrpc в качестве сети.

Мои тестовые примеры мокко для вышеуказанного контракта:

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

 });

Ответы (1)

Вместо звонка вам нужна транзакция. См.: В чем разница между транзакцией и вызовом?

Итак, вместо:

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

Пытаться:

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

Или более новый синтаксис из Web3.py v4:

bound_submission = self.smartIdContract.functions.submitContract(...)
txn_hash = bound_submission.transact({"from": sender_account})
Спасибо, Карвер. Как я получу результат во второй проверке? Должен ли я использовать событие или могу ли я получить это без изменения вышеуказанного контракта?
Или я могу позвонить и сказать, что это проверено?
После второй транзакции вы можете подождать, пока она будет добыта, а затем вызвать isValidContract. Но да, событие может быть даже лучше здесь.
Это пользователь веб-приложения, который сначала отправляет хэш идентификатора, а затем подтверждает его утверждение. 2 последовательных шага. Как я могу ждать, пока майнинг? Есть ли блокировка вызова? Мой план таков. Как следует, сначала выполните транзакцию при отправке контракта и вызовите вторую функцию.
Ожидание события звучит как ваш лучший вариант.