mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-31 00:53:46 +00:00
* feat(beacon): introduce soft blocks * feat: update api.go * chore(ci): update CI * feat: update L1Origin * feat: update `verifyHeader` * test: update tests * feat: update consensus * feat: update consensus * feat: update genesis * feat: remove timestamp check in prepareWork * feat: merge changes in #281 * Update eth/catalyst/api.go Co-authored-by: maskpp <maskpp266@gmail.com> * Update internal/ethapi/taiko_preconf.go Co-authored-by: maskpp <maskpp266@gmail.com> * fix consensus test * revert commit f1df58 * fix consensus test (#349) * Update eth/catalyst/api.go Co-authored-by: maskpp <maskpp266@gmail.com> * feat: add back timestamp check in worker * add genesis * temp fix for old l1origin * nil value * feat: rename to `L1OriginLegacy` * feat: change `common.Big0` as the default value for legacy l1Origin, to make `IsSoftblock` return `false` * feat(beacon): change the reorg log level (#350) * use debug log level to avoid logging too many logs when frequently soft block reorg. * use debug log level to avoid logging too many logs when frequently soft block reorg. * feat: check --taiko flag --------- Co-authored-by: David <david@taiko.xyz> * add rlp optional flag (#353) * fix lint * fix test case * feat(l1Origin): remove the reverted l1Origins (#355) * remove the reverted l1Origins * feat: add more comments --------- Co-authored-by: David <david@taiko.xyz> * only forward txs * chore: update ci --------- Co-authored-by: maskpp <maskpp266@gmail.com> Co-authored-by: Jeffery Walsh <cyberhorsey@gmail.com>
240 lines
8.1 KiB
Go
240 lines
8.1 KiB
Go
package taiko_test
|
|
|
|
import (
|
|
"bytes"
|
|
"math/big"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/consensus"
|
|
"github.com/ethereum/go-ethereum/consensus/taiko"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/eth"
|
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
"github.com/ethereum/go-ethereum/node"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"github.com/ethereum/go-ethereum/triedb"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var (
|
|
testL2RollupAddress = common.HexToAddress("0x79fcdef22feed20eddacbb2587640e45491b757f")
|
|
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
goldenTouchKey, _ = crypto.HexToECDSA("92954368afd3caa1f3ce3ead0069c1af414054aefe1ef9aeacc1bf426222ce38")
|
|
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
|
|
|
|
genesis *core.Genesis
|
|
txs []*types.Transaction
|
|
testEngine *taiko.Taiko
|
|
)
|
|
|
|
func init() {
|
|
config := params.TestChainConfig
|
|
config.GrayGlacierBlock = nil
|
|
config.ArrowGlacierBlock = nil
|
|
config.Ethash = nil
|
|
config.Taiko = true
|
|
testEngine = taiko.New(config, rawdb.NewMemoryDatabase())
|
|
|
|
taikoL2AddressPrefix := strings.TrimPrefix(config.ChainID.String(), "0")
|
|
|
|
taikoL2Address := common.HexToAddress(
|
|
"0x" +
|
|
taikoL2AddressPrefix +
|
|
strings.Repeat("0", common.AddressLength*2-len(taikoL2AddressPrefix)-len(taiko.TaikoL2AddressSuffix)) +
|
|
taiko.TaikoL2AddressSuffix,
|
|
)
|
|
|
|
genesis = &core.Genesis{
|
|
Config: config,
|
|
Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(2e15)}},
|
|
ExtraData: []byte("test genesis"),
|
|
Timestamp: 9000,
|
|
Difficulty: common.Big0,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
}
|
|
|
|
txs = []*types.Transaction{
|
|
types.MustSignNewTx(goldenTouchKey, types.LatestSigner(genesis.Config), &types.DynamicFeeTx{
|
|
Nonce: 0,
|
|
GasTipCap: common.Big0,
|
|
GasFeeCap: new(big.Int).SetUint64(875_000_000),
|
|
Data: taiko.AnchorSelector,
|
|
Gas: taiko.AnchorGasLimit,
|
|
To: &taikoL2Address,
|
|
}),
|
|
types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
|
|
Nonce: 0,
|
|
Value: big.NewInt(12),
|
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
|
Gas: params.TxGas,
|
|
To: &common.Address{2},
|
|
}),
|
|
types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
|
|
Nonce: 1,
|
|
Value: big.NewInt(8),
|
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
|
Gas: params.TxGas,
|
|
To: &common.Address{2},
|
|
}),
|
|
// prepareBlockTx
|
|
types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
|
|
Nonce: 2,
|
|
Value: big.NewInt(8),
|
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
|
Gas: params.TxGas,
|
|
To: &testL2RollupAddress,
|
|
}),
|
|
}
|
|
}
|
|
|
|
func generateTestChain(t *testing.T) ([]*types.Block, *eth.Ethereum) {
|
|
generate := func(i int, g *core.BlockGen) {
|
|
g.OffsetTime(5)
|
|
|
|
g.SetExtra([]byte("test_taiko"))
|
|
g.SetDifficulty(common.Big0)
|
|
|
|
for i, tx := range txs {
|
|
if i == 0 {
|
|
if err := tx.MarkAsAnchor(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
g.AddTx(tx)
|
|
}
|
|
}
|
|
|
|
// Create node
|
|
n, err := node.New(&node.Config{
|
|
DataDir: t.TempDir(),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("can't create new node: %v", err)
|
|
}
|
|
|
|
// Create Ethereum Service
|
|
ethService, err := eth.New(n, ðconfig.Config{
|
|
Genesis: genesis,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("can't create new ethereum service: %v", err)
|
|
}
|
|
|
|
db := ethService.ChainDb()
|
|
|
|
gblock := genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
|
|
blocks, _ := core.GenerateChain(genesis.Config, gblock, testEngine, db, 1, generate)
|
|
blocks = append([]*types.Block{gblock}, blocks...)
|
|
|
|
// Insert L1Origins.
|
|
for _, block := range blocks {
|
|
rawdb.WriteL1Origin(db, block.Number(), &rawdb.L1Origin{
|
|
BlockID: block.Number(),
|
|
L1BlockHeight: block.Number(),
|
|
L1BlockHash: block.Hash(),
|
|
})
|
|
}
|
|
|
|
// Import the test chain.
|
|
if err := n.Start(); err != nil {
|
|
t.Fatalf("can't start test node: %v", err)
|
|
}
|
|
|
|
if _, err := ethService.BlockChain().InsertChain(blocks[1:]); err != nil {
|
|
t.Fatalf("can't import test blocks: %v", err)
|
|
}
|
|
|
|
if _, ok := ethService.Engine().(*taiko.Taiko); !ok {
|
|
t.Fatalf("not use taiko engine")
|
|
}
|
|
|
|
return blocks, ethService
|
|
}
|
|
|
|
func TestVerifyHeader(t *testing.T) {
|
|
// Generate test chain.
|
|
blocks, ethService := generateTestChain(t)
|
|
|
|
for _, b := range blocks {
|
|
err := testEngine.VerifyHeader(ethService.BlockChain(), b.Header())
|
|
assert.NoErrorf(t, err, "VerifyHeader error: %s", err)
|
|
}
|
|
|
|
err := testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
Number: common.Big1,
|
|
Time: uint64(time.Now().Unix()),
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
WithdrawalsHash: &types.EmptyWithdrawalsHash,
|
|
UncleHash: types.EmptyUncleHash,
|
|
})
|
|
assert.ErrorIs(t, err, consensus.ErrUnknownAncestor, "VerifyHeader should throw ErrUnknownAncestor when parentHash is unknown")
|
|
|
|
err = testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
ParentHash: blocks[len(blocks)-1].Hash(),
|
|
Number: common.Big0,
|
|
Time: uint64(time.Now().Unix()),
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
WithdrawalsHash: &types.EmptyWithdrawalsHash,
|
|
UncleHash: types.EmptyUncleHash,
|
|
})
|
|
assert.ErrorIs(t, err, consensus.ErrInvalidNumber, "VerifyHeader should throw ErrInvalidNumber when the block number is wrong")
|
|
|
|
err = testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
ParentHash: blocks[len(blocks)-1].Hash(),
|
|
Number: new(big.Int).SetInt64(int64(len(blocks))),
|
|
Time: uint64(time.Now().Unix()),
|
|
Extra: bytes.Repeat([]byte{1}, int(params.MaximumExtraDataSize+1)),
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
WithdrawalsHash: &types.EmptyWithdrawalsHash,
|
|
UncleHash: types.EmptyUncleHash,
|
|
})
|
|
assert.ErrorContains(t, err, "extra-data too long", "VerifyHeader should throw ErrExtraDataTooLong when the block has too much extra data")
|
|
|
|
err = testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
ParentHash: blocks[len(blocks)-1].Hash(),
|
|
Number: new(big.Int).SetInt64(int64(len(blocks))),
|
|
Time: uint64(time.Now().Unix()),
|
|
Difficulty: common.Big1,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
WithdrawalsHash: &types.EmptyWithdrawalsHash,
|
|
UncleHash: types.EmptyUncleHash,
|
|
})
|
|
assert.ErrorContains(t, err, "invalid difficulty", "VerifyHeader should throw ErrInvalidDifficulty when difficulty is not 0")
|
|
|
|
err = testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
ParentHash: blocks[len(blocks)-1].Hash(),
|
|
Number: new(big.Int).SetInt64(int64(len(blocks))),
|
|
Time: uint64(time.Now().Unix()),
|
|
GasLimit: params.MaxGasLimit + 1,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
WithdrawalsHash: &types.EmptyWithdrawalsHash,
|
|
UncleHash: types.EmptyUncleHash,
|
|
})
|
|
assert.ErrorContains(t, err, "invalid gasLimit", "VerifyHeader should throw ErrInvalidGasLimit when gasLimit is higher than the limit")
|
|
|
|
err = testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
ParentHash: blocks[len(blocks)-1].Hash(),
|
|
Number: new(big.Int).SetInt64(int64(len(blocks))),
|
|
Time: uint64(time.Now().Unix()),
|
|
GasLimit: params.MaxGasLimit,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
UncleHash: types.EmptyUncleHash,
|
|
})
|
|
assert.ErrorContains(t, err, "withdrawals hash missing", "VerifyHeader should throw ErrWithdrawalsHashMissing withdrawalshash is nil")
|
|
|
|
err = testEngine.VerifyHeader(ethService.BlockChain(), &types.Header{
|
|
ParentHash: blocks[len(blocks)-1].Hash(),
|
|
Number: new(big.Int).SetInt64(int64(len(blocks))),
|
|
Time: uint64(time.Now().Unix()),
|
|
GasLimit: params.MaxGasLimit,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
WithdrawalsHash: &types.EmptyWithdrawalsHash,
|
|
})
|
|
assert.ErrorContains(t, err, "uncles not empty", "VerifyHeader should throw ErrUnclesNotEmpty if uncles is not the empty hash")
|
|
}
|