diff --git a/cli/nep_test/nep17_test.go b/cli/nep_test/nep17_test.go
index 9428b8d06a..a9340b3eb1 100644
--- a/cli/nep_test/nep17_test.go
+++ b/cli/nep_test/nep17_test.go
@@ -11,6 +11,7 @@ import (
 	"testing"
 
 	"github.com/nspcc-dev/neo-go/internal/testcli"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
@@ -273,7 +274,7 @@ func TestNEP17Transfer(t *testing.T) {
 		e.CheckAwaitableTxPersisted(t)
 	})
 
-	cmd = append(cmd, "--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
+	cmd = append(cmd, "--to", address.Uint160ToString(nativehashes.Notary),
 		"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]")
 
 	t.Run("with data", func(t *testing.T) {
diff --git a/cli/vm/cli_test.go b/cli/vm/cli_test.go
index defe957e4f..84254428ba 100644
--- a/cli/vm/cli_test.go
+++ b/cli/vm/cli_test.go
@@ -130,7 +130,6 @@ func newTestVMClIWithState(t *testing.T) *executor {
 	require.NoError(t, err)
 	customConfig := func(c *config.Blockchain) {
 		c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
-		c.P2PSigExtensions = true  // Need for basic chain initializer.
 	}
 	bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
 	require.NoError(t, err)
diff --git a/config/protocol.unit_testnet.yml b/config/protocol.unit_testnet.yml
index b538c21989..d250b2fbab 100644
--- a/config/protocol.unit_testnet.yml
+++ b/config/protocol.unit_testnet.yml
@@ -20,11 +20,11 @@ ProtocolConfiguration:
   VerifyTransactions: true
   P2PSigExtensions: true
   Hardforks:
-    Aspidochelone: 3
-    Basilisk: 6
-    Cockatrice: 9
-    Domovoi: 12
-    Echidna: 13
+    Aspidochelone: 1
+    Basilisk: 2
+    Cockatrice: 3
+    Domovoi: 4
+    Echidna: 5
 
 ApplicationConfiguration:
   SkipBlockVerification: false
diff --git a/docs/node-configuration.md b/docs/node-configuration.md
index 5a7fbc046a..aeab236049 100644
--- a/docs/node-configuration.md
+++ b/docs/node-configuration.md
@@ -417,7 +417,7 @@ protocol-related settings described in the table below.
 | MaxValidUntilBlockIncrement | `uint32` | `5760` | Upper height increment limit for transaction's ValidUntilBlock field value relative to the current blockchain height, exceeding which a transaction will fail validation. It is set to estimated daily number of blocks with 15s interval by default. This setting is replaced by [`Genesis`-level](#Genesis-Configuration) `MaxValidUntilBlockIncrement` protocol configuration setting and corresponding Policy value starting from `Echidna` hardfork. |
 | MemPoolSize | `int` | `50000` | Size of the node's memory pool where transactions are stored before they are added to block. |
 | P2PNotaryRequestPayloadPoolSize | `int` | `1000` | Size of the node's P2P Notary request payloads memory pool where P2P Notary requests are stored before main or fallback transaction is completed and added to the chain.
This option is valid only if `P2PSigExtensions` are enabled. | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
-| P2PSigExtensions | `bool` | `false` | Enables following additional Notary service related logic:
• Network payload of the `P2PNotaryRequest` type
• Native `Notary` contract
• Notary node module | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
+| P2PSigExtensions | `bool` | `false` | Enables following additional Notary service related logic:
• Network payload of the `P2PNotaryRequest` type
• Notary node module | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
 | P2PStateExchangeExtensions | `bool` | `false` | Enables the following P2P MPT state data exchange logic: 
• `StateSyncInterval` protocol setting 
• P2P commands `GetMPTDataCMD` and `MPTDataCMD` | Not supported by the C# node, thus may affect heterogeneous networks functionality. Can be supported either on MPT-complete node (`KeepOnlyLatestState`=`false`) or on light GC-enabled node (`RemoveUntraceableBlocks=true`) in which case `KeepOnlyLatestState` setting doesn't change the behavior, an appropriate set of MPTs is always stored (see `RemoveUntraceableBlocks`). |
 | ReservedAttributes | `bool` | `false` | Allows to have reserved attributes range for experimental or private purposes. |
 | SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
@@ -525,7 +525,7 @@ in development and can change in an incompatible way.
 | `Basilisk`      | Enables strict smart contract script check against a set of JMP instructions and against method boundaries enabled on contract deploy or update. Increases `stackitem.Integer` JSON parsing precision up to the maximum value supported by the NeoVM. Enables strict check for notifications emitted by a contract to precisely match the events specified in the contract manifest. | https://github.com/nspcc-dev/neo-go/pull/3056 
 https://github.com/neo-project/neo/pull/2881 
 https://github.com/nspcc-dev/neo-go/pull/3080 
 https://github.com/neo-project/neo/pull/2883 
 https://github.com/nspcc-dev/neo-go/pull/3085 
 https://github.com/neo-project/neo/pull/2810 |
 | `Cockatrice`    | Introduces the ability to update native contracts. Includes a couple of new native smart contract APIs: `keccak256` of native CryptoLib contract and `getCommitteeAddress` of native NeoToken contract. | https://github.com/nspcc-dev/neo-go/pull/3402 
 https://github.com/neo-project/neo/pull/2942 
 https://github.com/nspcc-dev/neo-go/pull/3301 
 https://github.com/neo-project/neo/pull/2925 
 https://github.com/nspcc-dev/neo-go/pull/3362 
 https://github.com/neo-project/neo/pull/3154 |
 | `Domovoi`       | Makes node use executing contract state for the contract call permissions check instead of the state stored in the native Management contract. In C# also makes System.Runtime.GetNotifications interop properly count stack references of notification parameters which prevents users from creating objects that exceed MaxStackSize constraint, but NeoGo has never had this bug, thus proper behaviour is preserved even before HFDomovoi. It results in the fact that some T5 testnet transactions have different ApplicationLogs compared to the C# node, but the node states match. | https://github.com/nspcc-dev/neo-go/pull/3476 
 https://github.com/neo-project/neo/pull/3290 
 https://github.com/nspcc-dev/neo-go/pull/3473 
 https://github.com/neo-project/neo/pull/3290 
 https://github.com/neo-project/neo/pull/3301 
 https://github.com/nspcc-dev/neo-go/pull/3485 |
-| `Echidna`       | Introduces `Designation` event extension with `Old` and `New` roles data to native RoleManagement contract. Adds support for `base64UrlEncode` and `base64UrlDecode` methods to native StdLib contract. Extends the list of required call flags for `registerCandidate`, `unregisterCandidate`and `vote` methods of native NeoToken contract with AllowNotify flag. Enables `onNEP17Payment` method of NEO contract for candidate registration. Introduces constraint for maximum number of execution notifications. Adds support for `recoverSecp256K1` method of native CryptoLib contract. Introduces `setMillisecondsPerBlock` and `getMillisecondsPerBlock` methods of native Policy contract. Introduces support for NotaryAssisted transaction attribute. | https://github.com/nspcc-dev/neo-go/pull/3554 
 https://github.com/nspcc-dev/neo-go/pull/3761 
 https://github.com/nspcc-dev/neo-go/pull/3554 
 https://github.com/neo-project/neo/pull/3597 
 https://github.com/nspcc-dev/neo-go/pull/3700 
 https://github.com/nspcc-dev/neo-go/pull/3640 
 https://github.com/neo-project/neo/pull/3548 
 https://github.com/nspcc-dev/neo-go/pull/3863 
 https://github.com/neo-project/neo/pull/3696 
 https://github.com/neo-project/neo/pull/3895 
 https://github.com/nspcc-dev/neo-go/pull/3835 
 https://github.com/nspcc-dev/neo-go/pull/3854 
 https://github.com/neo-project/neo/pull/3175 |
+| `Echidna`       | Introduces `Designation` event extension with `Old` and `New` roles data to native RoleManagement contract. Adds support for `base64UrlEncode` and `base64UrlDecode` methods to native StdLib contract. Extends the list of required call flags for `registerCandidate`, `unregisterCandidate`and `vote` methods of native NeoToken contract with AllowNotify flag. Enables `onNEP17Payment` method of NEO contract for candidate registration. Introduces constraint for maximum number of execution notifications. Adds support for `recoverSecp256K1` method of native CryptoLib contract. Introduces `setMillisecondsPerBlock` and `getMillisecondsPerBlock` methods of native Policy contract. Introduces support for NotaryAssisted transaction attribute and native Notary contract. | https://github.com/nspcc-dev/neo-go/pull/3554 
 https://github.com/nspcc-dev/neo-go/pull/3761 
 https://github.com/nspcc-dev/neo-go/pull/3554 
 https://github.com/neo-project/neo/pull/3597 
 https://github.com/nspcc-dev/neo-go/pull/3700 
 https://github.com/nspcc-dev/neo-go/pull/3640 
 https://github.com/neo-project/neo/pull/3548 
 https://github.com/nspcc-dev/neo-go/pull/3863 
 https://github.com/neo-project/neo/pull/3696 
 https://github.com/neo-project/neo/pull/3895 
 https://github.com/nspcc-dev/neo-go/pull/3835 
 https://github.com/nspcc-dev/neo-go/pull/3854 
 https://github.com/neo-project/neo/pull/3175 
 https://github.com/nspcc-dev/neo-go/pull/3478 
 https://github.com/neo-project/neo/pull/3178 |
 
 ## DB compatibility
 
diff --git a/internal/basicchain/basic.go b/internal/basicchain/basic.go
index 812012aa0a..228b211173 100644
--- a/internal/basicchain/basic.go
+++ b/internal/basicchain/basic.go
@@ -8,6 +8,7 @@ import (
 	"path/filepath"
 	"testing"
 
+	"github.com/nspcc-dev/neo-go/pkg/config"
 	"github.com/nspcc-dev/neo-go/pkg/core/native"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
@@ -77,9 +78,10 @@ func InitSimple(t *testing.T, rootpath string, e *neotest.Executor) {
 // Init pushes some predefined set  of transactions into the given chain, it needs a path to
 // the root project directory.
 func Init(t *testing.T, rootpath string, e *neotest.Executor) {
-	if !e.Chain.GetConfig().P2PSigExtensions {
-		t.Fatal("P2PSigExtensions should be enabled to init basic chain")
-	}
+	const notaryDepositHeight uint32 = 8
+	echidnaH, ok := e.Chain.GetConfig().Hardforks[config.HFEchidna.String()]
+	require.Truef(t, ok, "%s hardfork should be enabled since basic chain uses Notary contract", config.HFEchidna.String())
+	require.LessOrEqualf(t, echidnaH, notaryDepositHeight-1, "%s hardfork should be enabled starting from height %d, got: %d", config.HFEchidna.String(), notaryDepositHeight-1, echidnaH)
 
 	var (
 		// examplesPrefix is a prefix of the example smart-contracts.
@@ -189,6 +191,7 @@ func Init(t *testing.T, rootpath string, e *neotest.Executor) {
 	// Block #8: deposit some GAS to notary contract for priv0.
 	transferTxH = gasPriv0Invoker.Invoke(t, true, "transfer", priv0ScriptHash, notaryHash, 10_0000_0000, []any{priv0ScriptHash, int64(e.Chain.BlockHeight() + 1000)})
 	t.Logf("notaryDepositTxPriv0: %v", transferTxH.StringLE())
+	require.Equal(t, uint32(notaryDepositHeight), e.Chain.BlockHeight(), "notaryDepositHeight constant is out of date")
 
 	// Block #9: designate new Notary node.
 	ntr, err := wallet.NewWalletFromFile(path.Join(notaryModulePath, "./testdata/notary1.json"))
diff --git a/internal/contracts/contracts_test.go b/internal/contracts/contracts_test.go
index 426b184efe..94ce878a2e 100644
--- a/internal/contracts/contracts_test.go
+++ b/internal/contracts/contracts_test.go
@@ -5,7 +5,6 @@ import (
 	"os"
 	"testing"
 
-	"github.com/nspcc-dev/neo-go/pkg/config"
 	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
 	"github.com/nspcc-dev/neo-go/pkg/core/state"
@@ -65,9 +64,7 @@ func generateOracleContract(t *testing.T, saveState bool) {
 // native hashes and saves the generated NEF and manifest to `management_contract` folder.
 // Set `saveState` flag to true and run the test to rewrite NEF and manifest files.
 func generateManagementHelperContracts(t *testing.T, saveState bool) {
-	bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-		c.P2PSigExtensions = true
-	})
+	bc, validator, committee := chain.NewMulti(t)
 	e := neotest.NewExecutor(t, bc, validator, committee)
 
 	mgmtHash := e.NativeHash(t, nativenames.Management)
diff --git a/internal/fakechain/fakechain.go b/internal/fakechain/fakechain.go
index f650f42cfb..fd9a87839a 100644
--- a/internal/fakechain/fakechain.go
+++ b/internal/fakechain/fakechain.go
@@ -25,19 +25,18 @@ import (
 type FakeChain struct {
 	config.Blockchain
 	*mempool.Pool
-	blocksCh                 []chan *block.Block
-	Blockheight              atomic.Uint32
-	PoolTxF                  func(*transaction.Transaction) error
-	poolTxWithData           func(*transaction.Transaction, any, *mempool.Pool) error
-	blocks                   map[util.Uint256]*block.Block
-	hdrHashes                map[uint32]util.Uint256
-	txs                      map[util.Uint256]*transaction.Transaction
-	VerifyWitnessF           func() (int64, error)
-	MaxVerificationGAS       int64
-	NotaryContractScriptHash util.Uint160
-	NotaryDepositExpiration  uint32
-	PostBlock                []func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)
-	UtilityTokenBalance      *big.Int
+	blocksCh                []chan *block.Block
+	Blockheight             atomic.Uint32
+	PoolTxF                 func(*transaction.Transaction) error
+	poolTxWithData          func(*transaction.Transaction, any, *mempool.Pool) error
+	blocks                  map[util.Uint256]*block.Block
+	hdrHashes               map[uint32]util.Uint256
+	txs                     map[util.Uint256]*transaction.Transaction
+	VerifyWitnessF          func() (int64, error)
+	MaxVerificationGAS      int64
+	NotaryDepositExpiration uint32
+	PostBlock               []func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)
+	UtilityTokenBalance     *big.Int
 }
 
 // IsHardforkEnabled implements Blockchainer interface.
@@ -131,14 +130,6 @@ func (chain *FakeChain) GetNotaryDepositExpiration(acc util.Uint160) uint32 {
 	panic("TODO")
 }
 
-// GetNotaryContractScriptHash implements the Blockchainer interface.
-func (chain *FakeChain) GetNotaryContractScriptHash() util.Uint160 {
-	if !chain.NotaryContractScriptHash.Equals(util.Uint160{}) {
-		return chain.NotaryContractScriptHash
-	}
-	panic("TODO")
-}
-
 // GetNotaryBalance implements the Blockchainer interface.
 func (chain *FakeChain) GetNotaryBalance(acc util.Uint160) *big.Int {
 	panic("TODO")
diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go
index c130c21fef..ce0824d1ec 100644
--- a/pkg/compiler/native_test.go
+++ b/pkg/compiler/native_test.go
@@ -36,8 +36,7 @@ import (
 )
 
 func TestContractHashes(t *testing.T) {
-	cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
-	cs := native.NewContracts(cfg)
+	cs := native.NewContracts(config.ProtocolConfiguration{})
 	require.Equalf(t, []byte(neo.Hash), cs.NEO.Hash.BytesBE(), "%q", string(cs.NEO.Hash.BytesBE()))
 	require.Equalf(t, []byte(gas.Hash), cs.GAS.Hash.BytesBE(), "%q", string(cs.GAS.Hash.BytesBE()))
 	require.Equalf(t, []byte(oracle.Hash), cs.Oracle.Hash.BytesBE(), "%q", string(cs.Oracle.Hash.BytesBE()))
@@ -147,8 +146,7 @@ type nativeTestCase struct {
 
 // Here we test that corresponding method does exist, is invoked and correct value is returned.
 func TestNativeHelpersCompile(t *testing.T) {
-	cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
-	cs := native.NewContracts(cfg)
+	cs := native.NewContracts(config.ProtocolConfiguration{})
 	u160 := `interop.Hash160("aaaaaaaaaaaaaaaaaaaa")`
 	u256 := `interop.Hash256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
 	pub := `interop.PublicKey("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
diff --git a/pkg/core/basic_chain_test.go b/pkg/core/basic_chain_test.go
index 0cc8c3f062..14e4ae6f36 100644
--- a/pkg/core/basic_chain_test.go
+++ b/pkg/core/basic_chain_test.go
@@ -7,7 +7,6 @@ import (
 	"time"
 
 	"github.com/nspcc-dev/neo-go/internal/basicchain"
-	"github.com/nspcc-dev/neo-go/pkg/config"
 	"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
 	"github.com/nspcc-dev/neo-go/pkg/io"
 	"github.com/nspcc-dev/neo-go/pkg/neotest"
@@ -39,9 +38,7 @@ var (
 func TestCreateBasicChain(t *testing.T) {
 	const saveChain = false
 
-	bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.Blockchain) {
-		cfg.P2PSigExtensions = true
-	})
+	bc, validators, committee := chain.NewMulti(t)
 	e := neotest.NewExecutor(t, bc, validators, committee)
 
 	basicchain.Init(t, "../../", e)
diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go
index a147422423..92953d6b20 100644
--- a/pkg/core/blockchain.go
+++ b/pkg/core/blockchain.go
@@ -2211,12 +2211,17 @@ func (bc *Blockchain) GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint
 }
 
 // GetNotaryBalance returns Notary deposit amount for the specified account.
+// Default value is returned if Notary contract is not yet active.
 func (bc *Blockchain) GetNotaryBalance(acc util.Uint160) *big.Int {
+	if !bc.IsHardforkEnabled(bc.contracts.Notary.ActiveIn(), bc.BlockHeight()) {
+		return nil
+	}
 	return bc.contracts.Notary.BalanceOf(bc.dao, acc)
 }
 
 // GetNotaryServiceFeePerKey returns a NotaryAssisted transaction attribute fee
 // per key which is a reward per notary request key for designated notary nodes.
+// Default value is returned if Notary contract is not yet active.
 func (bc *Blockchain) GetNotaryServiceFeePerKey() int64 {
 	if !bc.IsHardforkEnabled(&transaction.NotaryAssistedActivation, bc.BlockHeight()) {
 		return 0
@@ -2224,16 +2229,12 @@ func (bc *Blockchain) GetNotaryServiceFeePerKey() int64 {
 	return bc.contracts.Policy.GetAttributeFeeInternal(bc.dao, transaction.NotaryAssistedT)
 }
 
-// GetNotaryContractScriptHash returns Notary native contract hash.
-func (bc *Blockchain) GetNotaryContractScriptHash() util.Uint160 {
-	if bc.P2PSigExtensionsEnabled() {
-		return bc.contracts.Notary.Hash
-	}
-	return util.Uint160{}
-}
-
 // GetNotaryDepositExpiration returns Notary deposit expiration height for the specified account.
+// Default value is returned if Notary contract is not yet active.
 func (bc *Blockchain) GetNotaryDepositExpiration(acc util.Uint160) uint32 {
+	if !bc.IsHardforkEnabled(bc.contracts.Notary.ActiveIn(), bc.BlockHeight()) {
+		return 0
+	}
 	return bc.contracts.Notary.ExpirationOf(bc.dao, acc)
 }
 
@@ -2819,7 +2820,7 @@ func (bc *Blockchain) verifyTxAttributes(d *dao.Simple, tx *transaction.Transact
 			if !bc.IsHardforkEnabled(&transaction.NotaryAssistedActivation, bc.BlockHeight()) {
 				return fmt.Errorf("%w: NotaryAssisted attribute was found, but %s is not active yet", ErrInvalidAttribute, transaction.NotaryAssistedActivation)
 			}
-			if !tx.HasSigner(bc.contracts.Notary.Hash) {
+			if !tx.HasSigner(nativehashes.Notary) {
 				return fmt.Errorf("%w: NotaryAssisted attribute was found, but transaction is not signed by the Notary native contract", ErrInvalidAttribute)
 			}
 			if tx.Sender().Equals(nativehashes.Notary) && len(tx.Signers) != 2 {
@@ -3250,9 +3251,6 @@ func (bc *Blockchain) GetMaxVerificationGAS() int64 {
 
 // GetMaxNotValidBeforeDelta returns maximum NotValidBeforeDelta Notary limit.
 func (bc *Blockchain) GetMaxNotValidBeforeDelta() (uint32, error) {
-	if !bc.config.P2PSigExtensions {
-		panic("disallowed call to Notary") // critical error, thus panic.
-	}
 	if !bc.IsHardforkEnabled(bc.contracts.Notary.ActiveIn(), bc.BlockHeight()) {
 		return 0, fmt.Errorf("native Notary is active starting from %s", bc.contracts.Notary.ActiveIn().String())
 	}
diff --git a/pkg/core/blockchain_neotest_test.go b/pkg/core/blockchain_neotest_test.go
index a28a5c0af7..48ccdd0237 100644
--- a/pkg/core/blockchain_neotest_test.go
+++ b/pkg/core/blockchain_neotest_test.go
@@ -69,7 +69,6 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
 	ps, path := newLevelDBForTestingWithPath(t, "")
 	customConfig := func(c *config.Blockchain) {
 		c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
-		c.P2PSigExtensions = true  // Need for basic chain initializer.
 	}
 	bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
 	require.NoError(t, err)
@@ -763,9 +762,7 @@ func TestBlockchain_VerifyHashAgainstScript(t *testing.T) {
 }
 
 func TestBlockchain_IsTxStillRelevant(t *testing.T) {
-	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
-		c.P2PSigExtensions = true
-	})
+	bc, acc := chain.NewSingle(t)
 	e := neotest.NewExecutor(t, bc, acc, acc)
 
 	mp := bc.GetMemPool()
@@ -1216,7 +1213,6 @@ func TestConfig_LoadDefaultConfigs(t *testing.T) {
 
 func TestBlockchain_VerifyTx(t *testing.T) {
 	bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-		c.P2PSigExtensions = true
 		c.ReservedAttributes = true
 		c.Hardforks = map[string]uint32{
 			config.HFEchidna.String(): 0,
@@ -1639,7 +1635,6 @@ func TestBlockchain_VerifyTx(t *testing.T) {
 			}
 			t.Run("Disabled", func(t *testing.T) { // check that NVB attribute is not an extension anymore.
 				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-					c.P2PSigExtensions = false
 					c.ReservedAttributes = false
 				})
 				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
@@ -1680,7 +1675,6 @@ func TestBlockchain_VerifyTx(t *testing.T) {
 			}
 			t.Run("Disabled", func(t *testing.T) {
 				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-					c.P2PSigExtensions = false
 					c.ReservedAttributes = false
 				})
 				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
@@ -1724,7 +1718,6 @@ func TestBlockchain_VerifyTx(t *testing.T) {
 			}
 			t.Run("disabled", func(t *testing.T) { // check that Conflicts attribute is not an extension anymore.
 				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-					c.P2PSigExtensions = false
 					c.ReservedAttributes = false
 				})
 				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
@@ -2063,7 +2056,6 @@ func TestBlockchain_VerifyTx(t *testing.T) {
 			}
 			t.Run("Disabled", func(t *testing.T) {
 				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-					c.P2PSigExtensions = true
 					c.Hardforks = map[string]uint32{
 						config.HFAspidochelone.String(): 0,
 						config.HFBasilisk.String():      0,
@@ -2376,9 +2368,7 @@ func TestBlockchain_ResetStateErrors(t *testing.T) {
 func TestBlockchain_ResetState(t *testing.T) {
 	// Create the DB.
 	db, path := newLevelDBForTestingWithPath(t, t.TempDir())
-	bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
-		cfg.P2PSigExtensions = true
-	}, db, false)
+	bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, nil, db, false)
 	go bc.Run()
 	e := neotest.NewExecutor(t, bc, validators, committee)
 	basicchain.Init(t, "../../", e)
@@ -2447,9 +2437,7 @@ func TestBlockchain_ResetState(t *testing.T) {
 
 	// Start new chain with existing DB, but do not run it.
 	db, _ = newLevelDBForTestingWithPath(t, path)
-	bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
-		cfg.P2PSigExtensions = true
-	}, db, false)
+	bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, nil, db, false)
 	defer db.Close()
 	require.Equal(t, topBlockHeight, bc.BlockHeight()) // ensure DB was properly initialized.
 
@@ -2583,8 +2571,13 @@ func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
 // in the right order.
 func TestNativenames(t *testing.T) {
 	bc, _ := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
-		cfg.Hardforks = map[string]uint32{}
-		cfg.P2PSigExtensions = true
+		cfg.Hardforks = map[string]uint32{
+			config.HFAspidochelone.String(): 0,
+			config.HFBasilisk.String():      0,
+			config.HFCockatrice.String():    0,
+			config.HFDomovoi.String():       0,
+			config.HFEchidna.String():       0,
+		}
 	})
 	natives := bc.GetNatives()
 	require.Equal(t, len(natives), len(nativenames.All))
diff --git a/pkg/core/chaindump/dump_test.go b/pkg/core/chaindump/dump_test.go
index 06531ff31e..3ae75188fe 100644
--- a/pkg/core/chaindump/dump_test.go
+++ b/pkg/core/chaindump/dump_test.go
@@ -18,23 +18,18 @@ func TestBlockchain_DumpAndRestore(t *testing.T) {
 	t.Run("no state root", func(t *testing.T) {
 		testDumpAndRestore(t, func(c *config.Blockchain) {
 			c.StateRootInHeader = false
-			c.P2PSigExtensions = true
 		}, nil)
 	})
 	t.Run("with state root", func(t *testing.T) {
 		testDumpAndRestore(t, func(c *config.Blockchain) {
 			c.StateRootInHeader = true
-			c.P2PSigExtensions = true
 		}, nil)
 	})
 	t.Run("remove untraceable", func(t *testing.T) {
 		// Dump can only be created if all blocks and transactions are present.
-		testDumpAndRestore(t, func(c *config.Blockchain) {
-			c.P2PSigExtensions = true
-		}, func(c *config.Blockchain) {
+		testDumpAndRestore(t, nil, func(c *config.Blockchain) {
 			c.MaxTraceableBlocks = 2
 			c.Ledger.RemoveUntraceableBlocks = true
-			c.P2PSigExtensions = true
 		})
 	})
 }
diff --git a/pkg/core/interop/contract/account_test.go b/pkg/core/interop/contract/account_test.go
index cb69de97a0..2817ae2d9c 100644
--- a/pkg/core/interop/contract/account_test.go
+++ b/pkg/core/interop/contract/account_test.go
@@ -120,9 +120,12 @@ func TestCreateMultisigAccount(t *testing.T) {
 func TestCreateAccount_HFAspidochelone(t *testing.T) {
 	const enabledHeight = 3
 	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
-		c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled
 		c.Hardforks = map[string]uint32{
 			config.HFAspidochelone.String(): enabledHeight,
+			config.HFBasilisk.String():      enabledHeight,
+			config.HFCockatrice.String():    enabledHeight,
+			config.HFDomovoi.String():       enabledHeight,
+			config.HFEchidna.String():       enabledHeight,
 		}
 	})
 	e := neotest.NewExecutor(t, bc, acc, acc)
diff --git a/pkg/core/native/compatibility_test.go b/pkg/core/native/compatibility_test.go
index 9ed1074f47..3f4a090466 100644
--- a/pkg/core/native/compatibility_test.go
+++ b/pkg/core/native/compatibility_test.go
@@ -10,8 +10,7 @@ import (
 
 // "C" and "O" can easily be typed by accident.
 func TestNamesASCII(t *testing.T) {
-	cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
-	cs := NewContracts(cfg)
+	cs := NewContracts(config.ProtocolConfiguration{})
 	latestHF := config.HFLatestKnown
 	for _, c := range cs.Contracts {
 		require.True(t, isASCII(c.Metadata().Name))
diff --git a/pkg/core/native/contract.go b/pkg/core/native/contract.go
index 75c81d71fa..2038bb2385 100644
--- a/pkg/core/native/contract.go
+++ b/pkg/core/native/contract.go
@@ -101,15 +101,13 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
 	cs.Oracle = oracle
 	cs.Contracts = append(cs.Contracts, oracle)
 
-	if cfg.P2PSigExtensions {
-		notary := newNotary()
-		notary.GAS = gas
-		notary.NEO = neo
-		notary.Desig = desig
-		notary.Policy = policy
-		cs.Notary = notary
-		cs.Contracts = append(cs.Contracts, notary)
-	}
+	notary := newNotary()
+	notary.GAS = gas
+	notary.NEO = neo
+	notary.Desig = desig
+	notary.Policy = policy
+	cs.Notary = notary
+	cs.Contracts = append(cs.Contracts, notary)
 
 	return cs
 }
diff --git a/pkg/core/native/contract_test.go b/pkg/core/native/contract_test.go
index c12cf25f96..1f186d2f06 100644
--- a/pkg/core/native/contract_test.go
+++ b/pkg/core/native/contract_test.go
@@ -10,8 +10,7 @@ import (
 // TestNativeGetMethod is needed to ensure that methods list has the same sorting
 // rule as we expect inside the `ContractMD.GetMethod`.
 func TestNativeGetMethod(t *testing.T) {
-	cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
-	cs := NewContracts(cfg)
+	cs := NewContracts(config.ProtocolConfiguration{})
 	latestHF := config.HFLatestKnown
 	for _, c := range cs.Contracts {
 		hfMD := c.Metadata().HFSpecificContractMD(&latestHF)
diff --git a/pkg/core/native/management_neotest_test.go b/pkg/core/native/management_neotest_test.go
index f470f3a25e..c29e19e457 100644
--- a/pkg/core/native/management_neotest_test.go
+++ b/pkg/core/native/management_neotest_test.go
@@ -29,9 +29,7 @@ func TestManagement_GetNEP17Contracts(t *testing.T) {
 	})
 
 	t.Run("basic chain", func(t *testing.T) {
-		bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-			c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled
-		})
+		bc, validators, committee := chain.NewMulti(t)
 		e := neotest.NewExecutor(t, bc, validators, committee)
 		basicchain.Init(t, "../../../", e)
 
diff --git a/pkg/core/native/native_test/gas_test.go b/pkg/core/native/native_test/gas_test.go
index 7926c1387e..60ecc16def 100644
--- a/pkg/core/native/native_test/gas_test.go
+++ b/pkg/core/native/native_test/gas_test.go
@@ -66,9 +66,12 @@ func TestGAS_RewardWithP2PSigExtensionsEnabled(t *testing.T) {
 	)
 
 	bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.Blockchain) {
-		cfg.P2PSigExtensions = true
 		cfg.Hardforks = map[string]uint32{
-			config.HFEchidna.String(): 0,
+			config.HFAspidochelone.String(): 0,
+			config.HFBasilisk.String():      0,
+			config.HFCockatrice.String():    0,
+			config.HFDomovoi.String():       0,
+			config.HFEchidna.String():       0,
 		}
 	})
 	e := neotest.NewExecutor(t, bc, validator, committee)
diff --git a/pkg/core/native/native_test/management_test.go b/pkg/core/native/native_test/management_test.go
index 56e7299a7d..c1119f0c47 100644
--- a/pkg/core/native/native_test/management_test.go
+++ b/pkg/core/native/native_test/management_test.go
@@ -49,7 +49,6 @@ var (
 		nativenames.Policy:      `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getExecFeeFactor","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":35,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":42,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":49,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":70,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
 		nativenames.Designation: `{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","abi":{"methods":[{"name":"designateAsRole","offset":0,"parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","safe":false},{"name":"getDesignatedByRole","offset":7,"parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
 		nativenames.Oracle:      `{"id":-9,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","abi":{"methods":[{"name":"finish","offset":0,"parameters":[],"returntype":"Void","safe":false},{"name":"getPrice","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"request","offset":14,"parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setPrice","offset":21,"parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":28,"parameters":[],"returntype":"Boolean","safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
-		nativenames.Notary:      `{"id":-10,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"expirationOf","offset":7,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"getMaxNotValidBeforeDelta","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"lockDepositUntil","offset":21,"parameters":[{"name":"address","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","safe":false},{"name":"onNEP17Payment","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"setMaxNotValidBeforeDelta","offset":35,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":42,"parameters":[{"name":"signature","type":"Signature"}],"returntype":"Boolean","safe":true},{"name":"withdraw","offset":49,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-27"],"trusts":[],"extra":null},"updatecounter":0}`,
 	}
 	// cockatriceCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
 	// under assumption that hardforks from Aspidochelone to Cockatrice (included) are enabled.
@@ -66,6 +65,7 @@ var (
 		nativenames.Neo:         `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"onNEP17Payment","offset":77,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"registerCandidate","offset":84,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":91,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":98,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":105,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":112,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":119,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":126,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":133,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":140,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17","NEP-27"],"trusts":[],"extra":null},"updatecounter":0}`,
 		nativenames.Policy:      `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":588003825},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getExecFeeFactor","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMaxTraceableBlocks","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMaxValidUntilBlockIncrement","offset":35,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMillisecondsPerBlock","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":56,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":63,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":70,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":77,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMaxTraceableBlocks","offset":84,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMaxValidUntilBlockIncrement","offset":91,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMillisecondsPerBlock","offset":98,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":105,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":112,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[{"name":"MillisecondsPerBlockChanged","parameters":[{"name":"old","type":"Integer"},{"name":"new","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
 		nativenames.Designation: `{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","abi":{"methods":[{"name":"designateAsRole","offset":0,"parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","safe":false},{"name":"getDesignatedByRole","offset":7,"parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"},{"name":"Old","type":"Array"},{"name":"New","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
+		nativenames.Notary:      `{"id":-10,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"expirationOf","offset":7,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"getMaxNotValidBeforeDelta","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"lockDepositUntil","offset":21,"parameters":[{"name":"account","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","safe":false},{"name":"onNEP17Payment","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"setMaxNotValidBeforeDelta","offset":35,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":42,"parameters":[{"name":"signature","type":"ByteArray"}],"returntype":"Boolean","safe":true},{"name":"withdraw","offset":49,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-27"],"trusts":[],"extra":null},"updatecounter":0}`,
 	}
 )
 
@@ -78,6 +78,11 @@ func init() {
 			echidnaCSS[k] = cockatriceCSS[k]
 		}
 	}
+	for k, v := range cockatriceCSS {
+		if _, ok := echidnaCSS[k]; !ok {
+			echidnaCSS[k] = v
+		}
+	}
 }
 
 func newManagementClient(t *testing.T) *neotest.ContractInvoker {
@@ -106,6 +111,10 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 			h := state.CreateNativeContractHash(name)
 			c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
 				si := stack[0]
+				if _, ok := expected[name]; !ok {
+					require.Equal(t, stackitem.Null{}, si, fmt.Errorf("contract %s state found", name))
+					return
+				}
 				var cs = &state.Contract{}
 				require.NoError(t, cs.FromStackItem(si), name)
 				jBytes, err := ojson.Marshal(cs)
@@ -118,7 +127,6 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 	t.Run("disabled hardforks", func(t *testing.T) {
 		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
 			cfg.Hardforks = map[string]uint32{}
-			cfg.P2PSigExtensions = true
 		})
 		check(t, mgmt, defaultCSS)
 	})
@@ -128,9 +136,9 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 				config.HFAspidochelone.String(): 100500,
 				config.HFBasilisk.String():      100500,
 				config.HFCockatrice.String():    100500,
+				config.HFDomovoi.String():       100500,
 				config.HFEchidna.String():       100500,
 			}
-			cfg.P2PSigExtensions = true
 		})
 		check(t, mgmt, defaultCSS)
 	})
@@ -139,7 +147,6 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 			cfg.Hardforks = map[string]uint32{
 				config.HFAspidochelone.String(): 0,
 			}
-			cfg.P2PSigExtensions = true
 		})
 		check(t, mgmt, defaultCSS)
 	})
@@ -149,7 +156,6 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 				config.HFAspidochelone.String(): 0,
 				config.HFBasilisk.String():      0,
 			}
-			cfg.P2PSigExtensions = true
 		})
 		check(t, mgmt, defaultCSS)
 	})
@@ -160,7 +166,17 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 				config.HFBasilisk.String():      0,
 				config.HFCockatrice.String():    0,
 			}
-			cfg.P2PSigExtensions = true
+		})
+		check(t, mgmt, cockatriceCSS)
+	})
+	t.Run("Cockatrice enabled", func(t *testing.T) {
+		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
+			cfg.Hardforks = map[string]uint32{
+				config.HFAspidochelone.String(): 0,
+				config.HFBasilisk.String():      0,
+				config.HFCockatrice.String():    0,
+				config.HFDomovoi.String():       0,
+			}
 		})
 		check(t, mgmt, cockatriceCSS)
 	})
@@ -172,7 +188,6 @@ func TestManagement_GenesisNativeState(t *testing.T) {
 				config.HFCockatrice.String():    0,
 				config.HFEchidna.String():       0,
 			}
-			cfg.P2PSigExtensions = true
 		})
 
 		check(t, mgmt, echidnaCSS)
