/*

`lockable` - An inheritable contract that provides functionality to

lock and unlock a contract in order to prevent any operations

when an issue is found with the contract or the blockchain.

Intended to provide a wide variety of parties the ability to lock a

contract, but a smaller set the ability to unlock it. Because this is

intended to be an emergency measure, there is no concensus requirement,

any address with the ability to lock or unlock can do so alone.

*/

contract lockable {

/* Local private variables */

address private _keymaster ; //administers the ability to lock and unlock

mapping ( address => bool ) private _addressesThatCanLock ;

mapping ( address => bool ) private _addressesThatCanUnlock ;

bool private _isLocked = false ;

address private _lockedBy = address ( 0x0 ) ;

uint private _lockedAt = 0 ;

/* events */

event ContractLocked ( address lockedBy ) ;

event ContractUnlocked ( address unlockedBy ) ;

/* constructor */

function lockable ( ) {

_keymaster = msg. sender ;

}

/*

Get information about the current state of the lock

*/

function isLocked ( ) public constant returns ( bool ) {

return _isLocked ;

}

function getLockedBy ( ) public constant returns ( address ) {

return _lockedBy ;

}

function getLockedAt ( ) public constant returns ( uint ) {

return _lockedAt ;

}

/*

Main lock and unlock functionality

*/

function lock ( ) public returns ( bool ) {

if ( _keymaster != msg. sender && _addressesThatCanLock [ msg. sender ] != true ) return false ; //you do not have permission

if ( _isLocked ) return false ; //already locked

_isLocked = true ;

_lockedBy = msg. sender ;

_lockedAt = block. timestamp ;

ContractLocked ( msg. sender ) ;

return true ;

}

function unlock ( ) public returns ( bool ) {

if ( _keymaster != msg. sender && _addressesThatCanUnlock [ msg. sender ] != true ) return false ; //you do not have permission

if ( ! _isLocked ) return ; //already unlocked

_isLocked = false ;

_lockedBy = address ( 0x0 ) ;

_lockedAt = 0 ;

ContractLocked ( msg. sender ) ;

return true ;

}

/*

Manage the list of addresses that can lock and unlock the contract

*/

function addAddressThatCanLock ( address newAddress ) public returns ( bool ) {

if ( _keymaster != msg. sender ) return false ; //you do not have permission

_addressesThatCanLock [ newAddress ] = true ;

return true ;

}

function addAddressThatCanUnlock ( address newAddress ) public returns ( bool ) {

if ( _keymaster != msg. sender ) return false ; //you do not have permission

_addressesThatCanUnlock [ newAddress ] = true ;

return true ;

}

function removeAddressThatCanLock ( address newAddress ) public returns ( bool ) {

if ( _keymaster != msg. sender ) return false ; //you do not have permission

_addressesThatCanLock [ newAddress ] = false ;

return true ;

}

function removeAddressThatCanUnlock ( address newAddress ) public returns ( bool ) {

if ( _keymaster != msg. sender ) return false ; //you do not have permission

_addressesThatCanUnlock [ newAddress ] = false ;

return true ;

}

/*

Change the keymaster

*/

function replaceKeymaster ( address newKeymaster ) public returns ( bool ) {

if ( _keymaster != msg. sender ) return false ; //you do not have permission

_keymaster = newKeymaster ;

return true ;

}

function getKeymaster ( ) public returns ( address ) {

return _keymaster ;

}