From 0c446d9027a9201536f4c5b5a80d23035687887b Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 15 May 2024 14:29:27 +0300 Subject: [PATCH] dao: fix transaction application log decoding Conflict record stub has value of 5 bytes length: 1 byte for storage.ExecTransaction prefix and 4 bytes for the block index LE. This scheme was implemented in #3138, and this commit should be a part of this PR. Also, transaction.DummyVersion is removed since it's unused anymore. Close #3426. The reason of `failed to locate application log: EOF` error during genesis AER request is in the following: genesis executable was overwritten by conflict record stub produced by transaction 0x289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc (ref. #3427). As a consequence, an attempt to decode transaction AER was initited, but conflict record scheme was changed in #3138. Signed-off-by: Anna Shaleva --- pkg/core/dao/dao.go | 9 +++++---- pkg/core/transaction/transaction.go | 4 +--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/core/dao/dao.go b/pkg/core/dao/dao.go index 961579a1ce..4adeec4e70 100644 --- a/pkg/core/dao/dao.go +++ b/pkg/core/dao/dao.go @@ -323,7 +323,7 @@ func (dao *Simple) GetTxExecResult(hash util.Uint256) (uint32, *transaction.Tran // 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 { + if len(buf) == 1+4 { // conflict record stub. return 0, nil, nil, storage.ErrKeyNotFound } r := io.NewBinReaderFromBuf(buf) @@ -605,7 +605,7 @@ func (dao *Simple) DeleteHeaderHashes(since uint32, batchSize int) { } // GetTransaction returns Transaction and its height by the given hash -// if it exists in the store. It does not return dummy transactions. +// if it exists in the store. It does not return conflict record stubs. func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) { key := dao.makeExecutableKey(hash) b, err := dao.Store.Get(key) @@ -844,8 +844,9 @@ func (dao *Simple) StoreAsCurrentBlock(block *block.Block) { dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes()) } -// 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 +// StoreAsTransaction stores the given TX as DataTransaction. It also stores conflict records +// (hashes of transactions the given tx has conflicts with) as DataTransaction with value containing +// only five bytes: 1-byte [storage.ExecTransaction] executable prefix + 4-bytes-LE block index. It can reuse the given // buffer for the purpose of value serialization. func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error { key := dao.makeExecutableKey(tx.Hash()) diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index a41c811a4d..443e75efa1 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -26,8 +26,6 @@ const ( // MaxAttributes is maximum number of attributes including signers that can be contained // within a transaction. It is set to be 16. MaxAttributes = 16 - // DummyVersion represents reserved transaction version for trimmed transactions. - DummyVersion = 255 ) // ErrInvalidWitnessNum returns when the number of witnesses does not match signers. @@ -408,7 +406,7 @@ var ( // isValid checks whether decoded/unmarshalled transaction has all fields valid. func (t *Transaction) isValid() error { - if t.Version > 0 && t.Version != DummyVersion { + if t.Version > 0 { return ErrInvalidVersion } if t.SystemFee < 0 {