refactor: determine contract dependencies + add specs

This commit is contained in:
Iuri Matias 2015-07-01 19:49:49 -04:00
parent 4499fc6c13
commit de9dff3397
7 changed files with 98 additions and 42 deletions

View File

@ -1,12 +1,15 @@
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
var readYaml = require('read-yaml'); var readYaml = require('read-yaml');
var fs = require('fs'); var fs = require('fs');
var Blockchain = require('./blockchain.js'); var Blockchain = require('./blockchain.js');
var toposort = require('toposort');
ContractsConfig = function(files, blockchainConfig, web3) { ContractsConfig = function(files, blockchainConfig, web3) {
this.all_contracts = []; this.all_contracts = [];
this.contractDB = {}; this.contractDB = {};
this.contractFiles = files; this.contractFiles = files;
this.web3 = web3; this.web3 = web3;
this.contractDependencies = {};
try { try {
this.web3.setProvider(new this.web3.providers.HttpProvider("http://" + blockchainConfig.rpcHost + ":" + blockchainConfig.rpcPort)); this.web3.setProvider(new this.web3.providers.HttpProvider("http://" + blockchainConfig.rpcHost + ":" + blockchainConfig.rpcPort));
@ -38,8 +41,27 @@ ContractsConfig.prototype.config = function(env) {
return this.contractConfig[env]; return this.contractConfig[env];
} }
ContractsConfig.prototype.compileContracts = function() { ContractsConfig.prototype.compileContracts = function(env) {
var contractFile, source, j; var contractFile, source, j;
var contractsConfig = this.config(env);
if (contractsConfig != null) {
for (className in contractsConfig) {
options = contractsConfig[className];
if (options.args == null) continue;
ref = options.args;
for (j = 0; j < ref.length; j++) {
arg = ref[j];
if (arg[0] === "$") {
if (this.contractDependencies[className] === void 0) {
this.contractDependencies[className] = [];
}
this.contractDependencies[className].push(arg.substr(1));
}
}
}
}
for (j = 0; j < this.contractFiles.length; j++) { for (j = 0; j < this.contractFiles.length; j++) {
contractFile = this.contractFiles[j]; contractFile = this.contractFiles[j];
@ -53,6 +75,27 @@ ContractsConfig.prototype.compileContracts = function() {
this.contractDB[className] = contract; this.contractDB[className] = contract;
} }
} }
this.sortContracts();
}
ContractsConfig.prototype.sortContracts = function() {
var converted_dependencies = [], i;
for(contract in this.contractDependencies) {
var dependencies = this.contractDependencies[contract];
for(i=0; i < dependencies.length; i++) {
converted_dependencies.push([contract, dependencies[i]]);
}
}
var orderedDependencies = toposort(converted_dependencies).reverse();
this.all_contracts = this.all_contracts.sort(function(a,b) {
var order_a = orderedDependencies.indexOf(a);
var order_b = orderedDependencies.indexOf(b);
return order_a - order_b;
});;
} }
module.exports = ContractsConfig module.exports = ContractsConfig

View File

@ -27,48 +27,10 @@ deployContracts = function(env, contractFiles, destFile) {
result = "web3.setProvider(new web3.providers.HttpProvider('http://" + blockchainConfig.rpcHost + ":" + blockchainConfig.rpcPort + "'));"; result = "web3.setProvider(new web3.providers.HttpProvider('http://" + blockchainConfig.rpcHost + ":" + blockchainConfig.rpcPort + "'));";
result += "web3.eth.defaultAccount = web3.eth.accounts[0];"; result += "web3.eth.defaultAccount = web3.eth.accounts[0];";
contractDependencies = {}; contractsManager.compileContracts(env);
if (contractsConfig != null) {
for (className in contractsConfig) {
options = contractsConfig[className];
if (options.args == null) {
continue;
}
ref = options.args;
for (i = 0, len = ref.length; i < len; i++) {
arg = ref[i];
if (arg[0] === "$") {
if (contractDependencies[className] === void 0) {
contractDependencies[className] = [];
}
contractDependencies[className].push(arg.substr(1));
}
}
}
}
contractsManager.compileContracts();
all_contracts = contractsManager.all_contracts; all_contracts = contractsManager.all_contracts;
contractDB = contractsManager.contractDB; contractDB = contractsManager.contractDB;
contractDependencies = contractsManager.contractDependencies;
all_contracts.sort((function(_this) {
return function(a, b) {
var contract_1, contract_2;
contract_1 = contractDependencies[a];
contract_2 = contractDependencies[b];
if (indexOf.call(contract_1, a) >= 0 && indexOf.call(contract_2, b) >= 0) {
console.log("looks like you have a circular dependency between " + a + " and " + b);
return exit;
} else if (indexOf.call(contract_1, b) >= 0) {
return 1;
} else if (indexOf.call(contract_2, a) >= 0) {
return -1;
} else {
return 0;
}
};
})(this));
deployedContracts = {}; deployedContracts = {};

View File

@ -34,7 +34,8 @@
"sync-me": "^0.1.1", "sync-me": "^0.1.1",
"python": "^0.0.4", "python": "^0.0.4",
"methodmissing": "^0.0.3", "methodmissing": "^0.0.3",
"jasmine": "^2.3.1" "jasmine": "^2.3.1",
"toposort": "^0.2.10"
}, },
"author": "Iuri Matias <iuri.matias@gmail.com>", "author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [], "contributors": [],

View File

@ -56,6 +56,25 @@ describe('embark.config.contracts', function() {
assert.deepEqual(contractsConfig.all_contracts, [ "SimpleStorage", "AnotherStorage" ]); assert.deepEqual(contractsConfig.all_contracts, [ "SimpleStorage", "AnotherStorage" ]);
}); });
}); });
context("contracts as arguments to other contracts", function() {
before(function() {
files = [
'test/support/contracts/wallet.sol',
'test/support/contracts/simple_storage.sol',
'test/support/contracts/another_storage.sol',
'test/support/contracts/wallets.sol'
]
contractsConfig = new Config.Contracts(files, blockchainConfig, web3);
contractsConfig.loadConfigFile('test/support/arguments.yml');
contractsConfig.compileContracts('development');
});
it('add contracts to a list', function() {
assert.deepEqual(contractsConfig.all_contracts, [ "SimpleStorage", "AnotherStorage", "Wallet", "Wallets" ]);
});
});
}); });
}); });

View File

@ -0,0 +1,14 @@
development:
Wallet:
args:
- $AnotherStorage
SimpleStorage:
args:
- 100
AnotherStorage:
args:
- 100
Wallets:
args:
- $Wallet
staging:

View File

@ -0,0 +1,8 @@
contract Wallet {
address currency;
function Wallet(address c) {
currency = c;
}
}

View File

@ -0,0 +1,9 @@
contract Wallets {
address wallet;
function Wallet(address w) {
wallet = w;
}
}