Skip to content

Instantly share code, notes, and snippets.

@wemeetagain
Created August 6, 2014 04:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wemeetagain/18d61324512348fad72c to your computer and use it in GitHub Desktop.
Save wemeetagain/18d61324512348fad72c to your computer and use it in GitHub Desktop.
Multi-address Identity Contract
;; 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