The more a single entity or small group maintains power over the application, the more centralized it is. The less any one group is able to control the fate of the application and its functioning, the more decentralized it is. Just as decentralized applications do not require a blockchain, running on a blockchain does not make an application decentralized. This means that many applications running on blockchains today may still not be true decentralized applications. This is true, even if the application is entirely open source.
To illustrate, let's consider a small sample application called SpecialClub, written in Solidity. It is very simple, merely keeping a list of members (stored as addresses) that are part of the Special Club:
pragma solidity ^0.4.23;
contract SpecialClub {
// Centralized owner of this application
address public owner;
// we set members to true if they are a member, false otherwise.
mapping(address => bool) public members;
mapping(address => bool) internal requests;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function approveMembership(address _address) onlyOwner external {
members[_address] = true;
requests[_address] = false;
emit GrantedMembership(_address);
}
function requestOwnership() external {
requests[msg.sender] = true;
emit RequestToJoin(msg.sender);
}
event RequestToJoin(address _address);
event GrantedMembership(address _address);
}
Despite being written in Solidity and deployed on a blockchain, this code is entirely centralized. It is still distributed, as the list of members will be publicly distributed across the entire Ethereum network if deployed. However, control remains with a single address—the owner. The owner address has absolute control over who is allowed to be added to the membership list of SpecialClub. Any further functionality based on this membership list will generally be centralized as a result. One advantage that continues to exist over traditional applications is transparency—by having both the code and its state written to the blockchain, everyone is clear about the rules and the list of members. However, to be a truly decentralized application, this app would need to be modified so that, for example, existing members could vote on who to accept or reject.
Here is a very basic example of how that might look:
pragma solidity ^0.4.23;
contract SpecialClub {
address public owner;
// we set members to true if they are a member, false otherwise.
mapping(address => bool) public members;
mapping(address => bool) internal requests;
mapping(address => mapping(address => bool)) votedOn;
mapping(address => uint8) votes;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier onlyMember() {
require(members[msg.sender] == true);
_;
}
function approveMembership(address _address) onlyOwner external {
members[_address] = true;
requests[_address] = false;
emit GrantedMembership(_address);
}
function requestOwnership() external {
requests[msg.sender] = true;
emit RequestToJoin(msg.sender);
}
function voteInMember(address _address) onlyMember external {
//don't allow re-votes
require(!votedOn[_address][msg.sender]);
votedOn[_address][msg.sender] = true;
votes[_address] = votes[_address] + 1;
if (votes[_address] >= 5) {
members[_address] = true;
requests[_address] = false;
emit GrantedMembership(_address);
}
}
event RequestToJoin(address _address);
event GrantedMembership(address _address);
}
This version allows new members to be added if at least five existing members vote to make it happen. While such an application would start out centralized, after five members, the owner would no longer be able to exert any control over the membership list. Over time, the level of decentralization would grow.