erigon-pulse/ethdb/privateapi/engine_test.go
ledgerwatch 94f4ea805d
Fixing hive SideChain reorg test (#5620)
the root cause is that when `inMemoryExecution` lambda gets created in
the `eth/backend.go`, it captures the reference of
`backend.notifications`, and so the execution of side-forks actually
adds notifications to there, and it all gets sent out to tx pool (and
RPC daemon) at the end of the stage loop (regardless of whether there
was forkchoice update or not)

so we can create a separate notification, but then somehow flush it to
the "main" nofitications when the in-memory exec state is flushed

Co-authored-by: Alexey Sharp <alexeysharp@Alexeys-iMac.local>
Co-authored-by: Alex Sharp <alexsharp@Alexs-MacBook-Pro.local>
2022-10-05 05:42:38 +01:00

257 lines
8.4 KiB
Go

package privateapi
import (
"context"
"testing"
"github.com/ledgerwatch/erigon-lib/gointerfaces"
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon-lib/kv/memdb"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/turbo/engineapi"
"github.com/ledgerwatch/erigon/turbo/shards"
"github.com/ledgerwatch/erigon/turbo/stages/headerdownload"
"github.com/stretchr/testify/require"
)
// Hashes
var (
startingHeadHash = common.HexToHash("0x1")
payload1Hash = common.HexToHash("2afc6f4132be8d1fded51aa7f914fd831d2939a100f61322842ab41d7898255b")
payload2Hash = common.HexToHash("219bb787708f832e40b734ab925e67e33f91f2c2a2a01b8f5f5f6284410982a6")
payload3Hash = common.HexToHash("a2dd4fc599747c1ce2176a4abae13afbc7ccb4a240f8f4cf22252767bab52f12")
)
// Payloads
var (
mockPayload1 = &types2.ExecutionPayload{
ParentHash: gointerfaces.ConvertHashToH256(common.HexToHash("0x2")),
BlockHash: gointerfaces.ConvertHashToH256(payload1Hash),
ReceiptRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x3")),
StateRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x4")),
PrevRandao: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
LogsBloom: gointerfaces.ConvertBytesToH2048(make([]byte, 256)),
ExtraData: make([]byte, 0),
BaseFeePerGas: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
BlockNumber: 100,
GasLimit: 52,
GasUsed: 4,
Timestamp: 4,
Coinbase: gointerfaces.ConvertAddressToH160(common.HexToAddress("0x1")),
Transactions: make([][]byte, 0),
}
mockPayload2 = &types2.ExecutionPayload{
ParentHash: gointerfaces.ConvertHashToH256(payload1Hash),
BlockHash: gointerfaces.ConvertHashToH256(payload2Hash),
ReceiptRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x3")),
StateRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x4")),
PrevRandao: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
LogsBloom: gointerfaces.ConvertBytesToH2048(make([]byte, 256)),
ExtraData: make([]byte, 0),
BaseFeePerGas: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
BlockNumber: 101,
GasLimit: 52,
GasUsed: 4,
Timestamp: 4,
Coinbase: gointerfaces.ConvertAddressToH160(common.HexToAddress("0x1")),
Transactions: make([][]byte, 0),
}
mockPayload3 = &types2.ExecutionPayload{
ParentHash: gointerfaces.ConvertHashToH256(startingHeadHash),
BlockHash: gointerfaces.ConvertHashToH256(payload3Hash),
ReceiptRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x3")),
StateRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x4")),
PrevRandao: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
LogsBloom: gointerfaces.ConvertBytesToH2048(make([]byte, 256)),
ExtraData: make([]byte, 0),
BaseFeePerGas: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
BlockNumber: 51,
GasLimit: 52,
GasUsed: 4,
Timestamp: 4,
Coinbase: gointerfaces.ConvertAddressToH160(common.HexToAddress("0x1")),
Transactions: make([][]byte, 0),
}
)
func makeTestDb(ctx context.Context, db kv.RwDB) {
tx, _ := db.BeginRw(ctx)
rawdb.WriteHeadBlockHash(tx, startingHeadHash)
rawdb.WriteHeaderNumber(tx, startingHeadHash, 50)
_ = tx.Commit()
}
func TestMockDownloadRequest(t *testing.T) {
db := memdb.New()
ctx := context.Background()
require := require.New(t)
makeTestDb(ctx, db)
hd := headerdownload.NewHeaderDownload(0, 0, nil, nil)
hd.SetPOSSync(true)
events := shards.NewEvents()
backend := NewEthBackendServer(ctx, nil, db, events, nil, &params.ChainConfig{TerminalTotalDifficulty: common.Big1}, nil, hd, false)
var err error
var reply *remote.EnginePayloadStatus
done := make(chan bool)
go func() {
reply, err = backend.EngineNewPayloadV1(ctx, mockPayload1)
done <- true
}()
hd.BeaconRequestList.WaitForRequest(true, false)
hd.PayloadStatusCh <- engineapi.PayloadStatus{Status: remote.EngineStatus_SYNCING}
<-done
require.NoError(err)
require.Equal(reply.Status, remote.EngineStatus_SYNCING)
require.Nil(reply.LatestValidHash)
// If we get another request we don't need to process it with processDownloadCh and ignore it and return Syncing status
go func() {
reply, err = backend.EngineNewPayloadV1(ctx, mockPayload2)
done <- true
}()
<-done
// Same result as before
require.NoError(err)
require.Equal(reply.Status, remote.EngineStatus_SYNCING)
require.Nil(reply.LatestValidHash)
// However if we simulate that we finish reverse downloading the chain by updating the head, we just execute 1:1
tx, _ := db.BeginRw(ctx)
rawdb.WriteHeadBlockHash(tx, payload1Hash)
rawdb.WriteHeaderNumber(tx, payload1Hash, 100)
_ = tx.Commit()
// Now we try to sync the next payload again
go func() {
reply, err = backend.EngineNewPayloadV1(ctx, mockPayload2)
done <- true
}()
<-done
require.NoError(err)
require.Equal(reply.Status, remote.EngineStatus_SYNCING)
require.Nil(reply.LatestValidHash)
}
func TestMockValidExecution(t *testing.T) {
db := memdb.New()
ctx := context.Background()
require := require.New(t)
makeTestDb(ctx, db)
hd := headerdownload.NewHeaderDownload(0, 0, nil, nil)
hd.SetPOSSync(true)
events := shards.NewEvents()
backend := NewEthBackendServer(ctx, nil, db, events, nil, &params.ChainConfig{TerminalTotalDifficulty: common.Big1}, nil, hd, false)
var err error
var reply *remote.EnginePayloadStatus
done := make(chan bool)
go func() {
reply, err = backend.EngineNewPayloadV1(ctx, mockPayload3)
done <- true
}()
hd.BeaconRequestList.WaitForRequest(true, false)
hd.PayloadStatusCh <- engineapi.PayloadStatus{
Status: remote.EngineStatus_VALID,
LatestValidHash: payload3Hash,
}
<-done
require.NoError(err)
require.Equal(reply.Status, remote.EngineStatus_VALID)
replyHash := gointerfaces.ConvertH256ToHash(reply.LatestValidHash)
require.Equal(replyHash[:], payload3Hash[:])
}
func TestMockInvalidExecution(t *testing.T) {
db := memdb.New()
ctx := context.Background()
require := require.New(t)
makeTestDb(ctx, db)
hd := headerdownload.NewHeaderDownload(0, 0, nil, nil)
hd.SetPOSSync(true)
events := shards.NewEvents()
backend := NewEthBackendServer(ctx, nil, db, events, nil, &params.ChainConfig{TerminalTotalDifficulty: common.Big1}, nil, hd, false)
var err error
var reply *remote.EnginePayloadStatus
done := make(chan bool)
go func() {
reply, err = backend.EngineNewPayloadV1(ctx, mockPayload3)
done <- true
}()
hd.BeaconRequestList.WaitForRequest(true, false)
// Simulate invalid status
hd.PayloadStatusCh <- engineapi.PayloadStatus{
Status: remote.EngineStatus_INVALID,
LatestValidHash: startingHeadHash,
}
<-done
require.NoError(err)
require.Equal(reply.Status, remote.EngineStatus_INVALID)
replyHash := gointerfaces.ConvertH256ToHash(reply.LatestValidHash)
require.Equal(replyHash[:], startingHeadHash[:])
}
func TestNoTTD(t *testing.T) {
db := memdb.New()
ctx := context.Background()
require := require.New(t)
makeTestDb(ctx, db)
hd := headerdownload.NewHeaderDownload(0, 0, nil, nil)
events := shards.NewEvents()
backend := NewEthBackendServer(ctx, nil, db, events, nil, &params.ChainConfig{}, nil, hd, false)
var err error
done := make(chan bool)
go func() {
_, err = backend.EngineNewPayloadV1(ctx, &types2.ExecutionPayload{
ParentHash: gointerfaces.ConvertHashToH256(common.HexToHash("0x2")),
BlockHash: gointerfaces.ConvertHashToH256(common.HexToHash("0xe6a580606b065e08034dcd6eea026cfdcbd3b41918d98b41cb9bf797d0c27033")),
ReceiptRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x4")),
StateRoot: gointerfaces.ConvertHashToH256(common.HexToHash("0x4")),
PrevRandao: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
LogsBloom: gointerfaces.ConvertBytesToH2048(make([]byte, 256)),
ExtraData: make([]byte, 0),
BaseFeePerGas: gointerfaces.ConvertHashToH256(common.HexToHash("0x0b3")),
BlockNumber: 51,
GasLimit: 52,
GasUsed: 4,
Timestamp: 4,
Coinbase: gointerfaces.ConvertAddressToH160(common.HexToAddress("0x1")),
Transactions: make([][]byte, 0),
})
done <- true
}()
<-done
require.Equal(err.Error(), "not a proof-of-stake chain")
}