2020-04-07 09:41:12 +00:00
package dao
2019-11-25 17:39:11 +00:00
import (
2024-03-04 18:09:36 +00:00
"bytes"
2021-10-06 12:54:44 +00:00
"context"
2019-11-25 17:39:11 +00:00
"encoding/binary"
2020-10-15 11:45:29 +00:00
"errors"
2022-02-25 10:44:14 +00:00
"fmt"
2020-11-11 15:43:28 +00:00
iocore "io"
2022-05-31 20:10:56 +00:00
"math/big"
2022-04-20 14:47:48 +00:00
"sync"
2019-11-25 17:39:11 +00:00
2022-07-08 16:51:59 +00:00
"github.com/nspcc-dev/neo-go/pkg/config/limits"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/core/block"
"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"
2023-09-19 14:35:51 +00:00
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
2022-05-31 20:10:56 +00:00
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/io"
2020-11-11 15:43:28 +00:00
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/util"
2022-05-31 17:10:20 +00:00
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
2019-11-25 17:39:11 +00:00
)
2021-05-12 20:17:03 +00:00
// HasTransaction errors.
2020-10-15 11:45:29 +00:00
var (
2022-04-20 18:30:09 +00:00
// ErrAlreadyExists is returned when the transaction exists in dao.
2020-10-15 11:45:29 +00:00
ErrAlreadyExists = errors . New ( "transaction already exists" )
2022-04-20 18:30:09 +00:00
// ErrHasConflicts is returned when the transaction is in the list of conflicting
2020-10-15 11:45:29 +00:00
// transactions which are already in dao.
ErrHasConflicts = errors . New ( "transaction has conflicts" )
2022-04-20 18:30:09 +00:00
// ErrInternalDBInconsistency is returned when the format of the retrieved DAO
2022-04-04 16:07:32 +00:00
// record is unexpected.
ErrInternalDBInconsistency = errors . New ( "internal DB inconsistency" )
2020-10-15 11:45:29 +00:00
)
2020-04-07 09:41:12 +00:00
// Simple is memCached wrapper around DB, simple DAO implementation.
type Simple struct {
2021-10-22 07:58:53 +00:00
Version Version
Store * storage . MemCachedStore
2022-04-20 14:47:48 +00:00
nativeCacheLock sync . RWMutex
nativeCache map [ int32 ] NativeContractCache
// nativeCachePS is the backend store that provides functionality to store
// and retrieve multi-tier native contract cache. The lowest Simple has its
// nativeCachePS set to nil.
nativeCachePS * Simple
2022-02-18 11:24:45 +00:00
private bool
2022-05-31 17:10:20 +00:00
serCtx * stackitem . SerializationContext
2022-02-16 20:33:53 +00:00
keyBuf [ ] byte
dataBuf * io . BufBinWriter
2019-11-25 17:39:11 +00:00
}
2022-04-20 14:47:48 +00:00
// NativeContractCache is an interface representing cache for a native contract.
// Cache can be copied to create a wrapper around current DAO layer. Wrapped cache
// can be persisted to the underlying DAO native cache.
type NativeContractCache interface {
// Copy returns a copy of native cache item that can safely be changed within
// the subsequent DAO operations.
Copy ( ) NativeContractCache
}
2022-04-20 18:30:09 +00:00
// NewSimple creates a new simple dao using the provided backend store.
2023-09-04 13:48:16 +00:00
func NewSimple ( backend storage . Store , stateRootInHeader bool ) * Simple {
2020-05-29 14:20:00 +00:00
st := storage . NewMemCachedStore ( backend )
2023-09-04 13:48:16 +00:00
return newSimple ( st , stateRootInHeader )
2022-02-16 16:13:06 +00:00
}
2023-09-04 13:48:16 +00:00
func newSimple ( st * storage . MemCachedStore , stateRootInHeader bool ) * Simple {
2021-09-27 13:35:25 +00:00
return & Simple {
2021-10-22 07:58:53 +00:00
Version : Version {
StoragePrefix : storage . STStorage ,
StateRootInHeader : stateRootInHeader ,
} ,
2022-04-20 14:47:48 +00:00
Store : st ,
nativeCache : make ( map [ int32 ] NativeContractCache ) ,
2021-09-27 13:35:25 +00:00
}
2020-04-03 06:49:01 +00:00
}
2022-04-20 18:30:09 +00:00
// GetBatch returns the currently accumulated DB changeset.
2020-04-07 09:41:12 +00:00
func ( dao * Simple ) GetBatch ( ) * storage . MemBatch {
return dao . Store . GetBatch ( )
2020-04-03 06:49:01 +00:00
}
2022-04-20 18:30:09 +00:00
// GetWrapped returns a new DAO instance with another layer of wrapped
2020-04-07 09:41:12 +00:00
// MemCachedStore around the current DAO Store.
2022-02-16 15:04:47 +00:00
func ( dao * Simple ) GetWrapped ( ) * Simple {
2023-09-04 13:48:16 +00:00
d := NewSimple ( dao . Store , dao . Version . StateRootInHeader )
2021-10-22 07:58:53 +00:00
d . Version = dao . Version
2022-04-20 14:47:48 +00:00
d . nativeCachePS = dao
2020-05-29 14:20:00 +00:00
return d
2019-12-12 18:04:55 +00:00
}
2022-04-20 18:30:09 +00:00
// GetPrivate returns a new DAO instance with another layer of private
2022-02-16 16:13:06 +00:00
// MemCachedStore around the current DAO Store.
func ( dao * Simple ) GetPrivate ( ) * Simple {
2022-04-20 15:42:49 +00:00
d := & Simple {
Version : dao . Version ,
keyBuf : dao . keyBuf ,
dataBuf : dao . dataBuf ,
2022-05-31 17:10:20 +00:00
serCtx : dao . serCtx ,
2022-04-20 15:42:49 +00:00
} // Inherit everything...
2022-02-18 11:18:56 +00:00
d . Store = storage . NewPrivateMemCachedStore ( dao . Store ) // except storage, wrap another layer.
2022-02-18 11:24:45 +00:00
d . private = true
2022-04-20 14:47:48 +00:00
d . nativeCachePS = dao
// Do not inherit cache from nativeCachePS; instead should create clear map:
// GetRWCache and GetROCache will retrieve cache from the underlying
// nativeCache if requested. The lowest underlying DAO MUST have its native
// cache initialized before access it, otherwise GetROCache and GetRWCache
// won't work properly.
d . nativeCache = make ( map [ int32 ] NativeContractCache )
2022-02-16 16:13:06 +00:00
return d
}
2019-11-25 17:39:11 +00:00
// GetAndDecode performs get operation and decoding with serializable structures.
2020-04-07 09:41:12 +00:00
func ( dao * Simple ) GetAndDecode ( entity io . Serializable , key [ ] byte ) error {
entityBytes , err := dao . Store . Get ( key )
2019-11-25 17:39:11 +00:00
if err != nil {
return err
}
reader := io . NewBinReaderFromBuf ( entityBytes )
entity . DecodeBinary ( reader )
return reader . Err
}
2020-03-17 09:06:46 +00:00
// putWithBuffer performs put operation using buf as a pre-allocated buffer for serialization.
2020-04-07 09:41:12 +00:00
func ( dao * Simple ) putWithBuffer ( entity io . Serializable , key [ ] byte , buf * io . BufBinWriter ) error {
2019-11-25 17:39:11 +00:00
entity . EncodeBinary ( buf . BinWriter )
if buf . Err != nil {
return buf . Err
}
2022-02-16 14:48:15 +00:00
dao . Store . Put ( key , buf . Bytes ( ) )
return nil
2019-11-25 17:39:11 +00:00
}
2021-11-18 13:37:42 +00:00
// -- start NEP-17 transfer info.
2020-03-11 15:22:46 +00:00
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) makeTTIKey ( acc util . Uint160 ) [ ] byte {
key := dao . getKeyBuf ( 1 + util . Uint160Size )
key [ 0 ] = byte ( storage . STTokenTransferInfo )
copy ( key [ 1 : ] , acc . BytesBE ( ) )
return key
}
2021-11-18 13:37:42 +00:00
// GetTokenTransferInfo retrieves NEP-17 transfer info from the cache.
2021-11-16 16:18:06 +00:00
func ( dao * Simple ) GetTokenTransferInfo ( acc util . Uint160 ) ( * state . TokenTransferInfo , error ) {
2022-02-16 20:33:53 +00:00
key := dao . makeTTIKey ( acc )
2021-11-16 16:18:06 +00:00
bs := state . NewTokenTransferInfo ( )
2020-03-11 15:22:46 +00:00
err := dao . GetAndDecode ( bs , key )
2022-09-02 11:29:47 +00:00
if err != nil && ! errors . Is ( err , storage . ErrKeyNotFound ) {
2020-03-11 15:22:46 +00:00
return nil , err
}
return bs , nil
}
2021-11-18 13:37:42 +00:00
// PutTokenTransferInfo saves NEP-17 transfer info in the cache.
2021-11-16 16:18:06 +00:00
func ( dao * Simple ) PutTokenTransferInfo ( acc util . Uint160 , bs * state . TokenTransferInfo ) error {
2022-02-16 20:33:53 +00:00
return dao . putTokenTransferInfo ( acc , bs , dao . getDataBuf ( ) )
2020-03-17 09:06:46 +00:00
}
2021-11-16 16:18:06 +00:00
func ( dao * Simple ) putTokenTransferInfo ( acc util . Uint160 , bs * state . TokenTransferInfo , buf * io . BufBinWriter ) error {
2022-02-16 20:33:53 +00:00
return dao . putWithBuffer ( bs , dao . makeTTIKey ( acc ) , buf )
2020-03-11 15:22:46 +00:00
}
2021-11-18 13:37:42 +00:00
// -- end NEP-17 transfer info.
2020-03-11 15:22:46 +00:00
2020-03-05 14:11:58 +00:00
// -- start transfer log.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) getTokenTransferLogKey ( acc util . Uint160 , newestTimestamp uint64 , index uint32 , isNEP11 bool ) [ ] byte {
key := dao . getKeyBuf ( 1 + util . Uint160Size + 8 + 4 )
2021-11-16 20:09:04 +00:00
if isNEP11 {
key [ 0 ] = byte ( storage . STNEP11Transfers )
} else {
key [ 0 ] = byte ( storage . STNEP17Transfers )
}
2020-03-12 09:43:21 +00:00
copy ( key [ 1 : ] , acc . BytesBE ( ) )
2022-01-18 15:28:24 +00:00
binary . BigEndian . PutUint64 ( key [ 1 + util . Uint160Size : ] , newestTimestamp )
binary . BigEndian . PutUint32 ( key [ 1 + util . Uint160Size + 8 : ] , index )
2020-03-12 09:43:21 +00:00
return key
}
2022-01-18 15:28:24 +00:00
// SeekNEP17TransferLog executes f for each NEP-17 transfer in log starting from
// the transfer with the newest timestamp up to the oldest transfer. It continues
// iteration until false is returned from f. The last non-nil error is returned.
func ( dao * Simple ) SeekNEP17TransferLog ( acc util . Uint160 , newestTimestamp uint64 , f func ( * state . NEP17Transfer ) ( bool , error ) ) error {
2022-02-16 20:33:53 +00:00
key := dao . getTokenTransferLogKey ( acc , newestTimestamp , 0 , false )
2022-01-18 15:28:24 +00:00
prefixLen := 1 + util . Uint160Size
var seekErr error
dao . Store . Seek ( storage . SeekRange {
Prefix : key [ : prefixLen ] ,
Start : key [ prefixLen : prefixLen + 8 ] ,
Backwards : true ,
} , func ( k , v [ ] byte ) bool {
lg := & state . TokenTransferLog { Raw : v }
cont , err := lg . ForEachNEP17 ( f )
if err != nil {
seekErr = err
}
return cont
} )
return seekErr
}
// SeekNEP11TransferLog executes f for each NEP-11 transfer in log starting from
// the transfer with the newest timestamp up to the oldest transfer. It continues
// iteration until false is returned from f. The last non-nil error is returned.
func ( dao * Simple ) SeekNEP11TransferLog ( acc util . Uint160 , newestTimestamp uint64 , f func ( * state . NEP11Transfer ) ( bool , error ) ) error {
2022-02-16 20:33:53 +00:00
key := dao . getTokenTransferLogKey ( acc , newestTimestamp , 0 , true )
2022-01-18 15:28:24 +00:00
prefixLen := 1 + util . Uint160Size
var seekErr error
dao . Store . Seek ( storage . SeekRange {
Prefix : key [ : prefixLen ] ,
Start : key [ prefixLen : prefixLen + 8 ] ,
Backwards : true ,
} , func ( k , v [ ] byte ) bool {
lg := & state . TokenTransferLog { Raw : v }
cont , err := lg . ForEachNEP11 ( f )
if err != nil {
seekErr = err
}
return cont
} )
return seekErr
}
2021-11-16 16:18:06 +00:00
// GetTokenTransferLog retrieves transfer log from the cache.
2022-01-18 15:28:24 +00:00
func ( dao * Simple ) GetTokenTransferLog ( acc util . Uint160 , newestTimestamp uint64 , index uint32 , isNEP11 bool ) ( * state . TokenTransferLog , error ) {
2022-02-16 20:33:53 +00:00
key := dao . getTokenTransferLogKey ( acc , newestTimestamp , index , isNEP11 )
2020-04-07 09:41:12 +00:00
value , err := dao . Store . Get ( key )
2020-03-05 14:11:58 +00:00
if err != nil {
2022-09-02 11:29:47 +00:00
if errors . Is ( err , storage . ErrKeyNotFound ) {
2021-11-16 16:18:06 +00:00
return new ( state . TokenTransferLog ) , nil
2020-03-05 12:16:03 +00:00
}
2020-03-05 14:11:58 +00:00
return nil , err
}
2021-11-16 16:18:06 +00:00
return & state . TokenTransferLog { Raw : value } , nil
2020-03-05 14:11:58 +00:00
}
2022-04-20 18:30:09 +00:00
// PutTokenTransferLog saves the given transfer log in the cache.
2022-02-16 14:48:15 +00:00
func ( dao * Simple ) PutTokenTransferLog ( acc util . Uint160 , start uint64 , index uint32 , isNEP11 bool , lg * state . TokenTransferLog ) {
2022-02-16 20:33:53 +00:00
key := dao . getTokenTransferLogKey ( acc , start , index , isNEP11 )
2022-02-16 14:48:15 +00:00
dao . Store . Put ( key , lg . Raw )
2020-03-05 14:11:58 +00:00
}
// -- end transfer log.
2019-11-25 17:39:11 +00:00
// -- start notification event.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) makeExecutableKey ( hash util . Uint256 ) [ ] byte {
key := dao . getKeyBuf ( 1 + util . Uint256Size )
key [ 0 ] = byte ( storage . DataExecutable )
copy ( key [ 1 : ] , hash . BytesBE ( ) )
return key
}
2020-11-11 15:43:28 +00:00
// GetAppExecResults gets application execution results with the specified trigger from the
2019-11-25 17:39:11 +00:00
// given store.
2020-11-11 15:43:28 +00:00
func ( dao * Simple ) GetAppExecResults ( hash util . Uint256 , trig trigger . Type ) ( [ ] state . AppExecResult , error ) {
2022-02-16 20:33:53 +00:00
key := dao . makeExecutableKey ( hash )
2021-12-07 20:05:28 +00:00
bs , err := dao . Store . Get ( key )
2019-11-25 17:39:11 +00:00
if err != nil {
return nil , err
}
2022-04-04 16:28:36 +00:00
if len ( bs ) == 0 {
return nil , fmt . Errorf ( "%w: empty execution log" , ErrInternalDBInconsistency )
}
switch bs [ 0 ] {
2021-12-07 20:05:28 +00:00
case storage . ExecBlock :
2022-04-04 16:28:36 +00:00
r := io . NewBinReaderFromBuf ( bs )
_ = r . ReadB ( )
2021-12-07 20:05:28 +00:00
_ , err = block . NewTrimmedFromReader ( dao . Version . StateRootInHeader , r )
if err != nil {
return nil , err
}
2022-04-04 16:28:36 +00:00
result := make ( [ ] state . AppExecResult , 0 , 2 )
for {
aer := new ( state . AppExecResult )
aer . DecodeBinary ( r )
if r . Err != nil {
2022-09-02 11:29:47 +00:00
if errors . Is ( r . Err , iocore . EOF ) {
2022-04-04 16:28:36 +00:00
break
}
return nil , r . Err
}
if aer . Trigger & trig != 0 {
result = append ( result , * aer )
}
}
return result , nil
2021-12-07 20:05:28 +00:00
case storage . ExecTransaction :
2022-04-04 16:28:36 +00:00
_ , _ , aer , err := decodeTxAndExecResult ( bs )
if err != nil {
return nil , err
2022-04-04 09:47:29 +00:00
}
2022-04-04 16:28:36 +00:00
if aer . Trigger & trig != 0 {
return [ ] state . AppExecResult { * aer } , nil
}
return nil , nil
2022-04-04 16:07:32 +00:00
default :
2022-04-04 16:28:36 +00:00
return nil , fmt . Errorf ( "%w: unexpected executable prefix %d" , ErrInternalDBInconsistency , bs [ 0 ] )
2021-12-07 20:05:28 +00:00
}
2022-04-04 16:28:36 +00:00
}
// GetTxExecResult gets application execution result of the specified transaction
// and returns the transaction itself, its height and its AppExecResult.
func ( dao * Simple ) GetTxExecResult ( hash util . Uint256 ) ( uint32 , * transaction . Transaction , * state . AppExecResult , error ) {
key := dao . makeExecutableKey ( hash )
bs , err := dao . Store . Get ( key )
if err != nil {
return 0 , nil , nil , err
}
if len ( bs ) == 0 {
return 0 , nil , nil , fmt . Errorf ( "%w: empty execution log" , ErrInternalDBInconsistency )
}
if bs [ 0 ] != storage . ExecTransaction {
return 0 , nil , nil , storage . ErrKeyNotFound
}
return decodeTxAndExecResult ( bs )
}
// decodeTxAndExecResult decodes transaction, its height and execution result from
// the given executable bytes. It performs no executable prefix check.
func decodeTxAndExecResult ( buf [ ] byte ) ( uint32 , * transaction . Transaction , * state . AppExecResult , error ) {
if len ( buf ) >= 6 && buf [ 5 ] == transaction . DummyVersion {
return 0 , nil , nil , storage . ErrKeyNotFound
}
r := io . NewBinReaderFromBuf ( buf )
_ = r . ReadB ( )
h := r . ReadU32LE ( )
tx := & transaction . Transaction { }
tx . DecodeBinary ( r )
2021-12-07 20:05:28 +00:00
if r . Err != nil {
2022-04-04 16:28:36 +00:00
return 0 , nil , nil , r . Err
2021-12-07 20:05:28 +00:00
}
2022-04-04 16:28:36 +00:00
aer := new ( state . AppExecResult )
aer . DecodeBinary ( r )
if r . Err != nil {
return 0 , nil , nil , r . Err
2020-11-11 15:43:28 +00:00
}
2022-04-04 16:28:36 +00:00
return h , tx , aer , nil
2020-11-11 15:43:28 +00:00
}
2019-11-25 17:39:11 +00:00
// -- end notification event.
// -- start storage item.
2020-04-07 09:41:12 +00:00
// GetStorageItem returns StorageItem if it exists in the given store.
2021-03-05 14:06:54 +00:00
func ( dao * Simple ) GetStorageItem ( id int32 , key [ ] byte ) state . StorageItem {
2022-02-16 20:33:53 +00:00
b , err := dao . Store . Get ( dao . makeStorageItemKey ( id , key ) )
2019-11-25 17:39:11 +00:00
if err != nil {
return nil
}
2021-03-09 09:09:44 +00:00
return b
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// PutStorageItem puts the given StorageItem for the given id with the given
2020-04-07 09:41:12 +00:00
// key into the given store.
2022-02-16 14:48:15 +00:00
func ( dao * Simple ) PutStorageItem ( id int32 , key [ ] byte , si state . StorageItem ) {
2022-02-16 20:33:53 +00:00
stKey := dao . makeStorageItemKey ( id , key )
2022-02-16 14:48:15 +00:00
dao . Store . Put ( stKey , si )
2019-11-25 17:39:11 +00:00
}
2022-05-31 20:10:56 +00:00
// PutBigInt serializaed and puts the given integer for the given id with the given
// key into the given store.
func ( dao * Simple ) PutBigInt ( id int32 , key [ ] byte , n * big . Int ) {
var buf [ bigint . MaxBytesLen ] byte
stData := bigint . ToPreallocatedBytes ( n , buf [ : ] )
dao . PutStorageItem ( id , key , stData )
}
2022-04-20 18:30:09 +00:00
// DeleteStorageItem drops a storage item for the given id with the
2020-04-07 09:41:12 +00:00
// given key from the store.
2022-02-16 14:48:15 +00:00
func ( dao * Simple ) DeleteStorageItem ( id int32 , key [ ] byte ) {
2022-02-16 20:33:53 +00:00
stKey := dao . makeStorageItemKey ( id , key )
2022-02-16 14:48:15 +00:00
dao . Store . Delete ( stKey )
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// Seek executes f for all storage items matching the given `rng` (matching the given prefix and
// starting from the point specified). If the key or the value is to be used outside of f, they
2023-11-23 15:44:19 +00:00
// may not be copied. Seek continues iterating until false is returned from f. A requested prefix
// (if any non-empty) is trimmed before passing to f.
2022-01-17 17:41:51 +00:00
func ( dao * Simple ) Seek ( id int32 , rng storage . SeekRange , f func ( k , v [ ] byte ) bool ) {
2024-03-04 18:09:36 +00:00
rng . Prefix = bytes . Clone ( dao . makeStorageItemKey ( id , rng . Prefix ) ) // f() can use dao too.
2022-01-17 17:41:51 +00:00
dao . Store . Seek ( rng , func ( k , v [ ] byte ) bool {
return f ( k [ len ( rng . Prefix ) : ] , v )
2021-10-19 15:03:47 +00:00
} )
2021-10-04 14:01:42 +00:00
}
2022-04-20 18:30:09 +00:00
// SeekAsync sends all storage items matching the given `rng` (matching the given prefix and
2021-12-16 13:55:50 +00:00
// starting from the point specified) to a channel and returns the channel.
// Resulting keys and values may not be copied.
func ( dao * Simple ) SeekAsync ( ctx context . Context , id int32 , rng storage . SeekRange ) chan storage . KeyValue {
2024-03-04 18:09:36 +00:00
rng . Prefix = bytes . Clone ( dao . makeStorageItemKey ( id , rng . Prefix ) )
2021-12-16 13:55:50 +00:00
return dao . Store . SeekAsync ( ctx , rng , true )
2020-11-03 15:08:58 +00:00
}
2022-04-20 18:30:09 +00:00
// makeStorageItemKey returns the key used to store the StorageItem in the DB.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) makeStorageItemKey ( id int32 , key [ ] byte ) [ ] byte {
2020-06-18 10:50:30 +00:00
// 1 for prefix + 4 for Uint32 + len(key) for key
2022-02-16 20:33:53 +00:00
buf := dao . getKeyBuf ( 5 + len ( key ) )
buf [ 0 ] = byte ( dao . Version . StoragePrefix )
2020-06-18 10:50:30 +00:00
binary . LittleEndian . PutUint32 ( buf [ 1 : ] , uint32 ( id ) )
copy ( buf [ 5 : ] , key )
return buf
2019-11-25 17:39:11 +00:00
}
// -- end storage item.
// -- other.
// GetBlock returns Block by the given hash if it exists in the store.
2020-06-04 19:59:34 +00:00
func ( dao * Simple ) GetBlock ( hash util . Uint256 ) ( * block . Block , error ) {
2022-02-18 08:41:27 +00:00
return dao . getBlock ( dao . makeExecutableKey ( hash ) )
}
func ( dao * Simple ) getBlock ( key [ ] byte ) ( * block . Block , error ) {
2020-04-07 09:41:12 +00:00
b , err := dao . Store . Get ( key )
2019-11-25 17:39:11 +00:00
if err != nil {
2020-06-04 19:59:34 +00:00
return nil , err
2019-11-25 17:39:11 +00:00
}
2020-02-27 13:31:28 +00:00
2021-12-07 20:05:28 +00:00
r := io . NewBinReaderFromBuf ( b )
if r . ReadB ( ) != storage . ExecBlock {
2022-04-04 16:07:32 +00:00
// It may be a transaction.
return nil , storage . ErrKeyNotFound
2021-12-07 20:05:28 +00:00
}
block , err := block . NewTrimmedFromReader ( dao . Version . StateRootInHeader , r )
2019-11-25 17:39:11 +00:00
if err != nil {
2020-06-04 19:59:34 +00:00
return nil , err
2019-11-25 17:39:11 +00:00
}
2020-06-04 19:59:34 +00:00
return block , nil
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// Version represents the current dao version.
2021-10-20 14:19:16 +00:00
type Version struct {
2021-11-03 09:55:33 +00:00
StoragePrefix storage . KeyPrefix
StateRootInHeader bool
P2PSigExtensions bool
P2PStateExchangeExtensions bool
KeepOnlyLatestState bool
2023-01-11 09:05:05 +00:00
Magic uint32
2021-11-03 09:55:33 +00:00
Value string
2021-10-20 14:19:16 +00:00
}
2021-10-22 07:58:53 +00:00
const (
stateRootInHeaderBit = 1 << iota
p2pSigExtensionsBit
2021-11-03 09:55:33 +00:00
p2pStateExchangeExtensionsBit
2021-10-22 08:09:47 +00:00
keepOnlyLatestStateBit
2021-10-22 07:58:53 +00:00
)
2021-10-20 14:19:16 +00:00
// FromBytes decodes v from a byte-slice.
func ( v * Version ) FromBytes ( data [ ] byte ) error {
if len ( data ) == 0 {
return errors . New ( "missing version" )
}
i := 0
2023-03-29 03:19:23 +00:00
for i < len ( data ) && data [ i ] != '\x00' {
i ++
2021-10-20 14:19:16 +00:00
}
if i == len ( data ) {
v . Value = string ( data )
return nil
}
2023-01-11 09:05:05 +00:00
if len ( data ) < i + 3 {
2021-10-22 07:58:53 +00:00
return errors . New ( "version is invalid" )
}
2021-10-20 14:19:16 +00:00
v . Value = string ( data [ : i ] )
2021-10-22 07:58:53 +00:00
v . StoragePrefix = storage . KeyPrefix ( data [ i + 1 ] )
v . StateRootInHeader = data [ i + 2 ] & stateRootInHeaderBit != 0
v . P2PSigExtensions = data [ i + 2 ] & p2pSigExtensionsBit != 0
2021-11-03 09:55:33 +00:00
v . P2PStateExchangeExtensions = data [ i + 2 ] & p2pStateExchangeExtensionsBit != 0
2021-10-22 08:09:47 +00:00
v . KeepOnlyLatestState = data [ i + 2 ] & keepOnlyLatestStateBit != 0
2023-01-11 09:05:05 +00:00
m := i + 3
if len ( data ) == m + 4 {
v . Magic = binary . LittleEndian . Uint32 ( data [ m : ] )
}
2021-10-20 14:19:16 +00:00
return nil
}
// Bytes encodes v to a byte-slice.
func ( v * Version ) Bytes ( ) [ ] byte {
2021-10-22 07:58:53 +00:00
var mask byte
if v . StateRootInHeader {
mask |= stateRootInHeaderBit
}
if v . P2PSigExtensions {
mask |= p2pSigExtensionsBit
}
2021-11-03 09:55:33 +00:00
if v . P2PStateExchangeExtensions {
mask |= p2pStateExchangeExtensionsBit
}
2021-10-22 08:09:47 +00:00
if v . KeepOnlyLatestState {
mask |= keepOnlyLatestStateBit
}
2023-10-11 12:41:04 +00:00
res := append ( [ ] byte ( v . Value ) , '\x00' , byte ( v . StoragePrefix ) , mask )
res = binary . LittleEndian . AppendUint32 ( res , v . Magic )
2023-01-11 09:05:05 +00:00
return res
2021-10-20 14:19:16 +00:00
}
2022-02-18 12:19:57 +00:00
func ( dao * Simple ) mkKeyPrefix ( k storage . KeyPrefix ) [ ] byte {
b := dao . getKeyBuf ( 1 )
b [ 0 ] = byte ( k )
return b
}
2019-11-25 17:39:11 +00:00
// GetVersion attempts to get the current version stored in the
2020-04-07 09:41:12 +00:00
// underlying store.
2021-10-20 14:19:16 +00:00
func ( dao * Simple ) GetVersion ( ) ( Version , error ) {
var version Version
2022-02-18 12:19:57 +00:00
data , err := dao . Store . Get ( dao . mkKeyPrefix ( storage . SYSVersion ) )
2021-10-20 14:19:16 +00:00
if err == nil {
err = version . FromBytes ( data )
}
return version , err
2019-11-25 17:39:11 +00:00
}
// GetCurrentBlockHeight returns the current block height found in the
2020-04-07 09:41:12 +00:00
// underlying store.
func ( dao * Simple ) GetCurrentBlockHeight ( ) ( uint32 , error ) {
2022-02-18 12:19:57 +00:00
b , err := dao . Store . Get ( dao . mkKeyPrefix ( storage . SYSCurrentBlock ) )
2019-11-25 17:39:11 +00:00
if err != nil {
return 0 , err
}
return binary . LittleEndian . Uint32 ( b [ 32 : 36 ] ) , nil
}
// GetCurrentHeaderHeight returns the current header height and hash from
2020-04-07 09:41:12 +00:00
// the underlying store.
func ( dao * Simple ) GetCurrentHeaderHeight ( ) ( i uint32 , h util . Uint256 , err error ) {
2019-11-25 17:39:11 +00:00
var b [ ] byte
2022-02-18 12:19:57 +00:00
b , err = dao . Store . Get ( dao . mkKeyPrefix ( storage . SYSCurrentHeader ) )
2019-11-25 17:39:11 +00:00
if err != nil {
return
}
i = binary . LittleEndian . Uint32 ( b [ 32 : 36 ] )
h , err = util . Uint256DecodeBytesLE ( b [ : 32 ] )
return
}
2022-04-20 18:30:09 +00:00
// GetStateSyncPoint returns current state synchronization point P.
2021-08-03 06:56:39 +00:00
func ( dao * Simple ) GetStateSyncPoint ( ) ( uint32 , error ) {
2022-02-18 12:19:57 +00:00
b , err := dao . Store . Get ( dao . mkKeyPrefix ( storage . SYSStateSyncPoint ) )
2021-08-03 06:56:39 +00:00
if err != nil {
return 0 , err
}
return binary . LittleEndian . Uint32 ( b ) , nil
}
2022-04-20 18:30:09 +00:00
// GetStateSyncCurrentBlockHeight returns the current block height stored during state
// synchronization process.
2021-08-03 06:56:39 +00:00
func ( dao * Simple ) GetStateSyncCurrentBlockHeight ( ) ( uint32 , error ) {
2022-02-18 12:19:57 +00:00
b , err := dao . Store . Get ( dao . mkKeyPrefix ( storage . SYSStateSyncCurrentBlockHeight ) )
2021-08-03 06:56:39 +00:00
if err != nil {
return 0 , err
}
return binary . LittleEndian . Uint32 ( b ) , nil
}
2022-11-18 20:06:39 +00:00
// GetHeaderHashes returns a page of header hashes retrieved from
2020-04-07 09:41:12 +00:00
// the given underlying store.
2022-11-18 20:06:39 +00:00
func ( dao * Simple ) GetHeaderHashes ( height uint32 ) ( [ ] util . Uint256 , error ) {
var hashes [ ] util . Uint256
2022-02-18 11:35:17 +00:00
2022-11-18 20:06:39 +00:00
key := dao . mkHeaderHashKey ( height )
b , err := dao . Store . Get ( key )
if err != nil {
return nil , err
}
2019-11-25 17:39:11 +00:00
2022-11-18 20:06:39 +00:00
br := io . NewBinReaderFromBuf ( b )
br . ReadArray ( & hashes )
if br . Err != nil {
return nil , br . Err
}
return hashes , nil
2019-11-25 17:39:11 +00:00
}
2022-10-20 10:59:19 +00:00
// DeleteHeaderHashes removes batches of header hashes starting from the one that
// contains header with index `since` up to the most recent batch. It assumes that
// all stored batches contain `batchSize` hashes.
func ( dao * Simple ) DeleteHeaderHashes ( since uint32 , batchSize int ) {
dao . Store . Seek ( storage . SeekRange {
Prefix : dao . mkKeyPrefix ( storage . IXHeaderHashList ) ,
Backwards : true ,
} , func ( k , _ [ ] byte ) bool {
first := binary . BigEndian . Uint32 ( k [ 1 : ] )
if first >= since {
dao . Store . Delete ( k )
return first != since
}
if first + uint32 ( batchSize ) - 1 >= since {
dao . Store . Delete ( k )
}
return false
} )
}
2019-11-25 17:39:11 +00:00
// GetTransaction returns Transaction and its height by the given hash
2020-10-15 11:45:29 +00:00
// if it exists in the store. It does not return dummy transactions.
2020-04-07 09:41:12 +00:00
func ( dao * Simple ) GetTransaction ( hash util . Uint256 ) ( * transaction . Transaction , uint32 , error ) {
2022-02-16 20:33:53 +00:00
key := dao . makeExecutableKey ( hash )
2020-04-07 09:41:12 +00:00
b , err := dao . Store . Get ( key )
2019-11-25 17:39:11 +00:00
if err != nil {
return nil , 0 , err
}
2023-09-19 14:35:51 +00:00
if len ( b ) < 1 {
2020-10-15 11:45:29 +00:00
return nil , 0 , errors . New ( "bad transaction bytes" )
}
2021-12-07 20:05:28 +00:00
if b [ 0 ] != storage . ExecTransaction {
2022-04-04 16:07:32 +00:00
// It may be a block.
return nil , 0 , storage . ErrKeyNotFound
2021-12-07 20:05:28 +00:00
}
2023-09-19 14:35:51 +00:00
if len ( b ) == 1 + 4 { // storage.ExecTransaction + index
// It's a conflict record stub.
2020-10-15 11:45:29 +00:00
return nil , 0 , storage . ErrKeyNotFound
}
2019-11-25 17:39:11 +00:00
r := io . NewBinReaderFromBuf ( b )
2021-12-07 20:05:28 +00:00
_ = r . ReadB ( )
2019-11-25 17:39:11 +00:00
2019-12-12 15:52:23 +00:00
var height = r . ReadU32LE ( )
2019-11-25 17:39:11 +00:00
2021-03-25 16:18:01 +00:00
tx := & transaction . Transaction { }
2019-11-25 17:39:11 +00:00
tx . DecodeBinary ( r )
if r . Err != nil {
return nil , 0 , r . Err
}
return tx , height , nil
}
2020-04-07 09:41:12 +00:00
// PutVersion stores the given version in the underlying store.
2022-02-16 14:48:15 +00:00
func ( dao * Simple ) PutVersion ( v Version ) {
2021-10-22 07:58:53 +00:00
dao . Version = v
2022-02-18 12:19:57 +00:00
dao . Store . Put ( dao . mkKeyPrefix ( storage . SYSVersion ) , v . Bytes ( ) )
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// PutCurrentHeader stores the current header.
2022-02-18 12:04:57 +00:00
func ( dao * Simple ) PutCurrentHeader ( h util . Uint256 , index uint32 ) {
buf := dao . getDataBuf ( )
buf . WriteBytes ( h . BytesLE ( ) )
buf . WriteU32LE ( index )
2022-02-18 12:19:57 +00:00
dao . Store . Put ( dao . mkKeyPrefix ( storage . SYSCurrentHeader ) , buf . Bytes ( ) )
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// PutStateSyncPoint stores the current state synchronization point P.
2022-02-16 14:48:15 +00:00
func ( dao * Simple ) PutStateSyncPoint ( p uint32 ) {
2022-02-18 12:19:57 +00:00
buf := dao . getDataBuf ( )
buf . WriteU32LE ( p )
dao . Store . Put ( dao . mkKeyPrefix ( storage . SYSStateSyncPoint ) , buf . Bytes ( ) )
2021-08-03 06:56:39 +00:00
}
2022-04-20 18:30:09 +00:00
// PutStateSyncCurrentBlockHeight stores the current block height during state synchronization process.
2022-02-16 14:48:15 +00:00
func ( dao * Simple ) PutStateSyncCurrentBlockHeight ( h uint32 ) {
2022-02-18 12:19:57 +00:00
buf := dao . getDataBuf ( )
buf . WriteU32LE ( h )
dao . Store . Put ( dao . mkKeyPrefix ( storage . SYSStateSyncCurrentBlockHeight ) , buf . Bytes ( ) )
2021-08-03 06:56:39 +00:00
}
2022-02-18 11:54:05 +00:00
func ( dao * Simple ) mkHeaderHashKey ( h uint32 ) [ ] byte {
b := dao . getKeyBuf ( 1 + 4 )
b [ 0 ] = byte ( storage . IXHeaderHashList )
binary . BigEndian . PutUint32 ( b [ 1 : ] , h )
return b
}
// StoreHeaderHashes pushes a batch of header hashes into the store.
func ( dao * Simple ) StoreHeaderHashes ( hashes [ ] util . Uint256 , height uint32 ) error {
key := dao . mkHeaderHashKey ( height )
buf := dao . getDataBuf ( )
buf . WriteArray ( hashes )
if buf . Err != nil {
return buf . Err
}
dao . Store . Put ( key , buf . Bytes ( ) )
return nil
}
2020-10-15 11:45:29 +00:00
// HasTransaction returns nil if the given store does not contain the given
2022-04-20 18:30:09 +00:00
// Transaction hash. It returns an error in case the transaction is in chain
2023-07-14 08:57:18 +00:00
// or in the list of conflicting transactions. If non-zero signers are specified,
// then additional check against the conflicting transaction signers intersection
// is held. Do not omit signers in case if it's important to check the validity
2023-09-19 14:35:51 +00:00
// of a supposedly conflicting on-chain transaction. The retrieved conflict isn't
// checked against the maxTraceableBlocks setting if signers are omitted.
// HasTransaction does not consider the case of block executable.
func ( dao * Simple ) HasTransaction ( hash util . Uint256 , signers [ ] transaction . Signer , currentIndex uint32 , maxTraceableBlocks uint32 ) error {
2022-02-16 20:33:53 +00:00
key := dao . makeExecutableKey ( hash )
2020-10-15 11:45:29 +00:00
bytes , err := dao . Store . Get ( key )
if err != nil {
return nil
2019-11-25 17:39:11 +00:00
}
2020-10-15 11:45:29 +00:00
2023-09-19 14:35:51 +00:00
if len ( bytes ) < 5 { // (storage.ExecTransaction + index) for conflict record
2020-10-15 11:45:29 +00:00
return nil
}
2023-09-19 14:35:51 +00:00
if len ( bytes ) != 5 {
return ErrAlreadyExists // fully-qualified transaction
2023-07-14 08:57:18 +00:00
}
if len ( signers ) == 0 {
2020-10-15 11:45:29 +00:00
return ErrHasConflicts
}
2023-07-14 08:57:18 +00:00
2023-09-19 14:35:51 +00:00
if ! isTraceableBlock ( bytes [ 1 : ] , currentIndex , maxTraceableBlocks ) {
// The most fresh conflict record is already outdated.
return nil
}
2023-07-14 08:57:18 +00:00
for _ , s := range signers {
2023-09-19 14:35:51 +00:00
v , err := dao . Store . Get ( append ( key , s . Account . BytesBE ( ) ... ) )
if err == nil {
if isTraceableBlock ( v [ 1 : ] , currentIndex , maxTraceableBlocks ) {
return ErrHasConflicts
2023-07-14 08:57:18 +00:00
}
}
}
return nil
2019-11-25 17:39:11 +00:00
}
2023-09-19 14:35:51 +00:00
func isTraceableBlock ( indexBytes [ ] byte , height , maxTraceableBlocks uint32 ) bool {
index := binary . LittleEndian . Uint32 ( indexBytes )
return index <= height && index + maxTraceableBlocks > height
}
2020-08-31 19:11:49 +00:00
// StoreAsBlock stores given block as DataBlock. It can reuse given buffer for
// the purpose of value serialization.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) StoreAsBlock ( block * block . Block , aer1 * state . AppExecResult , aer2 * state . AppExecResult ) error {
2019-11-25 17:39:11 +00:00
var (
2022-02-16 20:33:53 +00:00
key = dao . makeExecutableKey ( block . Hash ( ) )
buf = dao . getDataBuf ( )
2019-11-25 17:39:11 +00:00
)
2021-12-07 20:05:28 +00:00
buf . WriteB ( storage . ExecBlock )
2022-03-18 07:49:25 +00:00
block . EncodeTrimmed ( buf . BinWriter )
2021-12-07 20:05:28 +00:00
if aer1 != nil {
2022-05-31 17:10:20 +00:00
aer1 . EncodeBinaryWithContext ( buf . BinWriter , dao . GetItemCtx ( ) )
2021-12-07 20:05:28 +00:00
}
if aer2 != nil {
2022-05-31 17:10:20 +00:00
aer2 . EncodeBinaryWithContext ( buf . BinWriter , dao . GetItemCtx ( ) )
2021-12-07 20:05:28 +00:00
}
2019-11-25 17:39:11 +00:00
if buf . Err != nil {
return buf . Err
}
2022-02-16 14:48:15 +00:00
dao . Store . Put ( key , buf . Bytes ( ) )
return nil
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// DeleteBlock removes the block from dao. It's not atomic, so make sure you're
2022-02-16 13:13:12 +00:00
// using private MemCached instance here.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) DeleteBlock ( h util . Uint256 ) error {
key := dao . makeExecutableKey ( h )
2020-11-24 09:07:58 +00:00
2022-02-18 08:41:27 +00:00
b , err := dao . getBlock ( key )
2020-11-24 09:07:58 +00:00
if err != nil {
return err
}
2022-11-20 17:55:45 +00:00
err = dao . storeHeader ( key , & b . Header )
if err != nil {
return err
2020-11-24 09:07:58 +00:00
}
for _ , tx := range b . Transactions {
copy ( key [ 1 : ] , tx . Hash ( ) . BytesBE ( ) )
2022-02-16 14:48:15 +00:00
dao . Store . Delete ( key )
2023-04-07 08:26:58 +00:00
for _ , attr := range tx . GetAttributes ( transaction . ConflictsT ) {
hash := attr . Value . ( * transaction . Conflicts ) . Hash
copy ( key [ 1 : ] , hash . BytesBE ( ) )
2023-09-19 14:35:51 +00:00
v , err := dao . Store . Get ( key )
if err != nil {
return fmt . Errorf ( "failed to retrieve conflict record stub for %s (height %d, conflict %s): %w" , tx . Hash ( ) . StringLE ( ) , b . Index , hash . StringLE ( ) , err )
}
index := binary . LittleEndian . Uint32 ( v [ 1 : ] )
// We can check for `<=` here, but use equality comparison to be more precise
// and do not touch earlier conflict records (if any). Their removal must be triggered
// by the caller code.
if index == b . Index {
dao . Store . Delete ( key )
}
for _ , s := range tx . Signers {
sKey := append ( key , s . Account . BytesBE ( ) ... )
v , err := dao . Store . Get ( sKey )
if err != nil {
return fmt . Errorf ( "failed to retrieve conflict record for %s (height %d, conflict %s, signer %s): %w" , tx . Hash ( ) . StringLE ( ) , b . Index , hash . StringLE ( ) , address . Uint160ToString ( s . Account ) , err )
}
index = binary . LittleEndian . Uint32 ( v [ 1 : ] )
if index == b . Index {
dao . Store . Delete ( sKey )
}
}
2021-08-17 15:40:11 +00:00
}
2020-11-24 09:07:58 +00:00
}
2022-02-16 13:13:12 +00:00
return nil
2020-11-24 09:07:58 +00:00
}
2022-11-20 17:55:45 +00:00
// PurgeHeader completely removes specified header from dao. It differs from
// DeleteBlock in that it removes header anyway and does nothing except removing
// header. It does no checks for header existence.
func ( dao * Simple ) PurgeHeader ( h util . Uint256 ) {
key := dao . makeExecutableKey ( h )
dao . Store . Delete ( key )
}
2022-04-20 18:30:09 +00:00
// StoreHeader saves the block header into the store.
2022-02-18 08:55:06 +00:00
func ( dao * Simple ) StoreHeader ( h * block . Header ) error {
return dao . storeHeader ( dao . makeExecutableKey ( h . Hash ( ) ) , h )
}
func ( dao * Simple ) storeHeader ( key [ ] byte , h * block . Header ) error {
buf := dao . getDataBuf ( )
buf . WriteB ( storage . ExecBlock )
h . EncodeBinary ( buf . BinWriter )
buf . BinWriter . WriteB ( 0 )
if buf . Err != nil {
return buf . Err
}
dao . Store . Put ( key , buf . Bytes ( ) )
return nil
}
2022-04-20 18:30:09 +00:00
// StoreAsCurrentBlock stores the hash of the given block with prefix
// SYSCurrentBlock.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) StoreAsCurrentBlock ( block * block . Block ) {
buf := dao . getDataBuf ( )
2019-12-12 15:52:23 +00:00
h := block . Hash ( )
h . EncodeBinary ( buf . BinWriter )
buf . WriteU32LE ( block . Index )
2022-02-18 12:19:57 +00:00
dao . Store . Put ( dao . mkKeyPrefix ( storage . SYSCurrentBlock ) , buf . Bytes ( ) )
2019-11-25 17:39:11 +00:00
}
2022-04-20 18:30:09 +00:00
// StoreAsTransaction stores the given TX as DataTransaction. It also stores transactions
// the given tx has conflicts with as DataTransaction with dummy version. It can reuse the given
2020-08-31 19:11:49 +00:00
// buffer for the purpose of value serialization.
2022-02-16 20:33:53 +00:00
func ( dao * Simple ) StoreAsTransaction ( tx * transaction . Transaction , index uint32 , aer * state . AppExecResult ) error {
key := dao . makeExecutableKey ( tx . Hash ( ) )
buf := dao . getDataBuf ( )
2021-12-07 20:05:28 +00:00
buf . WriteB ( storage . ExecTransaction )
2019-12-12 15:52:23 +00:00
buf . WriteU32LE ( index )
2021-08-17 15:33:09 +00:00
tx . EncodeBinary ( buf . BinWriter )
2021-12-07 20:05:28 +00:00
if aer != nil {
2022-05-31 17:10:20 +00:00
aer . EncodeBinaryWithContext ( buf . BinWriter , dao . GetItemCtx ( ) )
2021-12-07 20:05:28 +00:00
}
2019-11-25 17:39:11 +00:00
if buf . Err != nil {
return buf . Err
}
2023-09-19 14:35:51 +00:00
val := buf . Bytes ( )
dao . Store . Put ( key , val )
2023-07-14 08:57:18 +00:00
2023-09-19 14:35:51 +00:00
val = val [ : 5 ] // storage.ExecTransaction (1 byte) + index (4 bytes)
2023-04-07 08:26:58 +00:00
attrs := tx . GetAttributes ( transaction . ConflictsT )
for _ , attr := range attrs {
2023-09-19 14:35:51 +00:00
// Conflict record stub.
2023-04-07 08:26:58 +00:00
hash := attr . Value . ( * transaction . Conflicts ) . Hash
copy ( key [ 1 : ] , hash . BytesBE ( ) )
dao . Store . Put ( key , val )
2023-09-19 14:35:51 +00:00
// Conflicting signers.
sKey := make ( [ ] byte , len ( key ) + util . Uint160Size )
copy ( sKey , key )
for _ , s := range tx . Signers {
copy ( sKey [ len ( key ) : ] , s . Account . BytesBE ( ) )
dao . Store . Put ( sKey , val )
2021-08-02 11:20:33 +00:00
}
}
return nil
}
2022-09-02 15:22:35 +00:00
func ( dao * Simple ) getKeyBuf ( l int ) [ ] byte {
2022-02-18 11:24:45 +00:00
if dao . private {
if dao . keyBuf == nil {
2022-07-08 16:51:59 +00:00
dao . keyBuf = make ( [ ] byte , 0 , 1 + 4 + limits . MaxStorageKeyLen ) // Prefix, uint32, key.
2022-02-18 11:24:45 +00:00
}
2022-09-02 15:22:35 +00:00
return dao . keyBuf [ : l ] // Should have enough capacity.
2022-02-16 20:33:53 +00:00
}
2022-09-02 15:22:35 +00:00
return make ( [ ] byte , l )
2022-02-16 20:33:53 +00:00
}
func ( dao * Simple ) getDataBuf ( ) * io . BufBinWriter {
2022-02-18 11:24:45 +00:00
if dao . private {
if dao . dataBuf == nil {
dao . dataBuf = io . NewBufBinWriter ( )
}
2022-02-16 20:33:53 +00:00
dao . dataBuf . Reset ( )
return dao . dataBuf
}
return io . NewBufBinWriter ( )
}
2022-05-31 17:10:20 +00:00
func ( dao * Simple ) GetItemCtx ( ) * stackitem . SerializationContext {
if dao . private {
if dao . serCtx == nil {
dao . serCtx = stackitem . NewSerializationContext ( )
}
return dao . serCtx
}
return stackitem . NewSerializationContext ( )
}
2019-12-12 18:17:13 +00:00
// Persist flushes all the changes made into the (supposedly) persistent
2021-11-22 07:41:40 +00:00
// underlying store. It doesn't block accesses to DAO from other threads.
2020-04-07 09:41:12 +00:00
func ( dao * Simple ) Persist ( ) ( int , error ) {
2022-04-20 14:47:48 +00:00
if dao . nativeCachePS != nil {
2022-05-06 07:27:48 +00:00
dao . nativeCacheLock . Lock ( )
dao . nativeCachePS . nativeCacheLock . Lock ( )
defer func ( ) {
dao . nativeCachePS . nativeCacheLock . Unlock ( )
dao . nativeCacheLock . Unlock ( )
} ( )
2022-04-20 14:47:48 +00:00
dao . persistNativeCache ( )
}
2020-04-07 09:41:12 +00:00
return dao . Store . Persist ( )
2019-12-12 18:17:13 +00:00
}
2020-12-24 16:32:27 +00:00
2021-11-22 07:41:40 +00:00
// PersistSync flushes all the changes made into the (supposedly) persistent
// underlying store. It's a synchronous version of Persist that doesn't allow
// other threads to work with DAO while flushing the Store.
func ( dao * Simple ) PersistSync ( ) ( int , error ) {
2022-04-20 14:47:48 +00:00
if dao . nativeCachePS != nil {
dao . nativeCacheLock . Lock ( )
dao . nativeCachePS . nativeCacheLock . Lock ( )
defer func ( ) {
dao . nativeCachePS . nativeCacheLock . Unlock ( )
dao . nativeCacheLock . Unlock ( )
} ( )
dao . persistNativeCache ( )
}
2021-11-22 07:41:40 +00:00
return dao . Store . PersistSync ( )
}
2022-04-20 14:47:48 +00:00
// persistNativeCache is internal unprotected method for native cache persisting.
// It does NO checks for nativeCachePS is not nil.
func ( dao * Simple ) persistNativeCache ( ) {
lower := dao . nativeCachePS
for id , nativeCache := range dao . nativeCache {
lower . nativeCache [ id ] = nativeCache
}
dao . nativeCache = nil
}
// GetROCache returns native contact cache. The cache CAN NOT be modified by
// the caller. It's the caller's duty to keep it unmodified.
func ( dao * Simple ) GetROCache ( id int32 ) NativeContractCache {
2022-05-06 07:27:48 +00:00
dao . nativeCacheLock . RLock ( )
defer dao . nativeCacheLock . RUnlock ( )
2022-04-20 14:47:48 +00:00
return dao . getCache ( id , true )
}
// GetRWCache returns native contact cache. The cache CAN BE safely modified
// by the caller.
func ( dao * Simple ) GetRWCache ( id int32 ) NativeContractCache {
2022-05-06 07:27:48 +00:00
dao . nativeCacheLock . Lock ( )
defer dao . nativeCacheLock . Unlock ( )
2022-04-20 14:47:48 +00:00
return dao . getCache ( id , false )
}
// getCache is an internal unlocked representation of GetROCache and GetRWCache.
func ( dao * Simple ) getCache ( k int32 , ro bool ) NativeContractCache {
if itm , ok := dao . nativeCache [ k ] ; ok {
// Don't need to create itm copy, because its value was already copied
2023-11-02 14:15:34 +00:00
// the first time it was retrieved from lower ps.
2022-04-20 14:47:48 +00:00
return itm
}
if dao . nativeCachePS != nil {
if ro {
return dao . nativeCachePS . GetROCache ( k )
}
v := dao . nativeCachePS . GetRWCache ( k )
if v != nil {
// Create a copy here in order not to modify the existing cache.
cp := v . Copy ( )
dao . nativeCache [ k ] = cp
return cp
}
}
return nil
}
// SetCache adds native contract cache to the cache map.
func ( dao * Simple ) SetCache ( id int32 , v NativeContractCache ) {
dao . nativeCacheLock . Lock ( )
defer dao . nativeCacheLock . Unlock ( )
dao . nativeCache [ id ] = v
}