Skip to content

Instantly share code, notes, and snippets.

@tjade273
Last active April 6, 2024 04:32
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save tjade273/69e3cb5dce1789738830 to your computer and use it in GitHub Desktop.
Save tjade273/69e3cb5dce1789738830 to your computer and use it in GitHub Desktop.
Example of separated storage and logic
contract Database{
mapping(uint => uint) public _data;
mapping(address => bool) _owners;
function Database(address[] owners){ //Called once at creation, pass in initial owners
for(uint i; i<owners.length; i++){
_owners[owners[i]]=true;
}
}
function setData(uint id, uint data) public returns (bool){
if(_owners[msg.sender]){
_data[id] = data;
return true;
}
return false;
}
function changeOwners(address owner, bool permission) public returns(bool){
if(_owners[msg.sender]){
_owners[owner] = permission;
return true;
}
return false;
}
}
var owners = [eth.accounts[0]];/* Initial owners*/ ;
/* First time - initialize the database */
var databaseContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"_data","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"data","type":"uint256"}],"name":"setData","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"},{"name":"permission","type":"bool"}],"name":"changeOwners","outputs":[{"name":"","type":"bool"}],"type":"function"},{"inputs":[{"name":"owners","type":"address[]"}],"type":"constructor"}]);
var database = databaseContract.new(
owners,
{
from: web3.eth.accounts[0],
data: '606060405260405161015b38038061015b8339810160405280510160005b81518110156075576001600160005060008484815181101560025790602001906020020151600160a060020a0316815260200190815260200160002060006101000a81548160ff02191690830217905550600101601d565b505060d7806100846000396000f3606060405260e060020a600035046303a7f8258114602e5780634848b1a5146045578063f9b30d03146085575b005b60cd60043560006020819052908152604090205481565b60cd600435602435600160a060020a03331660009081526001602052604081205460ff1615607f5782815260208190526040902081905560015b92915050565b60cd600435602435600160a060020a03331660009081526001602052604081205460ff1615607f57600160a060020a038316815260409020805460ff1916821790556001607f565b6060908152602090f3',
gas: 1000000
}
)
/* --------------- To add logic contracts ----------------- */
var data = database.address; /* Address of database */ ;
var logicContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"newContract","type":"address"}],"name":"update","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"example","outputs":[],"type":"function"},{"inputs":[{"name":"data","type":"address"}],"type":"constructor"}]);
var logic = logicContract.new(
data, // This is where the address gets passed in
{
from: web3.eth.accounts[0],
data: '60606040526040516020806101dd83395060806040525160008054600160a060020a03191682179055506101a6806100376000396000f3606060405260e060020a60003504631c1b8772811461002657806354353f2f146100d0575b005b6100246004356000805460e060020a63f9b30d03026060908152600160a060020a0384811660645260016084529091169163f9b30d039160a491602091906044908290876161da5a03f1156100025750604080516000805460e060020a63f9b30d0302835230600160a060020a03908116600485015260248401839052935193169450604482810193602093909290839003909101908290876161da5a03f1156100025750505050565b610024600080547f03a7f825000000000000000000000000000000000000000000000000000000006060908152610539606452600160a060020a03909116906303a7f8259060849060209060248187876161da5a03f11561000257505060408051805184547f4848b1a500000000000000000000000000000000000000000000000000000000835261053960048401526104d2602484015292519094600160a060020a03939093169350634848b1a5926044808401936020939290839003909101908290876161da5a03f115610002575050505056',
gas: 1000000
})
// To update the permissions in the database (first wait for logic to be mined)
database.changeOwners(logic.address, true,{from:eth.accounts[0],gas:100000});
//Or if there already is a logic contract
oldLogic.update(logic.address, {from:eth.accounts[0],gas:100000});
contract Database{
function _data(uint id) public constant returns (uint data);
function setData(uint id, uint data) public returns (bool);
function changeOwners(address owner, bool permission) public returns(bool);
}
contract Logic{
Database database;
function Logic (address data){
database = Database(data);
}
// Logic here
function update(address newContract) public {
database.changeOwners(newContract,true); // Give new contract write permissions
database.changeOwners(this,false); // Revokes it's own permissions
}
function example(){
uint foo = database._data(1337); // get data
database.setData(1337,1234); // set data
}
}
@tjade273
Copy link
Author

Using string arguments as mapping keys doesn't seem to work, so the DB now uses unique IDs instead of names. In real life, using a (uint => data) mapping where data is a custom struct would probably make the most sense.

@tjade273
Copy link
Author

The database contract is created only once, then the address is passed as an argument to the constructor of each new logic contract. Make sure to properly change the permissions, or you will lose access to the DB and will have to copy all the data to a new one :(

@sekharkumarroy
Copy link

There is an issue with web3 RPC to use string as key. One workaround I found is -
mapping(bytes32 => int) private mymapping;
mymapping[sha3(#inputstring)]

so instead of string use sha3(string) as key. Hope that helps.

@5chdn
Copy link

5chdn commented Jan 28, 2016

I am wondering, what's the difference between the two Database contracts, and why do you define it twice?

edit, nevermind, rereading everything sometimes help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment