mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Merge pull request #1405 from maticnetwork/develop
Port changes from develop to upstream_merge
This commit is contained in:
commit
190112023b
883 changed files with 65676 additions and 31395 deletions
2
.github/ISSUE_TEMPLATE/bug.md
vendored
2
.github/ISSUE_TEMPLATE/bug.md
vendored
|
|
@ -6,7 +6,7 @@ labels: 'type:bug'
|
||||||
assignees: ''
|
assignees: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
Our support team has aggregated some common issues and their solutions from past which are faced while running or interacting with a bor client. In order to prevent redundant efforts, we would encourage you to have a look at the [FAQ's section](https://wiki.polygon.technology/docs/faq/technical-faqs/) of our documentation mentioning the same, before filing an issue here. In case of additional support, you can also join our [discord](https://discord.com/invite/0xPolygonDevs) server
|
Our support team has aggregated some common issues and their solutions from past which are faced while running or interacting with a bor client. In order to prevent redundant efforts, we would encourage you to have a look at the [FAQ's section](https://wiki.polygon.technology/docs/faq/technical-faqs/) of our documentation mentioning the same, before filing an issue here. In case of additional support, you can also join our [discord](https://discord.com/invite/0xPolygonCommunity) server
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
NOTE: Please make sure to check of any addresses / private keys / rpc url's / IP's before sharing the logs or anything from the additional information section (start.sh or heimdall config).
|
NOTE: Please make sure to check of any addresses / private keys / rpc url's / IP's before sharing the logs or anything from the additional information section (start.sh or heimdall config).
|
||||||
|
|
|
||||||
2
.github/ISSUE_TEMPLATE/question.md
vendored
2
.github/ISSUE_TEMPLATE/question.md
vendored
|
|
@ -8,4 +8,4 @@ assignees: ''
|
||||||
|
|
||||||
This should only be used in very rare cases e.g. if you are not 100% sure if something is a bug or asking a question that leads to improving the documentation.
|
This should only be used in very rare cases e.g. if you are not 100% sure if something is a bug or asking a question that leads to improving the documentation.
|
||||||
|
|
||||||
For general questions please join our [discord](https://discord.com/invite/0xPolygonDevs) server.
|
For general questions please join our [discord](https://discord.com/invite/0xPolygonCommunity) server.
|
||||||
|
|
|
||||||
404
.github/workflows/amoy_deb_profiles.yml
vendored
Normal file
404
.github/workflows/amoy_deb_profiles.yml
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
name: amoy_deb_profiles
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# Variables
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
- name: adding version
|
||||||
|
run: |
|
||||||
|
NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' )
|
||||||
|
echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
|
- name: Making directory structure for yaml
|
||||||
|
run: mkdir -p packaging/deb/bor/var/lib/bor
|
||||||
|
- name: making directory structure for the systemd
|
||||||
|
run: mkdir -p packaging/deb/bor/lib/systemd/system
|
||||||
|
- name: Delete control file
|
||||||
|
run: rm -rf packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
# Control file creation
|
||||||
|
- name: create control file
|
||||||
|
run: |
|
||||||
|
touch packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Package: bor-profile" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Version: ${{ env.VERSION }}" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Section: base" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Priority: optional" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Architecture: all" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Maintainer: devops@polygon.technology" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Description: bor profile package" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
# Bootnode Profile
|
||||||
|
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} bootnode for ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/testnet-amoy/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/bor.service
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
# Sentry Profile
|
||||||
|
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} node for ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/testnet-amoy/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
# PBSS Sentry
|
||||||
|
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} node for ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/testnet-amoy/sentry/sentry/bor/pbss_config.toml packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/config.toml
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
# Validator Profile
|
||||||
|
- name: Prepping Bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying Postinstall script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying Prerm script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying Postrm script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying config.toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/testnet-amoy/sentry/validator/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
# PBSS Validator
|
||||||
|
- name: Prepping Bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying Postinstall script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying Prerm script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying Postrm script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying config.toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/testnet-amoy/sentry/validator/bor/pbss_config.toml packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/config.toml
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
# Archive Profile
|
||||||
|
- name: Creating bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying profile preinst file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the profile postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying profile prerm file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying profile postrm file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying the toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/testnet-amoy/archive/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
# Shasum
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: shasum the bor pbss debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: shasum the bor-${{ env.ARCH }} debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: shasum the bor pbss debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: amoy
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: amoy
|
||||||
|
|
||||||
|
############ Check and Upload ##########################
|
||||||
|
- name: Confirming package built
|
||||||
|
run: ls -ltr packaging/deb/ | grep bor
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/deb/bor-amoy-**.deb
|
||||||
|
packaging/deb/bor-pbss-amoy-**.deb
|
||||||
|
packaging/deb/bor-amoy-**.deb.checksum
|
||||||
|
packaging/deb/bor-pbss-amoy-**.deb.checksum
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: |
|
- run: |
|
||||||
git submodule update --init --recursive --force
|
git submodule update --init --recursive --force
|
||||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||||
|
|
@ -54,7 +54,7 @@ jobs:
|
||||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: |
|
- run: |
|
||||||
git submodule update --init --recursive --force
|
git submodule update --init --recursive --force
|
||||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||||
|
|
@ -82,7 +82,7 @@ jobs:
|
||||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: |
|
- run: |
|
||||||
git submodule update --init --recursive --force
|
git submodule update --init --recursive --force
|
||||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||||
|
|
@ -107,7 +107,7 @@ jobs:
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v4.4.0
|
||||||
with:
|
with:
|
||||||
name: unitTest-coverage
|
name: unitTest-coverage
|
||||||
path: cover.out
|
path: cover.out
|
||||||
|
|
@ -133,7 +133,7 @@ jobs:
|
||||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: |
|
- run: |
|
||||||
git submodule update --init --recursive --force
|
git submodule update --init --recursive --force
|
||||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||||
|
|
@ -146,7 +146,7 @@ jobs:
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: sudo apt update && sudo apt install build-essential
|
run: sudo apt update && sudo apt install build-essential
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
|
|
@ -158,7 +158,7 @@ jobs:
|
||||||
- name: test-integration
|
- name: test-integration
|
||||||
run: make test-integration
|
run: make test-integration
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v4.4.0
|
||||||
with:
|
with:
|
||||||
name: integrationTest-coverage
|
name: integrationTest-coverage
|
||||||
path: cover.out
|
path: cover.out
|
||||||
|
|
@ -172,9 +172,9 @@ jobs:
|
||||||
needs: [unit-tests, integration-tests]
|
needs: [unit-tests, integration-tests]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4.1.8
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ jobs:
|
||||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: bor
|
path: bor
|
||||||
- name: Checkout submodules
|
- name: Checkout submodules
|
||||||
|
|
@ -199,7 +199,7 @@ jobs:
|
||||||
go-version: 1.22.x
|
go-version: 1.22.x
|
||||||
|
|
||||||
- name: Checkout matic-cli
|
- name: Checkout matic-cli
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: maticnetwork/matic-cli
|
repository: maticnetwork/matic-cli
|
||||||
ref: master
|
ref: master
|
||||||
|
|
@ -258,7 +258,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload logs
|
- name: Upload logs
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4.4.0
|
||||||
with:
|
with:
|
||||||
name: logs_${{ github.run_id }}
|
name: logs_${{ github.run_id }}
|
||||||
path: |
|
path: |
|
||||||
|
|
@ -277,7 +277,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload code and chain data
|
- name: Upload code and chain data
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4.4.0
|
||||||
with:
|
with:
|
||||||
name: code_${{ github.run_id }}
|
name: code_${{ github.run_id }}
|
||||||
path: code.tar.gz
|
path: code.tar.gz
|
||||||
|
|
|
||||||
23
.github/workflows/go.yml
vendored
23
.github/workflows/go.yml
vendored
|
|
@ -1,23 +0,0 @@
|
||||||
name: i386 linux tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.21.4
|
|
||||||
- name: Run tests
|
|
||||||
run: go test ./...
|
|
||||||
env:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: 386
|
|
||||||
2
.github/workflows/govuln.yml
vendored
2
.github/workflows/govuln.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
fail-on-vuln: true
|
fail-on-vuln: true
|
||||||
|
|
||||||
- name: Upload govulncheck report
|
- name: Upload govulncheck report
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4.4.0
|
||||||
with:
|
with:
|
||||||
name: raw-report
|
name: raw-report
|
||||||
path: raw-report.json
|
path: raw-report.json
|
||||||
|
|
|
||||||
405
.github/workflows/mainnet_deb_profiles.yml
vendored
Normal file
405
.github/workflows/mainnet_deb_profiles.yml
vendored
Normal file
|
|
@ -0,0 +1,405 @@
|
||||||
|
name: mainnet_deb_profiles
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# Variables
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
- name: adding version
|
||||||
|
run: |
|
||||||
|
NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' )
|
||||||
|
echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
|
- name: Making directory structure for yaml
|
||||||
|
run: mkdir -p packaging/deb/bor/var/lib/bor
|
||||||
|
- name: making directory structure for the systemd
|
||||||
|
run: mkdir -p packaging/deb/bor/lib/systemd/system
|
||||||
|
- name: Delete control file
|
||||||
|
run: rm -rf packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
# Control file creation
|
||||||
|
- name: create control file
|
||||||
|
run: |
|
||||||
|
touch packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Package: bor-profile" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Version: ${{ env.VERSION }}" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Section: base" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Priority: optional" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Architecture: all" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Maintainer: devops@polygon.technology" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Description: bor profile package" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
# Bootnode Profile
|
||||||
|
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} bootnode for ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/bor.service
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
# Sentry Profile
|
||||||
|
- name: Setting up ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Building ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
# PBSS Sentry
|
||||||
|
- name: Setting up ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/mainnet-v1/sentry/sentry/bor/pbss_config.toml packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/config.toml
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Building ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
# Validator Profile
|
||||||
|
- name: Prepping Bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying Postinstall script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying config.toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/mainnet-v1/sentry/validator/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
# PBSS Validator
|
||||||
|
- name: Prepping Bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying Postinstall script for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying config.toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/mainnet-v1/sentry/validator/bor/pbss_config.toml packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/config.toml
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
# Archive Profile
|
||||||
|
- name: Creating bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying profile preinst file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the profile postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying profile prerm file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying profile postrm file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Copying the toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/templates/mainnet-v1/archive/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
# Shasum
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: bootnode
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: shasum the bor pbss debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: sentry
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: shasum the bor-${{ env.ARCH }} debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: shasum the bor pbss debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-pbss-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: validator
|
||||||
|
NETWORK: mainnet
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: all
|
||||||
|
NODE: archive
|
||||||
|
NETWORK: mainnet
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############ Check and Upload ##########################
|
||||||
|
- name: Confirming package built
|
||||||
|
run: ls -ltr packaging/deb/ | grep bor
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/deb/bor-mainnet-**.deb
|
||||||
|
packaging/deb/bor-pbss-mainnet-**.deb
|
||||||
|
packaging/deb/bor-mainnet-**.deb.checksum
|
||||||
|
packaging/deb/bor-pbss-mainnet-**.deb.checksum
|
||||||
1372
.github/workflows/packager.yml
vendored
1372
.github/workflows/packager.yml
vendored
File diff suppressed because it is too large
Load diff
129
.github/workflows/packager_deb.yml
vendored
Normal file
129
.github/workflows/packager_deb.yml
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
name: packager_deb
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@master
|
||||||
|
with:
|
||||||
|
go-version: 1.22.1
|
||||||
|
# Variables
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
- name: adding version
|
||||||
|
run: |
|
||||||
|
NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' )
|
||||||
|
echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Cleaning repo
|
||||||
|
run: make clean
|
||||||
|
- name: Building for amd64
|
||||||
|
run: make bor
|
||||||
|
|
||||||
|
- name: Making directory structure
|
||||||
|
run: mkdir -p packaging/deb/bor/usr/bin
|
||||||
|
- name: Copying necessary files
|
||||||
|
run: cp -rp build/bin/bor packaging/deb/bor/usr/bin/
|
||||||
|
- name: Delete control file
|
||||||
|
run: rm -rf packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
# Control file creation
|
||||||
|
- name: create control file
|
||||||
|
run: |
|
||||||
|
touch packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Package: bor" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Version: ${{ env.VERSION }}" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Section: base" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Priority: optional" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Architecture: amd64" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Maintainer: devops@polygon.technology" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Description: bor binary package" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
- name: Creating package for binary for bor ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: amd64
|
||||||
|
|
||||||
|
- name: Running package build
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: amd64
|
||||||
|
|
||||||
|
- name: Cleaning build directory for arm64 build
|
||||||
|
run: make clean
|
||||||
|
|
||||||
|
- name: Updating the apt-get
|
||||||
|
run: sudo apt-get update -y
|
||||||
|
|
||||||
|
- name: Adding requirements for cross compile
|
||||||
|
run: sudo apt-get install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
|
||||||
|
|
||||||
|
- name: delete amd64 control file
|
||||||
|
run: rm -rf packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
- name: Building bor for arm64
|
||||||
|
run: GOARCH=arm64 GOOS=linux CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ CGO_ENABLED=1 go build -o build/bin/bor ./cmd/cli/main.go
|
||||||
|
|
||||||
|
- name: Copying necessary binary post arm64 build
|
||||||
|
run: cp -rp build/bin/bor packaging/deb/bor/usr/bin/
|
||||||
|
|
||||||
|
# Control file for arm64 creation
|
||||||
|
- name: create control file
|
||||||
|
run: |
|
||||||
|
touch packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Package: bor" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Version: ${{ env.VERSION }}" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Section: base" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Priority: optional" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Architecture: arm64" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Maintainer: devops@polygon.technology" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
echo "Description: bor binary package" >> packaging/deb/bor/DEBIAN/control
|
||||||
|
|
||||||
|
|
||||||
|
- name: Creating package for binary for bor ${{ env.ARCH }}
|
||||||
|
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: arm64
|
||||||
|
|
||||||
|
- name: Running package build
|
||||||
|
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||||
|
env:
|
||||||
|
ARCH: arm64
|
||||||
|
|
||||||
|
# Shasum
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: amd64
|
||||||
|
|
||||||
|
- name: shasum the bor debian package
|
||||||
|
run: cd packaging/deb/ && sha256sum bor-${{ env.GIT_TAG }}-${{ env.ARCH }}.deb > bor-${{ env.GIT_TAG }}-${{ env.ARCH }}.deb.checksum
|
||||||
|
env:
|
||||||
|
ARCH: arm64
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/deb/bor**.deb
|
||||||
|
packaging/deb/bor**.deb.checksum
|
||||||
325
.github/workflows/rpm_amoy_profile_packager.yml
vendored
Normal file
325
.github/workflows/rpm_amoy_profile_packager.yml
vendored
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
name: rpm_amoy_profile
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Adding a TAG1 to the env
|
||||||
|
run: echo "GIT_TAG1=`echo $(git describe --tags --abbrev=0)`" | sed 's/-/./g' >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Installing some dependencies
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y rpm
|
||||||
|
|
||||||
|
- name: Setup rpm package directories
|
||||||
|
run: |
|
||||||
|
mkdir -p packaging/rpm/SPECS
|
||||||
|
mkdir -p packaging/rpm/BUILD
|
||||||
|
mkdir -p packaging/rpm/RPMS
|
||||||
|
mkdir -p packaging/rpm/SRPMS
|
||||||
|
|
||||||
|
- name: Start tasks needed for Amoy Sentry node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Amoy Sentry Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-amoy-sentry.spec
|
||||||
|
echo "Name: bor-amoy-sentry-config" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "Summary: bor amoy sentry config rpm package" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "Bor Amoy Sentry rpm package" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/testnet-amoy/sentry/sentry/bor/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
|
||||||
|
- name: Build Amoy Sentry Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-amoy-sentry.spec
|
||||||
|
|
||||||
|
- name: Start tasks needed for Amoy Sentry PBSS node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Amoy Sentry PBSS Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "Name: bor-pbss-amoy-sentry-config" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "Summary: bor amoy sentry config rpm package" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "Bor Amoy Sentry rpm package" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/testnet-amoy/sentry/sentry/bor/pbss_config.toml %{buildroot}/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
|
||||||
|
- name: Build Amoy Sentry PBSS Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-pbss-amoy-sentry.spec
|
||||||
|
|
||||||
|
- name: Setting up Amoy Validator Node node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Amoy Validator Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-amoy-validator.spec
|
||||||
|
echo "Name: bor-amoy-validator-config" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "Summary: bor amoy validator config rpm package" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "Bor Amoy Validator rpm package" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/testnet-amoy/sentry/validator/bor/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build Amoy Validator Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-amoy-validator.spec
|
||||||
|
|
||||||
|
- name: Setting up Amoy Validator PBSS Node node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Amoy Validator PBSS Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-pbss-amoy-validator.spec
|
||||||
|
echo "Name: bor-pbss-amoy-validator-config" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "Summary: bor amoy validator config rpm package" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "Bor Amoy Validator rpm package" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/testnet-amoy/sentry/validator/bor/pbss_config.toml %{buildroot}/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build Amoy Validator PBSS Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-pbss-amoy-validator.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: Setting up Amoy Boot node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Amoy Boot Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-amoy-bootnode.spec
|
||||||
|
echo "Name: bor-amoy-bootnode-config" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "Summary: bor amoy bootnode config rpm package" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "Bor Amoy Bootnode rpm package" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/testnet-amoy/sentry/sentry/bor/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor_bootnode.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
|
||||||
|
- name: Build Amoy Boot Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-amoy-bootnode.spec
|
||||||
|
|
||||||
|
- name: Setting up Amoy Archive node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Amoy Archive Node spec file
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-amoy-archive.spec
|
||||||
|
echo "Name: bor-amoy-archive-config" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "Summary: bor amoy archive config rpm package" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "Bor Amoy Archive rpm package" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/testnet-amoy/archive/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
|
||||||
|
- name: Build Amoy Archive Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-amoy-archive.spec
|
||||||
|
|
||||||
|
- name: renaming file for rpm release appendage archive amoy
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-archive-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-archive-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage bootnode amoy
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-bootnode-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-bootnode-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage sentry amoy
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-sentry-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage sentry pbss amoy
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-sentry-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage validator amoy
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-validator-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage validator pbss amoy
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-validator-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
|
||||||
|
- name: adding shasum for the rpm build amoy archive
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-amoy-archive-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-archive-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build amoy bootnode
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-amoy-bootnode-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-bootnode-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build amoy sentry
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-amoy-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build amoy sentry pbss
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-pbss-amoy-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build amoy validator
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-amoy-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-amoy-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build amoy validator pbss
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-pbss-amoy-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-amoy-**.rpm
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-amoy-**.rpm.checksum
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-**.rpm
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-pbss-amoy-**.rpm.checksum
|
||||||
95
.github/workflows/rpm_arm_packager.yml
vendored
Normal file
95
.github/workflows/rpm_arm_packager.yml
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
name: package_arm_rpm
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on:
|
||||||
|
labels: arm-runner-2204
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@master
|
||||||
|
with:
|
||||||
|
go-version: 1.22.1
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Adding a TAG1 to the env
|
||||||
|
run: echo "GIT_TAG1=`echo $(git describe --tags --abbrev=0)`" | sed 's/-/./g' >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Cleaning repo
|
||||||
|
run: make clean
|
||||||
|
- name: Building for arm64
|
||||||
|
run: make bor
|
||||||
|
|
||||||
|
- name: Installing some dependencies
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y rpm
|
||||||
|
|
||||||
|
- name: Setup rpm package for binary
|
||||||
|
run: |
|
||||||
|
mkdir -p packaging/rpm/SPECS
|
||||||
|
mkdir -p packaging/rpm/BUILD
|
||||||
|
mkdir -p packaging/rpm/RPMS
|
||||||
|
mkdir -p packaging/rpm/SRPMS
|
||||||
|
|
||||||
|
touch packaging/rpm/bor.spec
|
||||||
|
echo "Name: bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "BuildArch: aarch64" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Summary: bor rpm package" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Bor rpm package" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "getent group bor >/dev/null || groupadd -r bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "getent passwd bor >/dev/null || useradd -s /bin/false -d /var/lib/bor -r bor -g bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "mkdir -p %{buildroot}/usr/bin" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/build/bin/bor %{buildroot}/usr/bin/" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "/usr/bin/bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: construct rpm package
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
- name: rename file for post rpm build and for checksum
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/aarch64/bor-${{ env.GIT_TAG1 }}-1.aarch64.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/aarch64/bor-${{ env.GIT_TAG1 }}.aarch64.rpm
|
||||||
|
|
||||||
|
- name: checksum for the rpm package
|
||||||
|
run: sha256sum /home/runner/work/bor/bor/packaging/rpm_build/RPMS/aarch64/bor-${{ env.GIT_TAG1 }}.aarch64.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/aarch64/bor-${{ env.GIT_TAG1 }}.aarch64.rpm.checksum
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/rpm_build/RPMS/aarch64/bor-**.rpm
|
||||||
|
packaging/rpm_build/RPMS/aarch64/bor-**.rpm.checksum
|
||||||
323
.github/workflows/rpm_mainnet_profile_packager.yml
vendored
Normal file
323
.github/workflows/rpm_mainnet_profile_packager.yml
vendored
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
name: rpm_mainnet_profile
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Adding a TAG1 to the env
|
||||||
|
run: echo "GIT_TAG1=`echo $(git describe --tags --abbrev=0)`" | sed 's/-/./g' >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Installing some dependencies
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y rpm
|
||||||
|
|
||||||
|
- name: Setup rpm package directories
|
||||||
|
run: |
|
||||||
|
mkdir -p packaging/rpm/SPECS
|
||||||
|
mkdir -p packaging/rpm/BUILD
|
||||||
|
mkdir -p packaging/rpm/RPMS
|
||||||
|
mkdir -p packaging/rpm/SRPMS
|
||||||
|
|
||||||
|
- name: Start tasks needed for Mainnet Sentry node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Sentry Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-mainnet-sentry.spec
|
||||||
|
echo "Name: bor-mainnet-sentry-config" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "Summary: bor mainnet sentry config rpm package" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "Bor Mumbai Sentry rpm package" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
|
||||||
|
- name: Build Mainnet Sentry Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-mainnet-sentry.spec
|
||||||
|
|
||||||
|
- name: Start tasks needed for Mainnet Sentry PBSS node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Sentry PBSS Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "Name: bor-pbss-mainnet-sentry-config" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "Summary: bor mainnet sentry config rpm package" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "Bor Mumbai Sentry rpm package" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/mainnet-v1/sentry/sentry/bor/pbss_config.toml %{buildroot}/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
|
||||||
|
- name: Build Mainnet Sentry PBSS Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-pbss-mainnet-sentry.spec
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Validator Node node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Validator Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-mainnet-validator.spec
|
||||||
|
echo "Name: bor-mainnet-validator-config" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "Summary: bor mainnet validator config rpm package" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "Bor Mainnet Validator rpm package" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/mainnet-v1/sentry/validator/bor/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build Mainnet Validator Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-mainnet-validator.spec
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Validator PBSS Node node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Validator Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "Name: bor-pbss-mainnet-validator-config" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "Summary: bor mainnet validator config rpm package" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "Bor Mainnet Validator rpm package" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/mainnet-v1/sentry/validator/bor/pbss_config.toml %{buildroot}/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build Mainnet Validator PBSS Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-pbss-mainnet-validator.spec
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Boot node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Boot Node Spec files
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-mainnet-bootnode.spec
|
||||||
|
echo "Name: bor-mainnet-bootnode-config" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "Summary: bor mainnet bootnode config rpm package" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "Bor Mainnet Bootnode rpm package" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor_bootnode.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
|
||||||
|
- name: Build Mainnet Boot Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-mainnet-bootnode.spec
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Archive node
|
||||||
|
run: echo "#########################################################################"
|
||||||
|
|
||||||
|
- name: Setting up Mainnet Archive Node spec file
|
||||||
|
run: |
|
||||||
|
touch packaging/rpm/bor-mainnet-archive.spec
|
||||||
|
echo "Name: bor-mainnet-archive-config" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "BuildArch: noarch" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "Summary: bor mainnet archive config rpm package" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "Bor Mainnet Archive rpm package" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "mkdir -p %{buildroot}/var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/mainnet-v1/archive/config.toml %{buildroot}/var/lib/bor/" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "mkdir -p %{buildroot}/lib/systemd/system" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/packaging/templates/systemd/bor.service %{buildroot}/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "/var/lib/bor/config.toml" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "/lib/systemd/system/bor.service" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "%attr(0755, bor, bor) /var/lib/bor" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "%post" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
echo "/bin/systemctl daemon-reload" >> packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
|
||||||
|
- name: Build Mainnet Archive Node profile RPM
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor-mainnet-archive.spec
|
||||||
|
|
||||||
|
- name: renaming file for rpm release appendage archive mainnet
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-archive-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-archive-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage bootnode mainnet
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-bootnode-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-bootnode-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage sentry mainnet
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-sentry-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage sentry pbss mainnet
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-sentry-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage validator mainnet
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-validator-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
- name: renaming file for rpm release appendage validator pbss mainnet
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-validator-config-${{ env.GIT_TAG1 }}-1.noarch.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm
|
||||||
|
|
||||||
|
- name: adding shasum for the rpm build mainnet archive
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-mainnet-archive-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-archive-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build mainnet bootnode
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-mainnet-bootnode-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-bootnode-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build mainnet sentry
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-mainnet-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build mainnet sentry pbss
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-pbss-mainnet-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-sentry-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build mainnet validator
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-mainnet-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-mainnet-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
- name: adding shasum for the rpm build mainnet pbss validator
|
||||||
|
run: cd /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/ && sha256sum bor-pbss-mainnet-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-validator-config-${{ env.GIT_TAG1 }}.noarch.rpm.checksum
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-mainnet-**.rpm
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-mainnet-**.rpm.checksum
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-**.rpm
|
||||||
|
packaging/rpm_build/RPMS/noarch/bor-pbss-mainnet-**.rpm.checksum
|
||||||
94
.github/workflows/rpm_packager.yml
vendored
Normal file
94
.github/workflows/rpm_packager.yml
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
name: package_x86_rpm
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
- 'v*.*.*-*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@master
|
||||||
|
with:
|
||||||
|
go-version: 1.22.1
|
||||||
|
- name: Adding TAG to ENV
|
||||||
|
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Adding a TAG.1 to the env
|
||||||
|
run: echo "GIT_TAG1=`echo $(git describe --tags --abbrev=0)`" | sed 's/-/./g' >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Cleaning repo
|
||||||
|
run: make clean
|
||||||
|
- name: Building for amd64
|
||||||
|
run: make bor
|
||||||
|
|
||||||
|
- name: Installing some dependencies
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y rpm
|
||||||
|
|
||||||
|
- name: Setup rpm package for binary
|
||||||
|
run: |
|
||||||
|
mkdir -p packaging/rpm/SPECS
|
||||||
|
mkdir -p packaging/rpm/BUILD
|
||||||
|
mkdir -p packaging/rpm/RPMS
|
||||||
|
mkdir -p packaging/rpm/SRPMS
|
||||||
|
|
||||||
|
touch packaging/rpm/bor.spec
|
||||||
|
echo "Name: bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Version: ${{ env.GIT_TAG1 }}" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Release: 1%{?dist}" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "License: GPL/AGPL" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "BuildArch: x86_64" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Summary: bor rpm package" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%description" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "Bor rpm package" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%pre" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "getent group bor >/dev/null || groupadd -r bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "getent passwd bor >/dev/null || useradd -s /bin/false -d /var/lib/bor -r bor -g bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%install" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "mkdir -p %{buildroot}/usr/bin" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "cp /home/runner/work/bor/bor/build/bin/bor %{buildroot}/usr/bin/" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
echo "%files" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
echo "/usr/bin/bor" >> packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
|
||||||
|
- name: construct rpm package
|
||||||
|
run: |
|
||||||
|
rpmbuild --define "_topdir /home/runner/work/bor/bor/packaging/rpm_build" \
|
||||||
|
--define "_builddir %{_topdir}/BUILD" \
|
||||||
|
--define "_rpmdir %{_topdir}/RPMS" \
|
||||||
|
--define "_srcrpmdir %{_topdir}/SRPMS" \
|
||||||
|
--define "__spec_install_post /bin/true" \
|
||||||
|
-bb packaging/rpm/SPECS/bor.spec
|
||||||
|
|
||||||
|
- name: rename file for post rpm build and for checksum
|
||||||
|
run: mv /home/runner/work/bor/bor/packaging/rpm_build/RPMS/x86_64/bor-${{ env.GIT_TAG1 }}-1.x86_64.rpm /home/runner/work/bor/bor/packaging/rpm_build/RPMS/x86_64/bor-${{ env.GIT_TAG1 }}.x86_64.rpm
|
||||||
|
|
||||||
|
- name: checksum for the rpm package
|
||||||
|
run: sha256sum /home/runner/work/bor/bor/packaging/rpm_build/RPMS/x86_64/bor-${{ env.GIT_TAG1 }}.x86_64.rpm > /home/runner/work/bor/bor/packaging/rpm_build/RPMS/x86_64/bor-${{ env.GIT_TAG1 }}.x86_64.rpm.checksum
|
||||||
|
|
||||||
|
- name: Release bor Packages
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.GIT_TAG }}
|
||||||
|
prerelease: true
|
||||||
|
files: |
|
||||||
|
packaging/rpm_build/RPMS/x86_64/bor-**.rpm
|
||||||
|
packaging/rpm_build/RPMS/x86_64/bor-**.rpm.checksum
|
||||||
|
|
@ -10,7 +10,6 @@ run:
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
enable:
|
enable:
|
||||||
- goconst
|
|
||||||
- goimports
|
- goimports
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
|
|
@ -24,7 +23,10 @@ linters:
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- exportloopref
|
- exportloopref
|
||||||
- whitespace
|
- whitespace
|
||||||
|
- revive # only certain checks enabled
|
||||||
|
|
||||||
|
### linters we tried and will not be using:
|
||||||
|
###
|
||||||
# - structcheck # lots of false positives
|
# - structcheck # lots of false positives
|
||||||
# - errcheck #lot of false positives
|
# - errcheck #lot of false positives
|
||||||
# - contextcheck
|
# - contextcheck
|
||||||
|
|
@ -37,9 +39,15 @@ linters:
|
||||||
linters-settings:
|
linters-settings:
|
||||||
gofmt:
|
gofmt:
|
||||||
simplify: true
|
simplify: true
|
||||||
goconst:
|
revive:
|
||||||
min-len: 3 # minimum length of string constant
|
enable-all-rules: false
|
||||||
min-occurrences: 6 # minimum number of occurrences
|
# here we enable specific useful rules
|
||||||
|
# see https://golangci-lint.run/usage/linters/#revive for supported rules
|
||||||
|
rules:
|
||||||
|
- name: receiver-naming
|
||||||
|
severity: warning
|
||||||
|
disabled: false
|
||||||
|
exclude: [""]
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-files:
|
exclude-files:
|
||||||
|
|
@ -49,6 +57,9 @@ issues:
|
||||||
linters:
|
linters:
|
||||||
- deadcode
|
- deadcode
|
||||||
- staticcheck
|
- staticcheck
|
||||||
|
- path: crypto/bn256/
|
||||||
|
linters:
|
||||||
|
- revive
|
||||||
- path: internal/build/pgp.go
|
- path: internal/build/pgp.go
|
||||||
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
||||||
- path: core/vm/contracts.go
|
- path: core/vm/contracts.go
|
||||||
|
|
|
||||||
1
.mailmap
1
.mailmap
|
|
@ -56,7 +56,6 @@ Diederik Loerakker <proto@protolambda.com>
|
||||||
Dimitry Khokhlov <winsvega@mail.ru>
|
Dimitry Khokhlov <winsvega@mail.ru>
|
||||||
|
|
||||||
Domino Valdano <dominoplural@gmail.com>
|
Domino Valdano <dominoplural@gmail.com>
|
||||||
Domino Valdano <dominoplural@gmail.com> <jeff@okcupid.com>
|
|
||||||
|
|
||||||
Edgar Aroutiounian <edgar.factorial@gmail.com>
|
Edgar Aroutiounian <edgar.factorial@gmail.com>
|
||||||
|
|
||||||
|
|
|
||||||
50
.travis.yml
50
.travis.yml
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
arch: amd64
|
arch: amd64
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
env:
|
env:
|
||||||
- docker
|
- docker
|
||||||
|
|
@ -44,7 +44,7 @@ jobs:
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
env:
|
env:
|
||||||
- docker
|
- docker
|
||||||
|
|
@ -85,21 +85,20 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: noble
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
env:
|
env:
|
||||||
- azure-linux
|
- azure-linux
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
script:
|
script:
|
||||||
# Build for the primary platforms that Trusty can manage
|
# build amd64
|
||||||
- go run build/ci.go install -dlgo
|
- go run build/ci.go install -dlgo
|
||||||
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
# build 386
|
||||||
|
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||||
- go run build/ci.go install -dlgo -arch 386
|
- go run build/ci.go install -dlgo -arch 386
|
||||||
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
|
@ -172,48 +171,42 @@ jobs:
|
||||||
|
|
||||||
# These builders run the tests
|
# These builders run the tests
|
||||||
- stage: build
|
- stage: build
|
||||||
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
arch: amd64
|
arch: amd64
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
script:
|
script:
|
||||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = pull_request
|
if: type = pull_request
|
||||||
os: linux
|
os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
script:
|
script:
|
||||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
- stage: build
|
- stage: build
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
script:
|
script:
|
||||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
# This builder does the Ubuntu PPA nightly uploads
|
# This builder does the Ubuntu PPA nightly uploads
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
env:
|
env:
|
||||||
- ubuntu-ppa
|
- ubuntu-ppa
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
addons:
|
before_install:
|
||||||
apt:
|
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot
|
||||||
packages:
|
|
||||||
- devscripts
|
|
||||||
- debhelper
|
|
||||||
- dput
|
|
||||||
- fakeroot
|
|
||||||
- python-bzrlib
|
|
||||||
- python-paramiko
|
|
||||||
script:
|
script:
|
||||||
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
||||||
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
||||||
|
|
@ -222,7 +215,7 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron
|
if: type = cron
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
env:
|
env:
|
||||||
- azure-purge
|
- azure-purge
|
||||||
|
|
@ -235,8 +228,9 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron
|
if: type = cron
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: noble
|
||||||
go: 1.22.x
|
go: 1.22.x
|
||||||
|
env:
|
||||||
|
- racetests
|
||||||
script:
|
script:
|
||||||
- travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES
|
- travis_wait 60 go run build/ci.go test -race $TEST_PACKAGES
|
||||||
|
|
||||||
|
|
|
||||||
11
Makefile
11
Makefile
|
|
@ -7,6 +7,7 @@
|
||||||
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
|
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
|
||||||
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
|
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
|
||||||
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
|
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
|
||||||
|
.PHONY: geth all test lint fmt clean devtools help
|
||||||
|
|
||||||
GO ?= latest
|
GO ?= latest
|
||||||
GOBIN = $(CURDIR)/build/bin
|
GOBIN = $(CURDIR)/build/bin
|
||||||
|
|
@ -38,11 +39,13 @@ generate-mocks:
|
||||||
go generate mockgen -destination=./eth/filters/IBackend.go -package=filters ./eth/filters Backend
|
go generate mockgen -destination=./eth/filters/IBackend.go -package=filters ./eth/filters Backend
|
||||||
go generate mockgen -destination=../eth/filters/IDatabase.go -package=filters ./ethdb Database
|
go generate mockgen -destination=../eth/filters/IDatabase.go -package=filters ./ethdb Database
|
||||||
|
|
||||||
|
#? geth: Build geth.
|
||||||
geth:
|
geth:
|
||||||
$(GORUN) build/ci.go install ./cmd/geth
|
$(GORUN) build/ci.go install ./cmd/geth
|
||||||
@echo "Done building."
|
@echo "Done building."
|
||||||
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
||||||
|
|
||||||
|
#? all: Build all packages and executables.
|
||||||
all:
|
all:
|
||||||
$(GORUN) build/ci.go install
|
$(GORUN) build/ci.go install
|
||||||
|
|
||||||
|
|
@ -59,7 +62,7 @@ ios:
|
||||||
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(GOTEST) --timeout 15m -cover -short -coverprofile=cover.out -covermode=atomic $(TESTALL)
|
$(GOTEST) --timeout 30m -cover -short -coverprofile=cover.out -covermode=atomic $(TESTALL)
|
||||||
|
|
||||||
test-txpool-race:
|
test-txpool-race:
|
||||||
$(GOTEST) -run=TestPoolMiningDataRaces --timeout 600m -race -v ./core/
|
$(GOTEST) -run=TestPoolMiningDataRaces --timeout 600m -race -v ./core/
|
||||||
|
|
@ -89,6 +92,11 @@ goimports:
|
||||||
docs:
|
docs:
|
||||||
$(GORUN) cmd/clidoc/main.go -d ./docs/cli
|
$(GORUN) cmd/clidoc/main.go -d ./docs/cli
|
||||||
|
|
||||||
|
#? fmt: Ensure consistent code formatting.
|
||||||
|
fmt:
|
||||||
|
gofmt -s -w $(shell find . -name "*.go")
|
||||||
|
|
||||||
|
#? clean: Clean go cache, built executables, and the auto generated folder.
|
||||||
clean:
|
clean:
|
||||||
go clean -cache
|
go clean -cache
|
||||||
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
||||||
|
|
@ -96,6 +104,7 @@ clean:
|
||||||
# The devtools target installs tools required for 'go generate'.
|
# The devtools target installs tools required for 'go generate'.
|
||||||
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||||
|
|
||||||
|
#? devtools: Install recommended developer tools.
|
||||||
devtools:
|
devtools:
|
||||||
# Notice! If you adding new binary - add it also to tests/deps/fake.go file
|
# Notice! If you adding new binary - add it also to tests/deps/fake.go file
|
||||||
$(GOBUILD) -o $(GOBIN)/stringer github.com/golang.org/x/tools/cmd/stringer
|
$(GOBUILD) -o $(GOBIN)/stringer github.com/golang.org/x/tools/cmd/stringer
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
Bor is the Official Golang implementation of the Polygon PoS blockchain. It is a fork of [geth](https://github.com/ethereum/go-ethereum) and is EVM compatible (upto London fork).
|
Bor is the Official Golang implementation of the Polygon PoS blockchain. It is a fork of [geth](https://github.com/ethereum/go-ethereum) and is EVM compatible (upto London fork).
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/maticnetwork/bor)
|
)](https://pkg.go.dev/github.com/maticnetwork/bor)
|
||||||
[](https://goreportcard.com/report/github.com/maticnetwork/bor)
|
[](https://goreportcard.com/report/github.com/maticnetwork/bor)
|
||||||

|

|
||||||
[](https://discord.gg/0xpolygon)
|
[](https://discord.com/invite/0xpolygonrnd)
|
||||||
[](https://twitter.com/0xPolygon)
|
[](https://twitter.com/0xPolygon)
|
||||||
|
|
||||||
### Installing bor using packaging
|
### Installing bor using packaging
|
||||||
|
|
@ -79,4 +79,4 @@ included in our repository in the `COPYING` file.
|
||||||
|
|
||||||
## Join our Discord server
|
## Join our Discord server
|
||||||
|
|
||||||
Join Polygon community – share your ideas or just say hi over [on Discord](https://discord.com/invite/0xPolygonDevs).
|
Join Polygon community – share your ideas or just say hi over on [Polygon Community Discord](https://discord.com/invite/0xPolygonCommunity) or on [Polygon R&D Discord](https://discord.com/invite/0xpolygonrnd).
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ func (arguments Arguments) Copy(v interface{}, values []interface{}) error {
|
||||||
return arguments.copyAtomic(v, values[0])
|
return arguments.copyAtomic(v, values[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpackAtomic unpacks ( hexdata -> go ) a single value
|
// copyAtomic copies ( hexdata -> go ) a single value
|
||||||
func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{}) error {
|
func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{}) error {
|
||||||
dst := reflect.ValueOf(v).Elem()
|
dst := reflect.ValueOf(v).Elem()
|
||||||
src := reflect.ValueOf(marshalledValues)
|
src := reflect.ValueOf(marshalledValues)
|
||||||
|
|
|
||||||
|
|
@ -153,12 +153,10 @@ func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accou
|
||||||
// NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer
|
// NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer
|
||||||
// from a single private key.
|
// from a single private key.
|
||||||
func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*TransactOpts, error) {
|
func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*TransactOpts, error) {
|
||||||
keyAddr := crypto.PubkeyToAddress(key.PublicKey)
|
|
||||||
|
|
||||||
if chainID == nil {
|
if chainID == nil {
|
||||||
return nil, ErrNoChainID
|
return nil, ErrNoChainID
|
||||||
}
|
}
|
||||||
|
keyAddr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
signer := types.LatestSignerForChainID(chainID)
|
signer := types.LatestSignerForChainID(chainID)
|
||||||
|
|
||||||
return &TransactOpts{
|
return &TransactOpts{
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,11 @@ type BlockHashContractCaller interface {
|
||||||
// used when the user does not provide some needed values, but rather leaves it up
|
// used when the user does not provide some needed values, but rather leaves it up
|
||||||
// to the transactor to decide.
|
// to the transactor to decide.
|
||||||
type ContractTransactor interface {
|
type ContractTransactor interface {
|
||||||
|
ethereum.GasEstimator
|
||||||
|
ethereum.GasPricer
|
||||||
|
ethereum.GasPricer1559
|
||||||
|
ethereum.TransactionSender
|
||||||
|
|
||||||
// HeaderByNumber returns a block header from the current canonical chain. If
|
// HeaderByNumber returns a block header from the current canonical chain. If
|
||||||
// number is nil, the latest known header is returned.
|
// number is nil, the latest known header is returned.
|
||||||
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
||||||
|
|
@ -93,38 +98,6 @@ type ContractTransactor interface {
|
||||||
|
|
||||||
// PendingNonceAt retrieves the current pending nonce associated with an account.
|
// PendingNonceAt retrieves the current pending nonce associated with an account.
|
||||||
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
||||||
|
|
||||||
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
|
||||||
// execution of a transaction.
|
|
||||||
SuggestGasPrice(ctx context.Context) (*big.Int, error)
|
|
||||||
|
|
||||||
// SuggestGasTipCap retrieves the currently suggested 1559 priority fee to allow
|
|
||||||
// a timely execution of a transaction.
|
|
||||||
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
|
|
||||||
|
|
||||||
// EstimateGas tries to estimate the gas needed to execute a specific
|
|
||||||
// transaction based on the current pending state of the backend blockchain.
|
|
||||||
// There is no guarantee that this is the true gas limit requirement as other
|
|
||||||
// transactions may be added or removed by miners, but it should provide a basis
|
|
||||||
// for setting a reasonable default.
|
|
||||||
EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error)
|
|
||||||
|
|
||||||
// SendTransaction injects the transaction into the pending pool for execution.
|
|
||||||
SendTransaction(ctx context.Context, tx *types.Transaction) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractFilterer defines the methods needed to access log events using one-off
|
|
||||||
// queries or continuous event subscriptions.
|
|
||||||
type ContractFilterer interface {
|
|
||||||
// FilterLogs executes a log filter operation, blocking during execution and
|
|
||||||
// returning all the results in one batch.
|
|
||||||
//
|
|
||||||
// TODO(karalabe): Deprecate when the subscription one can return past data too.
|
|
||||||
FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)
|
|
||||||
|
|
||||||
// SubscribeFilterLogs creates a background log filtering operation, returning
|
|
||||||
// a subscription immediately, which can be used to stream the found events.
|
|
||||||
SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
||||||
|
|
@ -133,6 +106,12 @@ type DeployBackend interface {
|
||||||
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
|
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContractFilterer defines the methods needed to access log events using one-off
|
||||||
|
// queries or continuous event subscriptions.
|
||||||
|
type ContractFilterer interface {
|
||||||
|
ethereum.LogFilterer
|
||||||
|
}
|
||||||
|
|
||||||
// ContractBackend defines the methods needed to work with contracts on a read-write basis.
|
// ContractBackend defines the methods needed to work with contracts on a read-write basis.
|
||||||
type ContractBackend interface {
|
type ContractBackend interface {
|
||||||
ContractCaller
|
ContractCaller
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
|
|
@ -43,8 +44,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BOR
|
||||||
|
// Simulated backend is retained and upstream changes are not applied as block production is still needed for BOR
|
||||||
|
|
||||||
// This nil assignment ensures at compile time that SimulatedBackend implements bind.ContractBackend.
|
// This nil assignment ensures at compile time that SimulatedBackend implements bind.ContractBackend.
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
||||||
|
|
@ -78,7 +83,7 @@ type SimulatedBackend struct {
|
||||||
// NewSimulatedBackendWithDatabase creates a new binding backend based on the given database
|
// NewSimulatedBackendWithDatabase creates a new binding backend based on the given database
|
||||||
// and uses a simulated blockchain for testing purposes.
|
// and uses a simulated blockchain for testing purposes.
|
||||||
// A simulated backend always uses chainID 1337.
|
// A simulated backend always uses chainID 1337.
|
||||||
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc types.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||||
genesis := core.Genesis{
|
genesis := core.Genesis{
|
||||||
Config: params.AllEthashProtocolChanges,
|
Config: params.AllEthashProtocolChanges,
|
||||||
GasLimit: gasLimit,
|
GasLimit: gasLimit,
|
||||||
|
|
@ -94,7 +99,7 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis
|
||||||
|
|
||||||
filterBackend := &filterBackend{database, blockchain, backend}
|
filterBackend := &filterBackend{database, blockchain, backend}
|
||||||
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
|
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
|
||||||
backend.events = filters.NewEventSystem(backend.filterSystem, false)
|
backend.events = filters.NewEventSystem(backend.filterSystem)
|
||||||
|
|
||||||
header := backend.blockchain.CurrentBlock()
|
header := backend.blockchain.CurrentBlock()
|
||||||
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
||||||
|
|
@ -106,7 +111,7 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
// for testing purposes.
|
// for testing purposes.
|
||||||
// A simulated backend always uses chainID 1337.
|
// A simulated backend always uses chainID 1337.
|
||||||
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
func NewSimulatedBackend(alloc types.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||||
return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit)
|
return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,7 +227,7 @@ func (b *SimulatedBackend) CodeAtHash(ctx context.Context, contract common.Addre
|
||||||
}
|
}
|
||||||
|
|
||||||
// BalanceAt returns the wei balance of a certain account in the blockchain.
|
// BalanceAt returns the wei balance of a certain account in the blockchain.
|
||||||
func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) {
|
func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*uint256.Int, error) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -565,7 +570,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
// Recap the highest gas allowance with account's balance.
|
// Recap the highest gas allowance with account's balance.
|
||||||
if feeCap.BitLen() != 0 {
|
if feeCap.BitLen() != 0 {
|
||||||
balance := b.pendingState.GetBalance(call.From) // from can't be nil
|
balance := b.pendingState.GetBalance(call.From) // from can't be nil
|
||||||
available := new(big.Int).Set(balance)
|
available := balance.ToBig()
|
||||||
if call.Value != nil {
|
if call.Value != nil {
|
||||||
if call.Value.Cmp(available) >= 0 {
|
if call.Value.Cmp(available) >= 0 {
|
||||||
return 0, core.ErrInsufficientFundsForTransfer
|
return 0, core.ErrInsufficientFundsForTransfer
|
||||||
|
|
@ -681,7 +686,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
|
|
||||||
// Set infinite balance to the fake caller account.
|
// Set infinite balance to the fake caller account.
|
||||||
from := stateDB.GetOrNewStateObject(call.From)
|
from := stateDB.GetOrNewStateObject(call.From)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.BigIntToUint256Int(math.MaxBig256), tracing.BalanceChangeUnspecified)
|
||||||
|
|
||||||
// Execute the call.
|
// Execute the call.
|
||||||
msg := &core.Message{
|
msg := &core.Message{
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,16 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/goleak"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/leak"
|
"github.com/ethereum/go-ethereum/common/leak"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
"go.uber.org/goleak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSimulatedBackend(t *testing.T) {
|
func TestSimulatedBackend(t *testing.T) {
|
||||||
|
|
@ -46,8 +45,8 @@ func TestSimulatedBackend(t *testing.T) {
|
||||||
|
|
||||||
key, _ := crypto.GenerateKey() // nolint: gosec
|
key, _ := crypto.GenerateKey() // nolint: gosec
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
genAlloc := make(core.GenesisAlloc)
|
genAlloc := make(types.GenesisAlloc)
|
||||||
genAlloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(9223372036854775807)}
|
genAlloc[auth.From] = types.Account{Balance: big.NewInt(9223372036854775807)}
|
||||||
|
|
||||||
sim := NewSimulatedBackend(genAlloc, gasLimit)
|
sim := NewSimulatedBackend(genAlloc, gasLimit)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
@ -125,7 +124,7 @@ var expectedReturn = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
|
||||||
func simTestBackend(testAddr common.Address) *SimulatedBackend {
|
func simTestBackend(testAddr common.Address) *SimulatedBackend {
|
||||||
return NewSimulatedBackend(
|
return NewSimulatedBackend(
|
||||||
core.GenesisAlloc{
|
types.GenesisAlloc{
|
||||||
testAddr: {Balance: big.NewInt(10000000000000000)},
|
testAddr: {Balance: big.NewInt(10000000000000000)},
|
||||||
}, 10000000,
|
}, 10000000,
|
||||||
)
|
)
|
||||||
|
|
@ -150,7 +149,7 @@ func TestNewSimulatedBackend(t *testing.T) {
|
||||||
stateDB, _ := sim.blockchain.State()
|
stateDB, _ := sim.blockchain.State()
|
||||||
|
|
||||||
bal := stateDB.GetBalance(testAddr)
|
bal := stateDB.GetBalance(testAddr)
|
||||||
if bal.Cmp(expectedBal) != 0 {
|
if bal.Cmp(uint256.NewInt(expectedBal.Uint64())) != 0 {
|
||||||
t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
|
t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +157,7 @@ func TestNewSimulatedBackend(t *testing.T) {
|
||||||
func TestAdjustTime(t *testing.T) {
|
func TestAdjustTime(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
sim := NewSimulatedBackend(
|
sim := NewSimulatedBackend(
|
||||||
core.GenesisAlloc{}, 10000000,
|
types.GenesisAlloc{}, 10000000,
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -230,7 +229,7 @@ func TestNewAdjustTimeFail(t *testing.T) {
|
||||||
func TestBalanceAt(t *testing.T) {
|
func TestBalanceAt(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
expectedBal := big.NewInt(10000000000000000)
|
expectedBal := uint256.NewInt(10000000000000000)
|
||||||
|
|
||||||
sim := simTestBackend(testAddr)
|
sim := simTestBackend(testAddr)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
@ -250,7 +249,7 @@ func TestBalanceAt(t *testing.T) {
|
||||||
func TestBlockByHash(t *testing.T) {
|
func TestBlockByHash(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
sim := NewSimulatedBackend(
|
sim := NewSimulatedBackend(
|
||||||
core.GenesisAlloc{}, 10000000,
|
types.GenesisAlloc{}, 10000000,
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -274,7 +273,7 @@ func TestBlockByHash(t *testing.T) {
|
||||||
func TestBlockByNumber(t *testing.T) {
|
func TestBlockByNumber(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
sim := NewSimulatedBackend(
|
sim := NewSimulatedBackend(
|
||||||
core.GenesisAlloc{}, 10000000,
|
types.GenesisAlloc{}, 10000000,
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -412,7 +411,7 @@ func TestTransactionByHash(t *testing.T) {
|
||||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
|
|
||||||
sim := NewSimulatedBackend(
|
sim := NewSimulatedBackend(
|
||||||
core.GenesisAlloc{
|
types.GenesisAlloc{
|
||||||
testAddr: {Balance: big.NewInt(10000000000000000)},
|
testAddr: {Balance: big.NewInt(10000000000000000)},
|
||||||
}, 10000000,
|
}, 10000000,
|
||||||
)
|
)
|
||||||
|
|
@ -488,7 +487,7 @@ func TestEstimateGas(t *testing.T) {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether)}}, 10000000)
|
sim := NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
parsed, _ := abi.JSON(strings.NewReader(contractAbi))
|
parsed, _ := abi.JSON(strings.NewReader(contractAbi))
|
||||||
|
|
@ -599,7 +598,7 @@ func TestEstimateGasWithPrice(t *testing.T) {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether*2 + 2e17)}}, 10000000)
|
sim := NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether*2 + 2e17)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
recipient := common.HexToAddress("deadbeef")
|
recipient := common.HexToAddress("deadbeef")
|
||||||
|
|
@ -1002,7 +1001,7 @@ func TestTransactionReceipt(t *testing.T) {
|
||||||
func TestSuggestGasPrice(t *testing.T) {
|
func TestSuggestGasPrice(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
sim := NewSimulatedBackend(
|
sim := NewSimulatedBackend(
|
||||||
core.GenesisAlloc{},
|
types.GenesisAlloc{},
|
||||||
10000000,
|
10000000,
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
|
||||||
|
|
@ -495,8 +495,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
sub := event.NewSubscription(func(quit <-chan struct{}) error {
|
||||||
sub, err := event.NewSubscription(func(quit <-chan struct{}) error {
|
|
||||||
for _, log := range buff {
|
for _, log := range buff {
|
||||||
select {
|
select {
|
||||||
case logs <- log:
|
case logs <- log:
|
||||||
|
|
@ -506,11 +505,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}), nil
|
})
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return logs, sub, nil
|
return logs, sub, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -94,6 +97,10 @@ func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, b
|
||||||
return mc.callContractBytes, mc.callContractErr
|
return mc.callContractBytes, mc.callContractErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mc *mockCaller) CallWithState(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, state *state.StateDB, overrides *ethapi.StateOverride, blockOverrides *ethapi.BlockOverrides) (hexutil.Bytes, error) {
|
||||||
|
return mc.CallContract(ctx, ethereum.CallMsg{}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
type mockPendingCaller struct {
|
type mockPendingCaller struct {
|
||||||
*mockCaller
|
*mockCaller
|
||||||
pendingCodeAtBytes []byte
|
pendingCodeAtBytes []byte
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -297,7 +297,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy an interaction tester contract and call a transaction on it
|
// Deploy an interaction tester contract and call a transaction on it
|
||||||
|
|
@ -305,6 +305,7 @@ var bindTests = []struct {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deploy interactor contract: %v", err)
|
t.Fatalf("Failed to deploy interactor contract: %v", err)
|
||||||
}
|
}
|
||||||
|
sim.Commit()
|
||||||
if _, err := interactor.Transact(auth, "Transact string"); err != nil {
|
if _, err := interactor.Transact(auth, "Transact string"); err != nil {
|
||||||
t.Fatalf("Failed to transact with interactor contract: %v", err)
|
t.Fatalf("Failed to transact with interactor contract: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +345,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -352,7 +353,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a tuple tester contract and execute a structured call on it
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
|
|
@ -390,7 +391,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -398,7 +399,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a tuple tester contract and execute a structured call on it
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
|
|
@ -448,7 +449,7 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -456,7 +457,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a slice tester contract and execute a n array call on it
|
// Deploy a slice tester contract and execute a n array call on it
|
||||||
|
|
@ -496,7 +497,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -504,7 +505,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a default method invoker contract and execute its default method
|
// Deploy a default method invoker contract and execute its default method
|
||||||
|
|
@ -512,6 +513,7 @@ var bindTests = []struct {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deploy defaulter contract: %v", err)
|
t.Fatalf("Failed to deploy defaulter contract: %v", err)
|
||||||
}
|
}
|
||||||
|
sim.Commit()
|
||||||
if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil {
|
if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil {
|
||||||
t.Fatalf("Failed to invoke default method: %v", err)
|
t.Fatalf("Failed to invoke default method: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -562,7 +564,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -570,7 +572,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a structs method invoker contract and execute its default method
|
// Deploy a structs method invoker contract and execute its default method
|
||||||
|
|
@ -608,12 +610,12 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Create a simulator and wrap a non-deployed contract
|
// Create a simulator and wrap a non-deployed contract
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{}, uint64(10000000000))
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
||||||
|
|
@ -647,12 +649,12 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Create a simulator and wrap a non-deployed contract
|
// Create a simulator and wrap a non-deployed contract
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{}, uint64(10000000000))
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
nonexistent, err := NewNonExistentStruct(common.Address{}, sim)
|
nonexistent, err := NewNonExistentStruct(common.Address{}, sim)
|
||||||
|
|
@ -694,7 +696,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -702,7 +704,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a funky gas pattern contract
|
// Deploy a funky gas pattern contract
|
||||||
|
|
@ -744,7 +746,7 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -752,7 +754,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a sender tester contract and execute a structured call on it
|
// Deploy a sender tester contract and execute a structured call on it
|
||||||
|
|
@ -819,7 +821,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -827,7 +829,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a underscorer tester contract and execute a structured call on it
|
// Deploy a underscorer tester contract and execute a structured call on it
|
||||||
|
|
@ -913,7 +915,7 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -921,7 +923,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy an eventer contract
|
// Deploy an eventer contract
|
||||||
|
|
@ -1103,7 +1105,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -1111,7 +1113,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
//deploy the test contract
|
//deploy the test contract
|
||||||
|
|
@ -1238,7 +1240,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
|
|
||||||
|
|
@ -1246,7 +1248,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
_, _, contract, err := DeployTuple(auth, sim)
|
_, _, contract, err := DeployTuple(auth, sim)
|
||||||
|
|
@ -1380,7 +1382,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -1388,7 +1390,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
//deploy the test contract
|
//deploy the test contract
|
||||||
|
|
@ -1446,14 +1448,14 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Initialize test accounts
|
// Initialize test accounts
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// deploy the test contract
|
// deploy the test contract
|
||||||
|
|
@ -1535,7 +1537,7 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Initialize test accounts
|
// Initialize test accounts
|
||||||
|
|
@ -1543,7 +1545,7 @@ var bindTests = []struct {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
// Deploy registrar contract
|
// Deploy registrar contract
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
@ -1598,14 +1600,14 @@ var bindTests = []struct {
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
// Deploy registrar contract
|
// Deploy registrar contract
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
@ -1659,7 +1661,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
|
|
@ -1667,7 +1669,7 @@ var bindTests = []struct {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a tester contract and execute a structured call on it
|
// Deploy a tester contract and execute a structured call on it
|
||||||
|
|
@ -1720,14 +1722,14 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 1000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 1000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
@ -1808,7 +1810,7 @@ var bindTests = []struct {
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
|
|
@ -1816,7 +1818,7 @@ var bindTests = []struct {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -1874,11 +1876,12 @@ var bindTests = []struct {
|
||||||
[]string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"},
|
[]string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"},
|
||||||
[]string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
[]string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
||||||
`
|
`
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
|
|
@ -1886,7 +1889,7 @@ var bindTests = []struct {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -1895,7 +1898,7 @@ var bindTests = []struct {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
_, err = bind.WaitDeployed(nil, sim, tx)
|
_, err = bind.WaitDeployed(context.Background(), sim, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1926,11 +1929,12 @@ var bindTests = []struct {
|
||||||
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
|
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
|
||||||
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
|
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
|
||||||
imports: `
|
imports: `
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
|
|
@ -1938,7 +1942,7 @@ var bindTests = []struct {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -1948,7 +1952,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||||
t.Logf("Deployment tx: %+v", tx)
|
t.Logf("Deployment tx: %+v", tx)
|
||||||
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||||
}
|
}
|
||||||
|
|
@ -1974,11 +1978,12 @@ var bindTests = []struct {
|
||||||
bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"},
|
bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"},
|
||||||
abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`},
|
abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`},
|
||||||
imports: `
|
imports: `
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
|
|
@ -1986,7 +1991,7 @@ var bindTests = []struct {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
|
@ -1996,7 +2001,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||||
t.Logf("Deployment tx: %+v", tx)
|
t.Logf("Deployment tx: %+v", tx)
|
||||||
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||||
}
|
}
|
||||||
|
|
@ -2014,11 +2019,12 @@ var bindTests = []struct {
|
||||||
bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
|
bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
|
||||||
abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
||||||
imports: `
|
imports: `
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
|
|
@ -2026,7 +2032,7 @@ var bindTests = []struct {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
_, tx, _, err := DeployRangeKeyword(user, sim)
|
_, tx, _, err := DeployRangeKeyword(user, sim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -2034,7 +2040,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||||
t.Errorf("error deploying the contract: %v", err)
|
t.Errorf("error deploying the contract: %v", err)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -57,7 +56,7 @@ func TestWaitDeployed(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
for name, test := range waitDeployedTests {
|
for name, test := range waitDeployedTests {
|
||||||
backend := backends.NewSimulatedBackend(
|
backend := backends.NewSimulatedBackend(
|
||||||
core.GenesisAlloc{
|
types.GenesisAlloc{
|
||||||
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
||||||
},
|
},
|
||||||
10000000,
|
10000000,
|
||||||
|
|
@ -69,7 +68,7 @@ func TestWaitDeployed(t *testing.T) {
|
||||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei))
|
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei))
|
||||||
|
|
||||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
|
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(1337)), testKey)
|
||||||
|
|
||||||
// Wait for it to get mined in the background.
|
// Wait for it to get mined in the background.
|
||||||
var (
|
var (
|
||||||
|
|
@ -105,9 +104,8 @@ func TestWaitDeployed(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWaitDeployedCornerCases(t *testing.T) {
|
func TestWaitDeployedCornerCases(t *testing.T) {
|
||||||
t.Parallel()
|
|
||||||
backend := backends.NewSimulatedBackend(
|
backend := backends.NewSimulatedBackend(
|
||||||
core.GenesisAlloc{
|
types.GenesisAlloc{
|
||||||
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
||||||
},
|
},
|
||||||
10000000,
|
10000000,
|
||||||
|
|
@ -120,7 +118,7 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
||||||
// Create a transaction to an account.
|
// Create a transaction to an account.
|
||||||
code := "6060604052600a8060106000396000f360606040526008565b00"
|
code := "6060604052600a8060106000396000f360606040526008565b00"
|
||||||
tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
@ -133,7 +131,7 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
||||||
|
|
||||||
// Create a transaction that is not mined.
|
// Create a transaction that is not mined.
|
||||||
tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
contextCanceled := errors.New("context canceled")
|
contextCanceled := errors.New("context canceled")
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConvertType converts an interface of a runtime type into a interface of the
|
// ConvertType converts an interface of a runtime type into an interface of the
|
||||||
// given type, e.g. turn this code:
|
// given type, e.g. turn this code:
|
||||||
//
|
//
|
||||||
// var fields []reflect.StructField
|
// var fields []reflect.StructField
|
||||||
|
|
@ -33,7 +33,7 @@ import (
|
||||||
// Name: "X",
|
// Name: "X",
|
||||||
// Type: reflect.TypeOf(new(big.Int)),
|
// Type: reflect.TypeOf(new(big.Int)),
|
||||||
// Tag: reflect.StructTag("json:\"" + "x" + "\""),
|
// Tag: reflect.StructTag("json:\"" + "x" + "\""),
|
||||||
// }
|
// })
|
||||||
//
|
//
|
||||||
// into:
|
// into:
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -42,8 +43,7 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
|
||||||
case common.Address:
|
case common.Address:
|
||||||
copy(topic[common.HashLength-common.AddressLength:], rule[:])
|
copy(topic[common.HashLength-common.AddressLength:], rule[:])
|
||||||
case *big.Int:
|
case *big.Int:
|
||||||
blob := rule.Bytes()
|
copy(topic[:], math.U256Bytes(rule))
|
||||||
copy(topic[common.HashLength-len(blob):], blob)
|
|
||||||
case bool:
|
case bool:
|
||||||
if rule {
|
if rule {
|
||||||
topic[common.HashLength-1] = 1
|
topic[common.HashLength-1] = 1
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package abi
|
package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -56,9 +57,27 @@ func TestMakeTopics(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"support *big.Int types in topics",
|
"support positive *big.Int types in topics",
|
||||||
args{[][]interface{}{{big.NewInt(1).Lsh(big.NewInt(2), 254)}}},
|
args{[][]interface{}{
|
||||||
[][]common.Hash{{common.Hash{128}}},
|
{big.NewInt(1)},
|
||||||
|
{big.NewInt(1).Lsh(big.NewInt(2), 254)},
|
||||||
|
}},
|
||||||
|
[][]common.Hash{
|
||||||
|
{common.HexToHash("0000000000000000000000000000000000000000000000000000000000000001")},
|
||||||
|
{common.Hash{128}},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"support negative *big.Int types in topics",
|
||||||
|
args{[][]interface{}{
|
||||||
|
{big.NewInt(-1)},
|
||||||
|
{big.NewInt(math.MinInt64)},
|
||||||
|
}},
|
||||||
|
[][]common.Hash{
|
||||||
|
{common.MaxHash},
|
||||||
|
{common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000")},
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,9 @@ type Type struct {
|
||||||
var (
|
var (
|
||||||
// typeRegex parses the abi sub types
|
// typeRegex parses the abi sub types
|
||||||
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
||||||
|
|
||||||
|
// sliceSizeRegex grab the slice size
|
||||||
|
sliceSizeRegex = regexp.MustCompile("[0-9]+")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewType creates a new reflection type of abi type given in t.
|
// NewType creates a new reflection type of abi type given in t.
|
||||||
|
|
@ -93,8 +96,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
||||||
// grab the last cell and create a type from there
|
// grab the last cell and create a type from there
|
||||||
sliced := t[i:]
|
sliced := t[i:]
|
||||||
// grab the slice size with regexp
|
// grab the slice size with regexp
|
||||||
re := regexp.MustCompile("[0-9]+")
|
intz := sliceSizeRegex.FindAllString(sliced, -1)
|
||||||
intz := re.FindAllString(sliced, -1)
|
|
||||||
|
|
||||||
if len(intz) == 0 {
|
if len(intz) == 0 {
|
||||||
// is a slice
|
// is a slice
|
||||||
|
|
@ -193,11 +195,6 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] })
|
fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] })
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Type{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
used[fieldName] = true
|
used[fieldName] = true
|
||||||
|
|
||||||
if !isValidFieldName(fieldName) {
|
if !isValidFieldName(fieldName) {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// typeWithoutStringer is a alias for the Type type which simply doesn't implement
|
// typeWithoutStringer is an alias for the Type type which simply doesn't implement
|
||||||
// the stringer interface to allow printing type details in the tests below.
|
// the stringer interface to allow printing type details in the tests below.
|
||||||
type typeWithoutStringer Type
|
type typeWithoutStringer Type
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ func TextHash(data []byte) []byte {
|
||||||
//
|
//
|
||||||
// This gives context to the signed message and prevents signing of transactions.
|
// This gives context to the signed message and prevents signing of transactions.
|
||||||
func TextAndHash(data []byte) ([]byte, string) {
|
func TextAndHash(data []byte) ([]byte, string) {
|
||||||
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data))
|
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
hasher.Write([]byte(msg))
|
hasher.Write([]byte(msg))
|
||||||
|
|
||||||
|
|
|
||||||
16
accounts/external/backend.go
vendored
16
accounts/external/backend.go
vendored
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
@ -224,7 +224,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||||
}
|
}
|
||||||
|
|
||||||
args := &apitypes.SendTxArgs{
|
args := &apitypes.SendTxArgs{
|
||||||
Data: &data,
|
Input: &data,
|
||||||
Nonce: hexutil.Uint64(tx.Nonce()),
|
Nonce: hexutil.Uint64(tx.Nonce()),
|
||||||
Value: hexutil.Big(*tx.Value()),
|
Value: hexutil.Big(*tx.Value()),
|
||||||
Gas: hexutil.Uint64(tx.Gas()),
|
Gas: hexutil.Uint64(tx.Gas()),
|
||||||
|
|
@ -234,7 +234,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.LegacyTxType, types.AccessListTxType:
|
case types.LegacyTxType, types.AccessListTxType:
|
||||||
args.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
args.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
||||||
case types.DynamicFeeTxType:
|
case types.DynamicFeeTxType, types.BlobTxType:
|
||||||
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
||||||
default:
|
default:
|
||||||
|
|
@ -256,6 +256,16 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||||
accessList := tx.AccessList()
|
accessList := tx.AccessList()
|
||||||
args.AccessList = &accessList
|
args.AccessList = &accessList
|
||||||
}
|
}
|
||||||
|
if tx.Type() == types.BlobTxType {
|
||||||
|
args.BlobHashes = tx.BlobHashes()
|
||||||
|
sidecar := tx.BlobTxSidecar()
|
||||||
|
if sidecar == nil {
|
||||||
|
return nil, errors.New("blobs must be present for signing")
|
||||||
|
}
|
||||||
|
args.Blobs = sidecar.Blobs
|
||||||
|
args.Commitments = sidecar.Commitments
|
||||||
|
args.Proofs = sidecar.Proofs
|
||||||
|
}
|
||||||
|
|
||||||
var res signTransactionResult
|
var res signTransactionResult
|
||||||
if err := api.client.Call(&res, "account_signTransaction", args); err != nil {
|
if err := api.client.Call(&res, "account_signTransaction", args); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -32,7 +33,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -30,7 +31,6 @@ import (
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -89,7 +89,7 @@ func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error {
|
||||||
func TestWatchNewFile(t *testing.T) {
|
func TestWatchNewFile(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
dir, ks := tmpKeyStore(t, false)
|
dir, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
// Ensure the watcher is started before adding any files.
|
// Ensure the watcher is started before adding any files.
|
||||||
ks.Accounts()
|
ks.Accounts()
|
||||||
|
|
@ -342,7 +342,8 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a temporary keystore to test with
|
// Create a temporary keystore to test with
|
||||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int()))
|
dir := t.TempDir()
|
||||||
|
|
||||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||||
|
|
||||||
list := ks.Accounts()
|
list := ks.Accounts()
|
||||||
|
|
@ -353,9 +354,7 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
||||||
if !waitWatcherStart(ks) {
|
if !waitWatcherStart(ks) {
|
||||||
t.Fatal("keystore watcher didn't start in time")
|
t.Fatal("keystore watcher didn't start in time")
|
||||||
}
|
}
|
||||||
// Create the directory and copy a key file into it.
|
// Copy a key file into it
|
||||||
os.MkdirAll(dir, 0700)
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
file := filepath.Join(dir, "aaa")
|
file := filepath.Join(dir, "aaa")
|
||||||
|
|
||||||
// Place one of our testfiles in there
|
// Place one of our testfiles in there
|
||||||
|
|
|
||||||
|
|
@ -88,16 +88,6 @@ func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
|
||||||
return ks
|
return ks
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPlaintextKeyStore creates a keystore for the given directory.
|
|
||||||
// Deprecated: Use NewKeyStore.
|
|
||||||
func NewPlaintextKeyStore(keydir string) *KeyStore {
|
|
||||||
keydir, _ = filepath.Abs(keydir)
|
|
||||||
ks := &KeyStore{storage: &keyStorePlain{keydir}}
|
|
||||||
ks.init(keydir)
|
|
||||||
|
|
||||||
return ks
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ks *KeyStore) init(keydir string) {
|
func (ks *KeyStore) init(keydir string) {
|
||||||
// Lock the mutex since the account cache might call back with events
|
// Lock the mutex since the account cache might call back with events
|
||||||
ks.mu.Lock()
|
ks.mu.Lock()
|
||||||
|
|
@ -336,11 +326,10 @@ func (ks *KeyStore) Unlock(a accounts.Account, passphrase string) error {
|
||||||
// Lock removes the private key with the given address from memory.
|
// Lock removes the private key with the given address from memory.
|
||||||
func (ks *KeyStore) Lock(addr common.Address) error {
|
func (ks *KeyStore) Lock(addr common.Address) error {
|
||||||
ks.mu.Lock()
|
ks.mu.Lock()
|
||||||
if unl, found := ks.unlocked[addr]; found {
|
unl, found := ks.unlocked[addr]
|
||||||
ks.mu.Unlock()
|
ks.mu.Unlock()
|
||||||
|
if found {
|
||||||
ks.expire(addr, unl, time.Duration(0)*time.Nanosecond)
|
ks.expire(addr, unl, time.Duration(0)*time.Nanosecond)
|
||||||
} else {
|
|
||||||
ks.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -545,7 +534,5 @@ func (ks *KeyStore) isUpdating() bool {
|
||||||
// zeroKey zeroes a private key in memory.
|
// zeroKey zeroes a private key in memory.
|
||||||
func zeroKey(k *ecdsa.PrivateKey) {
|
func zeroKey(k *ecdsa.PrivateKey) {
|
||||||
b := k.D.Bits()
|
b := k.D.Bits()
|
||||||
for i := range b {
|
clear(b)
|
||||||
b[i] = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -30,14 +31,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var testSigData = make([]byte, 32)
|
var testSigData = make([]byte, 32)
|
||||||
|
|
||||||
func TestKeyStore(t *testing.T) {
|
func TestKeyStore(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
dir, ks := tmpKeyStore(t, true)
|
dir, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
a, err := ks.NewAccount("foo")
|
a, err := ks.NewAccount("foo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -80,7 +80,7 @@ func TestKeyStore(t *testing.T) {
|
||||||
|
|
||||||
func TestSign(t *testing.T) {
|
func TestSign(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
pass := "" // not used but required by API
|
pass := "" // not used but required by API
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ func TestSign(t *testing.T) {
|
||||||
|
|
||||||
func TestSignWithPassphrase(t *testing.T) {
|
func TestSignWithPassphrase(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
pass := "passwd"
|
pass := "passwd"
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ func TestSignWithPassphrase(t *testing.T) {
|
||||||
|
|
||||||
func TestTimedUnlock(t *testing.T) {
|
func TestTimedUnlock(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
|
|
||||||
|
|
@ -165,7 +165,7 @@ func TestTimedUnlock(t *testing.T) {
|
||||||
|
|
||||||
func TestOverrideUnlock(t *testing.T) {
|
func TestOverrideUnlock(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, false)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
|
|
||||||
|
|
@ -208,7 +208,7 @@ func TestOverrideUnlock(t *testing.T) {
|
||||||
// This test should fail under -race if signing races the expiration goroutine.
|
// This test should fail under -race if signing races the expiration goroutine.
|
||||||
func TestSignRace(t *testing.T) {
|
func TestSignRace(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, false)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
// Create a test account.
|
// Create a test account.
|
||||||
a1, err := ks.NewAccount("")
|
a1, err := ks.NewAccount("")
|
||||||
|
|
@ -257,7 +257,7 @@ func waitForKsUpdating(t *testing.T, ks *KeyStore, wantStatus bool, maxTime time
|
||||||
func TestWalletNotifierLifecycle(t *testing.T) {
|
func TestWalletNotifierLifecycle(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
// Create a temporary keystore to test with
|
// Create a temporary keystore to test with
|
||||||
_, ks := tmpKeyStore(t, false)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
// Ensure that the notification updater is not running yet
|
// Ensure that the notification updater is not running yet
|
||||||
time.Sleep(250 * time.Millisecond)
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
|
@ -305,7 +305,7 @@ type walletEvent struct {
|
||||||
// or deleted from the keystore.
|
// or deleted from the keystore.
|
||||||
func TestWalletNotifications(t *testing.T) {
|
func TestWalletNotifications(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, false)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
// Subscribe to the wallet feed and collect events.
|
// Subscribe to the wallet feed and collect events.
|
||||||
var (
|
var (
|
||||||
|
|
@ -375,8 +375,7 @@ func TestWalletNotifications(t *testing.T) {
|
||||||
// TestImportECDSA tests the import functionality of a keystore.
|
// TestImportECDSA tests the import functionality of a keystore.
|
||||||
func TestImportECDSA(t *testing.T) {
|
func TestImportECDSA(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to generate key: %v", key)
|
t.Fatalf("failed to generate key: %v", key)
|
||||||
|
|
@ -398,8 +397,7 @@ func TestImportECDSA(t *testing.T) {
|
||||||
// TestImportExport tests the import and export functionality of a keystore.
|
// TestImportExport tests the import and export functionality of a keystore.
|
||||||
func TestImportExport(t *testing.T) {
|
func TestImportExport(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
acc, err := ks.NewAccount("old")
|
acc, err := ks.NewAccount("old")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create account: %v", acc)
|
t.Fatalf("failed to create account: %v", acc)
|
||||||
|
|
@ -409,8 +407,7 @@ func TestImportExport(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to export account: %v", acc)
|
t.Fatalf("failed to export account: %v", acc)
|
||||||
}
|
}
|
||||||
|
_, ks2 := tmpKeyStore(t)
|
||||||
_, ks2 := tmpKeyStore(t, true)
|
|
||||||
if _, err = ks2.Import(json, "old", "old"); err == nil {
|
if _, err = ks2.Import(json, "old", "old"); err == nil {
|
||||||
t.Errorf("importing with invalid password succeeded")
|
t.Errorf("importing with invalid password succeeded")
|
||||||
}
|
}
|
||||||
|
|
@ -433,8 +430,7 @@ func TestImportExport(t *testing.T) {
|
||||||
// This test should fail under -race if importing races.
|
// This test should fail under -race if importing races.
|
||||||
func TestImportRace(t *testing.T) {
|
func TestImportRace(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t)
|
||||||
|
|
||||||
acc, err := ks.NewAccount("old")
|
acc, err := ks.NewAccount("old")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create account: %v", acc)
|
t.Fatalf("failed to create account: %v", acc)
|
||||||
|
|
@ -444,8 +440,7 @@ func TestImportRace(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to export account: %v", acc)
|
t.Fatalf("failed to export account: %v", acc)
|
||||||
}
|
}
|
||||||
|
_, ks2 := tmpKeyStore(t)
|
||||||
_, ks2 := tmpKeyStore(t, true)
|
|
||||||
var atom atomic.Uint32
|
var atom atomic.Uint32
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
|
@ -506,13 +501,7 @@ func checkEvents(t *testing.T, want []walletEvent, have []walletEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tmpKeyStore(t *testing.T, encrypted bool) (string, *KeyStore) {
|
func tmpKeyStore(t *testing.T) (string, *KeyStore) {
|
||||||
d := t.TempDir()
|
d := t.TempDir()
|
||||||
|
return d, NewKeyStore(d, veryLightScryptN, veryLightScryptP)
|
||||||
newKs := NewPlaintextKeyStore
|
|
||||||
if encrypted {
|
|
||||||
newKs = func(kd string) *KeyStore { return NewKeyStore(kd, veryLightScryptN, veryLightScryptP) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return d, newKs(d)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ func (ks keyStorePassphrase) JoinPath(filename string) string {
|
||||||
return filepath.Join(ks.keysDirPath, filename)
|
return filepath.Join(ks.keysDirPath, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encryptdata encrypts the data given as 'data' with the password 'auth'.
|
// EncryptDataV3 encrypts the data given as 'data' with the password 'auth'.
|
||||||
func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) {
|
func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) {
|
||||||
salt := make([]byte, 32)
|
salt := make([]byte, 32)
|
||||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,9 @@ func NewManager(config *Config, backends ...Backend) *Manager {
|
||||||
|
|
||||||
// Close terminates the account manager's internal notification processes.
|
// Close terminates the account manager's internal notification processes.
|
||||||
func (am *Manager) Close() error {
|
func (am *Manager) Close() error {
|
||||||
|
for _, w := range am.wallets {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
errc := make(chan error)
|
errc := make(chan error)
|
||||||
am.quit <- errc
|
am.quit <- errc
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ func (hub *Hub) readPairings() error {
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer pairingFile.Close()
|
||||||
|
|
||||||
pairingData, err := io.ReadAll(pairingFile)
|
pairingData, err := io.ReadAll(pairingFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -256,7 +257,7 @@ func (hub *Hub) refreshWallets() {
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Card connected, start tracking in amongst the wallets
|
// Card connected, start tracking among the wallets
|
||||||
hub.wallets[reader] = wallet
|
hub.wallets[reader] = wallet
|
||||||
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
|
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -73,6 +73,14 @@ var (
|
||||||
DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes())
|
DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// PinRegexp is the regular expression used to validate PIN codes.
|
||||||
|
pinRegexp = regexp.MustCompile(`^[0-9]{6,}$`)
|
||||||
|
|
||||||
|
// PukRegexp is the regular expression used to validate PUK codes.
|
||||||
|
pukRegexp = regexp.MustCompile(`^[0-9]{12,}$`)
|
||||||
|
)
|
||||||
|
|
||||||
// List of APDU command-related constants
|
// List of APDU command-related constants
|
||||||
const (
|
const (
|
||||||
claISO7816 = 0
|
claISO7816 = 0
|
||||||
|
|
@ -394,7 +402,7 @@ func (w *Wallet) Open(passphrase string) error {
|
||||||
case passphrase == "":
|
case passphrase == "":
|
||||||
return ErrPINUnblockNeeded
|
return ErrPINUnblockNeeded
|
||||||
case status.PinRetryCount > 0:
|
case status.PinRetryCount > 0:
|
||||||
if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) {
|
if !pinRegexp.MatchString(passphrase) {
|
||||||
w.log.Error("PIN needs to be at least 6 digits")
|
w.log.Error("PIN needs to be at least 6 digits")
|
||||||
return ErrPINNeeded
|
return ErrPINNeeded
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +411,7 @@ func (w *Wallet) Open(passphrase string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) {
|
if !pukRegexp.MatchString(passphrase) {
|
||||||
w.log.Error("PUK needs to be at least 12 digits")
|
w.log.Error("PUK needs to be at least 12 digits")
|
||||||
return ErrPINUnblockNeeded
|
return ErrPINUnblockNeeded
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/karalabe/usb"
|
"github.com/karalabe/hid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
|
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
|
||||||
|
|
@ -109,7 +109,7 @@ func NewTrezorHubWithWebUSB() (*Hub, error) {
|
||||||
|
|
||||||
// newHub creates a new hardware wallet manager for generic USB devices.
|
// newHub creates a new hardware wallet manager for generic USB devices.
|
||||||
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
|
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
|
||||||
if !usb.Supported() {
|
if !hid.Supported() {
|
||||||
return nil, errors.New("unsupported platform")
|
return nil, errors.New("unsupported platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,7 +158,7 @@ func (hub *Hub) refreshWallets() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Retrieve the current list of USB wallet devices
|
// Retrieve the current list of USB wallet devices
|
||||||
var devices []usb.DeviceInfo
|
var devices []hid.DeviceInfo
|
||||||
|
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
// hidapi on Linux opens the device during enumeration to retrieve some infos,
|
// hidapi on Linux opens the device during enumeration to retrieve some infos,
|
||||||
|
|
@ -173,8 +173,7 @@ func (hub *Hub) refreshWallets() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
infos, err := hid.Enumerate(hub.vendorID, 0)
|
||||||
infos, err := usb.Enumerate(hub.vendorID, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failcount := hub.enumFails.Add(1)
|
failcount := hub.enumFails.Add(1)
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
// This file contains the implementation for interacting with the Ledger hardware
|
// This file contains the implementation for interacting with the Ledger hardware
|
||||||
// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
|
// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
|
||||||
// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc
|
// https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc
|
||||||
|
|
||||||
package usbwallet
|
package usbwallet
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.common;
|
package hw.trezor.messages.common;
|
||||||
|
|
||||||
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response: Success of the previous request
|
* Response: Success of the previous request
|
||||||
* @end
|
* @end
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.ethereum;
|
package hw.trezor.messages.ethereum;
|
||||||
|
|
||||||
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
// Sugar for easier handling in Java
|
// Sugar for easier handling in Java
|
||||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
option java_outer_classname = "TrezorMessageEthereum";
|
option java_outer_classname = "TrezorMessageEthereum";
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.management;
|
package hw.trezor.messages.management;
|
||||||
|
|
||||||
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
// Sugar for easier handling in Java
|
// Sugar for easier handling in Java
|
||||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
option java_outer_classname = "TrezorMessageManagement";
|
option java_outer_classname = "TrezorMessageManagement";
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -9,11 +9,12 @@ package hw.trezor.messages;
|
||||||
* Messages for TREZOR communication
|
* Messages for TREZOR communication
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
// Sugar for easier handling in Java
|
// Sugar for easier handling in Java
|
||||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
option java_outer_classname = "TrezorMessage";
|
option java_outer_classname = "TrezorMessage";
|
||||||
|
|
||||||
option go_package = "hw.trezor.messages";
|
|
||||||
|
|
||||||
import "google/protobuf/descriptor.proto";
|
import "google/protobuf/descriptor.proto";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
// This file contains the implementation for interacting with the Trezor hardware
|
// This file contains the implementation for interacting with the Trezor hardware
|
||||||
// wallets. The wire protocol spec can be found on the SatoshiLabs website:
|
// wallets. The wire protocol spec can be found on the SatoshiLabs website:
|
||||||
// https://wiki.trezor.io/Developers_guide-Message_Workflows
|
// https://docs.trezor.io/trezor-firmware/common/message-workflows.html
|
||||||
|
|
||||||
// !!! STAHP !!!
|
// !!! STAHP !!!
|
||||||
//
|
//
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go`
|
// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go`
|
||||||
// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...`
|
// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...`
|
||||||
|
|
||||||
//go:generate protoc -I/usr/local/include:. --go_out=import_path=trezor:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
||||||
|
|
||||||
// Package trezor contains the wire protocol.
|
// Package trezor contains the wire protocol.
|
||||||
package trezor
|
package trezor
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/karalabe/usb"
|
"github.com/karalabe/hid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Maximum time between wallet health checks to detect USB unplugs.
|
// Maximum time between wallet health checks to detect USB unplugs.
|
||||||
|
|
@ -79,8 +79,8 @@ type wallet struct {
|
||||||
driver driver // Hardware implementation of the low level device operations
|
driver driver // Hardware implementation of the low level device operations
|
||||||
url *accounts.URL // Textual URL uniquely identifying this wallet
|
url *accounts.URL // Textual URL uniquely identifying this wallet
|
||||||
|
|
||||||
info usb.DeviceInfo // Known USB device infos about the wallet
|
info hid.DeviceInfo // Known USB device infos about the wallet
|
||||||
device usb.Device // USB device advertising itself as a hardware wallet
|
device hid.Device // USB device advertising itself as a hardware wallet
|
||||||
|
|
||||||
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
|
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
|
||||||
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
|
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
|
||||||
|
|
@ -505,6 +505,10 @@ func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
|
||||||
w.stateLock.Lock()
|
w.stateLock.Lock()
|
||||||
defer w.stateLock.Unlock()
|
defer w.stateLock.Unlock()
|
||||||
|
|
||||||
|
if w.device == nil {
|
||||||
|
return accounts.Account{}, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := w.paths[address]; !ok {
|
if _, ok := w.paths[address]; !ok {
|
||||||
w.accounts = append(w.accounts, account)
|
w.accounts = append(w.accounts, account)
|
||||||
w.paths[address] = make(accounts.DerivationPath, len(path))
|
w.paths[address] = make(accounts.DerivationPath, len(path))
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,10 @@ for:
|
||||||
- image: Ubuntu
|
- image: Ubuntu
|
||||||
build_script:
|
build_script:
|
||||||
- go run build/ci.go lint
|
- go run build/ci.go lint
|
||||||
|
- go run build/ci.go generate -verify
|
||||||
- go run build/ci.go install -dlgo
|
- go run build/ci.go install -dlgo
|
||||||
test_script:
|
test_script:
|
||||||
- go run build/ci.go test -dlgo
|
- go run build/ci.go test -dlgo -short
|
||||||
|
|
||||||
# linux/386 is disabled.
|
# linux/386 is disabled.
|
||||||
- matrix:
|
- matrix:
|
||||||
|
|
|
||||||
163
beacon/blsync/block_sync.go
Executable file
163
beacon/blsync/block_sync.go
Executable file
|
|
@ -0,0 +1,163 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package blsync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/sync"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// beaconBlockSync implements request.Module; it fetches the beacon blocks belonging
|
||||||
|
// to the validated and prefetch heads.
|
||||||
|
type beaconBlockSync struct {
|
||||||
|
recentBlocks *lru.Cache[common.Hash, *types.BeaconBlock]
|
||||||
|
locked map[common.Hash]request.ServerAndID
|
||||||
|
serverHeads map[request.Server]common.Hash
|
||||||
|
headTracker headTracker
|
||||||
|
|
||||||
|
lastHeadInfo types.HeadInfo
|
||||||
|
chainHeadFeed event.FeedOf[types.ChainHeadEvent]
|
||||||
|
}
|
||||||
|
|
||||||
|
type headTracker interface {
|
||||||
|
PrefetchHead() types.HeadInfo
|
||||||
|
ValidatedOptimistic() (types.OptimisticUpdate, bool)
|
||||||
|
ValidatedFinality() (types.FinalityUpdate, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBeaconBlockSync returns a new beaconBlockSync.
|
||||||
|
func newBeaconBlockSync(headTracker headTracker) *beaconBlockSync {
|
||||||
|
return &beaconBlockSync{
|
||||||
|
headTracker: headTracker,
|
||||||
|
recentBlocks: lru.NewCache[common.Hash, *types.BeaconBlock](10),
|
||||||
|
locked: make(map[common.Hash]request.ServerAndID),
|
||||||
|
serverHeads: make(map[request.Server]common.Hash),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *beaconBlockSync) SubscribeChainHead(ch chan<- types.ChainHeadEvent) event.Subscription {
|
||||||
|
return s.chainHeadFeed.Subscribe(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process implements request.Module.
|
||||||
|
func (s *beaconBlockSync) Process(requester request.Requester, events []request.Event) {
|
||||||
|
for _, event := range events {
|
||||||
|
switch event.Type {
|
||||||
|
case request.EvResponse, request.EvFail, request.EvTimeout:
|
||||||
|
sid, req, resp := event.RequestInfo()
|
||||||
|
blockRoot := common.Hash(req.(sync.ReqBeaconBlock))
|
||||||
|
log.Debug("Beacon block event", "type", event.Type.Name, "hash", blockRoot)
|
||||||
|
if resp != nil {
|
||||||
|
s.recentBlocks.Add(blockRoot, resp.(*types.BeaconBlock))
|
||||||
|
}
|
||||||
|
if s.locked[blockRoot] == sid {
|
||||||
|
delete(s.locked, blockRoot)
|
||||||
|
}
|
||||||
|
case sync.EvNewHead:
|
||||||
|
s.serverHeads[event.Server] = event.Data.(types.HeadInfo).BlockRoot
|
||||||
|
case request.EvUnregistered:
|
||||||
|
delete(s.serverHeads, event.Server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.updateEventFeed()
|
||||||
|
// request validated head block if unavailable and not yet requested
|
||||||
|
if vh, ok := s.headTracker.ValidatedOptimistic(); ok {
|
||||||
|
s.tryRequestBlock(requester, vh.Attested.Hash(), false)
|
||||||
|
}
|
||||||
|
// request prefetch head if the given server has announced it
|
||||||
|
if prefetchHead := s.headTracker.PrefetchHead().BlockRoot; prefetchHead != (common.Hash{}) {
|
||||||
|
s.tryRequestBlock(requester, prefetchHead, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *beaconBlockSync) tryRequestBlock(requester request.Requester, blockRoot common.Hash, needSameHead bool) {
|
||||||
|
if _, ok := s.recentBlocks.Get(blockRoot); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := s.locked[blockRoot]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, server := range requester.CanSendTo() {
|
||||||
|
if needSameHead && (s.serverHeads[server] != blockRoot) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
id := requester.Send(server, sync.ReqBeaconBlock(blockRoot))
|
||||||
|
s.locked[blockRoot] = request.ServerAndID{Server: server, ID: id}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockHeadInfo(block *types.BeaconBlock) types.HeadInfo {
|
||||||
|
if block == nil {
|
||||||
|
return types.HeadInfo{}
|
||||||
|
}
|
||||||
|
return types.HeadInfo{Slot: block.Slot(), BlockRoot: block.Root()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *beaconBlockSync) updateEventFeed() {
|
||||||
|
optimistic, ok := s.headTracker.ValidatedOptimistic()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validatedHead := optimistic.Attested.Hash()
|
||||||
|
headBlock, ok := s.recentBlocks.Get(validatedHead)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalizedHash common.Hash
|
||||||
|
if finality, ok := s.headTracker.ValidatedFinality(); ok {
|
||||||
|
he := optimistic.Attested.Epoch()
|
||||||
|
fe := finality.Attested.Header.Epoch()
|
||||||
|
switch {
|
||||||
|
case he == fe:
|
||||||
|
finalizedHash = finality.Finalized.PayloadHeader.BlockHash()
|
||||||
|
case he < fe:
|
||||||
|
return
|
||||||
|
case he == fe+1:
|
||||||
|
parent, ok := s.recentBlocks.Get(optimistic.Attested.ParentRoot)
|
||||||
|
if !ok || parent.Slot()/params.EpochLength == fe {
|
||||||
|
return // head is at first slot of next epoch, wait for finality update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headInfo := blockHeadInfo(headBlock)
|
||||||
|
if headInfo == s.lastHeadInfo {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.lastHeadInfo = headInfo
|
||||||
|
|
||||||
|
// new head block and finality info available; extract executable data and send event to feed
|
||||||
|
execBlock, err := headBlock.ExecutionPayload()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error extracting execution block from validated beacon block", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.chainHeadFeed.Send(types.ChainHeadEvent{
|
||||||
|
BeaconHead: optimistic.Attested.Header,
|
||||||
|
Block: execBlock,
|
||||||
|
Finalized: finalizedHash,
|
||||||
|
})
|
||||||
|
}
|
||||||
160
beacon/blsync/block_sync_test.go
Normal file
160
beacon/blsync/block_sync_test.go
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package blsync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/sync"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testServer1 = testServer("testServer1")
|
||||||
|
testServer2 = testServer("testServer2")
|
||||||
|
|
||||||
|
testBlock1 = types.NewBeaconBlock(&deneb.BeaconBlock{
|
||||||
|
Slot: 123,
|
||||||
|
Body: deneb.BeaconBlockBody{
|
||||||
|
ExecutionPayload: deneb.ExecutionPayload{
|
||||||
|
BlockNumber: 456,
|
||||||
|
BlockHash: zrntcommon.Hash32(common.HexToHash("905ac721c4058d9ed40b27b6b9c1bdd10d4333e4f3d9769100bf9dfb80e5d1f6")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
testBlock2 = types.NewBeaconBlock(&deneb.BeaconBlock{
|
||||||
|
Slot: 124,
|
||||||
|
Body: deneb.BeaconBlockBody{
|
||||||
|
ExecutionPayload: deneb.ExecutionPayload{
|
||||||
|
BlockNumber: 457,
|
||||||
|
BlockHash: zrntcommon.Hash32(common.HexToHash("011703f39c664efc1c6cf5f49ca09b595581eec572d4dfddd3d6179a9e63e655")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
type testServer string
|
||||||
|
|
||||||
|
func (t testServer) Name() string {
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlockSync(t *testing.T) {
|
||||||
|
ht := &testHeadTracker{}
|
||||||
|
blockSync := newBeaconBlockSync(ht)
|
||||||
|
headCh := make(chan types.ChainHeadEvent, 16)
|
||||||
|
blockSync.SubscribeChainHead(headCh)
|
||||||
|
ts := sync.NewTestScheduler(t, blockSync)
|
||||||
|
ts.AddServer(testServer1, 1)
|
||||||
|
ts.AddServer(testServer2, 1)
|
||||||
|
|
||||||
|
expHeadBlock := func(expHead *types.BeaconBlock) {
|
||||||
|
t.Helper()
|
||||||
|
var expNumber, headNumber uint64
|
||||||
|
if expHead != nil {
|
||||||
|
p, _ := expHead.ExecutionPayload()
|
||||||
|
expNumber = p.NumberU64()
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case event := <-headCh:
|
||||||
|
headNumber = event.Block.NumberU64()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if headNumber != expNumber {
|
||||||
|
t.Errorf("Wrong head block, expected block number %d, got %d)", expNumber, headNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no block requests expected until head tracker knows about a head
|
||||||
|
ts.Run(1)
|
||||||
|
expHeadBlock(nil)
|
||||||
|
|
||||||
|
// set block 1 as prefetch head, announced by server 2
|
||||||
|
head1 := blockHeadInfo(testBlock1)
|
||||||
|
ht.prefetch = head1
|
||||||
|
ts.ServerEvent(sync.EvNewHead, testServer2, head1)
|
||||||
|
|
||||||
|
// expect request to server 2 which has announced the head
|
||||||
|
ts.Run(2, testServer2, sync.ReqBeaconBlock(head1.BlockRoot))
|
||||||
|
|
||||||
|
// valid response
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testBlock1)
|
||||||
|
ts.AddAllowance(testServer2, 1)
|
||||||
|
ts.Run(3)
|
||||||
|
// head block still not expected as the fetched block is not the validated head yet
|
||||||
|
expHeadBlock(nil)
|
||||||
|
|
||||||
|
// set as validated head, expect no further requests but block 1 set as head block
|
||||||
|
ht.validated.Header = testBlock1.Header()
|
||||||
|
ts.Run(4)
|
||||||
|
expHeadBlock(testBlock1)
|
||||||
|
|
||||||
|
// set block 2 as prefetch head, announced by server 1
|
||||||
|
head2 := blockHeadInfo(testBlock2)
|
||||||
|
ht.prefetch = head2
|
||||||
|
ts.ServerEvent(sync.EvNewHead, testServer1, head2)
|
||||||
|
// expect request to server 1
|
||||||
|
ts.Run(5, testServer1, sync.ReqBeaconBlock(head2.BlockRoot))
|
||||||
|
|
||||||
|
// req2 fails, no further requests expected because server 2 has not announced it
|
||||||
|
ts.RequestEvent(request.EvFail, ts.Request(5, 1), nil)
|
||||||
|
ts.Run(6)
|
||||||
|
|
||||||
|
// set as validated head before retrieving block; now it's assumed to be available from server 2 too
|
||||||
|
ht.validated.Header = testBlock2.Header()
|
||||||
|
// expect req2 retry to server 2
|
||||||
|
ts.Run(7, testServer2, sync.ReqBeaconBlock(head2.BlockRoot))
|
||||||
|
// now head block should be unavailable again
|
||||||
|
expHeadBlock(nil)
|
||||||
|
|
||||||
|
// valid response, now head block should be block 2 immediately as it is already validated
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testBlock2)
|
||||||
|
ts.Run(8)
|
||||||
|
expHeadBlock(testBlock2)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testHeadTracker struct {
|
||||||
|
prefetch types.HeadInfo
|
||||||
|
validated types.SignedHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testHeadTracker) PrefetchHead() types.HeadInfo {
|
||||||
|
return h.prefetch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testHeadTracker) ValidatedOptimistic() (types.OptimisticUpdate, bool) {
|
||||||
|
return types.OptimisticUpdate{
|
||||||
|
Attested: types.HeaderWithExecProof{Header: h.validated.Header},
|
||||||
|
Signature: h.validated.Signature,
|
||||||
|
SignatureSlot: h.validated.SignatureSlot,
|
||||||
|
}, h.validated.Header != (types.Header{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add test case for finality
|
||||||
|
func (h *testHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) {
|
||||||
|
finalized := types.NewExecutionHeader(new(deneb.ExecutionPayloadHeader))
|
||||||
|
return types.FinalityUpdate{
|
||||||
|
Attested: types.HeaderWithExecProof{Header: h.validated.Header},
|
||||||
|
Finalized: types.HeaderWithExecProof{PayloadHeader: finalized},
|
||||||
|
Signature: h.validated.Signature,
|
||||||
|
SignatureSlot: h.validated.SignatureSlot,
|
||||||
|
}, h.validated.Header != (types.Header{})
|
||||||
|
}
|
||||||
115
beacon/blsync/client.go
Normal file
115
beacon/blsync/client.go
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package blsync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/api"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/sync"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
urls []string
|
||||||
|
customHeader map[string]string
|
||||||
|
chainConfig *lightClientConfig
|
||||||
|
scheduler *request.Scheduler
|
||||||
|
blockSync *beaconBlockSync
|
||||||
|
engineRPC *rpc.Client
|
||||||
|
|
||||||
|
chainHeadSub event.Subscription
|
||||||
|
engineClient *engineClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(ctx *cli.Context) *Client {
|
||||||
|
if !ctx.IsSet(utils.BeaconApiFlag.Name) {
|
||||||
|
utils.Fatalf("Beacon node light client API URL not specified")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
chainConfig = makeChainConfig(ctx)
|
||||||
|
customHeader = make(map[string]string)
|
||||||
|
)
|
||||||
|
for _, s := range ctx.StringSlice(utils.BeaconApiHeaderFlag.Name) {
|
||||||
|
kv := strings.Split(s, ":")
|
||||||
|
if len(kv) != 2 {
|
||||||
|
utils.Fatalf("Invalid custom API header entry: %s", s)
|
||||||
|
}
|
||||||
|
customHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// create data structures
|
||||||
|
var (
|
||||||
|
db = memorydb.New()
|
||||||
|
threshold = ctx.Int(utils.BeaconThresholdFlag.Name)
|
||||||
|
committeeChain = light.NewCommitteeChain(db, chainConfig.ChainConfig, threshold, !ctx.Bool(utils.BeaconNoFilterFlag.Name))
|
||||||
|
headTracker = light.NewHeadTracker(committeeChain, threshold)
|
||||||
|
)
|
||||||
|
headSync := sync.NewHeadSync(headTracker, committeeChain)
|
||||||
|
|
||||||
|
// set up scheduler and sync modules
|
||||||
|
scheduler := request.NewScheduler()
|
||||||
|
checkpointInit := sync.NewCheckpointInit(committeeChain, chainConfig.Checkpoint)
|
||||||
|
forwardSync := sync.NewForwardUpdateSync(committeeChain)
|
||||||
|
beaconBlockSync := newBeaconBlockSync(headTracker)
|
||||||
|
scheduler.RegisterTarget(headTracker)
|
||||||
|
scheduler.RegisterTarget(committeeChain)
|
||||||
|
scheduler.RegisterModule(checkpointInit, "checkpointInit")
|
||||||
|
scheduler.RegisterModule(forwardSync, "forwardSync")
|
||||||
|
scheduler.RegisterModule(headSync, "headSync")
|
||||||
|
scheduler.RegisterModule(beaconBlockSync, "beaconBlockSync")
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
scheduler: scheduler,
|
||||||
|
urls: ctx.StringSlice(utils.BeaconApiFlag.Name),
|
||||||
|
customHeader: customHeader,
|
||||||
|
chainConfig: &chainConfig,
|
||||||
|
blockSync: beaconBlockSync,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetEngineRPC(engine *rpc.Client) {
|
||||||
|
c.engineRPC = engine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Start() error {
|
||||||
|
headCh := make(chan types.ChainHeadEvent, 16)
|
||||||
|
c.chainHeadSub = c.blockSync.SubscribeChainHead(headCh)
|
||||||
|
c.engineClient = startEngineClient(c.chainConfig, c.engineRPC, headCh)
|
||||||
|
|
||||||
|
c.scheduler.Start()
|
||||||
|
for _, url := range c.urls {
|
||||||
|
beaconApi := api.NewBeaconLightApi(url, c.customHeader)
|
||||||
|
c.scheduler.RegisterServer(request.NewServer(api.NewApiServer(beaconApi), &mclock.System{}))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Stop() error {
|
||||||
|
c.engineClient.stop()
|
||||||
|
c.chainHeadSub.Unsubscribe()
|
||||||
|
c.scheduler.Stop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
129
beacon/blsync/config.go
Normal file
129
beacon/blsync/config.go
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
// Copyright 2022 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package blsync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// lightClientConfig contains beacon light client configuration
|
||||||
|
type lightClientConfig struct {
|
||||||
|
*types.ChainConfig
|
||||||
|
Checkpoint common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
MainnetConfig = lightClientConfig{
|
||||||
|
ChainConfig: (&types.ChainConfig{
|
||||||
|
GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"),
|
||||||
|
GenesisTime: 1606824023,
|
||||||
|
}).
|
||||||
|
AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
|
||||||
|
AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
|
||||||
|
AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
|
||||||
|
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
|
||||||
|
AddFork("DENEB", 269568, []byte{4, 0, 0, 0}),
|
||||||
|
Checkpoint: common.HexToHash("0x388be41594ec7d6a6894f18c73f3469f07e2c19a803de4755d335817ed8e2e5a"),
|
||||||
|
}
|
||||||
|
|
||||||
|
SepoliaConfig = lightClientConfig{
|
||||||
|
ChainConfig: (&types.ChainConfig{
|
||||||
|
GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
|
||||||
|
GenesisTime: 1655733600,
|
||||||
|
}).
|
||||||
|
AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
|
||||||
|
AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
|
||||||
|
AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
|
||||||
|
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
|
||||||
|
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
|
||||||
|
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
|
||||||
|
}
|
||||||
|
|
||||||
|
GoerliConfig = lightClientConfig{
|
||||||
|
ChainConfig: (&types.ChainConfig{
|
||||||
|
GenesisValidatorsRoot: common.HexToHash("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"),
|
||||||
|
GenesisTime: 1614588812,
|
||||||
|
}).
|
||||||
|
AddFork("GENESIS", 0, []byte{0, 0, 16, 32}).
|
||||||
|
AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}).
|
||||||
|
AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}).
|
||||||
|
AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}).
|
||||||
|
AddFork("DENEB", 231680, []byte{4, 0, 16, 32}),
|
||||||
|
Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeChainConfig(ctx *cli.Context) lightClientConfig {
|
||||||
|
var config lightClientConfig
|
||||||
|
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
|
||||||
|
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
|
||||||
|
switch {
|
||||||
|
case ctx.Bool(utils.MainnetFlag.Name):
|
||||||
|
config = MainnetConfig
|
||||||
|
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||||
|
config = SepoliaConfig
|
||||||
|
case ctx.Bool(utils.GoerliFlag.Name):
|
||||||
|
config = GoerliConfig
|
||||||
|
default:
|
||||||
|
if !customConfig {
|
||||||
|
config = MainnetConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Genesis root and time should always be specified together with custom chain config
|
||||||
|
if customConfig {
|
||||||
|
if !ctx.IsSet(utils.BeaconGenesisRootFlag.Name) {
|
||||||
|
utils.Fatalf("Custom beacon chain config is specified but genesis root is missing")
|
||||||
|
}
|
||||||
|
if !ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) {
|
||||||
|
utils.Fatalf("Custom beacon chain config is specified but genesis time is missing")
|
||||||
|
}
|
||||||
|
if !ctx.IsSet(utils.BeaconCheckpointFlag.Name) {
|
||||||
|
utils.Fatalf("Custom beacon chain config is specified but checkpoint is missing")
|
||||||
|
}
|
||||||
|
config.ChainConfig = &types.ChainConfig{
|
||||||
|
GenesisTime: ctx.Uint64(utils.BeaconGenesisTimeFlag.Name),
|
||||||
|
}
|
||||||
|
if c, err := hexutil.Decode(ctx.String(utils.BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 {
|
||||||
|
copy(config.GenesisValidatorsRoot[:len(c)], c)
|
||||||
|
} else {
|
||||||
|
utils.Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(utils.BeaconGenesisRootFlag.Name), "error", err)
|
||||||
|
}
|
||||||
|
if err := config.ChainConfig.LoadForks(ctx.String(utils.BeaconConfigFlag.Name)); err != nil {
|
||||||
|
utils.Fatalf("Could not load beacon chain config file", "file name", ctx.String(utils.BeaconConfigFlag.Name), "error", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ctx.IsSet(utils.BeaconGenesisRootFlag.Name) {
|
||||||
|
utils.Fatalf("Genesis root is specified but custom beacon chain config is missing")
|
||||||
|
}
|
||||||
|
if ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) {
|
||||||
|
utils.Fatalf("Genesis time is specified but custom beacon chain config is missing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Checkpoint is required with custom chain config and is optional with pre-defined config
|
||||||
|
if ctx.IsSet(utils.BeaconCheckpointFlag.Name) {
|
||||||
|
if c, err := hexutil.Decode(ctx.String(utils.BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 {
|
||||||
|
copy(config.Checkpoint[:len(c)], c)
|
||||||
|
} else {
|
||||||
|
utils.Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(utils.BeaconCheckpointFlag.Name), "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
150
beacon/blsync/engineclient.go
Normal file
150
beacon/blsync/engineclient.go
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package blsync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
ctypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type engineClient struct {
|
||||||
|
config *lightClientConfig
|
||||||
|
rpc *rpc.Client
|
||||||
|
rootCtx context.Context
|
||||||
|
cancelRoot context.CancelFunc
|
||||||
|
wg sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func startEngineClient(config *lightClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
ec := &engineClient{
|
||||||
|
config: config,
|
||||||
|
rpc: rpc,
|
||||||
|
rootCtx: ctx,
|
||||||
|
cancelRoot: cancel,
|
||||||
|
}
|
||||||
|
ec.wg.Add(1)
|
||||||
|
go ec.updateLoop(headCh)
|
||||||
|
return ec
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *engineClient) stop() {
|
||||||
|
ec.cancelRoot()
|
||||||
|
ec.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) {
|
||||||
|
defer ec.wg.Done()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ec.rootCtx.Done():
|
||||||
|
log.Debug("Stopping engine API update loop")
|
||||||
|
return
|
||||||
|
|
||||||
|
case event := <-headCh:
|
||||||
|
if ec.rpc == nil { // dry run, no engine API specified
|
||||||
|
log.Info("New execution block retrieved", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "finalized", event.Finalized)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fork := ec.config.ForkAtEpoch(event.BeaconHead.Epoch())
|
||||||
|
forkName := strings.ToLower(fork.Name)
|
||||||
|
|
||||||
|
log.Debug("Calling NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash())
|
||||||
|
if status, err := ec.callNewPayload(forkName, event); err == nil {
|
||||||
|
log.Info("Successful NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "status", status)
|
||||||
|
} else {
|
||||||
|
log.Error("Failed NewPayload", "number", event.Block.NumberU64(), "hash", event.Block.Hash(), "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Calling ForkchoiceUpdated", "head", event.Block.Hash())
|
||||||
|
if status, err := ec.callForkchoiceUpdated(forkName, event); err == nil {
|
||||||
|
log.Info("Successful ForkchoiceUpdated", "head", event.Block.Hash(), "status", status)
|
||||||
|
} else {
|
||||||
|
log.Error("Failed ForkchoiceUpdated", "head", event.Block.Hash(), "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) (string, error) {
|
||||||
|
execData := engine.BlockToExecutableData(event.Block, nil, nil).ExecutionPayload
|
||||||
|
|
||||||
|
var (
|
||||||
|
method string
|
||||||
|
params = []any{execData}
|
||||||
|
)
|
||||||
|
switch fork {
|
||||||
|
case "deneb":
|
||||||
|
method = "engine_newPayloadV3"
|
||||||
|
parentBeaconRoot := event.BeaconHead.ParentRoot
|
||||||
|
blobHashes := collectBlobHashes(event.Block)
|
||||||
|
params = append(params, blobHashes, parentBeaconRoot)
|
||||||
|
case "capella":
|
||||||
|
method = "engine_newPayloadV2"
|
||||||
|
default:
|
||||||
|
method = "engine_newPayloadV1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
||||||
|
defer cancel()
|
||||||
|
var resp engine.PayloadStatusV1
|
||||||
|
err := ec.rpc.CallContext(ctx, &resp, method, params...)
|
||||||
|
return resp.Status, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectBlobHashes(b *ctypes.Block) []common.Hash {
|
||||||
|
list := make([]common.Hash, 0)
|
||||||
|
for _, tx := range b.Transactions() {
|
||||||
|
list = append(list, tx.BlobHashes()...)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHeadEvent) (string, error) {
|
||||||
|
update := engine.ForkchoiceStateV1{
|
||||||
|
HeadBlockHash: event.Block.Hash(),
|
||||||
|
SafeBlockHash: event.Finalized,
|
||||||
|
FinalizedBlockHash: event.Finalized,
|
||||||
|
}
|
||||||
|
|
||||||
|
var method string
|
||||||
|
switch fork {
|
||||||
|
case "deneb":
|
||||||
|
method = "engine_forkchoiceUpdatedV3"
|
||||||
|
case "capella":
|
||||||
|
method = "engine_forkchoiceUpdatedV2"
|
||||||
|
default:
|
||||||
|
method = "engine_forkchoiceUpdatedV1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
||||||
|
defer cancel()
|
||||||
|
var resp engine.ForkChoiceResponse
|
||||||
|
err := ec.rpc.CallContext(ctx, &resp, method, update, nil)
|
||||||
|
return resp.PayloadStatus.Status, err
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ package engine
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
@ -26,6 +27,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PayloadVersion denotes the version of PayloadAttributes used to request the
|
||||||
|
// building of the payload to commence.
|
||||||
|
type PayloadVersion byte
|
||||||
|
|
||||||
|
var (
|
||||||
|
PayloadV1 PayloadVersion = 0x1
|
||||||
|
PayloadV2 PayloadVersion = 0x2
|
||||||
|
PayloadV3 PayloadVersion = 0x3
|
||||||
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
||||||
|
|
||||||
// PayloadAttributes describes the environment context in which a block should
|
// PayloadAttributes describes the environment context in which a block should
|
||||||
|
|
@ -115,6 +126,16 @@ type TransitionConfigurationV1 struct {
|
||||||
// PayloadID is an identifier of the payload build process
|
// PayloadID is an identifier of the payload build process
|
||||||
type PayloadID [8]byte
|
type PayloadID [8]byte
|
||||||
|
|
||||||
|
// Version returns the payload version associated with the identifier.
|
||||||
|
func (b PayloadID) Version() PayloadVersion {
|
||||||
|
return PayloadVersion(b[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is returns whether the identifier matches any of provided payload versions.
|
||||||
|
func (b PayloadID) Is(versions ...PayloadVersion) bool {
|
||||||
|
return slices.Contains(versions, b.Version())
|
||||||
|
}
|
||||||
|
|
||||||
func (b PayloadID) String() string {
|
func (b PayloadID) String() string {
|
||||||
return hexutil.Encode(b[:])
|
return hexutil.Encode(b[:])
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +216,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
||||||
if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
|
if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
|
||||||
return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
|
return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
|
||||||
}
|
}
|
||||||
var blobHashes []common.Hash
|
var blobHashes = make([]common.Hash, 0, len(txs))
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
blobHashes = append(blobHashes, tx.BlobHashes()...)
|
blobHashes = append(blobHashes, tx.BlobHashes()...)
|
||||||
}
|
}
|
||||||
|
|
@ -238,8 +259,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
||||||
BlobGasUsed: params.BlobGasUsed,
|
BlobGasUsed: params.BlobGasUsed,
|
||||||
ParentBeaconRoot: beaconRoot,
|
ParentBeaconRoot: beaconRoot,
|
||||||
}
|
}
|
||||||
|
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: params.Withdrawals})
|
||||||
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
|
|
||||||
if block.Hash() != params.BlockHash {
|
if block.Hash() != params.BlockHash {
|
||||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
|
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
|
||||||
}
|
}
|
||||||
|
|
@ -289,3 +309,21 @@ type ExecutionPayloadBodyV1 struct {
|
||||||
TransactionData []hexutil.Bytes `json:"transactions"`
|
TransactionData []hexutil.Bytes `json:"transactions"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client identifiers to support ClientVersionV1.
|
||||||
|
const (
|
||||||
|
ClientCode = "GE"
|
||||||
|
ClientName = "go-ethereum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientVersionV1 contains information which identifies a client implementation.
|
||||||
|
type ClientVersionV1 struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Commit string `json:"commit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ClientVersionV1) String() string {
|
||||||
|
return fmt.Sprintf("%s-%s-%s-%s", v.Code, v.Name, v.Version, v.Commit)
|
||||||
|
}
|
||||||
|
|
|
||||||
114
beacon/light/api/api_server.go
Executable file
114
beacon/light/api/api_server.go
Executable file
|
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/sync"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApiServer is a wrapper around BeaconLightApi that implements request.requestServer.
|
||||||
|
type ApiServer struct {
|
||||||
|
api *BeaconLightApi
|
||||||
|
eventCallback func(event request.Event)
|
||||||
|
unsubscribe func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApiServer creates a new ApiServer.
|
||||||
|
func NewApiServer(api *BeaconLightApi) *ApiServer {
|
||||||
|
return &ApiServer{api: api}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe implements request.requestServer.
|
||||||
|
func (s *ApiServer) Subscribe(eventCallback func(event request.Event)) {
|
||||||
|
s.eventCallback = eventCallback
|
||||||
|
listener := HeadEventListener{
|
||||||
|
OnNewHead: func(slot uint64, blockRoot common.Hash) {
|
||||||
|
log.Debug("New head received", "slot", slot, "blockRoot", blockRoot)
|
||||||
|
eventCallback(request.Event{Type: sync.EvNewHead, Data: types.HeadInfo{Slot: slot, BlockRoot: blockRoot}})
|
||||||
|
},
|
||||||
|
OnOptimistic: func(update types.OptimisticUpdate) {
|
||||||
|
log.Debug("New optimistic update received", "slot", update.Attested.Slot, "blockRoot", update.Attested.Hash(), "signerCount", update.Signature.SignerCount())
|
||||||
|
eventCallback(request.Event{Type: sync.EvNewOptimisticUpdate, Data: update})
|
||||||
|
},
|
||||||
|
OnFinality: func(update types.FinalityUpdate) {
|
||||||
|
log.Debug("New finality update received", "slot", update.Attested.Slot, "blockRoot", update.Attested.Hash(), "signerCount", update.Signature.SignerCount())
|
||||||
|
eventCallback(request.Event{Type: sync.EvNewFinalityUpdate, Data: update})
|
||||||
|
},
|
||||||
|
OnError: func(err error) {
|
||||||
|
log.Warn("Head event stream error", "err", err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.unsubscribe = s.api.StartHeadListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendRequest implements request.requestServer.
|
||||||
|
func (s *ApiServer) SendRequest(id request.ID, req request.Request) {
|
||||||
|
go func() {
|
||||||
|
var resp request.Response
|
||||||
|
var err error
|
||||||
|
switch data := req.(type) {
|
||||||
|
case sync.ReqUpdates:
|
||||||
|
log.Debug("Beacon API: requesting light client update", "reqid", id, "period", data.FirstPeriod, "count", data.Count)
|
||||||
|
var r sync.RespUpdates
|
||||||
|
r.Updates, r.Committees, err = s.api.GetBestUpdatesAndCommittees(data.FirstPeriod, data.Count)
|
||||||
|
resp = r
|
||||||
|
case sync.ReqHeader:
|
||||||
|
var r sync.RespHeader
|
||||||
|
log.Debug("Beacon API: requesting header", "reqid", id, "hash", common.Hash(data))
|
||||||
|
r.Header, r.Canonical, r.Finalized, err = s.api.GetHeader(common.Hash(data))
|
||||||
|
resp = r
|
||||||
|
case sync.ReqCheckpointData:
|
||||||
|
log.Debug("Beacon API: requesting checkpoint data", "reqid", id, "hash", common.Hash(data))
|
||||||
|
resp, err = s.api.GetCheckpointData(common.Hash(data))
|
||||||
|
case sync.ReqBeaconBlock:
|
||||||
|
log.Debug("Beacon API: requesting block", "reqid", id, "hash", common.Hash(data))
|
||||||
|
resp, err = s.api.GetBeaconBlock(common.Hash(data))
|
||||||
|
case sync.ReqFinality:
|
||||||
|
log.Debug("Beacon API: requesting finality update")
|
||||||
|
resp, err = s.api.GetFinalityUpdate()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Beacon API request failed", "type", reflect.TypeOf(req), "reqid", id, "err", err)
|
||||||
|
s.eventCallback(request.Event{Type: request.EvFail, Data: request.RequestResponse{ID: id, Request: req}})
|
||||||
|
} else {
|
||||||
|
log.Debug("Beacon API request answered", "type", reflect.TypeOf(req), "reqid", id)
|
||||||
|
s.eventCallback(request.Event{Type: request.EvResponse, Data: request.RequestResponse{ID: id, Request: req, Response: resp}})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe implements request.requestServer.
|
||||||
|
// Note: Unsubscribe should not be called concurrently with Subscribe.
|
||||||
|
func (s *ApiServer) Unsubscribe() {
|
||||||
|
if s.unsubscribe != nil {
|
||||||
|
s.unsubscribe()
|
||||||
|
s.unsubscribe = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements request.Server
|
||||||
|
func (s *ApiServer) Name() string {
|
||||||
|
return s.api.url
|
||||||
|
}
|
||||||
578
beacon/light/api/light_api.go
Executable file
578
beacon/light/api/light_api.go
Executable file
|
|
@ -0,0 +1,578 @@
|
||||||
|
// Copyright 2022 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more detaiapi.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/donovanhide/eventsource"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNotFound = errors.New("404 Not Found")
|
||||||
|
ErrInternal = errors.New("500 Internal Server Error")
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommitteeUpdate struct {
|
||||||
|
Version string
|
||||||
|
Update types.LightClientUpdate
|
||||||
|
NextSyncCommittee types.SerializedSyncCommittee
|
||||||
|
}
|
||||||
|
|
||||||
|
// See data structure definition here:
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
|
||||||
|
type committeeUpdateJson struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Data committeeUpdateData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type committeeUpdateData struct {
|
||||||
|
Header jsonBeaconHeader `json:"attested_header"`
|
||||||
|
NextSyncCommittee types.SerializedSyncCommittee `json:"next_sync_committee"`
|
||||||
|
NextSyncCommitteeBranch merkle.Values `json:"next_sync_committee_branch"`
|
||||||
|
FinalizedHeader *jsonBeaconHeader `json:"finalized_header,omitempty"`
|
||||||
|
FinalityBranch merkle.Values `json:"finality_branch,omitempty"`
|
||||||
|
SyncAggregate types.SyncAggregate `json:"sync_aggregate"`
|
||||||
|
SignatureSlot common.Decimal `json:"signature_slot"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonBeaconHeader struct {
|
||||||
|
Beacon types.Header `json:"beacon"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonHeaderWithExecProof struct {
|
||||||
|
Beacon types.Header `json:"beacon"`
|
||||||
|
Execution json.RawMessage `json:"execution"`
|
||||||
|
ExecutionBranch merkle.Values `json:"execution_branch"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
|
func (u *CommitteeUpdate) UnmarshalJSON(input []byte) error {
|
||||||
|
var dec committeeUpdateJson
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.Version = dec.Version
|
||||||
|
u.NextSyncCommittee = dec.Data.NextSyncCommittee
|
||||||
|
u.Update = types.LightClientUpdate{
|
||||||
|
AttestedHeader: types.SignedHeader{
|
||||||
|
Header: dec.Data.Header.Beacon,
|
||||||
|
Signature: dec.Data.SyncAggregate,
|
||||||
|
SignatureSlot: uint64(dec.Data.SignatureSlot),
|
||||||
|
},
|
||||||
|
NextSyncCommitteeRoot: u.NextSyncCommittee.Root(),
|
||||||
|
NextSyncCommitteeBranch: dec.Data.NextSyncCommitteeBranch,
|
||||||
|
FinalityBranch: dec.Data.FinalityBranch,
|
||||||
|
}
|
||||||
|
if dec.Data.FinalizedHeader != nil {
|
||||||
|
u.Update.FinalizedHeader = &dec.Data.FinalizedHeader.Beacon
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetcher is an interface useful for debug-harnessing the http api.
|
||||||
|
type fetcher interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeaconLightApi requests light client information from a beacon node REST API.
|
||||||
|
// Note: all required API endpoints are currently only implemented by Lodestar.
|
||||||
|
type BeaconLightApi struct {
|
||||||
|
url string
|
||||||
|
client fetcher
|
||||||
|
customHeaders map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLightApi {
|
||||||
|
return &BeaconLightApi{
|
||||||
|
url: url,
|
||||||
|
client: &http.Client{
|
||||||
|
Timeout: time.Second * 10,
|
||||||
|
},
|
||||||
|
customHeaders: customHeaders,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
|
||||||
|
req, err := http.NewRequest("GET", api.url+path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range api.customHeaders {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
resp, err := api.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case 200:
|
||||||
|
return io.ReadAll(resp.Body)
|
||||||
|
case 404:
|
||||||
|
return nil, ErrNotFound
|
||||||
|
case 500:
|
||||||
|
return nil, ErrInternal
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected error from API endpoint \"%s\": status code %d", path, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error) {
|
||||||
|
return api.httpGet(fmt.Sprintf(format, params...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given
|
||||||
|
// period and full serialized committee for the next period (committee root hash
|
||||||
|
// equals update.NextSyncCommitteeRoot).
|
||||||
|
// Note that the results are validated but the update signature should be verified
|
||||||
|
// by the caller as its validity depends on the update chain.
|
||||||
|
func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) {
|
||||||
|
resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []CommitteeUpdate
|
||||||
|
if err := json.Unmarshal(resp, &data); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if len(data) != int(count) {
|
||||||
|
return nil, nil, errors.New("invalid number of committee updates")
|
||||||
|
}
|
||||||
|
updates := make([]*types.LightClientUpdate, int(count))
|
||||||
|
committees := make([]*types.SerializedSyncCommittee, int(count))
|
||||||
|
for i, d := range data {
|
||||||
|
if d.Update.AttestedHeader.Header.SyncPeriod() != firstPeriod+uint64(i) {
|
||||||
|
return nil, nil, errors.New("wrong committee update header period")
|
||||||
|
}
|
||||||
|
if err := d.Update.Validate(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if d.NextSyncCommittee.Root() != d.Update.NextSyncCommitteeRoot {
|
||||||
|
return nil, nil, errors.New("wrong sync committee root")
|
||||||
|
}
|
||||||
|
updates[i], committees[i] = new(types.LightClientUpdate), new(types.SerializedSyncCommittee)
|
||||||
|
*updates[i], *committees[i] = d.Update, d.NextSyncCommittee
|
||||||
|
}
|
||||||
|
return updates, committees, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOptimisticUpdate fetches the latest available optimistic update.
|
||||||
|
// Note that the signature should be verified by the caller as its validity
|
||||||
|
// depends on the update chain.
|
||||||
|
//
|
||||||
|
// See data structure definition here:
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
||||||
|
func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) {
|
||||||
|
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update")
|
||||||
|
if err != nil {
|
||||||
|
return types.OptimisticUpdate{}, err
|
||||||
|
}
|
||||||
|
return decodeOptimisticUpdate(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) {
|
||||||
|
var data struct {
|
||||||
|
Version string
|
||||||
|
Data struct {
|
||||||
|
Attested jsonHeaderWithExecProof `json:"attested_header"`
|
||||||
|
Aggregate types.SyncAggregate `json:"sync_aggregate"`
|
||||||
|
SignatureSlot common.Decimal `json:"signature_slot"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(enc, &data); err != nil {
|
||||||
|
return types.OptimisticUpdate{}, err
|
||||||
|
}
|
||||||
|
// Decode the execution payload headers.
|
||||||
|
attestedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Attested.Execution)
|
||||||
|
if err != nil {
|
||||||
|
return types.OptimisticUpdate{}, fmt.Errorf("invalid attested header: %v", err)
|
||||||
|
}
|
||||||
|
if data.Data.Attested.Beacon.StateRoot == (common.Hash{}) {
|
||||||
|
// workaround for different event encoding format in Lodestar
|
||||||
|
if err := json.Unmarshal(enc, &data.Data); err != nil {
|
||||||
|
return types.OptimisticUpdate{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize {
|
||||||
|
return types.OptimisticUpdate{}, errors.New("invalid sync_committee_bits length")
|
||||||
|
}
|
||||||
|
if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize {
|
||||||
|
return types.OptimisticUpdate{}, errors.New("invalid sync_committee_signature length")
|
||||||
|
}
|
||||||
|
return types.OptimisticUpdate{
|
||||||
|
Attested: types.HeaderWithExecProof{
|
||||||
|
Header: data.Data.Attested.Beacon,
|
||||||
|
PayloadHeader: attestedExecHeader,
|
||||||
|
PayloadBranch: data.Data.Attested.ExecutionBranch,
|
||||||
|
},
|
||||||
|
Signature: data.Data.Aggregate,
|
||||||
|
SignatureSlot: uint64(data.Data.SignatureSlot),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFinalityUpdate fetches the latest available finality update.
|
||||||
|
//
|
||||||
|
// See data structure definition here:
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
||||||
|
func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
|
||||||
|
resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update")
|
||||||
|
if err != nil {
|
||||||
|
return types.FinalityUpdate{}, err
|
||||||
|
}
|
||||||
|
return decodeFinalityUpdate(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) {
|
||||||
|
var data struct {
|
||||||
|
Version string
|
||||||
|
Data struct {
|
||||||
|
Attested jsonHeaderWithExecProof `json:"attested_header"`
|
||||||
|
Finalized jsonHeaderWithExecProof `json:"finalized_header"`
|
||||||
|
FinalityBranch merkle.Values `json:"finality_branch"`
|
||||||
|
Aggregate types.SyncAggregate `json:"sync_aggregate"`
|
||||||
|
SignatureSlot common.Decimal `json:"signature_slot"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(enc, &data); err != nil {
|
||||||
|
return types.FinalityUpdate{}, err
|
||||||
|
}
|
||||||
|
// Decode the execution payload headers.
|
||||||
|
attestedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Attested.Execution)
|
||||||
|
if err != nil {
|
||||||
|
return types.FinalityUpdate{}, fmt.Errorf("invalid attested header: %v", err)
|
||||||
|
}
|
||||||
|
finalizedExecHeader, err := types.ExecutionHeaderFromJSON(data.Version, data.Data.Finalized.Execution)
|
||||||
|
if err != nil {
|
||||||
|
return types.FinalityUpdate{}, fmt.Errorf("invalid finalized header: %v", err)
|
||||||
|
}
|
||||||
|
// Perform sanity checks.
|
||||||
|
if len(data.Data.Aggregate.Signers) != params.SyncCommitteeBitmaskSize {
|
||||||
|
return types.FinalityUpdate{}, errors.New("invalid sync_committee_bits length")
|
||||||
|
}
|
||||||
|
if len(data.Data.Aggregate.Signature) != params.BLSSignatureSize {
|
||||||
|
return types.FinalityUpdate{}, errors.New("invalid sync_committee_signature length")
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.FinalityUpdate{
|
||||||
|
Attested: types.HeaderWithExecProof{
|
||||||
|
Header: data.Data.Attested.Beacon,
|
||||||
|
PayloadHeader: attestedExecHeader,
|
||||||
|
PayloadBranch: data.Data.Attested.ExecutionBranch,
|
||||||
|
},
|
||||||
|
Finalized: types.HeaderWithExecProof{
|
||||||
|
Header: data.Data.Finalized.Beacon,
|
||||||
|
PayloadHeader: finalizedExecHeader,
|
||||||
|
PayloadBranch: data.Data.Finalized.ExecutionBranch,
|
||||||
|
},
|
||||||
|
FinalityBranch: data.Data.FinalityBranch,
|
||||||
|
Signature: data.Data.Aggregate,
|
||||||
|
SignatureSlot: uint64(data.Data.SignatureSlot),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeader fetches and validates the beacon header with the given blockRoot.
|
||||||
|
// If blockRoot is null hash then the latest head header is fetched.
|
||||||
|
// The values of the canonical and finalized flags are also returned. Note that
|
||||||
|
// these flags are not validated.
|
||||||
|
func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool, bool, error) {
|
||||||
|
var blockId string
|
||||||
|
if blockRoot == (common.Hash{}) {
|
||||||
|
blockId = "head"
|
||||||
|
} else {
|
||||||
|
blockId = blockRoot.Hex()
|
||||||
|
}
|
||||||
|
resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId)
|
||||||
|
if err != nil {
|
||||||
|
return types.Header{}, false, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Finalized bool `json:"finalized"`
|
||||||
|
Data struct {
|
||||||
|
Root common.Hash `json:"root"`
|
||||||
|
Canonical bool `json:"canonical"`
|
||||||
|
Header struct {
|
||||||
|
Message types.Header `json:"message"`
|
||||||
|
Signature hexutil.Bytes `json:"signature"`
|
||||||
|
} `json:"header"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(resp, &data); err != nil {
|
||||||
|
return types.Header{}, false, false, err
|
||||||
|
}
|
||||||
|
header := data.Data.Header.Message
|
||||||
|
if blockRoot == (common.Hash{}) {
|
||||||
|
blockRoot = data.Data.Root
|
||||||
|
}
|
||||||
|
if header.Hash() != blockRoot {
|
||||||
|
return types.Header{}, false, false, errors.New("retrieved beacon header root does not match")
|
||||||
|
}
|
||||||
|
return header, data.Data.Canonical, data.Finalized, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint.
|
||||||
|
func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) {
|
||||||
|
resp, err := api.httpGetf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// See data structure definition here:
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientbootstrap
|
||||||
|
type bootstrapData struct {
|
||||||
|
Data struct {
|
||||||
|
Header jsonBeaconHeader `json:"header"`
|
||||||
|
Committee *types.SerializedSyncCommittee `json:"current_sync_committee"`
|
||||||
|
CommitteeBranch merkle.Values `json:"current_sync_committee_branch"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var data bootstrapData
|
||||||
|
if err := json.Unmarshal(resp, &data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if data.Data.Committee == nil {
|
||||||
|
return nil, errors.New("sync committee is missing")
|
||||||
|
}
|
||||||
|
header := data.Data.Header.Beacon
|
||||||
|
if header.Hash() != checkpointHash {
|
||||||
|
return nil, fmt.Errorf("invalid checkpoint block header, have %v want %v", header.Hash(), checkpointHash)
|
||||||
|
}
|
||||||
|
checkpoint := &types.BootstrapData{
|
||||||
|
Header: header,
|
||||||
|
CommitteeBranch: data.Data.CommitteeBranch,
|
||||||
|
CommitteeRoot: data.Data.Committee.Root(),
|
||||||
|
Committee: data.Data.Committee,
|
||||||
|
}
|
||||||
|
if err := checkpoint.Validate(); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid checkpoint: %w", err)
|
||||||
|
}
|
||||||
|
if checkpoint.Header.Hash() != checkpointHash {
|
||||||
|
return nil, errors.New("wrong checkpoint hash")
|
||||||
|
}
|
||||||
|
return checkpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) {
|
||||||
|
resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var beaconBlockMessage struct {
|
||||||
|
Version string
|
||||||
|
Data struct {
|
||||||
|
Message json.RawMessage `json:"message"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(resp, &beaconBlockMessage); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid block json data: %v", err)
|
||||||
|
}
|
||||||
|
block, err := types.BlockFromJSON(beaconBlockMessage.Version, beaconBlockMessage.Data.Message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
computedRoot := block.Root()
|
||||||
|
if computedRoot != blockRoot {
|
||||||
|
return nil, fmt.Errorf("Beacon block root hash mismatch (expected: %x, got: %x)", blockRoot, computedRoot)
|
||||||
|
}
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) {
|
||||||
|
var data struct {
|
||||||
|
Slot common.Decimal `json:"slot"`
|
||||||
|
Block common.Hash `json:"block"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(enc, &data); err != nil {
|
||||||
|
return 0, common.Hash{}, err
|
||||||
|
}
|
||||||
|
return uint64(data.Slot), data.Block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeadEventListener struct {
|
||||||
|
OnNewHead func(slot uint64, blockRoot common.Hash)
|
||||||
|
OnOptimistic func(head types.OptimisticUpdate)
|
||||||
|
OnFinality func(head types.FinalityUpdate)
|
||||||
|
OnError func(err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartHeadListener creates an event subscription for heads and signed (optimistic)
|
||||||
|
// head updates and calls the specified callback functions when they are received.
|
||||||
|
// The callbacks are also called for the current head and optimistic head at startup.
|
||||||
|
// They are never called concurrently.
|
||||||
|
func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() {
|
||||||
|
var (
|
||||||
|
ctx, closeCtx = context.WithCancel(context.Background())
|
||||||
|
streamCh = make(chan *eventsource.Stream, 1)
|
||||||
|
wg sync.WaitGroup
|
||||||
|
)
|
||||||
|
|
||||||
|
// When connected to a Lodestar node the subscription blocks until the first actual
|
||||||
|
// event arrives; therefore we create the subscription in a separate goroutine while
|
||||||
|
// letting the main goroutine sync up to the current head.
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
stream := api.startEventStream(ctx, &listener)
|
||||||
|
if stream == nil {
|
||||||
|
// This case happens when the context was closed.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Stream was opened, wait for close signal.
|
||||||
|
streamCh <- stream
|
||||||
|
<-ctx.Done()
|
||||||
|
stream.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// Request initial data.
|
||||||
|
log.Trace("Requesting initial head header")
|
||||||
|
if head, _, _, err := api.GetHeader(common.Hash{}); err == nil {
|
||||||
|
log.Trace("Retrieved initial head header", "slot", head.Slot, "hash", head.Hash())
|
||||||
|
listener.OnNewHead(head.Slot, head.Hash())
|
||||||
|
} else {
|
||||||
|
log.Debug("Failed to retrieve initial head header", "error", err)
|
||||||
|
}
|
||||||
|
log.Trace("Requesting initial optimistic update")
|
||||||
|
if optimisticUpdate, err := api.GetOptimisticUpdate(); err == nil {
|
||||||
|
log.Trace("Retrieved initial optimistic update", "slot", optimisticUpdate.Attested.Slot, "hash", optimisticUpdate.Attested.Hash())
|
||||||
|
listener.OnOptimistic(optimisticUpdate)
|
||||||
|
} else {
|
||||||
|
log.Debug("Failed to retrieve initial optimistic update", "error", err)
|
||||||
|
}
|
||||||
|
log.Trace("Requesting initial finality update")
|
||||||
|
if finalityUpdate, err := api.GetFinalityUpdate(); err == nil {
|
||||||
|
log.Trace("Retrieved initial finality update", "slot", finalityUpdate.Finalized.Slot, "hash", finalityUpdate.Finalized.Hash())
|
||||||
|
listener.OnFinality(finalityUpdate)
|
||||||
|
} else {
|
||||||
|
log.Debug("Failed to retrieve initial finality update", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("Starting event stream processing loop")
|
||||||
|
// Receive the stream.
|
||||||
|
var stream *eventsource.Stream
|
||||||
|
select {
|
||||||
|
case stream = <-streamCh:
|
||||||
|
case <-ctx.Done():
|
||||||
|
log.Trace("Stopping event stream processing loop")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-stream.Events:
|
||||||
|
if !ok {
|
||||||
|
log.Trace("Event stream closed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("New event received from event stream", "type", event.Event())
|
||||||
|
switch event.Event() {
|
||||||
|
case "head":
|
||||||
|
slot, blockRoot, err := decodeHeadEvent([]byte(event.Data()))
|
||||||
|
if err == nil {
|
||||||
|
listener.OnNewHead(slot, blockRoot)
|
||||||
|
} else {
|
||||||
|
listener.OnError(fmt.Errorf("error decoding head event: %v", err))
|
||||||
|
}
|
||||||
|
case "light_client_optimistic_update":
|
||||||
|
optimisticUpdate, err := decodeOptimisticUpdate([]byte(event.Data()))
|
||||||
|
if err == nil {
|
||||||
|
listener.OnOptimistic(optimisticUpdate)
|
||||||
|
} else {
|
||||||
|
listener.OnError(fmt.Errorf("error decoding optimistic update event: %v", err))
|
||||||
|
}
|
||||||
|
case "light_client_finality_update":
|
||||||
|
finalityUpdate, err := decodeFinalityUpdate([]byte(event.Data()))
|
||||||
|
if err == nil {
|
||||||
|
listener.OnFinality(finalityUpdate)
|
||||||
|
} else {
|
||||||
|
listener.OnError(fmt.Errorf("error decoding finality update event: %v", err))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
listener.OnError(fmt.Errorf("unexpected event: %s", event.Event()))
|
||||||
|
}
|
||||||
|
|
||||||
|
case err, ok := <-stream.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listener.OnError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
closeCtx()
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// startEventStream establishes an event stream. This will keep retrying until the stream has been
|
||||||
|
// established. It can only return nil when the context is canceled.
|
||||||
|
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
|
||||||
|
for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) {
|
||||||
|
path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update"
|
||||||
|
log.Trace("Sending event subscription request")
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil)
|
||||||
|
if err != nil {
|
||||||
|
listener.OnError(fmt.Errorf("error creating event subscription request: %v", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for k, v := range api.customHeaders {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
stream, err := eventsource.SubscribeWithRequest("", req)
|
||||||
|
if err != nil {
|
||||||
|
listener.OnError(fmt.Errorf("error creating event subscription: %v", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Trace("Successfully created event stream")
|
||||||
|
return stream
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) {
|
||||||
|
timer := time.NewTimer(timeout)
|
||||||
|
defer timer.Stop()
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
return true
|
||||||
|
case <-ctx.Done():
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -70,6 +70,7 @@ type CommitteeChain struct {
|
||||||
committees *canonicalStore[*types.SerializedSyncCommittee]
|
committees *canonicalStore[*types.SerializedSyncCommittee]
|
||||||
fixedCommitteeRoots *canonicalStore[common.Hash]
|
fixedCommitteeRoots *canonicalStore[common.Hash]
|
||||||
committeeCache *lru.Cache[uint64, syncCommittee] // cache deserialized committees
|
committeeCache *lru.Cache[uint64, syncCommittee] // cache deserialized committees
|
||||||
|
changeCounter uint64
|
||||||
|
|
||||||
clock mclock.Clock // monotonic clock (simulated clock in tests)
|
clock mclock.Clock // monotonic clock (simulated clock in tests)
|
||||||
unixNano func() int64 // system clock (simulated clock in tests)
|
unixNano func() int64 // system clock (simulated clock in tests)
|
||||||
|
|
@ -86,6 +87,11 @@ func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signer
|
||||||
return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() })
|
return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestCommitteeChain creates a new CommitteeChain for testing.
|
||||||
|
func NewTestCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, clock *mclock.Simulated) *CommitteeChain {
|
||||||
|
return newCommitteeChain(db, config, signerThreshold, enforceTime, dummyVerifier{}, clock, func() int64 { return int64(clock.Now()) })
|
||||||
|
}
|
||||||
|
|
||||||
// newCommitteeChain creates a new CommitteeChain with the option of replacing the
|
// newCommitteeChain creates a new CommitteeChain with the option of replacing the
|
||||||
// clock source and signature verification for testing purposes.
|
// clock source and signature verification for testing purposes.
|
||||||
func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain {
|
func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain {
|
||||||
|
|
@ -181,20 +187,20 @@ func (s *CommitteeChain) Reset() {
|
||||||
if err := s.rollback(0); err != nil {
|
if err := s.rollback(0); err != nil {
|
||||||
log.Error("Error writing batch into chain database", "error", err)
|
log.Error("Error writing batch into chain database", "error", err)
|
||||||
}
|
}
|
||||||
|
s.changeCounter++
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckpointInit initializes a CommitteeChain based on the checkpoint.
|
// CheckpointInit initializes a CommitteeChain based on a checkpoint.
|
||||||
// Note: if the chain is already initialized and the committees proven by the
|
// Note: if the chain is already initialized and the committees proven by the
|
||||||
// checkpoint do match the existing chain then the chain is retained and the
|
// checkpoint do match the existing chain then the chain is retained and the
|
||||||
// new checkpoint becomes fixed.
|
// new checkpoint becomes fixed.
|
||||||
func (s *CommitteeChain) CheckpointInit(bootstrap *types.BootstrapData) error {
|
func (s *CommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
|
||||||
s.chainmu.Lock()
|
s.chainmu.Lock()
|
||||||
defer s.chainmu.Unlock()
|
defer s.chainmu.Unlock()
|
||||||
|
|
||||||
if err := bootstrap.Validate(); err != nil {
|
if err := bootstrap.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
period := bootstrap.Header.SyncPeriod()
|
period := bootstrap.Header.SyncPeriod()
|
||||||
if err := s.deleteFixedCommitteeRootsFrom(period + 2); err != nil {
|
if err := s.deleteFixedCommitteeRootsFrom(period + 2); err != nil {
|
||||||
s.Reset()
|
s.Reset()
|
||||||
|
|
@ -215,6 +221,7 @@ func (s *CommitteeChain) CheckpointInit(bootstrap *types.BootstrapData) error {
|
||||||
s.Reset()
|
s.Reset()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
s.changeCounter++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,6 +374,7 @@ func (s *CommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommi
|
||||||
return ErrWrongCommitteeRoot
|
return ErrWrongCommitteeRoot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.changeCounter++
|
||||||
if reorg {
|
if reorg {
|
||||||
if err := s.rollback(period + 1); err != nil {
|
if err := s.rollback(period + 1); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -405,6 +413,13 @@ func (s *CommitteeChain) NextSyncPeriod() (uint64, bool) {
|
||||||
return s.committees.periods.End - 1, true
|
return s.committees.periods.End - 1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CommitteeChain) ChangeCounter() uint64 {
|
||||||
|
s.chainmu.RLock()
|
||||||
|
defer s.chainmu.RUnlock()
|
||||||
|
|
||||||
|
return s.changeCounter
|
||||||
|
}
|
||||||
|
|
||||||
// rollback removes all committees and fixed roots from the given period and updates
|
// rollback removes all committees and fixed roots from the given period and updates
|
||||||
// starting from the previous period.
|
// starting from the previous period.
|
||||||
func (s *CommitteeChain) rollback(period uint64) error {
|
func (s *CommitteeChain) rollback(period uint64) error {
|
||||||
|
|
@ -452,12 +467,12 @@ func (s *CommitteeChain) getSyncCommittee(period uint64) (syncCommittee, error)
|
||||||
if sc, ok := s.committees.get(s.db, period); ok {
|
if sc, ok := s.committees.get(s.db, period); ok {
|
||||||
c, err := s.sigVerifier.deserializeSyncCommittee(sc)
|
c, err := s.sigVerifier.deserializeSyncCommittee(sc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Sync committee #%d deserialization error: %v", period, err)
|
return nil, fmt.Errorf("sync committee #%d deserialization error: %v", period, err)
|
||||||
}
|
}
|
||||||
s.committeeCache.Add(period, c)
|
s.committeeCache.Add(period, c)
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Missing serialized sync committee #%d", period)
|
return nil, fmt.Errorf("missing serialized sync committee #%d", period)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySignedHeader returns true if the given signed header has a valid signature
|
// VerifySignedHeader returns true if the given signed header has a valid signature
|
||||||
|
|
|
||||||
|
|
@ -241,12 +241,12 @@ func newCommitteeChainTest(t *testing.T, config types.ChainConfig, signerThresho
|
||||||
signerThreshold: signerThreshold,
|
signerThreshold: signerThreshold,
|
||||||
enforceTime: enforceTime,
|
enforceTime: enforceTime,
|
||||||
}
|
}
|
||||||
c.chain = newCommitteeChain(c.db, &config, signerThreshold, enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) })
|
c.chain = NewTestCommitteeChain(c.db, &config, signerThreshold, enforceTime, c.clock)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *committeeChainTest) reloadChain() {
|
func (c *committeeChainTest) reloadChain() {
|
||||||
c.chain = newCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) })
|
c.chain = NewTestCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, c.clock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *committeeChainTest) setClockPeriod(period float64) {
|
func (c *committeeChainTest) setClockPeriod(period float64) {
|
||||||
|
|
|
||||||
161
beacon/light/head_tracker.go
Normal file
161
beacon/light/head_tracker.go
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package light
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HeadTracker keeps track of the latest validated head and the "prefetch" head
|
||||||
|
// which is the (not necessarily validated) head announced by the majority of
|
||||||
|
// servers.
|
||||||
|
type HeadTracker struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
committeeChain *CommitteeChain
|
||||||
|
minSignerCount int
|
||||||
|
optimisticUpdate types.OptimisticUpdate
|
||||||
|
hasOptimisticUpdate bool
|
||||||
|
finalityUpdate types.FinalityUpdate
|
||||||
|
hasFinalityUpdate bool
|
||||||
|
prefetchHead types.HeadInfo
|
||||||
|
changeCounter uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHeadTracker creates a new HeadTracker.
|
||||||
|
func NewHeadTracker(committeeChain *CommitteeChain, minSignerCount int) *HeadTracker {
|
||||||
|
return &HeadTracker{
|
||||||
|
committeeChain: committeeChain,
|
||||||
|
minSignerCount: minSignerCount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatedOptimistic returns the latest validated optimistic update.
|
||||||
|
func (h *HeadTracker) ValidatedOptimistic() (types.OptimisticUpdate, bool) {
|
||||||
|
h.lock.RLock()
|
||||||
|
defer h.lock.RUnlock()
|
||||||
|
|
||||||
|
return h.optimisticUpdate, h.hasOptimisticUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatedFinality returns the latest validated finality update.
|
||||||
|
func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) {
|
||||||
|
h.lock.RLock()
|
||||||
|
defer h.lock.RUnlock()
|
||||||
|
|
||||||
|
return h.finalityUpdate, h.hasFinalityUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateOptimistic validates the given optimistic update. If the update is
|
||||||
|
// successfully validated and it is better than the old validated update (higher
|
||||||
|
// slot or same slot and more signers) then ValidatedOptimistic is updated.
|
||||||
|
// The boolean return flag signals if ValidatedOptimistic has been changed.
|
||||||
|
func (h *HeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, error) {
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
|
if err := update.Validate(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
replace, err := h.validate(update.SignedHeader(), h.optimisticUpdate.SignedHeader())
|
||||||
|
if replace {
|
||||||
|
h.optimisticUpdate, h.hasOptimisticUpdate = update, true
|
||||||
|
h.changeCounter++
|
||||||
|
}
|
||||||
|
return replace, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateFinality validates the given finality update. If the update is
|
||||||
|
// successfully validated and it is better than the old validated update (higher
|
||||||
|
// slot or same slot and more signers) then ValidatedFinality is updated.
|
||||||
|
// The boolean return flag signals if ValidatedFinality has been changed.
|
||||||
|
func (h *HeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) {
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
|
if err := update.Validate(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
replace, err := h.validate(update.SignedHeader(), h.finalityUpdate.SignedHeader())
|
||||||
|
if replace {
|
||||||
|
h.finalityUpdate, h.hasFinalityUpdate = update, true
|
||||||
|
h.changeCounter++
|
||||||
|
}
|
||||||
|
return replace, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeadTracker) validate(head, oldHead types.SignedHeader) (bool, error) {
|
||||||
|
signerCount := head.Signature.SignerCount()
|
||||||
|
if signerCount < h.minSignerCount {
|
||||||
|
return false, errors.New("low signer count")
|
||||||
|
}
|
||||||
|
if head.Header.Slot < oldHead.Header.Slot || (head.Header.Slot == oldHead.Header.Slot && signerCount <= oldHead.Signature.SignerCount()) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
sigOk, age, err := h.committeeChain.VerifySignedHeader(head)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if age < 0 {
|
||||||
|
log.Warn("Future signed head received", "age", age)
|
||||||
|
}
|
||||||
|
if age > time.Minute*2 {
|
||||||
|
log.Warn("Old signed head received", "age", age)
|
||||||
|
}
|
||||||
|
if !sigOk {
|
||||||
|
return false, errors.New("invalid header signature")
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrefetchHead returns the latest known prefetch head's head info.
|
||||||
|
// This head can be used to start fetching related data hoping that it will be
|
||||||
|
// validated soon.
|
||||||
|
// Note that the prefetch head cannot be validated cryptographically so it should
|
||||||
|
// only be used as a performance optimization hint.
|
||||||
|
func (h *HeadTracker) PrefetchHead() types.HeadInfo {
|
||||||
|
h.lock.RLock()
|
||||||
|
defer h.lock.RUnlock()
|
||||||
|
|
||||||
|
return h.prefetchHead
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrefetchHead sets the prefetch head info.
|
||||||
|
// Note that HeadTracker does not verify the prefetch head, just acts as a thread
|
||||||
|
// safe bulletin board.
|
||||||
|
func (h *HeadTracker) SetPrefetchHead(head types.HeadInfo) {
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
|
if head == h.prefetchHead {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.prefetchHead = head
|
||||||
|
h.changeCounter++
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeCounter implements request.targetData
|
||||||
|
func (h *HeadTracker) ChangeCounter() uint64 {
|
||||||
|
h.lock.RLock()
|
||||||
|
defer h.lock.RUnlock()
|
||||||
|
|
||||||
|
return h.changeCounter
|
||||||
|
}
|
||||||
403
beacon/light/request/scheduler.go
Normal file
403
beacon/light/request/scheduler.go
Normal file
|
|
@ -0,0 +1,403 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Module represents a mechanism which is typically responsible for downloading
|
||||||
|
// and updating a passive data structure. It does not directly interact with the
|
||||||
|
// servers. It can start requests using the Requester interface, maintain its
|
||||||
|
// internal state by receiving and processing Events and update its target data
|
||||||
|
// structure based on the obtained data.
|
||||||
|
// It is the Scheduler's responsibility to feed events to the modules, call
|
||||||
|
// Process as long as there might be something to process and then generate request
|
||||||
|
// candidates using MakeRequest and start the best possible requests.
|
||||||
|
// Modules are called by Scheduler whenever a global trigger is fired. All events
|
||||||
|
// fire the trigger. Changing a target data structure also triggers a next
|
||||||
|
// processing round as it could make further actions possible either by the same
|
||||||
|
// or another Module.
|
||||||
|
type Module interface {
|
||||||
|
// Process is a non-blocking function responsible for starting requests,
|
||||||
|
// processing events and updating the target data structures(s) and the
|
||||||
|
// internal state of the module. Module state typically consists of information
|
||||||
|
// about pending requests and registered servers.
|
||||||
|
// Process is always called after an event is received or after a target data
|
||||||
|
// structure has been changed.
|
||||||
|
//
|
||||||
|
// Note: Process functions of different modules are never called concurrently;
|
||||||
|
// they are called by Scheduler in the same order of priority as they were
|
||||||
|
// registered in.
|
||||||
|
Process(Requester, []Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requester allows Modules to obtain the list of momentarily available servers,
|
||||||
|
// start new requests and report server failure when a response has been proven
|
||||||
|
// to be invalid in the processing phase.
|
||||||
|
// Note that all Requester functions should be safe to call from Module.Process.
|
||||||
|
type Requester interface {
|
||||||
|
CanSendTo() []Server
|
||||||
|
Send(Server, Request) ID
|
||||||
|
Fail(Server, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scheduler is a modular network data retrieval framework that coordinates multiple
|
||||||
|
// servers and retrieval mechanisms (modules). It implements a trigger mechanism
|
||||||
|
// that calls the Process function of registered modules whenever either the state
|
||||||
|
// of existing data structures or events coming from registered servers could
|
||||||
|
// allow new operations.
|
||||||
|
type Scheduler struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
modules []Module // first has the highest priority
|
||||||
|
names map[Module]string
|
||||||
|
servers map[server]struct{}
|
||||||
|
targets map[targetData]uint64
|
||||||
|
|
||||||
|
requesterLock sync.RWMutex
|
||||||
|
serverOrder []server
|
||||||
|
pending map[ServerAndID]pendingRequest
|
||||||
|
|
||||||
|
// eventLock guards access to the events list. Note that eventLock can be
|
||||||
|
// locked either while lock is locked or unlocked but lock cannot be locked
|
||||||
|
// while eventLock is locked.
|
||||||
|
eventLock sync.Mutex
|
||||||
|
events []Event
|
||||||
|
stopCh chan chan struct{}
|
||||||
|
|
||||||
|
triggerCh chan struct{} // restarts waiting sync loop
|
||||||
|
// if trigger has already been fired then send to testWaitCh blocks until
|
||||||
|
// the triggered processing round is finished
|
||||||
|
testWaitCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Server identifies a server without allowing any direct interaction.
|
||||||
|
// Note: server interface is used by Scheduler and Tracker but not used by
|
||||||
|
// the modules that do not interact with them directly.
|
||||||
|
// In order to make module testing easier, Server interface is used in
|
||||||
|
// events and modules.
|
||||||
|
Server interface {
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
Request any
|
||||||
|
Response any
|
||||||
|
ID uint64
|
||||||
|
ServerAndID struct {
|
||||||
|
Server Server
|
||||||
|
ID ID
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// targetData represents a registered target data structure that increases its
|
||||||
|
// ChangeCounter whenever it has been changed.
|
||||||
|
type targetData interface {
|
||||||
|
ChangeCounter() uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// pendingRequest keeps track of sent and not yet finalized requests and their
|
||||||
|
// sender modules.
|
||||||
|
type pendingRequest struct {
|
||||||
|
request Request
|
||||||
|
module Module
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewScheduler creates a new Scheduler.
|
||||||
|
func NewScheduler() *Scheduler {
|
||||||
|
s := &Scheduler{
|
||||||
|
servers: make(map[server]struct{}),
|
||||||
|
names: make(map[Module]string),
|
||||||
|
pending: make(map[ServerAndID]pendingRequest),
|
||||||
|
targets: make(map[targetData]uint64),
|
||||||
|
stopCh: make(chan chan struct{}),
|
||||||
|
// Note: testWaitCh should not have capacity in order to ensure
|
||||||
|
// that after a trigger happens testWaitCh will block until the resulting
|
||||||
|
// processing round has been finished
|
||||||
|
triggerCh: make(chan struct{}, 1),
|
||||||
|
testWaitCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterTarget registers a target data structure, ensuring that any changes
|
||||||
|
// made to it trigger a new round of Module.Process calls, giving a chance to
|
||||||
|
// modules to react to the changes.
|
||||||
|
func (s *Scheduler) RegisterTarget(t targetData) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.targets[t] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterModule registers a module. Should be called before starting the scheduler.
|
||||||
|
// In each processing round the order of module processing depends on the order of
|
||||||
|
// registration.
|
||||||
|
func (s *Scheduler) RegisterModule(m Module, name string) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.modules = append(s.modules, m)
|
||||||
|
s.names[m] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterServer registers a new server.
|
||||||
|
func (s *Scheduler) RegisterServer(server server) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.addEvent(Event{Type: EvRegistered, Server: server})
|
||||||
|
server.subscribe(func(event Event) {
|
||||||
|
event.Server = server
|
||||||
|
s.addEvent(event)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnregisterServer removes a registered server.
|
||||||
|
func (s *Scheduler) UnregisterServer(server server) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
server.unsubscribe()
|
||||||
|
s.addEvent(Event{Type: EvUnregistered, Server: server})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts the scheduler. It should be called after registering all modules
|
||||||
|
// and before registering any servers.
|
||||||
|
func (s *Scheduler) Start() {
|
||||||
|
go s.syncLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the scheduler.
|
||||||
|
func (s *Scheduler) Stop() {
|
||||||
|
stop := make(chan struct{})
|
||||||
|
s.stopCh <- stop
|
||||||
|
<-stop
|
||||||
|
s.lock.Lock()
|
||||||
|
for server := range s.servers {
|
||||||
|
server.unsubscribe()
|
||||||
|
}
|
||||||
|
s.servers = nil
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncLoop is the main event loop responsible for event/data processing and
|
||||||
|
// sending new requests.
|
||||||
|
// A round of processing starts whenever the global trigger is fired. Triggers
|
||||||
|
// fired during a processing round ensure that there is going to be a next round.
|
||||||
|
func (s *Scheduler) syncLoop() {
|
||||||
|
for {
|
||||||
|
s.lock.Lock()
|
||||||
|
s.processRound()
|
||||||
|
s.lock.Unlock()
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case stop := <-s.stopCh:
|
||||||
|
close(stop)
|
||||||
|
return
|
||||||
|
case <-s.triggerCh:
|
||||||
|
break loop
|
||||||
|
case <-s.testWaitCh:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetChanged returns true if a registered target data structure has been
|
||||||
|
// changed since the last call to this function.
|
||||||
|
func (s *Scheduler) targetChanged() (changed bool) {
|
||||||
|
for target, counter := range s.targets {
|
||||||
|
if newCounter := target.ChangeCounter(); newCounter != counter {
|
||||||
|
s.targets[target] = newCounter
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// processRound runs an entire processing round. It calls the Process functions
|
||||||
|
// of all modules, passing all relevant events and repeating Process calls as
|
||||||
|
// long as any changes have been made to the registered target data structures.
|
||||||
|
// Once all events have been processed and a stable state has been achieved,
|
||||||
|
// requests are generated and sent if necessary and possible.
|
||||||
|
func (s *Scheduler) processRound() {
|
||||||
|
for {
|
||||||
|
log.Trace("Processing modules")
|
||||||
|
filteredEvents := s.filterEvents()
|
||||||
|
for _, module := range s.modules {
|
||||||
|
log.Trace("Processing module", "name", s.names[module], "events", len(filteredEvents[module]))
|
||||||
|
module.Process(requester{s, module}, filteredEvents[module])
|
||||||
|
}
|
||||||
|
if !s.targetChanged() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger starts a new processing round. If fired during processing, it ensures
|
||||||
|
// another full round of processing all modules.
|
||||||
|
func (s *Scheduler) Trigger() {
|
||||||
|
select {
|
||||||
|
case s.triggerCh <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addEvent adds an event to be processed in the next round. Note that it can be
|
||||||
|
// called regardless of the state of the lock mutex, making it safe for use in
|
||||||
|
// the server event callback.
|
||||||
|
func (s *Scheduler) addEvent(event Event) {
|
||||||
|
s.eventLock.Lock()
|
||||||
|
s.events = append(s.events, event)
|
||||||
|
s.eventLock.Unlock()
|
||||||
|
s.Trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterEvent sorts each Event either as a request event or a server event,
|
||||||
|
// depending on its type. Request events are also sorted in a map based on the
|
||||||
|
// module that originally initiated the request. It also ensures that no events
|
||||||
|
// related to a server are returned before EvRegistered or after EvUnregistered.
|
||||||
|
// In case of an EvUnregistered server event it also closes all pending requests
|
||||||
|
// to the given server by adding a failed request event (EvFail), ensuring that
|
||||||
|
// all requests get finalized and thereby allowing the module logic to be safe
|
||||||
|
// and simple.
|
||||||
|
func (s *Scheduler) filterEvents() map[Module][]Event {
|
||||||
|
s.eventLock.Lock()
|
||||||
|
events := s.events
|
||||||
|
s.events = nil
|
||||||
|
s.eventLock.Unlock()
|
||||||
|
|
||||||
|
s.requesterLock.Lock()
|
||||||
|
defer s.requesterLock.Unlock()
|
||||||
|
|
||||||
|
filteredEvents := make(map[Module][]Event)
|
||||||
|
for _, event := range events {
|
||||||
|
server := event.Server.(server)
|
||||||
|
if _, ok := s.servers[server]; !ok && event.Type != EvRegistered {
|
||||||
|
continue // before EvRegister or after EvUnregister, discard
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.IsRequestEvent() {
|
||||||
|
sid, _, _ := event.RequestInfo()
|
||||||
|
pending, ok := s.pending[sid]
|
||||||
|
if !ok {
|
||||||
|
continue // request already closed, ignore further events
|
||||||
|
}
|
||||||
|
if event.Type == EvResponse || event.Type == EvFail {
|
||||||
|
delete(s.pending, sid) // final event, close pending request
|
||||||
|
}
|
||||||
|
filteredEvents[pending.module] = append(filteredEvents[pending.module], event)
|
||||||
|
} else {
|
||||||
|
switch event.Type {
|
||||||
|
case EvRegistered:
|
||||||
|
s.servers[server] = struct{}{}
|
||||||
|
s.serverOrder = append(s.serverOrder, nil)
|
||||||
|
copy(s.serverOrder[1:], s.serverOrder[:len(s.serverOrder)-1])
|
||||||
|
s.serverOrder[0] = server
|
||||||
|
case EvUnregistered:
|
||||||
|
s.closePending(event.Server, filteredEvents)
|
||||||
|
delete(s.servers, server)
|
||||||
|
for i, srv := range s.serverOrder {
|
||||||
|
if srv == server {
|
||||||
|
copy(s.serverOrder[i:len(s.serverOrder)-1], s.serverOrder[i+1:])
|
||||||
|
s.serverOrder = s.serverOrder[:len(s.serverOrder)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, module := range s.modules {
|
||||||
|
filteredEvents[module] = append(filteredEvents[module], event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredEvents
|
||||||
|
}
|
||||||
|
|
||||||
|
// closePending closes all pending requests to the given server and adds an EvFail
|
||||||
|
// event to properly finalize them
|
||||||
|
func (s *Scheduler) closePending(server Server, filteredEvents map[Module][]Event) {
|
||||||
|
for sid, pending := range s.pending {
|
||||||
|
if sid.Server == server {
|
||||||
|
filteredEvents[pending.module] = append(filteredEvents[pending.module], Event{
|
||||||
|
Type: EvFail,
|
||||||
|
Server: server,
|
||||||
|
Data: RequestResponse{
|
||||||
|
ID: sid.ID,
|
||||||
|
Request: pending.request,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
delete(s.pending, sid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// requester implements Requester. Note that while requester basically wraps
|
||||||
|
// Scheduler (with the added information of the currently processed Module), all
|
||||||
|
// functions are safe to call from Module.Process which is running while
|
||||||
|
// the Scheduler.lock mutex is held.
|
||||||
|
type requester struct {
|
||||||
|
*Scheduler
|
||||||
|
module Module
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanSendTo returns the list of currently available servers. It also returns
|
||||||
|
// them in an order of least to most recently used, ensuring a round-robin usage
|
||||||
|
// of suitable servers if the module always chooses the first suitable one.
|
||||||
|
func (s requester) CanSendTo() []Server {
|
||||||
|
s.requesterLock.RLock()
|
||||||
|
defer s.requesterLock.RUnlock()
|
||||||
|
|
||||||
|
list := make([]Server, 0, len(s.serverOrder))
|
||||||
|
for _, server := range s.serverOrder {
|
||||||
|
if server.canRequestNow() {
|
||||||
|
list = append(list, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sends a request and adds an entry to Scheduler.pending map, ensuring that
|
||||||
|
// related request events will be delivered to the sender Module.
|
||||||
|
func (s requester) Send(srv Server, req Request) ID {
|
||||||
|
s.requesterLock.Lock()
|
||||||
|
defer s.requesterLock.Unlock()
|
||||||
|
|
||||||
|
server := srv.(server)
|
||||||
|
id := server.sendRequest(req)
|
||||||
|
sid := ServerAndID{Server: srv, ID: id}
|
||||||
|
s.pending[sid] = pendingRequest{request: req, module: s.module}
|
||||||
|
for i, ss := range s.serverOrder {
|
||||||
|
if ss == server {
|
||||||
|
copy(s.serverOrder[i:len(s.serverOrder)-1], s.serverOrder[i+1:])
|
||||||
|
s.serverOrder[len(s.serverOrder)-1] = server
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Error("Target server not found in ordered list of registered servers")
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail should be called when a server delivers invalid or useless information.
|
||||||
|
// Calling Fail disables the given server for a period that is initially short
|
||||||
|
// but is exponentially growing if it happens frequently. This results in a
|
||||||
|
// somewhat fault tolerant operation that avoids hammering servers with requests
|
||||||
|
// that they cannot serve but still gives them a chance periodically.
|
||||||
|
func (s requester) Fail(srv Server, desc string) {
|
||||||
|
srv.(server).fail(desc)
|
||||||
|
}
|
||||||
126
beacon/light/request/scheduler_test.go
Normal file
126
beacon/light/request/scheduler_test.go
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEventFilter(t *testing.T) {
|
||||||
|
s := NewScheduler()
|
||||||
|
module1 := &testModule{name: "module1"}
|
||||||
|
module2 := &testModule{name: "module2"}
|
||||||
|
s.RegisterModule(module1, "module1")
|
||||||
|
s.RegisterModule(module2, "module2")
|
||||||
|
s.Start()
|
||||||
|
// startup process round without events
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expProcess(t, nil)
|
||||||
|
module2.expProcess(t, nil)
|
||||||
|
srv := &testServer{}
|
||||||
|
// register server; both modules should receive server event
|
||||||
|
s.RegisterServer(srv)
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expProcess(t, []Event{
|
||||||
|
{Type: EvRegistered, Server: srv},
|
||||||
|
})
|
||||||
|
module2.expProcess(t, []Event{
|
||||||
|
{Type: EvRegistered, Server: srv},
|
||||||
|
})
|
||||||
|
// let module1 send a request
|
||||||
|
srv.canRequest = 1
|
||||||
|
module1.sendReq = testRequest
|
||||||
|
s.Trigger()
|
||||||
|
// in first triggered round module1 sends the request, no events yet
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expProcess(t, nil)
|
||||||
|
module2.expProcess(t, nil)
|
||||||
|
// server emits EvTimeout; only module1 should receive it
|
||||||
|
srv.eventCb(Event{Type: EvTimeout, Data: RequestResponse{ID: 1, Request: testRequest}})
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expProcess(t, []Event{
|
||||||
|
{Type: EvTimeout, Server: srv, Data: RequestResponse{ID: 1, Request: testRequest}},
|
||||||
|
})
|
||||||
|
module2.expProcess(t, nil)
|
||||||
|
// unregister server; both modules should receive server event
|
||||||
|
s.UnregisterServer(srv)
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expProcess(t, []Event{
|
||||||
|
// module1 should also receive EvFail on its pending request
|
||||||
|
{Type: EvFail, Server: srv, Data: RequestResponse{ID: 1, Request: testRequest}},
|
||||||
|
{Type: EvUnregistered, Server: srv},
|
||||||
|
})
|
||||||
|
module2.expProcess(t, []Event{
|
||||||
|
{Type: EvUnregistered, Server: srv},
|
||||||
|
})
|
||||||
|
// response after server unregistered; should be discarded
|
||||||
|
srv.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expProcess(t, nil)
|
||||||
|
module2.expProcess(t, nil)
|
||||||
|
// no more process rounds expected; shut down
|
||||||
|
s.testWaitCh <- struct{}{}
|
||||||
|
module1.expNoMoreProcess(t)
|
||||||
|
module2.expNoMoreProcess(t)
|
||||||
|
s.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
type testServer struct {
|
||||||
|
eventCb func(Event)
|
||||||
|
lastID ID
|
||||||
|
canRequest int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testServer) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testServer) subscribe(eventCb func(Event)) {
|
||||||
|
s.eventCb = eventCb
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testServer) canRequestNow() bool {
|
||||||
|
return s.canRequest > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testServer) sendRequest(req Request) ID {
|
||||||
|
s.canRequest--
|
||||||
|
s.lastID++
|
||||||
|
return s.lastID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testServer) fail(string) {}
|
||||||
|
func (s *testServer) unsubscribe() {}
|
||||||
|
|
||||||
|
type testModule struct {
|
||||||
|
name string
|
||||||
|
processed [][]Event
|
||||||
|
sendReq Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *testModule) Process(requester Requester, events []Event) {
|
||||||
|
m.processed = append(m.processed, events)
|
||||||
|
if m.sendReq != nil {
|
||||||
|
if cs := requester.CanSendTo(); len(cs) > 0 {
|
||||||
|
requester.Send(cs[0], m.sendReq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *testModule) expProcess(t *testing.T, expEvents []Event) {
|
||||||
|
if len(m.processed) == 0 {
|
||||||
|
t.Errorf("Missing call to %s.Process", m.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
events := m.processed[0]
|
||||||
|
m.processed = m.processed[1:]
|
||||||
|
if !reflect.DeepEqual(events, expEvents) {
|
||||||
|
t.Errorf("Call to %s.Process with wrong events (expected %v, got %v)", m.name, expEvents, events)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *testModule) expNoMoreProcess(t *testing.T) {
|
||||||
|
for len(m.processed) > 0 {
|
||||||
|
t.Errorf("Unexpected call to %s.Process with events %v", m.name, m.processed[0])
|
||||||
|
m.processed = m.processed[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
451
beacon/light/request/server.go
Normal file
451
beacon/light/request/server.go
Normal file
|
|
@ -0,0 +1,451 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// request events
|
||||||
|
EvResponse = &EventType{Name: "response", requestEvent: true} // data: RequestResponse; sent by requestServer
|
||||||
|
EvFail = &EventType{Name: "fail", requestEvent: true} // data: RequestResponse; sent by requestServer
|
||||||
|
EvTimeout = &EventType{Name: "timeout", requestEvent: true} // data: RequestResponse; sent by serverWithTimeout
|
||||||
|
// server events
|
||||||
|
EvRegistered = &EventType{Name: "registered"} // data: nil; sent by Scheduler
|
||||||
|
EvUnregistered = &EventType{Name: "unregistered"} // data: nil; sent by Scheduler
|
||||||
|
EvCanRequestAgain = &EventType{Name: "canRequestAgain"} // data: nil; sent by serverWithLimits
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
softRequestTimeout = time.Second // allow resending request to a different server but do not cancel yet
|
||||||
|
hardRequestTimeout = time.Second * 10 // cancel request
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// serverWithLimits parameters
|
||||||
|
parallelAdjustUp = 0.1 // adjust parallelLimit up in case of success under full load
|
||||||
|
parallelAdjustDown = 1 // adjust parallelLimit down in case of timeout/failure
|
||||||
|
minParallelLimit = 1 // parallelLimit lower bound
|
||||||
|
defaultParallelLimit = 3 // parallelLimit initial value
|
||||||
|
minFailureDelay = time.Millisecond * 100 // minimum disable time in case of request failure
|
||||||
|
maxFailureDelay = time.Minute // maximum disable time in case of request failure
|
||||||
|
maxServerEventBuffer = 5 // server event allowance buffer limit
|
||||||
|
maxServerEventRate = time.Second // server event allowance buffer recharge rate
|
||||||
|
)
|
||||||
|
|
||||||
|
// requestServer can send requests in a non-blocking way and feed back events
|
||||||
|
// through the event callback. After each request it should send back either
|
||||||
|
// EvResponse or EvFail. Additionally, it may also send application-defined
|
||||||
|
// events that the Modules can interpret.
|
||||||
|
type requestServer interface {
|
||||||
|
Name() string
|
||||||
|
Subscribe(eventCallback func(Event))
|
||||||
|
SendRequest(ID, Request)
|
||||||
|
Unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// server is implemented by a requestServer wrapped into serverWithTimeout and
|
||||||
|
// serverWithLimits and is used by Scheduler.
|
||||||
|
// In addition to requestServer functionality, server can also handle timeouts,
|
||||||
|
// limit the number of parallel in-flight requests and temporarily disable
|
||||||
|
// new requests based on timeouts and response failures.
|
||||||
|
type server interface {
|
||||||
|
Server
|
||||||
|
subscribe(eventCallback func(Event))
|
||||||
|
canRequestNow() bool
|
||||||
|
sendRequest(Request) ID
|
||||||
|
fail(string)
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServer wraps a requestServer and returns a server
|
||||||
|
func NewServer(rs requestServer, clock mclock.Clock) server {
|
||||||
|
s := &serverWithLimits{}
|
||||||
|
s.parent = rs
|
||||||
|
s.serverWithTimeout.init(clock)
|
||||||
|
s.init()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventType identifies an event type, either related to a request or the server
|
||||||
|
// in general. Server events can also be externally defined.
|
||||||
|
type EventType struct {
|
||||||
|
Name string
|
||||||
|
requestEvent bool // all request events are pre-defined in request package
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event describes an event where the type of Data depends on Type.
|
||||||
|
// Server field is not required when sent through the event callback; it is filled
|
||||||
|
// out when processed by the Scheduler. Note that the Scheduler can also create
|
||||||
|
// and send events (EvRegistered, EvUnregistered) directly.
|
||||||
|
type Event struct {
|
||||||
|
Type *EventType
|
||||||
|
Server Server // filled by Scheduler
|
||||||
|
Data any
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRequestEvent returns true if the event is a request event
|
||||||
|
func (e *Event) IsRequestEvent() bool {
|
||||||
|
return e.Type.requestEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestInfo assumes that the event is a request event and returns its contents
|
||||||
|
// in a convenient form.
|
||||||
|
func (e *Event) RequestInfo() (ServerAndID, Request, Response) {
|
||||||
|
data := e.Data.(RequestResponse)
|
||||||
|
return ServerAndID{Server: e.Server, ID: data.ID}, data.Request, data.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestResponse is the Data type of request events.
|
||||||
|
type RequestResponse struct {
|
||||||
|
ID ID
|
||||||
|
Request Request
|
||||||
|
Response Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverWithTimeout wraps a requestServer and introduces timeouts.
|
||||||
|
// The request's lifecycle is concluded if EvResponse or EvFail emitted by the
|
||||||
|
// parent requestServer. If this does not happen until softRequestTimeout then
|
||||||
|
// EvTimeout is emitted, after which the final EvResponse or EvFail is still
|
||||||
|
// guaranteed to follow.
|
||||||
|
// If the parent fails to send this final event for hardRequestTimeout then
|
||||||
|
// serverWithTimeout emits EvFail and discards any further events from the
|
||||||
|
// parent related to the given request.
|
||||||
|
type serverWithTimeout struct {
|
||||||
|
parent requestServer
|
||||||
|
lock sync.Mutex
|
||||||
|
clock mclock.Clock
|
||||||
|
childEventCb func(event Event)
|
||||||
|
timeouts map[ID]mclock.Timer
|
||||||
|
lastID ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements request.Server
|
||||||
|
func (s *serverWithTimeout) Name() string {
|
||||||
|
return s.parent.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes serverWithTimeout
|
||||||
|
func (s *serverWithTimeout) init(clock mclock.Clock) {
|
||||||
|
s.clock = clock
|
||||||
|
s.timeouts = make(map[ID]mclock.Timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribe subscribes to events which include parent (requestServer) events
|
||||||
|
// plus EvTimeout.
|
||||||
|
func (s *serverWithTimeout) subscribe(eventCallback func(event Event)) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.childEventCb = eventCallback
|
||||||
|
s.parent.Subscribe(s.eventCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendRequest generated a new request ID, emits EvRequest, sets up the timeout
|
||||||
|
// timer, then sends the request through the parent (requestServer).
|
||||||
|
func (s *serverWithTimeout) sendRequest(request Request) (reqId ID) {
|
||||||
|
s.lock.Lock()
|
||||||
|
s.lastID++
|
||||||
|
id := s.lastID
|
||||||
|
s.startTimeout(RequestResponse{ID: id, Request: request})
|
||||||
|
s.lock.Unlock()
|
||||||
|
s.parent.SendRequest(id, request)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventCallback is called by parent (requestServer) event subscription.
|
||||||
|
func (s *serverWithTimeout) eventCallback(event Event) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
switch event.Type {
|
||||||
|
case EvResponse, EvFail:
|
||||||
|
id := event.Data.(RequestResponse).ID
|
||||||
|
if timer, ok := s.timeouts[id]; ok {
|
||||||
|
// Note: if stopping the timer is unsuccessful then the resulting AfterFunc
|
||||||
|
// call will just do nothing
|
||||||
|
timer.Stop()
|
||||||
|
delete(s.timeouts, id)
|
||||||
|
if s.childEventCb != nil {
|
||||||
|
s.childEventCb(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if s.childEventCb != nil {
|
||||||
|
s.childEventCb(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// startTimeout starts a timeout timer for the given request.
|
||||||
|
func (s *serverWithTimeout) startTimeout(reqData RequestResponse) {
|
||||||
|
id := reqData.ID
|
||||||
|
s.timeouts[id] = s.clock.AfterFunc(softRequestTimeout, func() {
|
||||||
|
s.lock.Lock()
|
||||||
|
if _, ok := s.timeouts[id]; !ok {
|
||||||
|
s.lock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.timeouts[id] = s.clock.AfterFunc(hardRequestTimeout-softRequestTimeout, func() {
|
||||||
|
s.lock.Lock()
|
||||||
|
if _, ok := s.timeouts[id]; !ok {
|
||||||
|
s.lock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(s.timeouts, id)
|
||||||
|
childEventCb := s.childEventCb
|
||||||
|
s.lock.Unlock()
|
||||||
|
if childEventCb != nil {
|
||||||
|
childEventCb(Event{Type: EvFail, Data: reqData})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
childEventCb := s.childEventCb
|
||||||
|
s.lock.Unlock()
|
||||||
|
if childEventCb != nil {
|
||||||
|
childEventCb(Event{Type: EvTimeout, Data: reqData})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsubscribe stops all goroutines associated with the server.
|
||||||
|
func (s *serverWithTimeout) unsubscribe() {
|
||||||
|
s.lock.Lock()
|
||||||
|
for _, timer := range s.timeouts {
|
||||||
|
if timer != nil {
|
||||||
|
timer.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.lock.Unlock()
|
||||||
|
s.parent.Unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverWithLimits wraps serverWithTimeout and implements server. It limits the
|
||||||
|
// number of parallel in-flight requests and prevents sending new requests when a
|
||||||
|
// pending one has already timed out. Server events are also rate limited.
|
||||||
|
// It also implements a failure delay mechanism that adds an exponentially growing
|
||||||
|
// delay each time a request fails (wrong answer or hard timeout). This makes the
|
||||||
|
// syncing mechanism less brittle as temporary failures of the server might happen
|
||||||
|
// sometimes, but still avoids hammering a non-functional server with requests.
|
||||||
|
type serverWithLimits struct {
|
||||||
|
serverWithTimeout
|
||||||
|
lock sync.Mutex
|
||||||
|
childEventCb func(event Event)
|
||||||
|
softTimeouts map[ID]struct{}
|
||||||
|
pendingCount, timeoutCount int
|
||||||
|
parallelLimit float32
|
||||||
|
sendEvent bool
|
||||||
|
delayTimer mclock.Timer
|
||||||
|
delayCounter int
|
||||||
|
failureDelayEnd mclock.AbsTime
|
||||||
|
failureDelay float64
|
||||||
|
serverEventBuffer int
|
||||||
|
eventBufferUpdated mclock.AbsTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes serverWithLimits
|
||||||
|
func (s *serverWithLimits) init() {
|
||||||
|
s.softTimeouts = make(map[ID]struct{})
|
||||||
|
s.parallelLimit = defaultParallelLimit
|
||||||
|
s.serverEventBuffer = maxServerEventBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribe subscribes to events which include parent (serverWithTimeout) events
|
||||||
|
// plus EvCanRequestAgain.
|
||||||
|
func (s *serverWithLimits) subscribe(eventCallback func(event Event)) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.childEventCb = eventCallback
|
||||||
|
s.serverWithTimeout.subscribe(s.eventCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventCallback is called by parent (serverWithTimeout) event subscription.
|
||||||
|
func (s *serverWithLimits) eventCallback(event Event) {
|
||||||
|
s.lock.Lock()
|
||||||
|
var sendCanRequestAgain bool
|
||||||
|
passEvent := true
|
||||||
|
switch event.Type {
|
||||||
|
case EvTimeout:
|
||||||
|
id := event.Data.(RequestResponse).ID
|
||||||
|
s.softTimeouts[id] = struct{}{}
|
||||||
|
s.timeoutCount++
|
||||||
|
s.parallelLimit -= parallelAdjustDown
|
||||||
|
if s.parallelLimit < minParallelLimit {
|
||||||
|
s.parallelLimit = minParallelLimit
|
||||||
|
}
|
||||||
|
log.Debug("Server timeout", "count", s.timeoutCount, "parallelLimit", s.parallelLimit)
|
||||||
|
case EvResponse, EvFail:
|
||||||
|
id := event.Data.(RequestResponse).ID
|
||||||
|
if _, ok := s.softTimeouts[id]; ok {
|
||||||
|
delete(s.softTimeouts, id)
|
||||||
|
s.timeoutCount--
|
||||||
|
log.Debug("Server timeout finalized", "count", s.timeoutCount, "parallelLimit", s.parallelLimit)
|
||||||
|
}
|
||||||
|
if event.Type == EvResponse && s.pendingCount >= int(s.parallelLimit) {
|
||||||
|
s.parallelLimit += parallelAdjustUp
|
||||||
|
}
|
||||||
|
s.pendingCount--
|
||||||
|
if s.canRequest() {
|
||||||
|
sendCanRequestAgain = s.sendEvent
|
||||||
|
s.sendEvent = false
|
||||||
|
}
|
||||||
|
if event.Type == EvFail {
|
||||||
|
s.failLocked("failed request")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// server event; check rate limit
|
||||||
|
if s.serverEventBuffer < maxServerEventBuffer {
|
||||||
|
now := s.clock.Now()
|
||||||
|
sinceUpdate := time.Duration(now - s.eventBufferUpdated)
|
||||||
|
if sinceUpdate >= maxServerEventRate*time.Duration(maxServerEventBuffer-s.serverEventBuffer) {
|
||||||
|
s.serverEventBuffer = maxServerEventBuffer
|
||||||
|
s.eventBufferUpdated = now
|
||||||
|
} else {
|
||||||
|
addBuffer := int(sinceUpdate / maxServerEventRate)
|
||||||
|
s.serverEventBuffer += addBuffer
|
||||||
|
s.eventBufferUpdated += mclock.AbsTime(maxServerEventRate * time.Duration(addBuffer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.serverEventBuffer > 0 {
|
||||||
|
s.serverEventBuffer--
|
||||||
|
} else {
|
||||||
|
passEvent = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
childEventCb := s.childEventCb
|
||||||
|
s.lock.Unlock()
|
||||||
|
if passEvent && childEventCb != nil {
|
||||||
|
childEventCb(event)
|
||||||
|
}
|
||||||
|
if sendCanRequestAgain && childEventCb != nil {
|
||||||
|
childEventCb(Event{Type: EvCanRequestAgain})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendRequest sends a request through the parent (serverWithTimeout).
|
||||||
|
func (s *serverWithLimits) sendRequest(request Request) (reqId ID) {
|
||||||
|
s.lock.Lock()
|
||||||
|
s.pendingCount++
|
||||||
|
s.lock.Unlock()
|
||||||
|
return s.serverWithTimeout.sendRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsubscribe stops all goroutines associated with the server.
|
||||||
|
func (s *serverWithLimits) unsubscribe() {
|
||||||
|
s.lock.Lock()
|
||||||
|
if s.delayTimer != nil {
|
||||||
|
s.delayTimer.Stop()
|
||||||
|
s.delayTimer = nil
|
||||||
|
}
|
||||||
|
s.childEventCb = nil
|
||||||
|
s.lock.Unlock()
|
||||||
|
s.serverWithTimeout.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// canRequest checks whether a new request can be started.
|
||||||
|
func (s *serverWithLimits) canRequest() bool {
|
||||||
|
if s.delayTimer != nil || s.pendingCount >= int(s.parallelLimit) || s.timeoutCount > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if s.parallelLimit < minParallelLimit {
|
||||||
|
s.parallelLimit = minParallelLimit
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// canRequestNow checks whether a new request can be started, according to the
|
||||||
|
// current in-flight request count and parallelLimit, and also the failure delay
|
||||||
|
// timer.
|
||||||
|
// If it returns false then it is guaranteed that an EvCanRequestAgain will be
|
||||||
|
// sent whenever the server becomes available for requesting again.
|
||||||
|
func (s *serverWithLimits) canRequestNow() bool {
|
||||||
|
var sendCanRequestAgain bool
|
||||||
|
s.lock.Lock()
|
||||||
|
canRequest := s.canRequest()
|
||||||
|
if canRequest {
|
||||||
|
sendCanRequestAgain = s.sendEvent
|
||||||
|
s.sendEvent = false
|
||||||
|
}
|
||||||
|
childEventCb := s.childEventCb
|
||||||
|
s.lock.Unlock()
|
||||||
|
if sendCanRequestAgain && childEventCb != nil {
|
||||||
|
childEventCb(Event{Type: EvCanRequestAgain})
|
||||||
|
}
|
||||||
|
return canRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// delay sets the delay timer to the given duration, disabling new requests for
|
||||||
|
// the given period.
|
||||||
|
func (s *serverWithLimits) delay(delay time.Duration) {
|
||||||
|
if s.delayTimer != nil {
|
||||||
|
// Note: if stopping the timer is unsuccessful then the resulting AfterFunc
|
||||||
|
// call will just do nothing
|
||||||
|
s.delayTimer.Stop()
|
||||||
|
s.delayTimer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.delayCounter++
|
||||||
|
delayCounter := s.delayCounter
|
||||||
|
log.Debug("Server delay started", "length", delay)
|
||||||
|
s.delayTimer = s.clock.AfterFunc(delay, func() {
|
||||||
|
log.Debug("Server delay ended", "length", delay)
|
||||||
|
var sendCanRequestAgain bool
|
||||||
|
s.lock.Lock()
|
||||||
|
if s.delayTimer != nil && s.delayCounter == delayCounter { // do nothing if there is a new timer now
|
||||||
|
s.delayTimer = nil
|
||||||
|
if s.canRequest() {
|
||||||
|
sendCanRequestAgain = s.sendEvent
|
||||||
|
s.sendEvent = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
childEventCb := s.childEventCb
|
||||||
|
s.lock.Unlock()
|
||||||
|
if sendCanRequestAgain && childEventCb != nil {
|
||||||
|
childEventCb(Event{Type: EvCanRequestAgain})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail reports that a response from the server was found invalid by the processing
|
||||||
|
// Module, disabling new requests for a dynamically adjusted time period.
|
||||||
|
func (s *serverWithLimits) fail(desc string) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.failLocked(desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// failLocked calculates the dynamic failure delay and applies it.
|
||||||
|
func (s *serverWithLimits) failLocked(desc string) {
|
||||||
|
log.Debug("Server error", "description", desc)
|
||||||
|
s.failureDelay *= 2
|
||||||
|
now := s.clock.Now()
|
||||||
|
if now > s.failureDelayEnd {
|
||||||
|
s.failureDelay *= math.Pow(2, -float64(now-s.failureDelayEnd)/float64(maxFailureDelay))
|
||||||
|
}
|
||||||
|
if s.failureDelay < float64(minFailureDelay) {
|
||||||
|
s.failureDelay = float64(minFailureDelay)
|
||||||
|
}
|
||||||
|
s.failureDelayEnd = now + mclock.AbsTime(s.failureDelay)
|
||||||
|
s.delay(time.Duration(s.failureDelay))
|
||||||
|
}
|
||||||
182
beacon/light/request/server_test.go
Normal file
182
beacon/light/request/server_test.go
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testRequest = "Life, the Universe, and Everything"
|
||||||
|
testResponse = 42
|
||||||
|
)
|
||||||
|
|
||||||
|
var testEventType = &EventType{Name: "testEvent"}
|
||||||
|
|
||||||
|
func TestServerEvents(t *testing.T) {
|
||||||
|
rs := &testRequestServer{}
|
||||||
|
clock := &mclock.Simulated{}
|
||||||
|
srv := NewServer(rs, clock)
|
||||||
|
var lastEventType *EventType
|
||||||
|
srv.subscribe(func(event Event) { lastEventType = event.Type })
|
||||||
|
evTypeName := func(evType *EventType) string {
|
||||||
|
if evType == nil {
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
return evType.Name
|
||||||
|
}
|
||||||
|
expEvent := func(expType *EventType) {
|
||||||
|
if lastEventType != expType {
|
||||||
|
t.Errorf("Wrong event type (expected %s, got %s)", evTypeName(expType), evTypeName(lastEventType))
|
||||||
|
}
|
||||||
|
lastEventType = nil
|
||||||
|
}
|
||||||
|
// user events should simply be passed through
|
||||||
|
rs.eventCb(Event{Type: testEventType})
|
||||||
|
expEvent(testEventType)
|
||||||
|
// send request, soft timeout, then valid response
|
||||||
|
srv.sendRequest(testRequest)
|
||||||
|
clock.WaitForTimers(1)
|
||||||
|
clock.Run(softRequestTimeout)
|
||||||
|
expEvent(EvTimeout)
|
||||||
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||||
|
expEvent(EvResponse)
|
||||||
|
// send request, hard timeout (response after hard timeout should be ignored)
|
||||||
|
srv.sendRequest(testRequest)
|
||||||
|
clock.WaitForTimers(1)
|
||||||
|
clock.Run(softRequestTimeout)
|
||||||
|
expEvent(EvTimeout)
|
||||||
|
clock.WaitForTimers(1)
|
||||||
|
clock.Run(hardRequestTimeout)
|
||||||
|
expEvent(EvFail)
|
||||||
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||||
|
expEvent(nil)
|
||||||
|
srv.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerParallel(t *testing.T) {
|
||||||
|
rs := &testRequestServer{}
|
||||||
|
srv := NewServer(rs, &mclock.Simulated{})
|
||||||
|
srv.subscribe(func(event Event) {})
|
||||||
|
|
||||||
|
expSend := func(expSent int) {
|
||||||
|
var sent int
|
||||||
|
for sent <= expSent {
|
||||||
|
if !srv.canRequestNow() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sent++
|
||||||
|
srv.sendRequest(testRequest)
|
||||||
|
}
|
||||||
|
if sent != expSent {
|
||||||
|
t.Errorf("Wrong number of parallel requests accepted (expected %d, got %d)", expSent, sent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// max out parallel allowance
|
||||||
|
expSend(defaultParallelLimit)
|
||||||
|
// 1 answered, should accept 1 more
|
||||||
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||||
|
expSend(1)
|
||||||
|
// 2 answered, should accept 2 more
|
||||||
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 2, Request: testRequest, Response: testResponse}})
|
||||||
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 3, Request: testRequest, Response: testResponse}})
|
||||||
|
expSend(2)
|
||||||
|
// failed request, should decrease allowance and not accept more
|
||||||
|
rs.eventCb(Event{Type: EvFail, Data: RequestResponse{ID: 4, Request: testRequest}})
|
||||||
|
expSend(0)
|
||||||
|
srv.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerFail(t *testing.T) {
|
||||||
|
rs := &testRequestServer{}
|
||||||
|
clock := &mclock.Simulated{}
|
||||||
|
srv := NewServer(rs, clock)
|
||||||
|
srv.subscribe(func(event Event) {})
|
||||||
|
expCanRequest := func(expCanRequest bool) {
|
||||||
|
if canRequest := srv.canRequestNow(); canRequest != expCanRequest {
|
||||||
|
t.Errorf("Wrong result for canRequestNow (expected %v, got %v)", expCanRequest, canRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// timed out request
|
||||||
|
expCanRequest(true)
|
||||||
|
srv.sendRequest(testRequest)
|
||||||
|
clock.WaitForTimers(1)
|
||||||
|
expCanRequest(true)
|
||||||
|
clock.Run(softRequestTimeout)
|
||||||
|
expCanRequest(false) // cannot request when there is a timed out request
|
||||||
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||||
|
expCanRequest(true)
|
||||||
|
// explicit server.Fail
|
||||||
|
srv.fail("")
|
||||||
|
clock.WaitForTimers(1)
|
||||||
|
expCanRequest(false) // cannot request for a while after a failure
|
||||||
|
clock.Run(minFailureDelay)
|
||||||
|
expCanRequest(true)
|
||||||
|
// request returned with EvFail
|
||||||
|
srv.sendRequest(testRequest)
|
||||||
|
rs.eventCb(Event{Type: EvFail, Data: RequestResponse{ID: 2, Request: testRequest}})
|
||||||
|
clock.WaitForTimers(1)
|
||||||
|
expCanRequest(false) // EvFail should also start failure delay
|
||||||
|
clock.Run(minFailureDelay)
|
||||||
|
expCanRequest(false) // second failure delay is longer, should still be disabled
|
||||||
|
clock.Run(minFailureDelay)
|
||||||
|
expCanRequest(true)
|
||||||
|
srv.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerEventRateLimit(t *testing.T) {
|
||||||
|
rs := &testRequestServer{}
|
||||||
|
clock := &mclock.Simulated{}
|
||||||
|
srv := NewServer(rs, clock)
|
||||||
|
var eventCount int
|
||||||
|
srv.subscribe(func(event Event) {
|
||||||
|
eventCount++
|
||||||
|
})
|
||||||
|
expEvents := func(send, expAllowed int) {
|
||||||
|
eventCount = 0
|
||||||
|
for sent := 0; sent < send; sent++ {
|
||||||
|
rs.eventCb(Event{Type: testEventType})
|
||||||
|
}
|
||||||
|
if eventCount != expAllowed {
|
||||||
|
t.Errorf("Wrong number of server events passing rate limitation (sent %d, expected %d, got %d)", send, expAllowed, eventCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
|
||||||
|
clock.Run(maxServerEventRate)
|
||||||
|
expEvents(5, 1)
|
||||||
|
clock.Run(maxServerEventRate * maxServerEventBuffer * 2)
|
||||||
|
expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
|
||||||
|
srv.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerUnsubscribe(t *testing.T) {
|
||||||
|
rs := &testRequestServer{}
|
||||||
|
clock := &mclock.Simulated{}
|
||||||
|
srv := NewServer(rs, clock)
|
||||||
|
var eventCount int
|
||||||
|
srv.subscribe(func(event Event) {
|
||||||
|
eventCount++
|
||||||
|
})
|
||||||
|
eventCb := rs.eventCb
|
||||||
|
eventCb(Event{Type: testEventType})
|
||||||
|
if eventCount != 1 {
|
||||||
|
t.Errorf("Server event callback not called before unsubscribe")
|
||||||
|
}
|
||||||
|
srv.unsubscribe()
|
||||||
|
if rs.eventCb != nil {
|
||||||
|
t.Errorf("Server event callback not removed after unsubscribe")
|
||||||
|
}
|
||||||
|
eventCb(Event{Type: testEventType})
|
||||||
|
if eventCount != 1 {
|
||||||
|
t.Errorf("Server event callback called after unsubscribe")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testRequestServer struct {
|
||||||
|
eventCb func(Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *testRequestServer) Name() string { return "" }
|
||||||
|
func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb }
|
||||||
|
func (rs *testRequestServer) SendRequest(ID, Request) {}
|
||||||
|
func (rs *testRequestServer) Unsubscribe() { rs.eventCb = nil }
|
||||||
202
beacon/light/sync/head_sync.go
Normal file
202
beacon/light/sync/head_sync.go
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type headTracker interface {
|
||||||
|
ValidateOptimistic(update types.OptimisticUpdate) (bool, error)
|
||||||
|
ValidateFinality(head types.FinalityUpdate) (bool, error)
|
||||||
|
ValidatedFinality() (types.FinalityUpdate, bool)
|
||||||
|
SetPrefetchHead(head types.HeadInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeadSync implements request.Module; it updates the validated and prefetch
|
||||||
|
// heads of HeadTracker based on the EvHead and EvSignedHead events coming from
|
||||||
|
// registered servers.
|
||||||
|
// It can also postpone the validation of the latest announced signed head
|
||||||
|
// until the committee chain is synced up to at least the required period.
|
||||||
|
type HeadSync struct {
|
||||||
|
headTracker headTracker
|
||||||
|
chain committeeChain
|
||||||
|
nextSyncPeriod uint64
|
||||||
|
chainInit bool
|
||||||
|
unvalidatedOptimistic map[request.Server]types.OptimisticUpdate
|
||||||
|
unvalidatedFinality map[request.Server]types.FinalityUpdate
|
||||||
|
serverHeads map[request.Server]types.HeadInfo
|
||||||
|
reqFinalityEpoch map[request.Server]uint64 // next epoch to request finality update
|
||||||
|
headServerCount map[types.HeadInfo]headServerCount
|
||||||
|
headCounter uint64
|
||||||
|
prefetchHead types.HeadInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// headServerCount is associated with most recently seen head infos; it counts
|
||||||
|
// the number of servers currently having the given head info as their announced
|
||||||
|
// head and a counter signaling how recent that head is.
|
||||||
|
// This data is used for selecting the prefetch head.
|
||||||
|
type headServerCount struct {
|
||||||
|
serverCount int
|
||||||
|
headCounter uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHeadSync creates a new HeadSync.
|
||||||
|
func NewHeadSync(headTracker headTracker, chain committeeChain) *HeadSync {
|
||||||
|
s := &HeadSync{
|
||||||
|
headTracker: headTracker,
|
||||||
|
chain: chain,
|
||||||
|
unvalidatedOptimistic: make(map[request.Server]types.OptimisticUpdate),
|
||||||
|
unvalidatedFinality: make(map[request.Server]types.FinalityUpdate),
|
||||||
|
serverHeads: make(map[request.Server]types.HeadInfo),
|
||||||
|
headServerCount: make(map[types.HeadInfo]headServerCount),
|
||||||
|
reqFinalityEpoch: make(map[request.Server]uint64),
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process implements request.Module.
|
||||||
|
func (s *HeadSync) Process(requester request.Requester, events []request.Event) {
|
||||||
|
nextPeriod, chainInit := s.chain.NextSyncPeriod()
|
||||||
|
if nextPeriod != s.nextSyncPeriod || chainInit != s.chainInit {
|
||||||
|
s.nextSyncPeriod, s.chainInit = nextPeriod, chainInit
|
||||||
|
s.processUnvalidatedUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
switch event.Type {
|
||||||
|
case EvNewHead:
|
||||||
|
s.setServerHead(event.Server, event.Data.(types.HeadInfo))
|
||||||
|
case EvNewOptimisticUpdate:
|
||||||
|
update := event.Data.(types.OptimisticUpdate)
|
||||||
|
s.newOptimisticUpdate(event.Server, update)
|
||||||
|
epoch := update.Attested.Epoch()
|
||||||
|
if epoch < s.reqFinalityEpoch[event.Server] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if finality, ok := s.headTracker.ValidatedFinality(); ok && finality.Attested.Header.Epoch() >= epoch {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
requester.Send(event.Server, ReqFinality{})
|
||||||
|
s.reqFinalityEpoch[event.Server] = epoch + 1
|
||||||
|
case EvNewFinalityUpdate:
|
||||||
|
s.newFinalityUpdate(event.Server, event.Data.(types.FinalityUpdate))
|
||||||
|
case request.EvResponse:
|
||||||
|
_, _, resp := event.RequestInfo()
|
||||||
|
s.newFinalityUpdate(event.Server, resp.(types.FinalityUpdate))
|
||||||
|
case request.EvUnregistered:
|
||||||
|
s.setServerHead(event.Server, types.HeadInfo{})
|
||||||
|
delete(s.serverHeads, event.Server)
|
||||||
|
delete(s.unvalidatedOptimistic, event.Server)
|
||||||
|
delete(s.unvalidatedFinality, event.Server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newOptimisticUpdate handles received optimistic update; either validates it if
|
||||||
|
// the chain is properly synced or stores it for further validation.
|
||||||
|
func (s *HeadSync) newOptimisticUpdate(server request.Server, optimisticUpdate types.OptimisticUpdate) {
|
||||||
|
if !s.chainInit || types.SyncPeriod(optimisticUpdate.SignatureSlot) > s.nextSyncPeriod {
|
||||||
|
s.unvalidatedOptimistic[server] = optimisticUpdate
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := s.headTracker.ValidateOptimistic(optimisticUpdate); err != nil {
|
||||||
|
log.Debug("Error validating optimistic update", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFinalityUpdate handles received finality update; either validates it if
|
||||||
|
// the chain is properly synced or stores it for further validation.
|
||||||
|
func (s *HeadSync) newFinalityUpdate(server request.Server, finalityUpdate types.FinalityUpdate) {
|
||||||
|
if !s.chainInit || types.SyncPeriod(finalityUpdate.SignatureSlot) > s.nextSyncPeriod {
|
||||||
|
s.unvalidatedFinality[server] = finalityUpdate
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := s.headTracker.ValidateFinality(finalityUpdate); err != nil {
|
||||||
|
log.Debug("Error validating finality update", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processUnvalidatedUpdates iterates the list of unvalidated updates and validates
|
||||||
|
// those which can be validated.
|
||||||
|
func (s *HeadSync) processUnvalidatedUpdates() {
|
||||||
|
if !s.chainInit {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for server, optimisticUpdate := range s.unvalidatedOptimistic {
|
||||||
|
if types.SyncPeriod(optimisticUpdate.SignatureSlot) <= s.nextSyncPeriod {
|
||||||
|
if _, err := s.headTracker.ValidateOptimistic(optimisticUpdate); err != nil {
|
||||||
|
log.Debug("Error validating deferred optimistic update", "error", err)
|
||||||
|
}
|
||||||
|
delete(s.unvalidatedOptimistic, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for server, finalityUpdate := range s.unvalidatedFinality {
|
||||||
|
if types.SyncPeriod(finalityUpdate.SignatureSlot) <= s.nextSyncPeriod {
|
||||||
|
if _, err := s.headTracker.ValidateFinality(finalityUpdate); err != nil {
|
||||||
|
log.Debug("Error validating deferred finality update", "error", err)
|
||||||
|
}
|
||||||
|
delete(s.unvalidatedFinality, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setServerHead processes non-validated server head announcements and updates
|
||||||
|
// the prefetch head if necessary.
|
||||||
|
func (s *HeadSync) setServerHead(server request.Server, head types.HeadInfo) bool {
|
||||||
|
if oldHead, ok := s.serverHeads[server]; ok {
|
||||||
|
if head == oldHead {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
h := s.headServerCount[oldHead]
|
||||||
|
if h.serverCount--; h.serverCount > 0 {
|
||||||
|
s.headServerCount[oldHead] = h
|
||||||
|
} else {
|
||||||
|
delete(s.headServerCount, oldHead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if head != (types.HeadInfo{}) {
|
||||||
|
h, ok := s.headServerCount[head]
|
||||||
|
if !ok {
|
||||||
|
s.headCounter++
|
||||||
|
h.headCounter = s.headCounter
|
||||||
|
}
|
||||||
|
h.serverCount++
|
||||||
|
s.headServerCount[head] = h
|
||||||
|
s.serverHeads[server] = head
|
||||||
|
} else {
|
||||||
|
delete(s.serverHeads, server)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
bestHead types.HeadInfo
|
||||||
|
bestHeadInfo headServerCount
|
||||||
|
)
|
||||||
|
for head, headServerCount := range s.headServerCount {
|
||||||
|
if headServerCount.serverCount > bestHeadInfo.serverCount ||
|
||||||
|
(headServerCount.serverCount == bestHeadInfo.serverCount && headServerCount.headCounter > bestHeadInfo.headCounter) {
|
||||||
|
bestHead, bestHeadInfo = head, headServerCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bestHead == s.prefetchHead {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s.prefetchHead = bestHead
|
||||||
|
s.headTracker.SetPrefetchHead(bestHead)
|
||||||
|
return true
|
||||||
|
}
|
||||||
183
beacon/light/sync/head_sync_test.go
Normal file
183
beacon/light/sync/head_sync_test.go
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testServer1 = testServer("testServer1")
|
||||||
|
testServer2 = testServer("testServer2")
|
||||||
|
testServer3 = testServer("testServer3")
|
||||||
|
testServer4 = testServer("testServer4")
|
||||||
|
testServer5 = testServer("testServer5")
|
||||||
|
|
||||||
|
testHead0 = types.HeadInfo{}
|
||||||
|
testHead1 = types.HeadInfo{Slot: 123, BlockRoot: common.Hash{1}}
|
||||||
|
testHead2 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{2}}
|
||||||
|
testHead3 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{3}}
|
||||||
|
testHead4 = types.HeadInfo{Slot: 125, BlockRoot: common.Hash{4}}
|
||||||
|
|
||||||
|
testOptUpdate1 = types.OptimisticUpdate{SignatureSlot: 0x0124, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x0123, StateRoot: common.Hash{1}}}}
|
||||||
|
testOptUpdate2 = types.OptimisticUpdate{SignatureSlot: 0x2010, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x200e, StateRoot: common.Hash{2}}}}
|
||||||
|
// testOptUpdate3 is at the end of period 1 but signed in period 2
|
||||||
|
testOptUpdate3 = types.OptimisticUpdate{SignatureSlot: 0x4000, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x3fff, StateRoot: common.Hash{3}}}}
|
||||||
|
testOptUpdate4 = types.OptimisticUpdate{SignatureSlot: 0x6444, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x6443, StateRoot: common.Hash{4}}}}
|
||||||
|
)
|
||||||
|
|
||||||
|
func finality(opt types.OptimisticUpdate) types.FinalityUpdate {
|
||||||
|
return types.FinalityUpdate{
|
||||||
|
SignatureSlot: opt.SignatureSlot,
|
||||||
|
Attested: opt.Attested,
|
||||||
|
Finalized: types.HeaderWithExecProof{Header: types.Header{Slot: (opt.Attested.Header.Slot - 64) & uint64(0xffffffffffffffe0)}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testServer string
|
||||||
|
|
||||||
|
func (t testServer) Name() string {
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidatedHead(t *testing.T) {
|
||||||
|
chain := &TestCommitteeChain{}
|
||||||
|
ht := &TestHeadTracker{}
|
||||||
|
headSync := NewHeadSync(ht, chain)
|
||||||
|
ts := NewTestScheduler(t, headSync)
|
||||||
|
|
||||||
|
ht.ExpValidated(t, 0, nil)
|
||||||
|
|
||||||
|
ts.AddServer(testServer1, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate1)
|
||||||
|
ts.Run(1, testServer1, ReqFinality{})
|
||||||
|
// announced head should be queued because of uninitialized chain
|
||||||
|
ht.ExpValidated(t, 1, nil)
|
||||||
|
|
||||||
|
chain.SetNextSyncPeriod(0) // initialize chain
|
||||||
|
ts.Run(2)
|
||||||
|
// expect previously queued head to be validated
|
||||||
|
ht.ExpValidated(t, 2, []types.OptimisticUpdate{testOptUpdate1})
|
||||||
|
|
||||||
|
chain.SetNextSyncPeriod(1)
|
||||||
|
ts.ServerEvent(EvNewFinalityUpdate, testServer1, finality(testOptUpdate2))
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate2)
|
||||||
|
ts.AddServer(testServer2, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer2, testOptUpdate2)
|
||||||
|
ts.Run(3)
|
||||||
|
// expect both head announcements to be validated instantly
|
||||||
|
ht.ExpValidated(t, 3, []types.OptimisticUpdate{testOptUpdate2, testOptUpdate2})
|
||||||
|
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate3)
|
||||||
|
ts.AddServer(testServer3, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer3, testOptUpdate4)
|
||||||
|
// finality should be requested from both servers
|
||||||
|
ts.Run(4, testServer1, ReqFinality{}, testServer3, ReqFinality{})
|
||||||
|
// future period announced heads should be queued
|
||||||
|
ht.ExpValidated(t, 4, nil)
|
||||||
|
|
||||||
|
chain.SetNextSyncPeriod(2)
|
||||||
|
ts.Run(5)
|
||||||
|
// testOptUpdate3 can be validated now but not testOptUpdate4
|
||||||
|
ht.ExpValidated(t, 5, []types.OptimisticUpdate{testOptUpdate3})
|
||||||
|
|
||||||
|
ts.AddServer(testServer4, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer4, testOptUpdate3)
|
||||||
|
// new server joined with recent optimistic update but still no finality; should be requested
|
||||||
|
ts.Run(6, testServer4, ReqFinality{})
|
||||||
|
ht.ExpValidated(t, 6, []types.OptimisticUpdate{testOptUpdate3})
|
||||||
|
|
||||||
|
ts.AddServer(testServer5, 1)
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(6, 1), finality(testOptUpdate3))
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer5, testOptUpdate3)
|
||||||
|
// finality update request answered; new server should not be requested
|
||||||
|
ts.Run(7)
|
||||||
|
ht.ExpValidated(t, 7, []types.OptimisticUpdate{testOptUpdate3})
|
||||||
|
|
||||||
|
// server 3 disconnected without proving period 3, its announced head should be dropped
|
||||||
|
ts.RemoveServer(testServer3)
|
||||||
|
ts.Run(8)
|
||||||
|
ht.ExpValidated(t, 8, nil)
|
||||||
|
|
||||||
|
chain.SetNextSyncPeriod(3)
|
||||||
|
ts.Run(9)
|
||||||
|
// testOptUpdate4 could be validated now but it's not queued by any registered server
|
||||||
|
ht.ExpValidated(t, 9, nil)
|
||||||
|
|
||||||
|
ts.ServerEvent(EvNewFinalityUpdate, testServer2, finality(testOptUpdate4))
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer2, testOptUpdate4)
|
||||||
|
ts.Run(10)
|
||||||
|
// now testOptUpdate4 should be validated
|
||||||
|
ht.ExpValidated(t, 10, []types.OptimisticUpdate{testOptUpdate4})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefetchHead(t *testing.T) {
|
||||||
|
chain := &TestCommitteeChain{}
|
||||||
|
ht := &TestHeadTracker{}
|
||||||
|
headSync := NewHeadSync(ht, chain)
|
||||||
|
ts := NewTestScheduler(t, headSync)
|
||||||
|
|
||||||
|
ht.ExpPrefetch(t, 0, testHead0) // no servers registered
|
||||||
|
|
||||||
|
ts.AddServer(testServer1, 1)
|
||||||
|
ts.ServerEvent(EvNewHead, testServer1, testHead1)
|
||||||
|
ts.Run(1)
|
||||||
|
ht.ExpPrefetch(t, 1, testHead1) // s1: h1
|
||||||
|
|
||||||
|
ts.AddServer(testServer2, 1)
|
||||||
|
ts.ServerEvent(EvNewHead, testServer2, testHead2)
|
||||||
|
ts.Run(2)
|
||||||
|
ht.ExpPrefetch(t, 2, testHead2) // s1: h1, s2: h2
|
||||||
|
|
||||||
|
ts.ServerEvent(EvNewHead, testServer1, testHead2)
|
||||||
|
ts.Run(3)
|
||||||
|
ht.ExpPrefetch(t, 3, testHead2) // s1: h2, s2: h2
|
||||||
|
|
||||||
|
ts.AddServer(testServer3, 1)
|
||||||
|
ts.ServerEvent(EvNewHead, testServer3, testHead3)
|
||||||
|
ts.Run(4)
|
||||||
|
ht.ExpPrefetch(t, 4, testHead2) // s1: h2, s2: h2, s3: h3
|
||||||
|
|
||||||
|
ts.AddServer(testServer4, 1)
|
||||||
|
ts.ServerEvent(EvNewHead, testServer4, testHead4)
|
||||||
|
ts.Run(5)
|
||||||
|
ht.ExpPrefetch(t, 5, testHead2) // s1: h2, s2: h2, s3: h3, s4: h4
|
||||||
|
|
||||||
|
ts.ServerEvent(EvNewHead, testServer2, testHead3)
|
||||||
|
ts.Run(6)
|
||||||
|
ht.ExpPrefetch(t, 6, testHead3) // s1: h2, s2: h3, s3: h3, s4: h4
|
||||||
|
|
||||||
|
ts.RemoveServer(testServer3)
|
||||||
|
ts.Run(7)
|
||||||
|
ht.ExpPrefetch(t, 7, testHead4) // s1: h2, s2: h3, s4: h4
|
||||||
|
|
||||||
|
ts.RemoveServer(testServer1)
|
||||||
|
ts.Run(8)
|
||||||
|
ht.ExpPrefetch(t, 8, testHead4) // s2: h3, s4: h4
|
||||||
|
|
||||||
|
ts.RemoveServer(testServer4)
|
||||||
|
ts.Run(9)
|
||||||
|
ht.ExpPrefetch(t, 9, testHead3) // s2: h3
|
||||||
|
|
||||||
|
ts.RemoveServer(testServer2)
|
||||||
|
ts.Run(10)
|
||||||
|
ht.ExpPrefetch(t, 10, testHead0) // no servers registered
|
||||||
|
}
|
||||||
259
beacon/light/sync/test_helpers.go
Normal file
259
beacon/light/sync/test_helpers.go
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type requestWithID struct {
|
||||||
|
sid request.ServerAndID
|
||||||
|
request request.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestScheduler struct {
|
||||||
|
t *testing.T
|
||||||
|
module request.Module
|
||||||
|
events []request.Event
|
||||||
|
servers []request.Server
|
||||||
|
allowance map[request.Server]int
|
||||||
|
sent map[int][]requestWithID
|
||||||
|
testIndex int
|
||||||
|
expFail map[request.Server]int // expected Server.Fail calls during next Run
|
||||||
|
lastId request.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestScheduler(t *testing.T, module request.Module) *TestScheduler {
|
||||||
|
return &TestScheduler{
|
||||||
|
t: t,
|
||||||
|
module: module,
|
||||||
|
allowance: make(map[request.Server]int),
|
||||||
|
expFail: make(map[request.Server]int),
|
||||||
|
sent: make(map[int][]requestWithID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) Run(testIndex int, exp ...any) {
|
||||||
|
expReqs := make([]requestWithID, len(exp)/2)
|
||||||
|
id := ts.lastId
|
||||||
|
for i := range expReqs {
|
||||||
|
id++
|
||||||
|
expReqs[i] = requestWithID{
|
||||||
|
sid: request.ServerAndID{Server: exp[i*2].(request.Server), ID: id},
|
||||||
|
request: exp[i*2+1].(request.Request),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(expReqs) == 0 {
|
||||||
|
expReqs = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.testIndex = testIndex
|
||||||
|
ts.module.Process(ts, ts.events)
|
||||||
|
ts.events = nil
|
||||||
|
|
||||||
|
for server, count := range ts.expFail {
|
||||||
|
delete(ts.expFail, server)
|
||||||
|
if count == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ts.t.Errorf("Missing %d Server.Fail(s) from server %s in test case #%d", count, server.Name(), testIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(ts.sent[testIndex], expReqs) {
|
||||||
|
ts.t.Errorf("Wrong sent requests in test case #%d (expected %v, got %v)", testIndex, expReqs, ts.sent[testIndex])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) CanSendTo() (cs []request.Server) {
|
||||||
|
for _, server := range ts.servers {
|
||||||
|
if ts.allowance[server] > 0 {
|
||||||
|
cs = append(cs, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) Send(server request.Server, req request.Request) request.ID {
|
||||||
|
ts.lastId++
|
||||||
|
ts.sent[ts.testIndex] = append(ts.sent[ts.testIndex], requestWithID{
|
||||||
|
sid: request.ServerAndID{Server: server, ID: ts.lastId},
|
||||||
|
request: req,
|
||||||
|
})
|
||||||
|
ts.allowance[server]--
|
||||||
|
return ts.lastId
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) Fail(server request.Server, desc string) {
|
||||||
|
if ts.expFail[server] == 0 {
|
||||||
|
ts.t.Errorf("Unexpected Fail from server %s in test case #%d: %s", server.Name(), ts.testIndex, desc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ts.expFail[server]--
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) Request(testIndex, reqIndex int) requestWithID {
|
||||||
|
if len(ts.sent[testIndex]) < reqIndex {
|
||||||
|
ts.t.Errorf("Missing request from test case %d index %d", testIndex, reqIndex)
|
||||||
|
return requestWithID{}
|
||||||
|
}
|
||||||
|
return ts.sent[testIndex][reqIndex-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) ServerEvent(evType *request.EventType, server request.Server, data any) {
|
||||||
|
ts.events = append(ts.events, request.Event{
|
||||||
|
Type: evType,
|
||||||
|
Server: server,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) RequestEvent(evType *request.EventType, req requestWithID, resp request.Response) {
|
||||||
|
if req.request == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ts.events = append(ts.events, request.Event{
|
||||||
|
Type: evType,
|
||||||
|
Server: req.sid.Server,
|
||||||
|
Data: request.RequestResponse{
|
||||||
|
ID: req.sid.ID,
|
||||||
|
Request: req.request,
|
||||||
|
Response: resp,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) AddServer(server request.Server, allowance int) {
|
||||||
|
ts.servers = append(ts.servers, server)
|
||||||
|
ts.allowance[server] = allowance
|
||||||
|
ts.ServerEvent(request.EvRegistered, server, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) RemoveServer(server request.Server) {
|
||||||
|
ts.servers = append(ts.servers, server)
|
||||||
|
for i, s := range ts.servers {
|
||||||
|
if s == server {
|
||||||
|
copy(ts.servers[i:len(ts.servers)-1], ts.servers[i+1:])
|
||||||
|
ts.servers = ts.servers[:len(ts.servers)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(ts.allowance, server)
|
||||||
|
ts.ServerEvent(request.EvUnregistered, server, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) AddAllowance(server request.Server, allowance int) {
|
||||||
|
ts.allowance[server] += allowance
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestScheduler) ExpFail(server request.Server) {
|
||||||
|
ts.expFail[server]++
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestCommitteeChain struct {
|
||||||
|
fsp, nsp uint64
|
||||||
|
init bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
|
||||||
|
tc.fsp, tc.nsp, tc.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
|
||||||
|
period := update.AttestedHeader.Header.SyncPeriod()
|
||||||
|
if period < tc.fsp || period > tc.nsp || !tc.init {
|
||||||
|
return light.ErrInvalidPeriod
|
||||||
|
}
|
||||||
|
if period == tc.nsp {
|
||||||
|
tc.nsp++
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TestCommitteeChain) NextSyncPeriod() (uint64, bool) {
|
||||||
|
return tc.nsp, tc.init
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
|
||||||
|
if tc.init != ExpInit {
|
||||||
|
t.Errorf("Incorrect init flag (expected %v, got %v)", ExpInit, tc.init)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) {
|
||||||
|
tc.init, tc.nsp = true, nsp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) {
|
||||||
|
tc.ExpInit(t, true)
|
||||||
|
if tc.nsp != expNsp {
|
||||||
|
t.Errorf("Incorrect NextSyncPeriod (expected %d, got %d)", expNsp, tc.nsp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestHeadTracker struct {
|
||||||
|
phead types.HeadInfo
|
||||||
|
validated []types.OptimisticUpdate
|
||||||
|
finality types.FinalityUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *TestHeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, error) {
|
||||||
|
ht.validated = append(ht.validated, update)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *TestHeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) {
|
||||||
|
ht.finality = update
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *TestHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) {
|
||||||
|
return ht.finality, ht.finality.Attested.Header != (types.Header{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *TestHeadTracker) ExpValidated(t *testing.T, tci int, expHeads []types.OptimisticUpdate) {
|
||||||
|
for i, expHead := range expHeads {
|
||||||
|
if i >= len(ht.validated) {
|
||||||
|
t.Errorf("Missing validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got none)", tci, i, expHead.Attested.Header.Slot, expHead.Attested.Header.Hash())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(ht.validated[i], expHead) {
|
||||||
|
vhead := ht.validated[i].Attested.Header
|
||||||
|
t.Errorf("Wrong validated head in test case #%d index #%d (expected {slot %d blockRoot %x}, got {slot %d blockRoot %x})", tci, i, expHead.Attested.Header.Slot, expHead.Attested.Header.Hash(), vhead.Slot, vhead.Hash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := len(expHeads); i < len(ht.validated); i++ {
|
||||||
|
vhead := ht.validated[i].Attested.Header
|
||||||
|
t.Errorf("Unexpected validated head in test case #%d index #%d (expected none, got {slot %d blockRoot %x})", tci, i, vhead.Slot, vhead.Hash())
|
||||||
|
}
|
||||||
|
ht.validated = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *TestHeadTracker) SetPrefetchHead(head types.HeadInfo) {
|
||||||
|
ht.phead = head
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *TestHeadTracker) ExpPrefetch(t *testing.T, tci int, exp types.HeadInfo) {
|
||||||
|
if ht.phead != exp {
|
||||||
|
t.Errorf("Wrong prefetch head in test case #%d (expected {slot %d blockRoot %x}, got {slot %d blockRoot %x})", tci, exp.Slot, exp.BlockRoot, ht.phead.Slot, ht.phead.BlockRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
47
beacon/light/sync/types.go
Normal file
47
beacon/light/sync/types.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
EvNewHead = &request.EventType{Name: "newHead"} // data: types.HeadInfo
|
||||||
|
EvNewOptimisticUpdate = &request.EventType{Name: "newOptimisticUpdate"} // data: types.OptimisticUpdate
|
||||||
|
EvNewFinalityUpdate = &request.EventType{Name: "newFinalityUpdate"} // data: types.FinalityUpdate
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ReqUpdates struct {
|
||||||
|
FirstPeriod, Count uint64
|
||||||
|
}
|
||||||
|
RespUpdates struct {
|
||||||
|
Updates []*types.LightClientUpdate
|
||||||
|
Committees []*types.SerializedSyncCommittee
|
||||||
|
}
|
||||||
|
ReqHeader common.Hash
|
||||||
|
RespHeader struct {
|
||||||
|
Header types.Header
|
||||||
|
Canonical, Finalized bool
|
||||||
|
}
|
||||||
|
ReqCheckpointData common.Hash
|
||||||
|
ReqBeaconBlock common.Hash
|
||||||
|
ReqFinality struct{}
|
||||||
|
)
|
||||||
398
beacon/light/sync/update_sync.go
Normal file
398
beacon/light/sync/update_sync.go
Normal file
|
|
@ -0,0 +1,398 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxUpdateRequest = 8 // maximum number of updates requested in a single request
|
||||||
|
|
||||||
|
type committeeChain interface {
|
||||||
|
CheckpointInit(bootstrap types.BootstrapData) error
|
||||||
|
InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error
|
||||||
|
NextSyncPeriod() (uint64, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckpointInit implements request.Module; it fetches the light client bootstrap
|
||||||
|
// data belonging to the given checkpoint hash and initializes the committee chain
|
||||||
|
// if successful.
|
||||||
|
type CheckpointInit struct {
|
||||||
|
chain committeeChain
|
||||||
|
checkpointHash common.Hash
|
||||||
|
locked request.ServerAndID
|
||||||
|
initialized bool
|
||||||
|
// per-server state is used to track the state of requesting checkpoint header
|
||||||
|
// info. Part of this info (canonical and finalized state) is not validated
|
||||||
|
// and therefore it is requested from each server separately after it has
|
||||||
|
// reported a missing checkpoint (which is also not validated info).
|
||||||
|
serverState map[request.Server]serverState
|
||||||
|
// the following fields are used to determine whether the checkpoint is on
|
||||||
|
// epoch boundary. This information is validated and therefore stored globally.
|
||||||
|
parentHash common.Hash
|
||||||
|
hasEpochInfo, epochBoundary bool
|
||||||
|
cpSlot, parentSlot uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ssDefault = iota // no action yet or checkpoint requested
|
||||||
|
ssNeedHeader // checkpoint req failed, need cp header
|
||||||
|
ssHeaderRequested // cp header requested
|
||||||
|
ssNeedParent // cp header slot %32 != 0, need parent to check epoch boundary
|
||||||
|
ssParentRequested // cp parent header requested
|
||||||
|
ssPrintStatus // has all necessary info, print log message if init still not successful
|
||||||
|
ssDone // log message printed, no more action required
|
||||||
|
)
|
||||||
|
|
||||||
|
type serverState struct {
|
||||||
|
state int
|
||||||
|
hasHeader, canonical, finalized bool // stored per server because not validated
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCheckpointInit creates a new CheckpointInit.
|
||||||
|
func NewCheckpointInit(chain committeeChain, checkpointHash common.Hash) *CheckpointInit {
|
||||||
|
return &CheckpointInit{
|
||||||
|
chain: chain,
|
||||||
|
checkpointHash: checkpointHash,
|
||||||
|
serverState: make(map[request.Server]serverState),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process implements request.Module.
|
||||||
|
func (s *CheckpointInit) Process(requester request.Requester, events []request.Event) {
|
||||||
|
if s.initialized {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
switch event.Type {
|
||||||
|
case request.EvResponse, request.EvFail, request.EvTimeout:
|
||||||
|
sid, req, resp := event.RequestInfo()
|
||||||
|
if s.locked == sid {
|
||||||
|
s.locked = request.ServerAndID{}
|
||||||
|
}
|
||||||
|
if event.Type == request.EvTimeout {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch s.serverState[sid.Server].state {
|
||||||
|
case ssDefault:
|
||||||
|
if resp != nil {
|
||||||
|
if checkpoint := resp.(*types.BootstrapData); checkpoint.Header.Hash() == common.Hash(req.(ReqCheckpointData)) {
|
||||||
|
s.chain.CheckpointInit(*checkpoint)
|
||||||
|
s.initialized = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
requester.Fail(event.Server, "invalid checkpoint data")
|
||||||
|
}
|
||||||
|
s.serverState[sid.Server] = serverState{state: ssNeedHeader}
|
||||||
|
case ssHeaderRequested:
|
||||||
|
if resp == nil {
|
||||||
|
s.serverState[sid.Server] = serverState{state: ssPrintStatus}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newState := serverState{
|
||||||
|
hasHeader: true,
|
||||||
|
canonical: resp.(RespHeader).Canonical,
|
||||||
|
finalized: resp.(RespHeader).Finalized,
|
||||||
|
}
|
||||||
|
s.cpSlot, s.parentHash = resp.(RespHeader).Header.Slot, resp.(RespHeader).Header.ParentRoot
|
||||||
|
if s.cpSlot%params.EpochLength == 0 {
|
||||||
|
s.hasEpochInfo, s.epochBoundary = true, true
|
||||||
|
}
|
||||||
|
if s.hasEpochInfo {
|
||||||
|
newState.state = ssPrintStatus
|
||||||
|
} else {
|
||||||
|
newState.state = ssNeedParent
|
||||||
|
}
|
||||||
|
s.serverState[sid.Server] = newState
|
||||||
|
case ssParentRequested:
|
||||||
|
s.parentSlot = resp.(RespHeader).Header.Slot
|
||||||
|
s.hasEpochInfo, s.epochBoundary = true, s.cpSlot/params.EpochLength > s.parentSlot/params.EpochLength
|
||||||
|
newState := s.serverState[sid.Server]
|
||||||
|
newState.state = ssPrintStatus
|
||||||
|
s.serverState[sid.Server] = newState
|
||||||
|
}
|
||||||
|
|
||||||
|
case request.EvUnregistered:
|
||||||
|
delete(s.serverState, event.Server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start a request if possible
|
||||||
|
for _, server := range requester.CanSendTo() {
|
||||||
|
switch s.serverState[server].state {
|
||||||
|
case ssDefault:
|
||||||
|
if s.locked == (request.ServerAndID{}) {
|
||||||
|
id := requester.Send(server, ReqCheckpointData(s.checkpointHash))
|
||||||
|
s.locked = request.ServerAndID{Server: server, ID: id}
|
||||||
|
}
|
||||||
|
case ssNeedHeader:
|
||||||
|
requester.Send(server, ReqHeader(s.checkpointHash))
|
||||||
|
newState := s.serverState[server]
|
||||||
|
newState.state = ssHeaderRequested
|
||||||
|
s.serverState[server] = newState
|
||||||
|
case ssNeedParent:
|
||||||
|
requester.Send(server, ReqHeader(s.parentHash))
|
||||||
|
newState := s.serverState[server]
|
||||||
|
newState.state = ssParentRequested
|
||||||
|
s.serverState[server] = newState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print log message if necessary
|
||||||
|
for server, state := range s.serverState {
|
||||||
|
if state.state != ssPrintStatus {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case !state.hasHeader:
|
||||||
|
log.Error("blsync: checkpoint block is not available, reported as unknown", "server", server.Name())
|
||||||
|
case !state.canonical:
|
||||||
|
log.Error("blsync: checkpoint block is not available, reported as non-canonical", "server", server.Name())
|
||||||
|
case !s.hasEpochInfo:
|
||||||
|
// should be available if hasHeader is true and state is ssPrintStatus
|
||||||
|
panic("checkpoint epoch info not available when printing retrieval status")
|
||||||
|
case !s.epochBoundary:
|
||||||
|
log.Error("blsync: checkpoint block is not first of epoch", "slot", s.cpSlot, "parent", s.parentSlot, "server", server.Name())
|
||||||
|
case !state.finalized:
|
||||||
|
log.Error("blsync: checkpoint block is reported as non-finalized", "server", server.Name())
|
||||||
|
default:
|
||||||
|
log.Error("blsync: checkpoint not available, but reported as finalized; specified checkpoint hash might be too old", "server", server.Name())
|
||||||
|
}
|
||||||
|
s.serverState[server] = serverState{state: ssDone}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForwardUpdateSync implements request.Module; it fetches updates between the
|
||||||
|
// committee chain head and each server's announced head. Updates are fetched
|
||||||
|
// in batches and multiple batches can also be requested in parallel.
|
||||||
|
// Out of order responses are also handled; if a batch of updates cannot be added
|
||||||
|
// to the chain immediately because of a gap then the future updates are
|
||||||
|
// remembered until they can be processed.
|
||||||
|
type ForwardUpdateSync struct {
|
||||||
|
chain committeeChain
|
||||||
|
rangeLock rangeLock
|
||||||
|
lockedIDs map[request.ServerAndID]struct{}
|
||||||
|
processQueue []updateResponse
|
||||||
|
nextSyncPeriod map[request.Server]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewForwardUpdateSync creates a new ForwardUpdateSync.
|
||||||
|
func NewForwardUpdateSync(chain committeeChain) *ForwardUpdateSync {
|
||||||
|
return &ForwardUpdateSync{
|
||||||
|
chain: chain,
|
||||||
|
rangeLock: make(rangeLock),
|
||||||
|
lockedIDs: make(map[request.ServerAndID]struct{}),
|
||||||
|
nextSyncPeriod: make(map[request.Server]uint64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rangeLock allows locking sections of an integer space, preventing the syncing
|
||||||
|
// mechanism from making requests again for sections where a not timed out request
|
||||||
|
// is already pending or where already fetched and unprocessed data is available.
|
||||||
|
type rangeLock map[uint64]int
|
||||||
|
|
||||||
|
// lock locks or unlocks the given section, depending on the sign of the add parameter.
|
||||||
|
func (r rangeLock) lock(first, count uint64, add int) {
|
||||||
|
for i := first; i < first+count; i++ {
|
||||||
|
if v := r[i] + add; v > 0 {
|
||||||
|
r[i] = v
|
||||||
|
} else {
|
||||||
|
delete(r, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstUnlocked returns the first unlocked section starting at or after start
|
||||||
|
// and not longer than maxCount.
|
||||||
|
func (r rangeLock) firstUnlocked(start, maxCount uint64) (first, count uint64) {
|
||||||
|
first = start
|
||||||
|
for {
|
||||||
|
if _, ok := r[first]; !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
first++
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
count++
|
||||||
|
if count == maxCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, ok := r[first+count]; ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// lockRange locks the range belonging to the given update request, unless the
|
||||||
|
// same request has already been locked
|
||||||
|
func (s *ForwardUpdateSync) lockRange(sid request.ServerAndID, req ReqUpdates) {
|
||||||
|
if _, ok := s.lockedIDs[sid]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.lockedIDs[sid] = struct{}{}
|
||||||
|
s.rangeLock.lock(req.FirstPeriod, req.Count, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlockRange unlocks the range belonging to the given update request, unless
|
||||||
|
// same request has already been unlocked
|
||||||
|
func (s *ForwardUpdateSync) unlockRange(sid request.ServerAndID, req ReqUpdates) {
|
||||||
|
if _, ok := s.lockedIDs[sid]; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(s.lockedIDs, sid)
|
||||||
|
s.rangeLock.lock(req.FirstPeriod, req.Count, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyRange returns true if the number of updates and the individual update
|
||||||
|
// periods in the response match the requested section.
|
||||||
|
func (s *ForwardUpdateSync) verifyRange(request ReqUpdates, response RespUpdates) bool {
|
||||||
|
if uint64(len(response.Updates)) != request.Count || uint64(len(response.Committees)) != request.Count {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, update := range response.Updates {
|
||||||
|
if update.AttestedHeader.Header.SyncPeriod() != request.FirstPeriod+uint64(i) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateResponse is a response that has passed initial verification and has been
|
||||||
|
// queued for processing. Note that an update response cannot be processed until
|
||||||
|
// the previous updates have also been added to the chain.
|
||||||
|
type updateResponse struct {
|
||||||
|
sid request.ServerAndID
|
||||||
|
request ReqUpdates
|
||||||
|
response RespUpdates
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateResponseList implements sort.Sort and sorts update request/response events by FirstPeriod.
|
||||||
|
type updateResponseList []updateResponse
|
||||||
|
|
||||||
|
func (u updateResponseList) Len() int { return len(u) }
|
||||||
|
func (u updateResponseList) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
|
||||||
|
func (u updateResponseList) Less(i, j int) bool {
|
||||||
|
return u[i].request.FirstPeriod < u[j].request.FirstPeriod
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process implements request.Module.
|
||||||
|
func (s *ForwardUpdateSync) Process(requester request.Requester, events []request.Event) {
|
||||||
|
for _, event := range events {
|
||||||
|
switch event.Type {
|
||||||
|
case request.EvResponse, request.EvFail, request.EvTimeout:
|
||||||
|
sid, rq, rs := event.RequestInfo()
|
||||||
|
req := rq.(ReqUpdates)
|
||||||
|
var queued bool
|
||||||
|
if event.Type == request.EvResponse {
|
||||||
|
resp := rs.(RespUpdates)
|
||||||
|
if s.verifyRange(req, resp) {
|
||||||
|
// there is a response with a valid format; put it in the process queue
|
||||||
|
s.processQueue = append(s.processQueue, updateResponse{sid: sid, request: req, response: resp})
|
||||||
|
s.lockRange(sid, req)
|
||||||
|
queued = true
|
||||||
|
} else {
|
||||||
|
requester.Fail(event.Server, "invalid update range")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !queued {
|
||||||
|
s.unlockRange(sid, req)
|
||||||
|
}
|
||||||
|
case EvNewOptimisticUpdate:
|
||||||
|
update := event.Data.(types.OptimisticUpdate)
|
||||||
|
s.nextSyncPeriod[event.Server] = types.SyncPeriod(update.SignatureSlot + 256)
|
||||||
|
case request.EvUnregistered:
|
||||||
|
delete(s.nextSyncPeriod, event.Server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try processing ordered list of available responses
|
||||||
|
sort.Sort(updateResponseList(s.processQueue))
|
||||||
|
for s.processQueue != nil {
|
||||||
|
u := s.processQueue[0]
|
||||||
|
if !s.processResponse(requester, u) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s.unlockRange(u.sid, u.request)
|
||||||
|
s.processQueue = s.processQueue[1:]
|
||||||
|
if len(s.processQueue) == 0 {
|
||||||
|
s.processQueue = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start new requests if possible
|
||||||
|
startPeriod, chainInit := s.chain.NextSyncPeriod()
|
||||||
|
if !chainInit {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
firstPeriod, maxCount := s.rangeLock.firstUnlocked(startPeriod, maxUpdateRequest)
|
||||||
|
var (
|
||||||
|
sendTo request.Server
|
||||||
|
bestCount uint64
|
||||||
|
)
|
||||||
|
for _, server := range requester.CanSendTo() {
|
||||||
|
nextPeriod := s.nextSyncPeriod[server]
|
||||||
|
if nextPeriod <= firstPeriod {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
count := maxCount
|
||||||
|
if nextPeriod < firstPeriod+maxCount {
|
||||||
|
count = nextPeriod - firstPeriod
|
||||||
|
}
|
||||||
|
if count > bestCount {
|
||||||
|
sendTo, bestCount = server, count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sendTo == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req := ReqUpdates{FirstPeriod: firstPeriod, Count: bestCount}
|
||||||
|
id := requester.Send(sendTo, req)
|
||||||
|
s.lockRange(request.ServerAndID{Server: sendTo, ID: id}, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processResponse adds the fetched updates and committees to the committee chain.
|
||||||
|
// Returns true in case of full or partial success.
|
||||||
|
func (s *ForwardUpdateSync) processResponse(requester request.Requester, u updateResponse) (success bool) {
|
||||||
|
for i, update := range u.response.Updates {
|
||||||
|
if err := s.chain.InsertUpdate(update, u.response.Committees[i]); err != nil {
|
||||||
|
if err == light.ErrInvalidPeriod {
|
||||||
|
// there is a gap in the update periods; stop processing without
|
||||||
|
// failing and try again next time
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == light.ErrInvalidUpdate || err == light.ErrWrongCommitteeRoot || err == light.ErrCannotReorg {
|
||||||
|
requester.Fail(u.sid.Server, "invalid update received")
|
||||||
|
} else {
|
||||||
|
log.Error("Unexpected InsertUpdate error", "error", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
success = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
219
beacon/light/sync/update_sync_test.go
Normal file
219
beacon/light/sync/update_sync_test.go
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light/request"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCheckpointInit(t *testing.T) {
|
||||||
|
chain := &TestCommitteeChain{}
|
||||||
|
checkpoint := &types.BootstrapData{Header: types.Header{Slot: 0x2000*4 + 0x1000}} // period 4
|
||||||
|
checkpointHash := checkpoint.Header.Hash()
|
||||||
|
chkInit := NewCheckpointInit(chain, checkpointHash)
|
||||||
|
ts := NewTestScheduler(t, chkInit)
|
||||||
|
// add 2 servers
|
||||||
|
ts.AddServer(testServer1, 1)
|
||||||
|
ts.AddServer(testServer2, 1)
|
||||||
|
|
||||||
|
// expect bootstrap request to server 1
|
||||||
|
ts.Run(1, testServer1, ReqCheckpointData(checkpointHash))
|
||||||
|
|
||||||
|
// server 1 times out; expect request to server 2
|
||||||
|
ts.RequestEvent(request.EvTimeout, ts.Request(1, 1), nil)
|
||||||
|
ts.Run(2, testServer2, ReqCheckpointData(checkpointHash))
|
||||||
|
|
||||||
|
// invalid response from server 2; expect init state to still be false
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(2, 1), &types.BootstrapData{Header: types.Header{Slot: 123456}})
|
||||||
|
ts.ExpFail(testServer2)
|
||||||
|
ts.Run(3)
|
||||||
|
chain.ExpInit(t, false)
|
||||||
|
|
||||||
|
// server 1 fails (hard timeout)
|
||||||
|
ts.RequestEvent(request.EvFail, ts.Request(1, 1), nil)
|
||||||
|
ts.Run(4)
|
||||||
|
chain.ExpInit(t, false)
|
||||||
|
|
||||||
|
// server 3 is registered; expect bootstrap request to server 3
|
||||||
|
ts.AddServer(testServer3, 1)
|
||||||
|
ts.Run(5, testServer3, ReqCheckpointData(checkpointHash))
|
||||||
|
|
||||||
|
// valid response from server 3; expect chain to be initialized
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(5, 1), checkpoint)
|
||||||
|
ts.Run(6)
|
||||||
|
chain.ExpInit(t, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateSyncParallel(t *testing.T) {
|
||||||
|
chain := &TestCommitteeChain{}
|
||||||
|
chain.SetNextSyncPeriod(0)
|
||||||
|
updateSync := NewForwardUpdateSync(chain)
|
||||||
|
ts := NewTestScheduler(t, updateSync)
|
||||||
|
// add 2 servers, head at period 100; allow 3-3 parallel requests for each
|
||||||
|
ts.AddServer(testServer1, 3)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer1, types.OptimisticUpdate{SignatureSlot: 0x2000*100 + 0x1000})
|
||||||
|
ts.AddServer(testServer2, 3)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer2, types.OptimisticUpdate{SignatureSlot: 0x2000*100 + 0x1000})
|
||||||
|
|
||||||
|
// expect 6 requests to be sent
|
||||||
|
ts.Run(1,
|
||||||
|
testServer1, ReqUpdates{FirstPeriod: 0, Count: 8},
|
||||||
|
testServer1, ReqUpdates{FirstPeriod: 8, Count: 8},
|
||||||
|
testServer1, ReqUpdates{FirstPeriod: 16, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 24, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 32, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 40, Count: 8})
|
||||||
|
|
||||||
|
// valid response to request 1; expect 8 periods synced and a new request started
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 1), testRespUpdate(ts.Request(1, 1)))
|
||||||
|
ts.AddAllowance(testServer1, 1)
|
||||||
|
ts.Run(2, testServer1, ReqUpdates{FirstPeriod: 48, Count: 8})
|
||||||
|
chain.ExpNextSyncPeriod(t, 8)
|
||||||
|
|
||||||
|
// valid response to requests 4 and 5
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 4), testRespUpdate(ts.Request(1, 4)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 5), testRespUpdate(ts.Request(1, 5)))
|
||||||
|
ts.AddAllowance(testServer2, 2)
|
||||||
|
// expect 2 more requests but no sync progress (responses 4 and 5 cannot be added before 2 and 3)
|
||||||
|
ts.Run(3,
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 56, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 64, Count: 8})
|
||||||
|
chain.ExpNextSyncPeriod(t, 8)
|
||||||
|
|
||||||
|
// soft timeout for requests 2 and 3 (server 1 is overloaded)
|
||||||
|
ts.RequestEvent(request.EvTimeout, ts.Request(1, 2), nil)
|
||||||
|
ts.RequestEvent(request.EvTimeout, ts.Request(1, 3), nil)
|
||||||
|
// no allowance, no more requests
|
||||||
|
ts.Run(4)
|
||||||
|
|
||||||
|
// valid response to requests 6 and 8 and 9
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 6), testRespUpdate(ts.Request(1, 6)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(3, 1), testRespUpdate(ts.Request(3, 1)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(3, 2), testRespUpdate(ts.Request(3, 2)))
|
||||||
|
ts.AddAllowance(testServer2, 3)
|
||||||
|
// server 2 can now resend requests 2 and 3 (timed out by server 1) and also send a new one
|
||||||
|
ts.Run(5,
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 8, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 16, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 72, Count: 8})
|
||||||
|
|
||||||
|
// server 1 finally answers timed out request 2
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 2), testRespUpdate(ts.Request(1, 2)))
|
||||||
|
ts.AddAllowance(testServer1, 1)
|
||||||
|
// expect sync progress and one new request
|
||||||
|
ts.Run(6, testServer1, ReqUpdates{FirstPeriod: 80, Count: 8})
|
||||||
|
chain.ExpNextSyncPeriod(t, 16)
|
||||||
|
|
||||||
|
// server 2 answers requests 11 and 12 (resends of requests 2 and 3)
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(5, 1), testRespUpdate(ts.Request(5, 1)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(5, 2), testRespUpdate(ts.Request(5, 2)))
|
||||||
|
ts.AddAllowance(testServer2, 2)
|
||||||
|
ts.Run(7,
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 88, Count: 8},
|
||||||
|
testServer2, ReqUpdates{FirstPeriod: 96, Count: 4})
|
||||||
|
// finally the gap is filled, update can process responses up to req6
|
||||||
|
chain.ExpNextSyncPeriod(t, 48)
|
||||||
|
|
||||||
|
// all remaining requests are answered
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 3), testRespUpdate(ts.Request(1, 3)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testRespUpdate(ts.Request(2, 1)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(5, 3), testRespUpdate(ts.Request(5, 3)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(6, 1), testRespUpdate(ts.Request(6, 1)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testRespUpdate(ts.Request(7, 1)))
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(7, 2), testRespUpdate(ts.Request(7, 2)))
|
||||||
|
ts.Run(8)
|
||||||
|
// expect chain to be fully synced
|
||||||
|
chain.ExpNextSyncPeriod(t, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateSyncDifferentHeads(t *testing.T) {
|
||||||
|
chain := &TestCommitteeChain{}
|
||||||
|
chain.SetNextSyncPeriod(10)
|
||||||
|
updateSync := NewForwardUpdateSync(chain)
|
||||||
|
ts := NewTestScheduler(t, updateSync)
|
||||||
|
// add 3 servers with different announced head periods
|
||||||
|
ts.AddServer(testServer1, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer1, types.OptimisticUpdate{SignatureSlot: 0x2000*15 + 0x1000})
|
||||||
|
ts.AddServer(testServer2, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer2, types.OptimisticUpdate{SignatureSlot: 0x2000*16 + 0x1000})
|
||||||
|
ts.AddServer(testServer3, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer3, types.OptimisticUpdate{SignatureSlot: 0x2000*17 + 0x1000})
|
||||||
|
|
||||||
|
// expect request to the best announced head
|
||||||
|
ts.Run(1, testServer3, ReqUpdates{FirstPeriod: 10, Count: 7})
|
||||||
|
|
||||||
|
// request times out, expect request to the next best head
|
||||||
|
ts.RequestEvent(request.EvTimeout, ts.Request(1, 1), nil)
|
||||||
|
ts.Run(2, testServer2, ReqUpdates{FirstPeriod: 10, Count: 6})
|
||||||
|
|
||||||
|
// request times out, expect request to the last available server
|
||||||
|
ts.RequestEvent(request.EvTimeout, ts.Request(2, 1), nil)
|
||||||
|
ts.Run(3, testServer1, ReqUpdates{FirstPeriod: 10, Count: 5})
|
||||||
|
|
||||||
|
// valid response to request 3, expect chain synced to period 15
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(3, 1), testRespUpdate(ts.Request(3, 1)))
|
||||||
|
ts.AddAllowance(testServer1, 1)
|
||||||
|
ts.Run(4)
|
||||||
|
chain.ExpNextSyncPeriod(t, 15)
|
||||||
|
|
||||||
|
// invalid response to request 1, server can only deliver updates up to period 15 despite announced head
|
||||||
|
truncated := ts.Request(1, 1)
|
||||||
|
truncated.request = ReqUpdates{FirstPeriod: 10, Count: 5}
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(1, 1), testRespUpdate(truncated))
|
||||||
|
ts.ExpFail(testServer3)
|
||||||
|
ts.Run(5)
|
||||||
|
// expect no progress of chain head
|
||||||
|
chain.ExpNextSyncPeriod(t, 15)
|
||||||
|
|
||||||
|
// valid response to request 2, expect chain synced to period 16
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testRespUpdate(ts.Request(2, 1)))
|
||||||
|
ts.AddAllowance(testServer2, 1)
|
||||||
|
ts.Run(6)
|
||||||
|
chain.ExpNextSyncPeriod(t, 16)
|
||||||
|
|
||||||
|
// a new server is registered with announced head period 17
|
||||||
|
ts.AddServer(testServer4, 1)
|
||||||
|
ts.ServerEvent(EvNewOptimisticUpdate, testServer4, types.OptimisticUpdate{SignatureSlot: 0x2000*17 + 0x1000})
|
||||||
|
// expect request to sync one more period
|
||||||
|
ts.Run(7, testServer4, ReqUpdates{FirstPeriod: 16, Count: 1})
|
||||||
|
|
||||||
|
// valid response, expect chain synced to period 17
|
||||||
|
ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testRespUpdate(ts.Request(7, 1)))
|
||||||
|
ts.AddAllowance(testServer4, 1)
|
||||||
|
ts.Run(8)
|
||||||
|
chain.ExpNextSyncPeriod(t, 17)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRespUpdate(request requestWithID) request.Response {
|
||||||
|
var resp RespUpdates
|
||||||
|
if request.request == nil {
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
req := request.request.(ReqUpdates)
|
||||||
|
resp.Updates = make([]*types.LightClientUpdate, int(req.Count))
|
||||||
|
resp.Committees = make([]*types.SerializedSyncCommittee, int(req.Count))
|
||||||
|
period := req.FirstPeriod
|
||||||
|
for i := range resp.Updates {
|
||||||
|
resp.Updates[i] = &types.LightClientUpdate{AttestedHeader: types.SignedHeader{Header: types.Header{Slot: 0x2000*period + 0x1000}}}
|
||||||
|
resp.Committees[i] = new(types.SerializedSyncCommittee)
|
||||||
|
period++
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
@ -41,4 +41,6 @@ const (
|
||||||
StateIndexNextSyncCommittee = 55
|
StateIndexNextSyncCommittee = 55
|
||||||
StateIndexExecPayload = 56
|
StateIndexExecPayload = 56
|
||||||
StateIndexExecHead = 908
|
StateIndexExecHead = 908
|
||||||
|
|
||||||
|
BodyIndexExecPayload = 25
|
||||||
)
|
)
|
||||||
|
|
|
||||||
110
beacon/types/beacon_block.go
Normal file
110
beacon/types/beacon_block.go
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||||
|
"github.com/protolambda/zrnt/eth2/configs"
|
||||||
|
"github.com/protolambda/ztyp/tree"
|
||||||
|
)
|
||||||
|
|
||||||
|
type blockObject interface {
|
||||||
|
HashTreeRoot(spec *zrntcommon.Spec, hFn tree.HashFn) zrntcommon.Root
|
||||||
|
Header(spec *zrntcommon.Spec) *zrntcommon.BeaconBlockHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeaconBlock represents a full block in the beacon chain.
|
||||||
|
type BeaconBlock struct {
|
||||||
|
blockObj blockObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockFromJSON decodes a beacon block from JSON.
|
||||||
|
func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
|
||||||
|
var obj blockObject
|
||||||
|
switch forkName {
|
||||||
|
case "deneb":
|
||||||
|
obj = new(deneb.BeaconBlock)
|
||||||
|
case "capella":
|
||||||
|
obj = new(capella.BeaconBlock)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, obj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BeaconBlock{obj}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBeaconBlock wraps a ZRNT block.
|
||||||
|
func NewBeaconBlock(obj blockObject) *BeaconBlock {
|
||||||
|
switch obj := obj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return &BeaconBlock{obj}
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return &BeaconBlock{obj}
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slot returns the slot number of the block.
|
||||||
|
func (b *BeaconBlock) Slot() uint64 {
|
||||||
|
switch obj := b.blockObj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return uint64(obj.Slot)
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return uint64(obj.Slot)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecutionPayload parses and returns the execution payload of the block.
|
||||||
|
func (b *BeaconBlock) ExecutionPayload() (*types.Block, error) {
|
||||||
|
switch obj := b.blockObj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot)
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header returns the block's header data.
|
||||||
|
func (b *BeaconBlock) Header() Header {
|
||||||
|
switch obj := b.blockObj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return headerFromZRNT(obj.Header(configs.Mainnet))
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return headerFromZRNT(obj.Header(configs.Mainnet))
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root computes the SSZ root hash of the block.
|
||||||
|
func (b *BeaconBlock) Root() common.Hash {
|
||||||
|
return common.Hash(b.blockObj.HashTreeRoot(configs.Mainnet, tree.GetHashFn()))
|
||||||
|
}
|
||||||
77
beacon/types/beacon_block_test.go
Normal file
77
beacon/types/beacon_block_test.go
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBlockFromJSON(t *testing.T) {
|
||||||
|
type blocktest struct {
|
||||||
|
file string
|
||||||
|
version string
|
||||||
|
wantSlot uint64
|
||||||
|
wantBlockNumber uint64
|
||||||
|
wantBlockHash common.Hash
|
||||||
|
}
|
||||||
|
tests := []blocktest{
|
||||||
|
{
|
||||||
|
file: "block_deneb.json",
|
||||||
|
version: "deneb",
|
||||||
|
wantSlot: 8631513,
|
||||||
|
wantBlockNumber: 19431837,
|
||||||
|
wantBlockHash: common.HexToHash("0x4cf7d9108fc01b50023ab7cab9b372a96068fddcadec551630393b65acb1f34c"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: "block_capella.json",
|
||||||
|
version: "capella",
|
||||||
|
wantSlot: 7378495,
|
||||||
|
wantBlockNumber: 18189758,
|
||||||
|
wantBlockHash: common.HexToHash("0x802acf5c350f4252e31d83c431fcb259470250fa0edf49e8391cfee014239820"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.file, func(t *testing.T) {
|
||||||
|
data, err := os.ReadFile(filepath.Join("testdata", test.file))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
beaconBlock, err := BlockFromJSON(test.version, data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if beaconBlock.Slot() != test.wantSlot {
|
||||||
|
t.Errorf("wrong slot number %d", beaconBlock.Slot())
|
||||||
|
}
|
||||||
|
execBlock, err := beaconBlock.ExecutionPayload()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("payload extraction failed: %v", err)
|
||||||
|
}
|
||||||
|
if execBlock.NumberU64() != test.wantBlockNumber {
|
||||||
|
t.Errorf("wrong block number: %v", execBlock.NumberU64())
|
||||||
|
}
|
||||||
|
if execBlock.Hash() != test.wantBlockHash {
|
||||||
|
t.Errorf("wrong block hash: %v", execBlock.Hash())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,9 @@ package types
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -27,17 +29,20 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"gopkg.in/yaml.v3"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// syncCommitteeDomain specifies the signatures specific use to avoid clashes
|
// syncCommitteeDomain specifies the signatures specific use to avoid clashes
|
||||||
// across signing different data structures.
|
// across signing different data structures.
|
||||||
const syncCommitteeDomain = 7
|
const syncCommitteeDomain = 7
|
||||||
|
|
||||||
|
var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"}
|
||||||
|
|
||||||
// Fork describes a single beacon chain fork and also stores the calculated
|
// Fork describes a single beacon chain fork and also stores the calculated
|
||||||
// signature domain used after this fork.
|
// signature domain used after this fork.
|
||||||
type Fork struct {
|
type Fork struct {
|
||||||
// Name of the fork in the chain config (config.yaml) file{
|
// Name of the fork in the chain config (config.yaml) file
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Epoch when given fork version is activated
|
// Epoch when given fork version is activated
|
||||||
|
|
@ -46,6 +51,9 @@ type Fork struct {
|
||||||
// Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
|
// Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
|
||||||
Version []byte
|
Version []byte
|
||||||
|
|
||||||
|
// index in list of known forks or MaxInt if unknown
|
||||||
|
knownIndex int
|
||||||
|
|
||||||
// calculated by computeDomain, based on fork version and genesis validators root
|
// calculated by computeDomain, based on fork version and genesis validators root
|
||||||
domain merkle.Value
|
domain merkle.Value
|
||||||
}
|
}
|
||||||
|
|
@ -99,9 +107,14 @@ func (f Forks) SigningRoot(header Header) (common.Hash, error) {
|
||||||
return signingRoot, nil
|
return signingRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f Forks) Len() int { return len(f) }
|
func (f Forks) Len() int { return len(f) }
|
||||||
func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
||||||
func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch }
|
func (f Forks) Less(i, j int) bool {
|
||||||
|
if f[i].Epoch != f[j].Epoch {
|
||||||
|
return f[i].Epoch < f[j].Epoch
|
||||||
|
}
|
||||||
|
return f[i].knownIndex < f[j].knownIndex
|
||||||
|
}
|
||||||
|
|
||||||
// ChainConfig contains the beacon chain configuration.
|
// ChainConfig contains the beacon chain configuration.
|
||||||
type ChainConfig struct {
|
type ChainConfig struct {
|
||||||
|
|
@ -110,18 +123,34 @@ type ChainConfig struct {
|
||||||
Forks Forks
|
Forks Forks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForkAtEpoch returns the latest active fork at the given epoch.
|
||||||
|
func (c *ChainConfig) ForkAtEpoch(epoch uint64) Fork {
|
||||||
|
for i := len(c.Forks) - 1; i >= 0; i-- {
|
||||||
|
if c.Forks[i].Epoch <= epoch {
|
||||||
|
return *c.Forks[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Fork{}
|
||||||
|
}
|
||||||
|
|
||||||
// AddFork adds a new item to the list of forks.
|
// AddFork adds a new item to the list of forks.
|
||||||
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
|
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
|
||||||
|
knownIndex := slices.Index(knownForks, name)
|
||||||
|
if knownIndex == -1 {
|
||||||
|
knownIndex = math.MaxInt // assume that the unknown fork happens after the known ones
|
||||||
|
if epoch != math.MaxUint64 {
|
||||||
|
log.Warn("Unknown fork in config.yaml", "fork name", name, "known forks", knownForks)
|
||||||
|
}
|
||||||
|
}
|
||||||
fork := &Fork{
|
fork := &Fork{
|
||||||
Name: name,
|
Name: name,
|
||||||
Epoch: epoch,
|
Epoch: epoch,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
knownIndex: knownIndex,
|
||||||
}
|
}
|
||||||
fork.computeDomain(c.GenesisValidatorsRoot)
|
fork.computeDomain(c.GenesisValidatorsRoot)
|
||||||
|
|
||||||
c.Forks = append(c.Forks, fork)
|
c.Forks = append(c.Forks, fork)
|
||||||
sort.Sort(c.Forks)
|
sort.Sort(c.Forks)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,6 +200,5 @@ func (c *ChainConfig) LoadForks(path string) error {
|
||||||
for name := range versions {
|
for name := range versions {
|
||||||
return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name)
|
return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name)
|
||||||
}
|
}
|
||||||
sort.Sort(c.Forks)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
80
beacon/types/exec_header.go
Normal file
80
beacon/types/exec_header.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||||
|
"github.com/protolambda/ztyp/tree"
|
||||||
|
)
|
||||||
|
|
||||||
|
type headerObject interface {
|
||||||
|
HashTreeRoot(hFn tree.HashFn) zrntcommon.Root
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionHeader struct {
|
||||||
|
obj headerObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecutionHeaderFromJSON decodes an execution header from JSON data provided by
|
||||||
|
// the beacon chain API.
|
||||||
|
func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, error) {
|
||||||
|
var obj headerObject
|
||||||
|
switch forkName {
|
||||||
|
case "capella":
|
||||||
|
obj = new(capella.ExecutionPayloadHeader)
|
||||||
|
case "deneb":
|
||||||
|
obj = new(deneb.ExecutionPayloadHeader)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, obj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ExecutionHeader{obj: obj}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExecutionHeader(obj headerObject) *ExecutionHeader {
|
||||||
|
switch obj.(type) {
|
||||||
|
case *capella.ExecutionPayloadHeader:
|
||||||
|
case *deneb.ExecutionPayloadHeader:
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported ExecutionPayloadHeader type %T", obj))
|
||||||
|
}
|
||||||
|
return &ExecutionHeader{obj: obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eh *ExecutionHeader) PayloadRoot() merkle.Value {
|
||||||
|
return merkle.Value(eh.obj.HashTreeRoot(tree.GetHashFn()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eh *ExecutionHeader) BlockHash() common.Hash {
|
||||||
|
switch obj := eh.obj.(type) {
|
||||||
|
case *capella.ExecutionPayloadHeader:
|
||||||
|
return common.Hash(obj.BlockHash)
|
||||||
|
case *deneb.ExecutionPayloadHeader:
|
||||||
|
return common.Hash(obj.BlockHash)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported ExecutionPayloadHeader type %T", obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
141
beacon/types/exec_payload.go
Normal file
141
beacon/types/exec_payload.go
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type payloadType interface {
|
||||||
|
*capella.ExecutionPayload | *deneb.ExecutionPayload
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertPayload converts a beacon chain execution payload to types.Block.
|
||||||
|
func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*types.Block, error) {
|
||||||
|
var (
|
||||||
|
header types.Header
|
||||||
|
transactions []*types.Transaction
|
||||||
|
withdrawals []*types.Withdrawal
|
||||||
|
expectedHash [32]byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
switch p := any(payload).(type) {
|
||||||
|
case *capella.ExecutionPayload:
|
||||||
|
convertCapellaHeader(p, &header)
|
||||||
|
transactions, err = convertTransactions(p.Transactions, &header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
withdrawals = convertWithdrawals(p.Withdrawals, &header)
|
||||||
|
expectedHash = p.BlockHash
|
||||||
|
case *deneb.ExecutionPayload:
|
||||||
|
convertDenebHeader(p, common.Hash(*parentRoot), &header)
|
||||||
|
transactions, err = convertTransactions(p.Transactions, &header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
withdrawals = convertWithdrawals(p.Withdrawals, &header)
|
||||||
|
expectedHash = p.BlockHash
|
||||||
|
default:
|
||||||
|
panic("unsupported block type")
|
||||||
|
}
|
||||||
|
|
||||||
|
block := types.NewBlockWithHeader(&header).WithBody(types.Body{Transactions: transactions, Withdrawals: withdrawals})
|
||||||
|
if hash := block.Hash(); hash != expectedHash {
|
||||||
|
return nil, fmt.Errorf("sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash)
|
||||||
|
}
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCapellaHeader(payload *capella.ExecutionPayload, h *types.Header) {
|
||||||
|
// note: h.TxHash is set in convertTransactions
|
||||||
|
h.ParentHash = common.Hash(payload.ParentHash)
|
||||||
|
h.UncleHash = types.EmptyUncleHash
|
||||||
|
h.Coinbase = common.Address(payload.FeeRecipient)
|
||||||
|
h.Root = common.Hash(payload.StateRoot)
|
||||||
|
h.ReceiptHash = common.Hash(payload.ReceiptsRoot)
|
||||||
|
h.Bloom = types.Bloom(payload.LogsBloom)
|
||||||
|
h.Difficulty = common.Big0
|
||||||
|
h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber))
|
||||||
|
h.GasLimit = uint64(payload.GasLimit)
|
||||||
|
h.GasUsed = uint64(payload.GasUsed)
|
||||||
|
h.Time = uint64(payload.Timestamp)
|
||||||
|
h.Extra = []byte(payload.ExtraData)
|
||||||
|
h.MixDigest = common.Hash(payload.PrevRandao)
|
||||||
|
h.Nonce = types.BlockNonce{}
|
||||||
|
h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDenebHeader(payload *deneb.ExecutionPayload, parentRoot common.Hash, h *types.Header) {
|
||||||
|
// note: h.TxHash is set in convertTransactions
|
||||||
|
h.ParentHash = common.Hash(payload.ParentHash)
|
||||||
|
h.UncleHash = types.EmptyUncleHash
|
||||||
|
h.Coinbase = common.Address(payload.FeeRecipient)
|
||||||
|
h.Root = common.Hash(payload.StateRoot)
|
||||||
|
h.ReceiptHash = common.Hash(payload.ReceiptsRoot)
|
||||||
|
h.Bloom = types.Bloom(payload.LogsBloom)
|
||||||
|
h.Difficulty = common.Big0
|
||||||
|
h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber))
|
||||||
|
h.GasLimit = uint64(payload.GasLimit)
|
||||||
|
h.GasUsed = uint64(payload.GasUsed)
|
||||||
|
h.Time = uint64(payload.Timestamp)
|
||||||
|
h.Extra = []byte(payload.ExtraData)
|
||||||
|
h.MixDigest = common.Hash(payload.PrevRandao)
|
||||||
|
h.Nonce = types.BlockNonce{}
|
||||||
|
h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig()
|
||||||
|
// new in deneb
|
||||||
|
h.BlobGasUsed = (*uint64)(&payload.BlobGasUsed)
|
||||||
|
h.ExcessBlobGas = (*uint64)(&payload.ExcessBlobGas)
|
||||||
|
h.ParentBeaconRoot = &parentRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTransactions(list zrntcommon.PayloadTransactions, execHeader *types.Header) ([]*types.Transaction, error) {
|
||||||
|
txs := make([]*types.Transaction, len(list))
|
||||||
|
for i, opaqueTx := range list {
|
||||||
|
var tx types.Transaction
|
||||||
|
if err := tx.UnmarshalBinary(opaqueTx); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse tx %d: %v", i, err)
|
||||||
|
}
|
||||||
|
txs[i] = &tx
|
||||||
|
}
|
||||||
|
execHeader.TxHash = types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil))
|
||||||
|
return txs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertWithdrawals(list zrntcommon.Withdrawals, execHeader *types.Header) []*types.Withdrawal {
|
||||||
|
withdrawals := make([]*types.Withdrawal, len(list))
|
||||||
|
for i, w := range list {
|
||||||
|
withdrawals[i] = &types.Withdrawal{
|
||||||
|
Index: uint64(w.Index),
|
||||||
|
Validator: uint64(w.ValidatorIndex),
|
||||||
|
Address: common.Address(w.Address),
|
||||||
|
Amount: uint64(w.Amount),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wroot := types.DeriveSha(types.Withdrawals(withdrawals), trie.NewStackTrie(nil))
|
||||||
|
execHeader.WithdrawalsHash = &wroot
|
||||||
|
return withdrawals
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||||
"github.com/ethereum/go-ethereum/beacon/params"
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
||||||
|
|
@ -57,6 +58,16 @@ type Header struct {
|
||||||
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
|
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func headerFromZRNT(zh *zrntcommon.BeaconBlockHeader) Header {
|
||||||
|
return Header{
|
||||||
|
Slot: uint64(zh.Slot),
|
||||||
|
ProposerIndex: uint64(zh.ProposerIndex),
|
||||||
|
ParentRoot: common.Hash(zh.ParentRoot),
|
||||||
|
StateRoot: common.Hash(zh.StateRoot),
|
||||||
|
BodyRoot: common.Hash(zh.BodyRoot),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// headerMarshaling is a field type overrides for gencodec.
|
// headerMarshaling is a field type overrides for gencodec.
|
||||||
type headerMarshaling struct {
|
type headerMarshaling struct {
|
||||||
Slot common.Decimal
|
Slot common.Decimal
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,15 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||||
"github.com/ethereum/go-ethereum/beacon/params"
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
ctypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HeadInfo represents an unvalidated new head announcement.
|
||||||
|
type HeadInfo struct {
|
||||||
|
Slot uint64
|
||||||
|
BlockRoot common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
// BootstrapData contains a sync committee where light sync can be started,
|
// BootstrapData contains a sync committee where light sync can be started,
|
||||||
// together with a proof through a beacon header and corresponding state.
|
// together with a proof through a beacon header and corresponding state.
|
||||||
// Note: BootstrapData is fetched from a server based on a known checkpoint hash.
|
// Note: BootstrapData is fetched from a server based on a known checkpoint hash.
|
||||||
|
|
@ -134,3 +141,96 @@ func (u UpdateScore) BetterThan(w UpdateScore) bool {
|
||||||
}
|
}
|
||||||
return u.SignerCount > w.SignerCount
|
return u.SignerCount > w.SignerCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HeaderWithExecProof contains a beacon header and proves the belonging execution
|
||||||
|
// payload header with a Merkle proof.
|
||||||
|
type HeaderWithExecProof struct {
|
||||||
|
Header
|
||||||
|
PayloadHeader *ExecutionHeader
|
||||||
|
PayloadBranch merkle.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate verifies the Merkle proof of the execution payload header.
|
||||||
|
func (h *HeaderWithExecProof) Validate() error {
|
||||||
|
return merkle.VerifyProof(h.BodyRoot, params.BodyIndexExecPayload, h.PayloadBranch, h.PayloadHeader.PayloadRoot())
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptimisticUpdate proves sync committee commitment on the attested beacon header.
|
||||||
|
// It also proves the belonging execution payload header with a Merkle proof.
|
||||||
|
//
|
||||||
|
// See data structure definition here:
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
||||||
|
type OptimisticUpdate struct {
|
||||||
|
Attested HeaderWithExecProof
|
||||||
|
// Sync committee BLS signature aggregate
|
||||||
|
Signature SyncAggregate
|
||||||
|
// Slot in which the signature has been created (newer than Header.Slot,
|
||||||
|
// determines the signing sync committee)
|
||||||
|
SignatureSlot uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedHeader returns the signed attested header of the update.
|
||||||
|
func (u *OptimisticUpdate) SignedHeader() SignedHeader {
|
||||||
|
return SignedHeader{
|
||||||
|
Header: u.Attested.Header,
|
||||||
|
Signature: u.Signature,
|
||||||
|
SignatureSlot: u.SignatureSlot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate verifies the Merkle proof proving the execution payload header.
|
||||||
|
// Note that the sync committee signature of the attested header should be
|
||||||
|
// verified separately by a synced committee chain.
|
||||||
|
func (u *OptimisticUpdate) Validate() error {
|
||||||
|
return u.Attested.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinalityUpdate proves a finalized beacon header by a sync committee commitment
|
||||||
|
// on an attested beacon header, referring to the latest finalized header with a
|
||||||
|
// Merkle proof.
|
||||||
|
// It also proves the execution payload header belonging to both the attested and
|
||||||
|
// the finalized beacon header with Merkle proofs.
|
||||||
|
//
|
||||||
|
// See data structure definition here:
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
||||||
|
type FinalityUpdate struct {
|
||||||
|
Attested, Finalized HeaderWithExecProof
|
||||||
|
FinalityBranch merkle.Values
|
||||||
|
// Sync committee BLS signature aggregate
|
||||||
|
Signature SyncAggregate
|
||||||
|
// Slot in which the signature has been created (newer than Header.Slot,
|
||||||
|
// determines the signing sync committee)
|
||||||
|
SignatureSlot uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedHeader returns the signed attested header of the update.
|
||||||
|
func (u *FinalityUpdate) SignedHeader() SignedHeader {
|
||||||
|
return SignedHeader{
|
||||||
|
Header: u.Attested.Header,
|
||||||
|
Signature: u.Signature,
|
||||||
|
SignatureSlot: u.SignatureSlot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate verifies the Merkle proofs proving the finalized beacon header and
|
||||||
|
// the execution payload headers belonging to the attested and finalized headers.
|
||||||
|
// Note that the sync committee signature of the attested header should be
|
||||||
|
// verified separately by a synced committee chain.
|
||||||
|
func (u *FinalityUpdate) Validate() error {
|
||||||
|
if err := u.Attested.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.Finalized.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock, u.FinalityBranch, merkle.Value(u.Finalized.Hash()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainHeadEvent returns an authenticated execution payload associated with the
|
||||||
|
// latest accepted head of the beacon chain, along with the hash of the latest
|
||||||
|
// finalized execution block.
|
||||||
|
type ChainHeadEvent struct {
|
||||||
|
BeaconHead Header
|
||||||
|
Block *ctypes.Block
|
||||||
|
Finalized common.Hash
|
||||||
|
}
|
||||||
|
|
|
||||||
1703
beacon/types/testdata/block_capella.json
vendored
Normal file
1703
beacon/types/testdata/block_capella.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
2644
beacon/types/testdata/block_deneb.json
vendored
Normal file
2644
beacon/types/testdata/block_deneb.json
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,64 +1,126 @@
|
||||||
# This file contains sha256 checksums of optional build dependencies.
|
# This file contains sha256 checksums of optional build dependencies.
|
||||||
|
|
||||||
# version:spec-tests 1.0.6
|
# version:spec-tests 2.1.0
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases
|
# https://github.com/ethereum/execution-spec-tests/releases
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/v1.0.6/
|
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||||
485af7b66cf41eb3a8c1bd46632913b8eb95995df867cf665617bbc9b4beedd1 fixtures_develop.tar.gz
|
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||||
|
|
||||||
# version:golang 1.22.1
|
# version:golang 1.22.4
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
79c9b91d7f109515a25fc3ecdaad125d67e6bdb54f6d4d98580f46799caea321 go1.22.1.src.tar.gz
|
fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz
|
||||||
3bc971772f4712fec0364f4bc3de06af22a00a12daab10b6f717fdcd13156cc0 go1.22.1.darwin-amd64.tar.gz
|
b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz
|
||||||
f6a9cec6b8a002fcc9c0ee24ec04d67f430a52abc3cfd613836986bcc00d8383 go1.22.1.darwin-arm64.tar.gz
|
7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg
|
||||||
99f81c10d5a3f8a886faf8fa86aaa2aaf929fbed54a972ae5eec3c5e0bdb961a go1.22.1.freebsd-386.tar.gz
|
c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz
|
||||||
51c614ddd92ee4a9913a14c39bf80508d9cfba08561f24d2f075fd00f3cfb067 go1.22.1.freebsd-amd64.tar.gz
|
4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg
|
||||||
8484df36d3d40139eaf0fe5e647b006435d826cc12f9ae72973bf7ec265e0ae4 go1.22.1.linux-386.tar.gz
|
242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz
|
||||||
aab8e15785c997ae20f9c88422ee35d962c4562212bb0f879d052a35c8307c7f go1.22.1.linux-amd64.tar.gz
|
f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz
|
||||||
e56685a245b6a0c592fc4a55f0b7803af5b3f827aaa29feab1f40e491acf35b8 go1.22.1.linux-arm64.tar.gz
|
7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz
|
||||||
8cb7a90e48c20daed39a6ac8b8a40760030ba5e93c12274c42191d868687c281 go1.22.1.linux-armv6l.tar.gz
|
88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz
|
||||||
ac775e19d93cc1668999b77cfe8c8964abfbc658718feccfe6e0eb87663cd668 go1.22.1.linux-ppc64le.tar.gz
|
3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz
|
||||||
7bb7dd8e10f95c9a4cc4f6bef44c816a6e7c9e03f56ac6af6efbb082b19b379f go1.22.1.linux-s390x.tar.gz
|
726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz
|
||||||
0c5ebb7eb39b7884ec99f92b425d4c03a96a72443562aafbf6e7d15c42a3108a go1.22.1.windows-386.zip
|
5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz
|
||||||
cf9c66a208a106402a527f5b956269ca506cfe535fc388e828d249ea88ed28ba go1.22.1.windows-amd64.zip
|
d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz
|
||||||
85b8511b298c9f4199ecae26afafcc3d46155bac934d43f2357b9224bcaa310f go1.22.1.windows-arm64.zip
|
47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz
|
||||||
|
ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz
|
||||||
|
a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz
|
||||||
|
e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz
|
||||||
|
e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz
|
||||||
|
73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz
|
||||||
|
417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz
|
||||||
|
7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz
|
||||||
|
69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz
|
||||||
|
dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz
|
||||||
|
a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz
|
||||||
|
56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz
|
||||||
|
7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz
|
||||||
|
ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz
|
||||||
|
33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz
|
||||||
|
fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz
|
||||||
|
c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz
|
||||||
|
d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz
|
||||||
|
72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz
|
||||||
|
1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz
|
||||||
|
a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz
|
||||||
|
9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz
|
||||||
|
a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz
|
||||||
|
5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz
|
||||||
|
6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz
|
||||||
|
e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz
|
||||||
|
5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi
|
||||||
|
aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip
|
||||||
|
3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi
|
||||||
|
26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip
|
||||||
|
c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi
|
||||||
|
5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip
|
||||||
|
553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi
|
||||||
|
8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip
|
||||||
|
|
||||||
# version:golangci 1.51.1
|
# version:golangci 1.59.0
|
||||||
# https://github.com/golangci/golangci-lint/releases/
|
# https://github.com/golangci/golangci-lint/releases/
|
||||||
# https://github.com/golangci/golangci-lint/releases/download/v1.51.1/
|
# https://github.com/golangci/golangci-lint/releases/download/v1.59.0/
|
||||||
fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz
|
418acf7e255ddc0783e97129c9b03d9311b77826a5311d425a01c708a86417e7 golangci-lint-1.59.0-darwin-amd64.tar.gz
|
||||||
75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz
|
5f6a1d95a6dd69f6e328eb56dd311a38e04cfab79a1305fbf4957f4e203f47b6 golangci-lint-1.59.0-darwin-arm64.tar.gz
|
||||||
e06b3459aaed356e1667580be00b05f41f3b2e29685d12cdee571c23e1edb414 golangci-lint-1.51.1-freebsd-386.tar.gz
|
8899bf589185d49f747f3e5db9f0bde8a47245a100c64a3dd4d65e8e92cfc4f2 golangci-lint-1.59.0-freebsd-386.tar.gz
|
||||||
623ce2d0fa4d35cc2e8d69fa7334227ab592380962a13b4d9cdc77cf41db2008 golangci-lint-1.51.1-freebsd-amd64.tar.gz
|
658212f138d9df2ac89427e22115af34bf387c0871d70f2a25101718946a014f golangci-lint-1.59.0-freebsd-amd64.tar.gz
|
||||||
131365feb0584cc2736c43192fa673ca50e5b6b765456990cb379ecfb787e568 golangci-lint-1.51.1-freebsd-armv6.tar.gz
|
4c6395ea40f314d3b6fa17d8997baab93464d5d1deeaab513155e625473bd03a golangci-lint-1.59.0-freebsd-armv6.tar.gz
|
||||||
98fb627927cbb654f5bf85dcffc5f646666b2ce96ea0fed977c9fb28abd51532 golangci-lint-1.51.1-freebsd-armv7.tar.gz
|
ff37da4fbaacdb6bbae70fdbdbb1ba932a859956f788c82822fa06bef5b7c6b3 golangci-lint-1.59.0-freebsd-armv7.tar.gz
|
||||||
b36a99702fa762c15840261bc0fb41b4b1b16b8b19b8c0941bae98c85bb0f8b8 golangci-lint-1.51.1-linux-386.tar.gz
|
439739469ed2bda182b1ec276d40c40e02f195537f78e3672996741ad223d6b6 golangci-lint-1.59.0-illumos-amd64.tar.gz
|
||||||
17aeb26c76820c22efa0e1838b0ab93e90cfedef43fbfc9a2f33f27eb9e5e070 golangci-lint-1.51.1-linux-amd64.tar.gz
|
940801d46790e40d0a097d8fee34e2606f0ef148cd039654029b0b8750a15ed6 golangci-lint-1.59.0-linux-386.tar.gz
|
||||||
9744bc34e7b8d82ca788b667bfb7155a39b4be9aef43bf9f10318b1372cea338 golangci-lint-1.51.1-linux-arm64.tar.gz
|
3b14a439f33c4fff83dbe0349950d984042b9a1feb6c62f82787b598fc3ab5f4 golangci-lint-1.59.0-linux-amd64.tar.gz
|
||||||
0dda8dbeb2ff7455a044ec8e347f2fc6d655d2e99d281b3b95e88167031c673d golangci-lint-1.51.1-linux-armv6.tar.gz
|
c57e6c0b0fa03089a2611dceddd5bc5d206716cccdff8b149da8baac598719a1 golangci-lint-1.59.0-linux-arm64.tar.gz
|
||||||
0512f311b11d43b8b22989d929f0fe8a2e1e5ebe497f1eb0ff73a0fc3d188fd1 golangci-lint-1.51.1-linux-armv7.tar.gz
|
93149e2d3b25ac754df9a23172403d8aa6d021a7e0d9c090a12f51897f68c9a0 golangci-lint-1.59.0-linux-armv6.tar.gz
|
||||||
d767108dcf84a8eaa844df3454cb0f75a492f4e7102ecc2b0a3545cfe073a566 golangci-lint-1.51.1-linux-loong64.tar.gz
|
d10ac38239d9efee3ee87b55c96cdf3fa09e1a525babe3ffdaaf65ccc48cf3dc golangci-lint-1.59.0-linux-armv7.tar.gz
|
||||||
3bd56c54daec16585b2668e0dfabb27af2c2b38cc0fdb46923e2521e1634846b golangci-lint-1.51.1-linux-mips64.tar.gz
|
047338114b4f0d5f08f0fb9a397b03cc171916ed0960be7dfb355c2320cd5e9c golangci-lint-1.59.0-linux-loong64.tar.gz
|
||||||
f72f5adfa2219e15d2414c9a2966f86e74556cf17a85c727a7fb7770a16cf814 golangci-lint-1.51.1-linux-mips64le.tar.gz
|
5632df0f7f8fc03a80a266130faef0b5902d280cf60621f1b2bdc1aef6d97ee9 golangci-lint-1.59.0-linux-mips64.tar.gz
|
||||||
e605521dac98096d8737e1997c954f41f1d0d8275b8731f62783d410c23574b9 golangci-lint-1.51.1-linux-ppc64le.tar.gz
|
71dd638c82fa4439171e7126d2c7a32b5d103bfdef282cea40c83632cb3d1f4b golangci-lint-1.59.0-linux-mips64le.tar.gz
|
||||||
2f683217b814339e74d61ca700922d8407f15addd6d4c5e8b156fbab79f26a87 golangci-lint-1.51.1-linux-riscv64.tar.gz
|
6cf9ea0d34e91669948483f9ae7f07da319a879344373a1981099fbd890cde00 golangci-lint-1.59.0-linux-ppc64le.tar.gz
|
||||||
d98528292b65971a3594e5880530e7624597dc9806fcfccdfbe39be411713d63 golangci-lint-1.51.1-linux-s390x.tar.gz
|
af0205fa6fbab197cee613c359947711231739095d21b5c837086233b36ad971 golangci-lint-1.59.0-linux-riscv64.tar.gz
|
||||||
9bb2d0fe9e692ed0aea4f2537e3e6862b2f6768fe2849a84f4a6ad09da9fd971 golangci-lint-1.51.1-netbsd-386.tar.gz
|
a9d2fb93f3c688ebccef94f5dc96c0b07c4d20bf6556cddebd8442159b0c80f6 golangci-lint-1.59.0-linux-s390x.tar.gz
|
||||||
34cafdcd11ae73ae88d66c33eb8449f5c976fc3e37b44774dbe9c71caa95e592 golangci-lint-1.51.1-netbsd-amd64.tar.gz
|
68ab4c57a847b8ace9679887f2f8b2b6760e57ee29dcde8c3f40dd8bb2654fa2 golangci-lint-1.59.0-netbsd-386.tar.gz
|
||||||
f8b4e1e47ac17caafe8a5f32f975a2b6a7cb14c27c0f73c1fb15c20ca91c2e03 golangci-lint-1.51.1-netbsd-armv6.tar.gz
|
d277b8b435c19406d00de4d509eadf5a024a5782878332e9a1b7c02bb76e87a7 golangci-lint-1.59.0-netbsd-amd64.tar.gz
|
||||||
c4f58b7e227b9fd41f0e9310dc83f4a4e7d026598e2f6e95b78761081a6d9bd2 golangci-lint-1.51.1-netbsd-armv7.tar.gz
|
83211656be8dcfa1545af4f92894409f412d1f37566798cb9460a526593ad62c golangci-lint-1.59.0-netbsd-arm64.tar.gz
|
||||||
6710e2f5375dc75521c1a17980a6cbbe6ff76c2f8b852964a8af558899a97cf5 golangci-lint-1.51.1-windows-386.zip
|
6c6866d28bf79fa9817a0f7d2b050890ed109cae80bdb4dfa39536a7226da237 golangci-lint-1.59.0-netbsd-armv6.tar.gz
|
||||||
722d7b87b9cdda0a3835d5030b3fc5385c2eba4c107f63f6391cfb2ac35f051d golangci-lint-1.51.1-windows-amd64.zip
|
11587566363bd03ca586b7df9776ccaed569fcd1f3489930ac02f9375b307503 golangci-lint-1.59.0-netbsd-armv7.tar.gz
|
||||||
eb57f9bcb56646f2e3d6ccaf02ec227815fb05077b2e0b1bf9e755805acdc2b9 golangci-lint-1.51.1-windows-arm64.zip
|
466181a8967bafa495e41494f93a0bec829c2cf715de874583b0460b3b8ae2b8 golangci-lint-1.59.0-windows-386.zip
|
||||||
bce02f7232723cb727755ee11f168a700a00896a25d37f87c4b173bce55596b4 golangci-lint-1.51.1-windows-armv6.zip
|
3317d8a87a99a49a0a1321d295c010790e6dbf43ee96b318f4b8bb23eae7a565 golangci-lint-1.59.0-windows-amd64.zip
|
||||||
cf6403f84707ce8c98664736772271bc8874f2e760c2fd0f00cf3e85963507e9 golangci-lint-1.51.1-windows-armv7.zip
|
b3af955c7fceac8220a36fc799e1b3f19d3b247d32f422caac5f9845df8f7316 golangci-lint-1.59.0-windows-arm64.zip
|
||||||
|
6f083c7d0c764e5a0e5bde46ee3e91ae357d80c194190fe1d9754392e9064c7e golangci-lint-1.59.0-windows-armv6.zip
|
||||||
|
3709b4dd425deadab27748778d08e03c0f804d7748f7dd5b6bb488d98aa031c7 golangci-lint-1.59.0-windows-armv7.zip
|
||||||
|
|
||||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||||
#
|
#
|
||||||
# This version is fine to be old and full of security holes, we just use it
|
# This version is fine to be old and full of security holes, we just use it
|
||||||
# to build the latest Go. Don't change it. If it ever becomes insufficient,
|
# to build the latest Go. Don't change it.
|
||||||
# we need to switch over to a recursive builder to jump across supported
|
|
||||||
# versions.
|
|
||||||
#
|
#
|
||||||
# version:ppa-builder 1.19.6
|
# version:ppa-builder-1 1.19.6
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
||||||
|
|
||||||
|
# version:ppa-builder-2 1.21.9
|
||||||
|
# https://go.dev/dl/
|
||||||
|
58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz
|
||||||
|
|
||||||
|
# version:protoc 27.1
|
||||||
|
# https://github.com/protocolbuffers/protobuf/releases/
|
||||||
|
# https://github.com/protocolbuffers/protobuf/releases/download/v27.1/
|
||||||
|
8809c2ec85368c6b6e9af161b6771a153aa92670a24adbe46dd34fa02a04df2f protoc-27.1-linux-aarch_64.zip
|
||||||
|
5d21979a6d27475e810b76b88863d1e784fa01ffb15e511a3ec5bd1924d89426 protoc-27.1-linux-ppcle_64.zip
|
||||||
|
84d8852750ed186dc4a057a1a86bcac409be5362d6af04770f42367fee6b7bc1 protoc-27.1-linux-s390_64.zip
|
||||||
|
2f028796ff5741691650e0eea290e61ff2f1c0d87f8d31fe45ef47fd967cef0c protoc-27.1-linux-x86_32.zip
|
||||||
|
8970e3d8bbd67d53768fe8c2e3971bdd71e51cfe2001ca06dacad17258a7dae3 protoc-27.1-linux-x86_64.zip
|
||||||
|
03b7af1bf469e7285dc51976ee5fa99412704dbd1c017105114852a37b165c12 protoc-27.1-osx-aarch_64.zip
|
||||||
|
f14d3973cf13283d07c520ed6f4c12405ad41b9efd18089a1c74897037d742b5 protoc-27.1-osx-universal_binary.zip
|
||||||
|
8520d944f3a3890fa296a3b3b0d4bb18337337e2526bbbf1b507eeea3c2a1ec4 protoc-27.1-osx-x86_64.zip
|
||||||
|
6263718ff96547b8392a079f6fdf02a4156f2e8d13cd51649a0d03fb7afa2de8 protoc-27.1-win32.zip
|
||||||
|
da531c51ccd1290d8d34821f0ce4e219c7fbaa6f9825f5a3fb092a9d03fe6206 protoc-27.1-win64.zip
|
||||||
|
|
||||||
|
# version:protoc-gen-go 1.34.2
|
||||||
|
# https://github.com/protocolbuffers/protobuf-go/releases/
|
||||||
|
# https://github.com/protocolbuffers/protobuf-go/releases/download/v1.34.2/
|
||||||
|
9b48d8f90add02e8e94e14962fed74e7ce2b2d6bda4dd42f1f4fbccf0f766f1a protoc-gen-go.v1.34.2.darwin.amd64.tar.gz
|
||||||
|
17aca7f948dbb624049030cf841e35895cf34183ba006e721247fdeb95ff2780 protoc-gen-go.v1.34.2.darwin.arm64.tar.gz
|
||||||
|
a191849433fd489f1d44f37788d762658f3f5fb225f3a85d4ce6ba32666703ed protoc-gen-go.v1.34.2.linux.386.tar.gz
|
||||||
|
b87bc134dee55576a842141bf0ed27761c635d746780fce5dee038c6dd16554f protoc-gen-go.v1.34.2.linux.amd64.tar.gz
|
||||||
|
63d400167e75ab9f6690688f6fdc6a9455aa20bc1faa71e32149dbd322f7f198 protoc-gen-go.v1.34.2.linux.arm64.tar.gz
|
||||||
|
56e7675816db6e62be4f833a51544d5716b8420c462515579e05ca8444ab06ed protoc-gen-go.v1.34.2.windows.386.zip
|
||||||
|
abafd39612177dd4e9a65207cadd5374a9352d8611e8e040f8462fcfa3010daf protoc-gen-go.v1.34.2.windows.amd64.zip
|
||||||
|
|
|
||||||
269
build/ci.go
269
build/ci.go
|
|
@ -39,9 +39,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
@ -117,23 +119,15 @@ var (
|
||||||
debEthereum,
|
debEthereum,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distros for which packages are created.
|
// Distros for which packages are created
|
||||||
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
debDistros = []string{
|
||||||
// Note: the following Ubuntu releases have been officially deprecated on Launchpad:
|
"xenial", // 16.04, EOL: 04/2026
|
||||||
// wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish,
|
"bionic", // 18.04, EOL: 04/2028
|
||||||
// kinetic
|
"focal", // 20.04, EOL: 04/2030
|
||||||
debDistroGoBoots = map[string]string{
|
"jammy", // 22.04, EOL: 04/2032
|
||||||
"trusty": "golang-1.11", // EOL: 04/2024
|
"noble", // 24.04, EOL: 04/2034
|
||||||
"xenial": "golang-go", // EOL: 04/2026
|
|
||||||
"bionic": "golang-go", // EOL: 04/2028
|
|
||||||
"focal": "golang-go", // EOL: 04/2030
|
|
||||||
"jammy": "golang-go", // EOL: 04/2032
|
|
||||||
"lunar": "golang-go", // EOL: 01/2024
|
|
||||||
}
|
|
||||||
|
|
||||||
debGoBootPaths = map[string]string{
|
"mantic", // 23.10, EOL: 07/2024
|
||||||
"golang-1.11": "/usr/lib/go-1.11",
|
|
||||||
"golang-go": "/usr/lib/go",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is where the tests should be unpacked.
|
// This is where the tests should be unpacked.
|
||||||
|
|
@ -177,6 +171,8 @@ func main() {
|
||||||
doPurge(os.Args[2:])
|
doPurge(os.Args[2:])
|
||||||
case "sanitycheck":
|
case "sanitycheck":
|
||||||
doSanityCheck()
|
doSanityCheck()
|
||||||
|
case "generate":
|
||||||
|
doGenerate()
|
||||||
default:
|
default:
|
||||||
log.Fatal("unknown command ", os.Args[1])
|
log.Fatal("unknown command ", os.Args[1])
|
||||||
}
|
}
|
||||||
|
|
@ -353,6 +349,86 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
||||||
return filepath.Join(cachedir, base)
|
return filepath.Join(cachedir, base)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hashSourceFiles iterates all files under the top-level project directory
|
||||||
|
// computing the hash of each file (excluding files within the tests
|
||||||
|
// subrepo)
|
||||||
|
func hashSourceFiles() (map[string]common.Hash, error) {
|
||||||
|
res := make(map[string]common.Hash)
|
||||||
|
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
||||||
|
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
if !d.Type().IsRegular() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// open the file and hash it
|
||||||
|
f, err := os.OpenFile(path, os.O_RDONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hasher := sha256.New()
|
||||||
|
if _, err := io.Copy(hasher, f); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res[path] = common.Hash(hasher.Sum(nil))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// doGenerate ensures that re-generating generated files does not cause
|
||||||
|
// any mutations in the source file tree: i.e. all generated files were
|
||||||
|
// updated and committed. Any stale generated files are updated.
|
||||||
|
func doGenerate() {
|
||||||
|
var (
|
||||||
|
tc = new(build.GoToolchain)
|
||||||
|
cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.")
|
||||||
|
verify = flag.Bool("verify", false, "check whether any files are changed by go generate")
|
||||||
|
)
|
||||||
|
|
||||||
|
protocPath := downloadProtoc(*cachedir)
|
||||||
|
protocGenGoPath := downloadProtocGenGo(*cachedir)
|
||||||
|
|
||||||
|
var preHashes map[string]common.Hash
|
||||||
|
if *verify {
|
||||||
|
var err error
|
||||||
|
preHashes, err = hashSourceFiles()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to compute map of source hashes", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := tc.Go("generate", "./...")
|
||||||
|
pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")}
|
||||||
|
c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator)))
|
||||||
|
build.MustRun(c)
|
||||||
|
|
||||||
|
if !*verify {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Check if files were changed.
|
||||||
|
postHashes, err := hashSourceFiles()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("error computing source tree file hashes", "err", err)
|
||||||
|
}
|
||||||
|
updates := []string{}
|
||||||
|
for path, postHash := range postHashes {
|
||||||
|
preHash, ok := preHashes[path]
|
||||||
|
if !ok || preHash != postHash {
|
||||||
|
updates = append(updates, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, updatedFile := range updates {
|
||||||
|
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||||
|
}
|
||||||
|
if len(updates) != 0 {
|
||||||
|
log.Fatal("One or more generated files were updated by running 'go generate ./...'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// doLint runs golangci-lint on requested packages.
|
// doLint runs golangci-lint on requested packages.
|
||||||
func doLint(cmdline []string) {
|
func doLint(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -366,7 +442,7 @@ func doLint(cmdline []string) {
|
||||||
|
|
||||||
linter := downloadLinter(*cachedir)
|
linter := downloadLinter(*cachedir)
|
||||||
lflags := []string{"run", "--config", ".golangci.yml"}
|
lflags := []string{"run", "--config", ".golangci.yml"}
|
||||||
build.MustRunCommand(linter, append(lflags, packages...)...)
|
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
|
||||||
fmt.Println("You have achieved perfection.")
|
fmt.Println("You have achieved perfection.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,6 +474,96 @@ func downloadLinter(cachedir string) string {
|
||||||
return filepath.Join(cachedir, base, "golangci-lint")
|
return filepath.Join(cachedir, base, "golangci-lint")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// protocArchiveBaseName returns the name of the protoc archive file for
|
||||||
|
// the current system, stripped of version and file suffix.
|
||||||
|
func protocArchiveBaseName() (string, error) {
|
||||||
|
switch runtime.GOOS + "-" + runtime.GOARCH {
|
||||||
|
case "windows-amd64":
|
||||||
|
return "win64", nil
|
||||||
|
case "windows-386":
|
||||||
|
return "win32", nil
|
||||||
|
case "linux-arm64":
|
||||||
|
return "linux-aarch_64", nil
|
||||||
|
case "linux-386":
|
||||||
|
return "linux-x86_32", nil
|
||||||
|
case "linux-amd64":
|
||||||
|
return "linux-x86_64", nil
|
||||||
|
case "darwin-arm64":
|
||||||
|
return "osx-aarch_64", nil
|
||||||
|
case "darwin-amd64":
|
||||||
|
return "osx-x86_64", nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("no prebuilt release of protoc available for this system (os: %s, arch: %s)", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// downloadProtocGenGo downloads protoc-gen-go, which is used by protoc
|
||||||
|
// in the generate command. It returns the full path of the directory
|
||||||
|
// containing the 'protoc-gen-go' executable.
|
||||||
|
func downloadProtocGenGo(cachedir string) string {
|
||||||
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
|
version, err := build.Version(csdb, "protoc-gen-go")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
baseName := fmt.Sprintf("protoc-gen-go.v%s.%s.%s", version, runtime.GOOS, runtime.GOARCH)
|
||||||
|
archiveName := baseName
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
archiveName += ".zip"
|
||||||
|
} else {
|
||||||
|
archiveName += ".tar.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf-go/releases/download/v%s/%s", version, archiveName)
|
||||||
|
|
||||||
|
archivePath := path.Join(cachedir, archiveName)
|
||||||
|
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
extractDest := filepath.Join(cachedir, baseName)
|
||||||
|
if err := build.ExtractArchive(archivePath, extractDest); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
extractDest, err = filepath.Abs(extractDest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("error resolving absolute path for protoc", "err", err)
|
||||||
|
}
|
||||||
|
return extractDest
|
||||||
|
}
|
||||||
|
|
||||||
|
// downloadProtoc downloads the prebuilt protoc binary used to lint generated
|
||||||
|
// files as a CI step. It returns the full path to the directory containing
|
||||||
|
// the protoc executable.
|
||||||
|
func downloadProtoc(cachedir string) string {
|
||||||
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
|
version, err := build.Version(csdb, "protoc")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
baseName, err := protocArchiveBaseName()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := fmt.Sprintf("protoc-%s-%s", version, baseName)
|
||||||
|
archiveFileName := fileName + ".zip"
|
||||||
|
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf/releases/download/v%s/%s", version, archiveFileName)
|
||||||
|
archivePath := filepath.Join(cachedir, archiveFileName)
|
||||||
|
|
||||||
|
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
extractDest := filepath.Join(cachedir, fileName)
|
||||||
|
if err := build.ExtractArchive(archivePath, extractDest); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
extractDest, err = filepath.Abs(extractDest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("error resolving absolute path for protoc", "err", err)
|
||||||
|
}
|
||||||
|
return extractDest
|
||||||
|
}
|
||||||
|
|
||||||
// Release Packaging
|
// Release Packaging
|
||||||
func doArchive(cmdline []string) {
|
func doArchive(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -694,7 +860,8 @@ func doDebianSource(cmdline []string) {
|
||||||
}
|
}
|
||||||
// Download and verify the Go source packages.
|
// Download and verify the Go source packages.
|
||||||
var (
|
var (
|
||||||
gobundle = downloadGoSources(*cachedir)
|
gobootbundles = downloadGoBootstrapSources(*cachedir)
|
||||||
|
gobundle = downloadGoSources(*cachedir)
|
||||||
)
|
)
|
||||||
// Download all the dependencies needed to build the sources and run the ci script
|
// Download all the dependencies needed to build the sources and run the ci script
|
||||||
srcdepfetch := tc.Go("mod", "download")
|
srcdepfetch := tc.Go("mod", "download")
|
||||||
|
|
@ -707,9 +874,9 @@ func doDebianSource(cmdline []string) {
|
||||||
|
|
||||||
// Create Debian packages and upload them.
|
// Create Debian packages and upload them.
|
||||||
for _, pkg := range debPackages {
|
for _, pkg := range debPackages {
|
||||||
for distro, goboot := range debDistroGoBoots {
|
for _, distro := range debDistros {
|
||||||
// Prepare the debian package with the go-ethereum sources.
|
// Prepare the debian package with the go-ethereum sources.
|
||||||
meta := newDebMetadata(distro, goboot, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
|
meta := newDebMetadata(distro, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
|
||||||
pkgdir := stageDebianSource(*workdir, meta)
|
pkgdir := stageDebianSource(*workdir, meta)
|
||||||
|
|
||||||
canonicalPath, err := common.VerifyPath(pkgdir)
|
canonicalPath, err := common.VerifyPath(pkgdir)
|
||||||
|
|
@ -718,6 +885,16 @@ func doDebianSource(cmdline []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add bootstrapper Go source code
|
||||||
|
for i, gobootbundle := range gobootbundles {
|
||||||
|
if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil {
|
||||||
|
log.Fatalf("Failed to extract bootstrapper Go sources: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, fmt.Sprintf(".goboot-%d", i+1))); err != nil {
|
||||||
|
log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add builder Go source code
|
// Add builder Go source code
|
||||||
if err := build.ExtractArchive(gobundle, canonicalPath); err != nil {
|
if err := build.ExtractArchive(gobundle, canonicalPath); err != nil {
|
||||||
log.Fatalf("Failed to extract builder Go sources: %v", err)
|
log.Fatalf("Failed to extract builder Go sources: %v", err)
|
||||||
|
|
@ -752,21 +929,26 @@ func doDebianSource(cmdline []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadGoBootstrapSources downloads the Go source tarball that will be used
|
// downloadGoBootstrapSources downloads the Go source tarball(s) that will be used
|
||||||
// to bootstrap the builder Go.
|
// to bootstrap the builder Go.
|
||||||
func downloadGoBootstrapSources(cachedir string) string {
|
func downloadGoBootstrapSources(cachedir string) []string {
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
gobootVersion, err := build.Version(csdb, "ppa-builder")
|
|
||||||
if err != nil {
|
var bundles []string
|
||||||
log.Fatal(err)
|
for _, booter := range []string{"ppa-builder-1", "ppa-builder-2"} {
|
||||||
|
gobootVersion, err := build.Version(csdb, booter)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
||||||
|
url := "https://dl.google.com/go/" + file
|
||||||
|
dst := filepath.Join(cachedir, file)
|
||||||
|
if err := csdb.DownloadFile(url, dst); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
bundles = append(bundles, dst)
|
||||||
}
|
}
|
||||||
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
return bundles
|
||||||
url := "https://dl.google.com/go/" + file
|
|
||||||
dst := filepath.Join(cachedir, file)
|
|
||||||
if err := csdb.DownloadFile(url, dst); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return dst
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadGoSources downloads the Go source tarball.
|
// downloadGoSources downloads the Go source tarball.
|
||||||
|
|
@ -844,10 +1026,7 @@ type debPackage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type debMetadata struct {
|
type debMetadata struct {
|
||||||
Env build.Environment
|
Env build.Environment
|
||||||
GoBootPackage string
|
|
||||||
GoBootPath string
|
|
||||||
|
|
||||||
PackageName string
|
PackageName string
|
||||||
|
|
||||||
// go-ethereum version being built. Note that this
|
// go-ethereum version being built. Note that this
|
||||||
|
|
@ -875,21 +1054,19 @@ func (d debExecutable) Package() string {
|
||||||
return d.BinaryName
|
return d.BinaryName
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDebMetadata(distro, goboot, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
|
func newDebMetadata(distro, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
|
||||||
if author == "" {
|
if author == "" {
|
||||||
// No signing key, use default author.
|
// No signing key, use default author.
|
||||||
author = "Ethereum Builds <fjl@ethereum.org>"
|
author = "Ethereum Builds <fjl@ethereum.org>"
|
||||||
}
|
}
|
||||||
return debMetadata{
|
return debMetadata{
|
||||||
GoBootPackage: goboot,
|
PackageName: name,
|
||||||
GoBootPath: debGoBootPaths[goboot],
|
Env: env,
|
||||||
PackageName: name,
|
Author: author,
|
||||||
Env: env,
|
Distro: distro,
|
||||||
Author: author,
|
Version: version,
|
||||||
Distro: distro,
|
Time: t.Format(time.RFC1123Z),
|
||||||
Version: version,
|
Executables: exes,
|
||||||
Time: t.Format(time.RFC1123Z),
|
|
||||||
Executables: exes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ Source: {{.Name}}
|
||||||
Section: science
|
Section: science
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: {{.Author}}
|
Maintainer: {{.Author}}
|
||||||
Build-Depends: debhelper (>= 8.0.0), {{.GoBootPackage}}
|
Build-Depends: debhelper (>= 8.0.0), golang-go
|
||||||
Standards-Version: 3.9.5
|
Standards-Version: 3.9.5
|
||||||
Homepage: https://ethereum.org
|
Homepage: https://ethereum.org
|
||||||
Vcs-Git: https://github.com/ethereum/go-ethereum.git
|
Vcs-Git: https://github.com/ethereum/go-ethereum.git
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# Launchpad rejects Go's access to $HOME, use custom folders
|
# Launchpad rejects Go's access to $HOME, use custom folders
|
||||||
export GOCACHE=/tmp/go-build
|
export GOCACHE=/tmp/go-build
|
||||||
export GOPATH=/tmp/gopath
|
export GOPATH=/tmp/gopath
|
||||||
export GOROOT_BOOTSTRAP={{.GoBootPath}}
|
export GOROOT_BOOTSTRAP=/usr/lib/go
|
||||||
|
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
# Don't try to be smart Launchpad, we know our build rules better than you
|
# Don't try to be smart Launchpad, we know our build rules better than you
|
||||||
|
|
@ -19,8 +19,9 @@ override_dh_auto_build:
|
||||||
#
|
#
|
||||||
# We're also shipping the bootstrapper as of Go 1.20 as it had minimum version
|
# We're also shipping the bootstrapper as of Go 1.20 as it had minimum version
|
||||||
# requirements opposed to older versions of Go.
|
# requirements opposed to older versions of Go.
|
||||||
(mv .goboot ../ && cd ../.goboot/src && ./make.bash)
|
(mv .goboot-1 ../ && cd ../.goboot-1/src && ./make.bash)
|
||||||
(mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot ./make.bash)
|
(mv .goboot-2 ../ && cd ../.goboot-2/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-1 ./make.bash)
|
||||||
|
(mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-2 ./make.bash)
|
||||||
|
|
||||||
# We can't download external go modules within Launchpad, so we're shipping the
|
# We can't download external go modules within Launchpad, so we're shipping the
|
||||||
# entire dependency source cache with go-ethereum.
|
# entire dependency source cache with go-ethereum.
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -292,8 +291,8 @@ func writeAuthors(files []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Write sorted list of authors back to the file.
|
// Write sorted list of authors back to the file.
|
||||||
slices.SortFunc(list, func(a, b string) bool {
|
slices.SortFunc(list, func(a, b string) int {
|
||||||
return strings.ToLower(a) < strings.ToLower(b)
|
return strings.Compare(strings.ToLower(a), strings.ToLower(b))
|
||||||
})
|
})
|
||||||
content := new(bytes.Buffer)
|
content := new(bytes.Buffer)
|
||||||
content.WriteString(authorsFileHeader)
|
content.WriteString(authorsFileHeader)
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ syncmode = "full"
|
||||||
|
|
||||||
[txpool]
|
[txpool]
|
||||||
nolocals = true
|
nolocals = true
|
||||||
pricelimit = 30000000000
|
pricelimit = 25000000000
|
||||||
accountslots = 16
|
accountslots = 16
|
||||||
globalslots = 32768
|
globalslots = 32768
|
||||||
accountqueue = 16
|
accountqueue = 16
|
||||||
|
|
@ -69,7 +69,7 @@ syncmode = "full"
|
||||||
|
|
||||||
[miner]
|
[miner]
|
||||||
gaslimit = 30000000
|
gaslimit = 30000000
|
||||||
gasprice = "30000000000"
|
gasprice = "25000000000"
|
||||||
# mine = true
|
# mine = true
|
||||||
# etherbase = "VALIDATOR ADDRESS"
|
# etherbase = "VALIDATOR ADDRESS"
|
||||||
# extradata = ""
|
# extradata = ""
|
||||||
|
|
@ -127,7 +127,7 @@ syncmode = "full"
|
||||||
# maxheaderhistory = 1024
|
# maxheaderhistory = 1024
|
||||||
# maxblockhistory = 1024
|
# maxblockhistory = 1024
|
||||||
# maxprice = "5000000000000"
|
# maxprice = "5000000000000"
|
||||||
ignoreprice = "30000000000"
|
ignoreprice = "25000000000"
|
||||||
|
|
||||||
[telemetry]
|
[telemetry]
|
||||||
metrics = true
|
metrics = true
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
104
cmd/blsync/main.go
Normal file
104
cmd/blsync/main.go
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright 2022 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/blsync"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
cli "github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := flags.NewApp("beacon light syncer tool")
|
||||||
|
app.Flags = flags.Merge([]cli.Flag{
|
||||||
|
utils.BeaconApiFlag,
|
||||||
|
utils.BeaconApiHeaderFlag,
|
||||||
|
utils.BeaconThresholdFlag,
|
||||||
|
utils.BeaconNoFilterFlag,
|
||||||
|
utils.BeaconConfigFlag,
|
||||||
|
utils.BeaconGenesisRootFlag,
|
||||||
|
utils.BeaconGenesisTimeFlag,
|
||||||
|
utils.BeaconCheckpointFlag,
|
||||||
|
//TODO datadir for optional permanent database
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.SepoliaFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.BlsyncApiFlag,
|
||||||
|
utils.BlsyncJWTSecretFlag,
|
||||||
|
},
|
||||||
|
debug.Flags,
|
||||||
|
)
|
||||||
|
app.Before = func(ctx *cli.Context) error {
|
||||||
|
flags.MigrateGlobalFlags(ctx)
|
||||||
|
return debug.Setup(ctx)
|
||||||
|
}
|
||||||
|
app.After = func(ctx *cli.Context) error {
|
||||||
|
debug.Exit()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
app.Action = sync
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sync(ctx *cli.Context) error {
|
||||||
|
// set up blsync
|
||||||
|
client := blsync.NewClient(ctx)
|
||||||
|
client.SetEngineRPC(makeRPCClient(ctx))
|
||||||
|
client.Start()
|
||||||
|
|
||||||
|
// run until stopped
|
||||||
|
<-ctx.Done()
|
||||||
|
client.Stop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRPCClient(ctx *cli.Context) *rpc.Client {
|
||||||
|
if !ctx.IsSet(utils.BlsyncApiFlag.Name) {
|
||||||
|
log.Warn("No engine API target specified, performing a dry run")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !ctx.IsSet(utils.BlsyncJWTSecretFlag.Name) {
|
||||||
|
utils.Fatalf("JWT secret parameter missing") //TODO use default if datadir is specified
|
||||||
|
}
|
||||||
|
|
||||||
|
engineApiUrl, jwtFileName := ctx.String(utils.BlsyncApiFlag.Name), ctx.String(utils.BlsyncJWTSecretFlag.Name)
|
||||||
|
var jwtSecret [32]byte
|
||||||
|
if jwt, err := node.ObtainJWTSecret(jwtFileName); err == nil {
|
||||||
|
copy(jwtSecret[:], jwt)
|
||||||
|
} else {
|
||||||
|
utils.Fatalf("Error loading or generating JWT secret: %v", err)
|
||||||
|
}
|
||||||
|
auth := node.NewJWTAuth(jwtSecret)
|
||||||
|
cl, err := rpc.DialOptions(context.Background(), engineApiUrl, rpc.WithHTTPAuth(auth))
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not create RPC client: %v", err)
|
||||||
|
}
|
||||||
|
return cl
|
||||||
|
}
|
||||||
|
|
@ -225,8 +225,8 @@ Response
|
||||||
- `value` [number:optional]: amount of Wei to send with the transaction
|
- `value` [number:optional]: amount of Wei to send with the transaction
|
||||||
- `data` [data:optional]: input data
|
- `data` [data:optional]: input data
|
||||||
- `nonce` [number]: account nonce
|
- `nonce` [number]: account nonce
|
||||||
1. method signature [string:optional]
|
2. method signature [string:optional]
|
||||||
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
||||||
|
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
|
|
@ -916,7 +916,7 @@ There are a couple of implementation for a UI. We'll try to keep this list up to
|
||||||
|
|
||||||
| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
|
| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
|
||||||
| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
|
| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
|
||||||
| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
|
| QtSigner| https://github.com/holiman/qtsigner/ | Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
|
||||||
| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
|
| GtkSigner| https://github.com/holiman/gtksigner | Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
|
||||||
| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |
|
| Frame | https://github.com/floating/frame/commits/go-signer | Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |
|
||||||
| Clef UI| https://github.com/ethereum/clef-ui| Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: | :+1: (approve tx only)|
|
| Clef UI| https://github.com/ethereum/clef-ui | Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: | :+1: (approve tx only)|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Additional labels for pre-release and build metadata are available as extensions
|
||||||
|
|
||||||
Added `clef_New` to the internal API callable from a UI.
|
Added `clef_New` to the internal API callable from a UI.
|
||||||
|
|
||||||
> `New` creates a new password protected Account. The private key is protected with
|
> `New` creates a new password-protected Account. The private key is protected with
|
||||||
> the given password. Users are responsible to backup the private key that is stored
|
> the given password. Users are responsible to backup the private key that is stored
|
||||||
> in the keystore location that was specified when this API was created.
|
> in the keystore location that was specified when this API was created.
|
||||||
> This method is the same as New on the external API, the difference being that
|
> This method is the same as New on the external API, the difference being that
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/signer/fourbyte"
|
"github.com/ethereum/go-ethereum/signer/fourbyte"
|
||||||
"github.com/ethereum/go-ethereum/signer/rules"
|
"github.com/ethereum/go-ethereum/signer/rules"
|
||||||
"github.com/ethereum/go-ethereum/signer/storage"
|
"github.com/ethereum/go-ethereum/signer/storage"
|
||||||
"github.com/mattn/go-colorable"
|
colorable "github.com/mattn/go-colorable"
|
||||||
"github.com/mattn/go-isatty"
|
isatty "github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -600,7 +600,7 @@ func listWallets(c *cli.Context) error {
|
||||||
// accountImport imports a raw hexadecimal private key via CLI.
|
// accountImport imports a raw hexadecimal private key via CLI.
|
||||||
func accountImport(c *cli.Context) error {
|
func accountImport(c *cli.Context) error {
|
||||||
if c.Args().Len() != 1 {
|
if c.Args().Len() != 1 {
|
||||||
return errors.New("<keyfile> must be given as first argument.")
|
return errors.New("<keyfile> must be given as first argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
internalApi, ui, err := initInternalApi(c)
|
internalApi, ui, err := initInternalApi(c)
|
||||||
|
|
@ -784,6 +784,7 @@ func signer(c *cli.Context) error {
|
||||||
"light-kdf", lightKdf, "advanced", advanced)
|
"light-kdf", lightKdf, "advanced", advanced)
|
||||||
|
|
||||||
am := core.StartClefAccountManager(ksLoc, nousb, lightKdf, scpath)
|
am := core.StartClefAccountManager(ksLoc, nousb, lightKdf, scpath)
|
||||||
|
defer am.Close()
|
||||||
apiImpl := core.NewSignerAPI(am, chainId, nousb, ui, db, advanced, pwStorage)
|
apiImpl := core.NewSignerAPI(am, chainId, nousb, ui, db, advanced, pwStorage)
|
||||||
|
|
||||||
// Establish the bidirectional communication, by creating a new UI backend and registering
|
// Establish the bidirectional communication, by creating a new UI backend and registering
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,14 @@ It enables usecases like the following:
|
||||||
|
|
||||||
The two main features that are required for this to work well are;
|
The two main features that are required for this to work well are;
|
||||||
|
|
||||||
1. Rule Implementation: how to create, manage and interpret rules in a flexible but secure manner
|
1. Rule Implementation: how to create, manage, and interpret rules in a flexible but secure manner
|
||||||
2. Credential managements and credentials; how to provide auto-unlock without exposing keys unnecessarily.
|
2. Credential management and credentials; how to provide auto-unlock without exposing keys unnecessarily.
|
||||||
|
|
||||||
The section below deals with both of them
|
The section below deals with both of them
|
||||||
|
|
||||||
## Rule Implementation
|
## Rule Implementation
|
||||||
|
|
||||||
A ruleset file is implemented as a `js` file. Under the hood, the ruleset-engine is a `SignerUI`, implementing the same methods as the `json-rpc` methods
|
A ruleset file is implemented as a `js` file. Under the hood, the ruleset engine is a `SignerUI`, implementing the same methods as the `json-rpc` methods
|
||||||
defined in the UI protocol. Example:
|
defined in the UI protocol. Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
@ -27,7 +27,7 @@ function asBig(str) {
|
||||||
return new BigNumber(str)
|
return new BigNumber(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approve transactions to a certain contract if value is below a certain limit
|
// Approve transactions to a certain contract if the value is below a certain limit
|
||||||
function ApproveTx(req) {
|
function ApproveTx(req) {
|
||||||
var limit = big.Newint("0xb1a2bc2ec50000")
|
var limit = big.Newint("0xb1a2bc2ec50000")
|
||||||
var value = asBig(req.transaction.value);
|
var value = asBig(req.transaction.value);
|
||||||
|
|
@ -70,7 +70,7 @@ The Otto vm has a few [caveats](https://github.com/robertkrimen/otto):
|
||||||
Additionally, a few more have been added
|
Additionally, a few more have been added
|
||||||
|
|
||||||
* The rule execution cannot load external javascript files.
|
* The rule execution cannot load external javascript files.
|
||||||
* The only preloaded library is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the github repository.
|
* The only preloaded library is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the GitHub repository.
|
||||||
* Each invocation is made in a fresh virtual machine. This means that you cannot store data in global variables between invocations. This is a deliberate choice -- if you want to store data, use the disk-backed `storage`, since rules should not rely on ephemeral data.
|
* Each invocation is made in a fresh virtual machine. This means that you cannot store data in global variables between invocations. This is a deliberate choice -- if you want to store data, use the disk-backed `storage`, since rules should not rely on ephemeral data.
|
||||||
* Javascript API parameters are _always_ an object. This is also a design choice, to ensure that parameters are accessed by _key_ and not by order. This is to prevent mistakes due to missing parameters or parameter changes.
|
* Javascript API parameters are _always_ an object. This is also a design choice, to ensure that parameters are accessed by _key_ and not by order. This is to prevent mistakes due to missing parameters or parameter changes.
|
||||||
* The JS engine has access to `storage` and `console`.
|
* The JS engine has access to `storage` and `console`.
|
||||||
|
|
@ -88,8 +88,8 @@ Some security precautions can be made, such as:
|
||||||
|
|
||||||
##### Security of implementation
|
##### Security of implementation
|
||||||
|
|
||||||
The drawbacks of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement, since it's already
|
The drawback of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement since it's already
|
||||||
implemented for `geth`. There are no known security vulnerabilities in, nor have we had any security-problems with it so far.
|
implemented for `geth`. There are no known security vulnerabilities in it, nor have we had any security problems with it so far.
|
||||||
|
|
||||||
The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered
|
The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered
|
||||||
an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit
|
an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit
|
||||||
|
|
@ -105,7 +105,7 @@ It's unclear whether any other DSL could be more secure; since there's always th
|
||||||
|
|
||||||
## Credential management
|
## Credential management
|
||||||
|
|
||||||
The ability to auto-approve transaction means that the signer needs to have necessary credentials to decrypt keyfiles. These passwords are hereafter called `ksp` (keystore pass).
|
The ability to auto-approve transactions means that the signer needs to have the necessary credentials to decrypt keyfiles. These passwords are hereafter called `ksp` (keystore pass).
|
||||||
|
|
||||||
### Example implementation
|
### Example implementation
|
||||||
|
|
||||||
|
|
@ -127,8 +127,8 @@ The `vault.dat` would be an encrypted container storing the following informatio
|
||||||
|
|
||||||
### Security considerations
|
### Security considerations
|
||||||
|
|
||||||
This would leave it up to the user to ensure that the `path/to/masterseed` is handled in a secure way. It's difficult to get around this, although one could
|
This would leave it up to the user to ensure that the `path/to/masterseed` is handled securely. It's difficult to get around this, although one could
|
||||||
imagine leveraging OS-level keychains where supported. The setup is however in general similar to how ssh-keys are stored in `.ssh/`.
|
imagine leveraging OS-level keychains where supported. The setup is however, in general, similar to how ssh-keys are stored in `.ssh/`.
|
||||||
|
|
||||||
|
|
||||||
# Implementation status
|
# Implementation status
|
||||||
|
|
@ -149,7 +149,7 @@ function big(str) {
|
||||||
// Time window: 1 week
|
// Time window: 1 week
|
||||||
var window = 1000* 3600*24*7;
|
var window = 1000* 3600*24*7;
|
||||||
|
|
||||||
// Limit : 1 ether
|
// Limit: 1 ether
|
||||||
var limit = new BigNumber("1e18");
|
var limit = new BigNumber("1e18");
|
||||||
|
|
||||||
function isLimitOk(transaction) {
|
function isLimitOk(transaction) {
|
||||||
|
|
@ -163,7 +163,7 @@ function isLimitOk(transaction) {
|
||||||
if (stored != "") {
|
if (stored != "") {
|
||||||
txs = JSON.parse(stored)
|
txs = JSON.parse(stored)
|
||||||
}
|
}
|
||||||
// First, remove all that have passed out of the time-window
|
// First, remove all that has passed out of the time window
|
||||||
var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart});
|
var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart});
|
||||||
console.log(txs, newtxs.length);
|
console.log(txs, newtxs.length);
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ function isLimitOk(transaction) {
|
||||||
console.log("ApproveTx > Sum so far", sum);
|
console.log("ApproveTx > Sum so far", sum);
|
||||||
console.log("ApproveTx > Requested", value.toNumber());
|
console.log("ApproveTx > Requested", value.toNumber());
|
||||||
|
|
||||||
// Would we exceed weekly limit ?
|
// Would we exceed the weekly limit ?
|
||||||
return sum.plus(value).lt(limit)
|
return sum.plus(value).lt(limit)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,31 +108,32 @@ Start the test by running `devp2p discv5 test -listen1 127.0.0.1 -listen2 127.0.
|
||||||
|
|
||||||
The Eth Protocol test suite is a conformance test suite for the [eth protocol][eth].
|
The Eth Protocol test suite is a conformance test suite for the [eth protocol][eth].
|
||||||
|
|
||||||
To run the eth protocol test suite against your implementation, the node needs to be initialized as such:
|
To run the eth protocol test suite against your implementation, the node needs to be initialized
|
||||||
|
with our test chain. The chain files are located in `./cmd/devp2p/internal/ethtest/testdata`.
|
||||||
|
|
||||||
1. initialize the geth node with the `genesis.json` file contained in the `testdata` directory
|
1. initialize the geth node with the `genesis.json` file
|
||||||
2. import the `halfchain.rlp` file in the `testdata` directory
|
2. import blocks from `chain.rlp`
|
||||||
3. run geth with the following flags:
|
3. run the client using the resulting database. For geth, use a command like the one below:
|
||||||
```
|
|
||||||
geth --datadir <datadir> --nodiscover --nat=none --networkid 19763 --verbosity 5
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, run the following command, replacing `<enode>` with the enode of the geth node:
|
geth \
|
||||||
```
|
--datadir <datadir> \
|
||||||
devp2p rlpx eth-test <enode> cmd/devp2p/internal/ethtest/testdata/chain.rlp cmd/devp2p/internal/ethtest/testdata/genesis.json
|
--nodiscover \
|
||||||
```
|
--nat=none \
|
||||||
|
--networkid 3503995874084926 \
|
||||||
|
--verbosity 5 \
|
||||||
|
--authrpc.jwtsecret 0x7365637265747365637265747365637265747365637265747365637265747365
|
||||||
|
|
||||||
|
Note that the tests also require access to the engine API.
|
||||||
|
The test suite can now be executed using the devp2p tool.
|
||||||
|
|
||||||
|
devp2p rlpx eth-test \
|
||||||
|
--chain internal/ethtest/testdata \
|
||||||
|
--node enode://.... \
|
||||||
|
--engineapi http://127.0.0.1:8551 \
|
||||||
|
--jwtsecret 0x7365637265747365637265747365637265747365637265747365637265747365
|
||||||
|
|
||||||
Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again.
|
Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again.
|
||||||
|
|
||||||
#### Eth66 Test Suite
|
|
||||||
|
|
||||||
The Eth66 test suite is also a conformance test suite for the eth 66 protocol version specifically.
|
|
||||||
To run the eth66 protocol test suite, initialize a geth node as described above and run the following command,
|
|
||||||
replacing `<enode>` with the enode of the geth node:
|
|
||||||
|
|
||||||
```
|
|
||||||
devp2p rlpx eth66-test <enode> cmd/devp2p/internal/ethtest/testdata/chain.rlp cmd/devp2p/internal/ethtest/testdata/genesis.json
|
|
||||||
```
|
|
||||||
|
|
||||||
[eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md
|
[eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md
|
||||||
[dns-tutorial]: https://geth.ethereum.org/docs/developers/geth-developer/dns-discovery-setup
|
[dns-tutorial]: https://geth.ethereum.org/docs/developers/geth-developer/dns-discovery-setup
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue