Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

Commit

Permalink
tests: add solidity test suites (#487)
Browse files Browse the repository at this point in the history
* tests: add solidity test suite

* tests: remove require strings

* Update tests-solidity/init-test-node.sh

* Update tests-solidity/init-test-node.sh

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
  • Loading branch information
sohkai and fedekunze authored Sep 1, 2020
1 parent 4344dc1 commit c9639c3
Show file tree
Hide file tree
Showing 104 changed files with 16,013 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests-solidity/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sol linguist-language=Solidity
5 changes: 5 additions & 0 deletions tests-solidity/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# dependencies
node_modules/

# ignore package-lock files (only use yarn.lock)
package-lock.json
102 changes: 102 additions & 0 deletions tests-solidity/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Solidity tests

Increasingly difficult tests are provided:

- [Basic](./suites/basic): simple Counter example, for basic calls, transactions, and events
- [Initialize](./suites/initialize): initialization contract and tests from [aragonOS](https://github.com/aragon/aragonOS)
- [Initialize (Buidler)](./suites/initialize-buidler): initialization contract and tests from [aragonOS](https://github.com/aragon/aragonOS), using [buidler](https://buidler.dev/)
- [Proxy](./suites/proxy): depositable delegate proxy contract and tests from [aragonOS](https://github.com/aragon/aragonOS)
- [Staking](./suites/staking): Staking contracts and full test suite from [aragon/staking](http://github.com/aragon/staking)

### Quick start

**Prerequisite**: in the repo's root, run `make install` to install the `ethermintd` and `ethermintcli` binaries. When done, come back to this directory.

**Prerequisite**: install the individual solidity packages. They're set up as individual reops in a yarn monorepo workspace. Install them all via `yarn install`.

To run the tests, start three terminals (or two, if you run `ethermintd` with `&`).

In the first, run `ethermintd`:

```sh
./init-test-node.sh
```

In the second, run `ethermintcli` as mentioned in the script's output:

```sh
ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id 1337 --trace --wsport 8546
```

You will now have three ethereum accounts unlocked in the test node:

- `0x3b7252d007059ffc82d16d022da3cbf9992d2f70` (Validator)
- `0xddd64b4712f7c8f1ace3c145c950339eddaf221d` (User 1)
- `0x0f54f47bf9b8e317b214ccd6a7c3e38b893cd7f0` (user 2)

From here, in your other available terminal, go into any of the tests and run `yarn test-ethermint`. You should see `ethermintd` accepting transactions and producing blocks. You should be able to query for any transaction via:

- `ethermintcli query tx <cosmos-sdk tx>`
- `curl localhost:8545 -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["<ethereum tx>"],"id":1}'`

And obviously more, via the Ethereum JSON-RPC API).

When in doubt, you can also run the tests against a Ganache instance via `yarn test-ganache`, to make sure they are behaving correctly.

### Test node

The [`init-test-node.sh`](./init-test-node.sh) script sets up ethermint with the following accounts:

- `eth18de995q8qk0leqk3d5pzmg7tlxvj6tmsku084d` (Validator)
- `0x3b7252d007059ffc82d16d022da3cbf9992d2f70`
- `eth1mhtyk3cj7ly0rt8rc9zuj5pnnmw67gsapygwyq` (User 1)
- `0xddd64b4712f7c8f1ace3c145c950339eddaf221d`
- `eth1pa20g7lehr330vs5ent20slr3wyne4lsy8qae3` (user 2)
- `0x0f54f47bf9b8e317b214ccd6a7c3e38b893cd7f0`

Each with roughly 100 ETH available (1e18 photon).

Running `ethermintcli list keys` should output:

```json
[
{
"name": "localkey",
"type": "local",
"address": "eth18de995q8qk0leqk3d5pzmg7tlxvj6tmsku084d",
"pubkey": "ethpub1pfqnmk6pq3ycjs34vv4n6rkty89f6m02qcsal3ecdzn7a3uunx0e5ly0846pzg903hxf2zp5gq4grh8jcatcemfrscdfl797zhg5crkcsx43gujzppge3n"
},
{
"name": "user1",
"type": "local",
"address": "eth1mhtyk3cj7ly0rt8rc9zuj5pnnmw67gsapygwyq",
"pubkey": "ethpub1pfqnmk6pq3wrkx6lh7uug8ss0thggact3n49m5gkmpca4vylldpur5qrept57e0rrxfmeq5mp5xt3cyf4kys53qcv66qxttv970das69hlpkf8cnyd2a2x"
},
{
"name": "user2",
"type": "local",
"address": "eth1pa20g7lehr330vs5ent20slr3wyne4lsy8qae3",
"pubkey": "ethpub1pfqnmk6pq3art9y45zw5ntyktt2qrt0skmsl0ux9qwk8458ed3d8sgnrs99zlgvj3rt2vggvkh0x56hffugwsyddwqla48npx46pglgs6xhcqpall58tgn"
}
]
```

And running:

```
curl localhost:8545 -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}'
```

Should output:

```json
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"0x3b7252d007059ffc82d16d022da3cbf9992d2f70",
"0xddd64b4712f7c8f1ace3c145c950339eddaf221d",
"0x0f54f47bf9b8e317b214ccd6a7c3e38b893cd7f0"
]
}
```
61 changes: 61 additions & 0 deletions tests-solidity/init-test-node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash

CHAINID=1337
MONIKER="localtestnet"

VAL_KEY="localkey"
VAL_MNEMONIC="gesture inject test cycle original hollow east ridge hen combine junk child bacon zero hope comfort vacuum milk pitch cage oppose unhappy lunar seat"

USER1_KEY="user1"
USER1_MNEMONIC="copper push brief egg scan entry inform record adjust fossil boss egg comic alien upon aspect dry avoid interest fury window hint race symptom"

USER2_KEY="user2"
USER2_MNEMONIC="maximum display century economy unlock van census kite error heart snow filter midnight usage egg venture cash kick motor survey drastic edge muffin visual"

# remove existing daemon and client
rm -rf ~/.ethermint*

ethermintcli config keyring-backend test

# Set up config for CLI
ethermintcli config chain-id $CHAINID
ethermintcli config output json
ethermintcli config indent true
ethermintcli config trust-node true

# Import keys from mnemonics
echo $VAL_MNEMONIC | ethermintcli keys add $VAL_KEY --recover
echo $USER1_MNEMONIC | ethermintcli keys add $USER1_KEY --recover
echo $USER2_MNEMONIC | ethermintcli keys add $USER2_KEY --recover

# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
ethermintd init $MONIKER --chain-id $CHAINID

# Allocate genesis accounts (cosmos formatted addresses)
ethermintd add-genesis-account $(ethermintcli keys show $VAL_KEY -a) 1000000000000000000000aphoton,10000000000000000stake
ethermintd add-genesis-account $(ethermintcli keys show $USER1_KEY -a) 1000000000000000000000aphoton,10000000000000000stake
ethermintd add-genesis-account $(ethermintcli keys show $USER2_KEY -a) 1000000000000000000000aphoton,10000000000000000stake

# Sign genesis transaction
ethermintd gentx --name $VAL_KEY --keyring-backend test

# Collect genesis tx
ethermintd collect-gentxs

# Enable faucet
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json

echo -e '\n\ntestnet faucet enabled'
echo -e 'to transfer tokens to your account address use:'
echo -e "ethermintcli tx faucet request 100aphoton --from $VAL_KEY\n"


# Run this to ensure everything worked and that the genesis file is setup correctly
ethermintd validate-genesis

# Command to run the rest server in a different terminal/window
echo -e '\nrun the following command in a different terminal/window to run the REST server and JSON-RPC:'
echo -e "ethermintcli rest-server --laddr \"tcp://localhost:8545\" --wsport 8546 --unlock-key $VAL_KEY,$USER1_KEY,$USER2_KEY --chain-id $CHAINID --trace\n"

# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace
15 changes: 15 additions & 0 deletions tests-solidity/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "tests-solidity",
"private": true,
"version": "1.0.0",
"author": "Aragon Association <contact@aragon.org>",
"license": "GPL-3.0-or-later",
"workspaces": {
"packages": [
"suites/*"
],
"nohoist": [
"**/@aragon/contract-helpers-test"
]
}
}
24 changes: 24 additions & 0 deletions tests-solidity/suites/basic/contracts/Counter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity ^0.5.11;

contract Counter {
uint256 counter = 0;
string internal constant ERROR_TOO_LOW = "COUNTER_TOO_LOW";
event Changed(uint256 counter);
event Added(uint256 counter);

function add() public {
counter++;
emit Added(counter);
emit Changed(counter);
}

function subtract() public {
require(counter > 0, ERROR_TOO_LOW);
counter--;
emit Changed(counter);
}

function getCounter() public view returns (uint256) {
return counter;
}
}
19 changes: 19 additions & 0 deletions tests-solidity/suites/basic/contracts/test/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.8.0;

contract Migrations {
address public owner = msg.sender;
uint public last_completed_migration;

modifier restricted() {
require(
msg.sender == owner,
"This function is restricted to the contract's owner"
);
_;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
5 changes: 5 additions & 0 deletions tests-solidity/suites/basic/migrations/1_initial_migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Migrations = artifacts.require("Migrations");

module.exports = function (deployer) {
deployer.deploy(Migrations);
};
14 changes: 14 additions & 0 deletions tests-solidity/suites/basic/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "basic",
"version": "1.0.0",
"author": "Aragon Association <contact@aragon.org>",
"license": "GPL-3.0-or-later",
"scripts": {
"test-ganache": "yarn truffle test",
"test-ethermint": "yarn truffle test --network ethermint"
},
"devDependencies": {
"truffle": "^5.1.42",
"web3": "^1.2.11"
}
}
Empty file.
80 changes: 80 additions & 0 deletions tests-solidity/suites/basic/test/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const Counter = artifacts.require("Counter")

contract('Counter', ([one, two, three]) => {
console.log(one, two, three)
let counter

beforeEach(async() => {
counter = await Counter.new()
console.log('Counter:', counter.address)

console.log('Current eth:')
console.log(' - ', await web3.eth.getBalance(one))
console.log(' - ', await web3.eth.getBalance(two))
console.log(' - ', await web3.eth.getBalance(three))
console.log('')
})

it('should add', async() => {
const balanceOne = await web3.eth.getBalance(one)
const balanceTwo = await web3.eth.getBalance(two)
const balanceThree = await web3.eth.getBalance(three)

let count

await counter.add({ from: one })
count = await counter.getCounter()
console.log(count.toString())
assert.equal(count, '1', 'Counter should be 1')
assert.notEqual(balanceOne, await web3.eth.getBalance(one), `${one}'s balance should be different`)

await counter.add({ from: two })
count = await counter.getCounter()
console.log(count.toString())
assert.equal(count, '2', 'Counter should be 2')
assert.notEqual(balanceTwo, await web3.eth.getBalance(two), `${two}'s balance should be different`)

await counter.add({ from: three })
count = await counter.getCounter()
console.log(count.toString())
assert.equal(count, '3', 'Counter should be 3')
assert.notEqual(balanceThree, await web3.eth.getBalance(three), `${three}'s balance should be different`)
})

it('should subtract', async() => {
let count

await counter.add()
count = await counter.getCounter()
console.log(count.toString())
assert.equal(count, '1', 'Counter should be 1')

// Use receipt to ensure logs are emitted
const receipt = await counter.subtract()
count = await counter.getCounter()
console.log(count.toString())
console.log()
console.log('Subtract tx receipt:', receipt)
assert.equal(count, '0', 'Counter should be 0')
assert.equal(receipt.logs[0].event, 'Changed', "Should have emitted 'Changed' event")
assert.equal(receipt.logs[0].args.counter, '0', "Should have emitted 'Changed' event with counter being 0")

// Check lifecycle of events
const contract = new web3.eth.Contract(counter.abi, counter.address)
const allEvents = await contract.getPastEvents("allEvents", { fromBlock: 0, toBlock: 'latest' })
const changedEvents = await contract.getPastEvents("Changed", { fromBlock: 0, toBlock: 'latest' })
console.log('allEvents', allEvents)
console.log('changedEvents', changedEvents)
assert.equal(allEvents.length, 3)
assert.equal(changedEvents.length, 2)

try {
await counter.subtract()
assert.fail('Subtracting past 0 should have reverted')
} catch (err) {
console.log()
console.log('Passed -- was expecting error')
console.log('Error:', err)
}
})
})
17 changes: 17 additions & 0 deletions tests-solidity/suites/basic/truffle-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
networks: {
// Development network is just left as truffle's default settings
ethermint: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
gas: 5000000, // Gas sent with each transaction
gasPrice: 1000000000, // 1 gwei (in wei)
},
},
compilers: {
solc: {
version: "0.5.17",
},
},
}
3 changes: 3 additions & 0 deletions tests-solidity/suites/initializable-buidler/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Buidler
artifacts
cache
28 changes: 28 additions & 0 deletions tests-solidity/suites/initializable-buidler/buidler.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { usePlugin } = require('@nomiclabs/buidler/config')

usePlugin("@nomiclabs/buidler-ganache")
usePlugin('@nomiclabs/buidler-truffle5')

module.exports = {
networks: {
// Development network is just left as truffle's default settings
ganache: {
url: 'http://localhost:8545',
gasLimit: 5000000,
gasPrice: 1000000000, // 1 gwei (in wei)
defaultBalanceEther: 100
},
ethermint: {
url: 'http://localhost:8545',
gasLimit: 5000000, // Gas sent with each transaction
gasPrice: 1000000000, // 1 gwei (in wei)
},
},
solc: {
version: '0.4.24',
optimizer: {
enabled: true,
runs: 10000,
},
},
}
Loading

0 comments on commit c9639c3

Please sign in to comment.