core: store statesync-related storage items under temp prefix
State jump should be an atomic operation, we can't modify contract storage items state on-the-fly. Thus, store fresh items under temp prefix and replase the outdated ones after state sync is completed. Related https://github.com/nspcc-dev/neo-go/pull/2019#discussion_r693350460.
This commit is contained in:
parent
51f405471e
commit
6381173293
3 changed files with 37 additions and 10 deletions
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"go.uber.org/zap"
|
||||
|
@ -43,7 +44,7 @@ import (
|
|||
// Tuning parameters.
|
||||
const (
|
||||
headerBatchCount = 2000
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
|
||||
defaultInitialGAS = 52000000_00000000
|
||||
defaultMemPoolSize = 50000
|
||||
|
@ -451,6 +452,27 @@ func (bc *Blockchain) JumpToState(module blockchainer.StateSync) error {
|
|||
return fmt.Errorf("can't perform MPT jump to height %d: %w", p, err)
|
||||
}
|
||||
|
||||
b := bc.dao.Store.Batch()
|
||||
bc.dao.Store.Seek([]byte{byte(storage.STStorage)}, func(k, _ []byte) {
|
||||
// Must copy here, #1468.
|
||||
key := slice.Copy(k)
|
||||
b.Delete(key)
|
||||
})
|
||||
bc.dao.Store.Seek([]byte{byte(storage.STTempStorage)}, func(k, v []byte) {
|
||||
// Must copy here, #1468.
|
||||
oldKey := slice.Copy(k)
|
||||
b.Delete(oldKey)
|
||||
key := make([]byte, len(k))
|
||||
key[0] = byte(storage.STStorage)
|
||||
copy(key[1:], k[1:])
|
||||
value := slice.Copy(v)
|
||||
b.Put(key, value)
|
||||
})
|
||||
err = bc.dao.Store.PutBatch(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to replace outdated contract storage items with the fresh ones: %w", err)
|
||||
}
|
||||
|
||||
err = bc.contracts.NEO.InitializeCache(bc, bc.dao)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't init cache for NEO native contract: %w", err)
|
||||
|
|
|
@ -62,9 +62,9 @@ func (b *Billet) RestoreHashNode(path []byte, node Node) error {
|
|||
}
|
||||
b.root = r
|
||||
|
||||
// If it's a leaf, then put into contract storage.
|
||||
// If it's a leaf, then put into temporary contract storage.
|
||||
if leaf, ok := node.(*LeafNode); ok {
|
||||
k := append([]byte{byte(storage.STStorage)}, fromNibbles(path)...)
|
||||
k := append([]byte{byte(storage.STTempStorage)}, fromNibbles(path)...)
|
||||
_ = b.Store.Put(k, leaf.value)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -8,13 +8,18 @@ import (
|
|||
|
||||
// KeyPrefix constants.
|
||||
const (
|
||||
DataBlock KeyPrefix = 0x01
|
||||
DataTransaction KeyPrefix = 0x02
|
||||
DataMPT KeyPrefix = 0x03
|
||||
STAccount KeyPrefix = 0x40
|
||||
STNotification KeyPrefix = 0x4d
|
||||
STContractID KeyPrefix = 0x51
|
||||
STStorage KeyPrefix = 0x70
|
||||
DataBlock KeyPrefix = 0x01
|
||||
DataTransaction KeyPrefix = 0x02
|
||||
DataMPT KeyPrefix = 0x03
|
||||
STAccount KeyPrefix = 0x40
|
||||
STNotification KeyPrefix = 0x4d
|
||||
STContractID KeyPrefix = 0x51
|
||||
STStorage KeyPrefix = 0x70
|
||||
// STTempStorage is used to store contract storage items during state sync process
|
||||
// in order not to mess up the previous state which has its own items stored by
|
||||
// STStorage prefix. Once state exchange process is completed, all items with
|
||||
// STStorage prefix will be replaced with STTempStorage-prefixed ones.
|
||||
STTempStorage KeyPrefix = 0x71
|
||||
STNEP17Transfers KeyPrefix = 0x72
|
||||
STNEP17TransferInfo KeyPrefix = 0x73
|
||||
IXHeaderHashList KeyPrefix = 0x80
|
||||
|
|
Loading…
Reference in a new issue