Исключение виртуальной машины: контракт внутри контракта

Я следую этому примеру , чтобы поэкспериментировать с контрактом внутри контракта (используя 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();
  }
}

Мое имя файла — Product.sol, а файл deloy в трюфеле — это:

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


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

При развертывании и ProductFactory, и Product работают хорошо, о чем свидетельствует создание нового продукта с помощью addProduct. Однако при выполнении getName возвращается ошибка: исключение VM.

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: когда я пытаюсь сделать следующее,

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

понятно что работает. PF.productAddresses(0)- это объект , как я понял, и когда я его использую, Product.at(PF.productAddresses(0))он терпит неудачу так же, как getName. Однако при прямом использовании адресной строки , как только что показано, это работает. Как справиться с этой проблемой?

РЕДАКТИРОВАТЬ1 над:

Я новичок. Если бы кто-то мог сообщить мне, что я могу делать неправильно. Я думаю, что это связано с асинхронным вызовом, но я не уверен. Я пробовал несколько вариантов, а также Remix, но это просто не работает.

Ответы (1)

Я не думаю, что речь идет о наличии нескольких контрактов, у вас есть проблема в функции getName()с этим оператором:

    productNames[i] = prod.Name();

Вам не разрешено назначать индекс за пределами конца массива с динамическим размером. В частности, при первом вызове getName()массив productNamesимеет нулевой размер, поэтому вы не можете присвоить значение одному из его элементов: их нет.

Вам лучше использовать productNames.push(_productName)в своей addProduct()функции и getName()полностью удалить.

В качестве альтернативы вы можете использовать сопоставление вместо массива в iкачестве ключа. То есть измените объявление productNamesследующим образом: остальной код не меняется:

mapping (uint => bytes32) productNames;

Это работает, но это странный способ кодирования (имхо).

См. также эти вопросы и ответы.

Отлично, вместо того, чтобы полностью удалить getName, я попытался увеличить размер массива на 1 (в addName) и проверить, работает ли он - как вы дали ссылку, в которой есть два способа увеличить размер массива, нажать или увеличить длину. Оба подхода работают! Идея отображения интересная, должен сказать, хотя я продолжу с обычными. Еще раз спасибо!