0

I am following this example to experiment with contract from within a contract (using testrpc).

contract Product {
    bytes32 public Name;

    function Product (bytes32 _Name) {
        Name = _Name;
    }
}

contract ProductFactory {

    bytes32[] public productNames;
    address[] public productAddresses;

    function addProduct (bytes32 _productName) {
        address newProduct = new Product(_productName);
        productAddresses.push(newProduct);
    }

    function getName (uint i) {
    Product prod = Product(productAddresses[i]);

    productNames[i] = prod.Name();
  }
}

My filename is Product.sol and the deloy file in truffle is:

var Product = artifacts.require("./Product.sol");
var ProductFactory = artifacts.require('ProductFactory');


module.exports = function(deployer) {
  // deployer.deploy(supplyChain);
  deployer.deploy(Product);
  deployer.deploy(ProductFactory);
};

On deploy, ProductFactory and Product both work well, as demonstrated by creating a new product with addProduct. However, on doing a getName, error: VM Exception is returned.

truffle(development)> ProductFactory.deployed().then(function(instance){PF=ProductFactory.at(instance.address)})

truffle(development)> PF.addProduct('abcd')
{ tx: '0xe304f9194fb9b06ae5f0a3664f64255e74d88de099cce0cd38092030b5d48d7f',
  receipt:
   { transactionHash: '0xe304f9194fb9b06ae5f0a3664f64255e74d88de099cce0cd38092030b5d48d7f',
     transactionIndex: 0,
     blockHash: '0x09d3e5547b1d4cd9ef40d05b5b15561a45b9f62f55410d03c175886dd1c591eb',
     blockNumber: 122,
     gasUsed: 122275,
     cumulativeGasUsed: 122275,
     contractAddress: null,
     logs: [] },
  logs: [] }

truffle(development)> PF.getName(0)
Error: VM Exception while processing transaction: invalid opcode
    at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:37047:16)
...

EDIT1: When I am trying the following,

truffle(development)> PF.productAddresses(0)
'0x4b01bd4691c306c59e8985bb6bd5bcc88abf1e81'
truffle(development)> Product.at('0x4b01bd4691c306c59e8985bb6bd5bcc88abf1e81').Name()
'0x6162686900000000000000000000000000000000000000000000000000000000'

understandably it works. PF.productAddresses(0) is an object as I gathered, and when I am using Product.at(PF.productAddresses(0)) it fails the same way as getName. However, on directly using the address string as just shown, it works. How to manage this issue?

EDIT1 over:

I am a newbie. If someone could let me know what might I am doing wrong. I think it is to do with async call, but I am not sure. I have tried multiple variations and on Remix as well, but it simply doesn't work.

1

I don't think this is about having multiple contracts, you have an issue in the getName() function with this statement:

    productNames[i] = prod.Name();

You are not allowed to assign to an index beyond the end of a dynamically sized array. More specifically, when you first call getName(), the productNames array has zero size, so you can't assign to one of its elements: there aren't any.

You'd be better using productNames.push(_productName) within your addProduct() function and removing getName() entirely.

Alternatively, you could use a mapping instead of an array with i as your key. That is, change your declaration of productNames as follows; the rest of the code is unchanged:

mapping (uint => bytes32) productNames;

This works, but it's a weird way to code it (imho).

See also this Q&A.

  • Perfect, rather than removing getName altogether, I tried increasing array size by 1 (in addName) and checking whether it works - as you gave the reference for wherein there are two ways to increase array size, push, or increasing length. Both approach work! The mapping idea is interesting, must say, though I will go ahead with conventional ones. Thanks again! – Manganese Aug 20 '17 at 9:42

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.