core: add cache to native Policy contract
We can cache maxBlockSize, maxTransactionsPerBlock and feePerByte in order to reduce the number of storage requests.
This commit is contained in:
parent
08cc04c3d5
commit
c2735a4569
2 changed files with 60 additions and 0 deletions
|
@ -640,6 +640,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
bc.lock.Unlock()
|
bc.lock.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
bc.contracts.Policy.OnPersistEnd(bc.dao)
|
||||||
bc.topBlock.Store(block)
|
bc.topBlock.Store(block)
|
||||||
atomic.StoreUint32(&bc.blockHeight, block.Index)
|
atomic.StoreUint32(&bc.blockHeight, block.Index)
|
||||||
bc.memPool.RemoveStale(bc.isTxStillRelevant, bc)
|
bc.memPool.RemoveStale(bc.isTxStillRelevant, bc)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
@ -42,6 +43,14 @@ var (
|
||||||
// Policy represents Policy native contract.
|
// Policy represents Policy native contract.
|
||||||
type Policy struct {
|
type Policy struct {
|
||||||
interop.ContractMD
|
interop.ContractMD
|
||||||
|
lock sync.RWMutex
|
||||||
|
// isValid defies whether cached values were changed during the current
|
||||||
|
// consensus iteration. If false, these values will be updated after
|
||||||
|
// blockchain DAO persisting. If true, we can safely use cached values.
|
||||||
|
isValid bool
|
||||||
|
maxTransactionsPerBlock uint32
|
||||||
|
maxBlockSize uint32
|
||||||
|
feePerByte int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ interop.Contract = (*Policy)(nil)
|
var _ interop.Contract = (*Policy)(nil)
|
||||||
|
@ -135,6 +144,12 @@ func (p *Policy) Initialize(ic *interop.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.isValid = true
|
||||||
|
p.maxTransactionsPerBlock = defaultMaxTransactionsPerBlock
|
||||||
|
p.maxBlockSize = defaultMaxBlockSize
|
||||||
|
p.feePerByte = defaultFeePerByte
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +158,26 @@ func (p *Policy) OnPersist(ic *interop.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnPersistEnd updates cached Policy values if they've been changed
|
||||||
|
func (p *Policy) OnPersistEnd(dao dao.DAO) {
|
||||||
|
if p.isValid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
maxTxPerBlock := p.getUint32WithKey(dao, maxTransactionsPerBlockKey)
|
||||||
|
p.maxTransactionsPerBlock = maxTxPerBlock
|
||||||
|
|
||||||
|
maxBlockSize := p.getUint32WithKey(dao, maxBlockSizeKey)
|
||||||
|
p.maxBlockSize = maxBlockSize
|
||||||
|
|
||||||
|
feePerByte := p.getInt64WithKey(dao, feePerByteKey)
|
||||||
|
p.feePerByte = feePerByte
|
||||||
|
|
||||||
|
p.isValid = true
|
||||||
|
}
|
||||||
|
|
||||||
// getMaxTransactionsPerBlock is Policy contract method and returns the upper
|
// getMaxTransactionsPerBlock is Policy contract method and returns the upper
|
||||||
// limit of transactions per block.
|
// limit of transactions per block.
|
||||||
func (p *Policy) getMaxTransactionsPerBlock(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
func (p *Policy) getMaxTransactionsPerBlock(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||||
|
@ -152,11 +187,21 @@ func (p *Policy) getMaxTransactionsPerBlock(ic *interop.Context, _ []stackitem.I
|
||||||
// GetMaxTransactionsPerBlockInternal returns the upper limit of transactions per
|
// GetMaxTransactionsPerBlockInternal returns the upper limit of transactions per
|
||||||
// block.
|
// block.
|
||||||
func (p *Policy) GetMaxTransactionsPerBlockInternal(dao dao.DAO) uint32 {
|
func (p *Policy) GetMaxTransactionsPerBlockInternal(dao dao.DAO) uint32 {
|
||||||
|
p.lock.RLock()
|
||||||
|
defer p.lock.RUnlock()
|
||||||
|
if p.isValid {
|
||||||
|
return p.maxTransactionsPerBlock
|
||||||
|
}
|
||||||
return p.getUint32WithKey(dao, maxTransactionsPerBlockKey)
|
return p.getUint32WithKey(dao, maxTransactionsPerBlockKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMaxBlockSize is Policy contract method and returns maximum block size.
|
// getMaxBlockSize is Policy contract method and returns maximum block size.
|
||||||
func (p *Policy) getMaxBlockSize(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
func (p *Policy) getMaxBlockSize(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||||
|
p.lock.RLock()
|
||||||
|
defer p.lock.RUnlock()
|
||||||
|
if p.isValid {
|
||||||
|
return stackitem.NewBigInteger(big.NewInt(int64(p.maxBlockSize)))
|
||||||
|
}
|
||||||
return stackitem.NewBigInteger(big.NewInt(int64(p.getUint32WithKey(ic.DAO, maxBlockSizeKey))))
|
return stackitem.NewBigInteger(big.NewInt(int64(p.getUint32WithKey(ic.DAO, maxBlockSizeKey))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +213,11 @@ func (p *Policy) getFeePerByte(ic *interop.Context, _ []stackitem.Item) stackite
|
||||||
|
|
||||||
// GetFeePerByteInternal returns required transaction's fee per byte.
|
// GetFeePerByteInternal returns required transaction's fee per byte.
|
||||||
func (p *Policy) GetFeePerByteInternal(dao dao.DAO) int64 {
|
func (p *Policy) GetFeePerByteInternal(dao dao.DAO) int64 {
|
||||||
|
p.lock.RLock()
|
||||||
|
defer p.lock.RUnlock()
|
||||||
|
if p.isValid {
|
||||||
|
return p.feePerByte
|
||||||
|
}
|
||||||
return p.getInt64WithKey(dao, feePerByteKey)
|
return p.getInt64WithKey(dao, feePerByteKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,10 +255,13 @@ func (p *Policy) setMaxTransactionsPerBlock(ic *interop.Context, args []stackite
|
||||||
return stackitem.NewBool(false)
|
return stackitem.NewBool(false)
|
||||||
}
|
}
|
||||||
value := uint32(toBigInt(args[0]).Int64())
|
value := uint32(toBigInt(args[0]).Int64())
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
err = p.setUint32WithKey(ic.DAO, maxTransactionsPerBlockKey, value)
|
err = p.setUint32WithKey(ic.DAO, maxTransactionsPerBlockKey, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
p.isValid = false
|
||||||
return stackitem.NewBool(true)
|
return stackitem.NewBool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,10 +278,13 @@ func (p *Policy) setMaxBlockSize(ic *interop.Context, args []stackitem.Item) sta
|
||||||
if payload.MaxSize <= value {
|
if payload.MaxSize <= value {
|
||||||
return stackitem.NewBool(false)
|
return stackitem.NewBool(false)
|
||||||
}
|
}
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
err = p.setUint32WithKey(ic.DAO, maxBlockSizeKey, value)
|
err = p.setUint32WithKey(ic.DAO, maxBlockSizeKey, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
p.isValid = false
|
||||||
return stackitem.NewBool(true)
|
return stackitem.NewBool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,10 +298,13 @@ func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stack
|
||||||
return stackitem.NewBool(false)
|
return stackitem.NewBool(false)
|
||||||
}
|
}
|
||||||
value := toBigInt(args[0]).Int64()
|
value := toBigInt(args[0]).Int64()
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
err = p.setInt64WithKey(ic.DAO, feePerByteKey, value)
|
err = p.setInt64WithKey(ic.DAO, feePerByteKey, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
p.isValid = false
|
||||||
return stackitem.NewBool(true)
|
return stackitem.NewBool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue