Created
August 6, 2014 04:42
-
-
Save wemeetagain/18d61324512348fad72c to your computer and use it in GitHub Desktop.
Multi-address Identity Contract
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; multi-addr identity with address voting | |
;; | |
;; addresses have 4 commands (transaction types): | |
;; - vote_add(address,category,permission,lifespan) | |
;; - tx.data[0]==0 | |
;; - This initiates a vote for `address` to be added to the member list. | |
;; This only works on addresses with a stored state of none(0) or | |
;; adding(1). If the vote total for `address` reaches 50% of voting | |
;; members, `address` is added to the member list. The category, | |
;; permission, lifespan args are optional once vote has been started. | |
;; - vote_remove(address) | |
;; - tx.data[0]==1 | |
;; - This initates a vote on a current member to be removed from the member | |
;; list. This only works on on addresses with a stored state of member(3) | |
;; or removing(2). If the vote total for `address` reached 50% of voting | |
;; members, `address` is removed from the member list | |
;; - check_lifespan(address) | |
;; - txdata[0]==2 | |
;; - This initiates a check on lifespan check on `address`. If `address` | |
;; has expired, `address` is removed from the member list. Voting and | |
;; non-voting members can check_lifespan | |
;; - vote_suicide() | |
;; - tx.data[0]==3 | |
;; - This initiates a vote for contract suicide. If a suicide attempt has | |
;; not been initiated in the past 60 blocks, name `caller` as beneficiary | |
;; and vote is started over. (suicide must be confirmed within 60 blocks) | |
;; | |
;; each address has: | |
;; - state - 0=none,1=adding,2=removing,3=member | |
;; - category - not currently used | |
;; - vote_total - total vote count, used for adding/removal, 0 if state is | |
;; none(0) or member(3) | |
;; - permissions - 0=no voting, 1=voting | |
;; - lifespan - time in blocks before expiry, 0 for no-exiration | |
;; | |
;; storage is allocated like so: | |
;; - storage[0]: total number of members | |
;; - storage[1:(N+1)]: addresses of N members | |
;; - storage[(N+1]: total number of voters | |
;; | |
;; - storage[address]: address state | |
;; - storage[(address+1)]: address category | |
;; - storage[(address+2)]: address vote_total | |
;; - storage[(address+3)]: address permissions | |
;; - storage[(address+4)]: address lifespan | |
;; - storage[(address+5)]: address index in member list | |
;; | |
;; - storage[(sha3(voter+address))]: store vote for voter on address | |
;; | |
;; - storage[contractAddr]: last suicide attempt | |
;; - storage[(contractAddr+1)]: last beneficiary | |
;; - storage[(contractAddr+2)]: last suicide vote total | |
{ | |
;; init | |
[[0]] 1 | |
[[1]] (caller) | |
[[(caller)]] 3 ; address state | |
[[(+ (caller) 3)]] 1 ; address permission | |
[[(+ (caller) 5)]] 1 ; address index | |
;; def macros | |
(def `stopOnBadAddr (addr) | |
(unless (&& (>= 5000 addr) | |
(< addr (- (address) 5)) | |
(> addr (+ (address) 3))) | |
(stop))) | |
(def 'initAdd (addr cat perm time) { | |
[[addr]] 1 | |
[[(+ 1 addr)]] cat ; category | |
[[(+ 3 addr)]] perm ; permissions | |
(when (!= 0 time) | |
[[(+ 4 addr)]] (+ (number) time)) | |
}) | |
(def 'initRemove (addr) [[addr]] 2) | |
(def 'voteAdd (addr) { | |
[votespot] (sha3pair addr (caller)) | |
(when (!= 1 (sload (mload votespot))) { | |
[[(mload votespot)]] 1 | |
[[(+ 2 addr)]] (+ (sload (+ 2 addr)) 1) | |
}) | |
}) | |
(def 'voteRemove (addr) { | |
[votespot] (sha3pair addr (caller)) | |
(when (!= (sload (mload votespot)) 2) { | |
[[(mload votespot)]] 2 | |
[[(+ 2 addr)]] (- (sload (+ 2 addr)) 1) | |
}) | |
}) | |
(def 'confirmAdd (addr) { | |
[[addr]] 3 ; set addr state | |
[[(+ 1 addr)]] 0 ; reset addr vote_total | |
[[0]] (+ 1 (sload 0)) ; increment member list length | |
[new_len] (sload 0) | |
[[(+ 1 (mload new_len))]] (+ (sload (mload new_len)) 1) ; increment and move voter list | |
[[(mload new_len)]] addr ; add addr to end of member list | |
[[(+ addr 5)]] (mload new_len) ; store index in list | |
}) | |
(def 'confirmRemove (addr) { | |
[[addr]] 0 ; state to 0 | |
[[(+ 2 addr)]] 0 ; vote total to 0 | |
[cur_len] (sload 0) | |
[old_len] (sload (- addr 1)) ; addr's spot in member list | |
;; replace entry with last entry | |
[[(mload old_len)]] (sload (mload cur_len)) ; replace removed addr with last | |
[[(mload cur_len)]] 0 ; delete last duplicate | |
[[(+ (sload (mload old_len)) 5)]] (mload old_len) ; set inserted addr's index (addr+5) | |
[[0]] (- (mload cur_len) 1) ; decrement member list | |
[[(mload cur_len)]] (sload (+ (mload cur_len) 1)) ; decrement and move voter list | |
}) | |
(def 'voteFinished (addr) (if (>= (sload (+ addr 2)) (/ (sload (+ (sload 0) 1)) 2)) 1 0)) | |
;; contract code | |
(return 0 (lll | |
{ | |
(when (&& (!= (sload (caller)) 2) (!= (sload (caller)) 3)) | |
(stop)) ; stop nonmembers | |
(stopOnBadAddr (calldataload 1)) | |
(if (= (calldataload 0) 0) ; add | |
{ | |
(unless (= (+ (sload (caller)) 3) 1) | |
(stop)) ; caller permission check | |
(when (&& (!= 0 (calldataload 3)) (!= 1 (calldataload 3))) | |
(stop)) ; permission to be added | |
(when (= (sload (calldataload 1)) 0) | |
(initAdd (calldataload 1) (calldataload 2) (calldataload 3) (calldataload 4))) | |
(when (= (sload (calldataload 1)) 1) | |
(voteAdd (calldataload 1))) | |
(when (voteFinished (calldataload 1)) | |
(confirmAdd (calldataload 1))) | |
} | |
(if (= (calldataload 0) 1) ; remove | |
{ | |
(unless (= (+ (sload (caller)) 3) 1) | |
(stop)) ; caller permission check | |
(when (= (sload (calldataload 1)) 3) | |
(initRemove (calldataload 1))) | |
(when (= (sload (calldataload 1)) 2) | |
(voteRemove (calldataload 1))) | |
(when (voteFinished (calldataload 1)) | |
(confirmRemove (calldataload 1))) | |
} | |
(if (= (calldataload 0) 2) ; check addr lifespan, remove if expired | |
;{ | |
(when (&& (!= (sload (+ (calldataload 1) 4)) 0) | |
(< (sload (+ (calldataload 1) 4)) (number))) | |
(confirmRemove (calldataload 1))) | |
;} | |
(when (= (calldataload 0) 3) ; suicide vote | |
{ | |
(unless (= (+ (sload (caller)) 3) 1) | |
(stop)) ; caller permission check | |
;; when last suicide attempt was old, reset suicide vote | |
(when (< (+ (sload (address)) 60) (number)) | |
{ | |
[[(address)]] (number) | |
[[(+ (address) 1)]] (caller) | |
}) | |
;; when caller's last suicide vote was old, revote, check total | |
(when (< (+ (sload (sha3pair (caller) (address))) 60) (number)) | |
{ | |
[[(sha3pair (caller) (address))]] (number) ; set caller vote | |
[[(+ (address) 2)]] (+ (sload (+ (address) 2)) 1) ; increment total | |
(when (voteFinished (address)) | |
(suicide (sload (+ (address) 1)))) | |
}) | |
})))) | |
} 0)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment