Skip to content

Commit

Permalink
Merge pull request #171 from skalenetwork/enhancement/SKALE-1242-supp…
Browse files Browse the repository at this point in the history
…ort-predeployed-ima

Enhancement/skale 1242 support predeployed ima
  • Loading branch information
dmytrotkk authored May 14, 2020
2 parents c0f8cd8 + 29c6fe7 commit 6a70781
Show file tree
Hide file tree
Showing 8 changed files with 3,418 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ wallet*.json
creds.tar.gz
data.json
schain.json
sample_config.json

abi.json
test_abi.json
Expand Down
33 changes: 33 additions & 0 deletions skale/schain_config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,37 @@

PORTS_PER_SCHAIN = 11

PRECOMPILED_IMA_CONTRACTS = {
'skale_features': {
'filename': 'SkaleFeatures'
},
'lock_and_data_for_schain': {
'filename': 'LockAndDataForSchain'
},
'eth_erc20': {
'filename': 'EthERC20'
},
'token_manager': {
'filename': 'TokenManager'
},
'lock_and_data_for_schain_erc20': {
'filename': 'LockAndDataForSchainERC20'
},
'erc20_module_for_schain': {
'filename': 'ERC20ModuleForSchain'
},
'lock_and_data_for_schain_erc721': {
'filename': 'LockAndDataForSchainERC721'
},
'erc721_module_for_schain': {
'filename': 'ERC721ModuleForSchain'
},
'token_factory': {
'filename': 'TokenFactory'
},
'message_proxy_chain': {
'filename': 'MessageProxyForSchain'
}
}

from skale.schain_config.generator import generate_skale_schain_config
44 changes: 28 additions & 16 deletions skale/schain_config/base_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,57 @@
from web3 import Web3
from Crypto.Hash import keccak

from skale.schain_config import NODE_OWNER_ALLOC, SCHAIN_OWNER_ALLOC
from skale.schain_config import NODE_OWNER_ALLOC, SCHAIN_OWNER_ALLOC, PRECOMPILED_IMA_CONTRACTS


def add_to_accounts(allocation, account, amount, code=None, storage={}, nonce=0):
def add_to_accounts(accounts, account, balance, code=None, storage={}, nonce=0):
assert isinstance(code, str) or code is None
assert isinstance(storage, dict) or storage is None
acc_fx = Web3.toChecksumAddress(account)
if str(acc_fx) not in allocation:
allocation[acc_fx] = {"balance": str(amount)}
if str(acc_fx) not in accounts:
accounts[acc_fx] = {"balance": str(balance)}
if code:
allocation[acc_fx]['code'] = code
allocation[acc_fx]['storage'] = storage
allocation[acc_fx]['nonce'] = str(nonce)
accounts[acc_fx]['code'] = code
accounts[acc_fx]['storage'] = storage
accounts[acc_fx]['nonce'] = str(nonce)


def update_accounts(schain, schain_nodes):
allocation = {}
add_to_accounts(allocation, schain['owner'], SCHAIN_OWNER_ALLOC)
def update_accounts(schain, schain_nodes, ima_data=None):
accounts = {}
add_to_accounts(accounts, schain['owner'], SCHAIN_OWNER_ALLOC)
for node in schain_nodes:
if str(node['owner']) not in allocation:
add_to_accounts(allocation, node['owner'], NODE_OWNER_ALLOC)
if str(node['owner']) not in accounts:
add_to_accounts(accounts, node['owner'], NODE_OWNER_ALLOC)
add_to_accounts(
allocation,
accounts,
'0xD2001000000000000000000000000000000000D2',
0,
*_generate_context_predeployed_smart_contract(
schain['owner'],
schain['name']
)
)
return allocation
if ima_data:
add_ima_accounts(accounts, ima_data)
return accounts


def update_base_config(base_config, schain, schain_nodes):
new_accounts = update_accounts(schain, schain_nodes)
def update_base_config(base_config, schain, schain_nodes, ima_data=None):
new_accounts = update_accounts(schain, schain_nodes, ima_data=ima_data)
base_config['accounts'] = {**base_config['accounts'], **new_accounts}
add_chain_id(base_config, schain['name'])


def add_ima_accounts(accounts, ima_data):
for contract_name in PRECOMPILED_IMA_CONTRACTS:
add_to_accounts(
accounts=accounts,
account=ima_data[f'{contract_name}_address'],
balance=0,
code=ima_data[f'{contract_name}_bytecode'],
)


def _generate_context_predeployed_smart_contract(owner_address: str,
schain_name: str) -> (str, dict):
code = ('0x608060405234801561001057600080fd5b506004361061005e576000357c0100' +
Expand Down
80 changes: 75 additions & 5 deletions skale/schain_config/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with SKALE.py. If not, see <https://www.gnu.org/licenses/>.

from web3 import Web3

from skale.dataclasses import CurrentNodeInfo, SchainNodeInfo
from skale.schain_config.ports_allocation import get_schain_base_port_on_node
from skale.utils.helper import ip_from_bytes
from skale.schain_config import PRECOMPILED_IMA_CONTRACTS
from skale.utils.helper import ip_from_bytes, decapitalize
from skale.utils.web3_utils import public_key_to_address
from skale.schain_config.base_config import update_base_config

Expand Down Expand Up @@ -67,10 +70,71 @@ def get_nodes_for_schain_config(skale, name):
return nodes_info


def generate_schain_config(base_config, node_info, schain_info):
def get_contract_address_from_ima_data(ima_data, name):
return ima_data[f'{name}_address']


def generate_permitted_ima_contracts_info(ima_data):
permitted_contracts = {}
for name in PRECOMPILED_IMA_CONTRACTS:
contract_filename = PRECOMPILED_IMA_CONTRACTS[name]['filename']
permitted_contracts[contract_filename] = get_contract_address_from_ima_data(ima_data, name)
return permitted_contracts


def generate_mp_authorized_callers(ima_data, schain_owner, schain_nodes):
mp_authorized_callers = {}
for name in PRECOMPILED_IMA_CONTRACTS:
address = get_contract_address_from_ima_data(ima_data, name)
mp_authorized_callers[address] = 1
for node in schain_nodes:
acc_fx = Web3.toChecksumAddress(node['owner'])
if not mp_authorized_callers.get(acc_fx, None):
mp_authorized_callers[acc_fx] = 1
schain_owner_fx = Web3.toChecksumAddress(schain_owner)
if not mp_authorized_callers.get(schain_owner_fx, None):
mp_authorized_callers[schain_owner_fx] = 1
return mp_authorized_callers


def generate_ima_contracts_addresses(ima_data):
ima_contracts_addresses = {}
for name in PRECOMPILED_IMA_CONTRACTS:
contract_filename = PRECOMPILED_IMA_CONTRACTS[name]['filename']
address = get_contract_address_from_ima_data(ima_data, name)
ima_contracts_addresses[decapitalize(contract_filename)] = address
return ima_contracts_addresses


def generate_schain_contract_settings(ima_data, schain_owner, schain_nodes):
# todo: refactor
permitted_contracts = generate_permitted_ima_contracts_info(ima_data)
mp_authorized_callers = generate_mp_authorized_callers(ima_data, schain_owner, schain_nodes)
ima_contracts_addresses = generate_ima_contracts_addresses(ima_data)
return {
'common': {
'enableContractLogMessages': False
},
'IMA': {
'ownerAddress': schain_owner,
'variables': {
'LockAndDataForSchain': {
'permitted': permitted_contracts
},
'MessageProxyForSchain': {
'mapAuthorizedCallers': mp_authorized_callers
}
},
**ima_contracts_addresses
}
}


def generate_schain_config(base_config, node_info, schain_info, schain_contract_settings={}):
return {
**base_config,
'skaleConfig': {
'contractSettings': schain_contract_settings,
'nodeInfo': node_info,
'sChain': schain_info,
}
Expand All @@ -79,7 +143,7 @@ def generate_schain_config(base_config, node_info, schain_info):

def generate_skale_schain_config(skale, schain_name, node_id, base_config=None, ima_mainnet=None,
ima_mp_schain=None, ima_mp_mainnet=None, wallets=None,
rotate_after_block=64, schain_log_level='info',
ima_data=None, rotate_after_block=64, schain_log_level='info',
schain_log_level_config='info'):
node = skale.nodes_data.get(node_id)
schain = skale.schains_data.get_by_name(schain_name)
Expand All @@ -105,11 +169,17 @@ def generate_skale_schain_config(skale, schain_name, node_id, base_config=None,
schain_info = generate_schain_info(schain, schain_nodes)

if base_config:
update_base_config(base_config, schain, schain_nodes)
update_base_config(base_config, schain, schain_nodes, ima_data=ima_data)
else:
base_config = {}
if ima_data:
schain_contract_settings = generate_schain_contract_settings(ima_data, schain['owner'],
schain_nodes)
else:
schain_contract_settings = {}
return generate_schain_config(
base_config=base_config,
node_info=node_info,
schain_info=schain_info
schain_info=schain_info,
schain_contract_settings=schain_contract_settings
)
4 changes: 4 additions & 0 deletions skale/utils/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
logger = logging.getLogger(__name__)


def decapitalize(s):
return s[:1].lower() + s[1:] if s else ''


def format_fields(fields):
"""
Transform array to object with passed fields
Expand Down
1 change: 1 addition & 0 deletions tests/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@


TEST_ABI_FILEPATH = os.path.join(DIR_PATH, os.pardir, 'test_abi.json')
IMA_DATA_FILEPATH = os.path.join(DIR_PATH, 'ima_data_sample.json')
ETH_PRIVATE_KEY = os.environ['ETH_PRIVATE_KEY']

# constants contract
Expand Down
Loading

0 comments on commit 6a70781

Please sign in to comment.