Merge branch 'develop'

This commit is contained in:
Iuri Matias 2015-09-05 07:47:58 -04:00
commit 87a8fc7eab
29 changed files with 538 additions and 62 deletions

View File

@ -23,7 +23,7 @@ module.exports = (grunt) ->
src: ['test/**/*.js']
grunt.loadTasks "tasks"
require('matchdep').filterAll('grunt-*').forEach(grunt.loadNpmTasks)
require('matchdep').filterAll(['grunt-*','!grunt-cli']).forEach(grunt.loadNpmTasks)
grunt.registerTask 'default', ['clean']
grunt.registerTask 'build', ['clean', 'coffee']

View File

@ -7,15 +7,17 @@ Embark is a framework that allows you to easily develop and deploy DApps.
With Embark you can:
* Automatically deploy contracts and make them available in your JS code. Embark watches for changes, and if you update a contract, Embark will automatically redeploy the contracts (if needed) and the dapp.
* Use any build pipeline or tool you wish, including grunt and meteor.
* Do Test Driven Development with Contracts using Javascript.
* Easily deploy to & use decentralized systems such as IPFS.
* Keep track of deployed contracts, deploy only when truly needed.
* Quickly create advanced DApps using multiple contracts.
See the [Wiki](https://github.com/iurimatias/embark-framework/wiki) for more details.
Installation
======
Requirements: geth (1.0.0), solc (0.9.23), node (0.12.2) and npm
Requirements: geth (1.0.0), solc (0.1.0) or serpent (develop), node (0.12.2) and npm
For specs: pyethereum, ethertdd.py
@ -49,6 +51,8 @@ This will automatically deploy the contracts, update their JS bindings and deplo
Note that if you update your code it will automatically be re-deployed, contracts included. There is no need to restart embark, refreshing the page on the browser will do.
note: for a demo using meteor do ```embark meteor_demo``` followed by ```embark deploy``` then ```meteor```
Creating a new DApp
======
@ -62,7 +66,7 @@ DApp Structure
```Bash
app/
|___ contracts/ #solidity contracts
|___ contracts/ #solidity or serpent contracts
|___ html/
|___ css/
|___ js/
@ -74,7 +78,7 @@ DApp Structure
|___ contracts/ #contracts tests
```
Solidity files in the contracts directory will automatically be deployed with embark run. Changes in any files will automatically be reflected in app, changes to contracts will result in a redeployment and update of their JS Bindings
Solidity/Serpent files in the contracts directory will automatically be deployed with embark run. Changes in any files will automatically be reflected in app, changes to contracts will result in a redeployment and update of their JS Bindings
Using Contracts
======
@ -145,6 +149,7 @@ You can now deploy many instances of the same contract. e.g
# config/contracts.yml
development:
Currency:
deploy: false
args:
- 100
Usd:
@ -171,16 +176,44 @@ Contracts addresses can be defined, If an address is defined the contract wouldn
...
```
You can also define contract interfaces (Stubs) and actions to do on deployment
```Yaml
development:
DataSource:
args:
MyDataSource:
args:
instanceOf: DataSource
Manager:
stubs:
- DataSource
args:
- $MyDataSource
onDeploy:
- Manager.updateStorage($MyDataSource)
- MyDataSource.set(5)
...
```
Tests
======
You can run specs with ```embark spec```, it will run any files ending *_spec.js under ```spec/```.
Embark includes a testing lib to fastly run & test your contracts in a EVM.
Embark includes a testing lib to fastly run & test your contracts in a EVM.
```Javascript
# spec/contracts/simple_storage_spec.js
EmbarkSpec = require('embark-framework').Tests;
Embark = require('embark-framework');
Embark.init();
Embark.blockchainConfig.loadConfigFile('config/blockchain.yml');
Embark.contractsConfig.loadConfigFile('config/contracts.yml');
var files = ['app/contracts/simpleStorage.sol'];
Embark.contractsConfig.init(files, 'development');
var EmbarkSpec = Embark.tests(files);
describe("SimpleStorage", function() {
beforeAll(function() {
@ -222,6 +255,7 @@ The environment is a specific blockchain configuration that can be managed at co
rpc_port: 8101
rpc_whitelist: "*"
datadir: default
chains: chains_staging.json
network_id: 0
console: true
account:
@ -231,7 +265,6 @@ The environment is a specific blockchain configuration that can be managed at co
See [Configuration](https://github.com/iurimatias/embark-framework/wiki/Configuration).
Deploying only contracts
======
Although embark run will automatically deploy contracts, you can choose to only deploy the contracts to a specific environment
@ -242,6 +275,26 @@ $ embark deploy privatenet
embark deploy will deploy all contracts at app/contracts and return the resulting addresses
Structuring Application
======
Embark is quite flexible and you can configure you're own directory structure using ```embark.yml```
```Yaml
# embark.yml
type: "manual" #other options: meteor, grunt
contracts: ["app/contracts/**/*.sol", "app/contracts/**/*.se"] # contracts files
output: "src/embark.js" # resulting javascript interface
blockchainConfig: "config/blockchain.yml" # blockchain config
contractsConfig: "config/contracts.yml" # contracts config
```
Deploying to IPFS
======
To deploy a dapp to IPFS, all you need to do is run a local IPFS node and then run ```embark ipfs```.
If you want to deploy to the live net then after configuring you account on ```config/blockchain.yml``` on the ```production``` environment then you can deploy to that chain by specifying the environment ```embark ipfs production```.
LiveReload Plugin
======
@ -255,5 +308,19 @@ Because embark is internally using grunt tasks, debugging is not straightforward
- normally you would write something like `node-debug -p 7000 embark -- deploy`
- This gives you nothing with embark. If you look at `deploy` command in [`./bin/embark`](https://github.com/iurimatias/embark-framework/blob/develop/bin/embark#L32-L35) you will notice that it internally runs grunt task `grunt deploy_contracts:[env]`
- with this knowledge we can prepare proper command to start debugging
- `node-debug -p 7000 grunt -- deploy_contracts:development`
- [here](https://github.com/iurimatias/embark-framework/blob/develop/tasks/tasks.coffee) is list of all debuggable grunt tasks
- ```node-debug -p 7000 grunt -- deploy_contracts:development```
[here](https://github.com/iurimatias/embark-framework/blob/develop/tasks/tasks.coffee) is list of all debuggable grunt tasks
EACCESS Error
======
If you get EACCES (access denied) errors, don't use sudo, try this:
```Bash
$ mkdir ~/npm-global
$ npm config set prefix ~/npm-global
$ echo 'export PATH="$PATH:$HOME/npm-global/bin"' >>~/.bashrc
$ source ~/.bashrc
$ npm install -g embark-framework grunt-cli
```

25
bin/embark Normal file → Executable file
View File

@ -6,7 +6,7 @@ var wrench = require('wrench');
var grunt = require('grunt');
require('shelljs/global');
var readYaml = require('read-yaml');
var Embark = require('embark-framework');
var Embark = require('..');
var run = function(cmd) {
if (exec(cmd).code != 0) {
@ -17,22 +17,19 @@ var run = function(cmd) {
var deploy = function(env, embarkConfig) {
var contractFiles = grunt.file.expand(embarkConfig.contracts);
var destFile = embarkConfig.output;
var chainFile = embarkConfig.chains;
Embark.init();
Embark.blockchainConfig.loadConfigFile(embarkConfig.blockchainConfig);
Embark.contractsConfig.loadConfigFile(embarkConfig.contractsConfig);
if (chainFile === undefined) {
chainFile = './chains.json';
}
var chainFile = Embark.blockchainConfig.blockchainConfig[env].chains || embarkConfig.chains || './chains.json';
abi = Embark.deployContracts(env, contractFiles, destFile, chainFile);
grunt.file.write(destFile, abi);
}
program
.version('0.8.4')
.version('0.9.1')
program.command('new [name]').description('New application').action(function(name) {
if (name === undefined) {
@ -132,13 +129,24 @@ program.command('blockchain [env]').description('run blockchain').action(functio
Embark.blockchainConfig.loadConfigFile(embarkConfig.blockchainConfig)
Embark.contractsConfig.loadConfigFile(embarkConfig.contractsConfig)
//TODO: better with --exec, but need to fix console bug first
wrench.copyDirSyncRecursive(__dirname + "/../js", "/tmp/js", {forceDelete: true});
Embark.copyMinerJavascriptToTemp();
Embark.startBlockchain(env, true);
}
});
program.command('geth <env> [args...]').description('run geth with specified arguments').action(function(env_, args_) {
var env = env_ || 'development';
var embarkConfig = readYaml.sync("./embark.yml");
var args = args_.join(' ');
Embark.init()
Embark.blockchainConfig.loadConfigFile(embarkConfig.blockchainConfig)
Embark.contractsConfig.loadConfigFile(embarkConfig.contractsConfig)
Embark.geth(env, args);
});
program.command('demo').description('create a working dapp with a SimpleStorage contract').action(function() {
var boilerPath = path.join(__dirname + '/../boilerplate');
var demoPath = path.join(__dirname + '/../demo');
@ -169,4 +177,3 @@ if (!process.argv.slice(2).length) {
}
exit();

2
boilerplate/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules/
chains/development.json

View File

@ -33,6 +33,7 @@ module.exports = (grunt) ->
contracts:
src: [
"app/contracts/**/*.sol"
"app/contracts/**/*.se"
]
coffee:

View File

@ -5,6 +5,7 @@ development:
minerthreads: 1
genesis_block: config/genesis/dev_genesis.json
datadir: /tmp/embark
chains: config/chains/development.json
mine_when_needed: true
max_peers: 0
gas_limit: 500000

View File

@ -0,0 +1 @@
{}

View File

@ -1,10 +1,11 @@
{
"nonce": "0x0000000000000042",
"difficulty": "0x40000",
"difficulty": "0x0",
"alloc": {
"0x3333333333333333333333333333333333333333": {"balance": "15000000000000000000"}
},
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"coinbase": "0x3333333333333333333333333333333333333333",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",

View File

@ -1,5 +1,5 @@
type: "grunt" #other options: meteor, manual
#contracts: ["app/contracts/**/*.sol"]
#contracts: ["app/contracts/**/*.sol", "app/contracts/**/*.se"]
#output: "src/embark.js"
#blockchainConfig: "config/blockchain.yml"
#contractsConfig: "config/contracts.yml"

View File

@ -10,8 +10,8 @@
"license": "ISC",
"homepage": "",
"devDependencies": {
"embark-framework": "^0.8.4",
"grunt-embark": "^0.3.0",
"embark-framework": "^0.9.1",
"grunt-embark": "^0.4.1",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-coffee": "^0.13.0",
"grunt-contrib-concat": "^0.5.1",

View File

@ -5,6 +5,7 @@ development:
minerthreads: 1
genesis_block: config/genesis/dev_genesis.json
datadir: /tmp/embark
chains: config/chains/development.json
mine_when_needed: true
gas_limit: 500000
gas_price: 10000000000000

View File

@ -0,0 +1 @@
{}

View File

@ -1,5 +1,5 @@
type: "meteor"
contracts: ["contracts/**/*.sol"]
contracts: ["contracts/**/*.sol", "contracts/**/*.se"]
output: "client/embark.js"
blockchainConfig: "config/blockchain.yml"
contractsConfig: "config/contracts.yml"

View File

@ -1,16 +1,75 @@
var miner_var;
// Adapted from Iuri Matias' Embark framework
// https://github.com/iurimatias/embark-framework
// Modified by ryepdx to mine at regular intervals.
(function() {
var main = function () {
/* TODO: Find a way to load mining config from YML.
if (admin.miner === undefined) {
miner_var = miner;
}
else {
miner_var = admin.miner;
}
if (!loadScript("config.js")) {
console.log("== config.js not found");
}
miner_var.setEtherbase(web3.eth.accounts[0]);
if (typeof(config) === "undefined") {
config = {};
console.log("== config is undefined, proceeding with defaults");
}
In the meantime, just set an empty config object.
*/
config = {}
defaults = {
interval_ms: 15000,
initial_ether: 15000000000000000000,
mine_pending_txns: true,
mine_periodically: false,
mine_normally: false,
threads: 1
}
for (key in defaults) {
if (config[key] === undefined) {
config[key] = defaults[key];
}
}
var miner_obj = (admin.miner === undefined) ? miner : admin.miner;
if (config.mine_normally) {
miner_obj.start(config.threads);
return;
}
miner_obj.stop();
fundAccount(config, miner_obj, function () {
if (config.mine_periodically) start_periodic_mining(config, miner_obj);
if (config.mine_pending_txns) start_transaction_mining(config, miner_obj);
});
};
var fundAccount = function (config, miner_obj, cb) {
var accountFunded = function () {
return (eth.getBalance(eth.coinbase) >= config.initial_ether);
}
if (accountFunded()) {
return cb();
}
console.log("== Funding account");
miner_obj.start();
var blockWatcher = web3.eth.filter("latest").watch(function () {
if (accountFunded()) {
console.log("== Account funded");
blockWatcher.stopWatching();
miner_obj.stop();
cb();
}
});
};
setInterval(function() {
var minimalAmount = (web3.eth.getBalance(web3.eth.coinbase) >= 15000000000000000000);
var pendingTransactions = function() {
if (web3.eth.pendingTransactions === undefined || web3.eth.pendingTransactions === null) {
return txpool.status.pending || txpool.status.queued;
@ -21,19 +80,60 @@ setInterval(function() {
else {
return web3.eth.pendingTransactions.length > 0 || web3.eth.getBlock('pending').transactions.length > 0;
}
}
};
if(!web3.eth.mining && (!minimalAmount || pendingTransactions())) {
if (!minimalAmount) { console.log("=== minimal ether amount not reached yet") }
if (pendingTransactions()) { console.log("=== there are pending transactions") }
console.log("=== start mining");
miner_var.start();
}
else if (web3.eth.mining && minimalAmount && !pendingTransactions()) {
if (minimalAmount) { console.log("=== minimal ether amount reached") }
if (!pendingTransactions()) { console.log("=== no pending transactions") }
console.log("=== stop mining");
miner_var.stop();
}
}, 1000)
var start_periodic_mining = function (config, miner_obj) {
var last_mined_ms = Date.now();
var timeout_set = false;
miner_obj.start(config.threads);
web3.eth.filter("latest").watch(function () {
if ((config.mine_pending_txns && pendingTransactions()) || timeout_set) {
return;
}
timeout_set = true;
var now = Date.now();
var ms_since_block = now - last_mined_ms;
last_mined_ms = now;
var next_block_in_ms;
if (ms_since_block > config.interval_ms) {
next_block_in_ms = 0;
} else {
next_block_in_ms = (config.interval_ms - ms_since_block);
}
miner_obj.stop();
console.log("== Looking for next block in " + next_block_in_ms + "ms");
setTimeout(function () {
console.log("== Looking for next block");
timeout_set = false;
miner_obj.start(config.threads);
}, next_block_in_ms);
});
};
var start_transaction_mining = function (config, miner_obj) {
web3.eth.filter("pending").watch(function () {
if (miner_obj.hashrate > 0) return;
console.log("== Pending transactions! Looking for next block...");
miner_obj.start(config.threads);
});
if (config.mine_periodically) return;
web3.eth.filter("latest").watch(function () {
if (!pendingTransactions()) {
console.log("== No transactions left. Stopping miner...");
miner_obj.stop();
}
});
};
main();
})();

View File

@ -9,6 +9,7 @@ Blockchain.prototype.generate_basic_command = function() {
var address = config.account.address;
var cmd = "geth ";
var rpc_api = ['eth', 'web3'];
if (config.datadir !== "default") {
cmd += "--datadir=\"" + config.datadir + "\" ";
@ -31,6 +32,13 @@ Blockchain.prototype.generate_basic_command = function() {
cmd += "--genesis=\"" + config.genesisBlock + "\" ";
}
if (config.whisper) {
cmd += "--shh ";
rpc_api.push('shh')
}
cmd += '--rpcapi "' + rpc_api.join(',') + '" ';
//TODO: this should be configurable
cmd += "--maxpeers " + config.maxPeers + " ";
@ -49,6 +57,10 @@ Blockchain.prototype.init_command = function() {
return this.generate_basic_command() + "account new ";
}
Blockchain.prototype.geth_command = function(geth_args) {
return this.generate_basic_command() + geth_args;
}
Blockchain.prototype.run_command = function(address, use_tmp) {
var cmd = this.generate_basic_command();
var config = this.config;
@ -108,4 +120,15 @@ Blockchain.prototype.startChain = function(use_tmp) {
exec(this.run_command(address, use_tmp));
}
Blockchain.prototype.execGeth = function(args) {
var cmd = this.geth_command(args);
console.log("executing: " + cmd);
exec(cmd);
}
Blockchain.prototype.getStartChainCommand = function(use_tmp) {
var address = this.get_address();
return this.run_command(address, use_tmp);
}
module.exports = Blockchain

View File

@ -6,6 +6,7 @@ ChainManager = function() {
this.chainManagerConfig = {};
this.currentChain = {};
this.file = "";
this.web3 = null;
}
ChainManager.prototype.loadConfigFile = function(filename) {
@ -34,6 +35,7 @@ ChainManager.prototype.init = function(env, config) {
}
this.currentChain = this.chainManagerConfig[chainId];
this.web3 = web3;
}
ChainManager.prototype.addContract = function(contractName, code, args, address) {

View File

@ -1,3 +1,5 @@
var shelljs = require('shelljs');
var shelljs_global = require('shelljs/global');
var web3 = require('web3');
Compiler = function(blockchainConfig) {
@ -18,8 +20,85 @@ Compiler.prototype.init = function(env) {
console.log("address is : " + primaryAddress);
};
Compiler.prototype.compile = function(source) {
return web3.eth.compile.solidity(source);
Compiler.prototype.compile_solidity = function(contractFile) {
var cmd, result, output, json, compiled_object;
cmd = "solc --input-file " + contractFile + " --combined-json binary,json-abi";
result = exec(cmd, {silent: true});
output = result.output;
if (result.code === 1) {
throw new Error(result.output);
}
json = JSON.parse(output).contracts;
compiled_object = {}
for (var className in json) {
var contract = json[className];
compiled_object[className] = {};
compiled_object[className].code = contract.binary;
compiled_object[className].info = {};
compiled_object[className].info.abiDefinition = JSON.parse(contract["json-abi"]);
}
return compiled_object;
}
Compiler.prototype.compile_serpent = function(contractFile) {
var cmd, result, output, json, compiled_object;
cmd = "serpent compile " + contractFile;
result = exec(cmd, {silent: true});
code = result.output;
if (result.code === 1) {
throw new Error(result.output);
}
cmd = "serpent mk_full_signature " + contractFile;
result = exec(cmd, {silent: true});
if (result.code === 1) {
throw new Error(result.output);
}
json = JSON.parse(result.output.trim());
className = contractFile.split('.')[0].split("/").pop();
for (var i=0; i < json.length; i++) {
var elem = json[i];
if (elem.outputs.length > 0) {
elem.constant = true;
}
}
compiled_object = {}
compiled_object[className] = {};
compiled_object[className].code = code.trim();
compiled_object[className].info = {};
compiled_object[className].info.abiDefinition = json;
return compiled_object;
}
Compiler.prototype.compile = function(contractFile) {
var extension = contractFile.split('.')[1];
if (extension === 'sol') {
return this.compile_solidity(contractFile);
}
else if (extension === 'se') {
return this.compile_serpent(contractFile);
}
else {
throw new Error("extension not known");
}
};
module.exports = Compiler;

View File

@ -40,11 +40,13 @@ BlockchainConfig.prototype.config = function(env) {
minerthreads: config.minerthreads,
genesisBlock: config.genesis_block,
datadir: config.datadir,
chains: config.chains,
networkId: networkId,
maxPeers: 4,
port: config.port || "30303",
console_toggle: config.console || false,
mine_when_needed: config.mine_when_needed || false,
whisper: config.whisper || false,
account: config.account
}

View File

@ -79,9 +79,8 @@ ContractsConfig.prototype.compileContracts = function(env) {
// compile files
for (j = 0; j < this.contractFiles.length; j++) {
contractFile = this.contractFiles[j];
source = fs.readFileSync(contractFile).toString()
compiled_contracts = this.compiler.compile(source);
compiled_contracts = this.compiler.compile(contractFile);
for (var className in compiled_contracts) {
var contract = compiled_contracts[className];
@ -133,6 +132,11 @@ ContractsConfig.prototype.compileContracts = function(env) {
contract.types.push('static');
}
contract.deploy = contractConfig.deploy;
if (contractConfig.deploy === undefined) {
contract.deploy = true;
}
if (this.all_contracts.indexOf(className) < 0) {
this.all_contracts.push(className);
}

View File

@ -58,6 +58,11 @@ Deploy.prototype.deploy_contracts = function(env) {
className = all_contracts[k];
contract = this.contractDB[className];
if (contract.deploy === false) {
console.log("skipping " + className);
continue;
}
var realArgs = [];
for (var l = 0; l < contract.args.length; l++) {
arg = contract.args[l];
@ -77,7 +82,7 @@ Deploy.prototype.deploy_contracts = function(env) {
else {
var chainContract = this.chainManager.getContract(className, contract.compiled.code, realArgs);
if (chainContract != undefined) {
if (chainContract != undefined && web3.eth.getCode(chainContract.address) !== "0x") {
console.log("contract " + className + " is unchanged and already deployed at " + chainContract.address);
this.deployedContracts[className] = chainContract.address;
this.execute_cmds(contract.onDeploy);
@ -110,13 +115,12 @@ Deploy.prototype.deploy_contracts = function(env) {
}
else {
console.log("deployed " + className + " at " + contractAddress);
this.chainManager.addContract(className, contract.compiled.code, realArgs, contractAddress);
this.chainManager.save();
}
this.deployedContracts[className] = contractAddress;
this.chainManager.addContract(className, contract.compiled.code, realArgs, contractAddress);
this.chainManager.save();
console.log("deployed " + className + " at " + contractAddress);
this.execute_cmds(contract.onDeploy);
}
}
@ -125,7 +129,7 @@ Deploy.prototype.deploy_contracts = function(env) {
};
Deploy.prototype.execute_cmds = function(cmds) {
if (cmds.length === 0) return;
if (cmds == undefined || cmds.length === 0) return;
eval(this.generate_abi_file());
for (var i = 0; i < cmds.length; i++) {

View File

@ -35,6 +35,16 @@ Embark = {
chain.startChain(use_tmp);
},
copyMinerJavascriptToTemp: function(){
//TODO: better with --exec, but need to fix console bug first
wrench.copyDirSyncRecursive(__dirname + "/../js", "/tmp/js", {forceDelete: true});
},
getStartBlockchainCommand: function(env, use_tmp) {
var chain = new Blockchain(this.blockchainConfig.config(env));
return chain.getStartChainCommand(use_tmp);
},
deployContracts: function(env, contractFiles, destFile, chainFile) {
this.contractsConfig.init(contractFiles, env);
@ -44,8 +54,12 @@ Embark = {
return deploy.generate_abi_file(destFile);
},
geth: function(env, args) {
var chain = new Blockchain(this.blockchainConfig.config(env));
chain.execGeth(args);
},
release: Release
}
module.exports = Embark;

View File

@ -1,6 +1,6 @@
{
"name": "embark-framework",
"version": "0.8.4",
"version": "0.9.1",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"

View File

@ -10,7 +10,7 @@ describe('embark.blockchain', function() {
var blockchain = new Blockchain(blockchainConfig);
it('should return correct cmd', function() {
assert.strictEqual(blockchain.generate_basic_command(), "geth --datadir=\"/tmp/embark\" --logfile=\"/tmp/embark.log\" --port 30303 --rpc --rpcport 8101 --networkid "+blockchainConfig.networkId+" --rpccorsdomain \"*\" --minerthreads \"1\" --mine --genesis=\"config/genesis.json\" --maxpeers 4 --password config/password ");
assert.strictEqual(blockchain.generate_basic_command(), "geth --datadir=\"/tmp/embark\" --logfile=\"/tmp/embark.log\" --port 30303 --rpc --rpcport 8101 --rpcaddr localhost --networkid "+blockchainConfig.networkId+" --rpccorsdomain \"*\" --minerthreads \"1\" --mine --genesis=\"config/genesis.json\" --rpcapi \"eth,web3\" --maxpeers 4 --password config/password ");
});
});

69
test/compiler.js Normal file
View File

@ -0,0 +1,69 @@
var Compiler = require('../lib/compiler.js');
var assert = require('assert');
describe('embark.compiler', function() {
describe('compile a file', function() {
var files = [
'test/support/contracts/simple_storage.sol'
];
it("should build a correct compiled object", function() {
var compiler = new Compiler();
var compiledFile = compiler.compile(files[0]);
assert.equal(compiledFile.SimpleStorage.code, '606060405260405160208060f78339016040526060805190602001505b806000600050819055505b5060c28060356000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd914604b57806360fe47b114606a5780636d4ce63c14607b576049565b005b605460045060b9565b6040518082815260200191505060405180910390f35b6079600480359060200150609a565b005b608460045060a8565b6040518082815260200191505060405180910390f35b806000600050819055505b50565b6000600060005054905060b6565b90565b6000600050548156');
assert.equal(JSON.stringify(compiledFile.SimpleStorage.info.abiDefinition), '[{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}]');
});
});
describe('compile a file with an error', function() {
var files = [
'test/support/contracts/error.sol'
];
it("throw an error", function() {
var compiler = new Compiler();
assert.throws(function() { compiler.compile(files[0]) }, Error);
});
});
describe('compile a serpent file', function() {
var files = [
'test/support/contracts/cash.se'
];
it("should build a correct compiled object", function() {
var compiler = new Compiler();
var compiledFile = compiler.compile(files[0]);
assert.equal(compiledFile.cash.code, '6000603f536a0186a000000000000000006040604059905901600090526000815232816020015280905020556103658061003a60003961039f56600061047f537c010000000000000000000000000000000000000000000000000000000060003504638357984f81141561005f57600435604052604060405990590160009052600081526040518160200152809050205460605260206060f35b63693200ce8114156101465760043560a05260243560c0523260e0526040604059905901600090526000815260e051816020015280905020546101005260c051610100511215156101385760c0516040604059905901600090526000815260e05181602001528090502054036040604059905901600090526000815260e0518160200152809050205560c0516040604059905901600090526000815260a05181602001528090502054016040604059905901600090526000815260a0518160200152809050205560c0516101c05260206101c0f3610145565b60006101e05260206101e0f35b5b6380b97fc081141561024c5760043560a05260243560c05260443561020052326102005114151561017e576000610220526020610220f35b6040604059905901600090526000815261020051816020015280905020546101005260c0516101005112151561023e5760c0516040604059905901600090526000815261020051816020015280905020540360406040599059016000905260008152610200518160200152809050205560c0516040604059905901600090526000815260a05181602001528090502054016040604059905901600090526000815260a0518160200152809050205560c0516102e05260206102e0f361024b565b6000610300526020610300f35b5b634c764abc8114156102b4576004356103205260243561034052610340516040604059905901600090526000815261032051816020015280905020540360406040599059016000905260008152610320518160200152809050205560016103a05260206103a0f35b63a92c9b8381141561031c57600435610320526024356103405261034051604060405990590160009052600081526103205181602001528090502054016040604059905901600090526000815261032051816020015280905020556001610400526020610400f35b631d62e92281141561036357600435604052602435610420526104205160406040599059016000905260008152604051816020015280905020556001610460526020610460f35b505b6000f3');
assert.equal(JSON.stringify(compiledFile.cash.info.abiDefinition), '[{\"name\":\"addCash(int256,int256)\",\"type\":\"function\",\"inputs\":[{\"name\":\"ID\",\"type\":\"int256\"},{\"name\":\"amount\",\"type\":\"int256\"}],\"outputs\":[{\"name\":\"out\",\"type\":\"int256\"}],\"constant\":true},{\"name\":\"balance(int256)\",\"type\":\"function\",\"inputs\":[{\"name\":\"address\",\"type\":\"int256\"}],\"outputs\":[{\"name\":\"out\",\"type\":\"int256\"}],\"constant\":true},{\"name\":\"send(int256,int256)\",\"type\":\"function\",\"inputs\":[{\"name\":\"recver\",\"type\":\"int256\"},{\"name\":\"value\",\"type\":\"int256\"}],\"outputs\":[{\"name\":\"out\",\"type\":\"int256\"}],\"constant\":true},{\"name\":\"sendFrom(int256,int256,int256)\",\"type\":\"function\",\"inputs\":[{\"name\":\"recver\",\"type\":\"int256\"},{\"name\":\"value\",\"type\":\"int256\"},{\"name\":\"from\",\"type\":\"int256\"}],\"outputs\":[{\"name\":\"out\",\"type\":\"int256\"}],\"constant\":true},{\"name\":\"setCash(int256,int256)\",\"type\":\"function\",\"inputs\":[{\"name\":\"address\",\"type\":\"int256\"},{\"name\":\"balance\",\"type\":\"int256\"}],\"outputs\":[{\"name\":\"out\",\"type\":\"int256\"}],\"constant\":true},{\"name\":\"subtractCash(int256,int256)\",\"type\":\"function\",\"inputs\":[{\"name\":\"ID\",\"type\":\"int256\"},{\"name\":\"amount\",\"type\":\"int256\"}],\"outputs\":[{\"name\":\"out\",\"type\":\"int256\"}],\"constant\":true}]');
});
});
describe('compile a file with an error', function() {
var files = [
'test/support/contracts/error.sol'
];
it("throw an error", function() {
var compiler = new Compiler();
assert.throws(function() { compiler.compile(files[0]) }, Error);
});
});
});

View File

@ -43,6 +43,7 @@ describe('embark.config.blockchain', function() {
minerthreads: 1,
genesis_block: 'config/genesis.json',
datadir: '/tmp/embark',
chains: 'chains_development.json',
mine_when_needed: true,
gas_limit: 123,
gas_price: 100,
@ -63,9 +64,11 @@ describe('embark.config.blockchain', function() {
gasLimit: 123,
gasPrice: 100,
rpcWhitelist: "*",
whisper: false,
minerthreads: 1,
genesisBlock: 'config/genesis.json',
datadir: '/tmp/embark',
chains: 'chains_development.json',
networkId: 0,
maxPeers: 4,
port: "30303",
@ -87,12 +90,13 @@ describe('embark.config.blockchain', function() {
network_id: 0,
minerthreads: 1,
datadir: '/tmp/embark',
chains: undefined,
mine_when_needed: true,
console: false,
account: {
init: true,
password: 'config/password'
}
},
},
staging: {}
};
@ -105,9 +109,11 @@ describe('embark.config.blockchain', function() {
gasLimit: 500000,
gasPrice: 10000000000000,
rpcWhitelist: "*",
whisper: false,
minerthreads: 1,
genesisBlock: undefined,
datadir: '/tmp/embark',
chains: undefined,
networkId: 0,
maxPeers: 4,
port: "30303",

View File

@ -110,12 +110,13 @@ describe('embark.deploy', function() {
deploy.deploy_contracts("development");
it("should deploy contracts", function() {
var all_contracts = ['SimpleStorage', 'BarStorage', 'FooStorage'];
var all_contracts = ['BarStorage', 'FooStorage'];
for(var i=0; i < all_contracts.length; i++) {
var className = all_contracts[i];
assert.equal(deploy.deployedContracts.hasOwnProperty(className), true);
}
assert.notEqual(deploy.deployedContracts.hasOwnProperty('SimpleStorage'), true);
});
});

View File

@ -0,0 +1,75 @@
# This software (Augur) allows buying && selling event outcomes in ethereum
# Copyright (C) 2015 Forecast Foundation
# This program is free software; you can redistribute it &&/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is free software: you can redistribute it &&/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Any questions please contact joey@augur.net
data cashcoinBalances[]
def init():
# test initial funds
self.cashcoinBalances[tx.origin] = 100000*2^64
# @return: cash balance of address
def balance(address):
return(self.cashcoinBalances[address])
# should send values as fixed point in UI (1 is 2^64, 4 is 4*2^64, .5 is 2^63, etc.)
# so cashcoin fees could just go to root branch, or we could not have fees besides
# gas fee to do a send transaction
# @return: value sent, 0 if fails
def send(recver, value):
sender = tx.origin
senderBalance = self.cashcoinBalances[sender]
if(senderBalance >= value):
self.cashcoinBalances[sender] -= value
self.cashcoinBalances[recver] += value
return(value)
else:
return(0)
# @return value of cash sent; fail is 0
def sendFrom(recver, value, from):
if(from!=tx.origin):
return(0)
senderBalance = self.cashcoinBalances[from]
if(senderBalance >= value):
self.cashcoinBalances[from] -= value
self.cashcoinBalances[recver] += value
return(value)
else:
return(0)
# make sure only coming from specific contracts
def subtractCash(ID, amount):
#if(!self.whitelist.check(msg.sender)):
# return(-1)
self.cashcoinBalances[ID] -= amount
return(1)
def addCash(ID, amount):
#if(!self.whitelist.check(msg.sender)):
# return(-1)
self.cashcoinBalances[ID] += amount
return(1)
def setCash(address, balance):
#if !self.whitelist.check(msg.sender):
# return(-1)
self.cashcoinBalances[address] = balance
return(1)

View File

@ -0,0 +1,14 @@
contract SimpleStorage {
uint public storedData;
function SimpleStorage(uint initialValue) {
storedData2 = initialValue;
}
function set(uint x) {
storedData = x;
}
function get() constant returns (uint retVal) {
return storedData;
}
}

View File

@ -1,5 +1,6 @@
development:
SimpleStorage:
deploy: false
args:
- 100
BarStorage: