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
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
def parse_address_of(self, 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):
if len(identifier_string) > 32:
raise ValueError('String too long')
enc = ABIContractEncoder()
enc.method('set')
enc.typ(ABIContractType.BYTES32)

View File

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

View File

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

View File

@ -1,4 +1,3 @@
pytest==6.0.1
eth-tester==0.5.0b3
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
import os
import unittest
import json
import logging
import hashlib
# 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 (
ABIContractEncoder,
ABIContractType,
abi_decode_single,
)
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from giftable_erc20_token import GiftableToken
from chainlib.eth.address import to_checksum_address
from hexathon import (
add_0x,
strip_0x,
same as same_hex,
)
add_0x,
strip_0x,
)
# local imports
from eth_contract_registry.registry import ContractRegistry
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()
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):
super(TestContractRegistry, self).setUp()
self.registry_ids = ['FOo', 'Bar', 'baz', 'XYZZY']
nonce_oracle = RPCNonceOracle(roles['CONTRACT_DEPLOYER'], eth_rpc)
builder = ContractRegistry(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = ContractRegistry(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash_hex, o) = c.constructor(self.accounts[0], self.registry_ids)
self.rpc.do(o)
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)
o = builder.address_of(registry, 'ContractRegistry', sender_address=eth_accounts[0])
r = eth_rpc.do(o)
r = abi_decode_single(ABIContractType.ADDRESS, r)
assert r == strip_0x(registry)
(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):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = ContractRegistry(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash_hex, o) = c.set(self.address, self.accounts[0], 'FOO', self.address)
r = self.rpc.do(o)
o = receipt(tx_hash_hex)
r = self.rpc.do(o)
self.assertEqual(r['status'], 0)
(tx_hash_hex, o) = builder.set(registry, roles['CONTRACT_DEPLOYER'], 'FooContract', addr_foo)
r = eth_rpc.do(o)
o = receipt(r)
rcpt = eth_rpc.do(o)
assert rcpt['status'] == 1
(tx_hash_hex, o) = c.set(self.address, self.accounts[0], 'FOo', self.address)
r = self.rpc.do(o)
o = receipt(tx_hash_hex)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
builder = Registry(default_chain_spec)
o = builder.address_of(registry, 'FooContract', sender_address=eth_accounts[0])
r = eth_rpc.do(o)
r = abi_decode_single(ABIContractType.ADDRESS, r)
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
// SPDX-License-Identifier: AGPL-3.0-or-later
// File-version: 4
// Description: Keyed smart contract registry
// SPDX-License-Identifier: GPL-3.0-or-later
// File-version: 2
// Description: Top-level smart contract registry for the CIC network
contract ContractRegistry {
mapping (bytes32 => address) entries;
contract CICRegistry {
// Implements ERC173
address public owner;
// Implements Registry
bytes32[] public identifier;
// Implements RegistryClient
bytes32[] public identifiers;
mapping (bytes32 => address) entries; // contractidentifier -> address
mapping (bytes32 => bytes32[]) entryBindings; // contractidentifier -> chainidentifier
// Implements ERC173
event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
// Implements Registry
event AddressKey(bytes32 indexed _key, address _address);
constructor(bytes32[] memory _identifiers) {
owner = msg.sender;
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) {
require(msg.sender == owner);
require(entries[_identifier] == address(0));
require(_address != address(0));
bool found = false;
for (uint i = 0; i < identifier.length; i++) {
if (identifier[i] == _identifier) {
for (uint i = 0; i < identifiers.length; i++) {
if (identifiers[i] == _identifier) {
found = true;
}
}
require(found);
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;
}
@ -53,26 +56,24 @@ contract ContractRegistry {
function transferOwnership(address _newOwner) public returns (bool) {
address _oldOwner;
require(msg.sender == owner, 'ERR_AXX');
require(msg.sender == owner);
_oldOwner = owner;
owner = _newOwner;
emit OwnershipTransferred(_oldOwner, _newOwner);
return true;
}
// Implements Registry
// Implements RegistryClient
function addressOf(bytes32 _identifier) public view returns (address) {
return entries[_identifier];
}
// Implements Registry
function identifierCount() public view returns(uint256) {
return identifier.length;
}
// Implements ERC165
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0xeffbf671) { // Registry
if (_sum == 0xd719b0cc) { // Registry
return true;
}
if (_sum == 0x93c68796) { // RegistryClient
return true;
}
if (_sum == 0x01ffc9a7) { // ERC165