core: refactor out policy check for transaction

We were checking blocked accounts twice which is obviously excessive. We also
have our accounts sorted, so we can rely on that in CheckPolicy(). It also
doesn't make much sense to check MaxBlockSystemFee in Blockchain code, policy
contract can handle that.
This commit is contained in:
Roman Khimov 2020-08-06 21:49:54 +03:00
parent 90180c6fb6
commit d5a9d80c12
2 changed files with 17 additions and 26 deletions

View file

@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"math/big"
"sort"
"sync"
"sync/atomic"
"time"
@ -1206,21 +1205,10 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
if t.ValidUntilBlock <= height || t.ValidUntilBlock > height+transaction.MaxValidUntilBlockIncrement {
return fmt.Errorf("transaction has expired. ValidUntilBlock = %d, current height = %d", t.ValidUntilBlock, height)
}
blockedAccounts, err := bc.contracts.Policy.GetBlockedAccountsInternal(bc.dao)
if err != nil {
return err
}
for _, signer := range t.Signers {
i := sort.Search(len(blockedAccounts), func(i int) bool {
return !blockedAccounts[i].Less(signer.Account)
})
if i != len(blockedAccounts) && blockedAccounts[i].Equals(signer.Account) {
return fmt.Errorf("policy check failed: account %s is blocked", signer.Account.StringLE())
}
}
maxBlockSystemFee := bc.contracts.Policy.GetMaxBlockSystemFeeInternal(bc.dao)
if maxBlockSystemFee < t.SystemFee {
return fmt.Errorf("policy check failed: transaction's fee shouldn't exceed maximum block system fee %d", maxBlockSystemFee)
// Policying.
if err := bc.contracts.Policy.CheckPolicy(bc.dao, t); err != nil {
// Only one %w can be used.
return fmt.Errorf("%w: %v", ErrPolicy, err)
}
balance := bc.GetUtilityTokenBalance(t.Sender())
need := t.SystemFee + t.NetworkFee
@ -1368,11 +1356,6 @@ func (bc *Blockchain) PoolTx(t *transaction.Transaction) error {
if err := bc.verifyTx(t, nil); err != nil {
return err
}
// Policying.
if err := bc.contracts.Policy.CheckPolicy(bc.dao, t); err != nil {
// Only one %w can be used.
return fmt.Errorf("%w: %v", ErrPolicy, err)
}
if err := bc.memPool.Add(t, bc); err != nil {
switch {
case errors.Is(err, mempool.ErrOOM):

View file

@ -509,19 +509,27 @@ func (p *Policy) checkValidators(ic *interop.Context) (bool, error) {
return runtime.CheckHashedWitness(ic, prevBlock.NextConsensus)
}
// CheckPolicy checks whether transaction's script hashes for verifying are
// included into blocked accounts list.
// CheckPolicy checks whether transaction conforms to current policy restrictions
// like not being signed by blocked account or not exceeding block-level system
// fee limit.
func (p *Policy) CheckPolicy(d dao.DAO, tx *transaction.Transaction) error {
ba, err := p.GetBlockedAccountsInternal(d)
if err != nil {
return fmt.Errorf("unable to get blocked accounts list: %w", err)
}
for _, acc := range ba {
if len(ba) > 0 {
for _, signer := range tx.Signers {
if acc.Equals(signer.Account) {
return fmt.Errorf("account %s is blocked", acc.StringLE())
i := sort.Search(len(ba), func(i int) bool {
return !ba[i].Less(signer.Account)
})
if i != len(ba) && ba[i].Equals(signer.Account) {
return fmt.Errorf("account %s is blocked", signer.Account.StringLE())
}
}
}
maxBlockSystemFee := p.GetMaxBlockSystemFeeInternal(d)
if maxBlockSystemFee < tx.SystemFee {
return fmt.Errorf("transaction's fee can't exceed maximum block system fee %d", maxBlockSystemFee)
}
return nil
}