Compare commits

..

36 Commits

Author SHA1 Message Date
zzzckck
ec318b9c97
github: upgrade upload artifact from v4.1.7 to v4.3.3 (#2713) 2024-09-19 15:02:02 +08:00
zzzckck
6624522423
github: upgrade artifact from v3 to v4.1.7 (#2712)
upload-artifact and download-artifact must use same version, otherwise
release workflow will fail.
https://github.com/actions/toolkit/blob/main/packages/artifact/docs/faq.md
2024-09-19 14:54:35 +08:00
zzzckck
206c3b0ab0
Merge pull request #2701 from bnb-chain/develop
Draft release v1.4.15
2024-09-19 11:50:11 +08:00
zzzckck
089064c1ff
Merge pull request #2683 from buddh0/remove_duplicate_list_check
eth/handler: remove duplicate check for lists in body
2024-09-19 10:13:27 +08:00
buddh0
5289ecdfe2 eth/protocols: add Withdrawals check before broadcastBlock 2024-09-18 17:12:43 +08:00
buddh0
d141ff06c3 Revert "eth/handler: check lists in body before broadcast blocks (#2461)"
This reverts commit 0c0958ff8709eab1d5d4d0adaa81c09a89ec75d9.
2024-09-18 17:11:37 +08:00
zzzckck
9cbac84363
doc: update readme to remove Beacon chain part (#2697)
others changes:
  - remove bsc-docker, as it is broken
  - remove light client, as it is no longer supported
2024-09-18 16:56:10 +08:00
zzzckck
21faa2de3f
release: prepare for release v1.4.15 (#2700) 2024-09-18 14:34:01 +08:00
WMQ
34059cb144
faucet: update DIN token faucet support (#2706) 2024-09-18 11:51:59 +08:00
tiaoxizhan
3e44dcaa55
chore: add missing symbols in comment (#2704) 2024-09-14 09:12:56 +08:00
zzzckck
282aee5856
faucet: add example for custimized token (#2698) 2024-09-12 15:48:11 +08:00
zzzckck
44e91bba23
faucet: support customized token (#2687) 2024-09-12 15:10:37 +08:00
zzzckck
774d1b7ddb
Merge pull request #2684 from ngotchac/ngotchac/requeue-fixes 2024-09-11 10:58:06 +08:00
buddho
8bbd8fbf48
consensus/parlia: wait more time when processing huge blocks (#2689) 2024-09-11 10:14:11 +08:00
buddho
a28262b3ec
miner: limit block size to eth protocol msg size (#2696) 2024-09-10 16:24:29 +08:00
buddho
7de27ca9e9
CI: nancy ignore CVE-2024-8421 (#2695) 2024-09-10 11:27:04 +08:00
zzzckck
e7e5d508b5
txpool: set default GasCeil from 30M to 0 (#2688)
This PR tries to improve https://github.com/bnb-chain/bsc/pull/2680
If the node did not set `Eth.Miner` in config.toml, the default GasCeil
will be 30000000, it is not an accurate number for both BSC mainnet and testnet.
Set it to 0 means disable the transaction GasLimit check, i.e. the TxPool will
accept transactions with any GasLimit size.
2024-09-05 22:01:24 +08:00
Nicolas Gotchac
03069a7703 fetcher: Sleep after marking block as done when requeuing
Otherwise the node will be waiting for 500ms before the block fetcher
keeps processing.
2024-09-04 11:31:12 +02:00
galaio
1bcdad851f
metrics: add some extra feature flags as node stats; (#2662) 2024-09-04 16:37:43 +08:00
Nicolas Gotchac
24a46de5b2
eth: Add sidecars when available to broadcasted current block (#2675) 2024-09-04 16:22:07 +08:00
zzzckck
5c4096fffa
faucet: with mainnet balance check, 0.002BNB at least (#2672) 2024-09-04 16:19:01 +08:00
dependabot[bot]
f85d19aa8f
build(deps): bump actions/download-artifact in /.github/workflows (#2679)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4.1.7.
2024-09-04 16:12:07 +08:00
zzzckck
0dab664d98
txpool: apply miner's gasceil to txpool (#2680)
apply `Eth.Miner.GasCeil` to TxPool even the node did not enable `--mine` option
Otherwise, there could be accmulated pending transactions in txpool.
Take an example:
- Currently, BSC testnet's block gaslimit is 70M, as 20M gas is reserved for
  SystemTxs, the maximum acceptable GasLimit for transaction is 50M.
- TxPool recevied a transaction with GasLimit 60M, it would be accepted in TxPool but it
  will never be accepted by validators. Such kinds of transactions will be kept in txpool
  and gradually make the txpool overflowed
2024-09-04 16:02:27 +08:00
Dike.w
094519d058
beaconserver: simulated beacon api server for op-stack (#2678)
only some necessary apis are implemented.
2024-09-04 09:39:01 +08:00
zzzckck
d3450f13c9
log: add some p2p log (#2677) 2024-09-03 14:27:53 +08:00
zzzckck
75af65dbf2
Merge pull request #2669 from bnb-chain/develop
Draft release v1.4.14
2024-08-27 15:00:23 +08:00
zzzckck
959850218c
release: prepare for release v1.4.14 (#2668) 2024-08-27 11:23:04 +08:00
zzzckck
af0204bd68
faucet: bump and resend faucet transaction if it has been pending for a while (#2665) 2024-08-26 16:09:34 +08:00
zzzckck
ec2d7e0228
config: setup Mainnet 2 hardfork date: HaberFix & Bohr (#2661)
expected hard fork date:
    Mainnet-HaberFix: 2024-09-26 02:02:00 AM UTC
    Mainnet-Bohr:     2024-09-26 02:20:00 AM UTC
2024-08-23 13:59:56 +08:00
Dike.w
c46d7e8bd8
ethclient: fix BlobSidecars api (#2656) 2024-08-22 11:07:05 +08:00
Chris Li
6cb4be4ebf
fix: when dataset is pruned and pruneancient is set, the offset is error (#2657) 2024-08-21 15:37:42 +08:00
buddho
3bd9a2395c
core: improve readability of the fork choice logic (#2658) 2024-08-20 23:06:49 +08:00
buddho
5d19f2182b
internal/ethapi: make GetFinalizedHeader monotonically increasing (#2655) 2024-08-20 11:51:32 +08:00
buddho
99a2dd5ed9
internal/debug: remove memsize (#2649) 2024-08-15 11:38:14 +08:00
zzzckck
26a4d4fda6
Merge pull request #2633 from bnb-chain/develop
Draft release v1.4.13
2024-08-08 16:38:42 +08:00
zzzckck
83a9b13771
Merge pull request #2607 from NathanBSC/for_release_v1.4.12
Revert "miner/worker: broadcast block immediately once sealed (bnb-chain#2576)"
2024-07-24 12:07:13 +08:00
52 changed files with 1016 additions and 330 deletions

View File

@ -82,28 +82,28 @@ jobs:
# ==============================
- name: Upload Linux Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'ubuntu-latest'
with:
name: linux
path: ./build/bin/geth
- name: Upload MacOS Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'macos-latest'
with:
name: macos
path: ./build/bin/geth
- name: Upload Windows Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'windows-latest'
with:
name: windows
path: ./build/bin/geth.exe
- name: Upload ARM-64 Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'ubuntu-latest'
with:
name: arm64
@ -125,25 +125,25 @@ jobs:
# ==============================
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: linux
path: ./linux
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: macos
path: ./macos
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: windows
path: ./windows
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: arm64
path: ./arm64

View File

@ -81,28 +81,28 @@ jobs:
# ==============================
- name: Upload Linux Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'ubuntu-latest'
with:
name: linux
path: ./build/bin/geth
- name: Upload MacOS Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'macos-latest'
with:
name: macos
path: ./build/bin/geth
- name: Upload Windows Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'windows-latest'
with:
name: windows
path: ./build/bin/geth.exe
- name: Upload ARM-64 Build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4.3.3
if: matrix.os == 'ubuntu-latest'
with:
name: arm64
@ -124,25 +124,25 @@ jobs:
# ==============================
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: linux
path: ./linux
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: macos
path: ./macos
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: windows
path: ./windows
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4.1.7
with:
name: arm64
path: ./arm64

View File

@ -1,2 +1,3 @@
CVE-2024-34478 # "CWE-754: Improper Check for Unusual or Exceptional Conditions." This vulnerability is BTC only, BSC does not have the issue.
CVE-2024-6104 # "CWE-532: Information Exposure Through Log Files" This is caused by the vulnerabilities go-retryablehttp@v0.7.4, it is only used in cmd devp2p, impact is limited. will upgrade to v0.7.7 later
CVE-2024-8421 # "CWE-400: Uncontrolled Resource Consumption (Resource Exhaustion)" This vulnerability is caused by issues in the golang.org/x/net package. Even the latest version(v0.29.0) has not yet addressed it, but we will continue to monitor updates closely.

View File

@ -1,4 +1,43 @@
# Changelog
## v1.4.15
### BUGFIX
* [\#2680](https://github.com/bnb-chain/bsc/pull/2680) txpool: apply miner's gasceil to txpool
* [\#2688](https://github.com/bnb-chain/bsc/pull/2688) txpool: set default GasCeil from 30M to 0
* [\#2696](https://github.com/bnb-chain/bsc/pull/2696) miner: limit block size to eth protocol msg size
* [\#2684](https://github.com/bnb-chain/bsc/pull/2684) eth: Add sidecars when available to broadcasted current block
### FEATURE
* [\#2672](https://github.com/bnb-chain/bsc/pull/2672) faucet: with mainnet balance check, 0.002BNB at least
* [\#2678](https://github.com/bnb-chain/bsc/pull/2678) beaconserver: simulated beacon api server for op-stack
* [\#2687](https://github.com/bnb-chain/bsc/pull/2687) faucet: support customized token
* [\#2698](https://github.com/bnb-chain/bsc/pull/2698) faucet: add example for custimized token
* [\#2706](https://github.com/bnb-chain/bsc/pull/2706) faucet: update DIN token faucet support
### IMPROVEMENT
* [\#2677](https://github.com/bnb-chain/bsc/pull/2677) log: add some p2p log
* [\#2679](https://github.com/bnb-chain/bsc/pull/2679) build(deps): bump actions/download-artifact in /.github/workflows
* [\#2662](https://github.com/bnb-chain/bsc/pull/2662) metrics: add some extra feature flags as node stats
* [\#2675](https://github.com/bnb-chain/bsc/pull/2675) fetcher: Sleep after marking block as done when requeuing
* [\#2695](https://github.com/bnb-chain/bsc/pull/2695) CI: nancy ignore CVE-2024-8421
* [\#2689](https://github.com/bnb-chain/bsc/pull/2689) consensus/parlia: wait more time when processing huge blocks
## v1.4.14
### BUGFIX
* [\#2643](https://github.com/bnb-chain/bsc/pull/2643)core: fix cache for receipts
* [\#2656](https://github.com/bnb-chain/bsc/pull/2656)ethclient: fix BlobSidecars api
* [\#2657](https://github.com/bnb-chain/bsc/pull/2657)fix: update prunefreezers offset when pruneancient and the dataset has pruned block
### FEATURE
* [\#2661](https://github.com/bnb-chain/bsc/pull/2661)config: setup Mainnet 2 hardfork date: HaberFix & Bohr
### IMPROVEMENT
* [\#2578](https://github.com/bnb-chain/bsc/pull/2578)core/systemcontracts: use vm.StateDB in UpgradeBuildInSystemContract
* [\#2649](https://github.com/bnb-chain/bsc/pull/2649)internal/debug: remove memsize
* [\#2655](https://github.com/bnb-chain/bsc/pull/2655)internal/ethapi: make GetFinalizedHeader monotonically increasing
* [\#2658](https://github.com/bnb-chain/bsc/pull/2658)core: improve readability of the fork choice logic
* [\#2665](https://github.com/bnb-chain/bsc/pull/2665)faucet: bump and resend faucet transaction if it has been pending for a while
## v1.4.13
### BUGFIX

View File

@ -17,6 +17,11 @@ geth:
@echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth."
#? faucet: Build faucet
faucet:
$(GORUN) build/ci.go install ./cmd/faucet
@echo "Done building faucet"
#? all: Build all packages and executables
all:
$(GORUN) build/ci.go install

View File

@ -9,16 +9,15 @@ https://pkg.go.dev/badge/github.com/ethereum/go-ethereum
)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/z2VpC455eU)
But from that baseline of EVM compatible, BNB Smart Chain introduces a system of 21 validators with Proof of Staked Authority (PoSA) consensus that can support short block time and lower fees. The most bonded validator candidates of staking will become validators and produce blocks. The double-sign detection and other slashing logic guarantee security, stability, and chain finality.
But from that baseline of EVM compatible, BNB Smart Chain introduces a system of 21 validators with Proof of Staked Authority (PoSA) consensus that can support short block time and lower fees. The most bonded validator candidates of staking will become validators and produce blocks. The double-sign detection and other slashing logic guarantee security, stability, and chain finality.
Cross-chain transfer and other communication are possible due to native support of interoperability. Relayers and on-chain contracts are developed to support that. BNB Beacon Chain DEX remains a liquid venue of the exchange of assets on both chains. This dual-chain architecture will be ideal for users to take advantage of the fast trading on one side and build their decentralized apps on the other side. **The BNB Smart Chain** will be:
**The BNB Smart Chain** will be:
- **A self-sovereign blockchain**: Provides security and safety with elected validators.
- **EVM-compatible**: Supports all the existing Ethereum tooling along with faster finality and cheaper transaction fees.
- **Interoperable**: Comes with efficient native dual chain communication; Optimized for scaling high-performance dApps that require fast and smooth user experience.
- **Distributed with on-chain governance**: Proof of Staked Authority brings in decentralization and community participants. As the native token, BNB will serve as both the gas of smart contract execution and tokens for staking.
More details in [White Paper](https://www.bnbchain.org/en#smartChain).
More details in [White Paper](https://github.com/bnb-chain/whitepaper/blob/master/WHITEPAPER.md).
## Key features
@ -34,18 +33,8 @@ To combine DPoS and PoA for consensus, BNB Smart Chain implement a novel consens
1. Blocks are produced by a limited set of validators.
2. Validators take turns to produce blocks in a PoA manner, similar to Ethereum's Clique consensus engine.
3. Validator set are elected in and out based on a staking based governance on BNB Beacon Chain.
4. The validator set change is relayed via a cross-chain communication mechanism.
5. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/bnb-smart-chain/staking/overview/#system-contracts) to achieve liveness slash, revenue distributing and validator set renewing func.
### Light Client of BNB Beacon Chain
To achieve the cross-chain communication from BNB Beacon Chain to BNB Smart Chain, need introduce a on-chain light client verification algorithm.
It contains two parts:
1. [Stateless Precompiled contracts](https://github.com/bnb-chain/bsc/blob/master/core/vm/contracts_lightclient.go) to do tendermint header verification and Merkle Proof verification.
2. [Stateful solidity contracts](https://github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/TendermintLightClient.sol) to store validator set and trusted appHash.
3. Validator set are elected in and out based on a staking based governance on BNB Smart Chain.
4. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/bnb-smart-chain/staking/overview/#system-contracts) to achieve liveness slash, revenue distributing and validator set renewing func.
## Native Token
@ -53,7 +42,6 @@ BNB will run on BNB Smart Chain in the same way as ETH runs on Ethereum so that
BNB will be used to:
1. pay `gas` to deploy or invoke Smart Contract on BSC
2. perform cross-chain operations, such as transfer token assets across BNB Smart Chain and BNB Beacon Chain.
## Building the source
@ -247,9 +235,7 @@ running web servers, so malicious web pages could try to subvert locally availab
APIs!**
### Operating a private network
- [BSC-Deploy](https://github.com/bnb-chain/node-deploy/): deploy tool for setting up both BNB Beacon Chain, BNB Smart Chain and the cross chain infrastructure between them.
- [BSC-Docker](https://github.com/bnb-chain/bsc-docker): deploy tool for setting up local BSC cluster in container.
- [BSC-Deploy](https://github.com/bnb-chain/node-deploy/): deploy tool for setting up BNB Smart Chain.
## Running a bootnode

View File

@ -0,0 +1,87 @@
package fakebeacon
import (
"context"
"sort"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
type BlobSidecar struct {
Blob kzg4844.Blob `json:"blob"`
Index int `json:"index"`
KZGCommitment kzg4844.Commitment `json:"kzg_commitment"`
KZGProof kzg4844.Proof `json:"kzg_proof"`
}
type APIGetBlobSidecarsResponse struct {
Data []*BlobSidecar `json:"data"`
}
type ReducedGenesisData struct {
GenesisTime string `json:"genesis_time"`
}
type APIGenesisResponse struct {
Data ReducedGenesisData `json:"data"`
}
type ReducedConfigData struct {
SecondsPerSlot string `json:"SECONDS_PER_SLOT"`
}
type IndexedBlobHash struct {
Index int // absolute index in the block, a.k.a. position in sidecar blobs array
Hash common.Hash // hash of the blob, used for consistency checks
}
func configSpec() ReducedConfigData {
return ReducedConfigData{SecondsPerSlot: "1"}
}
func beaconGenesis() APIGenesisResponse {
return APIGenesisResponse{Data: ReducedGenesisData{GenesisTime: "0"}}
}
func beaconBlobSidecars(ctx context.Context, backend ethapi.Backend, slot uint64, indices []int) (APIGetBlobSidecarsResponse, error) {
var blockNrOrHash rpc.BlockNumberOrHash
header, err := fetchBlockNumberByTime(ctx, int64(slot), backend)
if err != nil {
log.Error("Error fetching block number", "slot", slot, "indices", indices)
return APIGetBlobSidecarsResponse{}, err
}
sideCars, err := backend.GetBlobSidecars(ctx, header.Hash())
if err != nil {
log.Error("Error fetching Sidecars", "blockNrOrHash", blockNrOrHash, "err", err)
return APIGetBlobSidecarsResponse{}, err
}
sort.Ints(indices)
fullBlob := len(indices) == 0
res := APIGetBlobSidecarsResponse{}
idx := 0
curIdx := 0
for _, sideCar := range sideCars {
for i := 0; i < len(sideCar.Blobs); i++ {
//hash := kZGToVersionedHash(sideCar.Commitments[i])
if !fullBlob && curIdx >= len(indices) {
break
}
if fullBlob || idx == indices[curIdx] {
res.Data = append(res.Data, &BlobSidecar{
Index: idx,
Blob: sideCar.Blobs[i],
KZGCommitment: sideCar.Commitments[i],
KZGProof: sideCar.Proofs[i],
})
curIdx++
}
idx++
}
}
return res, nil
}

View File

@ -0,0 +1,88 @@
package fakebeacon
import (
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/network/httputil"
)
var (
versionMethod = "/eth/v1/node/version"
specMethod = "/eth/v1/config/spec"
genesisMethod = "/eth/v1/beacon/genesis"
sidecarsMethodPrefix = "/eth/v1/beacon/blob_sidecars/{slot}"
)
func VersionMethod(w http.ResponseWriter, r *http.Request) {
resp := &structs.GetVersionResponse{
Data: &structs.Version{
Version: "",
},
}
httputil.WriteJson(w, resp)
}
func SpecMethod(w http.ResponseWriter, r *http.Request) {
httputil.WriteJson(w, &structs.GetSpecResponse{Data: configSpec()})
}
func GenesisMethod(w http.ResponseWriter, r *http.Request) {
httputil.WriteJson(w, beaconGenesis())
}
func (s *Service) SidecarsMethod(w http.ResponseWriter, r *http.Request) {
indices, err := parseIndices(r.URL)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
segments := strings.Split(r.URL.Path, "/")
slot, err := strconv.ParseUint(segments[len(segments)-1], 10, 64)
if err != nil {
httputil.HandleError(w, "not a valid slot(timestamp)", http.StatusBadRequest)
return
}
resp, err := beaconBlobSidecars(r.Context(), s.backend, slot, indices)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
httputil.WriteJson(w, resp)
}
// parseIndices filters out invalid and duplicate blob indices
func parseIndices(url *url.URL) ([]int, error) {
rawIndices := url.Query()["indices"]
indices := make([]int, 0, field_params.MaxBlobsPerBlock)
invalidIndices := make([]string, 0)
loop:
for _, raw := range rawIndices {
ix, err := strconv.Atoi(raw)
if err != nil {
invalidIndices = append(invalidIndices, raw)
continue
}
if ix >= field_params.MaxBlobsPerBlock {
invalidIndices = append(invalidIndices, raw)
continue
}
for i := range indices {
if ix == indices[i] {
continue loop
}
}
indices = append(indices, ix)
}
if len(invalidIndices) > 0 {
return nil, fmt.Errorf("requested blob indices %v are invalid", invalidIndices)
}
return indices, nil
}

View File

@ -0,0 +1,97 @@
package fakebeacon
import (
"net/http"
"strconv"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/gorilla/mux"
"github.com/prysmaticlabs/prysm/v5/api/server"
)
const (
DefaultAddr = "localhost"
DefaultPort = 8686
)
type Config struct {
Enable bool
Addr string
Port int
}
func defaultConfig() *Config {
return &Config{
Enable: false,
Addr: DefaultAddr,
Port: DefaultPort,
}
}
type Service struct {
cfg *Config
router *mux.Router
backend ethapi.Backend
}
func NewService(cfg *Config, backend ethapi.Backend) *Service {
cfgs := defaultConfig()
if cfg.Addr != "" {
cfgs.Addr = cfg.Addr
}
if cfg.Port > 0 {
cfgs.Port = cfg.Port
}
s := &Service{
cfg: cfgs,
backend: backend,
}
router := s.newRouter()
s.router = router
return s
}
func (s *Service) Run() {
_ = http.ListenAndServe(s.cfg.Addr+":"+strconv.Itoa(s.cfg.Port), s.router)
}
func (s *Service) newRouter() *mux.Router {
r := mux.NewRouter()
r.Use(server.NormalizeQueryValuesHandler)
for _, e := range s.endpoints() {
r.HandleFunc(e.path, e.handler).Methods(e.methods...)
}
return r
}
type endpoint struct {
path string
handler http.HandlerFunc
methods []string
}
func (s *Service) endpoints() []endpoint {
return []endpoint{
{
path: versionMethod,
handler: VersionMethod,
methods: []string{http.MethodGet},
},
{
path: specMethod,
handler: SpecMethod,
methods: []string{http.MethodGet},
},
{
path: genesisMethod,
handler: GenesisMethod,
methods: []string{http.MethodGet},
},
{
path: sidecarsMethodPrefix,
handler: s.SidecarsMethod,
methods: []string{http.MethodGet},
},
}
}

View File

@ -0,0 +1,90 @@
package fakebeacon
import (
"context"
"fmt"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
)
//
//func TestFetchBlockNumberByTime(t *testing.T) {
// blockNum, err := fetchBlockNumberByTime(context.Background(), 1724052941, client)
// assert.Nil(t, err)
// assert.Equal(t, uint64(41493946), blockNum)
//
// blockNum, err = fetchBlockNumberByTime(context.Background(), 1734052941, client)
// assert.Equal(t, err, errors.New("time too large"))
//
// blockNum, err = fetchBlockNumberByTime(context.Background(), 1600153618, client)
// assert.Nil(t, err)
// assert.Equal(t, uint64(493946), blockNum)
//}
//
//func TestBeaconBlobSidecars(t *testing.T) {
// indexBlobHash := []IndexedBlobHash{
// {Hash: common.HexToHash("0x01231952ecbaede62f8d0398b656072c072db36982c9ef106fbbc39ce14f983c"), Index: 0},
// {Hash: common.HexToHash("0x012c21a8284d2d707bb5318e874d2e1b97a53d028e96abb702b284a2cbb0f79c"), Index: 1},
// {Hash: common.HexToHash("0x011196c8d02536ede0382aa6e9fdba6c460169c0711b5f97fcd701bd8997aee3"), Index: 2},
// {Hash: common.HexToHash("0x019c86b46b27401fb978fd175d1eb7dadf4976d6919501b0c5280d13a5bab57b"), Index: 3},
// {Hash: common.HexToHash("0x01e00db7ee99176b3fd50aab45b4fae953292334bbf013707aac58c455d98596"), Index: 4},
// {Hash: common.HexToHash("0x0117d23b68123d578a98b3e1aa029661e0abda821a98444c21992eb1e5b7208f"), Index: 5},
// //{Hash: common.HexToHash("0x01e00db7ee99176b3fd50aab45b4fae953292334bbf013707aac58c455d98596"), Index: 1},
// }
//
// resp, err := beaconBlobSidecars(context.Background(), 1724055046, []int{0, 1, 2, 3, 4, 5}) // block: 41494647
// assert.Nil(t, err)
// assert.NotNil(t, resp)
// assert.NotEmpty(t, resp.Data)
// for i, sideCar := range resp.Data {
// assert.Equal(t, indexBlobHash[i].Index, sideCar.Index)
// assert.Equal(t, indexBlobHash[i].Hash, kZGToVersionedHash(sideCar.KZGCommitment))
// }
//
// apiscs := make([]*BlobSidecar, 0, len(indexBlobHash))
// // filter and order by hashes
// for _, h := range indexBlobHash {
// for _, apisc := range resp.Data {
// if h.Index == int(apisc.Index) {
// apiscs = append(apiscs, apisc)
// break
// }
// }
// }
//
// assert.Equal(t, len(apiscs), len(resp.Data))
// assert.Equal(t, len(apiscs), len(indexBlobHash))
//}
type TimeToSlotFn func(timestamp uint64) (uint64, error)
// GetTimeToSlotFn returns a function that converts a timestamp to a slot number.
func GetTimeToSlotFn(ctx context.Context) (TimeToSlotFn, error) {
genesis := beaconGenesis()
config := configSpec()
genesisTime, _ := strconv.ParseUint(genesis.Data.GenesisTime, 10, 64)
secondsPerSlot, _ := strconv.ParseUint(config.SecondsPerSlot, 10, 64)
if secondsPerSlot == 0 {
return nil, fmt.Errorf("got bad value for seconds per slot: %v", config.SecondsPerSlot)
}
timeToSlotFn := func(timestamp uint64) (uint64, error) {
if timestamp < genesisTime {
return 0, fmt.Errorf("provided timestamp (%v) precedes genesis time (%v)", timestamp, genesisTime)
}
return (timestamp - genesisTime) / secondsPerSlot, nil
}
return timeToSlotFn, nil
}
func TestAPI(t *testing.T) {
slotFn, err := GetTimeToSlotFn(context.Background())
assert.Nil(t, err)
expTx := uint64(123151345)
gotTx, err := slotFn(expTx)
assert.Nil(t, err)
assert.Equal(t, expTx, gotTx)
}

View File

@ -0,0 +1,65 @@
package fakebeacon
import (
"context"
"errors"
"fmt"
"math/rand"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/rpc"
)
func fetchBlockNumberByTime(ctx context.Context, ts int64, backend ethapi.Backend) (*types.Header, error) {
// calc the block number of the ts.
currentHeader := backend.CurrentHeader()
blockTime := int64(currentHeader.Time)
if ts > blockTime {
return nil, errors.New("time too large")
}
blockNum := currentHeader.Number.Uint64()
estimateEndNumber := int64(blockNum) - (blockTime-ts)/3
// find the end number
for {
header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(estimateEndNumber))
if err != nil {
time.Sleep(time.Duration(rand.Int()%180) * time.Millisecond)
continue
}
if header == nil {
estimateEndNumber -= 1
time.Sleep(time.Duration(rand.Int()%180) * time.Millisecond)
continue
}
headerTime := int64(header.Time)
if headerTime == ts {
return header, nil
}
// let the estimateEndNumber a little bigger than real value
if headerTime > ts+8 {
estimateEndNumber -= (headerTime - ts) / 3
} else if headerTime < ts {
estimateEndNumber += (ts-headerTime)/3 + 1
} else {
// search one by one
for headerTime >= ts {
header, err = backend.HeaderByNumber(ctx, rpc.BlockNumber(estimateEndNumber-1))
if err != nil {
time.Sleep(time.Duration(rand.Int()%180) * time.Millisecond)
continue
}
headerTime = int64(header.Time)
if headerTime == ts {
return header, nil
}
estimateEndNumber -= 1
if headerTime < ts { //found the real endNumber
return nil, fmt.Errorf("block not found by time %d", ts)
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,23 @@
# 1.Background
This is to support some projects with customized tokens that they want to integrate into the BSC faucet tool.
## 1.1. How to Integrate Your Token
- Step 1: Fund the faucet address by sending a specific amount of your BEP-20 token to the faucet address (0xaa25aa7a19f9c426e07dee59b12f944f4d9f1dd3) on the BSC testnet.
- Step 2: Update this README.md file and create a Pull Request on [bsc github](https://github.com/bnb-chain/bsc) with relevant information.
We will review the request, and once it is approved, the faucet tool will start to support the customized token and list it on https://www.bnbchain.org/en/testnet-faucet.
# 2.Token List
## 2.1.DemoToken
- symbol: DEMO
- amount: 10000000000000000000
- icon: ./demotoken.png
- addr: https://testnet.bscscan.com/address/0xe15c158d768c306dae87b96430a94f884333e55d
- fundTx: [0xa499dc9aaf918aff0507538a8aa80a88d0af6ca15054e6acc57b69c651945280](https://testnet.bscscan.com/tx/0x2a3f334b6ca756b64331bdec9e6cf3207ac50a4839fda6379e909de4d9a194ca)
-
## 2.2.DIN token
- symbol: DIN
- amount: 10000000000000000000
- icon: ./DIN.png
- addr: https://testnet.bscscan.com/address/0xb8b40FcC5B4519Dba0E07Ac8821884CE90BdE677
- fundTx: [0x17fc4c1db133830c7c146a0d41ca1df31cb446989ec11b382d58bb6176d6fde3](https://testnet.bscscan.com/tx/0x17fc4c1db133830c7c146a0d41ca1df31cb446989ec11b382d58bb6176d6fde3)

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -53,9 +53,10 @@ import (
)
var (
genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with")
apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection")
wsEndpoint = flag.String("ws", "http://127.0.0.1:7777/", "Url to ws endpoint")
genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with")
apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection")
wsEndpoint = flag.String("ws", "http://127.0.0.1:7777/", "Url to ws endpoint")
wsEndpointMainnet = flag.String("ws.mainnet", "", "Url to ws endpoint of BSC mainnet")
netnameFlag = flag.String("faucet.name", "", "Network name to assign to the faucet")
payoutFlag = flag.Int("faucet.amount", 1, "Number of Ethers to pay out per user request")
@ -77,6 +78,12 @@ var (
fixGasPrice = flag.Int64("faucet.fixedprice", 0, "Will use fixed gas price if specified")
twitterTokenFlag = flag.String("twitter.token", "", "Bearer token to authenticate with the v2 Twitter API")
twitterTokenV1Flag = flag.String("twitter.token.v1", "", "Bearer token to authenticate with the v1.1 Twitter API")
resendInterval = 15 * time.Second
resendBatchSize = 3
resendMaxGasPrice = big.NewInt(50 * params.GWei)
wsReadTimeout = 5 * time.Minute
minMainnetBalance = big.NewInt(2 * 1e6 * params.GWei) // 0.002 bnb
)
var (
@ -87,11 +94,17 @@ var (
//go:embed faucet.html
var websiteTmpl string
func weiToEtherStringFx(wei *big.Int, prec int) string {
etherValue := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether))
// Format the big.Float directly to a string with the specified precision
return etherValue.Text('f', prec)
}
func main() {
// Parse the flags and set up the logger to print everything requested
flag.Parse()
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), true)))
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), false)))
log.Info("faucet started")
// Construct the payout tiers
amounts := make([]string, *tiersFlag)
for i := 0; i < *tiersFlag; i++ {
@ -170,7 +183,7 @@ func main() {
log.Crit("Failed to unlock faucet signer account", "err", err)
}
// Assemble and start the faucet light service
faucet, err := newFaucet(genesis, *wsEndpoint, ks, website.Bytes(), bep2eInfos)
faucet, err := newFaucet(genesis, *wsEndpoint, *wsEndpointMainnet, ks, website.Bytes(), bep2eInfos)
if err != nil {
log.Crit("Failed to start faucet", "err", err)
}
@ -197,9 +210,10 @@ type bep2eInfo struct {
// faucet represents a crypto faucet backed by an Ethereum light client.
type faucet struct {
config *params.ChainConfig // Chain configurations for signing
client *ethclient.Client // Client connection to the Ethereum chain
index []byte // Index page to serve up on the web
config *params.ChainConfig // Chain configurations for signing
client *ethclient.Client // Client connection to the Ethereum chain
clientMainnet *ethclient.Client // Client connection to BSC mainnet for balance check
index []byte // Index page to serve up on the web
keystore *keystore.KeyStore // Keystore containing the single signer
account accounts.Account // Account funding user faucet requests
@ -228,7 +242,7 @@ type wsConn struct {
wlock sync.Mutex
}
func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson))
if err != nil {
return nil, err
@ -237,6 +251,11 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [
if err != nil {
return nil, err
}
clientMainnet, err := ethclient.Dial(mainnetUrl)
if err != nil {
// skip mainnet balance check if it there is no available mainnet endpoint
log.Warn("dail mainnet endpoint failed", "mainnetUrl", mainnetUrl, "err", err)
}
// Allow 1 request per minute with burst of 5, and cache up to 1000 IPs
limiter, err := NewIPRateLimiter(rate.Limit(1.0), 5, 1000)
@ -245,16 +264,17 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [
}
return &faucet{
config: genesis.Config,
client: client,
index: index,
keystore: ks,
account: ks.Accounts()[0],
timeouts: make(map[string]time.Time),
update: make(chan struct{}, 1),
bep2eInfos: bep2eInfos,
bep2eAbi: bep2eAbi,
limiter: limiter,
config: genesis.Config,
client: client,
clientMainnet: clientMainnet,
index: index,
keystore: ks,
account: ks.Accounts()[0],
timeouts: make(map[string]time.Time),
update: make(chan struct{}, 1),
bep2eInfos: bep2eInfos,
bep2eAbi: bep2eAbi,
limiter: limiter,
}, nil
}
@ -378,7 +398,11 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
Captcha string `json:"captcha"`
Symbol string `json:"symbol"`
}
// not sure if it helps or not, but set a read deadline could help prevent resource leakage
// if user did not give response for too long, then the routine will be stuck.
conn.SetReadDeadline(time.Now().Add(wsReadTimeout))
if err = conn.ReadJSON(&msg); err != nil {
log.Debug("read json message failed", "err", err, "ip", ip)
return
}
if !*noauthFlag && !strings.HasPrefix(msg.URL, "https://twitter.com/") && !strings.HasPrefix(msg.URL, "https://www.facebook.com/") {
@ -396,9 +420,9 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
}
continue
}
log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier)
log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier, "ip", ip)
// If captcha verifications are enabled, make sure we're not dealing with a robot
// check #1: captcha verifications to exclude robot
if *captchaToken != "" {
form := url.Values{}
form.Add("secret", *captchaSecret)
@ -475,88 +499,108 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
}
continue
}
log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address)
// Ensure the user didn't request funds too recently
// check #2: check IP and ID(address) to ensure the user didn't request funds too frequently
f.lock.Lock()
var (
fund bool
timeout time.Time
)
if ipTimeout := f.timeouts[ips[len(ips)-2]]; time.Now().Before(ipTimeout) {
f.lock.Unlock()
if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(ipTimeout)))); err != nil { // nolint: gosimple
log.Warn("Failed to send funding error to client", "err", err)
return
}
f.lock.Unlock()
log.Info("too frequent funding(ip)", "TimeLeft", common.PrettyDuration(time.Until(ipTimeout)), "ip", ips[len(ips)-2], "ipsStr", ipsStr)
continue
}
if timeout = f.timeouts[id]; time.Now().After(timeout) {
var tx *types.Transaction
if msg.Symbol == "BNB" {
// User wasn't funded recently, create the funding transaction
amount := new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether), big.NewInt(10))
amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil))
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
} else {
tokenInfo, ok := f.bep2eInfos[msg.Symbol]
if !ok {
f.lock.Unlock()
log.Warn("Failed to find symbol", "symbol", msg.Symbol)
continue
}
input, err := f.bep2eAbi.Pack("transfer", address, &tokenInfo.Amount)
if err != nil {
f.lock.Unlock()
log.Warn("Failed to pack transfer transaction", "err", err)
continue
}
tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), tokenInfo.Contract, nil, 420000, f.price, input)
if idTimeout := f.timeouts[id]; time.Now().Before(idTimeout) {
f.lock.Unlock()
// Send an error if too frequent funding, otherwise a success
if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(idTimeout)))); err != nil { // nolint: gosimple
log.Warn("Failed to send funding error to client", "err", err)
return
}
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
log.Info("too frequent funding(id)", "TimeLeft", common.PrettyDuration(time.Until(idTimeout)), "id", id)
continue
}
// check #3: minimum mainnet balance check, internal error will bypass the check to avoid blocking the faucet service
if f.clientMainnet != nil {
mainnetAddr := address
balanceMainnet, err := f.clientMainnet.BalanceAt(context.Background(), mainnetAddr, nil)
if err != nil {
log.Warn("check balance failed, call BalanceAt", "err", err)
} else if balanceMainnet == nil {
log.Warn("check balance failed, balanceMainnet is nil")
} else {
if balanceMainnet.Cmp(minMainnetBalance) < 0 {
f.lock.Unlock()
log.Warn("insufficient BNB on BSC mainnet", "address", mainnetAddr,
"balanceMainnet", balanceMainnet, "minMainnetBalance", minMainnetBalance)
// Send an error if failed to meet the minimum balance requirement
if err = sendError(wsconn, fmt.Errorf("insufficient BNB on BSC mainnet (require >=%sBNB)",
weiToEtherStringFx(minMainnetBalance, 3))); err != nil {
log.Warn("Failed to send mainnet minimum balance error to client", "err", err)
return
}
continue
}
}
}
log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address, "ip", ip)
// now, it is ok to send tBNB or other tokens
var tx *types.Transaction
if msg.Symbol == "BNB" {
// User wasn't funded recently, create the funding transaction
amount := new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether), big.NewInt(10))
amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil))
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
} else {
tokenInfo, ok := f.bep2eInfos[msg.Symbol]
if !ok {
f.lock.Unlock()
log.Warn("Failed to find symbol", "symbol", msg.Symbol)
continue
}
input, err := f.bep2eAbi.Pack("transfer", address, &tokenInfo.Amount)
if err != nil {
f.lock.Unlock()
if err = sendError(wsconn, err); err != nil {
log.Warn("Failed to send transaction creation error to client", "err", err)
return
}
log.Warn("Failed to pack transfer transaction", "err", err)
continue
}
// Submit the transaction and mark as funded if successful
if err := f.client.SendTransaction(context.Background(), signed); err != nil {
f.lock.Unlock()
if err = sendError(wsconn, err); err != nil {
log.Warn("Failed to send transaction transmission error to client", "err", err)
return
}
continue
}
f.reqs = append(f.reqs, &request{
Avatar: avatar,
Account: address,
Time: time.Now(),
Tx: signed,
})
timeout := time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute
grace := timeout / 288 // 24h timeout => 5m grace
f.timeouts[id] = time.Now().Add(timeout - grace)
f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeout - grace)
fund = true
tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), tokenInfo.Contract, nil, 420000, f.price, input)
}
f.lock.Unlock()
// Send an error if too frequent funding, otherwise a success
if !fund {
if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(timeout)))); err != nil { // nolint: gosimple
log.Warn("Failed to send funding error to client", "err", err)
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
if err != nil {
f.lock.Unlock()
if err = sendError(wsconn, err); err != nil {
log.Warn("Failed to send transaction creation error to client", "err", err)
return
}
continue
}
// Submit the transaction and mark as funded if successful
if err := f.client.SendTransaction(context.Background(), signed); err != nil {
f.lock.Unlock()
if err = sendError(wsconn, err); err != nil {
log.Warn("Failed to send transaction transmission error to client", "err", err)
return
}
continue
}
f.reqs = append(f.reqs, &request{
Avatar: avatar,
Account: address,
Time: time.Now(),
Tx: signed,
})
timeoutInt64 := time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute
grace := timeoutInt64 / 288 // 24h timeout => 5m grace
f.timeouts[id] = time.Now().Add(timeoutInt64 - grace)
f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeoutInt64 - grace)
f.lock.Unlock()
if err = sendSuccess(wsconn, fmt.Sprintf("Funding request accepted for %s into %s", username, address.Hex())); err != nil {
log.Warn("Failed to send funding success to client", "err", err)
return
@ -605,9 +649,52 @@ func (f *faucet) refresh(head *types.Header) error {
f.lock.Lock()
f.head, f.balance = head, balance
f.price, f.nonce = price, nonce
if len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() > f.nonce {
if len(f.reqs) == 0 {
log.Debug("refresh len(f.reqs) == 0", "f.nonce", f.nonce)
f.lock.Unlock()
return nil
}
if f.reqs[0].Tx.Nonce() == f.nonce {
// if the next Tx failed to be included for a certain time(resendInterval), try to
// resend it with higher gasPrice, as it could be discarded in the network.
// Also resend extra following txs, as they could be discarded as well.
if time.Now().After(f.reqs[0].Time.Add(resendInterval)) {
for i, req := range f.reqs {
if i >= resendBatchSize {
break
}
prePrice := req.Tx.GasPrice()
// bump gas price 20% to replace the previous tx
newPrice := new(big.Int).Add(prePrice, new(big.Int).Div(prePrice, big.NewInt(5)))
if newPrice.Cmp(resendMaxGasPrice) >= 0 {
log.Info("resendMaxGasPrice reached", "newPrice", newPrice, "resendMaxGasPrice", resendMaxGasPrice, "nonce", req.Tx.Nonce())
break
}
newTx := types.NewTransaction(req.Tx.Nonce(), *req.Tx.To(), req.Tx.Value(), req.Tx.Gas(), newPrice, req.Tx.Data())
newSigned, err := f.keystore.SignTx(f.account, newTx, f.config.ChainID)
if err != nil {
log.Error("resend sign tx failed", "err", err)
}
log.Info("reqs[0] Tx has been stuck for a while, trigger resend",
"resendInterval", resendInterval, "resendTxSize", resendBatchSize,
"preHash", req.Tx.Hash().Hex(), "newHash", newSigned.Hash().Hex(),
"newPrice", newPrice, "nonce", req.Tx.Nonce(), "req.Tx.Gas()", req.Tx.Gas())
if err := f.client.SendTransaction(context.Background(), newSigned); err != nil {
log.Warn("resend tx failed", "err", err)
continue
}
req.Tx = newSigned
}
}
}
// it is abnormal that reqs[0] has larger nonce than next expected nonce.
// could be caused by reorg? reset it
if f.reqs[0].Tx.Nonce() > f.nonce {
log.Warn("reset due to nonce gap", "f.nonce", f.nonce, "f.reqs[0].Tx.Nonce()", f.reqs[0].Tx.Nonce())
f.reqs = f.reqs[:0]
}
// remove the reqs if they have smaller nonce, which means it is no longer valid,
// either has been accepted or replaced.
for len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() < f.nonce {
f.reqs = f.reqs[1:]
}

View File

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/beacon/fakebeacon"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
@ -92,10 +93,11 @@ type ethstatsConfig struct {
}
type gethConfig struct {
Eth ethconfig.Config
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
Eth ethconfig.Config
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
FakeBeacon fakebeacon.Config
}
func loadConfig(file string, cfg *gethConfig) error {
@ -242,11 +244,22 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL)
}
if ctx.IsSet(utils.FakeBeaconAddrFlag.Name) {
cfg.FakeBeacon.Addr = ctx.String(utils.FakeBeaconAddrFlag.Name)
}
if ctx.IsSet(utils.FakeBeaconPortFlag.Name) {
cfg.FakeBeacon.Port = ctx.Int(utils.FakeBeaconPortFlag.Name)
}
if cfg.FakeBeacon.Enable || ctx.IsSet(utils.FakeBeaconEnabledFlag.Name) {
go fakebeacon.NewService(&cfg.FakeBeacon, backend).Run()
}
git, _ := version.VCS()
utils.SetupMetrics(ctx,
utils.EnableBuildInfo(git.Commit, git.Date),
utils.EnableMinerInfo(ctx, &cfg.Eth.Miner),
utils.EnableNodeInfo(&cfg.Eth.TxPool, stack.Server().NodeInfo()),
utils.EnableNodeTrack(ctx, &cfg.Eth, stack),
)
return stack, backend
}

View File

@ -232,6 +232,12 @@ var (
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
}
fakeBeaconFlags = []cli.Flag{
utils.FakeBeaconEnabledFlag,
utils.FakeBeaconAddrFlag,
utils.FakeBeaconPortFlag,
}
)
var app = flags.NewApp("the go-ethereum command line interface")
@ -286,6 +292,7 @@ func init() {
consoleFlags,
debug.Flags,
metricsFlags,
fakeBeaconFlags,
)
flags.AutoEnvVars(app.Flags, "GETH")
@ -371,8 +378,6 @@ func geth(ctx *cli.Context) error {
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isConsole bool) {
debug.Memsize.Add("node", stack)
// Start up the node itself
utils.StartNode(ctx, stack, isConsole)
@ -445,22 +450,23 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
}
// Start auxiliary services if enabled
ethBackend, ok := backend.(*eth.EthAPIBackend)
gasCeil := ethBackend.Miner().GasCeil()
if gasCeil > params.SystemTxsGas {
ethBackend.TxPool().SetMaxGas(gasCeil - params.SystemTxsGas)
}
if ctx.Bool(utils.MiningEnabledFlag.Name) {
// Mining only makes sense if a full Ethereum node is running
if ctx.String(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
ethBackend, ok := backend.(*eth.EthAPIBackend)
if !ok {
utils.Fatalf("Ethereum service not running")
}
// Set the gas price to the limits from the CLI and start mining
gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
ethBackend.TxPool().SetGasTip(gasprice)
gasCeil := ethBackend.Miner().GasCeil()
if gasCeil > params.SystemTxsGas {
ethBackend.TxPool().SetMaxGas(gasCeil - params.SystemTxsGas)
}
if err := ethBackend.StartMining(); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}

View File

@ -35,8 +35,11 @@ import (
"strings"
"time"
"github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/beacon/fakebeacon"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/core"
@ -1146,6 +1149,25 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: params.DefaultExtraReserveForBlobRequests,
Category: flags.MiscCategory,
}
// Fake beacon
FakeBeaconEnabledFlag = &cli.BoolFlag{
Name: "fake-beacon",
Usage: "Enable the HTTP-RPC server of fake-beacon",
Category: flags.APICategory,
}
FakeBeaconAddrFlag = &cli.StringFlag{
Name: "fake-beacon.addr",
Usage: "HTTP-RPC server listening addr of fake-beacon",
Value: fakebeacon.DefaultAddr,
Category: flags.APICategory,
}
FakeBeaconPortFlag = &cli.IntFlag{
Name: "fake-beacon.port",
Usage: "HTTP-RPC server listening port of fake-beacon",
Value: fakebeacon.DefaultPort,
Category: flags.APICategory,
}
)
var (
@ -2297,6 +2319,67 @@ func EnableNodeInfo(poolConfig *legacypool.Config, nodeInfo *p2p.NodeInfo) Setup
}
}
func EnableNodeTrack(ctx *cli.Context, cfg *ethconfig.Config, stack *node.Node) SetupMetricsOption {
nodeInfo := stack.Server().NodeInfo()
return func() {
// register node info into metrics
metrics.NewRegisteredLabel("node-stats", nil).Mark(map[string]interface{}{
"NodeType": parseNodeType(),
"ENR": nodeInfo.ENR,
"Mining": ctx.Bool(MiningEnabledFlag.Name),
"Etherbase": parseEtherbase(cfg),
"MiningFeatures": parseMiningFeatures(ctx, cfg),
"DBFeatures": parseDBFeatures(cfg, stack),
})
}
}
func parseEtherbase(cfg *ethconfig.Config) string {
if cfg.Miner.Etherbase == (common.Address{}) {
return ""
}
return cfg.Miner.Etherbase.String()
}
func parseNodeType() string {
git, _ := version.VCS()
version := []string{params.VersionWithMeta}
if len(git.Commit) >= 7 {
version = append(version, git.Commit[:7])
}
if git.Date != "" {
version = append(version, git.Date)
}
arch := []string{runtime.GOOS, runtime.GOARCH}
infos := []string{"BSC", strings.Join(version, "-"), strings.Join(arch, "-"), runtime.Version()}
return strings.Join(infos, "/")
}
func parseDBFeatures(cfg *ethconfig.Config, stack *node.Node) string {
var features []string
if cfg.StateScheme == rawdb.PathScheme {
features = append(features, "PBSS")
}
if stack.CheckIfMultiDataBase() {
features = append(features, "MultiDB")
}
return strings.Join(features, "|")
}
func parseMiningFeatures(ctx *cli.Context, cfg *ethconfig.Config) string {
if !ctx.Bool(MiningEnabledFlag.Name) {
return ""
}
var features []string
if cfg.Miner.Mev.Enabled {
features = append(features, "MEV")
}
if cfg.Miner.VoteEnable {
features = append(features, "FFVoting")
}
return strings.Join(features, "|")
}
func SetupMetrics(ctx *cli.Context, options ...SetupMetricsOption) {
if metrics.Enabled {
log.Info("Enabling metrics collection")

View File

@ -68,7 +68,6 @@ const (
wiggleTime = uint64(1) // second, Random delay (per signer) to allow concurrent signers
initialBackOffTime = uint64(1) // second
processBackOffTime = uint64(1) // second
systemRewardPercent = 4 // it means 1/2^4 = 1/16 percentage of gas fee incoming will be distributed to system
@ -1616,12 +1615,15 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
if p.shouldWaitForCurrentBlockProcess(chain, header, snap) {
log.Info("Waiting for received in turn block to process")
highestVerifiedHeader := chain.GetHighestVerifiedHeader()
// including time for writing and committing blocks
waitProcessEstimate := math.Ceil(float64(highestVerifiedHeader.GasUsed) / float64(100_000_000))
log.Info("Waiting for received in turn block to process", "waitProcessEstimate(Seconds)", waitProcessEstimate)
select {
case <-stop:
log.Info("Received block process finished, abort block seal")
return
case <-time.After(time.Duration(processBackOffTime) * time.Second):
case <-time.After(time.Duration(waitProcessEstimate) * time.Second):
if chain.CurrentHeader().Number.Uint64() >= header.Number.Uint64() {
log.Info("Process backoff time exhausted, and current header has updated to abort this seal")
return

View File

@ -66,31 +66,6 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
return validator
}
// ValidateListsInBody validates that UncleHash, WithdrawalsHash, and WithdrawalsHash correspond to the lists in the block body, respectively.
func ValidateListsInBody(block *types.Block) error {
header := block.Header()
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
}
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
}
// Withdrawals are present after the Shanghai fork.
if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai.
if block.Withdrawals() == nil {
return errors.New("missing withdrawals in block body")
}
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
}
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
// Withdrawals are not allowed prior to shanghai fork
return errors.New("withdrawals present in block body")
}
return nil
}
// ValidateBody validates the given block's uncles and verifies the block
// header's transaction and uncle roots. The headers are assumed to be already
// validated at this point.
@ -108,12 +83,31 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
return err
}
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
}
validateFuns := []func() error{
func() error {
return ValidateListsInBody(block)
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
}
return nil
},
func() error {
// Withdrawals are present after the Shanghai fork.
if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai.
if block.Withdrawals() == nil {
return errors.New("missing withdrawals in block body")
}
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
}
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
// Withdrawals are not allowed prior to shanghai fork
return errors.New("withdrawals present in block body")
}
// Blob transactions may be present after the Cancun fork.
var blobs int
for i, tx := range block.Transactions() {

View File

@ -100,6 +100,8 @@ var (
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
blockRecvTimeDiffGauge = metrics.NewRegisteredGauge("chain/block/recvtimediff", nil)
errStateRootVerificationFailed = errors.New("state root verification failed")
errInsertionInterrupted = errors.New("insertion is interrupted")
errChainStopped = errors.New("blockchain is stopped")
@ -2055,6 +2057,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
return 0, nil
}
if len(chain) > 0 {
blockRecvTimeDiffGauge.Update(time.Now().Unix() - int64(chain[0].Time()))
}
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
signer := types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time())
go SenderCacher.RecoverFromBlocks(signer, chain)

View File

@ -121,12 +121,19 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
if f.preserve != nil {
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
}
doubleSign := (extern.Coinbase == current.Coinbase)
reorg = !currentPreserve && (externPreserve ||
extern.Time < current.Time ||
extern.Time == current.Time &&
((doubleSign && extern.Hash().Cmp(current.Hash()) < 0) ||
(!doubleSign && f.rand.Float64() < 0.5)))
choiceRules := func() bool {
if extern.Time == current.Time {
doubleSign := (extern.Coinbase == current.Coinbase)
if doubleSign {
return extern.Hash().Cmp(current.Hash()) < 0
} else {
return f.rand.Float64() < 0.5
}
} else {
return extern.Time < current.Time
}
}
reorg = !currentPreserve && (externPreserve || choiceRules())
}
return reorg, nil
}

View File

@ -68,6 +68,7 @@ func newPrunedFreezer(datadir string, db ethdb.KeyValueStore, offset uint64) (*p
// repair init frozen , compatible disk-ancientdb and pruner-block-tool.
func (f *prunedfreezer) repair(datadir string) error {
offset := atomic.LoadUint64(&f.frozen)
// compatible freezer
minItems := uint64(math.MaxUint64)
for name, disableSnappy := range chainFreezerNoSnappy {
@ -96,19 +97,14 @@ func (f *prunedfreezer) repair(datadir string) error {
table.Close()
}
// If minItems is non-zero, it indicates that the chain freezer was previously enabled, and we should use minItems as the current frozen value.
// If minItems is zero, it indicates that the pruneAncient was previously enabled, and we should continue using frozen
// (retrieved from CurrentAncientFreezer) as the current frozen value.
offset := minItems
if offset == 0 {
// no item in ancientDB, init `offset` to the `f.frozen`
offset = atomic.LoadUint64(&f.frozen)
}
log.Info("Read ancientdb item counts", "items", minItems, "offset", offset)
// If the dataset has undergone a prune block, the offset is a non-zero value, otherwise the offset is a zero value.
// The minItems is the value relative to offset
offset += minItems
// FrozenOfAncientFreezer is the progress of the last prune-freezer freeze.
frozenInDB := ReadFrozenOfAncientFreezer(f.db)
maxOffset := max(offset, frozenInDB)
log.Info("Read ancient db item counts", "items", minItems, "frozen", maxOffset)
atomic.StoreUint64(&f.frozen, maxOffset)
if err := f.Sync(); err != nil {
@ -161,12 +157,12 @@ func (f *prunedfreezer) AncientOffSet() uint64 {
// MigrateTable processes the entries in a given table in sequence
// converting them to a new format if they're of an old format.
func (db *prunedfreezer) MigrateTable(kind string, convert convertLegacyFn) error {
func (f *prunedfreezer) MigrateTable(kind string, convert convertLegacyFn) error {
return errNotSupported
}
// AncientDatadir returns an error as we don't have a backing chain freezer.
func (db *prunedfreezer) AncientDatadir() (string, error) {
func (f *prunedfreezer) AncientDatadir() (string, error) {
return "", errNotSupported
}

View File

@ -2,10 +2,12 @@ package types
import (
"bytes"
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
)
@ -53,3 +55,40 @@ func (s *BlobSidecar) SanityCheck(blockNumber *big.Int, blockHash common.Hash) e
}
return nil
}
func (s *BlobSidecar) MarshalJSON() ([]byte, error) {
fields := map[string]interface{}{
"blockHash": s.BlockHash,
"blockNumber": hexutil.EncodeUint64(s.BlockNumber.Uint64()),
"txHash": s.TxHash,
"txIndex": hexutil.EncodeUint64(s.TxIndex),
}
fields["blobSidecar"] = s.BlobTxSidecar
return json.Marshal(fields)
}
func (s *BlobSidecar) UnmarshalJSON(input []byte) error {
type blobSidecar struct {
BlobSidecar BlobTxSidecar `json:"blobSidecar"`
BlockNumber *hexutil.Big `json:"blockNumber"`
BlockHash common.Hash `json:"blockHash"`
TxIndex *hexutil.Big `json:"txIndex"`
TxHash common.Hash `json:"txHash"`
}
var blob blobSidecar
if err := json.Unmarshal(input, &blob); err != nil {
return err
}
s.BlobTxSidecar = blob.BlobSidecar
if blob.BlockNumber == nil {
return errors.New("missing required field 'blockNumber' for BlobSidecar")
}
s.BlockNumber = blob.BlockNumber.ToInt()
s.BlockHash = blob.BlockHash
if blob.TxIndex == nil {
return errors.New("missing required field 'txIndex' for BlobSidecar")
}
s.TxIndex = blob.TxIndex.ToInt().Uint64()
s.TxHash = blob.TxHash
return nil
}

View File

@ -1,7 +1,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (

View File

@ -1,7 +1,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
// gfP2 implements a field of size p² as a quadratic extension of the base field

View File

@ -1,7 +1,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ

View File

@ -5,7 +5,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (

View File

@ -5,7 +5,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (

View File

@ -5,7 +5,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (

View File

@ -441,14 +441,14 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}
func (b *EthAPIBackend) CurrentTurnLength() (turnLength uint8, err error) {
func (b *EthAPIBackend) CurrentValidators() ([]common.Address, error) {
if p, ok := b.eth.engine.(*parlia.Parlia); ok {
service := p.APIs(b.Chain())[0].Service
currentHead := rpc.LatestBlockNumber
return service.(*parlia.API).GetTurnLength(&currentHead)
return service.(*parlia.API).GetValidators(&currentHead)
}
return 1, nil
return []common.Address{}, errors.New("not supported")
}
func (b *EthAPIBackend) CurrentHeader() *types.Header {

View File

@ -73,7 +73,7 @@ func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
// SetGasLimit sets the gaslimit to target towards during mining.
func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool {
api.e.Miner().SetGasCeil(uint64(gasLimit))
if api.e.Miner().Mining() && uint64(gasLimit) > params.SystemTxsGas {
if uint64(gasLimit) > params.SystemTxsGas {
api.e.TxPool().SetMaxGas(uint64(gasLimit) - params.SystemTxsGas)
}
return true

View File

@ -327,7 +327,7 @@ func (d *Downloader) UnregisterPeer(id string) error {
// LegacySync tries to sync up our local blockchain with a remote peer, both
// adding various sanity checks and wrapping it with various log entries.
func (d *Downloader) LegacySync(id string, head common.Hash, td *big.Int, ttd *big.Int, mode SyncMode) error {
func (d *Downloader) LegacySync(id string, head common.Hash, name string, td *big.Int, ttd *big.Int, mode SyncMode) error {
err := d.synchronise(id, head, td, ttd, mode, false, nil)
switch err {
@ -337,7 +337,7 @@ func (d *Downloader) LegacySync(id string, head common.Hash, td *big.Int, ttd *b
if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) ||
errors.Is(err, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) ||
errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) {
log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err)
log.Warn("Synchronisation failed, dropping peer", "peer", id, "name", name, "td", td, "err", err)
if d.dropPeer == nil {
// The dropPeer method is nil when `--copydb` is used for a local copy.
// Timeouts can occur if e.g. compaction hits at the wrong time, and can be ignored

View File

@ -902,7 +902,7 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol uint) {
// Simulate a synchronisation and check the required result
tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result }
tester.downloader.LegacySync(id, tester.chain.Genesis().Hash(), big.NewInt(1000), nil, FullSync)
tester.downloader.LegacySync(id, tester.chain.Genesis().Hash(), "", big.NewInt(1000), nil, FullSync)
if _, ok := tester.peers[id]; !ok != tt.drop {
t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop)
}

View File

@ -868,9 +868,9 @@ func (f *BlockFetcher) importHeaders(op *blockOrHeaderInject) {
parent := f.getHeader(header.ParentHash)
if parent == nil {
log.Debug("Unknown parent of propagated header", "peer", peer, "number", header.Number, "hash", hash, "parent", header.ParentHash)
time.Sleep(reQueueBlockTimeout)
// forget block first, then re-queue
f.done <- hash
time.Sleep(reQueueBlockTimeout)
f.requeue <- op
return
}
@ -909,9 +909,9 @@ func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) {
parent := f.getBlock(block.ParentHash())
if parent == nil {
log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
time.Sleep(reQueueBlockTimeout)
// forget block first, then re-queue
f.done <- hash
time.Sleep(reQueueBlockTimeout)
f.requeue <- op
return
}

View File

@ -321,21 +321,14 @@ func newHandler(config *handlerConfig) (*handler, error) {
broadcastBlockWithCheck := func(block *types.Block, propagate bool) {
if propagate {
checkErrs := make(chan error, 2)
go func() {
checkErrs <- core.ValidateListsInBody(block)
}()
go func() {
checkErrs <- core.IsDataAvailable(h.chain, block)
}()
for i := 0; i < cap(checkErrs); i++ {
err := <-checkErrs
if err != nil {
log.Error("Propagating invalid block", "number", block.Number(), "hash", block.Hash(), "err", err)
return
}
if !(block.Header().WithdrawalsHash == nil && block.Withdrawals() == nil) &&
!(block.Header().EmptyWithdrawalsHash() && block.Withdrawals() != nil && len(block.Withdrawals()) == 0) {
log.Error("Propagated block has invalid withdrawals")
return
}
if err := core.IsDataAvailable(h.chain, block); err != nil {
log.Error("Propagating block with invalid sidecars", "number", block.Number(), "hash", block.Hash(), "err", err)
return
}
}
h.BroadcastBlock(block, propagate)
@ -369,7 +362,6 @@ func newHandler(config *handlerConfig) (*handler, error) {
}
h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, addTxs, fetchTx, h.removePeer)
h.chainSync = newChainSyncer(h)
h.printPeerStatus()
return h, nil
}
@ -484,13 +476,13 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
h.peersPerIP[remoteIP] = h.peersPerIP[remoteIP] + 1
h.peerPerIPLock.Unlock()
}
peer.Log().Debug("Ethereum peer connected", "name", peer.Name())
// Register the peer locally
if err := h.peers.registerPeer(peer, snap, trust, bsc); err != nil {
peer.Log().Error("Ethereum peer registration failed", "err", err)
return err
}
peer.Log().Debug("Ethereum peer connected", "name", peer.Name(), "peers.len", h.peers.len())
defer h.unregisterPeer(peer.ID())
p := h.peers.peer(peer.ID())
@ -633,7 +625,7 @@ func (h *handler) runBscExtension(peer *bsc.Peer, handler bsc.Handler) error {
bsc.EgressRegistrationErrorMeter.Mark(1)
}
}
peer.Log().Error("Bsc extension registration failed", "err", err)
peer.Log().Error("Bsc extension registration failed", "err", err, "name", peer.Name())
return err
}
return handler(peer)
@ -1018,67 +1010,3 @@ func (h *handler) enableSyncedFeatures() {
// h.chain.TrieDB().SetBufferSize(pathdb.DefaultBufferSize)
// }
}
type PeerDummy struct {
ID string
Head common.Hash
TD *big.Int
TimeStamp time.Time
}
func (h *handler) printPeerStatus() {
go func() {
statusMap := make(map[string]PeerDummy)
for {
// run in timer very 1 minue of time
time.Sleep(1 * time.Minute)
// Create a set to track current peers
currentPeers := make(map[string]struct{})
// print peer status
h.peers.lock.RLock()
for _, peer := range h.peers.peers {
currentPeers[peer.Peer.ID()] = struct{}{}
head, td := peer.Peer.Head()
if p, ok := statusMap[peer.Peer.ID()]; ok {
if p.Head == head && p.TD.Cmp(td) == 0 {
continue
}
p.Head = head
p.TD = td
p.TimeStamp = time.Now()
statusMap[peer.Peer.ID()] = p
} else {
statusMap[peer.Peer.ID()] = PeerDummy{
ID: peer.Peer.ID(),
Head: head,
TD: td,
TimeStamp: time.Now(),
}
}
}
h.peers.lock.RUnlock()
// Remove peers from statusMap that are no longer in h.peers.peers
for id := range statusMap {
if _, exists := currentPeers[id]; !exists {
delete(statusMap, id)
}
}
var count int
for _, peer := range statusMap {
if peer.TimeStamp.Before(time.Now().Add(-60 * time.Minute)) {
count++
if count == 1 {
log.Warn("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
}
log.Warn("peer", peer.ID, "head", peer.Head, "TD", peer.TD, "TimeStamp", peer.TimeStamp)
}
}
if count > 0 {
log.Warn("Total peers: ", len(statusMap), "inactive peers: ", count)
log.Warn("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
}
}
}()
}

View File

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/forkid"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
@ -46,7 +47,7 @@ var ProtocolVersions = []uint{ETH68}
var protocolLengths = map[uint]uint64{ETH68: 17}
// maxMessageSize is the maximum cap on the size of a protocol message.
const maxMessageSize = 10 * 1024 * 1024
var maxMessageSize = params.MaxMessageSize
const (
StatusMsg = 0x00

View File

@ -233,7 +233,7 @@ func (cs *chainSyncer) startSync(op *chainSyncOp) {
// doSync synchronizes the local blockchain with a remote peer.
func (h *handler) doSync(op *chainSyncOp) error {
// Run the sync cycle, and disable snap sync if we're past the pivot block
err := h.downloader.LegacySync(op.peer.ID(), op.head, op.td, h.chain.Config().TerminalTotalDifficulty, op.mode)
err := h.downloader.LegacySync(op.peer.ID(), op.head, op.peer.Name(), op.td, h.chain.Config().TerminalTotalDifficulty, op.mode)
if err != nil {
return err
}
@ -248,6 +248,9 @@ func (h *handler) doSync(op *chainSyncOp) error {
// degenerate connectivity, but it should be healthy for the mainnet too to
// more reliably update peers or the local TD state.
if block := h.chain.GetBlock(head.Hash(), head.Number.Uint64()); block != nil {
if h.chain.Config().IsCancun(block.Number(), block.Time()) {
block = block.WithSidecars(h.chain.GetSidecarsByHash(block.Hash()))
}
h.BroadcastBlock(block, false)
}
}

View File

@ -131,8 +131,8 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb
}
// BlobSidecars return the Sidecars of a given block number or hash.
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
var r []*types.BlobTxSidecar
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobSidecar, error) {
var r []*types.BlobSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String())
if err == nil && r == nil {
return nil, ethereum.NotFound
@ -141,8 +141,8 @@ func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumbe
}
// BlobSidecarByTxHash return a sidecar of a given blob transaction
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
var r *types.BlobTxSidecar
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobSidecar, error) {
var r *types.BlobSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecarByTxHash", hash)
if err == nil && r == nil {
return nil, ethereum.NotFound

1
go.mod
View File

@ -27,7 +27,6 @@ require (
github.com/fatih/color v1.16.0
github.com/fatih/structs v1.1.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.2
github.com/fsnotify/fsnotify v1.6.0
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46

2
go.sum
View File

@ -335,8 +335,6 @@ github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5 h1:6dVcS0LktRSyEE
github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=

View File

@ -30,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/exp"
"github.com/fjl/memsize/memsizeui"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
@ -38,8 +37,6 @@ import (
"gopkg.in/natefinch/lumberjack.v2"
)
var Memsize memsizeui.Handler
var (
verbosityFlag = &cli.IntFlag{
Name: "verbosity",
@ -313,7 +310,6 @@ func StartPProf(address string, withMetrics bool) {
if withMetrics {
exp.Exp(metrics.DefaultRegistry)
}
http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize))
log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address))
go func() {
if err := http.ListenAndServe(address, nil); err != nil {

View File

@ -862,54 +862,72 @@ func (s *BlockChainAPI) Health() bool {
return true
}
// GetFinalizedHeader returns the requested finalized block header.
// - probabilisticFinalized should be in range [2,21],
// then the block header with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFinalized int64) (map[string]interface{}, error) {
if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
func (s *BlockChainAPI) getFinalizedNumber(ctx context.Context, verifiedValidatorNum int64) (int64, error) {
parliaConfig := s.b.ChainConfig().Parlia
if parliaConfig == nil {
return 0, fmt.Errorf("only parlia engine supported")
}
currentTurnLength, err := s.b.CurrentTurnLength()
curValidators, err := s.b.CurrentValidators()
if err != nil { // impossible
return nil, err
return 0, err
}
valLen := int64(len(curValidators))
if verifiedValidatorNum < 1 || verifiedValidatorNum > valLen {
return 0, fmt.Errorf("%d out of range [1,%d]", verifiedValidatorNum, valLen)
}
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return nil, err
return 0, err
}
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if err != nil { // impossible
return 0, err
}
lastHeader := latestHeader
confirmedValSet := make(map[common.Address]struct{}, valLen)
confirmedValSet[lastHeader.Coinbase] = struct{}{}
for count := 1; int64(len(confirmedValSet)) < verifiedValidatorNum && count <= int(parliaConfig.Epoch) && lastHeader.Number.Int64() > max(fastFinalizedHeader.Number.Int64(), 1); count++ {
lastHeader, err = s.b.HeaderByHash(ctx, lastHeader.ParentHash)
if err != nil { // impossible
return 0, err
}
confirmedValSet[lastHeader.Coinbase] = struct{}{}
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), lastHeader.Number.Int64())
log.Debug("getFinalizedNumber", "LatestBlockNumber", latestHeader.Number.Int64(), "fastFinalizedHeight", fastFinalizedHeader.Number.Int64(),
"lastHeader", lastHeader.Number.Int64(), "finalizedBlockNumber", finalizedBlockNumber, "len(confirmedValSet)", len(confirmedValSet))
return finalizedBlockNumber, nil
}
// GetFinalizedHeader returns the finalized block header based on the specified parameters.
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)].
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators,
// it then returns the block header with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`.
// - The height of the returned block header is guaranteed to be monotonically increasing.
func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, verifiedValidatorNum int64) (map[string]interface{}, error) {
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum)
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))
return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
}
// GetFinalizedBlock returns the requested finalized block.
// - probabilisticFinalized should be in range [2,21],
// then the block with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
// - When fullTx is true all transactions in the block are returned, otherwise
// only the transaction hash is returned.
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFinalized int64, fullTx bool) (map[string]interface{}, error) {
if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
}
currentTurnLength, err := s.b.CurrentTurnLength()
// GetFinalizedBlock returns the finalized block based on the specified parameters.
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)].
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators,
// it then returns the block with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`.
// - If `fullTx` is true, the block includes all transactions; otherwise, only transaction hashes are included.
// - The height of the returned block is guaranteed to be monotonically increasing.
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, verifiedValidatorNum int64, fullTx bool) (map[string]interface{}, error) {
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum)
if err != nil { // impossible
return nil, err
}
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return nil, err
}
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))
return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx)
}

View File

@ -631,9 +631,9 @@ func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transactio
func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
panic("implement me")
}
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) CurrentValidators() ([]common.Address, error) { return []common.Address{}, nil }
func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
panic("implement me")
}

View File

@ -89,8 +89,8 @@ type Backend interface {
ChainConfig() *params.ChainConfig
Engine() consensus.Engine
// CurrentTurnLength return the turnLength at the latest block
CurrentTurnLength() (uint8, error)
// CurrentValidators return the list of validator at the latest block
CurrentValidators() ([]common.Address, error)
// This is copied from filters.Backend
// eth/filters needs to be initialized from this backend type, so methods needed by

View File

@ -416,7 +416,7 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
func (b *backendMock) Engine() consensus.Engine { return nil }
func (b *backendMock) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b *backendMock) CurrentValidators() ([]common.Address, error) { return []common.Address{}, nil }
func (b *backendMock) MevRunning() bool { return false }
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }

View File

@ -692,6 +692,14 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
return
}
// check bid size
if bidRuntime.env.size+blockReserveSize > params.MaxMessageSize {
log.Error("BidSimulator: failed to check bid size", "builder", bidRuntime.bid.Builder,
"bidHash", bidRuntime.bid.Hash(), "env.size", bidRuntime.env.size)
err = errors.New("invalid bid size")
return
}
bestBid := b.GetBestBid(parentHash)
if bestBid == nil {
log.Info("[BID RESULT]", "win", "true[first]", "builder", bidRuntime.bid.Builder, "hash", bidRuntime.bid.Hash().TerminalString())
@ -858,6 +866,7 @@ func (r *BidRuntime) commitTransaction(chain *core.BlockChain, chainConfig *para
}
r.env.tcount++
r.env.size += uint32(tx.Size())
return nil
}

View File

@ -62,7 +62,7 @@ type Config struct {
// DefaultConfig contains default settings for miner.
var DefaultConfig = Config{
GasCeil: 30000000,
GasCeil: 0,
GasPrice: big.NewInt(params.GWei),
// The default recommit time is chosen as two seconds since

View File

@ -70,6 +70,12 @@ const (
// the default to wait for the mev miner to finish
waitMEVMinerEndTimeLimit = 50 * time.Millisecond
// Reserve block size for the following 3 components:
// a. System transactions at the end of the block
// b. Seal in the block header
// c. Overhead from RLP encoding
blockReserveSize = 100 * 1024
)
var (
@ -89,6 +95,7 @@ type environment struct {
signer types.Signer
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
size uint32 // almost accurate block size,
gasPool *core.GasPool // available gas used to pack transactions
coinbase common.Address
@ -105,6 +112,7 @@ func (env *environment) copy() *environment {
signer: env.signer,
state: env.state.Copy(),
tcount: env.tcount,
size: env.size,
coinbase: env.coinbase,
header: types.CopyHeader(env.header),
receipts: copyReceipts(env.receipts),
@ -895,6 +903,13 @@ LOOP:
txs.Pop()
continue
}
// If we don't have enough size left for the next transaction, skip it.
if env.size+uint32(tx.Size())+blockReserveSize > params.MaxMessageSize {
log.Trace("Not enough size left for transaction", "hash", ltx.Hash,
"env.size", env.size, "needed", uint32(tx.Size()))
txs.Pop()
continue
}
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
from, _ := types.Sender(env.signer, tx)
@ -920,6 +935,7 @@ LOOP:
// Everything ok, collect the logs and shift in the next transaction from the same account
coalescedLogs = append(coalescedLogs, logs...)
env.tcount++
env.size += uint32(tx.Size()) // size of BlobTxSidecar included
txs.Shift()
default:
@ -1055,6 +1071,9 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{})
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state)
}
env.size = uint32(env.header.Size())
return env, nil
}

View File

@ -153,8 +153,8 @@ var (
FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
HaberTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
HaberFixTime: nil, // TBD
BohrTime: nil,
HaberFixTime: newUint64(1727316120), // 2024-09-26 02:02:00 AM UTC
BohrTime: newUint64(1727317200), // 2024-09-26 02:20:00 AM UTC
Parlia: &ParliaConfig{
Period: 3,

View File

@ -29,6 +29,8 @@ const (
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
PayBidTxGasLimit uint64 = 25000 // Gas limit of the PayBidTx in the types.BidArgs.
MaxMessageSize uint32 = 10 * 1024 * 1024 // MaxMessageSize is the maximum cap on the size of a eth protocol message.
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
ForkIDSize uint64 = 4 // The length of fork id
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.

View File

@ -23,7 +23,7 @@ import (
const (
VersionMajor = 1 // Major version component of the current release
VersionMinor = 4 // Minor version component of the current release
VersionPatch = 13 // Patch version component of the current release
VersionPatch = 15 // Patch version component of the current release
VersionMeta = "" // Version metadata to append to the version string
)