Skip to content

Commit

Permalink
Rollup Chain Contract Deployment Script (#486)
Browse files Browse the repository at this point in the history
Contract changes:
* Emitting NewBlock event and including transitions in it

Deployment:
* Adding deploy script to deploy rollup-chain smart contracts
* Adding configuration for different environments and requiring the user to pass an environment parameter to prevent mistakes

Other:
* Updating README to remove a bunch of old stuff.
  • Loading branch information
willmeister committed Oct 3, 2019
1 parent 648da33 commit f9a6158
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 69 deletions.
23 changes: 23 additions & 0 deletions packages/contracts/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
################
# Instructions #
################
# Create environment file(s) named ".<environment>.env" in this same location using this file as a template
# For instance `yarn run deploy:some-contract local` will use .local.env for configuration.


############
# Template #
############

# REQUIRED
DEPLOY_MNEMONIC='your mnemonic here'
# Note: can use any network name. 'local' or leaving it blank will deploy to DEPLOY_LOCAL_URL
DEPLOY_NETWORK='local'

# Only if deploying locally
DEPLOY_LOCAL_URL='http://127.0.0.1:7545'

# Only if contracts are already deployed
DEPLOY_EVALUATOR_CONTRACT_ADDRESS='address if it is deployed'
DEPLOY_MERKLE_UTILS_CONTRACT_ADDRESS='address if it is deployed'

2 changes: 2 additions & 0 deletions packages/contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.*.env

64 changes: 17 additions & 47 deletions packages/contracts/README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,39 @@
# plasma-contracts
[![Build Status](https://travis-ci.org/plasma-group/plasma-contracts.svg?branch=master)](https://travis-ci.org/plasma-group/plasma-contracts)

`plasma-contracts` is the set of smart contracts written in Vyper for the Plasma Group series of projects. It includes an implementation of a Plasma Cash variant, and a registry contract for discovering Plasma chains. This repo is used for compiling those contracts--If you don't need any modifications, you can spin up your own with [`plasma-chain-operator`](https://github.com/plasma-group/plasma-chain-operator) or try out other chains with [`@pigi/plasma-js`](https://github.com/plasma-group/@pigi/plasma-js).

## Contributing
If you're looking to contribute to `plasma-contracts`, you're in the right place. Welcome!

### Contributing Guide and CoC
Plasma Group follows a [Contributing Guide and Code of Conduct](https://github.com/plasma-group/plasma-utils/blob/master/.github/CONTRIBUTING.md) adapted slightly from the [Contributor Covenant](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html). All contributors are expected to read through this guide. We're here to cultivate a welcoming and inclusive contributing environment, and every new contributor needs to do their part to uphold our community standards.
# contracts
`contracts` is the set of smart contracts written in Solidity for the Plasma Group series of projects.

### Requirements and Setup
The first step is cloning this repo. Via https:

```sh
git clone https://github.com/plasma-group/plasma-contracts.git
```
or ssh:
```sh
git clone git@github.com:plasma-group/plasma-contracts.git
```
Clone the parent repo `pigi` and follow its instructions.

#### Node.js
`plasma-contracts` is tested with [`Node.js`](https://nodejs.org/en/) and has been tested on the following versions of Node:
`contracts` is tested with [`Node.js`](https://nodejs.org/en/) and has been tested on the following versions of Node:

- 11.6.0

If you're having trouble getting `plasma-contracts` tests running, please make sure you have one of the above `Node.js` versions installed.
If you're having trouble getting `contracts` tests running, please make sure you have one of the above `Node.js` versions installed.

#### Packages
`plasma-contracts` makes use of several `npm` packages.
### Running Tests
`contracts` makes use of a combination of [`Mocha`](https://mochajs.org/) (a testing framework) and [`Chai`](https://www.chaijs.com/) (an assertion library) for testing.

Install all required packages with:
Run all tests with:

```sh
npm install
yarn test
```
So that Python and Vyper aren't requirements for our other components, we do include a `compiled-contracts` folder which contains JS exports of the bytecode and ABI. Compilation is done automatically before testing.

#### Python and Vyper
`plasma-contracts` is written in Vyper, a pythonic Ethereum smart contract language. You'll need [Python 3.6 or above](https://www.python.org/downloads/) to install Vyper.

We reccomend setting up a [virtual environment](https://cewing.github.io/training.python_web/html/presentations/venv_intro.html) instead of installing globally:
### Deploying
You can deploy by running:

```sh
python3 -m venv venv
yarn run deploy:<contract-specific-task-here> <environment>
```

To activate:

```sh
source venv/bin/activate
```
The `environment` parameter tells the deployment script which config file to use (expected filename `.<environment>.env`).

Install Vyper:
For instance, to deploy the RollupChain contract using `.local.env` as the config file, you would run:

```sh
pip3 install vyper
yarn run deploy:rollup-chain local
```
Your `venv` must be activated whenever testing or otherwise using Vyper, but it will break the `npm install`, so be sure to `$ deactivate` if you still need to do that and reactivate afterwards.

### Running Tests
`plasma-contracts` makes use of a combination of [`Mocha`](https://mochajs.org/) (a testing framework) and [`Chai`](https://www.chaijs.com/) (an assertion library) for testing.

Run all tests with:

```sh
npm test
```
So that Python and Vyper aren't requirements for our other components, we do include a `compiled-contracts` folder which contains JS exports of the bytecode and ABI. Compilation is done automatically before testing.
See `.env.example` for more information.
37 changes: 19 additions & 18 deletions packages/contracts/contracts/RollupChain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ contract RollupChain {
bytes returnData
);
event NewRollupBlock(
bytes[] block
bytes[] block,
uint256 blockNumber
);

/***************
Expand All @@ -55,10 +56,10 @@ contract RollupChain {
dt.Block memory rollupBlock = dt.Block({
rootHash: root,
blockSize: _block.length
});
});
blocks.push(rollupBlock);
// NOTE: Toggle the event if you'd like easier historical block queries
// emit NewRollupBlock(_block);
emit NewRollupBlock(_block, blocks.length);
return root;
}

Expand Down Expand Up @@ -93,19 +94,19 @@ contract RollupChain {
uint32[2] memory storageSlots;
// First decode the prestate root
(success, returnData) =
address(transitionEvaluator).call(
abi.encodeWithSelector(transitionEvaluator.getTransitionStateRootAndAccessList.selector, _preStateTransition)
);
address(transitionEvaluator).call(
abi.encodeWithSelector(transitionEvaluator.getTransitionStateRootAndAccessList.selector, _preStateTransition)
);
// Emit the output as an event
emit DecodedTransition(success, returnData);
// Make sure the call was successful
require(success, "If the preStateRoot is invalid, then prove that invalid instead!");
(preStateRoot, preStateStorageSlots) = abi.decode((returnData), (bytes32, uint32[2]));
// Now that we have the prestateRoot, let's decode the postState
(success, returnData) =
address(transitionEvaluator).call(
abi.encodeWithSelector(transitionEvaluator.getTransitionStateRootAndAccessList.selector, _invalidTransition)
);
address(transitionEvaluator).call(
abi.encodeWithSelector(transitionEvaluator.getTransitionStateRootAndAccessList.selector, _invalidTransition)
);
// Emit the output as an event
emit DecodedTransition(success, returnData);
// If the call was successful let's decode!
Expand Down Expand Up @@ -135,10 +136,10 @@ contract RollupChain {
/********* #2: DECODE_TRANSITIONS *********/
// Decode our transitions and determine which storage slots we'll need in order to validate the transition
(
bool success,
bytes32 preStateRoot,
bytes32 postStateRoot,
uint32[2] memory storageSlotIndexes
bool success,
bytes32 preStateRoot,
bytes32 postStateRoot,
uint32[2] memory storageSlotIndexes
) = getStateRootsAndStorageSlots(preStateTransition, invalidTransition);
// If not success something went wrong with the decoding...
if (!success) {
Expand Down Expand Up @@ -168,9 +169,9 @@ contract RollupChain {
bytes memory returnData;
// Make the external call
(success, returnData) =
address(transitionEvaluator).call(
abi.encodeWithSelector(transitionEvaluator.evaluateTransition.selector, invalidTransition, storageSlots)
);
address(transitionEvaluator).call(
abi.encodeWithSelector(transitionEvaluator.evaluateTransition.selector, invalidTransition, storageSlots)
);
// Check if it was successful. If not, we've got to prune.
if (!success) {
pruneBlocksAfter(_invalidIncludedTransition.inclusionProof.blockNumber);
Expand Down Expand Up @@ -259,8 +260,8 @@ contract RollupChain {
function getStorageBytes(dt.Storage memory _storage) public view returns(bytes memory) {
// If it's an empty storage slot, return 32 bytes of zeros (empty value)
if (_storage.pubkey == 0x0000000000000000000000000000000000000000 &&
_storage.balances[0] == 0 &&
_storage.balances[1] == 0
_storage.balances[0] == 0 &&
_storage.balances[1] == 0
) {
return abi.encodePacked(uint(0));
}
Expand Down
113 changes: 113 additions & 0 deletions packages/contracts/deploy/deploy-rollup-chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Contract, ContractFactory, Wallet, ethers } from 'ethers'
import { config } from 'dotenv'
import { resolve } from 'path'

import * as RollupChain from '../build/RollupChain.json'
import * as UnipigTransitionEvaluator from '../build/UnipigTransitionEvaluator.json'
import * as RollupMerkleUtils from '../build/RollupMerkleUtils.json'
import { Provider } from 'ethers/providers'

// Make sure an environment argument was passed
if (
!process.argv.length ||
process.argv[process.argv.length - 1].endsWith('.js')
) {
console.log(
'\n\nError: Environment argument not provided. Usage: "yarn run deploy:rollup-chain <env>"\n'
)
process.exit(0)
}

// Get the environment and read the appropriate environment file
const environment = process.argv[process.argv.length - 1]
// Note: Path is from 'build/deploy/deploy-rollup-chain.js'
config({ path: resolve(__dirname, `../../.${environment}.env`) })

const deployContract = async (
contractJson: any,
wallet: Wallet,
...args: any
): Promise<Contract> => {
const factory = new ContractFactory(
contractJson.abi,
contractJson.bytecode,
wallet
)
const contract = await factory.deploy(...args)
console.log(
`Address: [${contract.address}], Tx: [${contract.deployTransaction.hash}]`
)
return contract.deployed()
}

const deployContracts = async (wallet: Wallet): Promise<void> => {
let evaluatorContractAddress = process.env.DEPLOY_EVALUATOR_CONTRACT_ADDRESS
if (!evaluatorContractAddress) {
console.log('Deploying UnipigTransitionEvaluator...')
const transitionEvaluator = await deployContract(
UnipigTransitionEvaluator,
wallet
)
evaluatorContractAddress = transitionEvaluator.address
console.log('UnipigTransitionEvaluator deployed!\n\n')
} else {
console.log(
`Using UnipigTransitionEvaluator contract at ${evaluatorContractAddress}\n`
)
}

let merkleUtilsCnontractAddress =
process.env.DEPLOY_MERKLE_UTILS_CONTRACT_ADDRESS
if (!merkleUtilsCnontractAddress) {
console.log('Deploying RollupMerkleUtils...')
const merkleUtils = await deployContract(RollupMerkleUtils, wallet)
merkleUtilsCnontractAddress = merkleUtils.address
console.log('RollupMerkleUtils deployed!\n\n')
} else {
console.log(
`Using RollupMerkleUtils contract at ${merkleUtilsCnontractAddress}\n`
)
}

console.log('Deploying RollupChain...')
const rollupChain = await deployContract(
RollupChain,
wallet,
evaluatorContractAddress,
merkleUtilsCnontractAddress
)
console.log('RollupChain deployed!\n\n')
}

const deploy = async (): Promise<void> => {
console.log(`\n\n********** STARTING DEPLOYMENT ***********\n\n`)
// Make sure mnemonic exists
const deployMnemonic = process.env.DEPLOY_MNEMONIC
if (!deployMnemonic) {
console.log(
`Error: No DEPLOY_MNEMONIC env var set. Please add it to .<environment>.env file it and try again. See .env.example for more info.\n`
)
return
}

// Connect provider
let provider: Provider
const network = process.env.DEPLOY_NETWORK
if (!network || network === 'local') {
provider = new ethers.providers.JsonRpcProvider(
process.env.DEPLOY_LOCAL_URL || 'http://127.0.0.1:7545'
)
} else {
provider = ethers.getDefaultProvider(network)
}

// Create wallet
const wallet = Wallet.fromMnemonic(deployMnemonic).connect(provider)

console.log(`\nDeploying to network [${network || 'local'}] in 5 seconds!\n`)
setTimeout(() => {
deployContracts(wallet)
}, 5_000)
}

deploy()
8 changes: 5 additions & 3 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
"scripts": {
"test": "waffle waffle-config.json && mocha --require ts-node/register 'test/**/*.spec.ts' --timeout 5000",
"lint": "tslint --format stylish --project .",
"fix": "prettier --config ./.prettierrc.js --write 'index.ts' '{src,test}/**/*.ts'",
"fix": "prettier --config ./.prettierrc.js --write 'index.ts' '{deploy,test}/**/*.ts'",
"build": "waffle waffle-config.json && tsc -p .",
"clean": "rimraf build/"
"clean": "rimraf build/",
"deploy:rollup-chain": "rimraf build/ && waffle waffle-config.json && tsc -p . && node ./build/deploy/deploy-rollup-chain.js"
},
"keywords": [
"plasma",
Expand Down Expand Up @@ -51,6 +52,7 @@
"ethereum-waffle": "^2.0.12",
"ethers": "^4.0.37",
"merkletreejs": "^0.1.7",
"openzeppelin-solidity": "^2.2.0"
"openzeppelin-solidity": "^2.2.0",
"dotenv": "^8.1.0"
}
}
3 changes: 2 additions & 1 deletion packages/contracts/tslint.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": ["./../../tslint.json"],
"rules": {
"prettier": [true, "./.prettierrc.js"]
"prettier": [true, "./.prettierrc.js"],
"no-console": false
}
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3361,6 +3361,11 @@ dot-prop@^4.2.0:
dependencies:
is-obj "^1.0.0"

dotenv@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.1.0.tgz#d811e178652bfb8a1e593c6dd704ec7e90d85ea2"
integrity sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==

drbg.js@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b"
Expand Down

0 comments on commit f9a6158

Please sign in to comment.