From cf4dfe1ed68c21e4c37a7083385a4ab2081c9075 Mon Sep 17 00:00:00 2001 From: Erik van den Brink Date: Mon, 27 Jun 2022 14:28:00 +0200 Subject: [PATCH] Fix fee of CreateMultisigAccount https://github.com/neo-project/neo/pull/2712 & https://github.com/neo-project/neo-node/pull/862 --- neo3/__init__.py | 17 ++++++++++++++++- neo3/contracts/applicationengine.py | 9 ++++++++- neo3/contracts/interop/contract.py | 15 ++++++++++++--- .../contracts/interop/test_contract_interop.py | 2 +- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/neo3/__init__.py b/neo3/__init__.py index cc400c83..958da1c7 100644 --- a/neo3/__init__.py +++ b/neo3/__init__.py @@ -2,6 +2,7 @@ import json import importlib import binascii +from enum import Enum, auto from typing import List from types import SimpleNamespace from neo3.core import cryptography @@ -46,6 +47,13 @@ def __len__(self): def __getitem__(self, key): return self.__dict__[key] + def __contains__(self, key): + try: + self.__dict__[key] + return True + except KeyError: + return False + def get(self, key, default=None): try: return self.__dict__[key] @@ -53,6 +61,10 @@ def get(self, key, default=None): return default +class HardFork(Enum): + HF_2712_FIX_SYSCALL_FEES = auto() + + class Settings(IndexableNamespace): db = None _cached_standby_committee = None @@ -62,7 +74,10 @@ class Settings(IndexableNamespace): 'account_version': 53, 'seedlist': [], 'validators_count': 1, - 'standby_committee': ['02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765'] + 'standby_committee': ['02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765'], + 'hardforks': { + HardFork.HF_2712_FIX_SYSCALL_FEES.name: 2000000 + } }, 'storage': { 'use_default': True, diff --git a/neo3/contracts/applicationengine.py b/neo3/contracts/applicationengine.py index 66a1f837..38063058 100644 --- a/neo3/contracts/applicationengine.py +++ b/neo3/contracts/applicationengine.py @@ -1,5 +1,5 @@ from __future__ import annotations -from neo3 import contracts, storage, vm +from neo3 import contracts, storage, vm, HardFork, settings from neo3.network import payloads from neo3.core import types, cryptography, IInteroperable, serialization, to_script_hash from typing import Any, Dict, cast, List, Tuple, Type, Optional, Union @@ -485,3 +485,10 @@ def _native_to_stackitem(self, value, native_type) -> vm.StackItem: return _struct else: return vm.StackItem.from_interface(value) + + def _is_hardfork_enabled(self, hf: HardFork) -> bool: + if self.snapshot and self.snapshot.persisting_block is None: + return True + if hf.name not in settings.network.hardforks: + return True + return self.snapshot.persisting_block.index >= settings.network.hardforks[hf.name] diff --git a/neo3/contracts/interop/contract.py b/neo3/contracts/interop/contract.py index 7e340ae6..66886fe7 100644 --- a/neo3/contracts/interop/contract.py +++ b/neo3/contracts/interop/contract.py @@ -1,8 +1,9 @@ from __future__ import annotations from typing import List -from neo3 import vm, contracts +from neo3 import vm, contracts, HardFork from neo3.core import cryptography, types, to_script_hash from neo3.contracts.interop import register +from neo3.contracts.interop.crypto import CHECKSIG_PRICE @register("System.Contract.Call", 1 << 15, contracts.CallFlags.READ_STATES | contracts.CallFlags.ALLOW_CALL) @@ -34,16 +35,24 @@ def get_callflags(engine: contracts.ApplicationEngine) -> contracts.CallFlags: return contracts.CallFlags(engine.current_context.call_flags) -@register("System.Contract.CreateStandardAccount", 1 << 8, contracts.CallFlags.NONE) +@register("System.Contract.CreateStandardAccount", 0, contracts.CallFlags.NONE) def contract_create_standard_account(engine: contracts.ApplicationEngine, public_key: cryptography.ECPoint) -> types.UInt160: + fee = 1 << 8 + if engine._is_hardfork_enabled(HardFork.HF_2712_FIX_SYSCALL_FEES): + fee = CHECKSIG_PRICE + engine.add_gas(fee * engine.exec_fee_factor) return to_script_hash(contracts.Contract.create_signature_redeemscript(public_key)) -@register("System.Contract.CreateMultisigAccount", 1 << 8, contracts.CallFlags.NONE) +@register("System.Contract.CreateMultisigAccount", 0, contracts.CallFlags.NONE) def contract_create_multisigaccount(engine: contracts.ApplicationEngine, m: int, public_keys: List[cryptography.ECPoint]) -> types.UInt160: + fee = 1 << 8 + if engine._is_hardfork_enabled(HardFork.HF_2712_FIX_SYSCALL_FEES): + fee = CHECKSIG_PRICE * len(public_keys) + engine.add_gas(fee * engine.exec_fee_factor) return to_script_hash(contracts.Contract.create_multisig_redeemscript(m, public_keys)) diff --git a/tests/contracts/interop/test_contract_interop.py b/tests/contracts/interop/test_contract_interop.py index e5e640d9..cacc78ff 100644 --- a/tests/contracts/interop/test_contract_interop.py +++ b/tests/contracts/interop/test_contract_interop.py @@ -261,7 +261,7 @@ def test_contract_call_flags(self): def test_contract_create_standard_account(self): keypair = cryptography.KeyPair(b'\x01' * 32) - engine = test_engine() + engine = test_engine(has_snapshot=True) engine.push(vm.ByteStringStackItem(keypair.public_key.to_array())) engine.invoke_syscall_by_name("System.Contract.CreateStandardAccount") engine.execute()