Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/phase/3/txExecution' into featur…
Browse files Browse the repository at this point in the history
…e/environmentalOpCodes
  • Loading branch information
rtkaczyk committed Apr 3, 2017
2 parents 894dfe9 + 420eb2e commit aaad33b
Show file tree
Hide file tree
Showing 23 changed files with 514 additions and 39 deletions.
18 changes: 12 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
enablePlugins(JavaAppPackaging)
enablePlugins(JavaAppPackaging, SolidityPlugin)

val commonSettings = Seq(
name := "etc-client",
Expand Down Expand Up @@ -42,12 +42,15 @@ val dep = {

val Integration = config("it") extend Test

val root = project.in(file("."))
.configs(Integration)
.settings(commonSettings: _*)
.settings(libraryDependencies ++= dep)
.settings(inConfig(Integration)(Defaults.testSettings) : _*)
val Evm = config("evm") extend Test

val root = project.in(file("."))
.configs(Integration)
.configs(Evm)
.settings(commonSettings: _*)
.settings(libraryDependencies ++= dep)
.settings(inConfig(Integration)(Defaults.testSettings) : _*)
.settings(inConfig(Evm)(Defaults.testSettings) : _*)

scalacOptions := Seq(
"-unchecked",
Expand All @@ -58,6 +61,9 @@ scalacOptions := Seq(

testOptions in Test += Tests.Argument("-oD")

(test in Evm) := (test in Evm).dependsOn(solidityCompile).value
(sourceDirectory in Evm) := baseDirectory.value / "src" / "evmTest"

(scalastyleConfig in Test) := baseDirectory.value / "scalastyle-test-config.xml"
scalastyleSources in Test ++= {(unmanagedSourceDirectories in Integration).value}

Expand Down
3 changes: 3 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies:
pre:
- sudo add-apt-repository -y ppa:ethereum/ethereum; sudo apt-get update; sudo apt-get install -y solc
41 changes: 41 additions & 0 deletions project/SolidityPlugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import java.io.PrintWriter

import sbt.TaskKey
import sbt._
import Keys._

object SolidityPlugin extends AutoPlugin {

object autoImport {
lazy val solidityCompile = TaskKey[Unit]("solidityCompile", "Compiles solidity contracts")
}

import autoImport._

override def projectSettings: Seq[Def.Setting[_]] = Seq(
solidityCompile := {
import sys.process._

val contractsDir = baseDirectory.value / "src" / "evmTest" / "resources" / "solidity"
val outDir = baseDirectory.value / "target" / "contracts"

(contractsDir ** "*.sol").get.foreach { f =>
Seq("solc", f.getPath, "--bin", "--overwrite", "-o", outDir.getPath).!!

// this is a temporary workaround, see: https://github.com/ethereum/solidity/issues/1732
val abiOut = Seq("solc", f.getPath, "--abi").!!
val abisLines = abiOut.split("\n").sliding(4, 4)
abisLines.foreach { abiLines =>
val contractName = abiLines(1)
.replace(f.getPath, "")
.dropWhile(_ != ':').drop(1)
.takeWhile(_ != ' ')
new PrintWriter(outDir / s"$contractName.abi") {
write(abiLines.drop(3).mkString); close()
}
}
}
}
)

}
24 changes: 24 additions & 0 deletions src/evmTest/resources/solidity/Caller.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity ^0.4.10;

contract Callee {

uint foo = 2;

function setFoo(uint v) {
foo = v;
}

function getFoo() constant returns (uint) {
return foo;
}

}

contract Caller {

function makeACall(address calleeAddr, uint fooVal) {
Callee callee = Callee(calleeAddr);
callee.setFoo(fooVal);
}

}
20 changes: 20 additions & 0 deletions src/evmTest/resources/solidity/ContractCallingItself.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pragma solidity ^0.4.10;

contract ContractCallingItself {

uint someVar = 10;

function callSelf() {
address selfAddress = this;
ContractCallingItself selfContract = ContractCallingItself(selfAddress);
selfContract.doubleSomeVar();
}

function doubleSomeVar() {
someVar = someVar * 2;
}

function getSomeVar() constant returns (uint) {
return someVar;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.10;

contract Fibonacci {
uint fib = 0;
Expand Down
19 changes: 19 additions & 0 deletions src/evmTest/resources/solidity/MinimumViableToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pragma solidity ^0.4.10;

contract MinimumViableToken {
/* This creates an array with all balances */
mapping (address => uint256) public balanceOf;

/* Initializes contract with initial supply tokens to the creator of the contract */
function MinimumViableToken(uint256 initialSupply) {
balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens
}

/* Send coins */
function transfer(address _to, uint256 _value) {
if (balanceOf[msg.sender] < _value) throw; // Check if the sender has enough
if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
balanceOf[msg.sender] -= _value; // Subtract from the sender
balanceOf[_to] += _value; // Add the same to the recipient
}
}
18 changes: 18 additions & 0 deletions src/evmTest/resources/solidity/MutualRecursion.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pragma solidity ^0.4.10;

contract MutualRecursion {

function isEven(uint n) returns (bool) {
if (n == 0)
return true;
else
return isOdd(n - 1);
}

function isOdd(uint n) returns (bool) {
if (n == 0)
return false;
else
return isEven(n - 1);
}
}
7 changes: 7 additions & 0 deletions src/evmTest/resources/solidity/Throw.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity ^0.4.10;

contract Throw {
function justThrow() {
throw;
}
}
22 changes: 22 additions & 0 deletions src/evmTest/scala/io/iohk/ethereum/vm/CallerSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.iohk.ethereum.vm

import io.iohk.ethereum.vm.utils.EvmTestEnv
import org.scalatest.{FreeSpec, Matchers}

// scalastyle:off magic.number
class CallerSpec extends FreeSpec with Matchers {

"EVM running Caller contract" - {

"should handle a call to Callee" in new EvmTestEnv {
val (_, callee) = deployContract("Callee")
val (_, caller) = deployContract("Caller")

val callRes = caller.makeACall(callee.address, 123).call()
callRes.error shouldBe None

callee.getFoo().call().returnData shouldBe UInt256(123).bytes
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.iohk.ethereum.vm

import io.iohk.ethereum.vm.utils.EvmTestEnv
import org.scalatest.{FreeSpec, Matchers}

// scalastyle:off magic.number
class ContractCallingItselfSpec extends FreeSpec with Matchers {

"EVM running ContractCallingItself contract" - {

"should handle a call to itself" in new EvmTestEnv {
val (_, contract) = deployContract("ContractCallingItself")

contract.getSomeVar().call().returnData shouldBe UInt256(10).bytes

val result = contract.callSelf().call()
result.error shouldBe None

contract.getSomeVar().call().returnData shouldBe UInt256(20).bytes
}
}

}
35 changes: 35 additions & 0 deletions src/evmTest/scala/io/iohk/ethereum/vm/FibonacciSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.iohk.ethereum.vm

import io.iohk.ethereum.vm.utils.EvmTestEnv
import org.scalatest.{FreeSpec, Matchers}

// scalastyle:off magic.number
class FibonacciSpec extends FreeSpec with Matchers {

"EVM running Fibonacci contract" - {

"should handle getNewFib call" in new EvmTestEnv {
val (_, contract) = deployContract("Fibonacci")

val result = contract.getNewFib(5).call()

result.error shouldBe None
result.returnData shouldBe UInt256(5).bytes
}

"should allow storage write/read" in new EvmTestEnv {
val (_, contract) = deployContract("Fibonacci")

val getNewRes = contract.getNewFib(6).call()

getNewRes.error shouldBe None
contract.storage.load(UInt256(0)) shouldBe UInt256(8)

val getStoredRes = contract.getStoredFib().call()

getStoredRes.error shouldBe None
getStoredRes.returnData shouldBe UInt256(8).bytes
}
}

}
57 changes: 57 additions & 0 deletions src/evmTest/scala/io/iohk/ethereum/vm/MinimumViableTokenSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.iohk.ethereum.vm

import io.iohk.ethereum.vm.utils.EvmTestEnv
import org.scalatest.{FreeSpec, Matchers}

// scalastyle:off magic.number
class MinimumViableTokenSpec extends FreeSpec with Matchers {

"EVM running MinimumViableToken contract" - {

"should init the balance and allow token transfer" in new EvmTestEnv {
val sender = createAccount(balance = 10)
val receiver = createAccount(balance = 10)

val (_, contract) = deployContract("MinimumViableToken", creatorAddress = sender, constructorArgs = Seq(150))

contract.balanceOf(sender).call().returnData shouldBe UInt256(150).bytes

val transferRes = contract.transfer(receiver, 40).call(sender = sender)
transferRes.error shouldBe None

contract.balanceOf(receiver).call().returnData shouldBe UInt256(40).bytes
contract.balanceOf(sender).call().returnData shouldBe UInt256(110).bytes
}

"should return an error when attempted to transfer more tokens than owned" in new EvmTestEnv {
val sender = createAccount(balance = 10)
val receiver = createAccount(balance = 10)

val (_, contract) = deployContract("MinimumViableToken", creatorAddress = sender, constructorArgs = Seq(100))

val transferRes = contract.transfer(receiver, 200).call(sender = sender)
transferRes.error shouldBe Some(InvalidOpCode(0xfd.toByte))
}

"should return an error when attempted to deploy and run out of gas" in new EvmTestEnv {
val sender = createAccount(balance = 10)
val receiver = createAccount(balance = 10)

val (result, _) = deployContract("MinimumViableToken", creatorAddress = sender,
constructorArgs = Seq(100), gasLimit = 75934)

result.error shouldBe Some(OutOfGas)
}

"should return an error when attempted to transfer and run out of gas" in new EvmTestEnv {
val sender = createAccount(balance = 10)
val receiver = createAccount(balance = 10)

val (_, contract) = deployContract("MinimumViableToken", creatorAddress = sender, constructorArgs = Seq(100))

val transferRes = contract.transfer(receiver, 10).call(sender = sender, gasLimit = 25934)
transferRes.error shouldBe Some(OutOfGas)
}
}

}
25 changes: 25 additions & 0 deletions src/evmTest/scala/io/iohk/ethereum/vm/MutualRecursionSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.iohk.ethereum.vm

import io.iohk.ethereum.vm.utils.EvmTestEnv
import org.scalatest.{FreeSpec, Matchers}

// scalastyle:off magic.number
class MutualRecursionSpec extends FreeSpec with Matchers {

"EVM running MutualRecursion contract" - {

"should handle a call to mutually recursive functions" in new EvmTestEnv {
val (_, contract) = deployContract("MutualRecursion")

val isOddRes = contract.isOdd(9).call()

isOddRes.error shouldBe None
isOddRes.returnData shouldBe UInt256(true).bytes

val isEvenRes = contract.isEven(99).call()
isEvenRes.error shouldBe None
isEvenRes.returnData shouldBe UInt256(false).bytes
}
}

}
20 changes: 20 additions & 0 deletions src/evmTest/scala/io/iohk/ethereum/vm/ThrowSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.iohk.ethereum.vm

import io.iohk.ethereum.vm.utils.EvmTestEnv
import org.scalatest.{FreeSpec, Matchers}

// scalastyle:off magic.number
class ThrowSpec extends FreeSpec with Matchers {

"EVM running Throw contract" - {

"should handle throwing" in new EvmTestEnv {
val (_, contract) = deployContract("Throw")

val result = contract.justThrow().call()

result.error shouldBe Some(InvalidOpCode(0xfd.toByte))
}
}

}

0 comments on commit aaad33b

Please sign in to comment.