Compare commits

..

No commits in common. "6abe08f2f5473219aefb40604f2f20ec855a936b" and "27fefe21f78f7f76fd8e689e6137749b66b53fef" have entirely different histories.

11 changed files with 86 additions and 116 deletions

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
[{"inputs":[{"internalType":"bytes32[]","name":"_identifiers","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"AddressKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"}],"name":"addressOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"identifier","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"identifierCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"},{"internalType":"address","name":"_address","type":"address"}],"name":"set","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sum","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] [{"inputs":[{"internalType":"bytes32[]","name":"_identifiers","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"}],"name":"addressOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"},{"internalType":"bytes32","name":"_reference","type":"bytes32"}],"name":"bind","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"identifiers","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"},{"internalType":"address","name":"_address","type":"address"}],"name":"set","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sum","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

View File

@ -1 +1 @@
{"compiler":{"version":"0.8.18+commit.87f61d96"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes32[]","name":"_identifiers","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"AddressKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"}],"name":"addressOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"identifier","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"identifierCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"},{"internalType":"address","name":"_address","type":"address"}],"name":"set","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sum","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"Registry.sol":"ContractRegistry"},"evmVersion":"byzantium","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Registry.sol":{"keccak256":"0x5e3faff7b6f6451b4e924784ad8732e1f4fdd4b49de85c1f64a8b185b39fa5bd","license":"AGPL-3.0-or-later","urls":["bzz-raw://c33a89bb4aa9200fac7cb354aa9499961d11f7d4d387a536f8b9910c45d7fc87","dweb:/ipfs/QmZnK2CtsRME2WW59TT1EqmrgDNz3CaL6GRDxaQoGL2h1R"]}},"version":1} {"compiler":{"version":"0.8.18+commit.87f61d96"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes32[]","name":"_identifiers","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"}],"name":"addressOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"},{"internalType":"bytes32","name":"_reference","type":"bytes32"}],"name":"bind","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"identifiers","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_identifier","type":"bytes32"},{"internalType":"address","name":"_address","type":"address"}],"name":"set","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sum","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"Registry.sol":"CICRegistry"},"evmVersion":"byzantium","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Registry.sol":{"keccak256":"0x68d1247a7776b5e3099c175b8108cc5b82950d5372888fdf38a76715d02eaa57","license":"GPL-3.0-or-later","urls":["bzz-raw://4f4dab8d265dc89ba26c3f9b90eedeb190af46575361dd9bc24fc44a80eded36","dweb:/ipfs/QmQe2NfXMfqDMacnenJaoW29iaM5nqdzYsiZVZgqMy64zb"]}},"version":1}

View File

@ -43,26 +43,6 @@ class Registry(TxFactory):
return o return o
def identifier(self, contract_address, idx, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('identifier')
enc.typ(ABIContractType.UINT256)
enc.uint256(idx)
data = add_0x(enc.encode())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o = j.finalize(o)
return o
def identifier_count(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
return self.call_noarg('identifierCount', contract_address, sender_address=sender_address, id_generator=id_generator)
@classmethod @classmethod
def parse_address_of(self, v): def parse_address_of(self, v):
return abi_decode_single(ABIContractType.ADDRESS, v) return abi_decode_single(ABIContractType.ADDRESS, v)

View File

@ -94,8 +94,6 @@ class ContractRegistry(Registry):
def set(self, contract_address, sender_address, identifier_string, address): def set(self, contract_address, sender_address, identifier_string, address):
if len(identifier_string) > 32:
raise ValueError('String too long')
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('set') enc.method('set')
enc.typ(ABIContractType.BYTES32) enc.typ(ABIContractType.BYTES32)

View File

@ -4,7 +4,7 @@ set -e
set -x set -x
default_pythonpath=$PYTHONPATH:. default_pythonpath=$PYTHONPATH:.
export PYTHONPATH=${default_pythonpath:-.} export PYTHONPATH=${default_pythonpath:-.}
for f in `ls tests/test_*.py`; do for f in `ls tests/*.py`; do
python $f python $f
if [ $? -gt 0 ]; then if [ $? -gt 0 ]; then
exit 1 exit 1

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = eth-contract-registry name = eth-contract-registry
version = 0.11.0 version = 0.10.0
description = Ethereum Smart Contract key-value registry description = Ethereum Smart Contract key-value registry
author = Louis Holbrook author = Louis Holbrook
author_email = dev@holbrook.no author_email = dev@holbrook.no

View File

@ -1,4 +1,3 @@
pytest==6.0.1 pytest==6.0.1
eth-tester==0.5.0b3 eth-tester==0.5.0b3
py-evm==0.3.0a20 py-evm==0.3.0a20
eth-erc20~=0.7.2

4
python/tests/conftest.py Normal file
View File

@ -0,0 +1,4 @@
# external imports
from chainlib.eth.pytest import *
from eth_contract_registry.pytest import *

View File

@ -1,86 +1,74 @@
# standard imports # standard imports
import os import os
import unittest
import json
import logging
import hashlib
# external imports # external imports
from chainlib.eth.unittest.ethtester import EthTesterCase import logging
import pytest
from chainlib.eth.tx import (
receipt,
transaction,
)
from chainlib.connection import RPCConnection
from chainlib.eth.contract import ( from chainlib.eth.contract import (
ABIContractEncoder, ABIContractEncoder,
ABIContractType, ABIContractType,
abi_decode_single,
) )
from chainlib.eth.nonce import RPCNonceOracle from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt from chainlib.eth.address import to_checksum_address
from giftable_erc20_token import GiftableToken
from hexathon import ( from hexathon import (
add_0x, add_0x,
strip_0x, strip_0x,
same as same_hex, )
)
# local imports # local imports
from eth_contract_registry.registry import ContractRegistry
from eth_contract_registry import Registry from eth_contract_registry import Registry
from eth_contract_registry.registry import ContractRegistry
from eth_contract_registry.encoding import from_identifier_hex
from eth_contract_registry.pytest.fixtures_registry import valid_identifiers
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger() logg = logging.getLogger()
valid_identifiers += [
'FooContract',
]
class TestContractRegistry(EthTesterCase): def test_set(
default_chain_spec,
registry,
eth_accounts,
eth_rpc,
eth_signer,
roles,
):
addr_registry = to_checksum_address(os.urandom(20).hex())
addr_foo = to_checksum_address(os.urandom(20).hex())
bogus_hash = add_0x(os.urandom(32).hex())
def setUp(self): nonce_oracle = RPCNonceOracle(roles['CONTRACT_DEPLOYER'], eth_rpc)
super(TestContractRegistry, self).setUp() builder = ContractRegistry(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
self.registry_ids = ['FOo', 'Bar', 'baz', 'XYZZY']
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) o = builder.address_of(registry, 'ContractRegistry', sender_address=eth_accounts[0])
c = ContractRegistry(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) r = eth_rpc.do(o)
(tx_hash_hex, o) = c.constructor(self.accounts[0], self.registry_ids) r = abi_decode_single(ABIContractType.ADDRESS, r)
self.rpc.do(o) assert r == strip_0x(registry)
o = receipt(tx_hash_hex)
rcpt = self.rpc.do(o)
self.assertEqual(rcpt['status'], 1)
self.address = rcpt['contract_address']
logg.info('registry published to ' + self.address)
(tx_hash_hex, o) = builder.set(registry, roles['CONTRACT_DEPLOYER'], 'ContractRegistry', addr_registry)
r = eth_rpc.do(o)
o = receipt(r)
rcpt = eth_rpc.do(o)
assert rcpt['status'] == 0
def test_retrieve(self): (tx_hash_hex, o) = builder.set(registry, roles['CONTRACT_DEPLOYER'], 'FooContract', addr_foo)
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) r = eth_rpc.do(o)
c = ContractRegistry(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) o = receipt(r)
(tx_hash_hex, o) = c.set(self.address, self.accounts[0], 'FOO', self.address) rcpt = eth_rpc.do(o)
r = self.rpc.do(o) assert rcpt['status'] == 1
o = receipt(tx_hash_hex)
r = self.rpc.do(o)
self.assertEqual(r['status'], 0)
(tx_hash_hex, o) = c.set(self.address, self.accounts[0], 'FOo', self.address) builder = Registry(default_chain_spec)
r = self.rpc.do(o) o = builder.address_of(registry, 'FooContract', sender_address=eth_accounts[0])
o = receipt(tx_hash_hex) r = eth_rpc.do(o)
r = self.rpc.do(o) r = abi_decode_single(ABIContractType.ADDRESS, r)
self.assertEqual(r['status'], 1) assert r == addr_foo
c = ContractRegistry(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
o = c.address_of(self.address, 'FOo', sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertTrue(same_hex(strip_0x(r)[24:], self.address))
def test_identifiers(self):
c = Registry(self.chain_spec)
o = c.identifier_count(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertEqual(int(r, 16), 4)
for i in range(4):
o = c.identifier(self.address, i, sender_address=self.accounts[0])
r = self.rpc.do(o)
r = bytes.fromhex(strip_0x(r))
r = r.strip(b'\x00')
s = r.decode('utf-8')
self.assertEqual(s, self.registry_ids[i])
if __name__ == '__main__':
unittest.main()

View File

@ -1,51 +1,54 @@
pragma solidity >=0.8.0; pragma solidity >0.6.11;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 // Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// File-version: 4 // File-version: 2
// Description: Keyed smart contract registry // Description: Top-level smart contract registry for the CIC network
contract ContractRegistry { contract CICRegistry {
mapping (bytes32 => address) entries;
// Implements ERC173 // Implements ERC173
address public owner; address public owner;
// Implements Registry // Implements RegistryClient
bytes32[] public identifier; bytes32[] public identifiers;
mapping (bytes32 => address) entries; // contractidentifier -> address
mapping (bytes32 => bytes32[]) entryBindings; // contractidentifier -> chainidentifier
// Implements ERC173 // Implements ERC173
event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner); event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
// Implements Registry
event AddressKey(bytes32 indexed _key, address _address);
constructor(bytes32[] memory _identifiers) { constructor(bytes32[] memory _identifiers) {
owner = msg.sender; owner = msg.sender;
for (uint i = 0; i < _identifiers.length; i++) { for (uint i = 0; i < _identifiers.length; i++) {
identifier.push(_identifiers[i]); identifiers.push(_identifiers[i]);
} }
} }
// Assign address to identifier // Implements Registry
function set(bytes32 _identifier, address _address) public returns (bool) { function set(bytes32 _identifier, address _address) public returns (bool) {
require(msg.sender == owner); require(msg.sender == owner);
require(entries[_identifier] == address(0)); require(entries[_identifier] == address(0));
require(_address != address(0)); require(_address != address(0));
bool found = false; bool found = false;
for (uint i = 0; i < identifier.length; i++) { for (uint i = 0; i < identifiers.length; i++) {
if (identifier[i] == _identifier) { if (identifiers[i] == _identifier) {
found = true; found = true;
} }
} }
require(found); require(found);
entries[_identifier] = _address; entries[_identifier] = _address;
return true;
}
emit AddressKey(_identifier, _address); // Implements Registry
function bind(bytes32 _identifier, bytes32 _reference) public returns (bool) {
require(msg.sender == owner);
require(entries[_identifier] != address(0));
entryBindings[_identifier].push(_reference);
return true; return true;
} }
@ -53,26 +56,24 @@ contract ContractRegistry {
function transferOwnership(address _newOwner) public returns (bool) { function transferOwnership(address _newOwner) public returns (bool) {
address _oldOwner; address _oldOwner;
require(msg.sender == owner, 'ERR_AXX'); require(msg.sender == owner);
_oldOwner = owner; _oldOwner = owner;
owner = _newOwner; owner = _newOwner;
emit OwnershipTransferred(_oldOwner, _newOwner); emit OwnershipTransferred(_oldOwner, _newOwner);
return true; return true;
} }
// Implements Registry // Implements RegistryClient
function addressOf(bytes32 _identifier) public view returns (address) { function addressOf(bytes32 _identifier) public view returns (address) {
return entries[_identifier]; return entries[_identifier];
} }
// Implements Registry
function identifierCount() public view returns(uint256) {
return identifier.length;
}
// Implements ERC165 // Implements ERC165
function supportsInterface(bytes4 _sum) public pure returns (bool) { function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0xeffbf671) { // Registry if (_sum == 0xd719b0cc) { // Registry
return true;
}
if (_sum == 0x93c68796) { // RegistryClient
return true; return true;
} }
if (_sum == 0x01ffc9a7) { // ERC165 if (_sum == 0x01ffc9a7) { // ERC165