Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/qa-rpc-integration-tests-gnosis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:

jobs:
gnosis-rpc-integ-tests:
if: false # Temporarily disabled
if: false # Temporarily disabled
concurrency:
group: >-
${{
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/qa-rpc-integration-tests-polygon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:

jobs:
bor-mainnet-rpc-integ-tests:
if: false # Temporarily disabled
if: false # Temporarily disabled
concurrency:
group: >-
${{
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/qa-rpc-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:

jobs:
mainnet-rpc-integ-tests:
if: false # Temporarily disabled
if: false # Temporarily disabled
concurrency:
group: >-
${{
Expand Down
109 changes: 7 additions & 102 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,117 +201,22 @@ jobs:
compression-level: 0
if-no-files-found: error

test-release:
name: test on ${{ matrix.id }}
if: ${{ ! inputs.skip_tests }}
runs-on: [ self-hosted, qa, Release, "${{ matrix.runner-arch }}" ]
timeout-minutes: 2800 # 2 days
needs: [ build-release ]
strategy:
matrix:
include:
- id: linux/amd64
runner-arch: X64
artifact: linux_amd64
- id: linux/arm64
runner-arch: ARM64
artifact: linux_arm64

steps:

- name: Cleanup working directory
run: rm -drfv *

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'

- name: Download artifact ${{ env.APPLICATION }}_${{ inputs.release_version }}_${{ matrix.artifact }}.tar
uses: actions/download-artifact@v5
with:
name: ${{ env.APPLICATION }}_${{ inputs.release_version }}_${{ matrix.artifact }}.tar
path: .

- name: Extract artifact ${{ env.APPLICATION }}_${{ inputs.release_version }}_${{ matrix.artifact }}.tar
env:
RELEASE_VERSION: ${{ inputs.release_version }}
run: |
pwd
ls -l ${{ env.APPLICATION }}_${RELEASE_VERSION}_${{ matrix.artifact }}.tar
tar xvf ${{ env.APPLICATION }}_${RELEASE_VERSION}_${{ matrix.artifact }}.tar
ls -lR
- name: Fast checkout git repository erigontech/erigon-qa
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 ## 5.0.0
with:
token: ${{ secrets.ORG_GITHUB_ERIGONTECH_ERIGON_QA_READ }}
repository: erigontech/erigon-qa
fetch-depth: 1
ref: main
path: erigon-qa

- name: Run QA Tests
env:
RELEASE_VERSION: ${{ inputs.release_version }}
run: |
cd ./erigon-qa/test_system
pwd
ls -lao
pip3 install -r requirements.txt
ln -s $(pwd)/base_library $(pwd)/qa-tests/tip-tracking/base_library
echo "DEBUG -- content of directory $(pwd) :"
ls -l
echo "DEBUG -- content of directory $(pwd)/qa-tests/tip-tracking/"
ls -l $(pwd)/qa-tests/tip-tracking/
echo "DEBUG -- content of directory GITHUB_WORKSPACE ${GITHUB_WORKSPACE} :"
ls -l ${GITHUB_WORKSPACE}
echo "DEBUG -- end."
rm -rf ${RUNNER_WORKSPACE}/erigon-data || true
mkdir ${RUNNER_WORKSPACE}/erigon-data
# Run Erigon, wait sync and check ability to maintain sync
python3 qa-tests/tip-tracking/run_and_check_tip_tracking.py \
${GITHUB_WORKSPACE}/${{ env.APPLICATION }}_${RELEASE_VERSION}_${{ matrix.artifact }} \
${RUNNER_WORKSPACE}/erigon-data ${{ env.TEST_TRACKING_TIME_SECONDS }} ${{ env.TEST_TOTAL_TIME_SECONDS }} ${{ env.APPLICATION_VERSION }} ${{ env.TEST_CHAIN }}
# Capture monitoring script exit status
test_exit_status=$?
# Save the subsection reached status
echo "test_executed=true" >> "$GITHUB_OUTPUT"
# Check test runner script exit status
if [ $test_exit_status -eq 0 ]; then
echo "Tests completed successfully"
echo "TEST_RESULT=success" >> "$GITHUB_OUTPUT"
else
echo "Error detected during tests"
echo "TEST_RESULT=failure" >> "$GITHUB_OUTPUT"
fi
- name: Upload Downloader Torrent Client Status
if: always()
uses: actions/upload-artifact@v4
with:
name: torrent-client-status-${{ matrix.artifact }}
path: torrent-client-status.txt

- name: Cleanup working directory
run: rm -drfv *

build-debian-pkg:
name: Debian packages
needs: [ build-release, test-release ]
if: always() && contains(needs.build-release.result, 'success') && !contains(needs.test-release.result, 'failure')
needs: [ build-release ]
if: always() && contains(needs.build-release.result, 'success')
uses: ./.github/workflows/reusable-release-build-debian-pkg.yml
with:
application: ${{ needs.build-release.outputs.application }}
version: ${{ needs.build-release.outputs.parsed-version }}


publish-docker-image:
needs: [ build-release, test-release ]
if: always() && contains(needs.build-release.result, 'success') && !contains(needs.test-release.result, 'failure')
needs: [ build-release ]
if: always() && contains(needs.build-release.result, 'success')
runs-on: ubuntu-latest
timeout-minutes: 30
name: Docker image
name: Docker image

steps:

Expand Down Expand Up @@ -422,8 +327,8 @@ jobs:
In-case-of-failure:
name: "In case of failure: remove remote git tag pointing to the new version."
needs: [ publish-release, build-release, test-release, build-debian-pkg, publish-docker-image ]
if: always() && !contains(needs.build-release.result, 'success') && contains(needs.test-release.result, 'failure') && !contains(needs.publish-release.result, 'success') && !contains(needs.build-debian-pkg.result, 'success') && !contains(needs.publish-docker-image.result, 'success')
needs: [ publish-release, build-release, build-debian-pkg, publish-docker-image ]
if: always() && !contains(needs.build-release.result, 'success') && !contains(needs.publish-release.result, 'success') && !contains(needs.build-debian-pkg.result, 'success') && !contains(needs.publish-docker-image.result, 'success')
runs-on: ubuntu-latest
env:
RELEASE_VERSION: ${{ inputs.release_version }}
Expand Down
1 change: 1 addition & 0 deletions cmd/integration/commands/stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,7 @@ func newSync(ctx context.Context, db kv.TemporalRwDB, miningConfig *buildercfg.M
maxBlockBroadcastPeers,
false, /* disableBlockDownload */
false, /* enableWitProtocol */
nil, /* bridgeReader */
logger,
)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ func ExecuteBlockEphemerally(
logs = append(logs, receipt.Logs...)
}

// PIP-74 state-sync receipt handling.
stateSyncReceipt := &types.Receipt{}
if chainConfig.Consensus == chain.BorConsensus && len(blockLogs) > 0 {
slices.SortStableFunc(blockLogs, func(i, j *types.Log) int { return cmp.Compare(i.Index, j.Index) })
Expand Down
9 changes: 9 additions & 0 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,14 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
}
}

// Create bridge.Reader for P2P state sync receipts.
// When Erigon nodes serve receipts to peers via P2P, they need bridge.Reader
// to include state sync transaction receipts in the response.
var bridgeReaderForP2P *bridge.Reader
if bridgeStore != nil && chainConfig.Bor != nil {
bridgeReaderForP2P = bridge.NewReader(bridgeStore, logger, chainConfig.Bor.StateReceiverContractAddress())
}

sentryMcDisableBlockDownload := chainConfig.Bor != nil || config.ElBlockDownloaderV2
backend.sentriesClient, err = sentry_multi_client.NewMultiClient(
backend.chainDB,
Expand All @@ -731,6 +739,7 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
maxBlockBroadcastPeers,
sentryMcDisableBlockDownload,
stack.Config().P2P.EnableWitProtocol,
bridgeReaderForP2P,
logger,
)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion execution/stages/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ func testReorgLong(t *testing.T) {

// Tests that reorganising a short difficult chain after a long easy one
// overwrites the canonical numbers and links in the database.
func TestReorgShortBlocks(t *testing.T) { testReorgShort(t) }
func TestReorgShortBlocks(t *testing.T) {
testReorgShort(t)
}

func testReorgShort(t *testing.T) {
t.Parallel()
Expand Down
3 changes: 2 additions & 1 deletion execution/stages/mock/mock_sentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK
PeerId: gointerfaces.ConvertHashToH512([64]byte{0x12, 0x34, 0x50}), // "12345"
BlockSnapshots: allSnapshots,
BlockReader: br,
ReceiptsReader: receipts.NewGenerator(br, engine, 5*time.Second),
ReceiptsReader: receipts.NewGenerator(br, engine, 5*time.Second, nil),
HistoryV3: true,
cfg: cfg,
}
Expand Down Expand Up @@ -442,6 +442,7 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK
maxBlockBroadcastPeers,
false, /* disableBlockDownload */
false, /* enableWitProtocol */
nil, /* bridgeReader */
logger,
)
if err != nil {
Expand Down
23 changes: 22 additions & 1 deletion execution/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,9 +580,30 @@ func (e receiptEncoder69) EncodeRLP(w io.Writer) error { return e.r.EncodeRLP69(

func (rs Receipts) EncodeRLP69(w io.Writer) error {
encs := make([]receiptEncoder69, len(rs))
n := len(rs)

for i := range rs {
encs[i] = receiptEncoder69{r: rs[i]}
// Copy the receipt reference.
r := rs[i]

// Only the last receipt can be a state-sync tx.
if i == n-1 {
// Post-Madhugiri, the state-sync transaction is a typed tx (StateSyncTxType)
// and must keep its type for eth/69 encoding. Only apply the pre-HF heuristic
// when the receipt is not already the typed state-sync receipt.
if r.Type != StateSyncTxType {
// Match the ReadStateSyncReceiptByHash logic for pre-HF:
// It's a state-sync transaction if the cumulative gas is zero, or
// the cumulative gas is equal to the previous one (zero gas usage)
if r.CumulativeGasUsed == 0 || (n >= 2 && r.CumulativeGasUsed == rs[n-2].CumulativeGasUsed) {
r.Type = LegacyTxType
}
}
}

encs[i] = receiptEncoder69{r: r}
}

return rlp.Encode(w, encs)
}

Expand Down
2 changes: 1 addition & 1 deletion node/nodecfg/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var DefaultConfig = Config{
WSModules: []string{"net", "web3"},
P2P: p2p.Config{
ListenAddr: ":30303",
ProtocolVersion: []uint{direct.ETH68, direct.ETH69}, // Keep eth/68 in first index for Hive tests
ProtocolVersion: []uint{direct.ETH69, direct.ETH68},
MaxPeers: 32,
MaxPendingPeers: 1000,
NAT: nat.Any(),
Expand Down
1 change: 1 addition & 0 deletions p2p/protocols/eth/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ type StatusPacket struct {
type StatusPacket69 struct {
ProtocolVersion uint32
NetworkID uint64
TD *big.Int
Genesis common.Hash
ForkID forkid.ID
MinimumBlock, LatestBlock uint64
Expand Down
2 changes: 2 additions & 0 deletions p2p/sentry/eth_handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,12 @@ func encodeStatusPacket(status *sentryproto.StatusData, version uint) eth.Status
}

func encodeStatusPacket69(status *sentryproto.StatusData, version uint) eth.StatusPacket69 {
ourTD := gointerfaces.ConvertH256ToUint256Int(status.TotalDifficulty)
genesisHash := gointerfaces.ConvertH256ToHash(status.ForkData.Genesis)
return eth.StatusPacket69{
ProtocolVersion: uint32(version),
NetworkID: status.NetworkId,
TD: ourTD.ToBig(),
Genesis: genesisHash,
ForkID: forkid.NewIDFromForks(status.ForkData.HeightForks, status.ForkData.TimeForks, genesisHash, status.MaxBlockHeight, status.MaxBlockTime),
MinimumBlock: status.MinimumBlockHeight,
Expand Down
16 changes: 15 additions & 1 deletion p2p/sentry/sentry_multi_client/sentry_multi_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,12 @@ type MultiClient struct {

var _ eth.ReceiptsGetter = new(receipts.Generator) // compile-time interface-check

// bridgeReader interface for reading bridge events (state sync).
type bridgeReader interface {
Events(ctx context.Context, blockHash common.Hash, blockNum uint64) ([]*types.Message, error)
EventTxnLookup(ctx context.Context, borTxHash common.Hash) (uint64, bool, error)
}

func NewMultiClient(
db kv.TemporalRoDB,
chainConfig *chain.Config,
Expand All @@ -307,6 +313,7 @@ func NewMultiClient(
maxBlockBroadcastPeers func(*types.Header) uint,
disableBlockDownload bool,
enableWitProtocol bool,
bridgeReader bridgeReader,
logger log.Logger,
) (*MultiClient, error) {
// header downloader
Expand Down Expand Up @@ -348,6 +355,13 @@ func NewMultiClient(
witnessBuffer = stagedsync.NewWitnessBuffer()
}

// Create BorGenerator for state sync receipts if bridgeReader is provided.
// This is required for Erigon to include state sync transaction receipts in P2P GetReceipts responses.
var borGenerator *receipts.BorGenerator
if bridgeReader != nil {
borGenerator = receipts.NewBorGenerator(blockReader, engine, bridgeReader)
}

cs := &MultiClient{
Hd: hd,
Bd: bd,
Expand All @@ -364,7 +378,7 @@ func NewMultiClient(
disableBlockDownload: disableBlockDownload,
logger: logger,
getReceiptsActiveGoroutineNumber: semaphore.NewWeighted(1),
ethApiWrapper: receipts.NewGenerator(blockReader, engine, 5*time.Minute),
ethApiWrapper: receipts.NewGenerator(blockReader, engine, 5*time.Minute, borGenerator),
}

return cs, nil
Expand Down
6 changes: 4 additions & 2 deletions rpc/jsonrpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ func NewBaseApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader serv
panic(err)
}

borReceiptGenerator := receipts.NewBorGenerator(blockReader, engine, bridgeReader)

return &BaseAPI{
filters: f,
stateCache: stateCache,
Expand All @@ -166,8 +168,8 @@ func NewBaseApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader serv
_txNumReader: blockReader.TxnumReader(context.Background()),
evmCallTimeout: evmCallTimeout,
_engine: engine,
receiptsGenerator: receipts.NewGenerator(blockReader, engine, evmCallTimeout),
borReceiptGenerator: receipts.NewBorGenerator(blockReader, engine),
receiptsGenerator: receipts.NewGenerator(blockReader, engine, evmCallTimeout, borReceiptGenerator),
borReceiptGenerator: borReceiptGenerator,
dirs: dirs,
bridgeReader: bridgeReader,
}
Expand Down
23 changes: 15 additions & 8 deletions rpc/jsonrpc/eth_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,18 +553,25 @@ func (api *APIImpl) GetBlockReceipts(ctx context.Context, numberOrHash rpc.Block
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
result := make([]map[string]interface{}, 0, len(receipts))
for _, receipt := range receipts {
txn := block.Transactions()[receipt.TransactionIndex]
result = append(result, ethutils.MarshalReceipt(receipt, txn, chainConfig, block.HeaderNoCopy(), txn.Hash(), true, true))
}

if chainConfig.Bor == nil {
return result, nil
numReceipts := len(receipts)
numTxs := len(block.Transactions())
result := make([]map[string]interface{}, 0, numReceipts)

for _, receipt := range receipts {
// State-sync receipts' TransactionIndex is equal to numTxs.
if int(receipt.TransactionIndex) == numTxs {
// This is a state-sync transaction receipt.
result = append(result, ethutils.MarshalReceipt(receipt, bortypes.NewBorTransaction(), chainConfig, block.HeaderNoCopy(), receipt.TxHash, false, true))
} else {
// This is a normal transaction receipt.
txn := block.Transactions()[receipt.TransactionIndex]
result = append(result, ethutils.MarshalReceipt(receipt, txn, chainConfig, block.HeaderNoCopy(), txn.Hash(), true, true))
}
}

var borTx types.Transaction = bortypes.NewBorTransaction()
if chainConfig.Bor.IsMadhugiri(blockNum) && len(receipts)+1 == len(block.Transactions()) {
if chainConfig.Bor != nil && chainConfig.Bor.IsMadhugiri(blockNum) && len(receipts)+1 == len(block.Transactions()) {
borTx = block.Transactions()[len(block.Transactions())-1]
if borTx.Type() != types.StateSyncTxType {
return result, nil
Expand Down
Loading
Loading