Add python support, move test to python unittest

This commit is contained in:
nolash 2020-11-13 23:19:48 +01:00
parent 9336d813ed
commit 22544ceb23
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
13 changed files with 200 additions and 43 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__
*.pyc

View File

@ -0,0 +1 @@
from .registry import Registry

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160028190555061054f806100cb6000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806306661abd146100675780630a3b0a4f146100855780634c2ebc6b146100c95780635ae06f7e14610121578063da2824a814610165578063f2a40db8146101a9575b600080fd5b61006f610201565b6040518082815260200191505060405180910390f35b6100c76004803603602081101561009b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610207565b005b61010b600480360360208110156100df57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610364565b6040518082815260200191505060405180910390f35b6101636004803603602081101561013757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061037c565b005b6101a76004803603602081101561017b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610428565b005b6101d5600480360360208110156101bf57600080fd5b81019080803590602001909291905050506104dd565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60025481565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661025d57600080fd5b6000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600254600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506002600081548092919060010191905055506001600254038173ffffffffffffffffffffffffffffffffffffffff167f5ed3bdd47b9af629827a8d129aa39c870b10c03f0153fe9ddb8e84b665061acd60405160405180910390a350565b60016020528060005260406000206000915090505481565b3373ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103d657600080fd5b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff021916905550565b3373ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461048257600080fd5b6001600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600081815481106104ea57fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea26469706673582212204dc3c533897e9c630d33c8c0767e5393cf2e4f0faca5d0cbc39dbe82580e869564736f6c63430007030033

View File

@ -0,0 +1,55 @@
import logging
import json
import os
logg = logging.getLogger()
class Registry:
abi = None
def __init__(self, w3, address, signer_address=None):
if Registry.abi == None:
moddir = os.path.dirname(__file__)
datadir = os.path.join(moddir, 'data')
f = open(os.path.join(datadir, 'registry.abi.json'), 'r')
Registry.abi = json.load(f)
f.close()
self.contract = w3.eth.contract(abi=Registry.abi, address=address)
self.w3 = w3
if signer_address != None:
self.signer_address = signer_address
else:
if type(self.w3.eth.defaultAccount).__name__ == 'Empty':
self.w3.eth.defaultAccount = self.w3.eth.accounts[0]
self.signer_address = self.w3.eth.defaultAccount
def add(self, address):
gasPrice = self.w3.eth.gasPrice;
tx_hash = self.contract.functions.add(address).transact({
'gasPrice': gasPrice,
'gas': 100000,
'from': self.signer_address,
})
def count(self):
return self.contract.functions.count().call()
def have(self, address):
r = self.contract.functions.accountsIndex(address).call()
return r != 0
def last(self, n):
c = self.count()
lo = c - n - 1
if lo < 0:
lo = 0
accounts = []
for i in range(c - 1, lo, -1):
a = self.contract.functions.accounts(i).call()
accounts.append(a)
return accounts

28
python/setup.cfg Normal file
View File

@ -0,0 +1,28 @@
[metadata]
name = accounts-index
version = 0.0.1
description = Accounts index evm contract tooling with permissioned writes
author = Louis Holbrook
author_email = dev@holbrook.no
url = https://gitlab.com/nolash/eth-accounts-index
keywords =
ethereum
classifiers =
Programming Language :: Python :: 3
Operating System :: OS Independent
Development Status :: 3 - Alpha
Environment :: No Input/Output (Daemon)
Intended Audience :: Developers
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Topic :: Internet
#Topic :: Blockchain :: EVM
license = GPL3
licence_files =
LICENSE.txt
[options]
python_requires = >= 3.6
packages =
install_requires =
confini==0.2.1
web3==5.12.2

6
python/setup.py Normal file
View File

@ -0,0 +1,6 @@
from setuptools import setup
setup(
scripts=[
]
)

103
python/tests/test_app.py Normal file
View File