@@ -193,9 +208,9 @@ func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
 			config.HFDomovoi.String():       domovoiHeight,
 			config.HFEchidna.String():       echidnaHeight,
 		}
-		cfg.P2PSigExtensions = true
 	})
 	e := mgmt.Executor
+	mgmt.GenerateNewBlocks(t, echidnaHeight)
 
 	// Check Deploy notifications.
 	aer, err := mgmt.Chain.GetAppExecResults(e.GetBlockByIndex(t, 0).Hash(), trigger.OnPersist)
@@ -204,6 +219,8 @@ func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
 	var expected []state.NotificationEvent
 	for _, name := range nativenames.All {
 		switch name {
+		case nativenames.Notary:
+			continue
 		case nativenames.Gas:
 			expected = append(expected, state.NotificationEvent{
 				ScriptHash: nativehashes.GasToken,
@@ -235,8 +252,7 @@ func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
 	}
 	require.Equal(t, expected, aer[0].Events)
 
-	// Generate some blocks and check Update notifications.
-	mgmt.GenerateNewBlocks(t, cockatriceHeight-int(mgmt.Chain.BlockHeight()))
+	// Check Update notifications for Cockatrice hardfork.
 	aer, err = mgmt.Chain.GetAppExecResults(mgmt.Chain.GetHeaderHash(cockatriceHeight), trigger.OnPersist)
 	require.NoError(t, err)
 	require.Equal(t, 1, len(aer))
@@ -252,8 +268,14 @@ func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
 	}
 	require.Equal(t, expected, aer[0].Events)
 
-	// Generate some blocks and check notifications for Echidna hardfork.
-	mgmt.GenerateNewBlocks(t, echidnaHeight-int(mgmt.Chain.BlockHeight()))
+	// Check that there's no native contract updates in Domovoi hardfork.
+	aer, err = mgmt.Chain.GetAppExecResults(mgmt.Chain.GetHeaderHash(domovoiHeight), trigger.OnPersist)
+	require.NoError(t, err)
+	require.Equal(t, 1, len(aer))
+	expected = expected[:0]
+	require.Equal(t, expected, aer[0].Events)
+
+	// Check notifications for Echidna hardfork.
 	aer, err = mgmt.Chain.GetAppExecResults(mgmt.Chain.GetHeaderHash(echidnaHeight), trigger.OnPersist)
 	require.NoError(t, err)
 	require.Equal(t, 1, len(aer))
@@ -267,18 +289,29 @@ func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
 			}),
 		})
 	}
