core: prevent direct access to Notary contract if not active

Otherwise it will cause panic, which isn't expected behaviour.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2023-04-26 14:10:12 +03:00
parent 2c984e2393
commit d560395985
2 changed files with 21 additions and 13 deletions

View file

@ -2447,7 +2447,10 @@ func (bc *Blockchain) verifyTxAttributes(d *dao.Simple, tx *transaction.Transact
nvb := tx.Attributes[i].Value.(*transaction.NotValidBefore).Height nvb := tx.Attributes[i].Value.(*transaction.NotValidBefore).Height
curHeight := bc.BlockHeight() curHeight := bc.BlockHeight()
if isPartialTx { if isPartialTx {
maxNVBDelta := bc.contracts.Notary.GetMaxNotValidBeforeDelta(bc.dao) maxNVBDelta, err := bc.GetMaxNotValidBeforeDelta()
if err != nil {
return fmt.Errorf("%w: failed to retrieve MaxNotValidBeforeDelta value from native Notary contract: %v", ErrInvalidAttribute, err)
}
if curHeight+maxNVBDelta < nvb { if curHeight+maxNVBDelta < nvb {
return fmt.Errorf("%w: NotValidBefore (%d) bigger than MaxNVBDelta (%d) allows at height %d", ErrInvalidAttribute, nvb, maxNVBDelta, curHeight) return fmt.Errorf("%w: NotValidBefore (%d) bigger than MaxNVBDelta (%d) allows at height %d", ErrInvalidAttribute, nvb, maxNVBDelta, curHeight)
} }
@ -2852,11 +2855,14 @@ func (bc *Blockchain) GetMaxVerificationGAS() int64 {
} }
// GetMaxNotValidBeforeDelta returns maximum NotValidBeforeDelta Notary limit. // GetMaxNotValidBeforeDelta returns maximum NotValidBeforeDelta Notary limit.
func (bc *Blockchain) GetMaxNotValidBeforeDelta() uint32 { func (bc *Blockchain) GetMaxNotValidBeforeDelta() (uint32, error) {
if !bc.config.P2PSigExtensions { if !bc.config.P2PSigExtensions {
panic("disallowed call to Notary") panic("disallowed call to Notary") // critical error, thus panic.
} }
return bc.contracts.Notary.GetMaxNotValidBeforeDelta(bc.dao) if bc.contracts.Notary.Metadata().UpdateHistory[0] > bc.BlockHeight() {
return 0, fmt.Errorf("native Notary is active starting from %d", bc.contracts.Notary.Metadata().UpdateHistory[0])
}
return bc.contracts.Notary.GetMaxNotValidBeforeDelta(bc.dao), nil
} }
// GetStoragePrice returns current storage price. // GetStoragePrice returns current storage price.

View file

@ -347,10 +347,9 @@ func TestBlockchain_InitializeNativeCacheWrtNativeActivations(t *testing.T) {
e = neotest.NewExecutor(t, bc, validators, committee) e = neotest.NewExecutor(t, bc, validators, committee)
h := e.Chain.BlockHeight() h := e.Chain.BlockHeight()
// Notary isn't initialized yet, so accessing Notary cache should panic. // Notary isn't initialized yet, so accessing Notary cache should return error.
require.Panics(t, func() { _, err = e.Chain.GetMaxNotValidBeforeDelta()
_ = e.Chain.GetMaxNotValidBeforeDelta() require.Error(t, err)
})
// Ensure Notary will be properly initialized and accessing Notary cache works // Ensure Notary will be properly initialized and accessing Notary cache works
// as expected. // as expected.
@ -359,9 +358,8 @@ func TestBlockchain_InitializeNativeCacheWrtNativeActivations(t *testing.T) {
e.AddNewBlock(t) e.AddNewBlock(t)
}, h+uint32(i)+1) }, h+uint32(i)+1)
} }
require.NotPanics(t, func() { _, err = e.Chain.GetMaxNotValidBeforeDelta()
_ = e.Chain.GetMaxNotValidBeforeDelta() require.NoError(t, err)
})
} }
func TestBlockchain_AddHeaders(t *testing.T) { func TestBlockchain_AddHeaders(t *testing.T) {
@ -1952,11 +1950,15 @@ func TestBlockchain_VerifyTx(t *testing.T) {
require.Error(t, bc.PoolTxWithData(tx, 5, mp, bc, verificationF)) require.Error(t, bc.PoolTxWithData(tx, 5, mp, bc, verificationF))
}) })
t.Run("bad NVB: too big", func(t *testing.T) { t.Run("bad NVB: too big", func(t *testing.T) {
tx := getPartiallyFilledTx(bc.BlockHeight()+bc.GetMaxNotValidBeforeDelta()+1, bc.BlockHeight()+1) maxNVB, err := bc.GetMaxNotValidBeforeDelta()
require.NoError(t, err)
tx := getPartiallyFilledTx(bc.BlockHeight()+maxNVB+1, bc.BlockHeight()+1)
require.True(t, errors.Is(bc.PoolTxWithData(tx, 5, mp, bc, verificationF), core.ErrInvalidAttribute)) require.True(t, errors.Is(bc.PoolTxWithData(tx, 5, mp, bc, verificationF), core.ErrInvalidAttribute))
}) })
t.Run("bad ValidUntilBlock: too small", func(t *testing.T) { t.Run("bad ValidUntilBlock: too small", func(t *testing.T) {
tx := getPartiallyFilledTx(bc.BlockHeight(), bc.BlockHeight()+bc.GetMaxNotValidBeforeDelta()+1) maxNVB, err := bc.GetMaxNotValidBeforeDelta()
require.NoError(t, err)
tx := getPartiallyFilledTx(bc.BlockHeight(), bc.BlockHeight()+maxNVB+1)
require.True(t, errors.Is(bc.PoolTxWithData(tx, 5, mp, bc, verificationF), core.ErrInvalidAttribute)) require.True(t, errors.Is(bc.PoolTxWithData(tx, 5, mp, bc, verificationF), core.ErrInvalidAttribute))
}) })
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {