Created
February 28, 2019 18:54
-
-
Save fubuloubu/3a51757f5dbbce8af9c5c294a0f0d201 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import random | |
from web3 import Web3, EthereumTesterProvider | |
from vyper import compile_code as compiler | |
from eth_tester.exceptions import TransactionFailed | |
w3 = Web3(EthereumTesterProvider()) | |
max_stakers = 5 | |
with open('cma.vy', 'r') as f: | |
interface = compiler(f.read(), | |
output_formats=['abi', 'bytecode', 'bytecode_runtime']) | |
txn_hash = w3.eth.contract(**interface).constructor().transact() | |
receipt = w3.eth.waitForTransactionReceipt(txn_hash) | |
contract = w3.eth.contract(receipt['contractAddress'], **interface) | |
logout_filter = contract.events.LogoutStarted.createFilter(fromBlock=receipt['blockNumber']) | |
def print_accounts(): | |
accounts = [(a, contract.functions.staked(a).call()) for a in w3.eth.accounts] | |
sorted_accounts = list(reversed(sorted(accounts, key=lambda a: a[1]))) | |
sorted_accounts = [a for a in sorted_accounts if a[1] != 0] | |
[print(s, "staked", a, "tokens") for s, a in sorted_accounts] | |
if len(sorted_accounts) > 0: | |
print("True average:", sum([a for _, a in sorted_accounts]) / len(sorted_accounts)) | |
print() | |
avg_stake = 1000 | |
while avg_stake < 2000: | |
try: | |
# Clear out stakers that are below the threshold | |
for loser in w3.eth.accounts: | |
amount = contract.functions.staked(loser).call() | |
if contract.functions.num_staked().call() > max_stakers and amount != 0 and amount < avg_stake: | |
print(loser, "is logging out", amount, "tokens") | |
contract.functions.logout().transact({'from':loser}) | |
# Choose a staker at random to either stake as new or existing account | |
avg_stake = contract.functions.average_stake().call() | |
staker = random.choice([a for a in w3.eth.accounts]) | |
amount = avg_stake+random.randint(1, 100)-contract.functions.staked(staker).call() | |
if amount < 1: | |
continue | |
print("Staker", staker, "adding", amount, "tokens") | |
txn_hash = contract.functions.stake().transact({'from':staker, 'value':amount}) | |
w3.eth.waitForTransactionReceipt(txn_hash) # Wait for finished execution | |
except TransactionFailed as e: | |
print("Failure! Stake dump:") | |
break | |
finally: | |
print_accounts() | |
avg_stake = contract.functions.average_stake().call() | |
print("Average Stake:", avg_stake) |
This file contains hidden or 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
LogoutStarted: event({validator: address}) | |
MAX_STAKERS: constant(uint256) = 5 | |
LOWEST_STAKE: constant(uint256(wei)) = 1000 | |
staked: public(map(address, uint256(wei))) | |
num_staked: public(uint256) | |
average_stake: public(uint256(wei)) | |
@public | |
def __init__(): | |
# Seed the CMA algorithm with the lowest stake | |
self.average_stake = LOWEST_STAKE | |
@public | |
@payable | |
def stake(): | |
""" | |
Stake on getting a slot in the validator pool | |
Must stake at least enough to put you at or above average | |
""" | |
currently_staked: bool = (self.staked[msg.sender] > 0) | |
self.staked[msg.sender] += msg.value | |
# Allows current stakers to add more | |
assert self.staked[msg.sender] >= self.average_stake | |
if not currently_staked: | |
# CMA_n+1 = CMA_n + (x_n+1 - CMA_n) / (n + 1) | |
self.average_stake += (msg.value - self.average_stake) / (self.num_staked + 1) | |
self.num_staked += 1 # Increase number of samples | |
else: | |
self.average_stake += msg.value / (self.num_staked) | |
@public | |
def logout(): | |
assert self.num_staked > MAX_STAKERS | |
assert self.staked[msg.sender] > 0 | |
_amount: uint256(wei) = self.staked[msg.sender] | |
self.staked[msg.sender] = 0 | |
# Inverse of stake formula | |
# CMA_n-1 = (n * CMA_n - x_n) / (n - 1) | |
self.average_stake = (self.num_staked * self.average_stake - _amount) / (self.num_staked - 1) | |
self.num_staked -= 1 # Decrease number of samples | |
send(msg.sender, _amount) |
This file contains hidden or 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
web3[tester]==5.0.0a6 | |
vyper==0.1.0b8 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment