Skip to content

Commit

Permalink
Merge 99ab8bf into ed11f66
Browse files Browse the repository at this point in the history
  • Loading branch information
gjgd committed Jul 24, 2018
2 parents ed11f66 + 99ab8bf commit dae9180
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 42 deletions.
56 changes: 52 additions & 4 deletions contracts/JobManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,69 @@ import "zeppelin-solidity/contracts/math/SafeMath.sol";
contract JobManager {
using SafeMath for uint;

enum MineralCategory { Null, Compute, Storage }

event MineralAdded (
uint id,
string name
string name,
MineralCategory category
);

event JobAdded (
uint id,
uint mineralId,
uint minPricePerMineral,
uint expirationBlock
);

struct Mineral {
string name;
MineralCategory category;
}

struct Job {
uint mineralId;
uint minPricePerMineral;
uint expirationBlock;
}

uint public numberOfMinerals;
mapping(uint => Mineral) public minerals;

function submitMineral(string _name) external {
minerals[numberOfMinerals] = Mineral(_name);
emit MineralAdded(numberOfMinerals, _name);
uint public numberOfJobs;
mapping(uint => Job) public jobs;

function submitMineral(string _name, uint _category) external {
// Mineral has to be one of two categories: Compute or Storage
MineralCategory mc;
if(_category == uint(MineralCategory.Compute)) {
mc = MineralCategory.Compute;
} else if (_category == uint(MineralCategory.Storage)) {
mc = MineralCategory.Storage;
} else {
revert();
}
minerals[numberOfMinerals] = Mineral(_name, mc);
emit MineralAdded(numberOfMinerals, _name, mc);
numberOfMinerals = numberOfMinerals.add(1);
}

function mineralIsValid(uint _mineralId) public view returns (bool) {
Mineral memory m = minerals[_mineralId];
return m.category != MineralCategory.Null;
}

function submitJob(uint _mineralId, uint _minPricePerMineral, uint _expirationBlock) external {
// mineralId must correspond to an existing mineral
require(mineralIsValid(_mineralId));
// expirationBlock must be in the future
require(_expirationBlock > block.number);

Job storage j = jobs[numberOfJobs];
j.mineralId = _mineralId;
j.minPricePerMineral = _minPricePerMineral;
j.expirationBlock = _expirationBlock;
emit JobAdded(numberOfJobs, _mineralId, _minPricePerMineral, _expirationBlock);
numberOfJobs = numberOfJobs.add(1);
}
}
21 changes: 13 additions & 8 deletions contracts/TransmuteDPOS.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ contract TransmuteDPOS is TransmuteToken, RoundManager, ProviderPool {
enum ProviderStatus { Unregistered, Registered }

struct Provider {
ProviderStatus status;
uint pricePerStorageMineral;
uint pricePerComputeMineral;
uint blockRewardCut;
Expand Down Expand Up @@ -86,22 +85,21 @@ contract TransmuteDPOS is TransmuteToken, RoundManager, ProviderPool {
Delegator storage d = delegators[msg.sender];
// Provider has to be a Delegator to himself
require(d.delegateAddress == msg.sender);
if (p.status == ProviderStatus.Unregistered) {
if (providerStatus(msg.sender) == ProviderStatus.Unregistered) {
numberOfProviders = numberOfProviders.add(1);
addProvider(msg.sender, p.totalAmountBonded);
emit ProviderAdded(msg.sender, _pricePerStorageMineral, _pricePerComputeMineral, _blockRewardCut, _feeShare);
} else {
emit ProviderUpdated(msg.sender, _pricePerStorageMineral, _pricePerComputeMineral, _blockRewardCut, _feeShare);
}
p.status = ProviderStatus.Registered;
p.pricePerStorageMineral = _pricePerStorageMineral;
p.pricePerComputeMineral = _pricePerComputeMineral;
p.blockRewardCut = _blockRewardCut;
p.feeShare = _feeShare;
}

function resignAsProvider(address _provider) internal {
require(providers[_provider].status != ProviderStatus.Unregistered);
require(providerStatus(_provider) != ProviderStatus.Unregistered);
removeProvider(_provider);
delete providers[_provider];
emit ProviderResigned(_provider);
Expand All @@ -112,14 +110,15 @@ contract TransmuteDPOS is TransmuteToken, RoundManager, ProviderPool {
Provider storage p = providers[_provider];
// A delegator is only allowed to bond to himself (in which case he wants to be a Provider)
// or to a Registered Provider
require(_provider == msg.sender || p.status == ProviderStatus.Registered);
ProviderStatus pStatus = providerStatus(_provider);
require(_provider == msg.sender || pStatus == ProviderStatus.Registered);
// Check if delegator has not already bonded to some address
require(delegators[msg.sender].delegateAddress == address(0));
this.transferFrom(msg.sender, this, _amount);
delegators[msg.sender] = Delegator(_provider, _amount);
p.totalAmountBonded = p.totalAmountBonded.add(_amount);
// Update the bonded amount of the provider in the pool
if (p.status == ProviderStatus.Registered) {
if (pStatus == ProviderStatus.Registered) {
updateProvider(_provider, p.totalAmountBonded);
}
emit DelegatorBonded(msg.sender, _provider, _amount);
Expand Down Expand Up @@ -157,8 +156,14 @@ contract TransmuteDPOS is TransmuteToken, RoundManager, ProviderPool {
delete withdrawInformations[msg.sender];
}

// TODO: Create the same function for Providers
// This will remove the need for ProviderStatus inside the Provider Struct
function providerStatus(address _provider) public view returns (ProviderStatus) {
if (this.containsProvider(_provider)) {
return ProviderStatus.Registered;
} else {
return ProviderStatus.Unregistered;
}
}

function delegatorStatus(address _delegator) public view returns (DelegatorStatus) {
if (delegators[_delegator].amountBonded != 0) {
// If _delegator is in the mapping, he is Bonded
Expand Down
92 changes: 85 additions & 7 deletions test/JobManager.spec.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,115 @@
const JobManager = artifacts.require('./JobManager.sol');
const { assertFail } = require('./utils.js');
require('truffle-test-utils').init();

contract('JobManager', accounts => {

let jm;
const MINERAL_COMPUTE = 1;
const MINEARL_STORAGE = 2;

describe('submitMineral', () => {

before(async () => {
jm = await JobManager.deployed();
});

it('should fail if category is not MINERAL_COMPUTE or MINERAL_STORAGE', async () => {
await assertFail( jm.submitMineral("test", 0) );
await jm.submitMineral("test", MINERAL_COMPUTE);
await jm.submitMineral("test", MINEARL_STORAGE);
await assertFail( jm.submitMineral("test", 3) );
});

it('should store the Mineral in the minerals mapping', async () => {
await jm.submitMineral('multiplication');
const mineral = await jm.minerals.call(0);
assert.equal('multiplication', mineral);
const mineralId = (await jm.numberOfMinerals.call()).toNumber();
await jm.submitMineral('multiplication', MINERAL_COMPUTE);
const mineral = await jm.minerals.call(mineralId);
let [name, category] = mineral;
assert.equal('multiplication', name);
assert.equal(MINERAL_COMPUTE, category);
});

it('should increase the value of numberOfMinerals', async () => {
it('should increment numberOfMinerals', async () => {
const numberOfMinerals = await jm.numberOfMinerals.call();
await jm.submitMineral('addition');
await jm.submitMineral('addition', MINERAL_COMPUTE);
assert.deepEqual(numberOfMinerals.add(1), await jm.numberOfMinerals.call())
});

it('should emit a MineralAdded event', async () => {
let result = await jm.submitMineral('division');
const mineralId = (await jm.numberOfMinerals.call()).toNumber();
let result = await jm.submitMineral('division', MINERAL_COMPUTE);
assert.web3Event(result, {
event: 'MineralAdded',
args: {
id: 2,
id: mineralId,
name: 'division',
category: MINERAL_COMPUTE,
}
});
});

it('should accept no name for Mineral', async () => {
const mineralId = (await jm.numberOfMinerals.call()).toNumber();
await jm.submitMineral("", MINERAL_COMPUTE);
const mineral = await jm.minerals.call(mineralId);
let [name, _] = mineral;
assert.equal("", name);
});
});

describe('submitJob', () => {

let expirationBlock = web3.eth.blockNumber + 1000;

before(async () => {
jm = await JobManager.new();
await jm.submitMineral("multiplication", MINERAL_COMPUTE);
await jm.submitMineral("addition", MINERAL_COMPUTE);
});

it('should fail if mineralId is not the id of a valid Mineral', async () => {
await assertFail( jm.submitJob(2, 10, expirationBlock) );
await jm.submitJob(0, 10, expirationBlock);
});

it('should fail if expiration block is not in the future', async () => {
const blockInThePast = web3.eth.blockNumber;
await assertFail( jm.submitJob(0, 10, blockInThePast) );
const presentBlock = web3.eth.blockNumber + 1;
await assertFail( jm.submitJob(0, 10, presentBlock) );
const blockInTheFuture = web3.eth.blockNumber + 2;
await jm.submitJob(0, 10, blockInTheFuture);
});

it('should store the Job parameters in the jobs mapping', async () => {
const jobId = await jm.numberOfJobs.call();
await jm.submitJob(1, 11, expirationBlock + 42);
const job = await jm.jobs.call(jobId);
const [mineralId, minPricePerMineral, expBlock] = job;
assert.equal(1, mineralId);
assert.equal(11, minPricePerMineral);
assert.equal(expirationBlock + 42, expBlock);
});

it('should emit a JobAdded event', async () => {
const jobId = await jm.numberOfJobs.call();
let result = await jm.submitJob(1, 12, expirationBlock);
assert.web3Event(result, {
event: 'JobAdded',
args: {
id: jobId.toNumber(),
mineralId: 1,
minPricePerMineral: 12,
expirationBlock: expirationBlock
}
});
});

it('should increment numberOfJobs', async () => {
const numberOfJobs = await jm.numberOfJobs.call();
await jm.submitJob(1, 12, expirationBlock);
assert.deepEqual(numberOfJobs.add(1), await jm.numberOfJobs.call())
});
});
});
Loading

0 comments on commit dae9180

Please sign in to comment.