core: use proper current block height/hash for interop API
This commit is contained in:
parent
9cc41528ef
commit
473955c2d6
7 changed files with 72 additions and 44 deletions
|
@ -433,7 +433,7 @@ func (bc *Blockchain) init() error {
|
|||
return fmt.Errorf("can't init MPT at height %d: %w", bHeight, err)
|
||||
}
|
||||
|
||||
err = bc.initializeNativeCache(bc.dao)
|
||||
err = bc.initializeNativeCache(bc.blockHeight, bc.dao)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't init natives cache: %w", err)
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ func (bc *Blockchain) jumpToStateInternal(p uint32, stage stateJumpStage) error
|
|||
Root: block.PrevStateRoot,
|
||||
})
|
||||
|
||||
err = bc.initializeNativeCache(bc.dao)
|
||||
err = bc.initializeNativeCache(block.Index, bc.dao)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize natives cache: %w", err)
|
||||
}
|
||||
|
@ -585,8 +585,8 @@ func (bc *Blockchain) jumpToStateInternal(p uint32, stage stateJumpStage) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (bc *Blockchain) initializeNativeCache(d *dao.Simple) error {
|
||||
err := bc.contracts.NEO.InitializeCache(bc, d)
|
||||
func (bc *Blockchain) initializeNativeCache(blockHeight uint32, d *dao.Simple) error {
|
||||
err := bc.contracts.NEO.InitializeCache(blockHeight, d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't init cache for NEO native contract: %w", err)
|
||||
}
|
||||
|
@ -2143,7 +2143,7 @@ func (bc *Blockchain) GetCommittee() (keys.PublicKeys, error) {
|
|||
|
||||
// GetValidators returns current validators.
|
||||
func (bc *Blockchain) GetValidators() ([]*keys.PublicKey, error) {
|
||||
return bc.contracts.NEO.ComputeNextBlockValidators(bc, bc.dao)
|
||||
return bc.contracts.NEO.ComputeNextBlockValidators(bc.blockHeight, bc.dao)
|
||||
}
|
||||
|
||||
// GetNextBlockValidators returns next block validators.
|
||||
|
@ -2189,7 +2189,7 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
|
|||
dTrie.Version = bc.dao.Version
|
||||
// Initialize native cache before passing DAO to interop context constructor, because
|
||||
// the constructor will call BaseExecFee/StoragePrice policy methods on the passed DAO.
|
||||
err = bc.initializeNativeCache(dTrie)
|
||||
err = bc.initializeNativeCache(b.Index, dTrie)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize native cache backed by historic DAO: %w", err)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||
"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/io"
|
||||
|
@ -339,3 +340,31 @@ func (ic *Context) Exec() error {
|
|||
defer ic.Finalize()
|
||||
return ic.VM.Run()
|
||||
}
|
||||
|
||||
// BlockHeight returns current block height got from Context's block if it's set.
|
||||
func (ic *Context) BlockHeight() uint32 {
|
||||
if ic.Block != nil {
|
||||
return ic.Block.Index - 1 // Persisting block is not yet stored.
|
||||
}
|
||||
return ic.Chain.BlockHeight()
|
||||
}
|
||||
|
||||
// CurrentBlockHash returns current block hash got from Context's block if it's set.
|
||||
func (ic *Context) CurrentBlockHash() util.Uint256 {
|
||||
if ic.Block != nil {
|
||||
return ic.Chain.GetHeaderHash(int(ic.Block.Index - 1)) // Persisting block is not yet stored.
|
||||
}
|
||||
return ic.Chain.CurrentBlockHash()
|
||||
}
|
||||
|
||||
// GetBlock returns block if it exists and available at the current Context's height.
|
||||
func (ic *Context) GetBlock(hash util.Uint256) (*block.Block, error) {
|
||||
block, err := ic.Chain.GetBlock(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block.Index > ic.BlockHeight() {
|
||||
return nil, storage.ErrKeyNotFound
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ func (s *Designate) getDesignatedByRole(ic *interop.Context, args []stackitem.It
|
|||
panic(ErrInvalidIndex)
|
||||
}
|
||||
index := ind.Uint64()
|
||||
if index > uint64(ic.Chain.BlockHeight()+1) {
|
||||
if index > uint64(ic.BlockHeight()+1) {
|
||||
panic(ErrInvalidIndex)
|
||||
}
|
||||
pubs, _, err := s.GetDesignatedByRole(ic.DAO, r, uint32(index))
|
||||
|
|
|
@ -31,7 +31,7 @@ func Call(ic *interop.Context) error {
|
|||
if len(history) == 0 {
|
||||
return fmt.Errorf("native contract %s is disabled", c.Metadata().Name)
|
||||
}
|
||||
if history[0] > ic.Chain.BlockHeight() {
|
||||
if history[0] > ic.BlockHeight() {
|
||||
return fmt.Errorf("native contract %s is active after height = %d", c.Metadata().Name, history[0])
|
||||
}
|
||||
m, ok := c.Metadata().GetMethodByOffset(ic.VM.Context().IP())
|
||||
|
|
|
@ -103,19 +103,19 @@ func (l *Ledger) PostPersist(ic *interop.Context) error {
|
|||
|
||||
// currentHash implements currentHash SC method.
|
||||
func (l *Ledger) currentHash(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
return stackitem.Make(ic.Chain.CurrentBlockHash().BytesBE())
|
||||
return stackitem.Make(ic.CurrentBlockHash().BytesBE())
|
||||
}
|
||||
|
||||
// currentIndex implements currentIndex SC method.
|
||||
func (l *Ledger) currentIndex(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
return stackitem.Make(ic.Chain.BlockHeight())
|
||||
return stackitem.Make(ic.BlockHeight())
|
||||
}
|
||||
|
||||
// getBlock implements getBlock SC method.
|
||||
func (l *Ledger) getBlock(ic *interop.Context, params []stackitem.Item) stackitem.Item {
|
||||
hash := getBlockHashFromItem(ic.Chain, params[0])
|
||||
block, err := ic.Chain.GetBlock(hash)
|
||||
if err != nil || !isTraceableBlock(ic.Chain, block.Index) {
|
||||
hash := getBlockHashFromItem(ic, params[0])
|
||||
block, err := ic.GetBlock(hash)
|
||||
if err != nil || !isTraceableBlock(ic, block.Index) {
|
||||
return stackitem.Null{}
|
||||
}
|
||||
return BlockToStackItem(block)
|
||||
|
@ -124,7 +124,7 @@ func (l *Ledger) getBlock(ic *interop.Context, params []stackitem.Item) stackite
|
|||
// getTransaction returns transaction to the SC.
|
||||
func (l *Ledger) getTransaction(ic *interop.Context, params []stackitem.Item) stackitem.Item {
|
||||
tx, h, err := getTransactionAndHeight(ic.DAO, params[0])
|
||||
if err != nil || !isTraceableBlock(ic.Chain, h) {
|
||||
if err != nil || !isTraceableBlock(ic, h) {
|
||||
return stackitem.Null{}
|
||||
}
|
||||
return TransactionToStackItem(tx)
|
||||
|
@ -133,7 +133,7 @@ func (l *Ledger) getTransaction(ic *interop.Context, params []stackitem.Item) st
|
|||
// getTransactionHeight returns transaction height to the SC.
|
||||
func (l *Ledger) getTransactionHeight(ic *interop.Context, params []stackitem.Item) stackitem.Item {
|
||||
_, h, err := getTransactionAndHeight(ic.DAO, params[0])
|
||||
if err != nil || !isTraceableBlock(ic.Chain, h) {
|
||||
if err != nil || !isTraceableBlock(ic, h) {
|
||||
return stackitem.Make(-1)
|
||||
}
|
||||
return stackitem.Make(h)
|
||||
|
@ -142,10 +142,10 @@ func (l *Ledger) getTransactionHeight(ic *interop.Context, params []stackitem.It
|
|||
// getTransactionFromBlock returns transaction with the given index from the
|
||||
// block with height or hash specified.
|
||||
func (l *Ledger) getTransactionFromBlock(ic *interop.Context, params []stackitem.Item) stackitem.Item {
|
||||
hash := getBlockHashFromItem(ic.Chain, params[0])
|
||||
hash := getBlockHashFromItem(ic, params[0])
|
||||
index := toUint32(params[1])
|
||||
block, err := ic.Chain.GetBlock(hash)
|
||||
if err != nil || !isTraceableBlock(ic.Chain, block.Index) {
|
||||
block, err := ic.GetBlock(hash)
|
||||
if err != nil || !isTraceableBlock(ic, block.Index) {
|
||||
return stackitem.Null{}
|
||||
}
|
||||
if index >= uint32(len(block.Transactions)) {
|
||||
|
@ -157,7 +157,7 @@ func (l *Ledger) getTransactionFromBlock(ic *interop.Context, params []stackitem
|
|||
// getTransactionSigners returns transaction signers to the SC.
|
||||
func (l *Ledger) getTransactionSigners(ic *interop.Context, params []stackitem.Item) stackitem.Item {
|
||||
tx, h, err := getTransactionAndHeight(ic.DAO, params[0])
|
||||
if err != nil || !isTraceableBlock(ic.Chain, h) {
|
||||
if err != nil || !isTraceableBlock(ic, h) {
|
||||
return stackitem.Null{}
|
||||
}
|
||||
return SignersToStackItem(tx.Signers)
|
||||
|
@ -170,7 +170,7 @@ func (l *Ledger) getTransactionVMState(ic *interop.Context, params []stackitem.I
|
|||
panic(err)
|
||||
}
|
||||
h, _, aer, err := ic.DAO.GetTxExecResult(hash)
|
||||
if err != nil || !isTraceableBlock(ic.Chain, h) {
|
||||
if err != nil || !isTraceableBlock(ic, h) {
|
||||
return stackitem.Make(vm.NoneState)
|
||||
}
|
||||
return stackitem.Make(aer.VMState)
|
||||
|
@ -178,9 +178,9 @@ func (l *Ledger) getTransactionVMState(ic *interop.Context, params []stackitem.I
|
|||
|
||||
// isTraceableBlock defines whether we're able to give information about
|
||||
// the block with index specified.
|
||||
func isTraceableBlock(bc interop.Ledger, index uint32) bool {
|
||||
height := bc.BlockHeight()
|
||||
MaxTraceableBlocks := bc.GetConfig().MaxTraceableBlocks
|
||||
func isTraceableBlock(ic *interop.Context, index uint32) bool {
|
||||
height := ic.BlockHeight()
|
||||
MaxTraceableBlocks := ic.Chain.GetConfig().MaxTraceableBlocks
|
||||
return index <= height && index+MaxTraceableBlocks > height
|
||||
}
|
||||
|
||||
|
@ -188,17 +188,17 @@ func isTraceableBlock(bc interop.Ledger, index uint32) bool {
|
|||
// Ledger if needed. Interop functions accept both block numbers and
|
||||
// block hashes as parameters, thus this function is needed. It's supposed to
|
||||
// be called within VM context, so it panics if anything goes wrong.
|
||||
func getBlockHashFromItem(bc interop.Ledger, item stackitem.Item) util.Uint256 {
|
||||
func getBlockHashFromItem(ic *interop.Context, item stackitem.Item) util.Uint256 {
|
||||
bigindex, err := item.TryInteger()
|
||||
if err == nil && bigindex.IsUint64() {
|
||||
index := bigindex.Uint64()
|
||||
if index > math.MaxUint32 {
|
||||
panic("bad block index")
|
||||
}
|
||||
if uint32(index) > bc.BlockHeight() {
|
||||
if uint32(index) > ic.BlockHeight() {
|
||||
panic(fmt.Errorf("no block with index %d", index))
|
||||
}
|
||||
return bc.GetHeaderHash(int(index))
|
||||
return ic.Chain.GetHeaderHash(int(index))
|
||||
}
|
||||
hash, err := getUint256FromItem(item)
|
||||
if err != nil {
|
||||
|
|
|
@ -249,7 +249,7 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
|||
|
||||
committee0 := n.standbyKeys[:n.cfg.GetCommitteeSize(ic.Block.Index)]
|
||||
cvs := toKeysWithVotes(committee0)
|
||||
err := n.updateCache(cache, cvs, ic.Chain)
|
||||
err := n.updateCache(cache, cvs, ic.BlockHeight())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
|||
// InitializeCache initializes all NEO cache with the proper values from storage.
|
||||
// Cache initialisation should be done apart from Initialize because Initialize is
|
||||
// called only when deploying native contracts.
|
||||
func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error {
|
||||
func (n *NEO) InitializeCache(blockHeight uint32, d *dao.Simple) error {
|
||||
cache := &NeoCache{
|
||||
gasPerVoteCache: make(map[string]big.Int),
|
||||
votesChanged: true,
|
||||
|
@ -290,7 +290,7 @@ func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error {
|
|||
if err := committee.DecodeBytes(si); err != nil {
|
||||
return fmt.Errorf("failed to decode committee: %w", err)
|
||||
}
|
||||
if err := n.updateCache(cache, committee, bc); err != nil {
|
||||
if err := n.updateCache(cache, committee, blockHeight); err != nil {
|
||||
return fmt.Errorf("failed to update cache: %w", err)
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ func (n *NEO) initConfigCache(cfg config.ProtocolConfiguration) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, bc interop.Ledger) error {
|
||||
func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, blockHeight uint32) error {
|
||||
cache.committee = cvs
|
||||
|
||||
var committee = getCommitteeMembers(cache)
|
||||
|
@ -319,8 +319,7 @@ func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, bc interop.Ledger)
|
|||
}
|
||||
cache.committeeHash = hash.Hash160(script)
|
||||
|
||||
// TODO: use block height from interop context for proper historical calls handling.
|
||||
nextVals := committee[:n.cfg.GetNumOfCNs(bc.BlockHeight()+1)].Copy()
|
||||
nextVals := committee[:n.cfg.GetNumOfCNs(blockHeight+1)].Copy()
|
||||
sort.Sort(nextVals)
|
||||
cache.nextValidators = nextVals
|
||||
return nil
|
||||
|
@ -333,11 +332,11 @@ func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
_, cvs, err := n.computeCommitteeMembers(ic.Chain, ic.DAO)
|
||||
_, cvs, err := n.computeCommitteeMembers(ic.BlockHeight(), ic.DAO)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := n.updateCache(cache, cvs, ic.Chain); err != nil {
|
||||
if err := n.updateCache(cache, cvs, ic.BlockHeight()); err != nil {
|
||||
return err
|
||||
}
|
||||
cache.votesChanged = false
|
||||
|
@ -939,8 +938,8 @@ func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stacki
|
|||
}
|
||||
|
||||
// ComputeNextBlockValidators returns an actual list of current validators.
|
||||
func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d *dao.Simple) (keys.PublicKeys, error) {
|
||||
numOfCNs := n.cfg.GetNumOfCNs(bc.BlockHeight() + 1)
|
||||
func (n *NEO) ComputeNextBlockValidators(blockHeight uint32, d *dao.Simple) (keys.PublicKeys, error) {
|
||||
numOfCNs := n.cfg.GetNumOfCNs(blockHeight + 1)
|
||||
// Most of the time it should be OK with RO cache, thus try to retrieve
|
||||
// validators without RW cache creation to avoid cached values copying.
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
|
@ -948,7 +947,7 @@ func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d *dao.Simple) (keys
|
|||
return vals.Copy(), nil
|
||||
}
|
||||
cache = d.GetRWCache(n.ID).(*NeoCache)
|
||||
result, _, err := n.computeCommitteeMembers(bc, d)
|
||||
result, _, err := n.computeCommitteeMembers(blockHeight, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1007,7 +1006,7 @@ func toKeysWithVotes(pubs keys.PublicKeys) keysWithVotes {
|
|||
}
|
||||
|
||||
// computeCommitteeMembers returns public keys of nodes in committee.
|
||||
func (n *NEO) computeCommitteeMembers(bc interop.Ledger, d *dao.Simple) (keys.PublicKeys, keysWithVotes, error) {
|
||||
func (n *NEO) computeCommitteeMembers(blockHeight uint32, d *dao.Simple) (keys.PublicKeys, keysWithVotes, error) {
|
||||
key := []byte{prefixVotersCount}
|
||||
si := d.GetStorageItem(n.ID, key)
|
||||
if si == nil {
|
||||
|
@ -1019,7 +1018,7 @@ func (n *NEO) computeCommitteeMembers(bc interop.Ledger, d *dao.Simple) (keys.Pu
|
|||
_, totalSupply := n.getTotalSupply(d)
|
||||
voterTurnout := votersCount.Div(votersCount, totalSupply)
|
||||
|
||||
count := n.cfg.GetCommitteeSize(bc.BlockHeight() + 1)
|
||||
count := n.cfg.GetCommitteeSize(blockHeight + 1)
|
||||
// Can be sorted and/or returned to outside users, thus needs to be copied.
|
||||
sbVals := keys.PublicKeys(n.standbyKeys[:count]).Copy()
|
||||
cs, err := n.getCandidates(d, false)
|
||||
|
|
|
@ -223,7 +223,7 @@ func (n *Notary) onPayment(ic *interop.Context, args []stackitem.Item) stackitem
|
|||
}
|
||||
|
||||
allowedChangeTill := ic.Tx.Sender() == to
|
||||
currentHeight := ic.Chain.BlockHeight()
|
||||
currentHeight := ic.BlockHeight()
|
||||
deposit := n.GetDepositFor(ic.DAO, to)
|
||||
till := toUint32(additionalParams[1])
|
||||
if till < currentHeight {
|
||||
|
@ -266,7 +266,7 @@ func (n *Notary) lockDepositUntil(ic *interop.Context, args []stackitem.Item) st
|
|||
return stackitem.NewBool(false)
|
||||
}
|
||||
till := toUint32(args[1])
|
||||
if till < ic.Chain.BlockHeight() {
|
||||
if till < ic.BlockHeight() {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
deposit := n.GetDepositFor(ic.DAO, addr)
|
||||
|
@ -302,7 +302,7 @@ func (n *Notary) withdraw(ic *interop.Context, args []stackitem.Item) stackitem.
|
|||
if deposit == nil {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
if ic.Chain.BlockHeight() < deposit.Till {
|
||||
if ic.BlockHeight() < deposit.Till {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
cs, err := ic.GetContract(n.GAS.Hash)
|
||||
|
@ -416,8 +416,8 @@ func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem
|
|||
value := toUint32(args[0])
|
||||
cfg := ic.Chain.GetConfig()
|
||||
maxInc := cfg.MaxValidUntilBlockIncrement
|
||||
if value > maxInc/2 || value < uint32(cfg.GetNumOfCNs(ic.Chain.BlockHeight())) {
|
||||
panic(fmt.Errorf("MaxNotValidBeforeDelta cannot be more than %d or less than %d", maxInc/2, cfg.GetNumOfCNs(ic.Chain.BlockHeight())))
|
||||
if value > maxInc/2 || value < uint32(cfg.GetNumOfCNs(ic.BlockHeight())) {
|
||||
panic(fmt.Errorf("MaxNotValidBeforeDelta cannot be more than %d or less than %d", maxInc/2, cfg.GetNumOfCNs(ic.BlockHeight())))
|
||||
}
|
||||
if !n.NEO.checkCommittee(ic) {
|
||||
panic("invalid committee signature")
|
||||
|
|
Loading…
Reference in a new issue