diff --git a/solidity/AddressDeclarator.bin b/solidity/AddressDeclarator.bin new file mode 100644 index 0000000..bbcd092 --- /dev/null +++ b/solidity/AddressDeclarator.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162001030380380620010308339818101604052810190620000379190620004a9565b60005b8151811015620000ae57620000973383838151811062000083577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151620000b660201b60201c565b508080620000a59062000565565b9150506200003a565b50506200062b565b600080600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156200034457338160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600380549050908060018154018082558091505060019003906000526020600020016000909190919091505560038190806001815401808255809150506001900390600052602060002090600202016000909190919091506000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001820181600101908054620002e99291906200037a565b505050600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906200033e9062000565565b91905055505b80600101839080600181540180825580915050600190039060005260206000200160009091909190915055600191505092915050565b828054828255906000526020600020908101928215620003be5760005260206000209182015b82811115620003bd578254825591600101919060010190620003a0565b5b509050620003cd9190620003d1565b5090565b5b80821115620003ec576000816000905550600101620003d2565b5090565b600062000407620004018462000522565b620004ee565b905080838252602082019050828560208602820111156200042757600080fd5b60005b858110156200045b578162000440888262000492565b8452602084019350602083019250506001810190506200042a565b5050509392505050565b600082601f8301126200047757600080fd5b815162000489848260208601620003f0565b91505092915050565b600081519050620004a38162000611565b92915050565b600060208284031215620004bc57600080fd5b600082015167ffffffffffffffff811115620004d757600080fd5b620004e58482850162000465565b91505092915050565b6000604051905081810181811067ffffffffffffffff82111715620005185762000517620005e2565b5b8060405250919050565b600067ffffffffffffffff82111562000540576200053f620005e2565b5b602082029050602081019050919050565b6000819050919050565b6000819050919050565b600062000572826200055b565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620005a857620005a7620005b3565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200061c8162000551565b81146200062857600080fd5b50565b6109f5806200063b6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80634cf94740146100515780638c661b3614610081578063ae47ece0146100b1578063d0e95db1146100e1575b600080fd5b61006b60048036038101906100669190610716565b610111565b6040516100789190610804565b60405180910390f35b61009b6004803603810190610096919061069e565b610212565b6040516100a8919061081f565b60405180910390f35b6100cb60048036038101906100c691906106da565b6102f0565b6040516100d89190610841565b60405180910390f35b6100fb60048036038101906100f69190610675565b6105af565b604051610108919061085c565b60405180910390f35b60008060008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020848154811061018c577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001549150600382815481106101d3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020906002020190508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169250505092915050565b60606000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001018054806020026020016040519081016040528092919081815260200182805480156102e257602002820191906000526020600020905b8154815260200190600101908083116102ce575b505050505091505092915050565b600080600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561057957338160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600380549050908060018154018082558091505060019003906000526020600020016000909190919091505560038190806001815401808255809150506001900390600052602060002090600202016000909190919091506000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018201816001019080546105209291906105c7565b505050600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061057390610902565b91905055505b80600101839080600181540180825580915050600190039060005260206000200160009091909190915055600191505092915050565b60016020528060005260406000206000915090505481565b8280548282559060005260206000209081019282156106085760005260206000209182015b828111156106075782548255916001019190600101906105ec565b5b5090506106159190610619565b5090565b5b8082111561063257600081600090555060010161061a565b5090565b6000813590506106458161097a565b92915050565b60008135905061065a81610991565b92915050565b60008135905061066f816109a8565b92915050565b60006020828403121561068757600080fd5b600061069584828501610636565b91505092915050565b600080604083850312156106b157600080fd5b60006106bf85828601610636565b92505060206106d085828601610636565b9150509250929050565b600080604083850312156106ed57600080fd5b60006106fb85828601610636565b925050602061070c8582860161064b565b9150509250929050565b6000806040838503121561072957600080fd5b600061073785828601610636565b925050602061074885828601610660565b9150509250929050565b600061075e83836107e6565b60208301905092915050565b610773816108b0565b82525050565b600061078482610887565b61078e818561089f565b935061079983610877565b8060005b838110156107ca5781516107b18882610752565b97506107bc83610892565b92505060018101905061079d565b5085935050505092915050565b6107e0816108c2565b82525050565b6107ef816108ce565b82525050565b6107fe816108f8565b82525050565b6000602082019050610819600083018461076a565b92915050565b600060208201905081810360008301526108398184610779565b905092915050565b600060208201905061085660008301846107d7565b92915050565b600060208201905061087160008301846107f5565b92915050565b6000819050602082019050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b60006108bb826108d8565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061090d826108f8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156109405761093f61094b565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b610983816108b0565b811461098e57600080fd5b50565b61099a816108ce565b81146109a557600080fd5b50565b6109b1816108f8565b81146109bc57600080fd5b5056fea2646970667358221220018b89b5374b244917beb3e68f94598e291bafd107b142f944885782690e4ab264736f6c63430008000033 \ No newline at end of file diff --git a/solidity/AddressDeclarator.json b/solidity/AddressDeclarator.json new file mode 100644 index 0000000..0a7511e --- /dev/null +++ b/solidity/AddressDeclarator.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bytes32[]","name":"_descriptions","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_subject","type":"address"},{"internalType":"bytes32","name":"_proof","type":"bytes32"}],"name":"addDeclaration","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_declarator","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"declaration","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"declarator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"declaratorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] diff --git a/solidity/AddressDeclarator.sol b/solidity/AddressDeclarator.sol new file mode 100644 index 0000000..d290133 --- /dev/null +++ b/solidity/AddressDeclarator.sol @@ -0,0 +1,55 @@ +pragma solidity >=0.6.12; + +// SPDX-License-Identifier: GPL-3.0-or-later + +contract AddressDeclarator { + + struct declaratorItem { + address signer; + bytes32[] content; + } + + mapping( address => uint256[] ) declaratorItemsIndex; + mapping( address => uint256 ) public declaratorCount; + mapping( address => mapping ( address => declaratorItem ) ) declarationByDeclaratorIndex; + declaratorItem[] declaratorItems; + + constructor(bytes32[] memory _descriptions) { + for (uint i; i < _descriptions.length; i++) { + addDeclaration(msg.sender, _descriptions[i]); + } + } + + function addDeclaration(address _subject, bytes32 _proof) public returns ( bool ) { + declaratorItem storage item; + + item = declarationByDeclaratorIndex[msg.sender][_subject]; + if (item.signer == address(0)) { + item.signer = msg.sender; + declaratorItemsIndex[_subject].push(declaratorItems.length); + declaratorItems.push(item); + declaratorCount[_subject]++; + } + item.content.push(_proof); + + return true; + } + + function declarator(address _target, uint256 _idx) public view returns ( address ) { + uint256 idx; + declaratorItem storage item; + + idx = declaratorItemsIndex[_target][_idx]; + item = declaratorItems[idx]; + + return item.signer; + } + + function declaration(address _declarator, address _target) public view returns ( bytes32[] memory ) { + declaratorItem storage item; + + item = declarationByDeclaratorIndex[_declarator][_target]; + + return item.content; + } +} diff --git a/solidity/Makefile b/solidity/Makefile index de929d9..a03440d 100644 --- a/solidity/Makefile +++ b/solidity/Makefile @@ -1,7 +1,7 @@ all: - solc TokenEndorser.sol --abi | awk 'NR>3' > TokenEndorser.json - solc TokenEndorser.sol --bin | awk 'NR>3' > TokenEndorser.bin - truncate -s -1 TokenEndorser.bin + solc AddressDeclarator.sol --abi | awk 'NR>3' > AddressDeclarator.json + solc AddressDeclarator.sol --bin | awk 'NR>3' > AddressDeclarator.bin + truncate -s -1 AddressDeclarator.bin test: all python test.py diff --git a/solidity/test.py b/solidity/test.py index 2bbd7d8..d52c4ec 100644 --- a/solidity/test.py +++ b/solidity/test.py @@ -19,60 +19,80 @@ provider = web3.Web3.EthereumTesterProvider(instance) w3 = web3.Web3(provider) -f = open('TokenEndorser.bin', 'r') +f = open('AddressDeclarator.bin', 'r') bytecode = f.read() f.close() -f = open('TokenEndorser.json', 'r') +f = open('AddressDeclarator.json', 'r') abi = json.load(f) f.close() -token_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex()) +#token_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex()) c = w3.eth.contract(abi=abi, bytecode=bytecode) -tx_hash = c.constructor().transact({'from': w3.eth.accounts[0]}) +#tx_hash = c.constructor().transact({'from': w3.eth.accounts[0]}) + +declarations = [ + ['0x' + os.urandom(32).hex(), '0x' + os.urandom(32).hex()], + ['0x' + os.urandom(32).hex(), '0x' + os.urandom(32).hex()], + ['0x' + os.urandom(32).hex(), '0x' + os.urandom(32).hex()], + ] + +# Deployment is a self-signed declaration +tx_hash = c.constructor(declarations[0]).transact({'from': w3.eth.accounts[0]}) r = w3.eth.getTransactionReceipt(tx_hash) -logg.debug('contract {} initial token {}'.format(r.contractAddress, token_address)) +logg.debug('contract {}'.format(r.contractAddress)) c = w3.eth.contract(abi=abi, address=r.contractAddress) -d = '0x' + os.urandom(32).hex() -# Initial token will fail in any case -c.functions.add(token_address, d).transact({'from':w3.eth.accounts[0]}) +r = c.functions.declaratorCount(w3.eth.accounts[0]).call() +assert r == 1 -fail = False -try: - c.functions.add(token_address, d).transact({'from':w3.eth.accounts[0]}) -except: - fail = True - pass +r = c.functions.declarator(w3.eth.accounts[0], 0).call() +assert r == w3.eth.accounts[0] -if not fail: - raise RuntimeError('expected fail on register same token to same address') +r = c.functions.declaration(w3.eth.accounts[0], w3.eth.accounts[0]).call() +assert r[0].hex() == declarations[0][0][2:] +assert r[1].hex() == declarations[0][1][2:] -c.functions.add(token_address, d).transact({'from':w3.eth.accounts[1]}) +# Add first declaration for 0 by 2 +c.functions.addDeclaration(w3.eth.accounts[0], declarations[1][0]).transact({'from': w3.eth.accounts[2]}) + +r = c.functions.declaratorCount(w3.eth.accounts[0]).call() +assert r == 2 + +r = c.functions.declarator(w3.eth.accounts[0], 1).call() +assert r == w3.eth.accounts[2] + +r = c.functions.declaration(w3.eth.accounts[2], w3.eth.accounts[0]).call() +assert r[0].hex() == declarations[1][0][2:] -h = hashlib.new('sha256') -h.update(bytes.fromhex(token_address[2:])) -h.update(bytes.fromhex(w3.eth.accounts[0][2:])) -z = h.digest() +# Add second declaration for 0 by 2 +c.functions.addDeclaration(w3.eth.accounts[0], declarations[1][1]).transact({'from': w3.eth.accounts[2]}) -assert d[2:] == c.functions.endorsement(z.hex()).call().hex() +r = c.functions.declaratorCount(w3.eth.accounts[0]).call() +assert r == 2 -another_token_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex()) -c.functions.add(another_token_address, d).transact({'from':w3.eth.accounts[0]}) - -assert c.functions.endorsers(w3.eth.accounts[0], 0).call() == 1 -assert c.functions.endorsers(w3.eth.accounts[1], 0).call() == 1 -assert c.functions.endorsers(w3.eth.accounts[0], 1).call() == 2 - -assert c.functions.tokens(1).call() == token_address -assert c.functions.tokens(2).call() == another_token_address - -assert c.functions.tokenIndex(token_address).call() == 1 -assert c.functions.tokenIndex(another_token_address).call() == 2 +r = c.functions.declaration(w3.eth.accounts[2], w3.eth.accounts[0]).call() +assert r[0].hex() == declarations[1][0][2:] +assert r[1].hex() == declarations[1][1][2:] +# Add first declaration for 1 by 2 +c.functions.addDeclaration(w3.eth.accounts[1], declarations[2][0]).transact({'from': w3.eth.accounts[2]}) + +r = c.functions.declaratorCount(w3.eth.accounts[0]).call() +assert r == 2 + +r = c.functions.declaratorCount(w3.eth.accounts[1]).call() +assert r == 1 + +r = c.functions.declarator(w3.eth.accounts[1], 0).call() +assert r == w3.eth.accounts[2] + +r = c.functions.declaration(w3.eth.accounts[2], w3.eth.accounts[1]).call() +assert r[0].hex() == declarations[2][0][2:] + diff --git a/solidity/tokenendorser_test.py b/solidity/tokenendorser_test.py new file mode 100644 index 0000000..2bbd7d8 --- /dev/null +++ b/solidity/tokenendorser_test.py @@ -0,0 +1,78 @@ +import logging +import os +import json +import hashlib + +import web3 +import eth_tester + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + + +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('TokenEndorser.bin', 'r') +bytecode = f.read() +f.close() + +f = open('TokenEndorser.json', 'r') +abi = json.load(f) +f.close() + +token_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex()) + +c = w3.eth.contract(abi=abi, bytecode=bytecode) +tx_hash = c.constructor().transact({'from': w3.eth.accounts[0]}) +r = w3.eth.getTransactionReceipt(tx_hash) +logg.debug('contract {} initial token {}'.format(r.contractAddress, token_address)) + +c = w3.eth.contract(abi=abi, address=r.contractAddress) +d = '0x' + os.urandom(32).hex() + +# Initial token will fail in any case +c.functions.add(token_address, d).transact({'from':w3.eth.accounts[0]}) + +fail = False +try: + c.functions.add(token_address, d).transact({'from':w3.eth.accounts[0]}) +except: + fail = True + pass + +if not fail: + raise RuntimeError('expected fail on register same token to same address') + + +c.functions.add(token_address, d).transact({'from':w3.eth.accounts[1]}) + + +h = hashlib.new('sha256') +h.update(bytes.fromhex(token_address[2:])) +h.update(bytes.fromhex(w3.eth.accounts[0][2:])) +z = h.digest() + +assert d[2:] == c.functions.endorsement(z.hex()).call().hex() + + +another_token_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex()) +c.functions.add(another_token_address, d).transact({'from':w3.eth.accounts[0]}) + +assert c.functions.endorsers(w3.eth.accounts[0], 0).call() == 1 +assert c.functions.endorsers(w3.eth.accounts[1], 0).call() == 1 +assert c.functions.endorsers(w3.eth.accounts[0], 1).call() == 2 + +assert c.functions.tokens(1).call() == token_address +assert c.functions.tokens(2).call() == another_token_address + +assert c.functions.tokenIndex(token_address).call() == 1 +assert c.functions.tokenIndex(another_token_address).call() == 2 + +