github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/dao/dao.go (about)

     1  package dao
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	iocore "io"
    10  	"math/big"
    11  	"sync"
    12  
    13  	"github.com/nspcc-dev/neo-go/pkg/config/limits"
    14  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    15  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    17  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    18  	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
    19  	"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
    20  	"github.com/nspcc-dev/neo-go/pkg/io"
    21  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    22  	"github.com/nspcc-dev/neo-go/pkg/util"
    23  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    24  )
    25  
    26  // HasTransaction errors.
    27  var (
    28  	// ErrAlreadyExists is returned when the transaction exists in dao.
    29  	ErrAlreadyExists = errors.New("transaction already exists")
    30  	// ErrHasConflicts is returned when the transaction is in the list of conflicting
    31  	// transactions which are already in dao.
    32  	ErrHasConflicts = errors.New("transaction has conflicts")
    33  	// ErrInternalDBInconsistency is returned when the format of the retrieved DAO
    34  	// record is unexpected.
    35  	ErrInternalDBInconsistency = errors.New("internal DB inconsistency")
    36  )
    37  
    38  // conflictRecordValueLen is the length of value of transaction conflict record.
    39  // It consists of 1-byte [storage.ExecTransaction] prefix and 4-bytes block index
    40  // in the LE form.
    41  const conflictRecordValueLen = 1 + 4
    42  
    43  // Simple is memCached wrapper around DB, simple DAO implementation.
    44  type Simple struct {
    45  	Version Version
    46  	Store   *storage.MemCachedStore
    47  
    48  	nativeCacheLock sync.RWMutex
    49  	nativeCache     map[int32]NativeContractCache
    50  	// nativeCachePS is the backend store that provides functionality to store
    51  	// and retrieve multi-tier native contract cache. The lowest Simple has its
    52  	// nativeCachePS set to nil.
    53  	nativeCachePS *Simple
    54  
    55  	private bool
    56  	serCtx  *stackitem.SerializationContext
    57  	keyBuf  []byte
    58  	dataBuf *io.BufBinWriter
    59  }
    60  
    61  // NativeContractCache is an interface representing cache for a native contract.
    62  // Cache can be copied to create a wrapper around current DAO layer. Wrapped cache
    63  // can be persisted to the underlying DAO native cache.
    64  type NativeContractCache interface {
    65  	// Copy returns a copy of native cache item that can safely be changed within
    66  	// the subsequent DAO operations.
    67  	Copy() NativeContractCache
    68  }
    69  
    70  // NewSimple creates a new simple dao using the provided backend store.
    71  func NewSimple(backend storage.Store, stateRootInHeader bool) *Simple {
    72  	st := storage.NewMemCachedStore(backend)
    73  	return newSimple(st, stateRootInHeader)
    74  }
    75  
    76  func newSimple(st *storage.MemCachedStore, stateRootInHeader bool) *Simple {
    77  	return &Simple{
    78  		Version: Version{
    79  			StoragePrefix:     storage.STStorage,
    80  			StateRootInHeader: stateRootInHeader,
    81  		},
    82  		Store:       st,
    83  		nativeCache: make(map[int32]NativeContractCache),
    84  	}
    85  }
    86  
    87  // GetBatch returns the currently accumulated DB changeset.
    88  func (dao *Simple) GetBatch() *storage.MemBatch {
    89  	return dao.Store.GetBatch()
    90  }
    91  
    92  // GetWrapped returns a new DAO instance with another layer of wrapped
    93  // MemCachedStore around the current DAO Store.
    94  func (dao *Simple) GetWrapped() *Simple {
    95  	d := NewSimple(dao.Store, dao.Version.StateRootInHeader)
    96  	d.Version = dao.Version
    97  	d.nativeCachePS = dao
    98  	return d
    99  }
   100  
   101  // GetPrivate returns a new DAO instance with another layer of private
   102  // MemCachedStore around the current DAO Store.
   103  func (dao *Simple) GetPrivate() *Simple {
   104  	d := &Simple{
   105  		Version: dao.Version,
   106  		keyBuf:  dao.keyBuf,
   107  		dataBuf: dao.dataBuf,
   108  		serCtx:  dao.serCtx,
   109  	} // Inherit everything...
   110  	d.Store = storage.NewPrivateMemCachedStore(dao.Store) // except storage, wrap another layer.
   111  	d.private = true
   112  	d.nativeCachePS = dao
   113  	// Do not inherit cache from nativeCachePS; instead should create clear map:
   114  	// GetRWCache and GetROCache will retrieve cache from the underlying
   115  	// nativeCache if requested. The lowest underlying DAO MUST have its native
   116  	// cache initialized before access it, otherwise GetROCache and GetRWCache
   117  	// won't work properly.
   118  	d.nativeCache = make(map[int32]NativeContractCache)
   119  	return d
   120  }
   121  
   122  // GetAndDecode performs get operation and decoding with serializable structures.
   123  func (dao *Simple) GetAndDecode(entity io.Serializable, key []byte) error {
   124  	entityBytes, err := dao.Store.Get(key)
   125  	if err != nil {
   126  		return err
   127  	}
   128  	reader := io.NewBinReaderFromBuf(entityBytes)
   129  	entity.DecodeBinary(reader)
   130  	return reader.Err
   131  }
   132  
   133  // putWithBuffer performs put operation using buf as a pre-allocated buffer for serialization.
   134  func (dao *Simple) putWithBuffer(entity io.Serializable, key []byte, buf *io.BufBinWriter) error {
   135  	entity.EncodeBinary(buf.BinWriter)
   136  	if buf.Err != nil {
   137  		return buf.Err
   138  	}
   139  	dao.Store.Put(key, buf.Bytes())
   140  	return nil
   141  }
   142  
   143  // -- start NEP-17 transfer info.
   144  
   145  func (dao *Simple) makeTTIKey(acc util.Uint160) []byte {
   146  	key := dao.getKeyBuf(1 + util.Uint160Size)
   147  	key[0] = byte(storage.STTokenTransferInfo)
   148  	copy(key[1:], acc.BytesBE())
   149  	return key
   150  }
   151  
   152  // GetTokenTransferInfo retrieves NEP-17 transfer info from the cache.
   153  func (dao *Simple) GetTokenTransferInfo(acc util.Uint160) (*state.TokenTransferInfo, error) {
   154  	key := dao.makeTTIKey(acc)
   155  	bs := state.NewTokenTransferInfo()
   156  	err := dao.GetAndDecode(bs, key)
   157  	if err != nil && !errors.Is(err, storage.ErrKeyNotFound) {
   158  		return nil, err
   159  	}
   160  	return bs, nil
   161  }
   162  
   163  // PutTokenTransferInfo saves NEP-17 transfer info in the cache.
   164  func (dao *Simple) PutTokenTransferInfo(acc util.Uint160, bs *state.TokenTransferInfo) error {
   165  	return dao.putTokenTransferInfo(acc, bs, dao.getDataBuf())
   166  }
   167  
   168  func (dao *Simple) putTokenTransferInfo(acc util.Uint160, bs *state.TokenTransferInfo, buf *io.BufBinWriter) error {
   169  	return dao.putWithBuffer(bs, dao.makeTTIKey(acc), buf)
   170  }
   171  
   172  // -- end NEP-17 transfer info.
   173  
   174  // -- start transfer log.
   175  
   176  func (dao *Simple) getTokenTransferLogKey(acc util.Uint160, newestTimestamp uint64, index uint32, isNEP11 bool) []byte {
   177  	key := dao.getKeyBuf(1 + util.Uint160Size + 8 + 4)
   178  	if isNEP11 {
   179  		key[0] = byte(storage.STNEP11Transfers)
   180  	} else {
   181  		key[0] = byte(storage.STNEP17Transfers)
   182  	}
   183  	copy(key[1:], acc.BytesBE())
   184  	binary.BigEndian.PutUint64(key[1+util.Uint160Size:], newestTimestamp)
   185  	binary.BigEndian.PutUint32(key[1+util.Uint160Size+8:], index)
   186  	return key
   187  }
   188  
   189  // SeekNEP17TransferLog executes f for each NEP-17 transfer in log starting from
   190  // the transfer with the newest timestamp up to the oldest transfer. It continues
   191  // iteration until false is returned from f. The last non-nil error is returned.
   192  func (dao *Simple) SeekNEP17TransferLog(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP17Transfer) (bool, error)) error {
   193  	key := dao.getTokenTransferLogKey(acc, newestTimestamp, 0, false)
   194  	prefixLen := 1 + util.Uint160Size
   195  	var seekErr error
   196  	dao.Store.Seek(storage.SeekRange{
   197  		Prefix:    key[:prefixLen],
   198  		Start:     key[prefixLen : prefixLen+8],
   199  		Backwards: true,
   200  	}, func(k, v []byte) bool {
   201  		lg := &state.TokenTransferLog{Raw: v}
   202  		cont, err := lg.ForEachNEP17(f)
   203  		if err != nil {
   204  			seekErr = err
   205  		}
   206  		return cont
   207  	})
   208  	return seekErr
   209  }
   210  
   211  // SeekNEP11TransferLog executes f for each NEP-11 transfer in log starting from
   212  // the transfer with the newest timestamp up to the oldest transfer. It continues
   213  // iteration until false is returned from f. The last non-nil error is returned.
   214  func (dao *Simple) SeekNEP11TransferLog(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP11Transfer) (bool, error)) error {
   215  	key := dao.getTokenTransferLogKey(acc, newestTimestamp, 0, true)
   216  	prefixLen := 1 + util.Uint160Size
   217  	var seekErr error
   218  	dao.Store.Seek(storage.SeekRange{
   219  		Prefix:    key[:prefixLen],
   220  		Start:     key[prefixLen : prefixLen+8],
   221  		Backwards: true,
   222  	}, func(k, v []byte) bool {
   223  		lg := &state.TokenTransferLog{Raw: v}
   224  		cont, err := lg.ForEachNEP11(f)
   225  		if err != nil {
   226  			seekErr = err
   227  		}
   228  		return cont
   229  	})
   230  	return seekErr
   231  }
   232  
   233  // GetTokenTransferLog retrieves transfer log from the cache.
   234  func (dao *Simple) GetTokenTransferLog(acc util.Uint160, newestTimestamp uint64, index uint32, isNEP11 bool) (*state.TokenTransferLog, error) {
   235  	key := dao.getTokenTransferLogKey(acc, newestTimestamp, index, isNEP11)
   236  	value, err := dao.Store.Get(key)
   237  	if err != nil {
   238  		if errors.Is(err, storage.ErrKeyNotFound) {
   239  			return new(state.TokenTransferLog), nil
   240  		}
   241  		return nil, err
   242  	}
   243  	return &state.TokenTransferLog{Raw: value}, nil
   244  }
   245  
   246  // PutTokenTransferLog saves the given transfer log in the cache.
   247  func (dao *Simple) PutTokenTransferLog(acc util.Uint160, start uint64, index uint32, isNEP11 bool, lg *state.TokenTransferLog) {
   248  	key := dao.getTokenTransferLogKey(acc, start, index, isNEP11)
   249  	dao.Store.Put(key, lg.Raw)
   250  }
   251  
   252  // -- end transfer log.
   253  
   254  // -- start notification event.
   255  
   256  func (dao *Simple) makeExecutableKey(hash util.Uint256) []byte {
   257  	key := dao.getKeyBuf(1 + util.Uint256Size)
   258  	key[0] = byte(storage.DataExecutable)
   259  	copy(key[1:], hash.BytesBE())
   260  	return key
   261  }
   262  
   263  // GetAppExecResults gets application execution results with the specified trigger from the
   264  // given store.
   265  func (dao *Simple) GetAppExecResults(hash util.Uint256, trig trigger.Type) ([]state.AppExecResult, error) {
   266  	key := dao.makeExecutableKey(hash)
   267  	bs, err := dao.Store.Get(key)
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  	if len(bs) == 0 {
   272  		return nil, fmt.Errorf("%w: empty execution log", ErrInternalDBInconsistency)
   273  	}
   274  	switch bs[0] {
   275  	case storage.ExecBlock:
   276  		r := io.NewBinReaderFromBuf(bs)
   277  		_ = r.ReadB()
   278  		_, err = block.NewTrimmedFromReader(dao.Version.StateRootInHeader, r)
   279  		if err != nil {
   280  			return nil, err
   281  		}
   282  		result := make([]state.AppExecResult, 0, 2)
   283  		for {
   284  			aer := new(state.AppExecResult)
   285  			aer.DecodeBinary(r)
   286  			if r.Err != nil {
   287  				if errors.Is(r.Err, iocore.EOF) {
   288  					break
   289  				}
   290  				return nil, r.Err
   291  			}
   292  			if aer.Trigger&trig != 0 {
   293  				result = append(result, *aer)
   294  			}
   295  		}
   296  		return result, nil
   297  	case storage.ExecTransaction:
   298  		_, _, aer, err := decodeTxAndExecResult(bs)
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  		if aer.Trigger&trig != 0 {
   303  			return []state.AppExecResult{*aer}, nil
   304  		}
   305  		return nil, nil
   306  	default:
   307  		return nil, fmt.Errorf("%w: unexpected executable prefix %d", ErrInternalDBInconsistency, bs[0])
   308  	}
   309  }
   310  
   311  // GetTxExecResult gets application execution result of the specified transaction
   312  // and returns the transaction itself, its height and its AppExecResult.
   313  func (dao *Simple) GetTxExecResult(hash util.Uint256) (uint32, *transaction.Transaction, *state.AppExecResult, error) {
   314  	key := dao.makeExecutableKey(hash)
   315  	bs, err := dao.Store.Get(key)
   316  	if err != nil {
   317  		return 0, nil, nil, err
   318  	}
   319  	if len(bs) == 0 {
   320  		return 0, nil, nil, fmt.Errorf("%w: empty execution log", ErrInternalDBInconsistency)
   321  	}
   322  	if bs[0] != storage.ExecTransaction {
   323  		return 0, nil, nil, storage.ErrKeyNotFound
   324  	}
   325  	return decodeTxAndExecResult(bs)
   326  }
   327  
   328  // decodeTxAndExecResult decodes transaction, its height and execution result from
   329  // the given executable bytes. It performs no executable prefix check.
   330  func decodeTxAndExecResult(buf []byte) (uint32, *transaction.Transaction, *state.AppExecResult, error) {
   331  	if len(buf) == conflictRecordValueLen { // conflict record stub.
   332  		return 0, nil, nil, storage.ErrKeyNotFound
   333  	}
   334  	r := io.NewBinReaderFromBuf(buf)
   335  	_ = r.ReadB()
   336  	h := r.ReadU32LE()
   337  	tx := &transaction.Transaction{}
   338  	tx.DecodeBinary(r)
   339  	if r.Err != nil {
   340  		return 0, nil, nil, r.Err
   341  	}
   342  	aer := new(state.AppExecResult)
   343  	aer.DecodeBinary(r)
   344  	if r.Err != nil {
   345  		return 0, nil, nil, r.Err
   346  	}
   347  
   348  	return h, tx, aer, nil
   349  }
   350  
   351  // -- end notification event.
   352  
   353  // -- start storage item.
   354  
   355  // GetStorageItem returns StorageItem if it exists in the given store.
   356  func (dao *Simple) GetStorageItem(id int32, key []byte) state.StorageItem {
   357  	b, err := dao.Store.Get(dao.makeStorageItemKey(id, key))
   358  	if err != nil {
   359  		return nil
   360  	}
   361  	return b
   362  }
   363  
   364  // PutStorageItem puts the given StorageItem for the given id with the given
   365  // key into the given store.
   366  func (dao *Simple) PutStorageItem(id int32, key []byte, si state.StorageItem) {
   367  	stKey := dao.makeStorageItemKey(id, key)
   368  	dao.Store.Put(stKey, si)
   369  }
   370  
   371  // PutBigInt serializaed and puts the given integer for the given id with the given
   372  // key into the given store.
   373  func (dao *Simple) PutBigInt(id int32, key []byte, n *big.Int) {
   374  	var buf [bigint.MaxBytesLen]byte
   375  	stData := bigint.ToPreallocatedBytes(n, buf[:])
   376  	dao.PutStorageItem(id, key, stData)
   377  }
   378  
   379  // DeleteStorageItem drops a storage item for the given id with the
   380  // given key from the store.
   381  func (dao *Simple) DeleteStorageItem(id int32, key []byte) {
   382  	stKey := dao.makeStorageItemKey(id, key)
   383  	dao.Store.Delete(stKey)
   384  }
   385  
   386  // Seek executes f for all storage items matching the given `rng` (matching the given prefix and
   387  // starting from the point specified). If the key or the value is to be used outside of f, they
   388  // may not be copied. Seek continues iterating until false is returned from f. A requested prefix
   389  // (if any non-empty) is trimmed before passing to f.
   390  func (dao *Simple) Seek(id int32, rng storage.SeekRange, f func(k, v []byte) bool) {
   391  	rng.Prefix = bytes.Clone(dao.makeStorageItemKey(id, rng.Prefix)) // f() can use dao too.
   392  	dao.Store.Seek(rng, func(k, v []byte) bool {
   393  		return f(k[len(rng.Prefix):], v)
   394  	})
   395  }
   396  
   397  // SeekAsync sends all storage items matching the given `rng` (matching the given prefix and
   398  // starting from the point specified) to a channel and returns the channel.
   399  // Resulting keys and values may not be copied.
   400  func (dao *Simple) SeekAsync(ctx context.Context, id int32, rng storage.SeekRange) chan storage.KeyValue {
   401  	rng.Prefix = bytes.Clone(dao.makeStorageItemKey(id, rng.Prefix))
   402  	return dao.Store.SeekAsync(ctx, rng, true)
   403  }
   404  
   405  // makeStorageItemKey returns the key used to store the StorageItem in the DB.
   406  func (dao *Simple) makeStorageItemKey(id int32, key []byte) []byte {
   407  	// 1 for prefix + 4 for Uint32 + len(key) for key
   408  	buf := dao.getKeyBuf(5 + len(key))
   409  	buf[0] = byte(dao.Version.StoragePrefix)
   410  	binary.LittleEndian.PutUint32(buf[1:], uint32(id))
   411  	copy(buf[5:], key)
   412  	return buf
   413  }
   414  
   415  // -- end storage item.
   416  
   417  // -- other.
   418  
   419  // GetBlock returns Block by the given hash if it exists in the store.
   420  func (dao *Simple) GetBlock(hash util.Uint256) (*block.Block, error) {
   421  	return dao.getBlock(dao.makeExecutableKey(hash))
   422  }
   423  
   424  func (dao *Simple) getBlock(key []byte) (*block.Block, error) {
   425  	b, err := dao.Store.Get(key)
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  
   430  	r := io.NewBinReaderFromBuf(b)
   431  	if r.ReadB() != storage.ExecBlock {
   432  		// It may be a transaction.
   433  		return nil, storage.ErrKeyNotFound
   434  	}
   435  	block, err := block.NewTrimmedFromReader(dao.Version.StateRootInHeader, r)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  	return block, nil
   440  }
   441  
   442  // Version represents the current dao version.
   443  type Version struct {
   444  	StoragePrefix              storage.KeyPrefix
   445  	StateRootInHeader          bool
   446  	P2PSigExtensions           bool
   447  	P2PStateExchangeExtensions bool
   448  	KeepOnlyLatestState        bool
   449  	Magic                      uint32
   450  	Value                      string
   451  }
   452  
   453  const (
   454  	stateRootInHeaderBit = 1 << iota
   455  	p2pSigExtensionsBit
   456  	p2pStateExchangeExtensionsBit
   457  	keepOnlyLatestStateBit
   458  )
   459  
   460  // FromBytes decodes v from a byte-slice.
   461  func (v *Version) FromBytes(data []byte) error {
   462  	if len(data) == 0 {
   463  		return errors.New("missing version")
   464  	}
   465  	i := 0
   466  	for i < len(data) && data[i] != '\x00' {
   467  		i++
   468  	}
   469  
   470  	if i == len(data) {
   471  		v.Value = string(data)
   472  		return nil
   473  	}
   474  
   475  	if len(data) < i+3 {
   476  		return errors.New("version is invalid")
   477  	}
   478  
   479  	v.Value = string(data[:i])
   480  	v.StoragePrefix = storage.KeyPrefix(data[i+1])
   481  	v.StateRootInHeader = data[i+2]&stateRootInHeaderBit != 0
   482  	v.P2PSigExtensions = data[i+2]&p2pSigExtensionsBit != 0
   483  	v.P2PStateExchangeExtensions = data[i+2]&p2pStateExchangeExtensionsBit != 0
   484  	v.KeepOnlyLatestState = data[i+2]&keepOnlyLatestStateBit != 0
   485  
   486  	m := i + 3
   487  	if len(data) == m+4 {
   488  		v.Magic = binary.LittleEndian.Uint32(data[m:])
   489  	}
   490  	return nil
   491  }
   492  
   493  // Bytes encodes v to a byte-slice.
   494  func (v *Version) Bytes() []byte {
   495  	var mask byte
   496  	if v.StateRootInHeader {
   497  		mask |= stateRootInHeaderBit
   498  	}
   499  	if v.P2PSigExtensions {
   500  		mask |= p2pSigExtensionsBit
   501  	}
   502  	if v.P2PStateExchangeExtensions {
   503  		mask |= p2pStateExchangeExtensionsBit
   504  	}
   505  	if v.KeepOnlyLatestState {
   506  		mask |= keepOnlyLatestStateBit
   507  	}
   508  	res := append([]byte(v.Value), '\x00', byte(v.StoragePrefix), mask)
   509  	res = binary.LittleEndian.AppendUint32(res, v.Magic)
   510  	return res
   511  }
   512  
   513  func (dao *Simple) mkKeyPrefix(k storage.KeyPrefix) []byte {
   514  	b := dao.getKeyBuf(1)
   515  	b[0] = byte(k)
   516  	return b
   517  }
   518  
   519  // GetVersion attempts to get the current version stored in the
   520  // underlying store.
   521  func (dao *Simple) GetVersion() (Version, error) {
   522  	var version Version
   523  
   524  	data, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSVersion))
   525  	if err == nil {
   526  		err = version.FromBytes(data)
   527  	}
   528  	return version, err
   529  }
   530  
   531  // GetCurrentBlockHeight returns the current block height found in the
   532  // underlying store.
   533  func (dao *Simple) GetCurrentBlockHeight() (uint32, error) {
   534  	b, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSCurrentBlock))
   535  	if err != nil {
   536  		return 0, err
   537  	}
   538  	return binary.LittleEndian.Uint32(b[32:36]), nil
   539  }
   540  
   541  // GetCurrentHeaderHeight returns the current header height and hash from
   542  // the underlying store.
   543  func (dao *Simple) GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error) {
   544  	var b []byte
   545  	b, err = dao.Store.Get(dao.mkKeyPrefix(storage.SYSCurrentHeader))
   546  	if err != nil {
   547  		return
   548  	}
   549  	i = binary.LittleEndian.Uint32(b[32:36])
   550  	h, err = util.Uint256DecodeBytesLE(b[:32])
   551  	return
   552  }
   553  
   554  // GetStateSyncPoint returns current state synchronization point P.
   555  func (dao *Simple) GetStateSyncPoint() (uint32, error) {
   556  	b, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSStateSyncPoint))
   557  	if err != nil {
   558  		return 0, err
   559  	}
   560  	return binary.LittleEndian.Uint32(b), nil
   561  }
   562  
   563  // GetStateSyncCurrentBlockHeight returns the current block height stored during state
   564  // synchronization process.
   565  func (dao *Simple) GetStateSyncCurrentBlockHeight() (uint32, error) {
   566  	b, err := dao.Store.Get(dao.mkKeyPrefix(storage.SYSStateSyncCurrentBlockHeight))
   567  	if err != nil {
   568  		return 0, err
   569  	}
   570  	return binary.LittleEndian.Uint32(b), nil
   571  }
   572  
   573  // GetHeaderHashes returns a page of header hashes retrieved from
   574  // the given underlying store.
   575  func (dao *Simple) GetHeaderHashes(height uint32) ([]util.Uint256, error) {
   576  	var hashes []util.Uint256
   577  
   578  	key := dao.mkHeaderHashKey(height)
   579  	b, err := dao.Store.Get(key)
   580  	if err != nil {
   581  		return nil, err
   582  	}
   583  
   584  	br := io.NewBinReaderFromBuf(b)
   585  	br.ReadArray(&hashes)
   586  	if br.Err != nil {
   587  		return nil, br.Err
   588  	}
   589  	return hashes, nil
   590  }
   591  
   592  // DeleteHeaderHashes removes batches of header hashes starting from the one that
   593  // contains header with index `since` up to the most recent batch. It assumes that
   594  // all stored batches contain `batchSize` hashes.
   595  func (dao *Simple) DeleteHeaderHashes(since uint32, batchSize int) {
   596  	dao.Store.Seek(storage.SeekRange{
   597  		Prefix:    dao.mkKeyPrefix(storage.IXHeaderHashList),
   598  		Backwards: true,
   599  	}, func(k, _ []byte) bool {
   600  		first := binary.BigEndian.Uint32(k[1:])
   601  		if first >= since {
   602  			dao.Store.Delete(k)
   603  			return first != since
   604  		}
   605  		if first+uint32(batchSize)-1 >= since {
   606  			dao.Store.Delete(k)
   607  		}
   608  		return false
   609  	})
   610  }
   611  
   612  // GetTransaction returns Transaction and its height by the given hash
   613  // if it exists in the store. It does not return conflict record stubs.
   614  func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) {
   615  	key := dao.makeExecutableKey(hash)
   616  	b, err := dao.Store.Get(key)
   617  	if err != nil {
   618  		return nil, 0, err
   619  	}
   620  	if len(b) < 1 {
   621  		return nil, 0, errors.New("bad transaction bytes")
   622  	}
   623  	if b[0] != storage.ExecTransaction {
   624  		// It may be a block.
   625  		return nil, 0, storage.ErrKeyNotFound
   626  	}
   627  	if len(b) == conflictRecordValueLen {
   628  		// It's a conflict record stub.
   629  		return nil, 0, storage.ErrKeyNotFound
   630  	}
   631  	r := io.NewBinReaderFromBuf(b)
   632  	_ = r.ReadB()
   633  
   634  	var height = r.ReadU32LE()
   635  
   636  	tx := &transaction.Transaction{}
   637  	tx.DecodeBinary(r)
   638  	if r.Err != nil {
   639  		return nil, 0, r.Err
   640  	}
   641  
   642  	return tx, height, nil
   643  }
   644  
   645  // PutVersion stores the given version in the underlying store.
   646  func (dao *Simple) PutVersion(v Version) {
   647  	dao.Version = v
   648  	dao.Store.Put(dao.mkKeyPrefix(storage.SYSVersion), v.Bytes())
   649  }
   650  
   651  // PutCurrentHeader stores the current header.
   652  func (dao *Simple) PutCurrentHeader(h util.Uint256, index uint32) {
   653  	buf := dao.getDataBuf()
   654  	buf.WriteBytes(h.BytesLE())
   655  	buf.WriteU32LE(index)
   656  	dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentHeader), buf.Bytes())
   657  }
   658  
   659  // PutStateSyncPoint stores the current state synchronization point P.
   660  func (dao *Simple) PutStateSyncPoint(p uint32) {
   661  	buf := dao.getDataBuf()
   662  	buf.WriteU32LE(p)
   663  	dao.Store.Put(dao.mkKeyPrefix(storage.SYSStateSyncPoint), buf.Bytes())
   664  }
   665  
   666  // PutStateSyncCurrentBlockHeight stores the current block height during state synchronization process.
   667  func (dao *Simple) PutStateSyncCurrentBlockHeight(h uint32) {
   668  	buf := dao.getDataBuf()
   669  	buf.WriteU32LE(h)
   670  	dao.Store.Put(dao.mkKeyPrefix(storage.SYSStateSyncCurrentBlockHeight), buf.Bytes())
   671  }
   672  
   673  func (dao *Simple) mkHeaderHashKey(h uint32) []byte {
   674  	b := dao.getKeyBuf(1 + 4)
   675  	b[0] = byte(storage.IXHeaderHashList)
   676  	binary.BigEndian.PutUint32(b[1:], h)
   677  	return b
   678  }
   679  
   680  // StoreHeaderHashes pushes a batch of header hashes into the store.
   681  func (dao *Simple) StoreHeaderHashes(hashes []util.Uint256, height uint32) error {
   682  	key := dao.mkHeaderHashKey(height)
   683  	buf := dao.getDataBuf()
   684  	buf.WriteArray(hashes)
   685  	if buf.Err != nil {
   686  		return buf.Err
   687  	}
   688  	dao.Store.Put(key, buf.Bytes())
   689  	return nil
   690  }
   691  
   692  // HasTransaction returns nil if the given store does not contain the given
   693  // Transaction hash. It returns an error in case the transaction is in chain
   694  // or in the list of conflicting transactions. If non-zero signers are specified,
   695  // then additional check against the conflicting transaction signers intersection
   696  // is held. Do not omit signers in case if it's important to check the validity
   697  // of a supposedly conflicting on-chain transaction. The retrieved conflict isn't
   698  // checked against the maxTraceableBlocks setting if signers are omitted.
   699  // HasTransaction does not consider the case of block executable.
   700  func (dao *Simple) HasTransaction(hash util.Uint256, signers []transaction.Signer, currentIndex uint32, maxTraceableBlocks uint32) error {
   701  	key := dao.makeExecutableKey(hash)
   702  	bytes, err := dao.Store.Get(key)
   703  	if err != nil {
   704  		return nil
   705  	}
   706  
   707  	if len(bytes) < conflictRecordValueLen { // (storage.ExecTransaction + index) for conflict record
   708  		return nil
   709  	}
   710  	if bytes[0] != storage.ExecTransaction {
   711  		// It's a block, thus no conflict. This path is needed since there's a transaction accepted on mainnet
   712  		// that conflicts with block. This transaction was declined by Go nodes, but accepted by C# nodes, and hence
   713  		// we need to adjust Go behaviour post-factum. Ref. #3427 and 0x289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc.
   714  		return nil
   715  	}
   716  	if len(bytes) != conflictRecordValueLen {
   717  		return ErrAlreadyExists // fully-qualified transaction
   718  	}
   719  	if len(signers) == 0 {
   720  		return ErrHasConflicts
   721  	}
   722  
   723  	if !isTraceableBlock(bytes[1:], currentIndex, maxTraceableBlocks) {
   724  		// The most fresh conflict record is already outdated.
   725  		return nil
   726  	}
   727  
   728  	for _, s := range signers {
   729  		v, err := dao.Store.Get(append(key, s.Account.BytesBE()...))
   730  		if err == nil {
   731  			if isTraceableBlock(v[1:], currentIndex, maxTraceableBlocks) {
   732  				return ErrHasConflicts
   733  			}
   734  		}
   735  	}
   736  
   737  	return nil
   738  }
   739  
   740  func isTraceableBlock(indexBytes []byte, height, maxTraceableBlocks uint32) bool {
   741  	index := binary.LittleEndian.Uint32(indexBytes)
   742  	return index <= height && index+maxTraceableBlocks > height
   743  }
   744  
   745  // StoreAsBlock stores given block as DataBlock. It can reuse given buffer for
   746  // the purpose of value serialization.
   747  func (dao *Simple) StoreAsBlock(block *block.Block, aer1 *state.AppExecResult, aer2 *state.AppExecResult) error {
   748  	var (
   749  		key = dao.makeExecutableKey(block.Hash())
   750  		buf = dao.getDataBuf()
   751  	)
   752  	buf.WriteB(storage.ExecBlock)
   753  	block.EncodeTrimmed(buf.BinWriter)
   754  	if aer1 != nil {
   755  		aer1.EncodeBinaryWithContext(buf.BinWriter, dao.GetItemCtx())
   756  	}
   757  	if aer2 != nil {
   758  		aer2.EncodeBinaryWithContext(buf.BinWriter, dao.GetItemCtx())
   759  	}
   760  	if buf.Err != nil {
   761  		return buf.Err
   762  	}
   763  	dao.Store.Put(key, buf.Bytes())
   764  	return nil
   765  }
   766  
   767  // DeleteBlock removes the block from dao. It's not atomic, so make sure you're
   768  // using private MemCached instance here.
   769  func (dao *Simple) DeleteBlock(h util.Uint256) error {
   770  	key := dao.makeExecutableKey(h)
   771  
   772  	b, err := dao.getBlock(key)
   773  	if err != nil {
   774  		return err
   775  	}
   776  	err = dao.storeHeader(key, &b.Header)
   777  	if err != nil {
   778  		return err
   779  	}
   780  
   781  	for _, tx := range b.Transactions {
   782  		copy(key[1:], tx.Hash().BytesBE())
   783  		dao.Store.Delete(key)
   784  		for _, attr := range tx.GetAttributes(transaction.ConflictsT) {
   785  			hash := attr.Value.(*transaction.Conflicts).Hash
   786  			copy(key[1:], hash.BytesBE())
   787  
   788  			v, err := dao.Store.Get(key)
   789  			if err != nil {
   790  				return fmt.Errorf("failed to retrieve conflict record stub for %s (height %d, conflict %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), err)
   791  			}
   792  			// It might be a block since we allow transactions to have block hash in the Conflicts attribute.
   793  			if v[0] != storage.ExecTransaction {
   794  				continue
   795  			}
   796  			index := binary.LittleEndian.Uint32(v[1:])
   797  			// We can check for `<=` here, but use equality comparison to be more precise
   798  			// and do not touch earlier conflict records (if any). Their removal must be triggered
   799  			// by the caller code.
   800  			if index == b.Index {
   801  				dao.Store.Delete(key)
   802  			}
   803  
   804  			for _, s := range tx.Signers {
   805  				sKey := append(key, s.Account.BytesBE()...)
   806  				v, err := dao.Store.Get(sKey)
   807  				if err != nil {
   808  					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)
   809  				}
   810  				index = binary.LittleEndian.Uint32(v[1:])
   811  				if index == b.Index {
   812  					dao.Store.Delete(sKey)
   813  				}
   814  			}
   815  		}
   816  	}
   817  
   818  	return nil
   819  }
   820  
   821  // PurgeHeader completely removes specified header from dao. It differs from
   822  // DeleteBlock in that it removes header anyway and does nothing except removing
   823  // header. It does no checks for header existence.
   824  func (dao *Simple) PurgeHeader(h util.Uint256) {
   825  	key := dao.makeExecutableKey(h)
   826  	dao.Store.Delete(key)
   827  }
   828  
   829  // StoreHeader saves the block header into the store.
   830  func (dao *Simple) StoreHeader(h *block.Header) error {
   831  	return dao.storeHeader(dao.makeExecutableKey(h.Hash()), h)
   832  }
   833  
   834  func (dao *Simple) storeHeader(key []byte, h *block.Header) error {
   835  	buf := dao.getDataBuf()
   836  	buf.WriteB(storage.ExecBlock)
   837  	h.EncodeBinary(buf.BinWriter)
   838  	buf.BinWriter.WriteB(0)
   839  	if buf.Err != nil {
   840  		return buf.Err
   841  	}
   842  	dao.Store.Put(key, buf.Bytes())
   843  	return nil
   844  }
   845  
   846  // StoreAsCurrentBlock stores the hash of the given block with prefix
   847  // SYSCurrentBlock.
   848  func (dao *Simple) StoreAsCurrentBlock(block *block.Block) {
   849  	buf := dao.getDataBuf()
   850  	h := block.Hash()
   851  	h.EncodeBinary(buf.BinWriter)
   852  	buf.WriteU32LE(block.Index)
   853  	dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes())
   854  }
   855  
   856  // StoreAsTransaction stores the given TX as DataTransaction. It also stores conflict records
   857  // (hashes of transactions the given tx has conflicts with) as DataTransaction with value containing
   858  // only five bytes: 1-byte [storage.ExecTransaction] executable prefix + 4-bytes-LE block index. It can reuse the given
   859  // buffer for the purpose of value serialization.
   860  func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error {
   861  	key := dao.makeExecutableKey(tx.Hash())
   862  	buf := dao.getDataBuf()
   863  
   864  	buf.WriteB(storage.ExecTransaction)
   865  	buf.WriteU32LE(index)
   866  	tx.EncodeBinary(buf.BinWriter)
   867  	if aer != nil {
   868  		aer.EncodeBinaryWithContext(buf.BinWriter, dao.GetItemCtx())
   869  	}
   870  	if buf.Err != nil {
   871  		return buf.Err
   872  	}
   873  	val := buf.Bytes()
   874  	dao.Store.Put(key, val)
   875  
   876  	val = val[:conflictRecordValueLen] // storage.ExecTransaction (1 byte) + index (4 bytes)
   877  	attrs := tx.GetAttributes(transaction.ConflictsT)
   878  	for _, attr := range attrs {
   879  		// Conflict record stub.
   880  		hash := attr.Value.(*transaction.Conflicts).Hash
   881  		copy(key[1:], hash.BytesBE())
   882  
   883  		// A short path if there's a block with the matching hash. If it's there, then
   884  		// don't store the conflict record stub and conflict signers since it's a
   885  		// useless record, no transaction with the same hash is possible.
   886  		exec, err := dao.Store.Get(key)
   887  		if err == nil {
   888  			if len(exec) > 0 && exec[0] != storage.ExecTransaction {
   889  				continue
   890  			}
   891  		}
   892  
   893  		dao.Store.Put(key, val)
   894  
   895  		// Conflicting signers.
   896  		sKey := make([]byte, len(key)+util.Uint160Size)
   897  		copy(sKey, key)
   898  		for _, s := range tx.Signers {
   899  			copy(sKey[len(key):], s.Account.BytesBE())
   900  			dao.Store.Put(sKey, val)
   901  		}
   902  	}
   903  	return nil
   904  }
   905  
   906  func (dao *Simple) getKeyBuf(l int) []byte {
   907  	if dao.private {
   908  		if dao.keyBuf == nil {
   909  			dao.keyBuf = make([]byte, 0, 1+4+limits.MaxStorageKeyLen) // Prefix, uint32, key.
   910  		}
   911  		return dao.keyBuf[:l] // Should have enough capacity.
   912  	}
   913  	return make([]byte, l)
   914  }
   915  
   916  func (dao *Simple) getDataBuf() *io.BufBinWriter {
   917  	if dao.private {
   918  		if dao.dataBuf == nil {
   919  			dao.dataBuf = io.NewBufBinWriter()
   920  		}
   921  		dao.dataBuf.Reset()
   922  		return dao.dataBuf
   923  	}
   924  	return io.NewBufBinWriter()
   925  }
   926  
   927  func (dao *Simple) GetItemCtx() *stackitem.SerializationContext {
   928  	if dao.private {
   929  		if dao.serCtx == nil {
   930  			dao.serCtx = stackitem.NewSerializationContext()
   931  		}
   932  		return dao.serCtx
   933  	}
   934  	return stackitem.NewSerializationContext()
   935  }
   936  
   937  // Persist flushes all the changes made into the (supposedly) persistent
   938  // underlying store. It doesn't block accesses to DAO from other threads.
   939  func (dao *Simple) Persist() (int, error) {
   940  	if dao.nativeCachePS != nil {
   941  		dao.nativeCacheLock.Lock()
   942  		dao.nativeCachePS.nativeCacheLock.Lock()
   943  		defer func() {
   944  			dao.nativeCachePS.nativeCacheLock.Unlock()
   945  			dao.nativeCacheLock.Unlock()
   946  		}()
   947  
   948  		dao.persistNativeCache()
   949  	}
   950  	return dao.Store.Persist()
   951  }
   952  
   953  // PersistSync flushes all the changes made into the (supposedly) persistent
   954  // underlying store. It's a synchronous version of Persist that doesn't allow
   955  // other threads to work with DAO while flushing the Store.
   956  func (dao *Simple) PersistSync() (int, error) {
   957  	if dao.nativeCachePS != nil {
   958  		dao.nativeCacheLock.Lock()
   959  		dao.nativeCachePS.nativeCacheLock.Lock()
   960  		defer func() {
   961  			dao.nativeCachePS.nativeCacheLock.Unlock()
   962  			dao.nativeCacheLock.Unlock()
   963  		}()
   964  		dao.persistNativeCache()
   965  	}
   966  	return dao.Store.PersistSync()
   967  }
   968  
   969  // persistNativeCache is internal unprotected method for native cache persisting.
   970  // It does NO checks for nativeCachePS is not nil.
   971  func (dao *Simple) persistNativeCache() {
   972  	lower := dao.nativeCachePS
   973  	for id, nativeCache := range dao.nativeCache {
   974  		lower.nativeCache[id] = nativeCache
   975  	}
   976  	dao.nativeCache = nil
   977  }
   978  
   979  // GetROCache returns native contact cache. The cache CAN NOT be modified by
   980  // the caller. It's the caller's duty to keep it unmodified.
   981  func (dao *Simple) GetROCache(id int32) NativeContractCache {
   982  	dao.nativeCacheLock.RLock()
   983  	defer dao.nativeCacheLock.RUnlock()
   984  
   985  	return dao.getCache(id, true)
   986  }
   987  
   988  // GetRWCache returns native contact cache. The cache CAN BE safely modified
   989  // by the caller.
   990  func (dao *Simple) GetRWCache(id int32) NativeContractCache {
   991  	dao.nativeCacheLock.Lock()
   992  	defer dao.nativeCacheLock.Unlock()
   993  
   994  	return dao.getCache(id, false)
   995  }
   996  
   997  // getCache is an internal unlocked representation of GetROCache and GetRWCache.
   998  func (dao *Simple) getCache(k int32, ro bool) NativeContractCache {
   999  	if itm, ok := dao.nativeCache[k]; ok {
  1000  		// Don't need to create itm copy, because its value was already copied
  1001  		// the first time it was retrieved from lower ps.
  1002  		return itm
  1003  	}
  1004  
  1005  	if dao.nativeCachePS != nil {
  1006  		if ro {
  1007  			return dao.nativeCachePS.GetROCache(k)
  1008  		}
  1009  		v := dao.nativeCachePS.GetRWCache(k)
  1010  		if v != nil {
  1011  			// Create a copy here in order not to modify the existing cache.
  1012  			cp := v.Copy()
  1013  			dao.nativeCache[k] = cp
  1014  			return cp
  1015  		}
  1016  	}
  1017  	return nil
  1018  }
  1019  
  1020  // SetCache adds native contract cache to the cache map.
  1021  func (dao *Simple) SetCache(id int32, v NativeContractCache) {
  1022  	dao.nativeCacheLock.Lock()
  1023  	defer dao.nativeCacheLock.Unlock()
  1024  
  1025  	dao.nativeCache[id] = v
  1026  }