I've been banging my head on this one for some hours, I'd appreciate any help :)
This is a final edit to clearly state the issue: Is there a proper way to pass a bytes32 array to a method on contract B, that itself instantiates a contract A (from its address) and passes the bytes32 array to a method of that contract? Passing the array directly to contract A's method works just fine, but passing it to contract B's method which in turn passes it to contract A's method doesn't work when the array has more than one bytes32.
Is that a limitation of solidity? Or am I doing something wrong (in solidity or with my javascript web3js code)? Or is that a bug with testrpc?
Full details below. Let me know if you can reproduce the problem, or if that works just fine or whatnot.
I have a contract A and a contract B which inherits from it. What I want to do is instantiate a contract A in contract B, from an already deployed contract A address, and call that instance's methods.
I know how to do this (or at least, I think I do; maybe it's not a proper way to do it?) and it works. The real issue is with the array of bytes32.
Context
Before anything else, here's the contracts code.
contract A {
struct MyStruct {
address user;
bytes32 [] stuff;
}
MyStruct [] public myStructs;
function addStuff (bytes32 [] _stuff) public {
myStructs.push (
MyStruct ({user: msg.sender, stuff: _stuff})
);
}
}
contract B is A {
function provideStuff (address to, bytes32 [] stuff) public {
A(to).addStuff(stuff);
}
}
A bit of context: stuff
is a hexadecimal string (which can be 256 bits = 32 bytes (fits perfectly in a bytes32
), or more (512, etc.); hence the array bytes32[]
).
First, I deploy a contract A (returning an instance contractA
) with the wallet address anAddress
. This gives me, when my contract is deployed, the smart contract address contractAaddress
.
Calling addStuff
with an array of bytes32 works perfectly:
gasEstimate = contractA.addStuff.estimateGas(getBytes32Array(stuff), {from: anAddress);
contractA.addStuff(getBytes32Array(stuff), {from: anAddress, gas: gasEstimate});
Note - getBytes32Array
I have a function, getBytes32Array
, which outputs an array of Bytes32 (hexadecimal strings actually) from a given hexadecimal string:
function getBytes32Array(string){
var splittedString = string.match(/.{1,64}/g);
for(var i=0; i< splittedString.length; i++){
splittedString[i] = "0x"+splittedString[i];
}
return splittedString;
}
This allows me to simply input my hex string, for instance e0f89ca8eae95281590977802df657506a151304234d15570c12cc26263a8b7a2bf140bc9f80baa93879634717d9c2cf08cc6c96492c1b56c053ae54546f4f20
(512 bits) and obtain ["0xe0f89ca8eae95281590977802df657506a151304234d15570c12cc26263a8b7a","0x2bf140bc9f80baa93879634717d9c2cf08cc6c96492c1b56c053ae54546f4f20"]
which will be understood as a bytes32 array containing two bytes32.
On to the real issue
Calling addStuff
in this manner works perfectly with an array of bytes32 containing more than one bytes32.
Now, second, I'm deploying my contract B (returning an instance contractB
) with the wallet address anotherAddress
. This gives me, when my contract is deployed, the smart contract address contractBaddress
.
What I'd like to do is call the provideStuff
method of contract B, feeding it the address of the deployed contract A contractAaddress
and the stuff
, which should instantiate the contract A from the address and call the addStuff
with the stuff
provided. (see contract B solidity code)
gasEstimate = contractB.provideStuff.estimateGas(contractAaddress, getBytes32Array(stuff), {from: anotherAddress});
contractB.provideStuff(contractAaddress, getBytes32Array(stuff), {from: anotherAddress, gas: gasEstimate});
But this gives me an invalid Op Code each time... Despite the estimateGas working (isn't that weird?)... This does work when my bytes32 array only has one bytes32. Even weirder, it also works when it has a second bytes32 that's a very short hex string (see PS1). But I can't get a consistent behaviour with an array of x bytes32, each 32 bytes (64 character) hex strings (or even shorter)...
Thanks in advance.
PS1: the previous example works fine if stuff is a 256bit hex value or a little longer (I tried with hardcoding ["0x256BitValueHere","0xverySmallValueHere"]
, 0xverySmallValueHere
can't be longer than a few characters (maybe 10, I don't remember), after that it fires invalide Op Code again. I also tried with several little values ["0xverySmallValueHere", "0xverySmallValueHere", "0xverySmallValueHere", "0xverySmallValueHere"]
, it won't work either.
PS2: working locally with testrpc.
EDIT: Everything works perfectly in Remix. So it's not a Solidity code issue.