mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-09 14:08:03 -05:00
Co-authored-by: Péter Garamvölgyi <peter@scroll.io> Co-authored-by: colinlyguo <colinlyguo@users.noreply.github.com> Co-authored-by: georgehao <haohongfan@gmail.com>
412 lines
14 KiB
Go
412 lines
14 KiB
Go
package orm
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"math/big"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/scroll-tech/go-ethereum/common"
|
|
gethTypes "github.com/scroll-tech/go-ethereum/core/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"gorm.io/gorm"
|
|
|
|
"scroll-tech/common/database"
|
|
"scroll-tech/common/docker"
|
|
"scroll-tech/common/types"
|
|
"scroll-tech/common/types/encoding"
|
|
"scroll-tech/common/types/encoding/codecv0"
|
|
"scroll-tech/database/migrate"
|
|
)
|
|
|
|
var (
|
|
base *docker.App
|
|
|
|
db *gorm.DB
|
|
l2BlockOrm *L2Block
|
|
chunkOrm *Chunk
|
|
batchOrm *Batch
|
|
pendingTransactionOrm *PendingTransaction
|
|
|
|
block1 *encoding.Block
|
|
block2 *encoding.Block
|
|
chunk1 *encoding.Chunk
|
|
chunk2 *encoding.Chunk
|
|
chunkHash1 common.Hash
|
|
chunkHash2 common.Hash
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
t := &testing.T{}
|
|
setupEnv(t)
|
|
defer tearDownEnv(t)
|
|
m.Run()
|
|
}
|
|
|
|
func setupEnv(t *testing.T) {
|
|
base = docker.NewDockerApp()
|
|
base.RunDBImage(t)
|
|
var err error
|
|
db, err = database.InitDB(
|
|
&database.Config{
|
|
DSN: base.DBConfig.DSN,
|
|
DriverName: base.DBConfig.DriverName,
|
|
MaxOpenNum: base.DBConfig.MaxOpenNum,
|
|
MaxIdleNum: base.DBConfig.MaxIdleNum,
|
|
},
|
|
)
|
|
assert.NoError(t, err)
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, migrate.ResetDB(sqlDB))
|
|
|
|
batchOrm = NewBatch(db)
|
|
chunkOrm = NewChunk(db)
|
|
l2BlockOrm = NewL2Block(db)
|
|
pendingTransactionOrm = NewPendingTransaction(db)
|
|
|
|
templateBlockTrace, err := os.ReadFile("../../../common/testdata/blockTrace_02.json")
|
|
assert.NoError(t, err)
|
|
block1 = &encoding.Block{}
|
|
err = json.Unmarshal(templateBlockTrace, block1)
|
|
assert.NoError(t, err)
|
|
|
|
templateBlockTrace, err = os.ReadFile("../../../common/testdata/blockTrace_03.json")
|
|
assert.NoError(t, err)
|
|
block2 = &encoding.Block{}
|
|
err = json.Unmarshal(templateBlockTrace, block2)
|
|
assert.NoError(t, err)
|
|
|
|
chunk1 = &encoding.Chunk{Blocks: []*encoding.Block{block1}}
|
|
daChunk1, err := codecv0.NewDAChunk(chunk1, 0)
|
|
assert.NoError(t, err)
|
|
chunkHash1, err = daChunk1.Hash()
|
|
assert.NoError(t, err)
|
|
|
|
chunk2 = &encoding.Chunk{Blocks: []*encoding.Block{block2}}
|
|
daChunk2, err := codecv0.NewDAChunk(chunk2, chunk1.NumL1Messages(0))
|
|
assert.NoError(t, err)
|
|
chunkHash2, err = daChunk2.Hash()
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func tearDownEnv(t *testing.T) {
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
sqlDB.Close()
|
|
base.Free()
|
|
}
|
|
|
|
func TestL1BlockOrm(t *testing.T) {
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, migrate.ResetDB(sqlDB))
|
|
|
|
l1BlockOrm := NewL1Block(db)
|
|
|
|
// mock blocks
|
|
block1 := L1Block{Number: 1, Hash: "hash1"}
|
|
block2 := L1Block{Number: 2, Hash: "hash2"}
|
|
block3 := L1Block{Number: 3, Hash: "hash3"}
|
|
block2AfterReorg := L1Block{Number: 2, Hash: "hash2-reorg"}
|
|
|
|
err = l1BlockOrm.InsertL1Blocks(context.Background(), []L1Block{block1, block2, block3})
|
|
assert.NoError(t, err)
|
|
|
|
height, err := l1BlockOrm.GetLatestL1BlockHeight(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, uint64(3), height)
|
|
|
|
blocks, err := l1BlockOrm.GetL1Blocks(context.Background(), map[string]interface{}{})
|
|
assert.NoError(t, err)
|
|
assert.Len(t, blocks, 3)
|
|
assert.Equal(t, "hash1", blocks[0].Hash)
|
|
assert.Equal(t, "hash2", blocks[1].Hash)
|
|
assert.Equal(t, "hash3", blocks[2].Hash)
|
|
|
|
// reorg handling: insert another block with same height and different hash
|
|
err = l1BlockOrm.InsertL1Blocks(context.Background(), []L1Block{block2AfterReorg})
|
|
assert.NoError(t, err)
|
|
|
|
blocks, err = l1BlockOrm.GetL1Blocks(context.Background(), map[string]interface{}{})
|
|
assert.NoError(t, err)
|
|
assert.Len(t, blocks, 2)
|
|
assert.Equal(t, "hash1", blocks[0].Hash)
|
|
assert.Equal(t, "hash2-reorg", blocks[1].Hash)
|
|
|
|
err = l1BlockOrm.UpdateL1GasOracleStatusAndOracleTxHash(context.Background(), "hash1", types.GasOracleImported, "txhash1")
|
|
assert.NoError(t, err)
|
|
|
|
updatedBlocks, err := l1BlockOrm.GetL1Blocks(context.Background(), map[string]interface{}{})
|
|
assert.NoError(t, err)
|
|
assert.Len(t, updatedBlocks, 2)
|
|
assert.Equal(t, types.GasOracleImported, types.GasOracleStatus(updatedBlocks[0].GasOracleStatus))
|
|
assert.Equal(t, "txhash1", updatedBlocks[0].OracleTxHash)
|
|
}
|
|
|
|
func TestL2BlockOrm(t *testing.T) {
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, migrate.ResetDB(sqlDB))
|
|
|
|
err = l2BlockOrm.InsertL2Blocks(context.Background(), []*encoding.Block{block1, block2})
|
|
assert.NoError(t, err)
|
|
|
|
height, err := l2BlockOrm.GetL2BlocksLatestHeight(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, uint64(3), height)
|
|
|
|
chunkHashes, err := l2BlockOrm.GetChunkHashes(context.Background(), 0)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, chunkHashes, 2)
|
|
assert.Equal(t, "", chunkHashes[0])
|
|
assert.Equal(t, "", chunkHashes[1])
|
|
|
|
blocks, err := l2BlockOrm.GetL2BlocksInRange(context.Background(), 2, 3)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, blocks, 2)
|
|
assert.Equal(t, block1, blocks[0])
|
|
assert.Equal(t, block2, blocks[1])
|
|
|
|
err = l2BlockOrm.UpdateChunkHashInRange(context.Background(), 2, 2, "test hash")
|
|
assert.NoError(t, err)
|
|
|
|
chunkHashes, err = l2BlockOrm.GetChunkHashes(context.Background(), 0)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, chunkHashes, 2)
|
|
assert.Equal(t, "test hash", chunkHashes[0])
|
|
assert.Equal(t, "", chunkHashes[1])
|
|
}
|
|
|
|
func TestChunkOrm(t *testing.T) {
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, migrate.ResetDB(sqlDB))
|
|
|
|
dbChunk1, err := chunkOrm.InsertChunk(context.Background(), chunk1)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, dbChunk1.Hash, chunkHash1.Hex())
|
|
|
|
dbChunk2, err := chunkOrm.InsertChunk(context.Background(), chunk2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, dbChunk2.Hash, chunkHash2.Hex())
|
|
|
|
chunks, err := chunkOrm.GetChunksGEIndex(context.Background(), 0, 0)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, chunks, 2)
|
|
assert.Equal(t, chunkHash1.Hex(), chunks[0].Hash)
|
|
assert.Equal(t, chunkHash2.Hex(), chunks[1].Hash)
|
|
assert.Equal(t, "", chunks[0].BatchHash)
|
|
assert.Equal(t, "", chunks[1].BatchHash)
|
|
|
|
err = chunkOrm.UpdateProvingStatus(context.Background(), chunkHash1.Hex(), types.ProvingTaskVerified)
|
|
assert.NoError(t, err)
|
|
err = chunkOrm.UpdateProvingStatus(context.Background(), chunkHash2.Hex(), types.ProvingTaskAssigned)
|
|
assert.NoError(t, err)
|
|
|
|
chunks, err = chunkOrm.GetChunksInRange(context.Background(), 0, 1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, chunks, 2)
|
|
assert.Equal(t, chunkHash1.Hex(), chunks[0].Hash)
|
|
assert.Equal(t, chunkHash2.Hex(), chunks[1].Hash)
|
|
assert.Equal(t, types.ProvingTaskVerified, types.ProvingStatus(chunks[0].ProvingStatus))
|
|
assert.Equal(t, types.ProvingTaskAssigned, types.ProvingStatus(chunks[1].ProvingStatus))
|
|
|
|
err = chunkOrm.UpdateBatchHashInRange(context.Background(), 0, 0, "test hash")
|
|
assert.NoError(t, err)
|
|
chunks, err = chunkOrm.GetChunksGEIndex(context.Background(), 0, 0)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, chunks, 2)
|
|
assert.Equal(t, chunkHash1.Hex(), chunks[0].Hash)
|
|
assert.Equal(t, chunkHash2.Hex(), chunks[1].Hash)
|
|
assert.Equal(t, "test hash", chunks[0].BatchHash)
|
|
assert.Equal(t, "", chunks[1].BatchHash)
|
|
}
|
|
|
|
func TestBatchOrm(t *testing.T) {
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, migrate.ResetDB(sqlDB))
|
|
|
|
batch := &encoding.Batch{
|
|
Index: 0,
|
|
TotalL1MessagePoppedBefore: 0,
|
|
ParentBatchHash: common.Hash{},
|
|
Chunks: []*encoding.Chunk{chunk1},
|
|
StartChunkIndex: 0,
|
|
StartChunkHash: chunkHash1,
|
|
EndChunkIndex: 0,
|
|
EndChunkHash: chunkHash1,
|
|
}
|
|
batch1, err := batchOrm.InsertBatch(context.Background(), batch)
|
|
assert.NoError(t, err)
|
|
hash1 := batch1.Hash
|
|
|
|
batch1, err = batchOrm.GetBatchByIndex(context.Background(), 0)
|
|
assert.NoError(t, err)
|
|
daBatch1, err := codecv0.NewDABatchFromBytes(batch1.BatchHeader)
|
|
assert.NoError(t, err)
|
|
batchHash1 := daBatch1.Hash().Hex()
|
|
assert.Equal(t, hash1, batchHash1)
|
|
|
|
batch = &encoding.Batch{
|
|
Index: 1,
|
|
TotalL1MessagePoppedBefore: 0,
|
|
ParentBatchHash: common.Hash{},
|
|
Chunks: []*encoding.Chunk{chunk1},
|
|
StartChunkIndex: 1,
|
|
StartChunkHash: chunkHash2,
|
|
EndChunkIndex: 1,
|
|
EndChunkHash: chunkHash2,
|
|
}
|
|
batch2, err := batchOrm.InsertBatch(context.Background(), batch)
|
|
assert.NoError(t, err)
|
|
hash2 := batch2.Hash
|
|
|
|
batch2, err = batchOrm.GetBatchByIndex(context.Background(), 1)
|
|
assert.NoError(t, err)
|
|
daBatch2, err := codecv0.NewDABatchFromBytes(batch2.BatchHeader)
|
|
assert.NoError(t, err)
|
|
batchHash2 := daBatch2.Hash().Hex()
|
|
assert.Equal(t, hash2, batchHash2)
|
|
|
|
count, err := batchOrm.GetBatchCount(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, uint64(2), count)
|
|
|
|
err = batchOrm.UpdateRollupStatus(context.Background(), batchHash1, types.RollupCommitFailed)
|
|
assert.NoError(t, err)
|
|
|
|
pendingBatches, err := batchOrm.GetFailedAndPendingBatches(context.Background(), 100)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, len(pendingBatches))
|
|
|
|
rollupStatus, err := batchOrm.GetRollupStatusByHashList(context.Background(), []string{batchHash1, batchHash2})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, len(rollupStatus))
|
|
assert.Equal(t, types.RollupCommitFailed, rollupStatus[0])
|
|
assert.Equal(t, types.RollupPending, rollupStatus[1])
|
|
|
|
err = batchOrm.UpdateProvingStatus(context.Background(), batchHash2, types.ProvingTaskVerified)
|
|
assert.NoError(t, err)
|
|
|
|
dbProof, err := batchOrm.GetVerifiedProofByHash(context.Background(), batchHash1)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, dbProof)
|
|
|
|
err = batchOrm.UpdateProvingStatus(context.Background(), batchHash2, types.ProvingTaskVerified)
|
|
assert.NoError(t, err)
|
|
err = batchOrm.UpdateRollupStatus(context.Background(), batchHash2, types.RollupFinalized)
|
|
assert.NoError(t, err)
|
|
err = batchOrm.UpdateL2GasOracleStatusAndOracleTxHash(context.Background(), batchHash2, types.GasOracleImported, "oracleTxHash")
|
|
assert.NoError(t, err)
|
|
|
|
updatedBatch, err := batchOrm.GetLatestBatch(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, updatedBatch)
|
|
assert.Equal(t, types.ProvingTaskVerified, types.ProvingStatus(updatedBatch.ProvingStatus))
|
|
assert.Equal(t, types.RollupFinalized, types.RollupStatus(updatedBatch.RollupStatus))
|
|
assert.Equal(t, types.GasOracleImported, types.GasOracleStatus(updatedBatch.OracleStatus))
|
|
assert.Equal(t, "oracleTxHash", updatedBatch.OracleTxHash)
|
|
|
|
err = batchOrm.UpdateCommitTxHashAndRollupStatus(context.Background(), batchHash2, "commitTxHash", types.RollupCommitted)
|
|
assert.NoError(t, err)
|
|
updatedBatch, err = batchOrm.GetLatestBatch(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, updatedBatch)
|
|
assert.Equal(t, "commitTxHash", updatedBatch.CommitTxHash)
|
|
assert.Equal(t, types.RollupCommitted, types.RollupStatus(updatedBatch.RollupStatus))
|
|
|
|
err = batchOrm.UpdateFinalizeTxHashAndRollupStatus(context.Background(), batchHash2, "finalizeTxHash", types.RollupFinalizeFailed)
|
|
assert.NoError(t, err)
|
|
|
|
updatedBatch, err = batchOrm.GetLatestBatch(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, updatedBatch)
|
|
assert.Equal(t, "finalizeTxHash", updatedBatch.FinalizeTxHash)
|
|
assert.Equal(t, types.RollupFinalizeFailed, types.RollupStatus(updatedBatch.RollupStatus))
|
|
}
|
|
|
|
func TestTransactionOrm(t *testing.T) {
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, migrate.ResetDB(sqlDB))
|
|
|
|
tx0 := gethTypes.NewTx(&gethTypes.DynamicFeeTx{
|
|
Nonce: 0,
|
|
To: &common.Address{},
|
|
Data: []byte{},
|
|
Gas: 21000,
|
|
AccessList: gethTypes.AccessList{},
|
|
Value: big.NewInt(0),
|
|
ChainID: big.NewInt(1),
|
|
GasTipCap: big.NewInt(0),
|
|
GasFeeCap: big.NewInt(1),
|
|
V: big.NewInt(0),
|
|
R: big.NewInt(0),
|
|
S: big.NewInt(0),
|
|
})
|
|
tx1 := gethTypes.NewTx(&gethTypes.DynamicFeeTx{
|
|
Nonce: 0,
|
|
To: &common.Address{},
|
|
Data: []byte{},
|
|
Gas: 42000,
|
|
AccessList: gethTypes.AccessList{},
|
|
Value: big.NewInt(0),
|
|
ChainID: big.NewInt(1),
|
|
GasTipCap: big.NewInt(1),
|
|
GasFeeCap: big.NewInt(2),
|
|
V: big.NewInt(0),
|
|
R: big.NewInt(0),
|
|
S: big.NewInt(0),
|
|
})
|
|
senderMeta := &SenderMeta{
|
|
Name: "testName",
|
|
Service: "testService",
|
|
Address: common.HexToAddress("0x1"),
|
|
Type: types.SenderTypeCommitBatch,
|
|
}
|
|
|
|
err = pendingTransactionOrm.InsertPendingTransaction(context.Background(), "test", senderMeta, tx0, 0)
|
|
assert.NoError(t, err)
|
|
|
|
err = pendingTransactionOrm.InsertPendingTransaction(context.Background(), "test", senderMeta, tx1, 0)
|
|
assert.NoError(t, err)
|
|
|
|
err = pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(context.Background(), tx0.Hash(), types.TxStatusReplaced)
|
|
assert.NoError(t, err)
|
|
|
|
txs, err := pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), senderMeta.Type, 2)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, txs, 2)
|
|
assert.Equal(t, tx1.Type(), txs[1].Type)
|
|
assert.Equal(t, tx1.Nonce(), txs[1].Nonce)
|
|
assert.Equal(t, tx1.Gas(), txs[1].GasLimit)
|
|
assert.Equal(t, tx1.GasTipCap().Uint64(), txs[1].GasTipCap)
|
|
assert.Equal(t, tx1.GasFeeCap().Uint64(), txs[1].GasFeeCap)
|
|
assert.Equal(t, tx1.ChainId().Uint64(), txs[1].ChainID)
|
|
assert.Equal(t, senderMeta.Name, txs[1].SenderName)
|
|
assert.Equal(t, senderMeta.Service, txs[1].SenderService)
|
|
assert.Equal(t, senderMeta.Address.String(), txs[1].SenderAddress)
|
|
assert.Equal(t, senderMeta.Type, txs[1].SenderType)
|
|
|
|
err = pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(context.Background(), tx1.Hash(), types.TxStatusConfirmed)
|
|
assert.NoError(t, err)
|
|
|
|
txs, err = pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), senderMeta.Type, 2)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, txs, 1)
|
|
|
|
err = pendingTransactionOrm.UpdateOtherTransactionsAsFailedByNonce(context.Background(), senderMeta.Address.String(), tx1.Nonce(), tx1.Hash())
|
|
assert.NoError(t, err)
|
|
|
|
txs, err = pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), senderMeta.Type, 2)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, txs, 0)
|
|
|
|
status, err := pendingTransactionOrm.GetTxStatusByTxHash(context.Background(), tx0.Hash())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, types.TxStatusConfirmedFailed, status)
|
|
}
|