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 }