+	expected = append(expected, state.NotificationEvent{
+		ScriptHash: nativehashes.ContractManagement,
+		Name:       "Deploy",
+		Item: stackitem.NewArray([]stackitem.Item{
+			stackitem.Make(nativehashes.Notary),
+		}),
+	})
 	require.Equal(t, expected, aer[0].Events)
 }
 
 func TestManagement_NativeUpdate(t *testing.T) {
-	const cockatriceHeight = 3
+	const (
+		cockatriceHeight = 3
+		echidnaHeight    = 6
+	)
+
 	c := newCustomManagementClient(t, func(cfg *config.Blockchain) {
 		cfg.Hardforks = map[string]uint32{
 			config.HFAspidochelone.String(): 0,
 			config.HFBasilisk.String():      0,
 			config.HFCockatrice.String():    cockatriceHeight,
+			config.HFEchidna.String():       echidnaHeight,
 		}
-		cfg.P2PSigExtensions = true
 	})
 
 	// Add some blocks up to the Cockatrice enabling height and check the default natives state.
@@ -287,7 +320,12 @@ func TestManagement_NativeUpdate(t *testing.T) {
 		for _, name := range nativenames.All {
 			h := state.CreateNativeContractHash(name)
 			cs := c.Chain.GetContractState(h)
-			require.NotNil(t, cs, name)
+			if name == nativenames.Notary {
+				require.Nil(t, cs, name)
+				continue
+			} else {
+				require.NotNil(t, cs, name)
+			}
 			jBytes, err := ojson.Marshal(cs)
 			require.NoError(t, err, name)
 			require.Equal(t, defaultCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
@@ -299,16 +337,41 @@ func TestManagement_NativeUpdate(t *testing.T) {
 	for _, name := range nativenames.All {
 		h := state.CreateNativeContractHash(name)
 		cs := c.Chain.GetContractState(h)
-		require.NotNil(t, cs, name)
+		if name == nativenames.Notary {
+			require.Nil(t, cs, name)
+			continue
+		} else {
+			require.NotNil(t, cs, name)
+		}
+		var actual = cs
 		if name == nativenames.Neo || name == nativenames.CryptoLib {
 			// A tiny hack to reuse cockatriceCSS map in the check below.
 			require.Equal(t, uint16(1), cs.UpdateCounter, name)
-			cs.UpdateCounter--
+			cp := *cs
+			actual = &cp // avoid Management cache corruption.
+			actual.UpdateCounter--
 		}
-		jBytes, err := ojson.Marshal(cs)
+		jBytes, err := ojson.Marshal(actual)
 		require.NoError(t, err, name)
 		require.Equal(t, cockatriceCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
 	}
+
+	// Add some blocks up to the Echidna enabling height and check the natives state.
+	for i := c.Chain.BlockHeight(); i < echidnaHeight; i++ {
+		c.AddNewBlock(t)
+	}
+	for _, name := range nativenames.All {
+		h := state.CreateNativeContractHash(name)
+		cs := c.Chain.GetContractState(h)
+		require.NotNil(t, cs, name)
+		// A tiny hack to reuse echidnaCSS map in the check below.
+		cp := *cs
+		actual := &cp // avoid Management cache corruption.
+		actual.UpdateCounter = 0
+		jBytes, err := ojson.Marshal(actual)
+		require.NoError(t, err, name)
+		require.Equal(t, echidnaCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
+	}
 }
 
 func TestManagement_NativeUpdate_Call(t *testing.T) {
@@ -322,7 +385,6 @@ func TestManagement_NativeUpdate_Call(t *testing.T) {
 			config.HFBasilisk.String():      0,
 			config.HFCockatrice.String():    cockatriceHeight,
 		}
-		cfg.P2PSigExtensions = true
 	})
 
 	// Invoke Cockatrice-dependant method before Cockatrice should fail.
@@ -344,20 +406,25 @@ func TestManagement_NativeUpdate_Call(t *testing.T) {
 // different block heights depending on hardfork settings. This test is located here since it
 // depends on defaultCSS and cockatriceCSS.
 func TestBlockchain_GetNatives(t *testing.T) {
-	const cockatriceHeight = 3
+	const (
+		cockatriceHeight = 3
+		domovoiHeight    = 5
+		echidnaHeight    = 6
+	)
 	bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
 		cfg.Hardforks = map[string]uint32{
 			config.HFAspidochelone.String(): 0,
 			config.HFBasilisk.String():      0,
 			config.HFCockatrice.String():    cockatriceHeight,
+			config.HFDomovoi.String():       domovoiHeight,
+			config.HFEchidna.String():       echidnaHeight,
 		}
-		cfg.P2PSigExtensions = true
 	})
 	e := neotest.NewExecutor(t, bc, acc, acc)
 
 	// Check genesis-based native contract states.
 	natives := bc.GetNatives()
-	require.Equal(t, len(nativenames.All), len(natives))
+	require.Equal(t, len(nativenames.All)-1, len(natives)) // Notary is deployed starting from D hardfork.
 	for _, cs := range natives {
 		csFull := state.Contract{
 			ContractBase:  cs.ContractBase,
@@ -368,10 +435,10 @@ func TestBlockchain_GetNatives(t *testing.T) {
 		require.Equal(t, defaultCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
 	}
 
-	// Check native state after update.
+	// Check native state after Cockatrice.
 	e.GenerateNewBlocks(t, cockatriceHeight)
 	natives = bc.GetNatives()
-	require.Equal(t, len(nativenames.All), len(natives))
+	require.Equal(t, len(nativenames.All)-1, len(natives)) // Notary is deployed starting from D hardfork.
 	for _, cs := range natives {
 		csFull := state.Contract{
 			ContractBase:  cs.ContractBase,
@@ -381,6 +448,20 @@ func TestBlockchain_GetNatives(t *testing.T) {
 		require.NoError(t, err, cs.Manifest.Name)
 		require.Equal(t, cockatriceCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
 	}
+
+	// Check native state after Echidna.
+	e.GenerateNewBlocks(t, echidnaHeight-cockatriceHeight)
+	natives = bc.GetNatives()
+	require.Equal(t, len(nativenames.All), len(natives))
+	for _, cs := range natives {
+		csFull := state.Contract{
+			ContractBase:  cs.ContractBase,
+			UpdateCounter: 0, // Since we're comparing only state.NativeContract part, set the update counter to 0 to match the echidnaCSS.
+		}
+		jBytes, err := ojson.Marshal(csFull)
+		require.NoError(t, err, cs.Manifest.Name)
+		require.Equal(t, echidnaCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
+	}
 }
 
 func TestManagement_ContractCache(t *testing.T) {
@@ -450,12 +531,8 @@ func TestManagement_ContractCache(t *testing.T) {
 			require.NoError(t, err)
 			require.Equal(t, vmstate.Halt, aer[0].VMState, aer[0].FaultException)
 			cs := aer[0].Stack[0]
-			if h.Equals(nativehashes.Notary) {
-				require.True(t, cs.Equals(stackitem.Null{}))
-			} else {
-				require.False(t, cs.Equals(stackitem.Null{}))
-			}
-			managementInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(!h.Equals(nativehashes.Notary)))
+			require.False(t, cs.Equals(stackitem.Null{}))
+			managementInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(true))
 		})
 	}
 }
diff --git a/pkg/core/native/native_test/neo_test.go b/pkg/core/native/native_test/neo_test.go
index e5edf39192..32f28accc1 100644
--- a/pkg/core/native/native_test/neo_test.go
+++ b/pkg/core/native/native_test/neo_test.go
@@ -13,6 +13,7 @@ import (
 	"github.com/nspcc-dev/neo-go/internal/contracts"
 	"github.com/nspcc-dev/neo-go/internal/random"
 	"github.com/nspcc-dev/neo-go/pkg/compiler"
+	"github.com/nspcc-dev/neo-go/pkg/config"
 	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
 	"github.com/nspcc-dev/neo-go/pkg/core/native"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
@@ -35,7 +36,15 @@ import (
 )
 
 func newNeoCommitteeClient(t *testing.T, expectedGASBalance int) *neotest.ContractInvoker {
-	bc, validators, committee := chain.NewMulti(t)
+	bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.Blockchain) {
+		cfg.Hardforks = map[string]uint32{
+			config.HFAspidochelone.String(): 0,
+			config.HFBasilisk.String():      0,
+			config.HFCockatrice.String():    0,
+			config.HFDomovoi.String():       0,
+			config.HFEchidna.String():       0,
+		}
+	})
 	e := neotest.NewExecutor(t, bc, validators, committee)
 
 	if expectedGASBalance > 0 {
diff --git a/pkg/core/native/native_test/notary_test.go b/pkg/core/native/native_test/notary_test.go
index e165db3d44..b5f45cd3ee 100644
--- a/pkg/core/native/native_test/notary_test.go
+++ b/pkg/core/native/native_test/notary_test.go
@@ -25,9 +25,12 @@ import (
 
 func newNotaryClient(t *testing.T) *neotest.ContractInvoker {
 	bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
-		cfg.P2PSigExtensions = true
 		cfg.Hardforks = map[string]uint32{
-			config.HFEchidna.String(): 0,
+			config.HFAspidochelone.String(): 0,
+			config.HFBasilisk.String():      0,
+			config.HFCockatrice.String():    0,
+			config.HFDomovoi.String():       0,
+			config.HFEchidna.String():       0,
 		}
 	})
 	e := neotest.NewExecutor(t, bc, acc, acc)
diff --git a/pkg/core/native/nativenames_test.go b/pkg/core/native/nativenames_test.go
index df0be1eba0..c648d45417 100644
--- a/pkg/core/native/nativenames_test.go
+++ b/pkg/core/native/nativenames_test.go
@@ -10,9 +10,7 @@ import (
 )
 
 func TestNativenamesIsValid(t *testing.T) {
-	// test that all native names have been added to IsValid
-	cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
-	contracts := NewContracts(cfg)
+	contracts := NewContracts(config.ProtocolConfiguration{})
 	for _, c := range contracts.Contracts {
 		require.True(t, nativenames.IsValid(c.Metadata().Name), fmt.Errorf("add %s to nativenames.IsValid(...)", c))
 	}
diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go
index 803d1cbc78..0fbe8df66f 100644
--- a/pkg/core/native/notary.go
+++ b/pkg/core/native/notary.go
@@ -52,7 +52,10 @@ const (
 	defaultMaxNotValidBeforeDelta = 140 // 20 rounds for 7 validators, a little more than half an hour
 )
 
-var maxNotValidBeforeDeltaKey = []byte{10}
+var (
+	maxNotValidBeforeDeltaKey = []byte{10}
+	notaryActiveIn            = config.HFEchidna
+)
 
 var (
 	_ interop.Contract        = (*Notary)(nil)
@@ -85,7 +88,7 @@ func newNotary() *Notary {
 	n.AddMethod(md, desc)
 
 	desc = newDescriptor("lockDepositUntil", smartcontract.BoolType,
-		manifest.NewParameter("address", smartcontract.Hash160Type),
+		manifest.NewParameter("account", smartcontract.Hash160Type),
 		manifest.NewParameter("till", smartcontract.IntegerType))
 	md = newMethodAndPrice(n.lockDepositUntil, 1<<15, callflag.States)
 	n.AddMethod(md, desc)
@@ -97,17 +100,17 @@ func newNotary() *Notary {
 	n.AddMethod(md, desc)
 
 	desc = newDescriptor("balanceOf", smartcontract.IntegerType,
-		manifest.NewParameter("addr", smartcontract.Hash160Type))
+		manifest.NewParameter("account", smartcontract.Hash160Type))
 	md = newMethodAndPrice(n.balanceOf, 1<<15, callflag.ReadStates)
 	n.AddMethod(md, desc)
 
 	desc = newDescriptor("expirationOf", smartcontract.IntegerType,
-		manifest.NewParameter("addr", smartcontract.Hash160Type))
+		manifest.NewParameter("account", smartcontract.Hash160Type))
 	md = newMethodAndPrice(n.expirationOf, 1<<15, callflag.ReadStates)
 	n.AddMethod(md, desc)
 
 	desc = newDescriptor("verify", smartcontract.BoolType,
-		manifest.NewParameter("signature", smartcontract.SignatureType))
+		manifest.NewParameter("signature", smartcontract.ByteArrayType))
 	md = newMethodAndPrice(n.verify, nativeprices.NotaryVerificationPrice, callflag.ReadStates)
 	n.AddMethod(md, desc)
 
@@ -172,6 +175,9 @@ func (n *Notary) OnPersist(ic *interop.Context) error {
 			if tx.Sender() == n.Hash {
 				payer := tx.Signers[1]
 				balance := n.GetDepositFor(ic.DAO, payer.Account)
+				if balance == nil {
+					continue
+				}
 				balance.Amount.Sub(balance.Amount, big.NewInt(tx.SystemFee+tx.NetworkFee))
 				if balance.Amount.Sign() == 0 {
 					n.removeDepositFor(ic.DAO, payer.Account)
@@ -187,6 +193,9 @@ func (n *Notary) OnPersist(ic *interop.Context) error {
 	if nFees == 0 {
 		return nil
 	}
+	if len(notaries) == 0 {
+		return nil
+	}
 	feePerKey := n.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
 	singleReward := calculateNotaryReward(nFees, feePerKey, len(notaries))
 	for _, notary := range notaries {
@@ -202,7 +211,7 @@ func (n *Notary) PostPersist(ic *interop.Context) error {
 
 // ActiveIn implements the Contract interface.
 func (n *Notary) ActiveIn() *config.Hardfork {
-	return nil
+	return ¬aryActiveIn
 }
 
 // onPayment records the deposited amount as belonging to "from" address with a lock
diff --git a/pkg/core/statesync/module.go b/pkg/core/statesync/module.go
index 177c028913..15a4d88f90 100644
--- a/pkg/core/statesync/module.go
+++ b/pkg/core/statesync/module.go
@@ -311,7 +311,17 @@ func (s *Module) getLatestSavedBlock(p uint32) uint32 {
 		copy(key[5:], native.MaxTraceableBlocksKey)
 		si, err := s.dao.Store.Get(key)
 		if err != nil {
-			panic(fmt.Errorf("failed to retrieve MaxTraceableBlock storage item from Policy contract storage by key %s at height %d: %w", hex.EncodeToString(key), p, err))
+			if errors.Is(err, storage.ErrKeyNotFound) {
+				// The only situation when it's possible is when state sync was already completed,
+				// DB storage prefix was swapped with temporary storage prefix and old storage items
+				// were already removed during state jump. Hence, we need to use the current DB
+				// prefix to retrieve MaxTraceableBlocks value.
+				key[0] = byte(TemporaryPrefix(storage.KeyPrefix(key[0])))
+				si, err = s.dao.Store.Get(key)
+			}
+			if err != nil {
+				panic(fmt.Errorf("failed to retrieve MaxTraceableBlock storage item from Policy contract storage by key %s at height %d: %w", hex.EncodeToString(key), p, err))
+			}
 		}
 		mtb = uint32(bigint.FromBytes(si).Int64())
 	}
diff --git a/pkg/core/statesync/neotest_test.go b/pkg/core/statesync/neotest_test.go
index 5667122c08..72f1398315 100644
--- a/pkg/core/statesync/neotest_test.go
+++ b/pkg/core/statesync/neotest_test.go
@@ -2,7 +2,6 @@ package statesync_test
 
 import (
 	"bytes"
-	"fmt"
 	"testing"
 
 	"github.com/nspcc-dev/neo-go/internal/basicchain"
@@ -278,22 +277,12 @@ func TestStateSyncModule_Init(t *testing.T) {
 }
 
 func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
-	check := func(t *testing.T, spoutEnableGC bool, enableEchidna bool) {
+	check := func(t *testing.T, spoutEnableGC bool) {
 		const (
 			stateSyncInterval = 4
 			maxTraceable      = 6
 			stateSyncPoint    = 24
 		)
-		var hfs = map[string]uint32{}
-		if enableEchidna {
-			hfs = map[string]uint32{
-				config.HFAspidochelone.String(): 0,
-				config.HFBasilisk.String():      0,
-				config.HFCockatrice.String():    0,
-				config.HFDomovoi.String():       0,
-				config.HFEchidna.String():       0,
-			}
-		}
 		spoutCfg := func(c *config.Blockchain) {
 			c.Ledger.KeepOnlyLatestState = spoutEnableGC
 			c.Ledger.RemoveUntraceableBlocks = spoutEnableGC
@@ -301,8 +290,13 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
 			c.P2PStateExchangeExtensions = true
 			c.StateSyncInterval = stateSyncInterval
 			c.MaxTraceableBlocks = maxTraceable
-			c.P2PSigExtensions = true // `basicchain.Init` assumes Notary is enabled.
-			c.Hardforks = hfs
+			c.Hardforks = map[string]uint32{
+				config.HFAspidochelone.String(): 0,
+				config.HFBasilisk.String():      0,
+				config.HFCockatrice.String():    0,
+				config.HFDomovoi.String():       0,
+				config.HFEchidna.String():       0,
+			}
 		}
 		bcSpoutStore := storage.NewMemoryStore()
 		bcSpout, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, spoutCfg, bcSpoutStore, false)
@@ -480,14 +474,10 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
 		})
 		require.False(t, haveItems)
 	}
-	for _, mtb := range []bool{true, false} {
-		t.Run(fmt.Sprintf("MaxTraceableBlocks in Policy: %t", mtb), func(t *testing.T) {
-			t.Run("source node is archive", func(t *testing.T) {
-				check(t, false, mtb)
-			})
-			t.Run("source node is light with GC", func(t *testing.T) {
-				check(t, true, mtb)
-			})
-		})
-	}
+	t.Run("source node is archive", func(t *testing.T) {
+		check(t, false)
+	})
+	t.Run("source node is light with GC", func(t *testing.T) {
+		check(t, true)
+	})
 }
diff --git a/pkg/network/server.go b/pkg/network/server.go
index 6508ff7969..62054d1525 100644
--- a/pkg/network/server.go
+++ b/pkg/network/server.go
@@ -21,6 +21,7 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
 	"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
 	"github.com/nspcc-dev/neo-go/pkg/core/mpt"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
 	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
 	"github.com/nspcc-dev/neo-go/pkg/io"
@@ -69,7 +70,6 @@ type (
 		GetMemPool() *mempool.Pool
 		GetMillisecondsPerBlock() uint32
 		GetNotaryBalance(acc util.Uint160) *big.Int
-		GetNotaryContractScriptHash() util.Uint160
 		GetNotaryDepositExpiration(acc util.Uint160) uint32
 		GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
 		HasBlock(util.Uint256) bool
@@ -1355,7 +1355,7 @@ func (s *Server) verifyNotaryRequest(_ *transaction.Transaction, data any) error
 	if _, err := s.chain.VerifyWitness(payer, r, &r.Witness, s.chain.GetMaxVerificationGAS()); err != nil {
 		return fmt.Errorf("bad P2PNotaryRequest payload witness: %w", err)
 	}
-	notaryHash := s.chain.GetNotaryContractScriptHash()
+	notaryHash := nativehashes.Notary
 	if r.FallbackTransaction.Sender() != notaryHash {
 		return fmt.Errorf("P2PNotary contract should be a sender of the fallback transaction, got %s", address.Uint160ToString(r.FallbackTransaction.Sender()))
 	}
diff --git a/pkg/network/server_test.go b/pkg/network/server_test.go
index ea3fb47bae..737a043edc 100644
--- a/pkg/network/server_test.go
+++ b/pkg/network/server_test.go
@@ -19,6 +19,7 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/core/block"
 	"github.com/nspcc-dev/neo-go/pkg/core/interop"
 	"github.com/nspcc-dev/neo-go/pkg/core/mpt"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
 	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
 	"github.com/nspcc-dev/neo-go/pkg/network/capability"
@@ -1049,7 +1050,6 @@ func TestMemPool(t *testing.T) {
 func TestVerifyNotaryRequest(t *testing.T) {
 	bc := fakechain.NewFakeChain()
 	bc.MaxVerificationGAS = 10
-	bc.NotaryContractScriptHash = util.Uint160{1, 2, 3}
 	s, err := newServerFromConstructors(ServerConfig{Addresses: []config.AnnounceableAddress{{Address: ":0"}}}, bc, new(fakechain.FakeStateSync), zaptest.NewLogger(t), newFakeTransp, newTestDiscovery)
 	require.NoError(t, err)
 	newNotaryRequest := func() *payload.P2PNotaryRequest {
@@ -1060,7 +1060,7 @@ func TestVerifyNotaryRequest(t *testing.T) {
 			},
 			FallbackTransaction: &transaction.Transaction{
 				ValidUntilBlock: 321,
-				Signers:         []transaction.Signer{{Account: bc.NotaryContractScriptHash}, {Account: random.Uint160()}},
+				Signers:         []transaction.Signer{{Account: nativehashes.Notary}, {Account: random.Uint160()}},
 			},
 			Witness: transaction.Witness{},
 		}
@@ -1081,7 +1081,7 @@ func TestVerifyNotaryRequest(t *testing.T) {
 	t.Run("bad main sender", func(t *testing.T) {
 		bc.VerifyWitnessF = func() (int64, error) { return 0, nil }
 		r := newNotaryRequest()
-		r.MainTransaction.Signers[0] = transaction.Signer{Account: bc.NotaryContractScriptHash}
+		r.MainTransaction.Signers[0] = transaction.Signer{Account: nativehashes.Notary}
 		require.Error(t, s.verifyNotaryRequest(nil, r))
 	})
 
diff --git a/pkg/services/notary/core_test.go b/pkg/services/notary/core_test.go
index 412e7346a8..f35a6f620a 100644
--- a/pkg/services/notary/core_test.go
+++ b/pkg/services/notary/core_test.go
@@ -14,6 +14,7 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/core"
 	"github.com/nspcc-dev/neo-go/pkg/core/block"
 	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
 	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
@@ -70,9 +71,7 @@ func dupNotaryRequest(t *testing.T, p *payload.P2PNotaryRequest) *payload.P2PNot
 }
 
 func TestNotary(t *testing.T) {
-	bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-		c.P2PSigExtensions = true
-	})
+	bc, validators, committee := chain.NewMulti(t)
 	e := neotest.NewExecutor(t, bc, validators, committee)
 	notaryHash := e.NativeHash(t, nativenames.Notary)
 	designationSuperInvoker := e.NewInvoker(e.NativeHash(t, nativenames.Designation), validators, committee)
@@ -171,7 +170,7 @@ func TestNotary(t *testing.T) {
 		fallback.ValidUntilBlock = bc.BlockHeight() + 2*nvbDiffFallback
 		fallback.Signers = []transaction.Signer{
 			{
-				Account: bc.GetNotaryContractScriptHash(),
+				Account: nativehashes.Notary,
 				Scopes:  transaction.None,
 			},
 			{
@@ -241,7 +240,7 @@ func TestNotary(t *testing.T) {
 			verificationScripts = append(verificationScripts, script)
 		}
 		signers[len(signers)-1] = transaction.Signer{
-			Account: bc.GetNotaryContractScriptHash(),
+			Account: nativehashes.Notary,
 			Scopes:  transaction.None,
 		}
 		mainTx.Signers = signers
@@ -754,9 +753,9 @@ func TestNotary(t *testing.T) {
 	requester1, _ := wallet.NewAccount()
 	requester2, _ := wallet.NewAccount()
 	amount := int64(100_0000_0000)
-	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []any{requester1.ScriptHash(), int64(bc.BlockHeight() + 50)})
+	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), nativehashes.Notary, amount, []any{requester1.ScriptHash(), int64(bc.BlockHeight() + 50)})
 	e.CheckGASBalance(t, notaryHash, big.NewInt(amount))
-	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []any{requester2.ScriptHash(), int64(bc.BlockHeight() + 50)})
+	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), nativehashes.Notary, amount, []any{requester2.ScriptHash(), int64(bc.BlockHeight() + 50)})
 	e.CheckGASBalance(t, notaryHash, big.NewInt(2*amount))
 
 	// create request for 2 standard signatures => main tx should be completed after the second request is added to the pool
@@ -793,7 +792,6 @@ func TestNotary_GenesisRoles(t *testing.T) {
 	acc := w.Accounts[0]
 
 	bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
-		c.P2PSigExtensions = true
 		c.Genesis.Roles = map[noderoles.Role]keys.PublicKeys{
 			noderoles.P2PNotary: {acc.PublicKey()},
 		}
diff --git a/pkg/services/notary/notary.go b/pkg/services/notary/notary.go
index 2e5b4d2fe0..41db4b2b5d 100644
--- a/pkg/services/notary/notary.go
+++ b/pkg/services/notary/notary.go
@@ -15,6 +15,7 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/core/block"
 	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
 	"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
 	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@@ -32,7 +33,6 @@ type (
 	Ledger interface {
 		BlockHeight() uint32
 		GetMaxVerificationGAS() int64
-		GetNotaryContractScriptHash() util.Uint160
 		SubscribeForBlocks(ch chan *block.Block)
 		UnsubscribeFromBlocks(ch chan *block.Block)
 		VerifyWitness(util.Uint160, hash.Hashable, *transaction.Witness, int64) (int64, error)
@@ -408,7 +408,7 @@ func (n *Notary) finalize(acc *wallet.Account, tx *transaction.Transaction, h ut
 		VerificationScript: []byte{},
 	}
 	for i, signer := range tx.Signers {
-		if signer.Account == n.Config.Chain.GetNotaryContractScriptHash() {
+		if signer.Account == nativehashes.Notary {
 			tx.Scripts[i] = notaryWitness
 			break
 		}
@@ -511,7 +511,7 @@ func (n *Notary) verifyIncompleteWitnesses(tx *transaction.Transaction, nKeysExp
 	if len(tx.Signers) < 2 {
 		return nil, errors.New("transaction should have at least 2 signers")
 	}
-	if !tx.HasSigner(n.Config.Chain.GetNotaryContractScriptHash()) {
+	if !tx.HasSigner(nativehashes.Notary) {
 		return nil, fmt.Errorf("P2PNotary contract should be a signer of the transaction")
 	}
 	result := make([]witnessInfo, len(tx.Signers))
diff --git a/pkg/services/notary/notary_test.go b/pkg/services/notary/notary_test.go
index 9df86c72fa..afc630f8a7 100644
--- a/pkg/services/notary/notary_test.go
+++ b/pkg/services/notary/notary_test.go
@@ -7,11 +7,11 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/config"
 	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
 	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
 	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
 	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
-	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
 	"github.com/stretchr/testify/require"
 	"go.uber.org/zap/zaptest"
@@ -48,8 +48,7 @@ func TestWallet(t *testing.T) {
 
 func TestVerifyIncompleteRequest(t *testing.T) {
 	bc := fakechain.NewFakeChain()
-	notaryContractHash := util.Uint160{1, 2, 3}
-	bc.NotaryContractScriptHash = notaryContractHash
+	notaryContractHash := nativehashes.Notary
 	_, ntr, _ := getTestNotary(t, bc, "./testdata/notary1.json", "one")
 	sig := append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...) // we're not interested in signature correctness
 	acc1, _ := keys.NewPrivateKey()
diff --git a/pkg/services/rpcsrv/client_test.go b/pkg/services/rpcsrv/client_test.go
index 983be896a2..20419b1927 100644
--- a/pkg/services/rpcsrv/client_test.go
+++ b/pkg/services/rpcsrv/client_test.go
@@ -468,6 +468,10 @@ func TestClientNEOContract(t *testing.T) {
 func TestClientNotary(t *testing.T) {
 	chain, _, httpSrv := initServerWithInMemoryChain(t)
 
+	// Echidna should be enabled since this test uses Notary contract.
+	_, ok := chain.GetConfig().Hardforks[config.HFEchidna.String()]
+	require.True(t, ok)
+
 	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
 	require.NoError(t, err)
 	t.Cleanup(c.Close)
@@ -2453,11 +2457,11 @@ func TestClient_GetVersion_Hardforks(t *testing.T) {
 	v, err := c.GetVersion()
 	require.NoError(t, err)
 	expected := map[config.Hardfork]uint32{
-		config.HFAspidochelone: 3,
-		config.HFBasilisk:      6,
-		config.HFCockatrice:    9,
-		config.HFDomovoi:       12,
-		config.HFEchidna:       13,
+		config.HFAspidochelone: 1,
+		config.HFBasilisk:      2,
+		config.HFCockatrice:    3,
+		config.HFDomovoi:       4,
+		config.HFEchidna:       5,
 	}
 	require.InDeltaMapValues(t, expected, v.Protocol.Hardforks, 0)
 }
diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go
index 8823ca38f3..140699b667 100644
--- a/pkg/services/rpcsrv/server.go
+++ b/pkg/services/rpcsrv/server.go
@@ -90,7 +90,6 @@ type (
 		GetNativeContractScriptHash(string) (util.Uint160, error)
 		GetNatives() []state.Contract
 		GetNextBlockValidators() ([]*keys.PublicKey, error)
-		GetNotaryContractScriptHash() util.Uint160
 		GetStateModule() core.StateRoot
 		GetStorageItem(id int32, key []byte) state.StorageItem
 		GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error)
diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go
index 0aa618c593..09a16bea32 100644
--- a/pkg/services/rpcsrv/server_test.go
+++ b/pkg/services/rpcsrv/server_test.go
@@ -122,7 +122,7 @@ const (
 	// not yet deployed to the testing basic chain.
 	invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
 	// block20StateRootLE is an LE stateroot of block #20 of basic testing chain.
-	block20StateRootLE = "501589598f1ea6d043070d7bbf77c8a7813a69cc280b1284571a2051fd88ee4f"
+	block20StateRootLE = "c4317d7941e5d4d072bc7e6672c78b9bd7aa217fc19ee779e02968dd43cc9927"
 )
 
 var (
@@ -2625,7 +2625,7 @@ func createValidNotaryRequest(chain *core.Blockchain, sender *keys.PrivateKey, n
 			{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
 			{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
 		},
-		Signers: []transaction.Signer{{Account: chain.GetNotaryContractScriptHash()}, {Account: sender.GetScriptHash()}},
+		Signers: []transaction.Signer{{Account: nativehashes.Notary}, {Account: sender.GetScriptHash()}},
 		Scripts: []transaction.Witness{
 			{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: []byte{}},
 		},
@@ -4184,7 +4184,7 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc any, sent, rcvd []int
 			{
 				Timestamp:   blockDepositGAS.Timestamp,
 				Asset:       e.chain.UtilityTokenHash(),
-				Address:     address.Uint160ToString(e.chain.GetNotaryContractScriptHash()),
+				Address:     address.Uint160ToString(nativehashes.Notary),
 				Amount:      "1000000000",
 				Index:       8,
 				NotifyIndex: 0,