RAHHH
This commit is contained in:
471
backend/lib/python3.12/site-packages/autobahn/xbr/_frealm.py
Normal file
471
backend/lib/python3.12/site-packages/autobahn/xbr/_frealm.py
Normal file
@@ -0,0 +1,471 @@
|
||||
###############################################################################
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) typedef int GmbH
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
import os
|
||||
from binascii import b2a_hex
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
import web3
|
||||
from web3.contract import Contract
|
||||
from ens import ENS
|
||||
|
||||
from twisted.internet.defer import Deferred, inlineCallbacks
|
||||
from twisted.internet.threads import deferToThread
|
||||
|
||||
from autobahn.wamp.interfaces import ICryptosignKey, IEthereumKey
|
||||
from autobahn.wamp.message import identify_realm_name_category
|
||||
from autobahn.xbr import make_w3, EIP712AuthorityCertificate
|
||||
|
||||
|
||||
class Seeder(object):
|
||||
"""
|
||||
|
||||
"""
|
||||
__slots__ = (
|
||||
'_frealm',
|
||||
'_operator',
|
||||
'_label',
|
||||
'_country',
|
||||
'_legal',
|
||||
'_endpoint',
|
||||
'_bandwidth_requested',
|
||||
'_bandwidth_offered',
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
frealm: 'FederatedRealm',
|
||||
operator: Optional[str] = None,
|
||||
label: Optional[str] = None,
|
||||
country: Optional[str] = None,
|
||||
legal: Optional[str] = None,
|
||||
endpoint: Optional[str] = None,
|
||||
bandwidth_requested: Optional[int] = None,
|
||||
bandwidth_offered: Optional[int] = None,
|
||||
):
|
||||
"""
|
||||
|
||||
:param frealm:
|
||||
:param operator:
|
||||
:param label:
|
||||
:param country:
|
||||
:param legal:
|
||||
:param endpoint:
|
||||
:param bandwidth_requested:
|
||||
:param bandwidth_offered:
|
||||
"""
|
||||
self._frealm: FederatedRealm = frealm
|
||||
self._operator: Optional[str] = operator
|
||||
self._label: Optional[str] = label
|
||||
self._country: Optional[str] = country
|
||||
self._legal: Optional[str] = legal
|
||||
self._endpoint: Optional[str] = endpoint
|
||||
self._bandwidth_requested: Optional[str] = bandwidth_requested
|
||||
self._bandwidth_offered: Optional[str] = bandwidth_offered
|
||||
|
||||
@staticmethod
|
||||
def _create_eip712_connect(chain_id: int,
|
||||
verifying_contract: bytes,
|
||||
channel_binding: str,
|
||||
channel_id: bytes,
|
||||
block_no: int,
|
||||
challenge: bytes,
|
||||
pubkey: bytes,
|
||||
realm: bytes,
|
||||
delegate: bytes,
|
||||
seeder: bytes,
|
||||
bandwidth: int):
|
||||
channel_binding = channel_binding or ''
|
||||
channel_id = channel_id or b''
|
||||
assert chain_id
|
||||
assert verifying_contract
|
||||
assert channel_binding is not None
|
||||
assert channel_id is not None
|
||||
assert block_no
|
||||
assert challenge
|
||||
assert pubkey
|
||||
assert realm
|
||||
assert delegate
|
||||
assert bandwidth
|
||||
|
||||
data = {
|
||||
'types': {
|
||||
'EIP712Domain': [
|
||||
{
|
||||
'name': 'name',
|
||||
'type': 'string'
|
||||
},
|
||||
{
|
||||
'name': 'version',
|
||||
'type': 'string'
|
||||
},
|
||||
],
|
||||
'EIP712SeederConnect': [
|
||||
{
|
||||
'name': 'chainId',
|
||||
'type': 'uint256'
|
||||
},
|
||||
{
|
||||
'name': 'verifyingContract',
|
||||
'type': 'address'
|
||||
},
|
||||
{
|
||||
'name': 'channel_binding',
|
||||
'type': 'string'
|
||||
},
|
||||
{
|
||||
'name': 'channel_id',
|
||||
'type': 'bytes32'
|
||||
},
|
||||
{
|
||||
'name': 'block_no',
|
||||
'type': 'uint256'
|
||||
},
|
||||
{
|
||||
'name': 'challenge',
|
||||
'type': 'bytes32'
|
||||
},
|
||||
{
|
||||
'name': 'pubkey',
|
||||
'type': 'bytes32'
|
||||
},
|
||||
{
|
||||
'name': 'realm',
|
||||
'type': 'address'
|
||||
},
|
||||
{
|
||||
'name': 'delegate',
|
||||
'type': 'address'
|
||||
},
|
||||
{
|
||||
'name': 'seeder',
|
||||
'type': 'address'
|
||||
},
|
||||
{
|
||||
'name': 'bandwidth',
|
||||
'type': 'uint32'
|
||||
},
|
||||
]
|
||||
},
|
||||
'primaryType': 'EIP712SeederConnect',
|
||||
'domain': {
|
||||
'name': 'XBR',
|
||||
'version': '1',
|
||||
},
|
||||
'message': {
|
||||
'chainId': chain_id,
|
||||
'verifyingContract': verifying_contract,
|
||||
'channel_binding': channel_binding,
|
||||
'channel_id': channel_id,
|
||||
'block_no': block_no,
|
||||
'challenge': challenge,
|
||||
'pubkey': pubkey,
|
||||
'realm': realm,
|
||||
'delegate': delegate,
|
||||
'seeder': seeder,
|
||||
'bandwidth': bandwidth,
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
@inlineCallbacks
|
||||
def create_authextra(self,
|
||||
client_key: ICryptosignKey,
|
||||
delegate_key: IEthereumKey,
|
||||
bandwidth_requested: int,
|
||||
channel_id: Optional[bytes] = None,
|
||||
channel_binding: Optional[str] = None) -> Deferred:
|
||||
"""
|
||||
|
||||
:param client_key:
|
||||
:param delegate_key:
|
||||
:param bandwidth_requested:
|
||||
:param channel_id:
|
||||
:param channel_binding:
|
||||
:return:
|
||||
"""
|
||||
chain_id = 1
|
||||
# FIXME
|
||||
verifying_contract = b'\x01' * 20
|
||||
block_no = 1
|
||||
challenge = os.urandom(32)
|
||||
eip712_data = Seeder._create_eip712_connect(chain_id=chain_id,
|
||||
verifying_contract=verifying_contract,
|
||||
channel_binding=channel_binding,
|
||||
channel_id=channel_id,
|
||||
block_no=block_no,
|
||||
challenge=challenge,
|
||||
pubkey=client_key.public_key(binary=True),
|
||||
# FIXME
|
||||
# realm=self._frealm.address(binary=True),
|
||||
realm=b'\x02' * 20,
|
||||
delegate=delegate_key.address(binary=False),
|
||||
# FIXME
|
||||
# seeder=self._operator,
|
||||
seeder=b'\x03' * 20,
|
||||
bandwidth=bandwidth_requested)
|
||||
signature = yield delegate_key.sign_typed_data(eip712_data)
|
||||
authextra = {
|
||||
# string
|
||||
'pubkey': client_key.public_key(binary=False),
|
||||
|
||||
# string
|
||||
'challenge': challenge,
|
||||
|
||||
# string
|
||||
'channel_binding': channel_binding,
|
||||
|
||||
# string
|
||||
'channel_id': channel_id,
|
||||
|
||||
# address
|
||||
# FIXME
|
||||
'realm': '7f' * 20,
|
||||
|
||||
# int
|
||||
'chain_id': chain_id,
|
||||
|
||||
# int
|
||||
'block_no': block_no,
|
||||
|
||||
# address
|
||||
'delegate': delegate_key.address(binary=False),
|
||||
|
||||
# address
|
||||
'seeder': self._operator,
|
||||
|
||||
# int: requested bandwidth in kbps
|
||||
'bandwidth': bandwidth_requested,
|
||||
|
||||
# string: Eth signature by delegate_key over EIP712 typed data as above
|
||||
'signature': b2a_hex(signature).decode(),
|
||||
}
|
||||
return authextra
|
||||
|
||||
@property
|
||||
def frealm(self) -> 'FederatedRealm':
|
||||
"""
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self._frealm
|
||||
|
||||
@property
|
||||
def operator(self) -> Optional[str]:
|
||||
"""
|
||||
Operator address, e.g. ``"0xe59C7418403CF1D973485B36660728a5f4A8fF9c"``.
|
||||
|
||||
:return: The Ethereum address of the endpoint operator.
|
||||
"""
|
||||
return self._operator
|
||||
|
||||
@property
|
||||
def label(self) -> Optional[str]:
|
||||
"""
|
||||
Operator endpoint label.
|
||||
|
||||
:return: A human readable label for the operator or specific operator endpoint.
|
||||
"""
|
||||
return self._label
|
||||
|
||||
@property
|
||||
def country(self) -> Optional[str]:
|
||||
"""
|
||||
Operator country (ISO 3166-1 alpha-2), e.g. ``"US"``.
|
||||
|
||||
:return: ISO 3166-1 alpha-2 country code.
|
||||
"""
|
||||
return self._country
|
||||
|
||||
@property
|
||||
def legal(self) -> Optional[str]:
|
||||
"""
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self._legal
|
||||
|
||||
@property
|
||||
def endpoint(self) -> Optional[str]:
|
||||
"""
|
||||
Public WAMP endpoint of seeder. Secure WebSocket URL resolving to a public IPv4
|
||||
or IPv6 listening url accepting incoming WAMP-WebSocket connections,
|
||||
e.g. ``wss://service1.example.com/ws``.
|
||||
|
||||
:return: The endpoint URL.
|
||||
"""
|
||||
return self._endpoint
|
||||
|
||||
@property
|
||||
def bandwidth_requested(self) -> Optional[int]:
|
||||
"""
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self._bandwidth_requested
|
||||
|
||||
@property
|
||||
def bandwidth_offered(self) -> Optional[int]:
|
||||
"""
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self._bandwidth_offered
|
||||
|
||||
|
||||
class FederatedRealm(object):
|
||||
"""
|
||||
A federated realm is a WAMP application realm with a trust anchor rooted in Ethereum, and
|
||||
which can be shared between multiple parties.
|
||||
|
||||
A federated realm is globally identified on an Ethereum chain (e.g. on Mainnet or Rinkeby)
|
||||
by an Ethereum address associated to a federated realm owner by an on-chain record stored
|
||||
in the WAMP Network contract. The federated realm address thus only needs to exist as an
|
||||
identifier of the federated realm-owner record.
|
||||
"""
|
||||
__slots__ = (
|
||||
'_name_or_address',
|
||||
'_gateway_config',
|
||||
'_status',
|
||||
'_name_category',
|
||||
'_w3',
|
||||
'_ens',
|
||||
'_address',
|
||||
'_contract',
|
||||
|
||||
'_seeders',
|
||||
'_root_ca',
|
||||
'_catalog',
|
||||
'_meta',
|
||||
)
|
||||
# FIXME
|
||||
CONTRACT_ADDRESS = web3.Web3.toChecksumAddress('0xF7acf1C4CB4a9550B8969576573C2688B48988C2')
|
||||
CONTRACT_ABI: str = ''
|
||||
|
||||
def __init__(self, name_or_address: str, gateway_config: Optional[Dict[str, Any]] = None):
|
||||
"""
|
||||
Instantiate a federated realm from a federated realm ENS name (which is resolved to an Ethereum
|
||||
address) or Ethereum address.
|
||||
|
||||
:param name_or_address: Ethereum ENS name or address.
|
||||
:param gateway_config: If provided, use this Ethereum gateway. If not provided,
|
||||
connect via Infura to Ethereum Mainnet, which requires an environment variable
|
||||
``WEB3_INFURA_PROJECT_ID`` with your Infura project ID.
|
||||
"""
|
||||
self._name_or_address = name_or_address
|
||||
self._gateway_config = gateway_config
|
||||
|
||||
# status, will change to 'RUNNING' after initialize() has completed
|
||||
self._status = 'STOPPED'
|
||||
|
||||
self._name_category: Optional[str] = identify_realm_name_category(self._name_or_address)
|
||||
if self._name_category not in ['eth', 'ens', 'reverse_ens']:
|
||||
raise ValueError('name_or_address "{}" not an Ethereum address or ENS name'.format(self._name_or_address))
|
||||
|
||||
# will be filled once initialize()'ed
|
||||
self._w3 = None
|
||||
self._ens = None
|
||||
|
||||
# address identifying the federated realm
|
||||
self._address: Optional[str] = None
|
||||
|
||||
# will be initialized with a FederatedRealm contract instance
|
||||
self._contract: Optional[Contract] = None
|
||||
|
||||
# cache of federated realm seeders, filled once in status running
|
||||
self._seeders: List[Seeder] = []
|
||||
|
||||
self._root_ca = None
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._status
|
||||
|
||||
@property
|
||||
def name_or_address(self) -> str:
|
||||
return self._name_or_address
|
||||
|
||||
@property
|
||||
def gateway_config(self) -> Optional[Dict[str, Any]]:
|
||||
return self._gateway_config
|
||||
|
||||
@property
|
||||
def name_category(self) -> Optional[str]:
|
||||
return self._name_category
|
||||
|
||||
@property
|
||||
def address(self):
|
||||
return self._address
|
||||
|
||||
def root_ca(self) -> EIP712AuthorityCertificate:
|
||||
assert self._status == 'RUNNING'
|
||||
return self._root_ca
|
||||
|
||||
@property
|
||||
def seeders(self) -> List[Seeder]:
|
||||
return self._seeders
|
||||
|
||||
def initialize(self):
|
||||
"""
|
||||
|
||||
:return:
|
||||
"""
|
||||
if self._status != 'STOPPED':
|
||||
raise RuntimeError('cannot start in status "{}"'.format(self._status))
|
||||
d = deferToThread(self._initialize_background)
|
||||
return d
|
||||
|
||||
def _initialize_background(self):
|
||||
self._status = 'STARTING'
|
||||
|
||||
if self._gateway_config:
|
||||
self._w3 = make_w3(self._gateway_config)
|
||||
else:
|
||||
raise RuntimeError('cannot auto-configure ethereum connection (was removed from web3.py in v6)')
|
||||
# https://github.com/ethereum/web3.py/issues/1416
|
||||
# https://github.com/ethereum/web3.py/pull/2706
|
||||
# from web3.auto.infura import w3
|
||||
# self._w3 = w3
|
||||
self._ens = ENS.from_web3(self._w3)
|
||||
|
||||
if self._name_category in ['ens', 'reverse_ens']:
|
||||
if self._name_category == 'reverse_ens':
|
||||
name = ''.join(reversed(self._name_or_address.split('.')))
|
||||
else:
|
||||
name = self._name_or_address
|
||||
self._address = self._ens.address(name)
|
||||
elif self._name_category == 'eth':
|
||||
self._address = self._w3.toChecksumAddress(self._name_or_address)
|
||||
else:
|
||||
assert False, 'should not arrive here'
|
||||
|
||||
# https://web3py.readthedocs.io/en/stable/contracts.html#web3.contract.Contract
|
||||
# https://web3py.readthedocs.io/en/stable/web3.eth.html#web3.eth.Eth.contract
|
||||
# self._contract = self._w3.eth.contract(address=self.CONTRACT_ADDRESS, abi=self.CONTRACT_ABI)
|
||||
|
||||
# FIXME: get IPFS hash, download file, unzip seeders
|
||||
|
||||
self._status = 'RUNNING'
|
||||
Reference in New Issue
Block a user