Merge branch 'develop'
This commit is contained in:
commit
87a8fc7eab
|
@ -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']
|
||||
|
|
81
README.md
81
README.md
|
@ -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,6 +176,26 @@ 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
|
||||
======
|
||||
|
||||
|
@ -180,7 +205,15 @@ 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
|
||||
```
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
chains/development.json
|
|
@ -33,6 +33,7 @@ module.exports = (grunt) ->
|
|||
contracts:
|
||||
src: [
|
||||
"app/contracts/**/*.sol"
|
||||
"app/contracts/**/*.se"
|
||||
]
|
||||
|
||||
coffee:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -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"
|
||||
|
|
146
js/mine.js
146
js/mine.js
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
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();
|
||||
})();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++) {
|
||||
|
|
16
lib/index.js
16
lib/index.js
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 ");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
development:
|
||||
SimpleStorage:
|
||||
deploy: false
|
||||
args:
|
||||
- 100
|
||||
BarStorage:
|
||||
|
|
Loading…
Reference in New Issue