Compare commits

..

2 Commits

Author SHA1 Message Date
Matus Kysel
af34894fc3 add logs 2024-08-22 11:34:23 +02:00
Matus Kysel
7dcd01e9be statistics on stale peers 2024-08-22 09:23:58 +02:00
36 changed files with 260 additions and 1169 deletions

View File

@@ -125,25 +125,25 @@ jobs:
# ============================== # ==============================
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: linux name: linux
path: ./linux path: ./linux
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: macos name: macos
path: ./macos path: ./macos
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: windows name: windows
path: ./windows path: ./windows
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: arm64 name: arm64
path: ./arm64 path: ./arm64

View File

@@ -124,25 +124,25 @@ jobs:
# ============================== # ==============================
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: linux name: linux
path: ./linux path: ./linux
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: macos name: macos
path: ./macos path: ./macos
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: windows name: windows
path: ./windows path: ./windows
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v3
with: with:
name: arm64 name: arm64
path: ./arm64 path: ./arm64

View File

@@ -1,21 +1,4 @@
# Changelog # Changelog
## 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 ## v1.4.13
### BUGFIX ### BUGFIX

View File

@@ -17,11 +17,6 @@ geth:
@echo "Done building." @echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth." @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: Build all packages and executables
all: all:
$(GORUN) build/ci.go install $(GORUN) build/ci.go install

View File

@@ -1,87 +0,0 @@
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

@@ -1,88 +0,0 @@
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

@@ -1,97 +0,0 @@
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

@@ -1,90 +0,0 @@
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

@@ -1,65 +0,0 @@
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)
}
}
}
}
}

View File

@@ -53,10 +53,9 @@ import (
) )
var ( var (
genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with") genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with")
apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection") 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") 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") 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") payoutFlag = flag.Int("faucet.amount", 1, "Number of Ethers to pay out per user request")
@@ -78,12 +77,6 @@ var (
fixGasPrice = flag.Int64("faucet.fixedprice", 0, "Will use fixed gas price if specified") 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") 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") 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 ( var (
@@ -94,17 +87,11 @@ var (
//go:embed faucet.html //go:embed faucet.html
var websiteTmpl string 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() { func main() {
// Parse the flags and set up the logger to print everything requested // Parse the flags and set up the logger to print everything requested
flag.Parse() flag.Parse()
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), false))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), true)))
log.Info("faucet started")
// Construct the payout tiers // Construct the payout tiers
amounts := make([]string, *tiersFlag) amounts := make([]string, *tiersFlag)
for i := 0; i < *tiersFlag; i++ { for i := 0; i < *tiersFlag; i++ {
@@ -183,7 +170,7 @@ func main() {
log.Crit("Failed to unlock faucet signer account", "err", err) log.Crit("Failed to unlock faucet signer account", "err", err)
} }
// Assemble and start the faucet light service // Assemble and start the faucet light service
faucet, err := newFaucet(genesis, *wsEndpoint, *wsEndpointMainnet, ks, website.Bytes(), bep2eInfos) faucet, err := newFaucet(genesis, *wsEndpoint, ks, website.Bytes(), bep2eInfos)
if err != nil { if err != nil {
log.Crit("Failed to start faucet", "err", err) log.Crit("Failed to start faucet", "err", err)
} }
@@ -210,10 +197,9 @@ type bep2eInfo struct {
// faucet represents a crypto faucet backed by an Ethereum light client. // faucet represents a crypto faucet backed by an Ethereum light client.
type faucet struct { type faucet struct {
config *params.ChainConfig // Chain configurations for signing config *params.ChainConfig // Chain configurations for signing
client *ethclient.Client // Client connection to the Ethereum chain 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
index []byte // Index page to serve up on the web
keystore *keystore.KeyStore // Keystore containing the single signer keystore *keystore.KeyStore // Keystore containing the single signer
account accounts.Account // Account funding user faucet requests account accounts.Account // Account funding user faucet requests
@@ -242,7 +228,7 @@ type wsConn struct {
wlock sync.Mutex wlock sync.Mutex
} }
func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) { func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson)) bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -251,11 +237,6 @@ func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystor
if err != nil { if err != nil {
return nil, err 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 // Allow 1 request per minute with burst of 5, and cache up to 1000 IPs
limiter, err := NewIPRateLimiter(rate.Limit(1.0), 5, 1000) limiter, err := NewIPRateLimiter(rate.Limit(1.0), 5, 1000)
@@ -264,17 +245,16 @@ func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystor
} }
return &faucet{ return &faucet{
config: genesis.Config, config: genesis.Config,
client: client, client: client,
clientMainnet: clientMainnet, index: index,
index: index, keystore: ks,
keystore: ks, account: ks.Accounts()[0],
account: ks.Accounts()[0], timeouts: make(map[string]time.Time),
timeouts: make(map[string]time.Time), update: make(chan struct{}, 1),
update: make(chan struct{}, 1), bep2eInfos: bep2eInfos,
bep2eInfos: bep2eInfos, bep2eAbi: bep2eAbi,
bep2eAbi: bep2eAbi, limiter: limiter,
limiter: limiter,
}, nil }, nil
} }
@@ -398,11 +378,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
Captcha string `json:"captcha"` Captcha string `json:"captcha"`
Symbol string `json:"symbol"` 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 { if err = conn.ReadJSON(&msg); err != nil {
log.Debug("read json message failed", "err", err, "ip", ip)
return return
} }
if !*noauthFlag && !strings.HasPrefix(msg.URL, "https://twitter.com/") && !strings.HasPrefix(msg.URL, "https://www.facebook.com/") { if !*noauthFlag && !strings.HasPrefix(msg.URL, "https://twitter.com/") && !strings.HasPrefix(msg.URL, "https://www.facebook.com/") {
@@ -420,9 +396,9 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
} }
continue continue
} }
log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier, "ip", ip) log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier)
// check #1: captcha verifications to exclude robot // If captcha verifications are enabled, make sure we're not dealing with a robot
if *captchaToken != "" { if *captchaToken != "" {
form := url.Values{} form := url.Values{}
form.Add("secret", *captchaSecret) form.Add("secret", *captchaSecret)
@@ -499,108 +475,88 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
} }
continue continue
} }
log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address)
// check #2: check IP and ID(address) to ensure the user didn't request funds too recently, // Ensure the user didn't request funds too recently
f.lock.Lock() f.lock.Lock()
var (
fund bool
timeout time.Time
)
if ipTimeout := f.timeouts[ips[len(ips)-2]]; time.Now().Before(ipTimeout) { 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 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) log.Warn("Failed to send funding error to client", "err", err)
return
} }
log.Info("too frequent funding(ip)", "TimeLeft", common.PrettyDuration(time.Until(ipTimeout)), "ip", ips[len(ips)-2], "ipsStr", ipsStr) f.lock.Unlock()
continue continue
} }
if idTimeout := f.timeouts[id]; time.Now().Before(idTimeout) {
f.lock.Unlock() if timeout = f.timeouts[id]; time.Now().After(timeout) {
// Send an error if too frequent funding, otherwise a success var tx *types.Transaction
if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(idTimeout)))); err != nil { // nolint: gosimple 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)
}
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,
})
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
}
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) log.Warn("Failed to send funding error to client", "err", err)
return return
} }
log.Info("too frequent funding(id)", "TimeLeft", common.PrettyDuration(time.Until(idTimeout)), "id", id)
continue 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()
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)
}
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 { 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) log.Warn("Failed to send funding success to client", "err", err)
return return
@@ -649,52 +605,9 @@ func (f *faucet) refresh(head *types.Header) error {
f.lock.Lock() f.lock.Lock()
f.head, f.balance = head, balance f.head, f.balance = head, balance
f.price, f.nonce = price, nonce f.price, f.nonce = price, nonce
if len(f.reqs) == 0 { if len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() > f.nonce {
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] 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 { for len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() < f.nonce {
f.reqs = f.reqs[1:] f.reqs = f.reqs[1:]
} }

View File

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

View File

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

View File

@@ -35,11 +35,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "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"
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@@ -1149,25 +1146,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: params.DefaultExtraReserveForBlobRequests, Value: params.DefaultExtraReserveForBlobRequests,
Category: flags.MiscCategory, 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 ( var (
@@ -2319,67 +2297,6 @@ 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) { func SetupMetrics(ctx *cli.Context, options ...SetupMetricsOption) {
if metrics.Enabled { if metrics.Enabled {
log.Info("Enabling metrics collection") log.Info("Enabling metrics collection")

View File

@@ -100,8 +100,6 @@ var (
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
blockRecvTimeDiffGauge = metrics.NewRegisteredGauge("chain/block/recvtimediff", nil)
errStateRootVerificationFailed = errors.New("state root verification failed") errStateRootVerificationFailed = errors.New("state root verification failed")
errInsertionInterrupted = errors.New("insertion is interrupted") errInsertionInterrupted = errors.New("insertion is interrupted")
errChainStopped = errors.New("blockchain is stopped") errChainStopped = errors.New("blockchain is stopped")
@@ -2057,9 +2055,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
return 0, nil 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) // 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()) signer := types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time())
go SenderCacher.RecoverFromBlocks(signer, chain) go SenderCacher.RecoverFromBlocks(signer, chain)

View File

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

View File

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

View File

@@ -2,12 +2,10 @@ package types
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@@ -55,40 +53,3 @@ func (s *BlobSidecar) SanityCheck(blockNumber *big.Int, blockHash common.Hash) e
} }
return nil 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

@@ -441,14 +441,14 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine return b.eth.engine
} }
func (b *EthAPIBackend) CurrentValidators() ([]common.Address, error) { func (b *EthAPIBackend) CurrentTurnLength() (turnLength uint8, err error) {
if p, ok := b.eth.engine.(*parlia.Parlia); ok { if p, ok := b.eth.engine.(*parlia.Parlia); ok {
service := p.APIs(b.Chain())[0].Service service := p.APIs(b.Chain())[0].Service
currentHead := rpc.LatestBlockNumber currentHead := rpc.LatestBlockNumber
return service.(*parlia.API).GetValidators(&currentHead) return service.(*parlia.API).GetTurnLength(&currentHead)
} }
return []common.Address{}, errors.New("not supported") return 1, nil
} }
func (b *EthAPIBackend) CurrentHeader() *types.Header { 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. // SetGasLimit sets the gaslimit to target towards during mining.
func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool { func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool {
api.e.Miner().SetGasCeil(uint64(gasLimit)) api.e.Miner().SetGasCeil(uint64(gasLimit))
if uint64(gasLimit) > params.SystemTxsGas { if api.e.Miner().Mining() && uint64(gasLimit) > params.SystemTxsGas {
api.e.TxPool().SetMaxGas(uint64(gasLimit) - params.SystemTxsGas) api.e.TxPool().SetMaxGas(uint64(gasLimit) - params.SystemTxsGas)
} }
return true return true

View File

@@ -1,114 +0,0 @@
package eth
import (
"container/heap"
"sync"
"time"
)
// Implements the heap.Interface for *BlackListPeer based on LastSeen
type PeerHeap []*BlackListPeer
func (h PeerHeap) Len() int { return len(h) }
func (h PeerHeap) Less(i, j int) bool { return h[i].LastSeen.Before(h[j].LastSeen) }
func (h PeerHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i]; h[i].index = i; h[j].index = j }
func (h *PeerHeap) Push(x interface{}) {
n := len(*h)
item := x.(*BlackListPeer)
item.index = n
*h = append(*h, item)
}
func (h *PeerHeap) Pop() interface{} {
old := *h
n := len(old)
item := old[n-1]
item.index = -1 // for safety
*h = old[0 : n-1]
return item
}
// Peer represents the state of a peer in the network.
type BlackListPeer struct {
ID string // Unique identifier for the peer
HeadBlock int64 // Current head block of the peer
LastSeen time.Time // Timestamp of the last head block update
BlacklistCount int // Counter for failed head block updates
index int // Index of the peer in the heap
}
// blackList manages peers, both active and blacklisted.
type blackList struct {
mu sync.Mutex // To handle concurrent access
peers map[string]*BlackListPeer
peerHeap PeerHeap
maxPeers int
expiryTime time.Duration
blacklistedCount int
}
// NewBlackList creates a new instance of blackList.
func NewBlackList(maxPeers int, expiryTime time.Duration, blacklistedCount int) *blackList {
bl := &blackList{
peers: make(map[string]*BlackListPeer),
peerHeap: make(PeerHeap, 0, maxPeers),
maxPeers: maxPeers,
expiryTime: expiryTime,
blacklistedCount: blacklistedCount,
}
heap.Init(&bl.peerHeap)
return bl
}
// AddOrUpdatePeer adds or updates a peer in the map, rejecting invalid IDs.
func (bl *blackList) AddOrUpdatePeer(id string, headBlock int64) {
if id == "" {
return // Reject empty ID
}
bl.mu.Lock()
defer bl.mu.Unlock()
peer, exists := bl.peers[id]
if exists {
if peer.HeadBlock != headBlock {
peer.HeadBlock = headBlock
peer.LastSeen = time.Now()
peer.BlacklistCount = 0
heap.Fix(&bl.peerHeap, peer.index)
}
} else {
if len(bl.peers) >= bl.maxPeers {
oldest := heap.Pop(&bl.peerHeap).(*BlackListPeer)
delete(bl.peers, oldest.ID) // Corrected to use ID
}
newPeer := &BlackListPeer{
ID: id, HeadBlock: headBlock, LastSeen: time.Now(), BlacklistCount: 0,
}
bl.peers[id] = newPeer
heap.Push(&bl.peerHeap, newPeer)
}
}
// BlacklistStalePeers updates the blacklist count of stale peers.
func (bl *blackList) BlacklistStalePeers() {
bl.mu.Lock()
defer bl.mu.Unlock()
now := time.Now()
for _, peer := range bl.peers {
if now.Sub(peer.LastSeen) > bl.expiryTime {
peer.BlacklistCount++
}
}
}
// IsBlacklisted checks if a peer is blacklisted.
func (bl *blackList) IsBlacklisted(id string) bool {
bl.mu.Lock()
defer bl.mu.Unlock()
peer, exists := bl.peers[id]
return exists && peer.BlacklistCount >= bl.blacklistedCount
}

View File

@@ -1,161 +0,0 @@
package eth
import (
"sync"
"testing"
"time"
)
// TestAddOrUpdatePeer tests adding new peers and updating existing ones.
func TestAddOrUpdatePeer(t *testing.T) {
bl := NewBlackList(2, 10*time.Minute, 3)
bl.AddOrUpdatePeer("peer1", 100)
if len(bl.peers) != 1 {
t.Errorf("Expected 1 peer, got %d", len(bl.peers))
}
// Test updating the same peer
bl.AddOrUpdatePeer("peer1", 101)
if bl.peers["peer1"].HeadBlock != 101 {
t.Errorf("Expected head block 101, got %d", bl.peers["peer1"].HeadBlock)
}
// Test adding another peer and triggering the maxPeers limit
bl.AddOrUpdatePeer("peer2", 102)
bl.AddOrUpdatePeer("peer3", 103) // This should remove the oldest (peer1)
if len(bl.peers) != 2 {
t.Errorf("Expected 2 peers, got %d", len(bl.peers))
}
if _, exists := bl.peers["peer1"]; exists {
t.Errorf("Expected peer1 to be removed")
}
}
// TestBlacklistStalePeers tests the automatic blacklisting of stale peers.
func TestBlacklistStalePeers(t *testing.T) {
bl := NewBlackList(2, 1*time.Minute, 1)
bl.AddOrUpdatePeer("peer1", 100)
time.Sleep(2 * time.Minute) // simulate time passing
bl.BlacklistStalePeers()
if bl.peers["peer1"].BlacklistCount != 1 {
t.Errorf("Expected BlacklistCount of 1, got %d", bl.peers["peer1"].BlacklistCount)
}
}
// TestIsBlacklisted tests checking if a peer is blacklisted.
func TestIsBlacklisted(t *testing.T) {
bl := NewBlackList(2, 1*time.Minute, 1)
bl.AddOrUpdatePeer("peer1", 100)
bl.peers["peer1"].LastSeen = time.Now().Add(-2 * time.Minute) // make peer stale
bl.BlacklistStalePeers()
if !bl.IsBlacklisted("peer1") {
t.Errorf("Expected peer1 to be blacklisted")
}
}
// TestEdgeCases tests handling of edge cases such as invalid IDs.
func TestEdgeCases(t *testing.T) {
bl := NewBlackList(2, 1*time.Minute, 1)
bl.AddOrUpdatePeer("", 100) // testing with empty ID
if len(bl.peers) != 0 {
t.Errorf("Expected 0 peers, got %d", len(bl.peers))
}
}
// TestAddOrUpdatePeer_MaxPeers tests behavior when adding peers up to and beyond the maximum limit.
func TestAddOrUpdatePeer_MaxPeers(t *testing.T) {
bl := NewBlackList(3, 10*time.Minute, 3)
bl.AddOrUpdatePeer("peer1", 100)
bl.AddOrUpdatePeer("peer2", 101)
bl.AddOrUpdatePeer("peer3", 102)
bl.AddOrUpdatePeer("peer4", 103) // This should remove peer1
if len(bl.peers) != 3 {
t.Errorf("Expected 3 peers, got %d", len(bl.peers))
}
if _, exists := bl.peers["peer1"]; exists {
t.Errorf("Expected peer1 to be removed")
}
}
// TestBlacklistCountOverflow checks how the system handles when a peer's BlacklistCount exceeds the threshold.
func TestBlacklistCountOverflow(t *testing.T) {
bl := NewBlackList(2, 1*time.Second, 2)
bl.AddOrUpdatePeer("peer1", 100)
// Simulate multiple blacklist increments
time.Sleep(2 * time.Second)
bl.BlacklistStalePeers()
bl.BlacklistStalePeers()
if !bl.IsBlacklisted("peer1") {
t.Errorf("Expected peer1 to be blacklisted after exceeding blacklist count")
}
}
// TestExpiryTimeBoundary tests behavior when a peer's LastSeen is exactly at the expiry boundary.
func TestExpiryTimeBoundary(t *testing.T) {
bl := NewBlackList(2, 1*time.Second, 2)
bl.AddOrUpdatePeer("peer1", 100)
time.Sleep(1 * time.Second)
bl.BlacklistStalePeers() // Should increment blacklist count but not blacklisted yet
if bl.peers["peer1"].BlacklistCount != 1 {
t.Errorf("Expected BlacklistCount of 1, got %d", bl.peers["peer1"].BlacklistCount)
}
if bl.IsBlacklisted("peer1") {
t.Errorf("Peer1 should not be blacklisted yet")
}
}
// TestConcurrentAccess tests concurrent access to the blackList.
func TestConcurrentAccess(t *testing.T) {
bl := NewBlackList(100, 10*time.Minute, 3)
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
wg.Add(1)
go func(id string) {
defer wg.Done()
bl.AddOrUpdatePeer(id, int64(i))
}(string(rune('a' + i)))
}
wg.Wait()
if len(bl.peers) != 50 {
t.Errorf("Expected 50 peers, got %d", len(bl.peers))
}
}
// TestReaddingBlacklistedPeer tests the behavior when a blacklisted peer is re-added.
func TestReaddingBlacklistedPeer(t *testing.T) {
bl := NewBlackList(2, 1*time.Second, 1)
bl.AddOrUpdatePeer("peer1", 100)
// Simulate time passing to trigger blacklist
time.Sleep(2 * time.Second)
bl.BlacklistStalePeers()
// Ensure peer1 is blacklisted
if !bl.IsBlacklisted("peer1") {
t.Errorf("Expected peer1 to be blacklisted")
}
// Re-add the same peer
bl.AddOrUpdatePeer("peer1", 101)
if bl.peers["peer1"].BlacklistCount != 0 {
t.Errorf("Expected BlacklistCount to be reset, got %d", bl.peers["peer1"].BlacklistCount)
}
if bl.IsBlacklisted("peer1") {
t.Errorf("Peer1 should not be blacklisted after re-adding with updated information")
}
}

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 // LegacySync tries to sync up our local blockchain with a remote peer, both
// adding various sanity checks and wrapping it with various log entries. // adding various sanity checks and wrapping it with various log entries.
func (d *Downloader) LegacySync(id string, head common.Hash, name string, td *big.Int, ttd *big.Int, mode SyncMode) error { func (d *Downloader) LegacySync(id string, head common.Hash, td *big.Int, ttd *big.Int, mode SyncMode) error {
err := d.synchronise(id, head, td, ttd, mode, false, nil) err := d.synchronise(id, head, td, ttd, mode, false, nil)
switch err { switch err {
@@ -337,7 +337,7 @@ func (d *Downloader) LegacySync(id string, head common.Hash, name string, td *bi
if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) || 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, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) ||
errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) { errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) {
log.Warn("Synchronisation failed, dropping peer", "peer", id, "name", name, "td", td, "err", err) log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err)
if d.dropPeer == nil { if d.dropPeer == nil {
// The dropPeer method is nil when `--copydb` is used for a local copy. // 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 // 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 // Simulate a synchronisation and check the required result
tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.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 { 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) t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop)
} }

View File

@@ -172,8 +172,6 @@ type handler struct {
handlerStartCh chan struct{} handlerStartCh chan struct{}
handlerDoneCh chan struct{} handlerDoneCh chan struct{}
blackList *blackList
} }
// newHandler returns a handler for all Ethereum chain management protocol. // newHandler returns a handler for all Ethereum chain management protocol.
@@ -371,6 +369,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
} }
h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, addTxs, fetchTx, h.removePeer) h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, addTxs, fetchTx, h.removePeer)
h.chainSync = newChainSyncer(h) h.chainSync = newChainSyncer(h)
h.printPeerStatus()
return h, nil return h, nil
} }
@@ -485,13 +484,13 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
h.peersPerIP[remoteIP] = h.peersPerIP[remoteIP] + 1 h.peersPerIP[remoteIP] = h.peersPerIP[remoteIP] + 1
h.peerPerIPLock.Unlock() h.peerPerIPLock.Unlock()
} }
peer.Log().Debug("Ethereum peer connected", "name", peer.Name())
// Register the peer locally // Register the peer locally
if err := h.peers.registerPeer(peer, snap, trust, bsc); err != nil { if err := h.peers.registerPeer(peer, snap, trust, bsc); err != nil {
peer.Log().Error("Ethereum peer registration failed", "err", err) peer.Log().Error("Ethereum peer registration failed", "err", err)
return err return err
} }
peer.Log().Debug("Ethereum peer connected", "name", peer.Name(), "peers.len", h.peers.len())
defer h.unregisterPeer(peer.ID()) defer h.unregisterPeer(peer.ID())
p := h.peers.peer(peer.ID()) p := h.peers.peer(peer.ID())
@@ -634,7 +633,7 @@ func (h *handler) runBscExtension(peer *bsc.Peer, handler bsc.Handler) error {
bsc.EgressRegistrationErrorMeter.Mark(1) bsc.EgressRegistrationErrorMeter.Mark(1)
} }
} }
peer.Log().Error("Bsc extension registration failed", "err", err, "name", peer.Name()) peer.Log().Error("Bsc extension registration failed", "err", err)
return err return err
} }
return handler(peer) return handler(peer)
@@ -704,7 +703,6 @@ func (h *handler) unregisterPeer(id string) {
func (h *handler) Start(maxPeers int, maxPeersPerIP int) { func (h *handler) Start(maxPeers int, maxPeersPerIP int) {
h.maxPeers = maxPeers h.maxPeers = maxPeers
h.maxPeersPerIP = maxPeersPerIP h.maxPeersPerIP = maxPeersPerIP
h.blackList = NewBlackList(maxPeers, 1*time.Hour, 3)
// broadcast and announce transactions (only new ones, not resurrected ones) // broadcast and announce transactions (only new ones, not resurrected ones)
h.wg.Add(1) h.wg.Add(1)
h.txsCh = make(chan core.NewTxsEvent, txChanSize) h.txsCh = make(chan core.NewTxsEvent, txChanSize)
@@ -1020,3 +1018,67 @@ func (h *handler) enableSyncedFeatures() {
// h.chain.TrieDB().SetBufferSize(pathdb.DefaultBufferSize) // 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

@@ -233,7 +233,7 @@ func (cs *chainSyncer) startSync(op *chainSyncOp) {
// doSync synchronizes the local blockchain with a remote peer. // doSync synchronizes the local blockchain with a remote peer.
func (h *handler) doSync(op *chainSyncOp) error { func (h *handler) doSync(op *chainSyncOp) error {
// Run the sync cycle, and disable snap sync if we're past the pivot block // 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.peer.Name(), op.td, h.chain.Config().TerminalTotalDifficulty, op.mode) err := h.downloader.LegacySync(op.peer.ID(), op.head, op.td, h.chain.Config().TerminalTotalDifficulty, op.mode)
if err != nil { if err != nil {
return err return err
} }

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. // BlobSidecars return the Sidecars of a given block number or hash.
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobSidecar, error) { func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
var r []*types.BlobSidecar var r []*types.BlobTxSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String()) err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String())
if err == nil && r == nil { if err == nil && r == nil {
return nil, ethereum.NotFound 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 // BlobSidecarByTxHash return a sidecar of a given blob transaction
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobSidecar, error) { func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
var r *types.BlobSidecar var r *types.BlobTxSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecarByTxHash", hash) err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecarByTxHash", hash)
if err == nil && r == nil { if err == nil && r == nil {
return nil, ethereum.NotFound return nil, ethereum.NotFound

1
go.mod
View File

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

2
go.sum
View File

@@ -335,6 +335,8 @@ 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/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 h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= 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/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 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=

View File

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

View File

@@ -862,72 +862,54 @@ func (s *BlockChainAPI) Health() bool {
return true return true
} }
func (s *BlockChainAPI) getFinalizedNumber(ctx context.Context, verifiedValidatorNum int64) (int64, error) { // GetFinalizedHeader returns the requested finalized block header.
parliaConfig := s.b.ChainConfig().Parlia // - probabilisticFinalized should be in range [2,21],
if parliaConfig == nil { // then the block header with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
return 0, fmt.Errorf("only parlia engine supported") 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)
} }
curValidators, err := s.b.CurrentValidators() currentTurnLength, err := s.b.CurrentTurnLength()
if err != nil { // impossible
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 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 if err != nil { // impossible
return nil, err 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.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber)) return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
} }
// GetFinalizedBlock returns the finalized block based on the specified parameters. // GetFinalizedBlock returns the requested finalized block.
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)]. // - probabilisticFinalized should be in range [2,21],
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators, // then the block with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
// it then returns the block with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`. // - When fullTx is true all transactions in the block are returned, otherwise
// - If `fullTx` is true, the block includes all transactions; otherwise, only transaction hashes are included. // only the transaction hash is returned.
// - The height of the returned block is guaranteed to be monotonically increasing. func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFinalized int64, fullTx bool) (map[string]interface{}, error) {
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, verifiedValidatorNum int64, fullTx bool) (map[string]interface{}, error) { if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum) return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
}
currentTurnLength, err := s.b.CurrentTurnLength()
if err != nil { // impossible if err != nil { // impossible
return nil, err 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) 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 { func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
panic("implement me") panic("implement me")
} }
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() } func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() } func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) CurrentValidators() ([]common.Address, error) { return []common.Address{}, nil } func (b testBackend) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
panic("implement me") panic("implement me")
} }

View File

@@ -89,8 +89,8 @@ type Backend interface {
ChainConfig() *params.ChainConfig ChainConfig() *params.ChainConfig
Engine() consensus.Engine Engine() consensus.Engine
// CurrentValidators return the list of validator at the latest block // CurrentTurnLength return the turnLength at the latest block
CurrentValidators() ([]common.Address, error) CurrentTurnLength() (uint8, error)
// This is copied from filters.Backend // This is copied from filters.Backend
// eth/filters needs to be initialized from this backend type, so methods needed by // 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) Engine() consensus.Engine { return nil }
func (b *backendMock) CurrentValidators() ([]common.Address, error) { return []common.Address{}, nil } func (b *backendMock) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b *backendMock) MevRunning() bool { return false } func (b *backendMock) MevRunning() bool { return false }
func (b *backendMock) HasBuilder(builder common.Address) bool { return false } func (b *backendMock) HasBuilder(builder common.Address) bool { return false }

View File

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

View File

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

View File

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