@ -0,0 +1,103 @@
import os
import unittest
import json
import web3
import eth_tester
from eth_accounts_index import Registry
testdir = os.path.dirname(__file__)
class Test(unittest.TestCase):
def setUp(self):
eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({
'gas_limit': 9000000,
})
f = open(os.path.join(testdir, '../eth_accounts_index/data/registry.bin'), 'r')
bytecode = f.read()
f.close()
f = open(os.path.join(testdir, '../eth_accounts_index/data/registry.abi.json'), 'r')
abi = json.load(f)
f.close()
backend = eth_tester.PyEVMBackend(eth_params)
self.eth_tester = instance = eth_tester.EthereumTester(backend)
provider = web3.Web3.EthereumTesterProvider(instance)
self.w3 = web3.Web3(provider)
c = self.w3.eth.contract(abi=abi, bytecode=bytecode)
tx_hash = c.constructor().transact({'from': self.w3.eth.accounts[0]})
r = self.w3.eth.getTransactionReceipt(tx_hash)
self.address = r.contractAddress
c = self.w3.eth.contract(abi=abi, address=self.address)
c.functions.addWriter(self.w3.eth.accounts[1]).transact()
def tearDown(self):
pass
def test_basic(self):
registry = Registry(self.w3, self.address)
self.assertEqual(registry.count(), 1); # count starts at 1, first addess is always 0x0
def test_access(self):
registry = Registry(self.w3, self.address, self.w3.eth.accounts[1])
registry.add(self.w3.eth.accounts[2])
self.eth_tester.mine_block()
self.assertEqual(registry.count(), 2)
# account 0 does not have access
registry = Registry(self.w3, self.address, self.w3.eth.accounts[2])
registry.add(self.w3.eth.accounts[2])
self.eth_tester.mine_block()
self.assertEqual(registry.count(), 2)
# after this account 2 has access
registry.contract.functions.addWriter(self.w3.eth.accounts[2]).transact()
registry.add(self.w3.eth.accounts[3])
self.eth_tester.mine_block()
self.assertEqual(registry.count(), 3)
# after this account 2 no longer has access
registry.contract.functions.deleteWriter(self.w3.eth.accounts[2]).transact()
registry.add(self.w3.eth.accounts[3])
self.eth_tester.mine_block()
self.assertEqual(registry.count(), 3)
def test_indices(self):
registry = Registry(self.w3, self.address, self.w3.eth.accounts[1])
registry.add(self.w3.eth.accounts[2])
self.assertTrue(registry.have(self.w3.eth.accounts[2]))
self.assertFalse(registry.have(self.w3.eth.accounts[3]))
def test_list(self):
registry = Registry(self.w3, self.address, self.w3.eth.accounts[1])
for i in range(2, 10):
registry.add(self.w3.eth.accounts[i])
self.assertEqual(registry.count(), 9)
accounts_reverse = []
for i in range(9, 1, -1):
accounts_reverse.append(self.w3.eth.accounts[i])
accounts_list = registry.last(8)
for i in range(8):
self.assertEqual(accounts_list[i], accounts_reverse[i])
if __name__ == '__main__':
unittest.main()

View File

@ -1 +0,0 @@
608060405234801561001057600080fd5b5033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061054f806100616000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806306661abd146100675780630a3b0a4f146100855780634c2ebc6b146100c95780635ae06f7e14610121578063da2824a814610165578063f2a40db8146101a9575b600080fd5b61006f610201565b6040518082815260200191505060405180910390f35b6100c76004803603602081101561009b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610207565b005b61010b600480360360208110156100df57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610364565b6040518082815260200191505060405180910390f35b6101636004803603602081101561013757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061037c565b005b6101a76004803603602081101561017b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610428565b005b6101d5600480360360208110156101bf57600080fd5b81019080803590602001909291905050506104dd565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60025481565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661025d57600080fd5b6000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600254600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506002600081548092919060010191905055506001600254038173ffffffffffffffffffffffffffffffffffffffff167f5ed3bdd47b9af629827a8d129aa39c870b10c03f0153fe9ddb8e84b665061acd60405160405180910390a350565b60016020528060005260406000206000915090505481565b3373ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103d657600080fd5b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff021916905550565b3373ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461048257600080fd5b6001600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600081815481106104ea57fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea2646970667358221220d0c43ebb44ba788ac3723dd1aa1293f073f92c8f6e68a8dd975553f67976555264736f6c63430007030033

