Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eternal storage #381

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
143 changes: 143 additions & 0 deletions contracts/data/EternalStorage.sol
@@ -0,0 +1,143 @@
pragma solidity ^0.4.13;

import "../lifecycle/Pausable.sol";

/**
* @title Contract that store data in behalf of another contract
* @author SylTi inspired from colony blog post https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88
* @dev This contract should be used in combinaison of other strategies to make your contract upgradeable
* like encapsulating logic into libraries.
*/

contract EternalStorage is Pausable {
mapping(bytes32 => uint) public UIntValues;
mapping(bytes32 => int) public IntValues;
mapping(bytes32 => string) public StringValues;
mapping(bytes32 => address) public AddressValues;
mapping(bytes32 => bytes) public BytesValues;
mapping(bytes32 => bytes32) public Bytes32Values;
mapping(bytes32 => bool) public BooleanValues;

function EternalStorage() {
}

/**
* @dev change the value inside UIntValues for the given key
* @param record sha3 key
* @param value new value is uint
*/
function setUIntValue(bytes32 record, uint value) public onlyOwner {
UIntValues[record] = value;
}

/**
* @dev delete the value inside UIntValues for the given key
* @param record sha3 key
*/
function deleteUIntValue(bytes32 record) public onlyOwner {
delete UIntValues[record];
}

/**
* @dev change the value inside IntValues for the given key
* @param record sha3 key
* @param value new value is int
*/
function setIntValue(bytes32 record, int value) public onlyOwner {
IntValues[record] = value;
}

/**
* @dev delete the value inside IntValues for the given key
* @param record sha3 key
*/
function deleteIntValue(bytes32 record) public onlyOwner {
delete IntValues[record];
}

/**
* @dev change the value inside StringValues for the given key
* @param record sha3 key
* @param value new value is string
*/
function setStringValue(bytes32 record, string value) public onlyOwner {
StringValues[record] = value;
}

/**
* @dev delete the value inside StringValues for the given key
* @param record sha3 key
*/
function deleteStringValue(bytes32 record) public onlyOwner {
delete StringValues[record];
}

/**
* @dev change the value inside AddressValues for the given key
* @param record sha3 key
* @param value new value is address
*/
function setAddressValue(bytes32 record, address value) public onlyOwner {
AddressValues[record] = value;
}

/**
* @dev delete the value inside AddressValues for the given key
* @param record sha3 key
*/
function deleteAddressValue(bytes32 record) public onlyOwner {
delete AddressValues[record];
}

/**
* @dev change the value inside BytesValues for the given key
* @param record sha3 key
* @param value new value is bytes
*/
function setBytesValue(bytes32 record, bytes value) public onlyOwner {
BytesValues[record] = value;
}

/**
* @dev delete the value inside BytesValues for the given key
* @param record sha3 key
*/
function deleteBytesValue(bytes32 record) public onlyOwner {
delete BytesValues[record];
}

/**
* @dev change the value inside Bytes32Values for the given key
* @param record sha3 key
* @param value new value is bytes32
*/
function setBytes32Value(bytes32 record, bytes32 value) public onlyOwner {
Bytes32Values[record] = value;
}

/**
* @dev delete the value inside Bytes32Values for the given key
* @param record sha3 key
*/
function deleteBytes32Value(bytes32 record) public onlyOwner {
delete Bytes32Values[record];
}

/**
* @dev change the value inside BooleanValues for the given key
* @param record sha3 key
* @param value new value is bool
*/
function setBooleanValue(bytes32 record, bool value) public onlyOwner {
BooleanValues[record] = value;
}

/**
* @dev delete the value inside BooleanValues for the given key
* @param record sha3 key
*/
function deleteBooleanValue(bytes32 record) public onlyOwner {
delete BooleanValues[record];
}

}
34 changes: 34 additions & 0 deletions contracts/examples/SampleContractWithEternalStorage.sol
@@ -0,0 +1,34 @@
pragma solidity ^0.4.13;

import "../lifecycle/Pausable.sol";
import "../examples/SampleLibraryEternalStorage.sol";

/**
* @title Sample contract that show how to use the EternalStorage contract
* @author SylTi inspired from colony blog post https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88
* @dev This contract is just an example and should not be used directly
*/
contract SampleContractWithEternalStorage is Pausable {

using CounterLibrary for address;
address eternalStorage;

function SampleContractWithEternalStorage(address _eternalStorage) {
eternalStorage = _eternalStorage;
}

/**
* @dev call library function to increment the value in EternalStorage
*/
function incrementValue() public returns (uint) {
return eternalStorage.increment();
}

/**
* @dev call library function to get value stored in EternalStorage
*/
function getValue() public constant returns (uint) {
return eternalStorage.getCount();
}

}
32 changes: 32 additions & 0 deletions contracts/examples/SampleLibraryEternalStorage.sol
@@ -0,0 +1,32 @@
pragma solidity ^0.4.13;

import '../math/SafeMath.sol';
import "../data/EternalStorage.sol";

/**
* @title Sample library that show how to store/read data in the EternalStorage contract
* @author SylTi inspired from colony blog post https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88
* @dev This is just a example lib and should not be used directly
*/
library CounterLibrary {
using SafeMath for uint256;

/**
* @dev read value from EternalStorage contract
* @param _storageContract address of the EternalStorage contract
*/
function getCount(address _storageContract) public constant returns(uint256) {
return EternalStorage(_storageContract).UIntValues(sha3("counter"));
}

/**
* @dev increment value in EternalStorage by one
* @param _storageContract address of the EternalStorage contract
*/
function increment(address _storageContract) public returns (uint) {
uint count = getCount(_storageContract);
uint value = count.add(1);
EternalStorage(_storageContract).setUIntValue(sha3("counter"), value);
return value;
}
}
5 changes: 5 additions & 0 deletions migrations/2_deploy_contracts.js
@@ -1,5 +1,10 @@
//var Ownable = artifacts.require("ownership/Ownable.sol");
let SampleLibraryEternalStorage = artifacts.require("CounterLibrary");
let SampleContractWithEternalStorage = artifacts.require("SampleContractWithEternalStorage");

