1

I'm getting issues with the following contract for no obvious reason (I'm banging my head over this problem last 8 hours), I'm getting:

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? 
Error: gas required exceeds allowance or always failing transaction at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1724108 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1274130 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:370402 at o (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:388633) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373232 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:370402 at c (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373508) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373546 at Ht (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:382915) at Object.<anonymous> (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373635) at e.value (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1275045) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1274612 at n (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:388577) at o (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:388655) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373232 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1274578 at n (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:388577) at o (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:388655) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373232 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1274951 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:374042 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:370402 at c (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373508) at s (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373430) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:373232 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:374022 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1274833 at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1273270 at i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:1:1392551)

I've played with various variations of the code, but generally as you uncomment functions in the code you reach some sort of limit in gas which is overlaps block gas limit (I'm using solc --gas ./contracts/Banks.sol to check gas necessary to deploy this contract). The estimate of gas necessary to deploy such contract is currently over 4million which essentially makes it impossible to deploy due to block gas limit.

The contract itself compiles fine but contract creation cost is so much high that I can't deploy it to Ropsten. The contract however is deployable to a JavaScript VM in Remix if sufficient gas is provided. What's wrong with the following contract?

Disclaimer: This is whole contract is a proof of concept code with no real intentions. The whole purpose of it is to demonstrate a virtual use-case.

pragma solidity ^0.4.16;


contract Banks {
    address internal owner;

    struct Bank {
        bool registered;

        string name;
    }

    struct Account {
        bool registered;

        string id;
        string bankId;
        string password;
        string lastName;
        string firstName;
        string passportNumber;
    }

    struct User {
        bool registered;

        string password;
        string lastName;
        string firstName;
        string passportNumber;

        string[] bankIdByAccountIndex;

        mapping (string => Account) bankIdToAccount;
        mapping (string => uint256) bankIdToAccountBalance;
    }

    enum TransactionType {
        FromUserToUser,
        FromBankToUser
    }

    struct Transaction {
        string fromAccountId;
        string toAccountId;

        string bankId;

        uint256 amount;
        uint256 fromTimestamp;
        uint256 tillTimestamp;

        TransactionType transactionType;
    }

    mapping (string => uint256) qrCodeToBalance;

    mapping (string => Bank) internal bankIdToBank;
    mapping (string => User) internal accountIdToUser;
    mapping (string => Transaction[]) internal bankIdToTransactionArray;
    mapping (string => Transaction[]) internal accountIdToTransactionArray;

    constructor() public {
        owner = msg.sender;
    }

    function registerBank(string code, string name) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(!bankIdToBank[code].registered, "Bank is already registered");

        bankIdToBank[code] = Bank({ registered: true, name: name });
    }

    function deleteBank(string code) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(!bankIdToBank[code].registered, "Bank is not registered");

        delete bankIdToBank[code];
    }

    function registerUser(
        string accountId,
        string password,
        string firstName,
        string lastName,
        string passportNumber
    ) public
    {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(!accountIdToUser[accountId].registered, "Banks user is already registered");

        User memory user;

        user.registered = true;
        user.firstName = firstName;
        user.lastName = lastName;
        user.passportNumber = passportNumber;
        user.password = password;

        accountIdToUser[accountId] = user;
    }

    function changePassword(string accountId, string password) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        accountIdToUser[accountId].password = password;
    }

    function registerAccount(
        string accountId,
        string bankId,
        string id,
        string password,
        string firstName,
        string lastName,
        string passportNumber,
        uint256 value
    ) public
    {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");
        require(
            !accountIdToUser[accountId].bankIdToAccount[bankId].registered,
            "User's account already registered"
        );

        accountIdToUser[accountId].bankIdByAccountIndex.push(bankId);
        accountIdToUser[accountId].bankIdToAccount[bankId] = Account({
            registered: true,

            id: id,
            password: password,
            lastName: lastName,
            firstName: firstName,
            bankId: bankId,
            passportNumber: passportNumber
        });

        accountIdToUser[accountId].bankIdToAccountBalance[bankId] = value;
    }

    function getUserAccountCount(string accountId) public view returns (uint256) {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        return accountIdToUser[accountId].bankIdByAccountIndex.length;
    }

    function getUserAccount(string accountId, uint32 accountIndex) public view returns (string, string, uint256) {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        string memory bankId = accountIdToUser[accountId].bankIdByAccountIndex[accountIndex];

        return (
            accountIdToUser[accountId].bankIdToAccount[bankId].id,
            bankId,
            accountIdToUser[accountId].bankIdToAccountBalance[bankId]
        );
    }

    function getUserInfo(string accountId) public view returns (string, string, string) {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        return (accountIdToUser[accountId].firstName, accountIdToUser[accountId].lastName, accountIdToUser[accountId].passportNumber);
    }

    function getUserTransactionsCount(string accountId) public view returns (uint256) {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        return accountIdToTransactionArray[accountId].length;
    }

    function getUserTransaction(string accountId, uint256 transactionIndex) public view returns (
        string, // fromAccountId
        string, // toAccountId

        string, // bankId

        uint256, // amount,

        uint256, // fromTimestamp
        uint256, // tillTimestamp

        TransactionType // transactionType
    ) {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        return (
            accountIdToTransactionArray[accountId][transactionIndex].fromAccountId,
            accountIdToTransactionArray[accountId][transactionIndex].toAccountId,
            accountIdToTransactionArray[accountId][transactionIndex].bankId,
            accountIdToTransactionArray[accountId][transactionIndex].amount,
            accountIdToTransactionArray[accountId][transactionIndex].fromTimestamp,
            accountIdToTransactionArray[accountId][transactionIndex].tillTimestamp,
            accountIdToTransactionArray[accountId][transactionIndex].transactionType
        );
    }

    function sendMoney(
        string bankId,
        string fromAccountId,
        string toAccountId,
        uint256 fromTimestamp,
        uint256 tillTimestamp,
        uint256 value
    ) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[fromAccountId].registered, "from account is not registered");
        require(accountIdToUser[toAccountId].registered, "to account is not registered");
        require(accountIdToUser[fromAccountId].bankIdToAccountBalance[bankId] >= value, "Insufficient amount of value");

        Transaction memory transaction = Transaction({
            fromAccountId: fromAccountId,
            toAccountId: toAccountId,
            bankId: bankId,
            amount: value,
            fromTimestamp: fromTimestamp,
            tillTimestamp: tillTimestamp,
            transactionType: TransactionType.FromUserToUser
        });

        accountIdToTransactionArray[toAccountId].push(transaction);
        accountIdToTransactionArray[fromAccountId].push(transaction);

        accountIdToUser[toAccountId].bankIdToAccountBalance[bankId] += value;
        accountIdToUser[fromAccountId].bankIdToAccountBalance[bankId] -= value;
    }

    function requestLoan(string qrCode, string accountId, string bankId, uint256 fromTimestamp, uint256 tillTimestamp, uint256 value) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");

        qrCodeToBalance[qrCode] = value;

        Transaction memory transaction = Transaction({
            fromAccountId: bankId,
            toAccountId: accountId,
            bankId: bankId,
            amount: value,
            fromTimestamp: fromTimestamp,
            tillTimestamp: tillTimestamp,
            transactionType: TransactionType.FromBankToUser
        });

        accountIdToTransactionArray[accountId].push(transaction);
    }

    function provideLoan(string qrCode, string accountId, string bankId, uint256 fromTimestamp, uint256 tillTimestamp, uint256 value) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");

        Transaction memory transaction = Transaction({
            fromAccountId: bankId,
            toAccountId: accountId,
            bankId: bankId,
            amount: value,
            fromTimestamp: fromTimestamp,
            tillTimestamp: tillTimestamp,
            transactionType: TransactionType.FromBankToUser
        });

        if (qrCodeToBalance[qrCode] == 0) {
            qrCodeToBalance[qrCode] = value;

            accountIdToTransactionArray[accountId].push(transaction);
        }

        bankIdToTransactionArray[bankId].push(transaction);
    }

    function deleteUser(string accountId) public {
        require(msg.sender == owner, "You are not allowed to perform this operation");
        require(accountIdToUser[accountId].registered, "Banks user is not registered");

        delete accountIdToUser[accountId];
    }
}
  • 1
    Why dont you refactor your smart contract into multiple smaller smart contract? – Ha ĐANG Aug 27 '18 at 3:07
  • A 4m+ gas contract will deploy on the mainnet, but not on the testnets. You can either refactor to build it as multiple small contracts, or work directly on the mainnet (or use something like ganache with a custom block gas limit) – Raghav Sood Aug 27 '18 at 3:56
  • Using strings will increase the size of your contract, as an alternative you can use bytes32 if your strings will fit in 32 bytes, you will save from including the runtime support for strings in your contract. – Ismael Aug 29 '18 at 19:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.