0

I have deployed a smart contract to the Polygon Mumbai Testnet (it shouldn't really matter where I deployed it).

When sending a transaction to call a function on this contract, the transaction fails, and after looking through the instructions trace, it seems a REVERT opcode was triggered.

There are no requires, asserts or anything in my code that would make me believe that a revert opcode would occur.

The only possibility I could think of is some error such as running out of stack space (if that's even a thing), although I would have presumed any such errors would be picked up at compile-time.

How do I fix this?


Here is my code:

pragma solidity ^0.8.0;

contract Predictions {
    mapping (address => PredictionCollection) predictions;

    struct PredictionCollection {
        Prediction[] predictions;
        uint length;
    }

    struct Prediction {
        bytes32[8] text;
    }

    struct PredictionInfo {
        bytes32[8] text;
    }

    function open(PredictionInfo calldata prediction) public returns (uint) {
        uint id = predictions[msg.sender].length;
        predictions[msg.sender].predictions[id] = Prediction({
            text: prediction.text
        });
        return id;
    }
}

Here is a link to the deployed contract.


Here is the code for my failed transaction (using web3js), in case this helps determine why my transaction has failed:

async function submitTransaction() {
    let text = [];
    for (let i = 0; i < 8; i++) {
        text.push(web3.utils.asciiToHex("Hello, World! :)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"));
    }

    await predictionsContract.methods.open({
        text,
    }).send({
        from: wallet,
    });
}

Here is a link to the mined transaction which includes the relevant input data.

Edit: This is the raw input data:

0x82715e9948656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a290000000000000000000000000000000048656c6c6f2c20576f726c6421203a2900000000000000000000000000000000
1

A few things I noticed that may be causing you trouble:

  1. Calldata is only available for external functions. Also, you’ve defined the struct as a storage variable. Why use calldata? Do you mean storage?

  2. Need to define the PredictionCollection struct before the mapping using PredictionCollection struct.

  3. You have shadow declarations where the mapping is predictions and the first dynamic array in your struct PredictionCollection is also named predictions.

Do you have specs for what you intend the smart contract to do?

Suggestion:

  1. Use Hardhat console.log to debug.
11
  • Thanks for these possibilities. I will take a look. I intend for the smart contract to simply store the text data (bytes32[8]) into an array inside a mapping, nothing complicated. Jun 29 '21 at 20:27
  • 1. I am surprised there was no compile-time error if this is the case. I will try to change this to memory. 2. I will try this, but once again I would have expected a compile-time error. 3. I don't see why that is a problem. Jun 29 '21 at 20:34
  • I have tried 1 and 2, getting the same error. Jun 29 '21 at 20:42
  • 1
    I tried running it through remix. Coming up with a potentially infinite loop with the gas limit being met running open. No compilation errors. Also, 3. matters for readability and convention. Gas requirement of function Predictions.open is infinite: If the gas requirement of a function is higher than the block gas limit, it cannot be executed. Please avoid loops in your functions or actions that modify large areas of storage (this includes clearing or copying arrays in storage) Pos: 21:4: What's a sample input for the open function?
    – maxgrok
    Jun 30 '21 at 13:35
  • 1
    And, for the record, everyone makes mistakes. No harm, no foul. :) Glad you discovered what you needed!
    – maxgrok
    Jul 1 '21 at 12:39
0

The problem was accessing an array with index out of bounds. I was modifying the last index rather than pushing an element to the array. (I thought the behaviour of an array was similar to that of a mapping).

Fixed code:

pragma solidity ^0.8.0;

contract Predictions {
    struct PredictionInfo {
        bytes32[8] text;
    }
    
    struct Prediction {
        bytes32[8] text;
    }
    
    mapping (address => Prediction[]) predictions;

    function open(PredictionInfo calldata prediction) public returns (uint) {
        uint id = predictions[msg.sender].length;
        
        predictions[msg.sender].push(Prediction({
            text: prediction.text
        }));
        
        return id;
    }
}

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.