Skip to content

Commit

Permalink
Merge pull request #3928 from ElrondNetwork/fix-epoch-start-with-inva…
Browse files Browse the repository at this point in the history
…lid-scheduled

fix invalid scheduled tx on epoch start
  • Loading branch information
iulianpascalau authored Mar 22, 2022
2 parents 6fa07c6 + 20ca2e6 commit 38ed1e8
Show file tree
Hide file tree
Showing 8 changed files with 473 additions and 12 deletions.
12 changes: 10 additions & 2 deletions epochStart/bootstrap/startInEpochScheduled.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ func isScheduledIntermediateTx(
) bool {
blockType := getBlockTypeOfTx(txHash, miniBlocks)
if blockType != block.SmartContractResultBlock && blockType != block.InvalidBlock {
log.Debug("isScheduledIntermediateTx", "blockType", blockType, "txHash", txHash, "ret", false)
return false
}

Expand All @@ -323,8 +324,15 @@ func isScheduledIntermediateTx(
scheduledTxHash = txHash
}

receiverShardID, isScheduledIntermediateTx := scheduledTxHashes[string(scheduledTxHash)]
return isScheduledIntermediateTx && receiverShardID == selfShardID
receiverShardID, isScheduledIntermediateTransaction := scheduledTxHashes[string(scheduledTxHash)]
isTxExecutedInSelfShard := receiverShardID == selfShardID || blockType == block.InvalidBlock
log.Debug("isScheduledIntermediateTx",
"blockType", blockType,
"txHash", txHash,
"isScheduledIntermediateTransaction", isScheduledIntermediateTransaction,
"isTxExecutedInSelfShard", isTxExecutedInSelfShard)

return isScheduledIntermediateTransaction && isTxExecutedInSelfShard
}

func getScheduledIntermediateTxsMap(
Expand Down
68 changes: 68 additions & 0 deletions epochStart/bootstrap/startInEpochScheduled_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,3 +782,71 @@ func TestNumScheduledIntermediateTxs(t *testing.T) {
num := getNumScheduledIntermediateTxs(mapTxs)
assert.Equal(t, 3, num)
}

func Test_isScheduledIntermediateTx(t *testing.T) {
t.Parallel()

selfShardID := uint32(0)
destinationAsInvalid := selfShardID

mbHash := "miniBlockHash"
tx1Hash := "tx1Hash"
scrHash := "scrHash"

t.Run("executed in self shard - scheduled", func(t *testing.T) {
scr := &smartContractResult.SmartContractResult{Nonce: 0,
PrevTxHash: []byte(tx1Hash),
}
miniBlockScr := &block.MiniBlock{
TxHashes: [][]byte{[]byte(scrHash)},
ReceiverShardID: selfShardID,
SenderShardID: selfShardID,
Type: block.SmartContractResultBlock,
}
miniBlocks := map[string]*block.MiniBlock{
mbHash: miniBlockScr,
}
scheduledTxHashes := map[string]uint32{
tx1Hash: selfShardID,
}

require.True(t, isScheduledIntermediateTx(miniBlocks, scheduledTxHashes, []byte(scrHash), scr, selfShardID))
})
t.Run("invalid scheduled", func(t *testing.T) {
miniBlockInvalid := &block.MiniBlock{
TxHashes: [][]byte{[]byte(tx1Hash)},
ReceiverShardID: destinationAsInvalid,
SenderShardID: selfShardID,
Type: block.InvalidBlock,
}

miniBlocks := map[string]*block.MiniBlock{
mbHash: miniBlockInvalid,
}
scheduledTxHashes := map[string]uint32{
tx1Hash: destinationAsInvalid,
}
tx1 := &transaction.Transaction{
Nonce: 1,
}
require.True(t, isScheduledIntermediateTx(miniBlocks, scheduledTxHashes, []byte(tx1Hash), tx1, selfShardID))
})
t.Run("normal tx", func(t *testing.T) {
tx2Hash := "tx2Hash"
tx2 := &transaction.Transaction{Nonce: 1}

miniBlocks := map[string]*block.MiniBlock{
mbHash: {
TxHashes: [][]byte{[]byte(tx2Hash)},
ReceiverShardID: 1,
SenderShardID: 0,
Type: block.TxBlock,
},
}
scheduledTxHashes := map[string]uint32{
tx1Hash: selfShardID,
}

require.False(t, isScheduledIntermediateTx(miniBlocks, scheduledTxHashes, []byte(tx2Hash), tx2, selfShardID))
})
}
15 changes: 12 additions & 3 deletions process/block/preprocess/scheduledTxsExecution.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,15 @@ func (ste *scheduledTxsExecution) removeInvalidTxsFromScheduledMiniBlocks(interm
}
}