View File

@ -0,0 +1 @@
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addedAccount","type":"address"},{"indexed":true,"internalType":"uint256","name":"accountIndex","type":"uint256"}],"name":"AccountAdded","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"accounts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_writer","type":"address"}],"name":"addWriter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_writer","type":"address"}],"name":"deleteWriter","outputs":[],"stateMutability":"nonpayable","type":"function"}]

1
solidity/registry.bin Normal file
View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160028190555061054f806100cb6000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806306661abd146100675780630a3b0a4f146100855780634c2ebc6b146100c95780635ae06f7e14610121578063da2824a814610165578063f2a40db8146101a9575b600080fd5b61006f610201565b6040518082815260200191505060405180910390f35b6100c76004803603602081101561009b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610207565b005b61010b600480360360208110156100df57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610364565b6040518082815260200191505060405180910390f35b6101636004803603602081101561013757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061037c565b005b6101a76004803603602081101561017b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610428565b005b6101d5600480360360208110156101bf57600080fd5b81019080803590602001909291905050506104dd565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60025481565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661025d57600080fd5b6000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600254600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506002600081548092919060010191905055506001600254038173ffffffffffffffffffffffffffffffffffffffff167f5ed3bdd47b9af629827a8d129aa39c870b10c03f0153fe9ddb8e84b665061acd60405160405180910390a350565b60016020528060005260406000206000915090505481565b3373ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103d657600080fd5b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff021916905550565b3373ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461048257600080fd5b6001600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600081815481106104ea57fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea26469706673582212204dc3c533897e9c630d33c8c0767e5393cf2e4f0faca5d0cbc39dbe82580e869564736f6c63430007030033

View File

@ -14,6 +14,8 @@ contract CustodialAccountIndex {
constructor() {
owner = msg.sender;
accounts.push(address(0));
count = 1;
}
function addWriter(address _writer) public {

42
test.py
View File

@ -1,42 +0,0 @@
import web3
import eth_tester
import json
eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({
'gas_limit': 9000000,
})
backend = eth_tester.PyEVMBackend(eth_params)
instance = eth_tester.EthereumTester(backend)
provider = web3.Web3.EthereumTesterProvider(instance)
w3 = web3.Web3(provider)
f = open('registry.bin', 'r')
bytecode = f.read()
f.close()
f = open('registry.abi.json', 'r')
abi = json.load(f)
f.close()
c = w3.eth.contract(abi=abi, bytecode=bytecode)
tx_hash = c.constructor().transact({'from': w3.eth.accounts[0]})
r = w3.eth.getTransactionReceipt(tx_hash)
c = w3.eth.contract(abi=abi, address=r.contractAddress)
fail = False
try:
c.functions.add(w3.eth.accounts[2]).transact({'from': w3.eth.accounts[1]})
except:
fail = True
assert fail
c.functions.addWriter(w3.eth.accounts[1]).transact({'from': w3.eth.accounts[0]})
c.functions.add(w3.eth.accounts[2]).transact({'from': w3.eth.accounts[1]})
c.functions.add(w3.eth.accounts[3]).transact({'from': w3.eth.accounts[1]})
assert c.functions.count().call() == 2
assert c.functions.accountsIndex(w3.eth.accounts[3]).call() == 1
assert c.functions.accounts(1).call() == w3.eth.accounts[3]