Merge pull request #572 from nspcc-dev/tiny-vm-and-core-speedups

This eliminates some easy to fix blocks, but the overall improvement is on the order
of ~1-2%, so it's hardly visible in a 100K block import test. Still, it slightly reduces
the DB pressure and eliminates useless hashing, so it's nice to have.
This commit is contained in:
Roman Khimov 2019-12-23 22:19:34 +03:00 committed by GitHub
commit f92e84c4cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 1 deletions

View file

@ -55,6 +55,9 @@ type Blockchain struct {
// Write access should only happen in storeBlock().
blockHeight uint32
// Current top Block wrapped in an atomic.Value for safe access.
topBlock atomic.Value
// Current persisted block count.
persistedHeight uint32
@ -558,6 +561,7 @@ func (bc *Blockchain) storeBlock(block *Block) error {
if err != nil {
return err
}
bc.topBlock.Store(block)
atomic.StoreUint32(&bc.blockHeight, block.Index)
updateBlockHeightMetric(block.Index)
for _, tx := range block.Transactions {
@ -749,6 +753,13 @@ func (bc *Blockchain) GetStorageItems(hash util.Uint160) (map[string]*state.Stor
// GetBlock returns a Block by the given hash.
func (bc *Blockchain) GetBlock(hash util.Uint256) (*Block, error) {
topBlock := bc.topBlock.Load()
if topBlock != nil {
if tb, ok := topBlock.(*Block); ok && tb.Hash().Equals(hash) {
return tb, nil
}
}
block, err := bc.dao.GetBlock(hash)
if err != nil {
return nil, err
@ -768,6 +779,12 @@ func (bc *Blockchain) GetBlock(hash util.Uint256) (*Block, error) {
// GetHeader returns data block header identified with the given hash value.
func (bc *Blockchain) GetHeader(hash util.Uint256) (*Header, error) {
topBlock := bc.topBlock.Load()
if topBlock != nil {
if tb, ok := topBlock.(*Block); ok && tb.Hash().Equals(hash) {
return tb.Header(), nil
}
}
block, err := bc.dao.GetBlock(hash)
if err != nil {
return nil, err

View file

@ -238,6 +238,14 @@ func (v *VM) LoadScript(b []byte) {
v.istack.PushVal(ctx)
}
// loadScriptWithHash if similar to the LoadScript method, but it also loads
// given script hash directly into the Context to avoid its recalculations. It's
// up to user of this function to make sure the script and hash match each other.
func (v *VM) loadScriptWithHash(b []byte, hash util.Uint160) {
v.LoadScript(b)
v.istack.Top().Value().(*Context).scriptHash = hash
}
// Context returns the current executed context. Nil if there is no context,
// which implies no program is loaded.
func (v *VM) Context() *Context {
@ -1120,7 +1128,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
_ = v.istack.Pop()
}
v.LoadScript(script)
v.loadScriptWithHash(script, hash)
case opcode.RET:
oldCtx := v.istack.Pop().Value().(*Context)
@ -1336,6 +1344,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
panic(fmt.Sprintf("could not find script %s", hash))
}
newCtx = NewContext(script)
newCtx.scriptHash = hash
}
newCtx.rvcount = rvcount
newCtx.estack = NewStack("evaluation")