mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-03 09:37:38 +00:00
94f4ea805d
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>
257 lines
8.4 KiB
Go
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, ¶ms.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, ¶ms.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, ¶ms.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, ¶ms.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")
|
|
}
|