resultedScheduledMbs := make(block.MiniBlockSlice, 0)
for _, miniBlock := range ste.scheduledMbs {
if len(miniBlock.TxHashes) == 0 {
continue
}
resultedScheduledMbs = append(resultedScheduledMbs, miniBlock)
}
ste.scheduledMbs = resultedScheduledMbs

log.Debug("scheduledTxsExecution.removeInvalidTxsFromScheduledMiniBlocks", "num of invalid txs removed", numInvalidTxsRemoved)
}

Expand Down Expand Up @@ -630,9 +639,9 @@ func (ste *scheduledTxsExecution) IsScheduledTx(txHash []byte) bool {

// IsMiniBlockExecuted returns true if the given mini block is already executed
func (ste *scheduledTxsExecution) IsMiniBlockExecuted(mbHash []byte) bool {
//TODO: This method and also ste.mapScheduledMbHashes could be removed when we will have mini block header IsFinal method later,
//but only when we could differentiate between the final mini blocks executed as scheduled in the last block and the normal mini blocks
//from the current block which are also final, but not yet executed
// TODO: This method and also ste.mapScheduledMbHashes could be removed when we will have mini block header IsFinal method later,
// but only when we could differentiate between the final mini blocks executed as scheduled in the last block and the normal mini blocks
// from the current block which are also final, but not yet executed
ste.mutScheduledTxs.RLock()
_, ok := ste.mapScheduledMbHashes[string(mbHash)]
ste.mutScheduledTxs.RUnlock()
Expand Down
9 changes: 5 additions & 4 deletions process/block/preprocess/scheduledTxsExecution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1525,12 +1525,13 @@ func TestScheduledTxsExecution_removeInvalidTxsFromScheduledMiniBlocks(t *testin
scheduledTxsExec.scheduledMbs = mbs
scheduledTxsExec.removeInvalidTxsFromScheduledMiniBlocks(scrsInfo)

//TODO: check if a scheduledMB should have no TxHashes inside
expectedLen := 0
assert.Equal(t, expectedLen, len(scheduledTxsExec.scheduledMbs[1].TxHashes))
// a scheduled miniBlock without any txs is removed completely
expectedNumScheduledMiniBlocks := 1
assert.Equal(t, expectedNumScheduledMiniBlocks, len(scheduledTxsExec.scheduledMbs))

expectedLen = 2
expectedLen := 2
assert.Equal(t, expectedLen, len(scheduledTxsExec.scheduledMbs[0].TxHashes))

remainingTxHashes := scheduledTxsExec.scheduledMbs[0].TxHashes
assert.True(t, bytes.Equal(txHash2, remainingTxHashes[0]))
assert.True(t, bytes.Equal(txHash4, remainingTxHashes[1]))
Expand Down
20 changes: 19 additions & 1 deletion process/block/preprocess/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func (txs *transactions) RestoreBlockDataIntoPools(
continue
}

strCache := process.ShardCacherIdentifier(miniBlock.SenderShardID, miniBlock.ReceiverShardID)
miniBlockStrCache := process.ShardCacherIdentifier(miniBlock.SenderShardID, miniBlock.ReceiverShardID)
txsBuff, err := txs.storage.GetAll(dataRetriever.TransactionUnit, miniBlock.TxHashes)
if err != nil {
log.Debug("tx from mini block was not found in TransactionUnit",
Expand All @@ -272,6 +272,7 @@ func (txs *transactions) RestoreBlockDataIntoPools(
return txsRestored, err
}

strCache := txs.computeCacheIdentifier(miniBlockStrCache, &tx, miniBlock.Type)
txs.txPool.AddData([]byte(txHash), &tx, tx.Size(), strCache)
}

Expand All @@ -290,6 +291,23 @@ func (txs *transactions) RestoreBlockDataIntoPools(
return txsRestored, nil
}

func (txs *transactions) computeCacheIdentifier(miniBlockStrCache string, tx *transaction.Transaction, miniBlockType block.Type) string {
if miniBlockType != block.InvalidBlock {
return miniBlockStrCache
}
if !txs.flagScheduledMiniBlocks.IsSet() {
return miniBlockStrCache
}

// scheduled miniblocks feature requires that the transactions are properly restored in the correct cache, not the one
// provided by the containing miniblock (think of how invalid transactions are executed and stored)

senderShardID := txs.getShardFromAddress(tx.GetSndAddr())
receiverShardID := txs.getShardFromAddress(tx.GetRcvAddr())

return process.ShardCacherIdentifier(senderShardID, receiverShardID)
}

// ProcessBlockTransactions processes all the transaction from the block.Body, updates the state
func (txs *transactions) ProcessBlockTransactions(
header data.HeaderHandler,
Expand Down
Loading

0 comments on commit 38ed1e8

Please sign in to comment.