示例#1
0
const compileNewFile = async (c) => {

  // Write a new source file from scratch
  if (!fs.existsSync('contracts')) { fs.mkdirSync('contracts') }
  const source = 'contract TestRecompile { uint256 public thing; constructor() { thing = 0x1; } }'
  fs.writeFileSync(path.join('contracts', 'TestRecompile.sol'), source)

  const inputHash = util.keccak(source).toString('hex')
  const compileOutput = await c.compile('TestRecompile.sol')
  assert(isCompile(compileOutput))

  const contract = await c.getContractsManager().getContract('TestRecompile')
  assert(isContract(contract))

  const timestamp = contract.get('timestamp')
  assert.equal(inputHash, compileOutput.get('TestRecompile').get('inputHash'))
  assert.equal(inputHash, contract.get('inputHash'))
  assert.equal(compileOutput.get('TestRecompile').get('timestamp'), timestamp)

  const output = {
    inputHash: inputHash,
    timestamp: timestamp,
  }
  LOGGER.debug('OUTPUT', output)
  return output
}
示例#2
0
const checkRecompile = async (c, prevInputHash, prevTimestamp) => {

  const source2 = 'contract TestRecompile { uint256 public thing2; constructor() { thing2 = 0x1; } }'
  fs.unlinkSync(path.join('contracts', 'TestRecompile.sol'))
  fs.writeFileSync(path.join('contracts', 'TestRecompile.sol'), source2)
  const inputHash2 = util.keccak(source2)
  const compileOutput3 = await c.compile('TestRecompile.sol')
  assert(isCompile(compileOutput3))
  const contract2 = await c.getContractsManager().getContract('TestRecompile')
  assert(isContract(contract2))
  const timestamp2 = await contract2.get('timestamp')
  assert.notEqual(inputHash2, prevInputHash)
  LOGGER.debug( 'Timestamps', prevTimestamp, timestamp2 )
  assert.ok(Number(timestamp2) > Number(prevTimestamp))

  fs.unlinkSync(path.join('contracts', 'TestRecompile.sol'))
  // Ideally we would rmdir this, but node requires some rimraf magic
  //fs.unlinkSync('contracts')

}
示例#3
0
  /**
   * Link a previously compiled contract. Validate dependencies and generate appropriate metadata
   * @param eth network object connected to a local provider
   * @param contractOutput the JSON compiled output to deploy
   * @param depMap is an Immutable Map of library names to deploy IDs
   * @return the contractOutput augmented with a linkDepMap
   */
  async link(contractName, linkId, _depMap) {
    const contractOutput = await this.bm.getContract(contractName)
    if (!isContract(contractOutput)) { throw new Error(`Compile output not found for ${contractName}`) } 
    //assert(isContract(contractOutput), `Compile output not found for ${contractName}` )
    const code = '0x' + contractOutput.get('code')
    //const contractName = contractOutput.get('name')
    const linkName = `${contractName}-${linkId}`

    const linksDir = LINKS_DIR
    //ensureDir(LINKS_DIR)
    //ensureDir(linksDir)

    const link = await this.bm.getLink(linkName)
    const inputHash = keccak(JSON.stringify(contractOutput.toJS())).toString('hex')
    if (link && link.get('inputHash') === inputHash) {
      LOGGER.info(`Link ${linkName} is up-to-date with hash ${inputHash}`)
      return link
    } else {
      LOGGER.info(`Link ${linkName} out-of-date with hash ${inputHash}`)
    }
    assert(!isLink(link), `Link ${linkName} already exists`)

    const deployMap = await this.bm.getDeploys()

    let matches = Map({})
    let match
    while (match = LIB_PATTERN.exec(code)) {
      assert(match[0], `Match expression not found in ${code}`)
      assert(match[1], `Match group not found ${code}`)
      LOGGER.debug(`Match found ${JSON.stringify(match)}`)
      if (matches.has(match[1])) { assert.equal(match[0], matches.get(match[1])); continue }
      matches = matches.set(match[1], match[0])
    }
    LOGGER.debug(`matches ${matches.toString()}`)

    if (matches.count() === 0 && _depMap && _depMap.count() > 0) {
      throw new Error(`No matches to replace with link map ${JSON.stringify(depMap)}`)
    }

    if (matches.count() > 0 && (!_depMap || _depMap.count() == 0)) {
      throw new Error(`No link map found to replace ${JSON.stringify(matches)}`)
    }

    const depMap = Map.isMap(_depMap) ? _depMap : new Map({})

    const replacedCode = depMap.reduce((codeSoFar, deployId, contractName) => {
      // The linkId to replace for the given linkName can also
      // be a full deployName by itself (e.g. TestInterface=TestImpl-deploy)
      // in which case, deployId == `TestImpl-deploy` directly
      // instead of `TestInterface-deploy`
      const deployName = (deployId.startsWith('deploy')) ?
        `${contractName}-${deployId}` : deployId
      const linkPlaceholder = matches.get(contractName)
      if (!linkPlaceholder) {
        throw new Error(`Placeholder for dependency ${linkPlaceholder} not found in bytecode.`)
      }

      const deployObject = deployMap.get(deployName)
      if (!isDeploy(deployObject)) { throw new Error(`Deploy ${deployName} not deployed`) }
      LOGGER.debug('DEPLOY OBJECT', deployObject)

      const deployAddress = deployObject.get('deployAddress')
      assert(deployAddress)

      LOGGER.debug(`Replacing symbols ${linkPlaceholder} with ${deployAddress.slice(2)}`)
      while (codeSoFar.search(linkPlaceholder) !== -1) {
        codeSoFar = codeSoFar.replace(linkPlaceholder, deployAddress.slice(2))
      }
      return codeSoFar
    }, code)

    assert(replacedCode.match(LIB_PATTERN) === null) // All placeholders should be replaced

    const now = new Date()

    const linkOutput = new Map({
      type           : 'link',
      name           : contractName,
      linkId         : linkId,
      linkMap        : depMap,
      linkDate       : now.toLocaleString(),
      linkTime       : now.getTime(),
      code           : replacedCode,
      abi            : contractOutput.get('abi'),
      inputHash      : inputHash,
    })

    const linkFilePath = `${linksDir}/${linkName}`

    LOGGER.debug(`Writing link to ${linkFilePath}`)
    return awaitOutputter(this.outputter(linkFilePath, linkOutput),
                          () => { return linkOutput })
  }