Additional linking object search (#38)

* Withdraw test case improvements
* Additional linking object requests to detect issue details with unreturned Linking object
This commit is contained in:
anatoly-bogatyrev 2021-02-20 17:05:03 +03:00 committed by GitHub
parent 49cc629412
commit 0a47c0a815
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 112 additions and 67 deletions

View file

@ -412,19 +412,40 @@ def search_object(private_key: str, cid: str, keys: str, bearer: str, filters: s
def get_component_objects(private_key: str, cid: str, oid: str): def get_component_objects(private_key: str, cid: str, oid: str):
logger.info("Collect Split objects list from Linked object.") logger.info("Collect Split objects list from Linked object.")
split_id = ""
nodes = _get_storage_nodes() nodes = _get_storage_nodes()
for node in nodes: for node in nodes:
header_virtual = head_object(private_key, cid, oid, '', '', '--raw --ttl 1', node, True) header_virtual = head_object(private_key, cid, oid, '', '', '--raw --ttl 1', node, True)
parsed_header_virtual = parse_object_virtual_raw_header(header_virtual) if header_virtual:
parsed_header_virtual = parse_object_virtual_raw_header(header_virtual)
if 'Linking object' in parsed_header_virtual.keys(): if 'Linking object' in parsed_header_virtual.keys():
return _collect_split_objects_from_header(private_key, cid, parsed_header_virtual)
header_link = head_object(private_key, cid, parsed_header_virtual['Linking object'], '', '', '--raw') elif 'Split ID' in parsed_header_virtual.keys():
header_link_parsed = parse_object_system_header(header_link) logger.info(f"parsed_header_virtual: !@ {parsed_header_virtual}" )
split_id = parsed_header_virtual['Split ID']
return header_link_parsed['Split ChildID'] logger.warn("Linking object has not been found.")
# Get all existing objects
full_obj_list = search_object(private_key, cid, None, None, None, None, '--phy')
# Search expected Linking object
for targer_oid in full_obj_list:
header = head_object(private_key, cid, targer_oid, '', '', '--raw')
header_parsed = parse_object_system_header(header)
if header_parsed['Split ID'] == split_id and 'Split ChildID' in header_parsed.keys():
logger.info("Linking object has been found in additional check (head of all objects).")
return _collect_split_objects_from_header(private_key, cid, parsed_header_virtual)
raise Exception("Linking object is not found at all - all existed objects have been headed.")
def _collect_split_objects_from_header(private_key, cid, parsed_header):
header_link = head_object(private_key, cid, parsed_header['Linking object'], '', '', '--raw')
header_link_parsed = parse_object_system_header(header_link)
return header_link_parsed['Split ChildID']
raise Exception("Linking object has not been found.")
@keyword('Verify Split Chain') @keyword('Verify Split Chain')
@ -689,76 +710,73 @@ def parse_object_system_header(header: str):
# ID # ID
m = re.search(r'^ID: (\w+)', header) m = re.search(r'^ID: (\w+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['ID'] = m.group(1) result_header['ID'] = m.group(1)
else: else:
raise Exception("no ID was parsed from object header: \t%s" % output) raise Exception("no ID was parsed from object header: \t%s" % header)
# CID # CID
m = re.search(r'CID: (\w+)', header) m = re.search(r'CID: (\w+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['CID'] = m.group(1) result_header['CID'] = m.group(1)
else: else:
raise Exception("no CID was parsed from object header: \t%s" % output) raise Exception("no CID was parsed from object header: \t%s" % header)
# Owner # Owner
m = re.search(r'Owner: ([a-zA-Z0-9]+)', header) m = re.search(r'Owner: ([a-zA-Z0-9]+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['OwnerID'] = m.group(1) result_header['OwnerID'] = m.group(1)
else: else:
raise Exception("no OwnerID was parsed from object header: \t%s" % output) raise Exception("no OwnerID was parsed from object header: \t%s" % header)
# CreatedAtEpoch # CreatedAtEpoch
m = re.search(r'CreatedAt: (\d+)', header) m = re.search(r'CreatedAt: (\d+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['CreatedAtEpoch'] = m.group(1) result_header['CreatedAtEpoch'] = m.group(1)
else: else:
raise Exception("no CreatedAtEpoch was parsed from object header: \t%s" % output) raise Exception("no CreatedAtEpoch was parsed from object header: \t%s" % header)
# PayloadLength # PayloadLength
m = re.search(r'Size: (\d+)', header) m = re.search(r'Size: (\d+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['PayloadLength'] = m.group(1) result_header['PayloadLength'] = m.group(1)
else: else:
raise Exception("no PayloadLength was parsed from object header: \t%s" % output) raise Exception("no PayloadLength was parsed from object header: \t%s" % header)
# HomoHash # HomoHash
m = re.search(r'HomoHash:\s+(\w+)', header) m = re.search(r'HomoHash:\s+(\w+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['HomoHash'] = m.group(1) result_header['HomoHash'] = m.group(1)
else: else:
raise Exception("no HomoHash was parsed from object header: \t%s" % output) raise Exception("no HomoHash was parsed from object header: \t%s" % header)
# Checksum # Checksum
m = re.search(r'Checksum:\s+(\w+)', header) m = re.search(r'Checksum:\s+(\w+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['Checksum'] = m.group(1) result_header['Checksum'] = m.group(1)
else: else:
raise Exception("no Checksum was parsed from object header: \t%s" % output) raise Exception("no Checksum was parsed from object header: \t%s" % header)
# Type # Type
m = re.search(r'Type:\s+(\w+)', header) m = re.search(r'Type:\s+(\w+)', header)
if m.start() != m.end(): # e.g., if match found something if m is not None:
result_header['Type'] = m.group(1) result_header['Type'] = m.group(1)
else: else:
raise Exception("no Type was parsed from object header: \t%s" % output) raise Exception("no Type was parsed from object header: \t%s" % header)
# Header - Optional attributes # Header - Optional attributes
m = re.search(r'Split ID:\s+([\w-]+)', header) m = re.search(r'Split ID:\s+([\w-]+)', header)
if m != None: if m is not None:
if m.start() != m.end(): # e.g., if match found something result_header['Split ID'] = m.group(1)
result_header['Split ID'] = m.group(1)
m = re.search(r'Split PreviousID:\s+(\w+)', header) m = re.search(r'Split PreviousID:\s+(\w+)', header)
if m != None: if m is not None:
if m.start() != m.end(): # e.g., if match found something result_header['Split PreviousID'] = m.group(1)
result_header['Split PreviousID'] = m.group(1)
m = re.search(r'Split ParentID:\s+(\w+)', header) m = re.search(r'Split ParentID:\s+(\w+)', header)
if m != None: if m is not None:
if m.start() != m.end(): # e.g., if match found something result_header['Split ParentID'] = m.group(1)
result_header['Split ParentID'] = m.group(1)
# Split ChildID list # Split ChildID list
found_objects = re.findall(r'Split ChildID:\s+(\w+)', header) found_objects = re.findall(r'Split ChildID:\s+(\w+)', header)

View file

@ -121,14 +121,29 @@ def mainnet_balance(address: str):
amount = m.group(1) amount = m.group(1)
return amount return amount
@keyword('Expexted Mainnet Balance') @keyword('Expected Mainnet Balance')
def expected_mainnet_balance(address: str, expected: float): def expected_mainnet_balance(address: str, expected: float):
amount = mainnet_balance(address) amount = mainnet_balance(address)
gas_expected = int(expected * 10**8) gas_expected = int(expected * 10**8)
if int(amount) != int(gas_expected): if int(amount) != int(gas_expected):
raise Exception(f"Expected amount ({gas_expected}) of GAS has not been found. Found {amount}.") raise Exception(f"Expected amount ({gas_expected}) of GAS has not been found. Found {amount}.")
return amount
return True @keyword('Expected Mainnet Balance Diff')
def expected_mainnet_balance_diff(address: str, old_value: float, expected_diff: float):
amount = mainnet_balance(address)
gas_expected = old_value + _convert_int_to_gas(expected_diff)
if int(amount) != int(gas_expected):
raise Exception(f"Balance amount ({int(amount)})) of GAS has not been changed for expected value:",
f"{_convert_int_to_gas(expected_diff)} from initial {old_value}.",
f"Expected: {old_value + _convert_int_to_gas(expected_diff)}")
return amount
def _convert_int_to_gas(input_value: float):
return int(input_value * 10**8)
def _convert_gas_to_int(input_value: float):
return int(input_value / 10**8)
@keyword('NeoFS Deposit') @keyword('NeoFS Deposit')
def neofs_deposit(wallet: str, address: str, scripthash: str, amount: int, wallet_pass:str=''): def neofs_deposit(wallet: str, address: str, scripthash: str, amount: int, wallet_pass:str=''):

View file

@ -39,13 +39,13 @@ Check eACL Deny and Allow All Bearer Filter Requst Equal
@{S_OBJ_H} = Create List ${S_OID_USER} @{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_OTH_HEADER} Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_OTH_HEADER}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl
Search object ${USER_KEY} ${CID} ${EMPTY} ${EMPTY} ${FILE_USR_HEADER} ${S_OBJ_H} Search object ${USER_KEY} ${CID} ${EMPTY} ${EMPTY} ${FILE_USR_HEADER} ${S_OBJ_H}
Head object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} Head object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY}
Get Range ${USER_KEY} ${CID} ${S_OID_USER} s_get_range ${EMPTY} 0:256 Get Range ${USER_KEY} ${CID} ${S_OID_USER} s_get_range ${EMPTY} 0:256
Delete object ${USER_KEY} ${CID} ${D_OID_USER} ${EMPTY} Delete object ${USER_KEY} ${CID} ${D_OID_USER} ${EMPTY}
Set eACL ${USER_KEY} ${CID} ${EACL_DENY_ALL_USER} --await Set eACL ${USER_KEY} ${CID} ${EACL_DENY_ALL_USER} --await
${filters}= Create Dictionary headerType=REQUEST matchType=STRING_EQUAL key=a value=256 ${filters}= Create Dictionary headerType=REQUEST matchType=STRING_EQUAL key=a value=256
${rule1}= Create Dictionary Operation=GET Access=ALLOW Role=USER Filters=${filters} ${rule1}= Create Dictionary Operation=GET Access=ALLOW Role=USER Filters=${filters}

View file

@ -35,16 +35,16 @@ Check eACL Deny and Allow All Bearer Filter Requst NotEqual
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER} ${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${EMPTY} ${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${EMPTY}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER_DEL} ${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER_DEL}
@{S_OBJ_H} = Create List ${S_OID_USER} @{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_OTH_HEADER} Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_OTH_HEADER}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl
Search object ${USER_KEY} ${CID} ${EMPTY} ${EMPTY} ${FILE_USR_HEADER} ${S_OBJ_H} Search object ${USER_KEY} ${CID} ${EMPTY} ${EMPTY} ${FILE_USR_HEADER} ${S_OBJ_H}
Head object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} Head object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY}
Get Range ${USER_KEY} ${CID} ${S_OID_USER} s_get_range ${EMPTY} 0:256 Get Range ${USER_KEY} ${CID} ${S_OID_USER} s_get_range ${EMPTY} 0:256
Delete object ${USER_KEY} ${CID} ${D_OID_USER} ${EMPTY} Delete object ${USER_KEY} ${CID} ${D_OID_USER} ${EMPTY}
Set eACL ${USER_KEY} ${CID} ${EACL_DENY_ALL_USER} --await Set eACL ${USER_KEY} ${CID} ${EACL_DENY_ALL_USER} --await
${filters}= Create Dictionary headerType=REQUEST matchType=STRING_NOT_EQUAL key=a value=256 ${filters}= Create Dictionary headerType=REQUEST matchType=STRING_NOT_EQUAL key=a value=256
${rule1}= Create Dictionary Operation=GET Access=ALLOW Role=USER Filters=${filters} ${rule1}= Create Dictionary Operation=GET Access=ALLOW Role=USER Filters=${filters}

View file

@ -37,7 +37,7 @@ Payment Operations
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 3 Expected Mainnet Balance ${ADDR} 3
${SCRIPT_HASH} = Get ScripHash ${KEY} ${SCRIPT_HASH} = Get ScripHash ${KEY}

View file

@ -43,7 +43,7 @@ Payment Operations
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 3 Expected Mainnet Balance ${ADDR} 3
${SCRIPT_HASH} = Get ScripHash ${KEY} ${SCRIPT_HASH} = Get ScripHash ${KEY}

View file

@ -40,7 +40,7 @@ Payment Operations
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 3 Expected Mainnet Balance ${ADDR} 3
${SCRIPT_HASH} = Get ScripHash ${KEY} ${SCRIPT_HASH} = Get ScripHash ${KEY}

View file

@ -87,7 +87,7 @@ Payment Operations
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 11 Expected Mainnet Balance ${ADDR} 11
${SCRIPT_HASH} = Get ScripHash ${KEY} ${SCRIPT_HASH} = Get ScripHash ${KEY}

View file

@ -19,7 +19,7 @@ NeoFS Object Replication
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 11 Expected Mainnet Balance ${ADDR} 11
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}

View file

@ -20,7 +20,7 @@ NeoFS Complex Object Operations
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 15 Expected Mainnet Balance ${ADDR} 15
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}

View file

@ -20,7 +20,7 @@ NeoFS Simple Object Operations
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 15 Expected Mainnet Balance ${ADDR} 15
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}

