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 <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2024-05-15 14:29:27 +03:00
parent 58a086ea91
commit 9a1075d332
2 changed files with 6 additions and 7 deletions

View file

@ -323,7 +323,7 @@ func (dao *Simple) GetTxExecResult(hash util.Uint256) (uint32, *transaction.Tran
// decodeTxAndExecResult decodes transaction, its height and execution result from // decodeTxAndExecResult decodes transaction, its height and execution result from
// the given executable bytes. It performs no executable prefix check. // the given executable bytes. It performs no executable prefix check.
func decodeTxAndExecResult(buf []byte) (uint32, *transaction.Transaction, *state.AppExecResult, error) { 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 return 0, nil, nil, storage.ErrKeyNotFound
} }
r := io.NewBinReaderFromBuf(buf) 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 // 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) { func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) {
key := dao.makeExecutableKey(hash) key := dao.makeExecutableKey(hash)
b, err := dao.Store.Get(key) 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()) dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes())
} }
// StoreAsTransaction stores the given TX as DataTransaction. It also stores transactions // StoreAsTransaction stores the given TX as DataTransaction. It also stores conflict records
// the given tx has conflicts with as DataTransaction with dummy version. It can reuse the given // (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. // buffer for the purpose of value serialization.
func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error { func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error {
key := dao.makeExecutableKey(tx.Hash()) key := dao.makeExecutableKey(tx.Hash())

View file

@ -26,8 +26,6 @@ const (
// MaxAttributes is maximum number of attributes including signers that can be contained // MaxAttributes is maximum number of attributes including signers that can be contained
// within a transaction. It is set to be 16. // within a transaction. It is set to be 16.
MaxAttributes = 16 MaxAttributes = 16
// DummyVersion represents reserved transaction version for trimmed transactions.
DummyVersion = 255
) )
// ErrInvalidWitnessNum returns when the number of witnesses does not match signers. // 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. // isValid checks whether decoded/unmarshalled transaction has all fields valid.
func (t *Transaction) isValid() error { func (t *Transaction) isValid() error {
if t.Version > 0 && t.Version != DummyVersion { if t.Version > 0 {
return ErrInvalidVersion return ErrInvalidVersion
} }
if t.SystemFee < 0 { if t.SystemFee < 0 {