module.exports = function(deployer) {
//deployer.deploy(Ownable);
deployer.deploy(SampleLibraryEternalStorage);
deployer.link(SampleLibraryEternalStorage, SampleContractWithEternalStorage);
deployer.deploy(SampleContractWithEternalStorage);
};
131 changes: 131 additions & 0 deletions test/EternalStorage.js
@@ -0,0 +1,131 @@
'use strict';

import expectThrow from './helpers/expectThrow';
let EternalStorage = artifacts.require('../contracts/data/EternalStorage.sol');

contract('EternalStorage', function (accounts) {
let storage;

beforeEach(async function () {
storage = await EternalStorage.new();
});

contract('UIntValues', function () {
it('should start with a value of 0', async function () {
let value = await storage.UIntValues(web3.sha3("value"));

assert.equal(value, 0);
});

it('should set value to 1', async function () {
await storage.setUIntValue(web3.sha3("value"), 1);
let value = await storage.UIntValues(web3.sha3("value"));

assert.equal(value, 1);
});
it('should fail to set negative number', async function () {
await storage.setUIntValue(web3.sha3("value"), -1);
let value = await storage.UIntValues(web3.sha3("value"));

assert.notEqual(value.toNumber(), -1);
})
});

contract('IntValues', function () {
it('should start with a value of 0', async function () {
let value = await storage.IntValues(web3.sha3("value"));

assert.equal(value, 0);
});

it('should set value to -1', async function () {
await storage.setIntValue(web3.sha3("value"), -1);
let value = await storage.IntValues(web3.sha3("value"));

assert.equal(value, -1);
});

it('should fail to set an address', async function () {
await storage.setIntValue(web3.sha3("value"), accounts[0])
let value = await storage.UIntValues(web3.sha3("value"));
assert.notEqual(value.valueOf(), accounts[0]);
})
});

contract('StringValues', function () {
it('should start with a empty string', async function () {
let value = await storage.StringValues(web3.sha3("value"));

assert.equal(value.valueOf(), "");
});

it('should set string value to test', async function () {
await storage.setStringValue(web3.sha3("value"), "test");
let value = await storage.StringValues(web3.sha3("value"));

assert.equal(value.valueOf(), "test");
});
});

contract('AddressValues', function () {
it('should start with a empty Address', async function () {
let value = await storage.AddressValues(web3.sha3("value"));

assert.equal(value.valueOf(), 0x0);
});

it('should set Address value to accounts[0]', async function () {
await storage.setAddressValue(web3.sha3("value"), accounts[0]);
let value = await storage.AddressValues(web3.sha3("value"));

assert.equal(value.valueOf(), accounts[0]);
});
});

contract('BytesValues', function () {
it('should start with a empty Bytes', async function () {
let value = await storage.BytesValues(web3.sha3("value"));

assert.equal(value.valueOf(), "0x");
});

it('should set Bytes value to substring of sha3(test)', async function () {
let insert = web3.sha3("test").substring(0, 10);
await storage.setBytesValue(web3.sha3("value"), insert);
let value = await storage.BytesValues(web3.sha3("value"));

assert.equal(value.valueOf(), insert);
});
});

contract('Bytes32Values', function () {
it('should start with a empty Bytes32', async function () {
let value = await storage.Bytes32Values(web3.sha3("value"));

assert.equal(value.valueOf(), "0x0000000000000000000000000000000000000000000000000000000000000000");
});

it('should set Bytes32 value to sha3(test)', async function () {
let insert = web3.sha3("test");
await storage.setBytes32Value(web3.sha3("value"), insert);
let value = await storage.Bytes32Values(web3.sha3("value"));

assert.equal(value.valueOf(), insert);
});
});

contract('BooleanValues', function () {
it('should start with a empty Boolean', async function () {
let value = await storage.BooleanValues(web3.sha3("value"));

assert.equal(value, false);
});

it('should set Boolean value to true', async function () {
await storage.setBooleanValue(web3.sha3("value"), true);
let value = await storage.BooleanValues(web3.sha3("value"));

assert.equal(value, true);
});
});
});
33 changes: 33 additions & 0 deletions test/SampleContractWithEternalStorage.js
@@ -0,0 +1,33 @@
'use strict';

import expectThrow from './helpers/expectThrow';
let EternalStorage = artifacts.require('../contracts/data/EternalStorage.sol');
let SampleContract = artifacts.require('../contracts/examples/SampleContractWithEternalStorage.sol');

contract('SampleContractWithEternalStorage', function (accounts) {
let sample;
let storage;

beforeEach(async function () {
storage = await EternalStorage.new();
sample = await SampleContract.new(storage.address);
});

it('should start with a count of 0', async function () {
let value = await sample.getValue();

assert.equal(value.toNumber(), 0);
});

it('should fail to write to eternalStorage', async function () {
await expectThrow(sample.incrementValue());
})

it('should set value to 1', async function () {
await storage.transferOwnership(sample.address);
await sample.incrementValue();
let value = await sample.getValue();
assert.equal(value.toNumber(), 1);
});

});