parent
13336f9dba
commit
c647f8e4ed
3 changed files with 124 additions and 1 deletions
|
@ -1159,6 +1159,15 @@ func (bc *Blockchain) ApplyPolicyToTxSet(txes []*transaction.Transaction) []*tra
|
|||
if maxTx != 0 && len(txes) > int(maxTx) {
|
||||
txes = txes[:maxTx]
|
||||
}
|
||||
maxBlockSysFee := bc.contracts.Policy.GetMaxBlockSystemFeeInternal(bc.dao)
|
||||
var sysFee int64
|
||||
for i, tx := range txes {
|
||||
sysFee += tx.SystemFee
|
||||
if sysFee > maxBlockSysFee {
|
||||
txes = txes[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return txes
|
||||
}
|
||||
|
||||
|
@ -1194,9 +1203,13 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
|
|||
return !blockedAccounts[i].Less(h)
|
||||
})
|
||||
if i != len(blockedAccounts) && blockedAccounts[i].Equals(h) {
|
||||
return errors.Errorf("policy check failed")
|
||||
return errors.Errorf("policy check failed: account %s is blocked", h.StringLE())
|
||||
}
|
||||
}
|
||||
maxBlockSystemFee := bc.contracts.Policy.GetMaxBlockSystemFeeInternal(bc.dao)
|
||||
if maxBlockSystemFee < t.SystemFee {
|
||||
return errors.Errorf("policy check failed: transaction's fee shouldn't exceed maximum block system fee %d", maxBlockSystemFee)
|
||||
}
|
||||
balance := bc.GetUtilityTokenBalance(t.Sender)
|
||||
need := t.SystemFee + t.NetworkFee
|
||||
if balance.Cmp(big.NewInt(need)) < 0 {
|
||||
|
|
|
@ -26,6 +26,9 @@ const (
|
|||
defaultMaxTransactionsPerBlock = 512
|
||||
defaultFeePerByte = 1000
|
||||
defaultMaxVerificationGas = 50000000
|
||||
defaultMaxBlockSystemFee = 9000 * GASFactor
|
||||
// minBlockSystemFee is the minimum allowed system fee per block.
|
||||
minBlockSystemFee = 4007600
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -39,6 +42,8 @@ var (
|
|||
blockedAccountsKey = []byte{15}
|
||||
// maxBlockSizeKey is a key used to store the maximum block size value.
|
||||
maxBlockSizeKey = []byte{12}
|
||||
// maxBlockSystemFeeKey is a key used to store the maximum block system fee value.
|
||||
maxBlockSystemFeeKey = []byte{17}
|
||||
)
|
||||
|
||||
// Policy represents Policy native contract.
|
||||
|
@ -52,6 +57,7 @@ type Policy struct {
|
|||
maxTransactionsPerBlock uint32
|
||||
maxBlockSize uint32
|
||||
feePerByte int64
|
||||
maxBlockSystemFee int64
|
||||
maxVerificationGas int64
|
||||
}
|
||||
|
||||
|
@ -80,6 +86,10 @@ func newPolicy() *Policy {
|
|||
md = newMethodAndPrice(p.getBlockedAccounts, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
|
||||
desc = newDescriptor("getMaxBlockSystemFee", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(p.getMaxBlockSystemFee, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
|
||||
desc = newDescriptor("setMaxBlockSize", smartcontract.BoolType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setMaxBlockSize, 3000000, smartcontract.AllowModifyStates)
|
||||
|
@ -95,6 +105,11 @@ func newPolicy() *Policy {
|
|||
md = newMethodAndPrice(p.setFeePerByte, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
|
||||
desc = newDescriptor("setMaxBlockSystemFee", smartcontract.BoolType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setMaxBlockSystemFee, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
|
||||
desc = newDescriptor("blockAccount", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.blockAccount, 3000000, smartcontract.AllowModifyStates)
|
||||
|
@ -140,6 +155,12 @@ func (p *Policy) Initialize(ic *interop.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint64(si.Value, defaultMaxBlockSystemFee)
|
||||
err = ic.DAO.PutStorageItem(p.ContractID, maxBlockSystemFeeKey, si)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ba := new(BlockedAccounts)
|
||||
si.Value = ba.Bytes()
|
||||
err = ic.DAO.PutStorageItem(p.ContractID, blockedAccountsKey, si)
|
||||
|
@ -151,6 +172,7 @@ func (p *Policy) Initialize(ic *interop.Context) error {
|
|||
p.maxTransactionsPerBlock = defaultMaxTransactionsPerBlock
|
||||
p.maxBlockSize = defaultMaxBlockSize
|
||||
p.feePerByte = defaultFeePerByte
|
||||
p.maxBlockSystemFee = defaultMaxBlockSystemFee
|
||||
p.maxVerificationGas = defaultMaxVerificationGas
|
||||
|
||||
return nil
|
||||
|
@ -178,6 +200,9 @@ func (p *Policy) OnPersistEnd(dao dao.DAO) {
|
|||
feePerByte := p.getInt64WithKey(dao, feePerByteKey)
|
||||
p.feePerByte = feePerByte
|
||||
|
||||
maxBlockSystemFee := p.getInt64WithKey(dao, maxBlockSystemFeeKey)
|
||||
p.maxBlockSystemFee = maxBlockSystemFee
|
||||
|
||||
p.isValid = true
|
||||
}
|
||||
|
||||
|
@ -229,6 +254,22 @@ func (p *Policy) GetMaxVerificationGas(_ dao.DAO) int64 {
|
|||
return p.maxVerificationGas
|
||||
}
|
||||
|
||||
// getMaxBlockSystemFee is Policy contract method and returns the maximum overall
|
||||
// system fee per block.
|
||||
func (p *Policy) getMaxBlockSystemFee(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
return stackitem.NewBigInteger(big.NewInt(p.GetMaxBlockSystemFeeInternal(ic.DAO)))
|
||||
}
|
||||
|
||||
// GetMaxBlockSystemFeeInternal the maximum overall system fee per block.
|
||||
func (p *Policy) GetMaxBlockSystemFeeInternal(dao dao.DAO) int64 {
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
if p.isValid {
|
||||
return p.maxBlockSystemFee
|
||||
}
|
||||
return p.getInt64WithKey(dao, maxBlockSystemFeeKey)
|
||||
}
|
||||
|
||||
// getBlockedAccounts is Policy contract method and returns list of blocked
|
||||
// accounts hashes.
|
||||
func (p *Policy) getBlockedAccounts(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
|
@ -316,6 +357,29 @@ func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stack
|
|||
return stackitem.NewBool(true)
|
||||
}
|
||||
|
||||
// setMaxBlockSystemFee is Policy contract method and sets the maximum system fee per block.
|
||||
func (p *Policy) setMaxBlockSystemFee(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
ok, err := p.checkValidators(ic)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !ok {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
value := toBigInt(args[0]).Int64()
|
||||
if value <= minBlockSystemFee {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
err = p.setInt64WithKey(ic.DAO, maxBlockSystemFeeKey, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.isValid = false
|
||||
return stackitem.NewBool(true)
|
||||
}
|
||||
|
||||
// blockAccount is Policy contract method and adds given account hash to the list
|
||||
// of blocked accounts.
|
||||
func (p *Policy) blockAccount(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
|
|
@ -113,6 +113,52 @@ func TestFeePerByte(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestBlockSystemFee(t *testing.T) {
|
||||
chain := newTestChain(t)
|
||||
defer chain.Close()
|
||||
|
||||
t.Run("get, internal method", func(t *testing.T) {
|
||||
n := chain.contracts.Policy.GetMaxBlockSystemFeeInternal(chain.dao)
|
||||
require.Equal(t, 9000*native.GASFactor, int(n))
|
||||
})
|
||||
|
||||
t.Run("get", func(t *testing.T) {
|
||||
res, err := invokeNativePolicyMethod(chain, "getMaxBlockSystemFee")
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, smartcontract.Parameter{
|
||||
Type: smartcontract.IntegerType,
|
||||
Value: 9000 * native.GASFactor,
|
||||
})
|
||||
require.NoError(t, chain.persist())
|
||||
})
|
||||
|
||||
t.Run("set, too low fee", func(t *testing.T) {
|
||||
res, err := invokeNativePolicyMethod(chain, "setMaxBlockSystemFee", bigint.ToBytes(big.NewInt(4007600)))
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, smartcontract.Parameter{
|
||||
Type: smartcontract.BoolType,
|
||||
Value: false,
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("set, success", func(t *testing.T) {
|
||||
res, err := invokeNativePolicyMethod(chain, "setMaxBlockSystemFee", bigint.ToBytes(big.NewInt(100000000)))
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, smartcontract.Parameter{
|
||||
Type: smartcontract.BoolType,
|
||||
Value: true,
|
||||
})
|
||||
require.NoError(t, chain.persist())
|
||||
res, err = invokeNativePolicyMethod(chain, "getMaxBlockSystemFee")
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, smartcontract.Parameter{
|
||||
Type: smartcontract.IntegerType,
|
||||
Value: 100000000,
|
||||
})
|
||||
require.NoError(t, chain.persist())
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockedAccounts(t *testing.T) {
|
||||
chain := newTestChain(t)
|
||||
defer chain.Close()
|
||||
|
|
Loading…
Reference in a new issue