View file

@ -20,7 +20,7 @@ NeoFS Complex Storagegroup
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 15 Expected Mainnet Balance ${ADDR} 15
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}

View file

@ -20,7 +20,7 @@ NeoFS Simple Storagegroup
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 15 Expected Mainnet Balance ${ADDR} 15
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}

View file

@ -4,6 +4,10 @@ Variables ../../../variables/common.py
Library ../${RESOURCES}/neofs.py Library ../${RESOURCES}/neofs.py
Library ../${RESOURCES}/payment_neogo.py Library ../${RESOURCES}/payment_neogo.py
*** Variables ***
${DEPOSIT_AMOUNT} = 10
${WITHDRAW_AMOUNT} = 10
*** Test cases *** *** Test cases ***
NeoFS Deposit and Withdraw NeoFS Deposit and Withdraw
[Documentation] Testcase to validate NeoFS Withdraw operation. [Documentation] Testcase to validate NeoFS Withdraw operation.
@ -15,32 +19,39 @@ NeoFS Deposit and Withdraw
${ADDR} = Dump Address ${WALLET} ${ADDR} = Dump Address ${WALLET}
${PRIV_KEY} = Dump PrivKey ${WALLET} ${ADDR} ${PRIV_KEY} = Dump PrivKey ${WALLET} ${ADDR}
${TX} = Transfer Mainnet Gas wallets/wallet.json NTrezR3C4X8aMLVg7vozt5wguyNfFhwuFx ${ADDR} 55 ${TX} = Transfer Mainnet Gas wallets/wallet.json NTrezR3C4X8aMLVg7vozt5wguyNfFhwuFx ${ADDR} 15
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 55 ${MAINNET_BALANCE} = Expected Mainnet Balance ${ADDR} 15
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}
${TX_DEPOSIT} = NeoFS Deposit ${WALLET} ${ADDR} ${SCRIPT_HASH} 50
${TX_DEPOSIT} = NeoFS Deposit ${WALLET} ${ADDR} ${SCRIPT_HASH} ${DEPOSIT_AMOUNT}
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX_DEPOSIT} ... Transaction accepted in block ${TX_DEPOSIT}
Get Transaction ${TX_DEPOSIT} Get Transaction ${TX_DEPOSIT}
Sleep 1 min Sleep 1 min
Expexted Mainnet Balance ${ADDR} 4.85067180 # Expected amount diff will be formed from deposit amount and contract fee
${EXPECTED_DIFF} = Evaluate -${DEPOSIT_AMOUNT}-${NEOFS_CONTRACT_DEPOSIT_GAS_FEE}
${DEPOSIT_BALANCE} = Expected Mainnet Balance Diff ${ADDR} ${MAINNET_BALANCE} ${EXPECTED_DIFF}
${NEOFS_BALANCE} = Get Balance ${PRIV_KEY} ${NEOFS_BALANCE} = Get Balance ${PRIV_KEY}
${TX} = Withdraw Mainnet Gas ${WALLET} ${ADDR} ${SCRIPT_HASH} 50 ${TX} = Withdraw Mainnet Gas ${WALLET} ${ADDR} ${SCRIPT_HASH} ${WITHDRAW_AMOUNT}
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Sleep 1 min Sleep 1 min
Get Balance ${PRIV_KEY} Get Balance ${PRIV_KEY}
Expected Balance ${PRIV_KEY} ${NEOFS_BALANCE} -50 Expected Balance ${PRIV_KEY} ${NEOFS_BALANCE} -${WITHDRAW_AMOUNT}
Expexted Mainnet Balance ${ADDR} 54.81748270
# Expected amount diff will be formed from withdrawal amount and contract fee
${EXPECTED_DIFF_W} = Evaluate ${WITHDRAW_AMOUNT}-${NEOFS_CONTRACT_WITHDRAW_GAS_FEE}
Expected Mainnet Balance Diff ${ADDR} ${DEPOSIT_BALANCE} ${EXPECTED_DIFF_W}
[Teardown] Cleanup [Teardown] Cleanup

View file

@ -22,7 +22,7 @@ NeoFS HTTP Gateway
Wait Until Keyword Succeeds 1 min 15 sec Wait Until Keyword Succeeds 1 min 15 sec
... Transaction accepted in block ${TX} ... Transaction accepted in block ${TX}
Get Transaction ${TX} Get Transaction ${TX}
Expexted Mainnet Balance ${ADDR} 6 Expected Mainnet Balance ${ADDR} 6
${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY} ${SCRIPT_HASH} = Get ScripHash ${PRIV_KEY}

View file

@ -9,5 +9,6 @@ CERT="%s/../../ca" % ROOT
# in case when test is run from root in docker # in case when test is run from root in docker
ABSOLUTE_FILE_PATH="/robot/testsuites/integration" ABSOLUTE_FILE_PATH="/robot/testsuites/integration"
MORPH_BLOCK_TIMEOUT = "10sec" # Price of the contract Deposit execution: 0.1493182 GAS
NEOFS_EPOCH_TIMEOUT = "30sec" NEOFS_CONTRACT_DEPOSIT_GAS_FEE = 0.1493182
NEOFS_CONTRACT_WITHDRAW_GAS_FEE = 0.0331791